Skip to content

pref(runtime): 去掉taskcompletion无用信号#620

Merged
Yumiue merged 2 commits into
1024XEngineer:mainfrom
phantom5099:main
May 11, 2026
Merged

pref(runtime): 去掉taskcompletion无用信号#620
Yumiue merged 2 commits into
1024XEngineer:mainfrom
phantom5099:main

Conversation

@phantom5099
Copy link
Copy Markdown
Collaborator

问题

当前 system prompt 要求模型在最终回复正文中输出 {"task_completion":{"completed":true}} JSON 作为完成信号。这套机制在实践中暴露了三个根本问题:

1. 控制信号混入用户可见正文
task_completion 作为正文 JSON 输出,控制面和展示面混在一起。模型需要记住输出前加 JSON,runtime 需要从文本中解析、strip、渲染,streaming 阶段可能先把未验收文本展示给用户。控制信号不应依赖用户可见文本格式。

2. 简单聊天被强行套入任务完成协议
用户输入"你好""谢谢""解释一下 interface"时,模型直接给出文本回答是自然行为。但旧机制要求它必须输出 task_completion,否则 runtime 注入 completion reminder,导致"自然回复 → 追加提醒 → 模型重复回复 → 用户看到两遍同样内容"的循环。

3. 与主流 coding agent 实践背离
截至 2026-05-11,Codex、Claude Code、opencode 等主流 agent 均不要求正文 completion JSON。它们采用 tool-call loop:有 tool calls 就继续执行工具,无 tool calls + 有文本就是 final answer。NeoCode 的差异化能力应体现在 Accept Gate 的确定性验收,不在 completion token 的形式。

此外还发现:即使把 task_completion 做成工具(如 OpenCode 的 task_complete 工具),也会引入双信号歧义(模型自然说话 vs 调用完成工具)、语义不匹配(完成是元控制信号不是动作请求)、OpenCode 自身 issue 证明工具路径不可靠等新问题。

方案

本 PR 落地 V2 重设计:删除 task_completion 正文协议,改用主流 tool-call loop + Accept Gate 架构。

终止协议改为:

assistant 输出 runtime 行为
有 tool calls 执行工具,记录事实,回灌结果,继续 loop
无 tool calls + 非空文本 生成 final candidate,进入 Accept Gate
无 tool calls + 空文本 直接终止为 empty_response,不注入 reminder

核心变更:

  1. 删除旧 completion 协议:移除 taskCompletionSignalcompletionTurnOutputmaybeParseCompletionTurnOutputrenderAssistantTextWithoutCompletionstripCompletionSignalFromAssistantMessageStopReasonMissingCompletionSignal 及相关 state 字段。
  2. 空响应直接终止:不带 reminder 注入、不带 streak 计数。主流方案(Claude Code、OpenCode)对空响应的处理就是直接终止或 provider 层重试,不额外注入提示。
  3. Accept Gate 直接消费原始文本:不再 strip task_completion JSON,LastAssistantText 就是模型的原始回复文本。
  4. Prompt 同步plan_mode_build_execute.md 移除 task_completion 要求,替换为"无工具纯文本 = final answer"语义。
  5. 执行与验收分离command_success 类 verifier 只检查执行阶段是否留下成功事实,验收阶段不再重新执行命令。

涉及变更

删除代码(~200 行)

文件 变更
internal/runtime/planning.go 删除 taskCompletionSignal/completionTurnOutput 类型、maybeParseCompletionTurnOutput
internal/runtime/state.go 删除 missingCompletionSignalStreak 字段
internal/runtime/acceptgate_runtime.go 删除 missingCompletionSignalLimitcompletionProtocolReminderForStreakrenderAssistantTextWithoutCompletionstripCompletionSignalFromAssistantMessage
internal/promptasset/assets.go 删除 completionProtocolReminder/completionProtocolFinalReminder 变量和访问器
internal/promptasset/templates/runtime/ 删除 completion_protocol_reminder.mdcompletion_protocol_final_reminder.md
internal/runtime/controlplane/stop_reason.go 删除 StopReasonMissingCompletionSignal
internal/tui/services/runtime_contract.go 删除 StopReasonMissingCompletionSignal
测试文件 删除 withDefaultCompletionSignal/shouldInjectDefaultCompletionForStream/TestMaybeParseCompletionTurnOutput 等辅助

新增代码

文件 变更
internal/runtime/controlplane/stop_reason.go 新增 StopReasonEmptyResponse
internal/tui/services/runtime_contract.go 新增 StopReasonEmptyResponse

修改代码

文件 变更
internal/runtime/run.go !hasToolCalls 分支重写:空文本 → StopReasonEmptyResponse;非空文本 → 直接进入 Accept Gate
internal/runtime/planning.go markCurrentPlanCompleted 移除 completionSignaled 参数
internal/runtime/acceptgate_runtime.go evaluateAcceptGate 改用原始文本,不再 strip
internal/promptasset/templates/context/plan_mode_build_execute.md 移除 task_completion 协议,替换为 tool-call loop 语义
internal/tui/core/app/update.go StopReasonMissingCompletionSignalStopReasonEmptyResponse
5 个测试文件 适配新行为

设计约束

  • 不兼容旧 task_completion JSON:旧 JSON 作为普通文本处理,不 strip、不解析、不触发任何特殊控制流。
  • plan_spec JSON 不受影响extractPlanningJSONObjectIfPresentstripPlanningJSONObjectText 保留(plan 解析仍需要)。
  • empty_response 不涉及重试或提醒:空响应直接终止,复现时检查 provider 行为即可。
  • Accept Gate 职责不变:final candidate 不直接等于成功,必须经过 RuntimeFacts、Plan Verify、todo 收敛的确定性检查。

预期收益

  • 简单聊天/问答一次结束,不再有 protocol reminder 循环
  • 模型回复不再需要记住"输出前加 JSON"的格式要求
  • 控制信号与展示面彻底分离
  • 与主流 coding agent 架构对齐,降低后续迁移成本
  • 空响应异常不再走 6 轮提醒才终止,快进快出

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 11, 2026

Codecov Report

❌ Patch coverage is 45.45455% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/runtime/run.go 33.33% 4 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@fennoai fennoai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

发现 2 个需要处理的问题:1) 当前实现会把尚未 approved 的 draft plan 直接推进到 completed;2) empty_response 的注释语义与实际运行时行为不一致,容易继续误导文档和测试。

Comment thread internal/runtime/run.go
Comment thread internal/runtime/controlplane/stop_reason.go Outdated
@Yumiue Yumiue merged commit 591a6b3 into 1024XEngineer:main May 11, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants