Skip to content

fix(MOC-57): apply_patch chat-path 截断检测 + V4A 后验校验(摘自 #321)#322

Merged
Cmochance merged 1 commit into
mainfrom
worktree-moc57-truncation-detect
May 30, 2026
Merged

fix(MOC-57): apply_patch chat-path 截断检测 + V4A 后验校验(摘自 #321)#322
Cmochance merged 1 commit into
mainfrom
worktree-moc57-truncation-detect

Conversation

@Cmochance
Copy link
Copy Markdown
Owner

背景

基于 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 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 逻辑
  • 12 新测试(detect ×4 + validate ×5 + 转义边界 + 端到端 incomplete)

#321 的关系(保留作者贡献)

摘自 @Alpaca233114514 的 PR #321,co-author 已署名。 但只取截断检测/校验精华,有意排除:

验证

Refs MOC-57, #321, #302

🤖 Generated with Claude Code

chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@Cmochance Cmochance force-pushed the worktree-moc57-truncation-detect branch from ae2f784 to 2cdcdcc Compare May 30, 2026 12:46
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@Cmochance Cmochance force-pushed the worktree-moc57-truncation-detect branch from 2cdcdcc to f5445a6 Compare May 30, 2026 12:51
chatgpt-codex-connector[bot]

This comment was marked as resolved.

#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>
@Cmochance Cmochance force-pushed the worktree-moc57-truncation-detect branch from f5445a6 to e4df2a1 Compare May 30, 2026 13:04
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 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".

Comment thread crates/adapters/src/responses/converter.rs
@Cmochance Cmochance closed this May 30, 2026
@Cmochance Cmochance deleted the worktree-moc57-truncation-detect branch May 30, 2026 13:10
@Cmochance Cmochance restored the worktree-moc57-truncation-detect branch May 30, 2026 13:12
@Cmochance Cmochance reopened this May 30, 2026
@Cmochance Cmochance merged commit 5832dfd into main May 30, 2026
10 checks passed
@Cmochance Cmochance deleted the worktree-moc57-truncation-detect branch May 30, 2026 13:35
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
@Cmochance
Copy link
Copy Markdown
Owner Author

致谢 🙏:本 PR(MOC-57)摘自 @Alpaca233114514#321(codex/moc57,apply_patch chat-path complete robust solution),并补充了截断检测 / V4A 后验校验。感谢贡献!

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.

1 participant