Repository navigation
[Compatibility] Nested tools.apply_patch still uses decorated Begin Patch delimiters in code mode #2367
Description
Client or integration
Codex App
Provider or upstream service
xai / grok-4.6 through OpenCodex 2.29.0 (@bitkyc08/opencodex)
OpenCodex version
2.29.0
Endpoint or capability
Codex Desktop code mode: top-level freeform exec -> nested tools.apply_patch(input: string)
Current behaviour
In a Codex Desktop side conversation, the only top-level tool is freeform exec. File edits go through the nested helper await tools.apply_patch(string).
A nested helper call whose first line is *** Begin Patch *** is rejected by Codex before any file is touched:
apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'
The same helper succeeds when the first line is exactly *** Begin Patch with no trailing ***.
This is not the {input:string} JSON wrapper. Passing a raw string that starts with *** Begin Patch works. Passing a decorated *** Begin Patch *** envelope fails even when the rest of the patch is valid.
OpenCodex 2.29.0 does not include src/responses/apply-patch-envelope.ts. Open PR #2310 repairs decorated envelopes for top-level apply_patch custom-tool payloads, and it correctly leaves exec JavaScript byte-identical. Nested tools.apply_patch(...) is host-executed by Codex from inside that JavaScript, so the decorated delimiter never reaches #2310's repair and still fails.
Expected behaviour
Code-mode catalog guidance should tell routed models that nested tools.apply_patch(input) is host-executed and must begin exactly with *** Begin Patch / *** End Patch, with no trailing *** on those lines.
OpenCodex should not rewrite JavaScript inside exec. The nested helper body is Codex-owned. The proxy can only teach the correct delimiter, or repair a top-level apply_patch custom-tool payload as #2310 does.
Minimal redacted request or reproduction
From a Codex Desktop code-mode turn whose catalog lists only exec:
await tools.apply_patch("*** Begin Patch ***\n*** End Patch ***\n");
// rejected: first line of the patch must be '*** Begin Patch'
await tools.apply_patch("*** Begin Patch\n*** End Patch\n");
// accepted by the verifier (empty-patch rejection is a later, unrelated check)Actual response or error
apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'
Upstream documentation
Codex apply_patch grammar requires the first line to be exactly *** Begin Patch (no trailing ***). OpenCodex already documents that for top-level custom tools in src/responses/parser.ts (begin exactly with *** Begin Patch (no trailing *** )). Nested helpers in code mode currently do not inherit that sentence.
https://github.com/lidge-jun/opencodex/blob/dev/src/responses/parser.ts
Related: #2310 repairs decorated top-level envelopes and leaves exec JavaScript untouched. #2111 covered missing exec tool events, not this delimiter mismatch.
Suggested mapping or implementation notes
Add the nested-helper delimiter rule to the shared non-OpenAI code-mode catalog nudge and the Cursor code-mode guidance. Keep exec JavaScript byte-identical. Do not invent an exec-body rewriter.
Additional context and attachments
Live observation was on Codex Desktop with OpenCodex 2.29.0 routing xai/grok-4.6. The nested helper is invoked from V8 isolate JavaScript, not as a top-level custom_tool_call named apply_patch.
Checks
- I searched existing provider and compatibility issues.
- The request and response were redacted.
- The expected behaviour is based on an upstream specification or a concrete client requirement.
Activity
lidge-jun commentedon Aug 22, 2026
리뷰 · 우선순위 56 / 80
설명: 이 이슈는 Codex Desktop 코드 모드에서 중첩
tools.apply_patch가 첫 줄을 장식 Begin Patch 로 쓰면 검증이 파일을 건드리지 않고 거절한다고 말한다. 지금 CURRENTdevHEAD 는5921c20df이다. 이번 시간에 origin/dev 가 ced9a85 에서 여기로 옮겼다. 착지한 코드는 #2309 키로, #2339 구글 서명, #2335 도구 고르기, #2313 리플레이 범위다. #2369 는 문서만. package.json 은 2.27.0 이다. 보고된 버전은 2.29.0, 제공자는 xai / grok-4.6 이다. 재현이 짧다. 장식 첫 줄은 검증 실패이고, 끝 별이 없는 첫 줄은 첫 줄 검사는 통과한다. 빈 패치 거절은 나중 이야기다. 이것은 input JSON 래퍼 문제가 아니다. 문자열 그대로 넣어도 장식만 실패한다. 지금 HEAD 에는 src/responses/apply-patch-envelope.ts 가 없다. 열린 #2310 은 위쪽 apply_patch 커스텀 도구 봉투만 고친다. exec 자바스크립트는 그대로 둔다. 중첩 헬퍼는 Codex 가 V8 안에서 실행하므로 그 수리가 닿지 않는다. 이슈가 그 경계를 정확히 가리킨다. 기대 동작은 카탈로그 안내에 정확한 구분자만 가르치는 것이다. exec 본문 재작성기를 만들지 말라고 했다. 이미 같은 내용의 열린 PR #2368 이 넛지와 Cursor 안내에 그 문장을 넣는다. parser 쪽 위쪽 커스텀 도구 안내와 코드모드 중첩 헬퍼 안내는 다른 길이다. 이 이슈는 후자다. 카탈로그 팁은 Ox Alpha x-preview-f-free + deepseek-v4-flash-vision-exp. Cursor #2334 미연결, #2332 H2 discovery 전용. #2188 사이드카는 이미 dev. 사용자 길이 호환 버그이고 수리가 이미 열려 있어서 56.이슈 본문 재현 - 장식 Begin Patch 는 실패, 정확한 첫 줄은 통과. 빈 패치 거절과 섞지 않았다
src/responses/apply-patch-envelope.ts 없음 - 지금 HEAD 에는 파일이 없다. #2310 이 위쪽만 다룬다
#2310 exec 바이트 동일 - 중첩 헬퍼 본문은 Codex 소유라 프록시가 못 고친다. 이슈의 핵심이다
열린 PR #2368 - 넛지와 Cursor 안내에 구분자 문장을 넣는다. 이 이슈의 제안과 같다
2.29.0 / grok-4.6 / Codex Desktop 코드 모드 - 위쪽 도구 목록이 exec 하나일 때 생긴다
메인테이너의 판단이 필요한 지점
너의 추천
#2368 을 먼저 머지한다. 이 이슈는 그 PR 머지와 라이브 한 턴을 본 뒤에 닫는다. 지금 닫지 말 것. #2310 이 없어도 이 이슈의 핵심은 설명된다. #2210 워치독, #2330 호출 불가 모델, #2316, #2292 와 묶지 않는다. 라벨은 그대로 둔다. 프리뷰 배포가 아니다.
이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Aug 22, 2026
Landed via #2368 at 03d5767