fix(agent-to-agent): route A2A replies back to originating session (#2267)
Squash merge of PR #2267 by ddaniels. When an agent group has more than one active session, A2A replies landed in the newest session via findSessionByAgentGroup's ORDER BY created_at DESC. The session that asked the question never saw the answer. Adds origin-aware return-path routing with three layers: 1. Direct return-path: if the reply has in_reply_to, look up the triggering inbound row's source_session_id and route there. 2. Peer-affinity fallback: find the most recent A2A inbound from this peer and use its source_session_id. 3. Legacy fallback: newest active session (pre-migration compat). Container-side: MCP send_message/send_file now thread the current batch's in_reply_to through to outbound rows via current-batch.ts. Also flips our A2A bug-documenting test (#2332) from asserting the broken behavior to asserting the fixed behavior. Co-Authored-By: Doug Daniels <ddaniels888@gmail.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -969,12 +969,10 @@ describe('agent-to-agent routing', () => {
|
||||
expect(JSON.parse(rows[0].content).text).toBe('research this');
|
||||
});
|
||||
|
||||
it('BUG: A2A return path resolves to wrong session when multiple channel sessions exist (#2332)', async () => {
|
||||
it('A2A return path routes to originating session, not newest (#2332)', async () => {
|
||||
// PA has Slack session, then gets wired to Discord (newer session).
|
||||
// Researcher responds to PA. routeAgentMessage calls
|
||||
// resolveSession('ag-pa', null, null, 'agent-shared') which calls
|
||||
// findSessionByAgentGroup — picks newest (Discord) instead of the
|
||||
// Slack session that originated the A2A call.
|
||||
// Researcher responds to PA. With the return-path fix, the reply
|
||||
// routes back to the Slack session (originator) not Discord (newest).
|
||||
const { routeAgentMessage } = await import('./modules/agent-to-agent/agent-route.js');
|
||||
|
||||
const { session: paSlackSession } = resolveSession('ag-pa', 'mg-slack', null, 'shared');
|
||||
@@ -1013,9 +1011,9 @@ describe('agent-to-agent routing', () => {
|
||||
const discordA2a = discordDb.prepare("SELECT * FROM messages_in WHERE channel_type = 'agent'").all();
|
||||
discordDb.close();
|
||||
|
||||
// Document the bug: response lands in Discord (newest) not Slack (origin)
|
||||
expect(discordA2a).toHaveLength(1); // BUG: should be 0
|
||||
expect(slackA2a).toHaveLength(0); // BUG: should be 1
|
||||
// Fixed: response lands in Slack (origin) not Discord (newest)
|
||||
expect(slackA2a).toHaveLength(1);
|
||||
expect(discordA2a).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('BUG: A2A-only session gets null session_routing (#2332)', async () => {
|
||||
|
||||
Reference in New Issue
Block a user