fix(acp): keep agent-native tool calls out of dispatch correlation - #2387
Conversation
|
@dosenr This PR is a Bug fix, Feature, or UI / frontend change but the Demo section is missing or only contains a placeholder. These change types require a screenshot or screen recording so reviewers can see the new behaviour without checking out the branch. Please update the Demo section with:
Use |
|
Pushed |
|
Status update:
|
fdbef2e to
ee1bf0d
Compare
|
ee1bf0d to
f3336a6
Compare
|
@fanzeyi - rebased onto current main (b06722c) same change, one commit, 4 files. I double checked the original issue still reproduces on that base, so the fix is still needed, and have been running it daily in my deployment for weeks. Executor and adapter suites are green on the new head, including a new interleaving test that pins the exact mis-correlation this fixes. |
f3336a6 to
05e7ed2
Compare
|
Rebased onto current main. Clean rebase, nothing hand-resolved, and the commit is unchanged from the previous head. Same fix you approved in July, just carried forward. Still needed on today's main: without the fix, the PR's own tests fail 9 of 99. I also re-ran a live Hermes ACP turn on the new head, one native call plus one bridge call in the same turn, and each keeps its own call ID. Numbers, all from commands on the rebased head |
05e7ed2 to
0df7efd
Compare
An ACP agent reports its own internal tools and Omnigent's MCP bridge tools through the same tool_call session update. The executor stamped every one alike, so a native call's id sat in the adapter's dispatch correlation queue and the next bridge completion popped it, attaching to the wrong card. Snapshot the tool names advertised at session/new, and classify each tool_call against that set. Only a bridge call takes a correlation slot; anything else is marked internally_executed, which the adapter already honors. An unrecognized shape reads as native, which can duplicate a card but cannot corrupt dispatch. Also reset per-session tool state when a session is respawned, so a "Session not found" retry does not classify against tools the new session never got. Closes omnigent-ai#4594. Signed-off-by: Robert Dosen <robert.dosen@gmail.com> Signed-off-by: Dhruv Gupta <dhruv0811@gmail.com> Co-authored-by: Isaac <no-reply@databricks.com>
0df7efd to
da0809e
Compare
|
Maintainer takeover. I rebased this onto current The bug is still real on today's main: a native ACP What landed on main since your last rebase:
Resolving the conflict by keeping both sides would have shipped two metadata keys for one concept, two argument caches, and two durable-card emitters, which means a duplicate card for every observed call. So I dropped the adapter changes entirely and re-pointed the classification at main's existing Net: 4 files / +350 −19 becomes 2 files / +82 −17 plus tests. The design, the wire shapes (including the nested Goose Tests: the classification coverage now lives in Two notes for reviewers:
|
|
|
🏷️ Doc impact: Internal fix to ACP executor tool-call classification (agent-native vs MCP-bridge dispatch correlation) with tests; no user-facing surface, integration, or documented behavior changed. Auto-classified on merge. Set the label manually before merging to override. · run |
…mnigent-ai#2387) An ACP agent reports its own internal tools and Omnigent's MCP bridge tools through the same tool_call session update. The executor stamped every one alike, so a native call's id sat in the adapter's dispatch correlation queue and the next bridge completion popped it, attaching to the wrong card. Snapshot the tool names advertised at session/new, and classify each tool_call against that set. Only a bridge call takes a correlation slot; anything else is marked internally_executed, which the adapter already honors. An unrecognized shape reads as native, which can duplicate a card but cannot corrupt dispatch. Also reset per-session tool state when a session is respawned, so a "Session not found" retry does not classify against tools the new session never got. Closes omnigent-ai#4594. Signed-off-by: Robert Dosen <robert.dosen@gmail.com> Signed-off-by: Dhruv Gupta <dhruv0811@gmail.com> Co-authored-by: Isaac <no-reply@databricks.com> Co-authored-by: dosenr <robert.dosen@gmail.com>
Related issue
Closes #4594. Extracted from review of #2211 (#2211 (comment)), which depends on this change and remains parked as a conflicting draft.
Summary
ACP agents report both agent-native tools and Omnigent MCP bridge tools through the same
tool_callupdate. Treating every update as bridge dispatch state leaves a native call in the correlation queue, so the next bridge completion can attach to the wrong card. Native cards also disappear after reload because only their initial, in-progress item was emitted.This change snapshots the exact bridge aliases advertised at
session/new. Only calls matching that immutable set enter dispatch correlation. Other calls are markedself_executed, retain their arguments through completion, and emit a durable completed card.ELI5: ACP has two tool lanes. This keeps native tools in the display lane and MCP tools in the dispatch lane.
Unknown shapes fail closed as self-executed. They may render a duplicate card, but cannot poison a later bridge dispatch.
Test Plan
uv run pytest tests/inner/test_acp_executor.py tests/runtime/harnesses/test_executor_adapter.py -q: 83 passed.uv run pre-commit run --all-files: passed on current main40fa33f7.tests/inner/andtests/runtime/, excluding two unavailable optional-dependency collection modules: 548 passed, 26 skipped, 6 failed. The same six tests and pytest plugin error reproduce on unmodified40fa33f7.ee1bf0d6: the bridge tool dispatched once; its humanized request and completion shared the same call ID; no event was marked self-executed.Seven focused test functions cover native and bridge wire shapes, the nested Goose
_meta.goose.toolCall.toolNameshape, foreign-server collisions, no-advertised-bridge behavior, immutable session snapshots, session cleanup, durable native completion, and a mixed native-to-bridge dispatch sequence. This replaces the previous roughly 20-function, 680-line proof package with 221 added test lines.Demo
Real Goose 1.41 bridge turn on this commit:
The screenshot is a genuine Hermes native-plus-bridge turn from the earlier stacked branch. The final commits were revalidated by direct ACP turns; the UI event shape is unchanged.
Type of change
Test coverage
Coverage notes
Manual verification covers real Goose bridge dispatch and a stacked Hermes native-plus-bridge turn. Goose ACP did not expose an agent-native tool in this configuration, so native classification is covered live by Hermes and deterministically by the generic tests.
Changelog
Agent-native ACP tool cards persist without mis-pairing the next MCP tool dispatch.