Skip to content

feat: add the ACP diff patch capability - #530

Open
nikita-ashihmin wants to merge 2 commits into
mainfrom
nikita.ashikhmin/acp-patch-content
Open

nikita-ashihmin wants to merge 2 commits into
mainfrom
nikita.ashikhmin/acp-patch-content

Conversation

@nikita-ashihmin

@nikita-ashihmin nikita-ashihmin commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Step 1 of 3 of the AIR tool call stack. This PR is only the diff patch capability.

  • Advertise the diffPatch AIR capability, and send a file change as one compact Git patch only when the client declares it.
  • Build valid Git patches (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.
  • Apply the negotiated mode to live and replayed file changes. Clients that do not declare diffPatch keep the standard oldText/newText diff.

Next steps: #544 (tool call contract and fixes for every client), #545 (scenario tests).

Tests

  • npm run typecheck, npm test: 751 passed.

@nikita-ashihmin nikita-ashihmin changed the title feat: add ACP patch content capability feat: AIR tool call contract, exact diff patches, and no duplicated tool call data Sep 23, 2026
@nikita-ashihmin
nikita-ashihmin requested a balanced review from Copilot September 23, 2026 10:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 High severity · 1 Medium severity

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:2297 must force terminal status when replaying history.
  • Moderate (2 votes): src/GitPatch.ts:103 accepts malformed no-newline markers.
  • Moderate (1 vote): src/ToolCallReportingConnection.ts:49 does not restore full permission-call fields after cancellation.
  • Moderate (1 vote): src/ToolCallReportingConnection.ts:41 repeats unchanged permission-call fields.
  • Moderate (1 vote): src/subagents/PendingNotificationBuffer.ts:34 undercounts JSON-escaped buffered bytes.
  • Moderate (1 vote): src/tool-calls/reporters/FileChangeReporter.ts:110 drops pure renames with empty patches.
  • Moderate (1 vote): src/tool-calls/reporters/ImageGenerationReporter.ts:61 duplicates images for non-AIR clients.
  • Nit (1 vote): README.md:17 incorrectly 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.

Comment thread src/CodexAcpServer.ts Outdated
return [renderer.render(ImageViewReporter.viewed(item))];
case "imageGeneration":
return [createImageGenerationUpdate(item)];
return [renderer.render(ImageGenerationReporter.whole(item))];
Comment thread src/GitPatch.ts
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
nikita-ashihmin force-pushed the nikita.ashikhmin/acp-patch-content branch from 21b4f35 to 34a3d5c Compare September 23, 2026 11:48
@nikita-ashihmin nikita-ashihmin changed the title feat: AIR tool call contract, exact diff patches, and no duplicated tool call data feat: add the ACP diff patch capability Sep 23, 2026
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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 High severity · 2 Medium severity

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 thread src/GitPatch.ts
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

No deployments
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.

2 participants