feat: add the ACP diff patch capability - #530
Open
nikita-ashihmin wants to merge 2 commits into
Open
nikita-ashihmin wants to merge 2 commits into
nikita-ashihmin wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
One critical and six moderate correctness issues remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Implements the AIR tool-call contract, sparse field reporting, exact Git patches, and improved tool/subagent lifecycle handling while preserving non-AIR compatibility.
Changes:
- Adds capability-aware tool reporters and AIR-specific metadata/rendering.
- Adds exact Git patch and plan-delta support.
- Expands protocol, lifecycle, replay, buffering, and scenario coverage.
Unresolved findings:
- Critical (1 vote):
src/CodexAcpServer.ts:2297must force terminal status when replaying history. - Moderate (2 votes):
src/GitPatch.ts:103accepts malformed no-newline markers. - Moderate (1 vote):
src/ToolCallReportingConnection.ts:49does not restore full permission-call fields after cancellation. - Moderate (1 vote):
src/ToolCallReportingConnection.ts:41repeats unchanged permission-call fields. - Moderate (1 vote):
src/subagents/PendingNotificationBuffer.ts:34undercounts JSON-escaped buffered bytes. - Moderate (1 vote):
src/tool-calls/reporters/FileChangeReporter.ts:110drops pure renames with empty patches. - Moderate (1 vote):
src/tool-calls/reporters/ImageGenerationReporter.ts:61duplicates images for non-AIR clients. - Nit (1 vote):
README.md:17incorrectly presents the AIR-only shape as universal.
| File | Reviewed change |
|---|---|
src/ToolCallReportingConnection.ts |
Filters changed fields; two permission-flow issues remain. |
src/tool-calls/ToolFacts.ts |
Defines normalized tool facts. |
src/tool-calls/reporters/WebSearchReporter.ts |
Reports web searches. |
src/tool-calls/reporters/ToolStatus.ts |
Maps tool statuses. |
src/tool-calls/reporters/SubagentActivityReporter.ts |
Reports subagent activity. |
src/tool-calls/reporters/SandboxPermissionReporter.ts |
Reports sandbox permissions. |
src/tool-calls/reporters/PlanReviewReporter.ts |
Reports plan reviews. |
src/tool-calls/reporters/McpToolReporter.ts |
Reports MCP tools. |
src/tool-calls/reporters/McpStartupReporter.ts |
Reports MCP startup. |
src/tool-calls/reporters/ImageViewReporter.ts |
Reports viewed images. |
src/tool-calls/reporters/ImageGenerationReporter.ts |
Reports generated images; non-AIR duplication remains. |
src/tool-calls/reporters/GuardianReporter.ts |
Reports guardian reviews. |
src/tool-calls/reporters/FuzzySearchReporter.ts |
Reports fuzzy searches. |
src/tool-calls/reporters/ElicitationReporter.ts |
Reports elicitation requests. |
src/tool-calls/reporters/DynamicToolReporter.ts |
Reports dynamic tools. |
src/tool-calls/reporters/CompactionReporter.ts |
Reports context compaction. |
src/tool-calls/reporters/CollabAgentReporter.ts |
Reports collaborative agents. |
src/tool-calls/ClientCapabilities.ts |
Centralizes client capabilities. |
src/TerminalOutputMode.ts |
Removes superseded output capability handling. |
src/subagents/PendingNotificationBuffer.ts |
Buffers notifications; encoded-size accounting remains incorrect. |
src/subagents/CodexSubagentEventRouter.ts |
Routes and cleans up subagent events. |
src/PlanCapabilities.ts |
Removes superseded plan capabilities. |
src/permissions/presentation.ts |
Updates permission presentation. |
src/permissions/plan-review.ts |
Updates plan-review permissions. |
src/permissions/metadata.ts |
Namespaces permission metadata. |
src/permissions/mcp.ts |
Updates MCP permissions. |
src/permissions/lifecycle.ts |
Updates permission lifecycle handling. |
src/permissions/CodexApprovalHandler.ts |
Integrates approval reporting. |
src/DiffStats.ts |
Removes replaced diff statistics. |
src/ContextCompactionMeta.ts |
Reshapes compaction metadata. |
src/ContentChunks.ts |
Gates AIR content metadata. |
src/CodexPlanStream.ts |
Streams capability-aware plan deltas. |
src/CodexElicitationHandler.ts |
Integrates elicitation reporting. |
src/CodexCommands.ts |
Namespaces AIR command actions. |
src/AirExtension.ts |
Defines AIR negotiation and metadata. |
src/AgentMode.ts |
Gates AIR mode metadata. |
src/__tests__/ToolCallReportingConnection.test.ts |
Tests filtering and cancellation. |
src/__tests__/TerminalOutputMode.test.ts |
Updates terminal-output tests. |
src/__tests__/scenarios/data/zed/mcp-elicitation.json |
Updates Zed elicitation snapshot. |
src/__tests__/scenarios/data/zed/goal-update.json |
Updates Zed goal snapshot. |
src/__tests__/scenarios/data/plain/plan-stream.json |
Updates plain plan snapshot. |
src/__tests__/scenarios/data/plain/mcp-elicitation.json |
Updates plain elicitation snapshot. |
src/__tests__/scenarios/data/plain/goal-update.json |
Updates plain goal snapshot. |
src/__tests__/scenarios/acp-schema.ts |
Validates outbound ACP messages. |
src/__tests__/PendingNotificationBuffer.test.ts |
Tests notification buffering. |
src/__tests__/GitPatch.test.ts |
Tests Git patch generation. |
src/__tests__/DiffStats.test.ts |
Updates diff-related tests. |
src/__tests__/CodexPlanStream.test.ts |
Tests plan streaming profiles. |
src/__tests__/CodexACPAgent/turn-diff-events.test.ts |
Tests turn diff events. |
src/__tests__/CodexACPAgent/thread-goal-events.test.ts |
Tests goal events. |
src/__tests__/CodexACPAgent/terminal-output-events.test.ts |
Tests terminal output events. |
src/__tests__/CodexACPAgent/session-compaction.test.ts |
Tests session compaction. |
src/__tests__/CodexACPAgent/response-item-history-fallback.test.ts |
Tests history fallback. |
src/__tests__/CodexACPAgent/plan-review-events.test.ts |
Tests plan-review events. |
src/__tests__/CodexACPAgent/plan-events.test.ts |
Tests plan events. |
src/__tests__/CodexACPAgent/load-session.test.ts |
Tests session loading. |
src/__tests__/CodexACPAgent/initialize.test.ts |
Tests capability initialization. |
src/__tests__/CodexACPAgent/fuzzy-file-search-events.test.ts |
Tests fuzzy-search events. |
src/__tests__/CodexACPAgent/elicitation-events.test.ts |
Tests elicitation events. |
src/__tests__/CodexACPAgent/data/web-search-start-and-complete.json |
Covers web-search lifecycle. |
src/__tests__/CodexACPAgent/data/web-search-action-titles.json |
Covers web-search titles. |
src/__tests__/CodexACPAgent/data/view-image-flow.json |
Covers image viewing. |
src/__tests__/CodexACPAgent/data/tool-call-dynamic-names.json |
Covers dynamic tool names. |
src/__tests__/CodexACPAgent/data/tool-call-completed-name.json |
Covers completed tool names. |
src/__tests__/CodexACPAgent/data/tool-call-command-names.json |
Covers command names. |
src/__tests__/CodexACPAgent/data/thread-goal-updated.json |
Covers goal updates. |
src/__tests__/CodexACPAgent/data/thread-goal-updated-multiline.json |
Covers multiline goals. |
src/__tests__/CodexACPAgent/data/thread-goal-cleared.json |
Covers cleared goals. |
src/__tests__/CodexACPAgent/data/terminal-output-parsed-command-legacy-delta.json |
Covers legacy terminal deltas. |
src/__tests__/CodexACPAgent/data/terminal-interaction-stdin.json |
Covers terminal input. |
src/__tests__/CodexACPAgent/data/terminal-command-failed.json |
Covers failed commands. |
src/__tests__/CodexACPAgent/data/terminal-command-completed.json |
Covers completed commands. |
src/__tests__/CodexACPAgent/data/session-notices-replay.json |
Covers notice replay. |
src/__tests__/CodexACPAgent/data/session-compaction-legacy.json |
Covers legacy compaction. |
src/__tests__/CodexACPAgent/data/response-item-history-tool-names.json |
Covers history tool names. |
src/__tests__/CodexACPAgent/data/plan-deltas.json |
Covers plan deltas. |
src/__tests__/CodexACPAgent/data/plan-delta-fallback.json |
Covers plan-delta fallback. |
src/__tests__/CodexACPAgent/data/plan-completed-fallback.json |
Covers completed-plan fallback. |
src/__tests__/CodexACPAgent/data/mcp-tool-repeated-progress.json |
Covers repeated MCP progress. |
src/__tests__/CodexACPAgent/data/mcp-tool-completed-with-logs.json |
Covers MCP completion logs. |
src/__tests__/CodexACPAgent/data/load-session-response-item-history-fallback.json |
Covers loaded history fallback. |
src/__tests__/CodexACPAgent/data/load-session-history.json |
Covers loaded session history. |
src/__tests__/CodexACPAgent/data/image-generation-flow.json |
Covers image-generation lifecycle. |
src/__tests__/CodexACPAgent/data/image-generation-completed-only.json |
Covers completion-only image generation. |
src/__tests__/CodexACPAgent/data/guardian-approval-review-flow.json |
Covers guardian review flow. |
src/__tests__/CodexACPAgent/data/guardian-approval-review-completed-without-start.json |
Covers completion-only guardian review. |
src/__tests__/CodexACPAgent/data/file-change-delete-raw-content.json |
Covers deletion from raw content. |
src/__tests__/CodexACPAgent/data/file-change-delete-file.json |
Covers file deletion. |
src/__tests__/CodexACPAgent/data/file-change-add-raw-content.json |
Covers addition from raw content. |
src/__tests__/CodexACPAgent/data/file-change-add-new-file.json |
Covers new files. |
src/__tests__/CodexACPAgent/data/file-change-add-multiple-files.json |
Covers multiple file additions. |
src/__tests__/CodexACPAgent/data/elicitation-url-accept.json |
Covers accepted URL elicitation. |
src/__tests__/CodexACPAgent/data/elicitation-tool-approval-session-only.json |
Covers session-only approval. |
src/__tests__/CodexACPAgent/data/elicitation-tool-approval-no-persist.json |
Covers non-persisted approval. |
src/__tests__/CodexACPAgent/data/elicitation-tool-approval-all-persist.json |
Covers persisted approval. |
src/__tests__/CodexACPAgent/data/dynamic-tool-in-progress.json |
Covers active dynamic tools. |
src/__tests__/CodexACPAgent/data/dynamic-tool-completed.json |
Covers completed dynamic tools. |
src/__tests__/CodexACPAgent/data/context-compaction-lifecycle.json |
Covers compaction lifecycle. |
src/__tests__/CodexACPAgent/data/command-search-with-query-only.json |
Covers query-only search. |
src/__tests__/CodexACPAgent/data/command-search-with-query-and-path.json |
Covers scoped query search. |
src/__tests__/CodexACPAgent/data/command-search-with-path-only.json |
Covers path-only search. |
src/__tests__/CodexACPAgent/data/command-search-no-query-no-path.json |
Covers empty search parameters. |
src/__tests__/CodexACPAgent/data/command-read-file-with-path.json |
Covers file reads. |
src/__tests__/CodexACPAgent/data/command-list-files-without-path.json |
Covers unscoped file listing. |
src/__tests__/CodexACPAgent/data/command-list-files-with-path.json |
Covers scoped file listing. |
src/__tests__/CodexACPAgent/data/available-commands-skills.json |
Covers skill commands. |
src/__tests__/CodexACPAgent/data/available-commands-build-in.json |
Covers built-in commands. |
src/__tests__/CodexACPAgent/data/agent-message-phases.json |
Covers message phases. |
src/__tests__/CodexACPAgent/collab-agent-events.test.ts |
Tests collaborative-agent events. |
src/__tests__/CodexACPAgent/CodexAcpClient.test.ts |
Tests ACP client behavior. |
src/__tests__/CodexACPAgent/auth-status.test.ts |
Tests authentication status. |
src/__tests__/CodexACPAgent/auth-error-events.test.ts |
Tests authentication errors. |
src/__tests__/CodexACPAgent/approval-events.test.ts |
Tests approval events. |
src/__tests__/CodexACPAgent/agent-file-change-report.test.ts |
Tests file-change reports. |
src/__tests__/AirExtension.test.ts |
Tests AIR negotiation. |
src/__tests__/acp-test-utils.ts |
Updates shared test utilities. |
README.md |
Documents AIR features; wording overstates their scope. |
readme-dev.md |
Removes obsolete diff-statistics guidance. |
package.json |
Adds schema-validation support. |
package-lock.json |
Locks dependency changes. |
docs/subagent-sessions.md |
Updates subagent documentation. |
docs/session-compaction.md |
Updates compaction documentation. |
docs/recommended-config-values-extension.md |
Removes superseded documentation. |
docs/goal-extension.md |
Removes superseded documentation. |
docs/diff-statistics-extension.md |
Removes replaced documentation. |
docs/async-tasks.md |
Removes superseded documentation. |
docs/agent-file-change-report.md |
Removes superseded documentation. |
CHANGELOG.md |
Removes the obsolete diff-statistics entry. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| return [renderer.render(ImageViewReporter.viewed(item))]; | ||
| case "imageGeneration": | ||
| return [createImageGenerationUpdate(item)]; | ||
| return [renderer.render(ImageGenerationReporter.whole(item))]; |
Send compact Git patches when both the client and the adapter advertise diffPatch. Keep the standard diff text fields for a client without the capability. The patch builders: - strip the leading slash of an absolute path, so a header reads a/workspace/App.ts and not a//workspace/App.ts; - quote a path that Git quotes; - add rename from and rename to headers and use the target path; - replace the file headers that Codex supplied, so that all headers agree; - add new file mode and deleted file mode headers; - keep carriage returns and mark a missing final newline. A patch is built only when it has at least one valid hunk, holds no binary content and is at most 1 MiB. Otherwise the adapter sends the standard diff with the file texts. This covers an empty file, a pure rename and malformed Codex hunks. Before, the adapter dropped the change when the diff did not parse. The legacy already-patched branch now reports the move target path. Stop sending the ACP diff statistics. A client can derive the line counts from a negotiated patch or from the standard diff texts. The diff statistics contract and its documentation are removed. docs/diff-patch-extension.md describes the negotiation, the patch metadata, the placeholder text fields, the header paths and quoting, the file mode and rename headers, the kept bytes, the final newline marker and every fallback case.
nikita-ashihmin
force-pushed
the
nikita.ashikhmin/acp-patch-content
branch
from
September 23, 2026 11:48
21b4f35 to
34a3d5c
Compare
The hunk validator accepted every line that starts with a backslash. A hunk with such a line then went to the client as a valid patch. Now the validator accepts only the exact "\ No newline at end of file" line that Git writes. Any other backslash line makes the hunks invalid. The adapter then sends the standard ACP diff.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Multiple moderate patch-validation and pure-rename handling issues remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (3)
Resolved since last review (1)
Comment on lines
+882
to
+885
| const patch = parseSinglePatch(unifiedDiff); | ||
| if (patch === null) { | ||
| logger.log("Skipped a file change whose diff has no single valid patch", {path: change.path}); | ||
| return null; |
Comment on lines
+83
to
+86
| const header = HUNK_HEADER.exec(hunks[index]!); | ||
| if (header === null) return null; | ||
| let oldLines = header[1] === undefined ? 1 : Number(header[1]); | ||
| let newLines = header[2] === undefined ? 1 : Number(header[2]); |
This branch has not been deployed
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.


Summary
Step 1 of 3 of the AIR tool call stack. This PR is only the diff patch capability.
diffPatchAIR capability, and send a file change as one compact Git patch only when the client declares it.src/GitPatch.ts): paths and quoting, rename headers, file modes, CRLF, a missing final newline. The standard diff is used for binary, empty, over-1-MiB, or unparseable changes.diffPatchkeep the standardoldText/newTextdiff.Next steps: #544 (tool call contract and fixes for every client), #545 (scenario tests).
Tests
npm run typecheck,npm test: 751 passed.