Skip to content

Keep ACP vocabulary out of native tool and image declarations - #2913

Merged
trissim merged 4 commits into
mainfrom
perf/acp-out-of-domain
Oct 23, 2026
Merged

trissim merged 4 commits into
mainfrom
perf/acp-out-of-domain

Conversation

@trissim

@trissim trissim commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Domain tool declarations imported ACP's ToolKind solely to name an action, and native image records lived inside the ACP prompt decoder. Every CLI paid for the schema through those vocabulary imports.

Tool actions are now plain ABC capabilities registered by ToolAction.init_subclass (tool_declaration.py:38-46), composed into tools through their bases. ToolDeclaration.declared_action() reads the C3 MRO, defaulting to OtherAction; FamilyMeta is unchanged. Live ToolStart.kind and the derived ToolTranscript.kind carry the capability class. One AcpToolAction MroDispatch in agent_event_updates.py owns the five SDK literal spellings, used by Core publication and Toad's saved-call reconstruction.

ImageInput and its byte/MIME validation live in image_input.py. Every Core and paired Toad importer moved; image_inputs.py only owns ACP projection and does not re-export the record. Existing tests now expect capability classes for domain values and keep their SDK-string assertions at the ACP output.

Paired Toad dependency

OpenHCSDev/toad#1165 at 5727cccb9 migrates the three image imports and both recorded-tool readers. Core #2913 must land first, then the Toad ratchet must rerun: its current failure at run 40025551025 is TypeErrors +1 in prompt.py, clipboard_image.py and prompt/resource.py because Core main lacks the new image_input module. Toad's workflow resolves Core from its declared source at .github/workflows/ci.yml:42-51. Against this Core checkout, all paired modules import and a saved ReadAction becomes SDK kind read. No compatibility export or CI exception is added.

Storage and source evidence

ToolStart is an in-process observation (agent_events.py:1-5), created at pi_events.py:924 and dispatched through turn_progress.py:269-278 to ACP publication. The stored transcript has tool_name; its action is a property, not a stored field (transcript_events.py:422-423). A sample encoded ToolStartTranscript contains kind=tool_start, tool_call_id, tool_name and raw_input, with no stored action kind. Thus no stored spelling changes.

Existing refactor-audit Package.load parsed 450 production modules and 486 test modules before, and 451 production modules after, with zero parse omissions. The paired Toad scan parsed 288 modules with zero omissions. The inventory covered declarations, action assignments/readers, constructors, annotated image fields and imports. Dynamic dispatch was followed through the existing MroDispatch consumers; the interpreter checked all seven native tool declarations and paired Toad conversion. The independent Codex wire ImageInput declaration is unchanged.

After AST inspection: tool_declaration, agent_events, native_tools, image_input and pi_commands each have 0 absolute acp SDK imports. Remaining production import from image_inputs is acp.py:75 importing prompt_images. acp_kind has 0 hits in src/tests/tools.

The requested literal grep is printed honestly; it still matches the internal ACP failure module, not an SDK import:

src/agent_comms/agent_events.py:14:from .acp_failure import (

No route-lock files are changed.

Importtime at the delivered head

Base 01aa67d versus ff66279, pinned installed core-a02979325 runtime, nice 19, PYTHONPATH set to the checked-out src. One before/after pair per entry, measured consecutively. These are TOTAL lines in milliseconds; elapsed totals vary with machine load. ACP still loads through the reserved controller/CLI dependencies; this change removes the vocabulary edges rather than completing the entire startup target.

Entry Before TOTAL ms After TOTAL ms
agent_comms.cli 1821.949 1599.255
agent_comms.commander.cli 1797.037 1686.35
agent_comms.cli_bridges.claude 2103.284 1374.855

agent_comms.cli

acp(311) <- acp.exceptions(311) <- agent_comms.cli_commands(1379) <- agent_comms.cli(1594)
agent_comms.tool_declaration(6) <- agent_comms.native_tools(59) <- agent_comms.threads(283) <- agent_comms.input_disposition(294) <- agent_comms.goal_actions(508) <- agent_comms.registration(513) <- agent_comms.historical_views(523) <- agent_comms.message_bus(736) <- agent_comms.cli_commands(1379) <- agent_comms.cli(1594)
agent_comms.agent_events(37) <- agent_comms.pi_payloads(77) <- agent_comms.native_entries(115) <- agent_comms.native_transcript(129) <- agent_comms.external_transcript(135) <- agent_comms.unstarted_runtime(136) <- agent_comms.session_file(140) <- agent_comms.threads(283) <- agent_comms.input_disposition(294) <- agent_comms.goal_actions(508) <- agent_comms.registration(513) <- agent_comms.historical_views(523) <- agent_comms.message_bus(736) <- agent_comms.cli_commands(1379) <- agent_comms.cli(1594)

agent_comms.commander.cli

acp(254) <- acp.schema(254) <- agent_comms.controller(254) <- agent_comms.input_origin(257) <- agent_comms.input_attempt(262) <- agent_comms.acp_failure(333) <- agent_comms.agent_events(353) <- agent_comms.pi_events(538) <- agent_comms.plan_phases(573) <- agent_comms.heartbeat_frame(614) <- agent_comms.commander_heartbeat(812) <- agent_comms.commander.standing(1129) <- agent_comms.commander.order(1475) <- agent_comms.commander.cli(1681)
agent_comms.tool_declaration(5) <- agent_comms.pi_payloads(58) <- agent_comms.acp_failure(333) <- agent_comms.agent_events(353) <- agent_comms.pi_events(538) <- agent_comms.plan_phases(573) <- agent_comms.heartbeat_frame(614) <- agent_comms.commander_heartbeat(812) <- agent_comms.commander.standing(1129) <- agent_comms.commander.order(1475) <- agent_comms.commander.cli(1681)
agent_comms.agent_events(353) <- agent_comms.pi_events(538) <- agent_comms.plan_phases(573) <- agent_comms.heartbeat_frame(614) <- agent_comms.commander_heartbeat(812) <- agent_comms.commander.standing(1129) <- agent_comms.commander.order(1475) <- agent_comms.commander.cli(1681)

agent_comms.cli_bridges.claude

agent_comms.tool_declaration(6) <- agent_comms.native_tools(51) <- agent_comms.threads(541) <- agent_comms.private_send_rules(544) <- agent_comms.native_input_owner(585) <- agent_comms.agent_activity(589) <- agent_comms.runtime_updates(616) <- agent_comms.cli_bridges.claude(1370)
acp(253) <- acp.schema(253) <- agent_comms.controller(253) <- agent_comms.input_origin(256) <- agent_comms.input_attempt(261) <- agent_comms.acp_failure(277) <- agent_comms.agent_events(298) <- agent_comms.pi_payloads(333) <- agent_comms.native_entries(375) <- agent_comms.native_transcript(389) <- agent_comms.external_transcript(395) <- agent_comms.unstarted_runtime(396) <- agent_comms.session_file(399) <- agent_comms.threads(541) <- agent_comms.private_send_rules(544) <- agent_comms.native_input_owner(585) <- agent_comms.agent_activity(589) <- agent_comms.runtime_updates(616) <- agent_comms.cli_bridges.claude(1370)
agent_comms.agent_events(298) <- agent_comms.pi_payloads(333) <- agent_comms.native_entries(375) <- agent_comms.native_transcript(389) <- agent_comms.external_transcript(395) <- agent_comms.unstarted_runtime(396) <- agent_comms.session_file(399) <- agent_comms.threads(541) <- agent_comms.private_send_rules(544) <- agent_comms.native_input_owner(585) <- agent_comms.agent_activity(589) <- agent_comms.runtime_updates(616) <- agent_comms.cli_bridges.claude(1370)

The direct schema edges from tool_declaration and agent_events are gone; the remaining commander/bridge chain still passes transitively through agent_events -> acp_failure -> input_attempt -> input_origin -> controller. The controller/input_origin dependency was explicitly left for the next cut.

Interpreter and static checks

All seven declarations resolve to the original SDK answers: ReadTool->ReadAction->read; BashTool->ExecuteAction->execute; EditTool/WriteTool/FilePatchTool->EditAction->edit; GrepTool/GlobTool->SearchAction->search. The registry contains five capability declarations, not tool records. The unclassified base resolves to OtherAction.

ImageInput('YQ==', 'image/png') retains {'data': 'YQ==', 'mimeType': 'image/png', 'type': 'image'} and decodes equal. The paired Toad prompt, clipboard and resource modules import; saved ReadAction publishes as read.

Mypy --explicit-package-bases --follow-imports=silent on the six existing declaration/projection modules: 77 -> 73 errors, no file grows. New image_input.py was also checked without errors. Ruff on all 19 touched Core files: 87 -> 67 findings, no file grows. ToolAction is intentionally an ABC marker per the owner decision; it has no fake abstract behavior merely to silence B024. No pytest or other test runs.

Checked module Mypy before Mypy after
src/agent_comms/agent_event_updates.py 1 1
src/agent_comms/agent_events.py 8 8
src/agent_comms/image_inputs.py 0 0
src/agent_comms/native_tools.py 19 15
src/agent_comms/tool_declaration.py 5 5
src/agent_comms/transcript_events.py 44 44

Assumed:

MCP field collision correction

Head 10b3ebb merges origin/main 6b042c7 and renames the capability classmethod to declared_action without changing its body. This avoids CommsCollaborationTool.action, a required MCP field whose name must stay unchanged. All three callers are migrated. The only remaining .action() call is coordinated_runtime.py:132; the declared_action field/assignment grep has no matches. No test runs.

@trissim
trissim marked this pull request as ready for review October 23, 2026 21:21
Copilot AI balanced review requested due to automatic review settings October 23, 2026 21:21

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 was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@trissim
trissim merged commit a2333ca into main Oct 23, 2026
5 of 8 checks passed
trissim added a commit that referenced this pull request Oct 23, 2026
Resolve the test_native_tool_declarations import conflict: keep main's
formatting and import ToolRequest from its tool_request owner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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