Conversation
…tent parts
UserPromptSubmit hook messages now merge into the user prompt message as
meta-marked text content parts (contentType text/xml, source 'user prompt
submit hook') at content position 0 instead of a standalone hook_result
user message, so one prompt always yields exactly one user message and
turn pairing can no longer shift. Structured hook JSON without a message
field (e.g. {"continue":true}) no longer injects anything; plain-text
stdout still falls through. turn.prompt records, TurnStarted prompts,
fold turn openings, and steer content keys all strip hook parts; existing
wires with standalone hook_result messages keep their current behavior.
… and render them in clients Per the revised contract, turn.prompt records and TurnStarted prompts keep hook content (the data is persisted and enters the context), and the presentation layers own how it shows up: the cold transcript fold maps hook parts to visible hook markers, the live transcript projection strips hook_result wrappers from turn headers (the hook marker carries the injection), and the TUI replay renders meta hook parts as the same hook entries old wires produced, keeping prompt text clean. vis sees the full data from the wire unchanged.
🦋 Changeset detectedLatest commit: a743499 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
sailist
force-pushed
the
feat-273-09-28-hook-result-prompt-part
branch
from
September 28, 2026 11:38
095878c to
612a4c4
Compare
…onal slicing
Bundled skill blocks are now constructed with meta { source: 'skill
activation' }, matching the hook-part convention. Every former
content.slice(skillActivations.length) site — turn prompt text, steer
merge/echo, session and fork titles, transcript fold, TUI replay — now
annotates then filters by meta, so prompt content no longer depends on
block positions and the loop needs no hook-part knowledge. A shared
annotate step keeps legacy wires working: leading unmarked blocks (one
per bundled activation) are marked on read before filtering.
sailist
force-pushed
the
feat-273-09-28-hook-result-prompt-part
branch
from
September 28, 2026 11:42
612a4c4 to
a743499
Compare
Collaborator
Collaborator
Author
|
Superseded: resubmitting under a different account. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requirement or Bug
Resolve #4032
Bug Reproduction Steps
See linked issue(2.1.0/2.1.1 可复现:配置
UserPromptSubmit钩子的会话里,轮次整体错位一位,最后一条消息看起来永远没有回复,刷新后恢复)。Root Cause
引擎在
UserPromptSubmit钩子返回文本后,把它作为一条独立的 user 角色消息(origin: hook_result)追加到真实用户消息之前,上下文序列变成[hook 消息][用户消息][回复],user 单元翻倍。渲染层的轮次配对依赖「一个 user 单元配一段 assistant 输出」的不变量,任何不消费origin的配对路径都会因多出的 user 单元而整体错位一位。排查确认数据层(wire、fold、live store、投影)完整且对齐,错位只来自不消费 hook origin 的渲染路径。这是根本修复而非绕过:让「一条 prompt 一条 user 消息」在结构上成立——钩子注入文本以带 meta 标记的 content part 并入 user prompt 消息,不再产生第二条 user 消息,轮次配对在结构上不存在错位可能,不再依赖每条渲染路径自觉遵守 origin 约定。
Code Changes
三个提交,按主题分五块:
1. content part 增加 meta 能力(
agent-core-v2+transcript)wire schema(
historySchema.ts)以 looseObject 形态接受meta(前向兼容);packages/transcript的HistoryContentParttext 变体同步(browser-safe 纯类型)。meta 不下发 LLM provider(adapter 只读type/text)。2. 钩子注入合并进 prompt 消息(gate 单次落盘)
PromptSubmitContext增加hookParts可变插槽(钩子的唯一输出通道,与既有block字段同模式);hook part 固定形状{ type:'text', text:'<hook_result …>…</hook_result>', meta:{ contentType:'text/xml', source:'user prompt submit hook' } },多钩子按返回顺序各成一个 part。message字段(如{"continue":true})不再注入任何内容(此前原文注入,每轮都有噪声);纯文本 stdout 仍兜底注入。3. Turn 层记录保留完整数据(vis/replay 可见)
turn.promptwire 记录与TurnStarted.prompt均含 hook 内容。4. 展示层可见渲染
hookmarker(载荷与 livehook.resultmarker 同形),轮 prompt 提取/steer 匹配仍按剥离后内容加工,不产生 0 步轮组;<hook_result>wrapper(注入已由 live hook marker 承载);5. skill bundled 块统一 meta 化,消除位置切片
skill 块与 hook part 一样在构造时携带
meta: { source: 'skill activation', activationId }(fallback 补标时按 origin 顺序对应一并回填 activationId,新老 wire 的 skill part 均自描述)。原先全部content.slice(skillActivations.length)位置切片点——轮 prompt 文本、steer 合并与 echo、会话标题与 fork 标题、transcript fold、TUI replay——统一改为「先 annotate 再按 meta 过滤」:annotate 是集中的向后兼容层,老 wire 里无标记的前 N 个块(每个 bundled activation 一个)在读取时补标,之后与有标记的新 wire 走同一条过滤路径。prompt 内容不再依赖块位置,loop 也无需识别 hook part。Behavior Changes and Affected Users
UserPromptSubmit注入文本的上下文形态origin: hook_result),位于真实 prompt 之前message的 JSON(如{"continue":true}){"message": "..."}turn.prompt记录 /turn.started事件的 promptturn.started.prompt的客户端:ACP 客户端(如 Zed)、desktop、klient SDK 用户,将看到含 hook 文本的 promptorigin.skillActivations.length位置识别meta: { source: 'skill activation', activationId }(含 steer 合并消息;老 wire 读取时由 fallback 回填)受影响模块与测试覆盖:
agent-core-v2gate / 钩子服务):promptService.test.ts的 gate 用例钉住单条 user 消息、content[0] meta 形状、turn.prompt/TurnStarted均含 hook 内容、skill 块不进 prompt 文本;runHook/userPrompt):runner.test.ts钉住无messageJSON(含{"continue":true})不注入、纯文本 stdout 产出带约定 meta 的 part;origin.ts/ steer 合并):promptService.test.ts的 steer/queue 用例与machine.test.ts钉住标记与未标记块两种形态的合并/echo 结果;transcript、kap-server):layers.test.ts钉住 hook marker 可见、bundled 标记/未标记两形态展开一致、steer content-key 匹配不受影响;apps/kimi-code):message-replay.test.ts与kimi-tui-message-flow.test.ts钉住合并 wire 的 hook 条目可见、marked/unmarked skill 块渲染一致、prompt 文本干净;Checklist
/approve).gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.(state-manifest.d.ts已随类型同步重新生成)