pref(runtime): 去掉taskcompletion无用信号#620
Merged
Merged
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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.
问题
当前 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 架构。终止协议改为:
empty_response,不注入 reminder核心变更:
taskCompletionSignal、completionTurnOutput、maybeParseCompletionTurnOutput、renderAssistantTextWithoutCompletion、stripCompletionSignalFromAssistantMessage、StopReasonMissingCompletionSignal及相关 state 字段。task_completionJSON,LastAssistantText就是模型的原始回复文本。plan_mode_build_execute.md移除task_completion要求,替换为"无工具纯文本 = final answer"语义。command_success类 verifier 只检查执行阶段是否留下成功事实,验收阶段不再重新执行命令。涉及变更
删除代码(~200 行)
internal/runtime/planning.gotaskCompletionSignal/completionTurnOutput类型、maybeParseCompletionTurnOutputinternal/runtime/state.gomissingCompletionSignalStreak字段internal/runtime/acceptgate_runtime.gomissingCompletionSignalLimit、completionProtocolReminderForStreak、renderAssistantTextWithoutCompletion、stripCompletionSignalFromAssistantMessageinternal/promptasset/assets.gocompletionProtocolReminder/completionProtocolFinalReminder变量和访问器internal/promptasset/templates/runtime/completion_protocol_reminder.md、completion_protocol_final_reminder.mdinternal/runtime/controlplane/stop_reason.goStopReasonMissingCompletionSignalinternal/tui/services/runtime_contract.goStopReasonMissingCompletionSignalwithDefaultCompletionSignal/shouldInjectDefaultCompletionForStream/TestMaybeParseCompletionTurnOutput等辅助新增代码
internal/runtime/controlplane/stop_reason.goStopReasonEmptyResponseinternal/tui/services/runtime_contract.goStopReasonEmptyResponse修改代码
internal/runtime/run.go!hasToolCalls分支重写:空文本 →StopReasonEmptyResponse;非空文本 → 直接进入 Accept Gateinternal/runtime/planning.gomarkCurrentPlanCompleted移除completionSignaled参数internal/runtime/acceptgate_runtime.goevaluateAcceptGate改用原始文本,不再 stripinternal/promptasset/templates/context/plan_mode_build_execute.mdtask_completion协议,替换为 tool-call loop 语义internal/tui/core/app/update.goStopReasonMissingCompletionSignal→StopReasonEmptyResponse设计约束
task_completionJSON:旧 JSON 作为普通文本处理,不 strip、不解析、不触发任何特殊控制流。plan_specJSON 不受影响:extractPlanningJSONObjectIfPresent和stripPlanningJSONObjectText保留(plan 解析仍需要)。empty_response不涉及重试或提醒:空响应直接终止,复现时检查 provider 行为即可。预期收益