Open the ACP tool-call enums at the wire boundary (M4) - #2198
Closed
SawyerHood wants to merge 1 commit into
Closed
Conversation
ACP's ToolKind is an open enum upstream; a closed zod enum dropped the whole tool_call for one unseen kind, so the call never opened and its completed update merged into nothing. Unknown kind → other (raw value kept on rawKind for the tool slot), unknown status → pending, switch_mode accepted, v2 cancelled → interrupted, null kind/status read as absent, and an unknown content entry is skipped per entry instead of per call. Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Aug 21, 2026
Closed
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.
What was wrong
plugins/provider-acp/src/wire.tsparsed the ACP tool-callkindandstatuswith closed zod enums. ACP'sToolKindis an open enum upstream (#[serde(other)]; the v2 draft addsUnknown(String), an open status, andcancelled), and the v1 schema already hasswitch_mode, which the enum did not list. One unseen value failed the wholetool_callparse, so the call never opened and its latercompletedupdate merged into nothing: the row was lost. The same schema drove the permission request'stoolCall, and a foreigncontententry dropped the call the same way. This is the M4 finding of the ACP tool-reporting spike (a live data-loss bug).What changed
z.preprocessboundary on the tool-call schemas (acpToolCallUpdateEventSchema, the permissiontoolCall) normalizes the enums before validation: an unknownkindparses asotherand the agent's own word survives onrawKind; an unknownstatusparses aspending;nullreads as absent.switch_modeis a known kind (presentation: "Switching mode" /SlidersHorizontal). The v2cancelledstatus is terminal and settles the item asinterrupted.contententries parse one at a time: an entry of an unknown type is skipped, the call keeps the rest.rawKind ?? kindso adeploycall readstool: "deploy", and the merge cache carriesrawKindthrough updates.No grammar change, no wire change to the daemon.
How I verified
wire.test.ts(unknown kind/status,switch_mode+cancelled, null enums, foreign content entry, the permission request path) anddelta-translation.test.ts("keeps a call whose kind the schema does not know": the call now opens under its own kind word and thecompletedupdate closes the same item; acancelledclose isinterrupted). All fail onmain.pnpm exec turbo run typecheck test --filter=bb-plugin-provider-acp: 15 files, 203 tests pass, including the recorded acp-cursor conformance cells.Part of the WS2b ACP stack (kit + plugin-owned agents + ACP tier deletion). This is the bottom layer.