fix(MOC-57): apply_patch chat-path 截断检测 + V4A 后验校验(摘自 #321)#322
Merged
Conversation
ae2f784 to
2cdcdcc
Compare
2cdcdcc to
f5445a6
Compare
在 #303(apply_patch chat-path 非破坏性信封修复)基础上补全 MOC-57 的截断/校验 层。#303 只靠 `interrupted` 模糊信号判断 patch 是否完整;本提交主动检测: - detect_json_truncation:未闭合 JSON 字符串(奇数未转义引号)/ {} 不平衡 - detect_v4a_truncation:缺列 0 裸 `*** End Patch` sentinel - validate_v4a_syntax:首/末 sentinel + 文件操作 header + 行前缀合法性后验校验 - close_tool_call:should_incomplete = interrupted || is_truncated || v4a_invalid, 任一成立 emit custom_tool_call status=incomplete(防 Codex CLI 执行 partial/ invalid patch);抽 emit_apply_patch_output 让三条 incomplete 路径复用 emit 逻辑 移植自 @Alpaca233114514 的 PR #321,但**只取截断检测/校验精华**: - 不含 chunked apply_patch(apply_patch_chunk 工具,要模型学会分块协议,投机性强) → 单独 Linear issue 评估 - 基于最新 main,保留 tool_search MCP 全链路(#288 系)+ #303,不回退任何东西 - TruncationInfo struct 简化为 Option<String> 返回(原 level 字段从未被读) 12 新测试(detect ×4 + validate ×5 + 转义边界 + 端到端 incomplete);adapters lib 612 passed。 Co-authored-by: Alpaca233114514 <Alpaca233114514@users.noreply.github.com>
f5445a6 to
e4df2a1
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e4df2a180a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Cmochance
added a commit
that referenced
this pull request
May 30, 2026
…用防护) silent-failure review:gemini 路径对完整但畸形的 V4A patch(有 *** Begin Patch 头但 hunk header / operation marker 非法)一律 emit completed,缺 #322 MOC-57 chat 路径的 破坏性半应用防护(apply_patch partial 执行可能在意外目标写入意外内容)。 - 复用 chat 的 validate_v4a_syntax(提 pub(crate) + re-export);has Begin Patch 且 validate 失败 → emit status=incomplete + 跳过 custom_tool_call_input.done + envelope 终态 incomplete + 不写 cache(对齐 #322 chat 路径) - 空 / 裸串(无 Begin Patch,无 hunk 可半应用)保持 completed 让 Codex parse_patch 报错(非破坏性;test 2116 行为不变) - Gemini args 一次性完整无截断风险,只做语法后验、不复用 chat 截断双检测器 - warn 加 stable error_id(GEMINI_APPLY_PATCH_V4A_INVALID / _NO_V4A_ENVELOPE) - 回归测试 apply_patch_malformed_v4a_emits_incomplete Refs MOC-75
Cmochance
added a commit
that referenced
this pull request
May 30, 2026
chatgpt review P1:apply_patch 的 input.done 在 emit_function_call 急切 emit,而
finishReason 在 part 处理之后才记 → MAX_TOKENS 截断的 patch 仍发了"就绪"信号 →
Codex 可能应用被 token 上限切断的 patch(破坏性,即使语法暂时合法)。
- finishReason 记录移到 candidate 循环开头(part 循环之前),emit_function_call 即可
见本 chunk 的 finishReason(粘性保护不变:INTERRUPTED 不被后续 STOP 覆盖)
- apply_patch incomplete 判据加响应级截断:finishReason ∈ {MAX_TOKENS / SAFETY /
RECITATION / ... / INTERRUPTED} → incomplete(跳过 input.done + status=incomplete +
envelope 终态 incomplete),对齐 #322 chat 路径
- **不含 None**(part 处理时 None 仅表示"本 chunk 尚无 finishReason",后续可能 STOP
正常收尾;断流 + 完整 functionCall 非破坏性,不在此 gate)
- 回归测试 apply_patch_truncated_by_max_tokens_emits_incomplete
Refs MOC-75
Cmochance
added a commit
that referenced
this pull request
May 30, 2026
…om_tool_call) (#314) * fix(MOC-75): gemini 系 apply_patch 等 freeform 工具修复(请求补 input + 响应 custom_tool_call) gemini 系(gemini_native + cloud_code/antigravity)用 Codex 时 apply_patch 等 custom freeform 工具全失效:模型调用 arguments 为空 → Codex aborted → 文件编辑不生效 (forward-trace 实证 64 轮 6 次 apply_patch 全 aborted,gemini thought 自承 "empty patch, it's FREEFORM")。 根因:apply_patch 是 Codex custom freeform tool(lark grammar,patch 纯文本无 JSON parameters),gemini_native/cloud_code 转 functionDeclaration 时只保留 name+description、 丢了入参 → Gemini 不知道 patch 放哪个 arg → 给空 args。 修复(借鉴 chat 路径 responses/request/tools.rs:221 + converter.rs::close_tool_call): - 请求侧 gemini_native/request.rs custom 分支:freeform 降级成带 input string 参数的 function,apply_patch 复用 chat 强化 description 常量(grammar 没了靠 description 教模型) - 响应侧 gemini_native/response.rs:apply_patch functionCall 重打包成 custom_tool_call wire(Codex CLI router 硬要求 Custom payload,收 Function 直接 abort)+ envelope 终态 同步;input 不含 V4A 信封时 warn 带 model 上下文(review 采纳,可观测性) - responses/converter.rs extract_apply_patch_input 提 pub(crate) + mod.rs re-export (gemini 复用同一套 alt-key 容错,不重复造轮子) - 4 单测:请求侧 input 参数 + 正向 desc + 非 apply_patch custom;响应侧 custom_tool_call wire + 空 args 回归保护 - README 双语 apply_patch rollup 加 Gemini 系 cloud_code/antigravity 复用 gemini_native 转换,自动覆盖。 Refs MOC-75 * fix(MOC-75): apply_patch custom_tool_call 纳入 gemini session 历史(多轮续话修复) devin review BUG:build_assistant_message_for_session 只处理 function_call, custom_tool_call(apply_patch)落进 _=>{} 被静默丢弃 → 下一轮 previous_response_id 续话时 assistant 历史缺这条 call,新进来的 custom_tool_call_output 无匹配 functionCall → Gemini BadRequest / 多轮 apply_patch 断。 加 custom_tool_call arm:重建成 function-type tool_call(arguments={"input":<patch>}), 与请求侧 responses/request.rs 的 custom_tool_call 回放形态一致。+ 回归测试。 Refs MOC-75 * fix(MOC-75): gemini apply_patch 完整但畸形 patch → status=incomplete(破坏性半应用防护) silent-failure review:gemini 路径对完整但畸形的 V4A patch(有 *** Begin Patch 头但 hunk header / operation marker 非法)一律 emit completed,缺 #322 MOC-57 chat 路径的 破坏性半应用防护(apply_patch partial 执行可能在意外目标写入意外内容)。 - 复用 chat 的 validate_v4a_syntax(提 pub(crate) + re-export);has Begin Patch 且 validate 失败 → emit status=incomplete + 跳过 custom_tool_call_input.done + envelope 终态 incomplete + 不写 cache(对齐 #322 chat 路径) - 空 / 裸串(无 Begin Patch,无 hunk 可半应用)保持 completed 让 Codex parse_patch 报错(非破坏性;test 2116 行为不变) - Gemini args 一次性完整无截断风险,只做语法后验、不复用 chat 截断双检测器 - warn 加 stable error_id(GEMINI_APPLY_PATCH_V4A_INVALID / _NO_V4A_ENVELOPE) - 回归测试 apply_patch_malformed_v4a_emits_incomplete Refs MOC-75 * fix(MOC-75): gemini apply_patch 响应级截断(MAX_TOKENS 等)→ status=incomplete chatgpt review P1:apply_patch 的 input.done 在 emit_function_call 急切 emit,而 finishReason 在 part 处理之后才记 → MAX_TOKENS 截断的 patch 仍发了"就绪"信号 → Codex 可能应用被 token 上限切断的 patch(破坏性,即使语法暂时合法)。 - finishReason 记录移到 candidate 循环开头(part 循环之前),emit_function_call 即可 见本 chunk 的 finishReason(粘性保护不变:INTERRUPTED 不被后续 STOP 覆盖) - apply_patch incomplete 判据加响应级截断:finishReason ∈ {MAX_TOKENS / SAFETY / RECITATION / ... / INTERRUPTED} → incomplete(跳过 input.done + status=incomplete + envelope 终态 incomplete),对齐 #322 chat 路径 - **不含 None**(part 处理时 None 仅表示"本 chunk 尚无 finishReason",后续可能 STOP 正常收尾;断流 + 完整 functionCall 非破坏性,不在此 gate) - 回归测试 apply_patch_truncated_by_max_tokens_emits_incomplete Refs MOC-75 * fix(MOC-75): apply_patch 截断 gate 补 MALFORMED_FUNCTION_CALL/_RESPONSE + 清理 silent-failure review:apply_patch 响应级截断 gate 列了 MAX_TOKENS / SAFETY 等却漏了 Gemini 自报"本次产出畸形"的 MALFORMED_FUNCTION_CALL / MALFORMED_RESPONSE —— 这是 destructive apply_patch 风险最高的信号(patch 文本可能碰巧通过 V4A 宽松后验, v4a_err=None 漏判)。补进 gate 列表 → incomplete。 - gate 列表加 MALFORMED_FUNCTION_CALL / MALFORMED_RESPONSE - 补同 chunk 边界注释:此 gate 依赖 finishReason 与 functionCall 同 chunk(Gemini wire 常见情形成立);跨 chunk 时由不依赖时序的 validate_v4a_syntax 兜底,破坏性主防护不漏 - 删 mod.rs 未用的 V4aError re-export(调用方经 .err() 类型推断读 line/message) - 回归测试 apply_patch_malformed_function_call_finish_reason_emits_incomplete Refs MOC-75 * fix(MOC-75): apply_patch forced tool_choice {type:custom} → allowed_function_names chatgpt review P2:tool_choice={"type":"custom","name":"apply_patch"} 强制 freeform 工具时, convert_tool_choice 只认 {function:{name}},custom shape 落空 → Gemini 收不到 allowed_function_names、强制信号静默丢失。请求侧已把该工具声明降级成同名 function, 这里把 forced choice 也映射成 allowed_function_names(custom 分支)。+ 测试。 Refs MOC-75
Owner
Author
|
致谢 🙏:本 PR(MOC-57)摘自 @Alpaca233114514 的 #321( |
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.
背景
基于 main 已合的 #303(apply_patch chat-path 非破坏性信封修复)补全 MOC-57 的截断检测 + 后验校验层。#303 只靠
interrupted模糊信号判断 patch 是否完整;本 PR 主动检测 args 是否被切。改动(单文件
responses/converter.rs)detect_json_truncation:未闭合 JSON 字符串(奇数未转义引号)/{}不平衡detect_v4a_truncation:缺列 0 裸*** End Patchsentinelvalidate_v4a_syntax:首/末 sentinel + 文件操作 header + 行前缀合法性后验校验close_tool_call:should_incomplete = interrupted || is_truncated || v4a_invalid,任一成立 emitcustom_tool_call status=incomplete(防 Codex CLI 执行 partial/invalid patch);抽emit_apply_patch_output让三条 incomplete 路径复用 emit 逻辑与 #321 的关系(保留作者贡献)
摘自 @Alpaca233114514 的 PR #321,co-author 已署名。 但只取截断检测/校验精华,有意排除:
apply_patch_chunk工具,需模型学会分块协议,投机性强)→ 已开 Linear 单独评估2482359,fix: transfer adapter 把 Codex 0.130+ Responses APItool_search工具 silently drop 导致 MCP server tools 不可用 #288 之前),直接合会回退 tool_search MCP 全链路(fix: transfer adapter 把 Codex 0.130+ Responses APItool_search工具 silently drop 导致 MCP server tools 不可用 #288/fix(#288): transfer adapter 识别 Codex 0.130+ tool_search 不再 silently drop (MOC-32 PR-1) #289/fix(#288 PR-2): warn_once_drop_tool first-N + counter (stacked on PR-1) #290/fix(#288): 打通 Codex 0.130+ tool_search MCP 工具全链路 (PR-3) #293/chore(MOC-48): tool_search 工具链 observability 加固 + README 兼容矩阵 #296)+ 重复 fix(#302): apply_patch chat-path 非破坏性信封修复 #303;本 PR 重新基于 main,不回退任何东西TruncationInfostruct 简化为Option<String>返回(原level字段从未被读,去掉避免 dead_code)验证
Refs MOC-57, #321, #302
🤖 Generated with Claude Code