From 73b3271c83967c5144903803ef404df8b6a42fef Mon Sep 17 00:00:00 2001 From: Adam Weidman Date: Sun, 19 Apr 2026 17:08:40 -0400 Subject: [PATCH 1/4] fix(core): remove duplicate initialize call on agents refreshed --- packages/core/src/config/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index 01c6fd7bfd6..dd38a4105f7 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -3804,7 +3804,7 @@ export class Config implements McpContext, AgentLoopContext { } private onAgentsRefreshed = async () => { - await this.agentRegistry.initialize(); + // Removed to prevent duplicate calls to loadAgents during reload // Propagate updates to the active chat session const client = this.geminiClient; From 863a9479629e4344564ccd77cddffefdd0146759 Mon Sep 17 00:00:00 2001 From: Adam Weidman Date: Sun, 19 Apr 2026 17:12:53 -0400 Subject: [PATCH 2/4] cleanup(core): remove temporary comment in onAgentsRefreshed --- packages/core/src/config/config.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index dd38a4105f7..a1fc634448f 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -3804,8 +3804,6 @@ export class Config implements McpContext, AgentLoopContext { } private onAgentsRefreshed = async () => { - // Removed to prevent duplicate calls to loadAgents during reload - // Propagate updates to the active chat session const client = this.geminiClient; if (client?.isInitialized()) { From 82a7ef0cb374b84d664a4fc701dd900bb9ae9ffa Mon Sep 17 00:00:00 2001 From: Adam Weidman Date: Mon, 20 Apr 2026 00:09:13 -0400 Subject: [PATCH 3/4] fix(core): correctly trigger agent registry reload in tests Replaced the hacky invocation of the private `onAgentsRefreshed` method with the correct public API `getAgentRegistry().reload()` in the config-agents-reload tests. This aligns the tests with the intended architecture where the registry manages its own state and emits an event upon reload, which the Config then reacts to. --- packages/core/src/config/config-agents-reload.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/src/config/config-agents-reload.test.ts b/packages/core/src/config/config-agents-reload.test.ts index 9a9eea3a65b..6f4b9b7fceb 100644 --- a/packages/core/src/config/config-agents-reload.test.ts +++ b/packages/core/src/config/config-agents-reload.test.ts @@ -95,8 +95,8 @@ Test System Prompt`; }); // Trigger the refresh action that follows reloading - // @ts-expect-error accessing private method for testing - await config.onAgentsRefreshed(); + + await config.getAgentRegistry().reload(); // 4. Verify the agent is UNREGISTERED const finalAgents = agentRegistry.getAllDefinitions().map((d) => d.name); @@ -237,8 +237,8 @@ Test System Prompt`; }); // Trigger the refresh action that follows reloading - // @ts-expect-error accessing private method for testing - await config.onAgentsRefreshed(); + + await config.getAgentRegistry().reload(); expect(agentRegistry.getAllDefinitions().map((d) => d.name)).toContain( agentName, From a3d4a63977f32bd88a63eb62d827a509c776de79 Mon Sep 17 00:00:00 2001 From: Adam Weidman Date: Mon, 20 Apr 2026 03:04:42 -0400 Subject: [PATCH 4/4] fix streaming --- packages/core/src/agents/a2aUtils.test.ts | 47 +++++++++++++++++++++++ packages/core/src/agents/a2aUtils.ts | 46 ++++++++++++++-------- 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/packages/core/src/agents/a2aUtils.test.ts b/packages/core/src/agents/a2aUtils.test.ts index f8416ae2ad7..14d9fd061ea 100644 --- a/packages/core/src/agents/a2aUtils.test.ts +++ b/packages/core/src/agents/a2aUtils.test.ts @@ -538,5 +538,52 @@ describe('a2aUtils', () => { expect(output).toContain('Artifact (Data):'); expect(output).not.toContain('Answer from history'); }); + + it('should return message log as activity items', () => { + const reassembler = new A2AResultReassembler(); + + reassembler.update({ + kind: 'status-update', + taskId: 't1', + contextId: 'ctx1', + status: { + state: 'working', + message: { + kind: 'message', + role: 'agent', + parts: [{ kind: 'text', text: 'Message 1' }], + } as Message, + }, + } as unknown as SendMessageResult); + + reassembler.update({ + kind: 'status-update', + taskId: 't1', + contextId: 'ctx1', + status: { + state: 'working', + message: { + kind: 'message', + role: 'agent', + parts: [{ kind: 'text', text: 'Message 2' }], + } as Message, + }, + } as unknown as SendMessageResult); + + const items = reassembler.toActivityItems(); + expect(items).toHaveLength(2); + expect(items[0]).toEqual({ + id: 'msg-0', + type: 'thought', + content: 'Message 1', + status: 'completed', + }); + expect(items[1]).toEqual({ + id: 'msg-1', + type: 'thought', + content: 'Message 2', + status: 'completed', + }); + }); }); }); diff --git a/packages/core/src/agents/a2aUtils.ts b/packages/core/src/agents/a2aUtils.ts index b617082416d..db08fdb8714 100644 --- a/packages/core/src/agents/a2aUtils.ts +++ b/packages/core/src/agents/a2aUtils.ts @@ -124,6 +124,7 @@ export class A2AResultReassembler { private pushMessage(message: Message | undefined) { if (!message) return; + if (message.role === 'user') return; // Skip user messages reflected by server const text = extractPartsText(message.parts, ''); if (text && this.messageLog[this.messageLog.length - 1] !== text) { this.messageLog.push(text); @@ -135,21 +136,36 @@ export class A2AResultReassembler { */ toActivityItems(): SubagentActivityItem[] { const isAuthRequired = this.messageLog.includes(AUTH_REQUIRED_MSG); - return [ - isAuthRequired - ? { - id: 'auth-required', - type: 'thought', - content: AUTH_REQUIRED_MSG, - status: 'running', - } - : { - id: 'pending', - type: 'thought', - content: 'Working...', - status: 'running', - }, - ]; + const items: SubagentActivityItem[] = []; + + if (isAuthRequired) { + items.push({ + id: 'auth-required', + type: 'thought', + content: AUTH_REQUIRED_MSG, + status: 'running', + }); + } + + this.messageLog.forEach((msg, index) => { + items.push({ + id: `msg-${index}`, + type: 'thought', + content: msg.trim(), + status: 'completed', + }); + }); + + if (items.length === 0 && !isAuthRequired) { + items.push({ + id: 'pending', + type: 'thought', + content: 'Working...', + status: 'running', + }); + } + + return items; } /**