Skip to content

Commit 3c211f7

Browse files
committed
Updates made to allow Orchestrator UI to display which A2A Agent was in charge of putting together the reponse message.
See https://screenshot.googleplex.com/7ZbNPqcLb9GHtuf for demo.
1 parent e330a76 commit 3c211f7

File tree

5 files changed

+53
-7
lines changed

5 files changed

+53
-7
lines changed

a2a_agents/python/adk/samples/orchestrator/agent_executor.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import asyncio
1616
import logging
17+
import json
1718
from typing import List, Optional, override
1819
from google.adk.agents.invocation_context import new_invocation_context_id
1920
from google.adk.events.event_actions import EventActions
@@ -84,6 +85,20 @@ def convert_event_to_a2a_events_and_save_surface_id_to_subagent_name(
8485
)
8586

8687
for a2a_event in a2a_events:
88+
# Try to populate subagent agent card if available.
89+
subagent_card = None
90+
if (active_subagent_name := event.author):
91+
# We need to find the subagent by name
92+
if (subagent := next((sub for sub in invocation_context.agent.sub_agents if sub.name == active_subagent_name), None)):
93+
try:
94+
subagent_card = json.loads(subagent.description)
95+
except Exception:
96+
logger.warning(f"Failed to parse agent description for {active_subagent_name}")
97+
if subagent_card:
98+
if a2a_event.metadata is None:
99+
a2a_event.metadata = {}
100+
a2a_event.metadata["a2a_subagent"] = subagent_card
101+
87102
for a2a_part in a2a_event.status.message.parts:
88103
if (
89104
is_a2ui_part(a2a_part)

samples/client/angular/projects/a2a-chat-canvas/src/lib/components/chat/message/message.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
>
2424
@if (isRoleAgent(role)) {
2525
<agent-header
26-
[agentName]="role.name"
26+
[agentName]="getAgentName(role)"
2727
[agentIconUrl]="role.iconUrl"
2828
[agentThoughts]="agentThoughts()"
2929
[showProgressIndicator]="showProgressIndicator()"

samples/client/angular/projects/a2a-chat-canvas/src/lib/components/chat/message/message.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ export class Message {
3737
/** Service for managing chat interactions. */
3838
private readonly chatService = inject(ChatService);
3939

40+
protected getAgentName(role: UiAgent) {
41+
const rootagentName = role.name;
42+
return role.subagentName ? `${rootagentName} + ${role.subagentName}` : rootagentName;
43+
}
44+
4045
/** Agent thought contents. */
4146
protected readonly agentThoughts = computed(() =>
4247
this.message().contents.filter((content) => containsAgentThought(content)),

samples/client/angular/projects/a2a-chat-canvas/src/lib/services/chat-service.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import { AgentCard, SendMessageSuccessResponse } from '@a2a-js/sdk';
1818
import { PART_RESOLVERS } from '@a2a_chat_canvas/a2a-renderer/tokens';
1919
import { A2A_SERVICE } from '@a2a_chat_canvas/interfaces/a2a-service';
20-
import { UiMessage, UiMessageContent } from '@a2a_chat_canvas/types/ui-message';
20+
import { UiAgent, UiMessage, UiMessageContent } from '@a2a_chat_canvas/types/ui-message';
2121
import { extractA2aPartsFromResponse } from '@a2a_chat_canvas/utils/a2a';
2222
import { extractA2uiDataParts } from '@a2a_chat_canvas/utils/a2ui';
2323
import { convertPartToUiMessageContent } from '@a2a_chat_canvas/utils/ui-message-utils';
@@ -148,6 +148,7 @@ export class ChatService {
148148

149149
this.updateLastMessage((msg) => ({
150150
...msg,
151+
role: this.createRole(response),
151152
contents: [...msg.contents, ...newContents],
152153
status: 'completed',
153154
lastUpdated: new Date().toISOString(),
@@ -246,15 +247,36 @@ export class ChatService {
246247
type: 'ui_message',
247248
id: uuid(),
248249
contextId: this.contextId() ?? '',
249-
role: {
250-
type: 'ui_agent',
251-
name: this.agentCard()?.name ?? 'Agent',
252-
iconUrl: this.agentCard()?.iconUrl ?? 'gemini-color.svg',
253-
},
250+
role: this.createRole(),
254251
contents: [],
255252
status: 'pending',
256253
created: nowTimestamp,
257254
lastUpdated: nowTimestamp,
258255
};
259256
}
257+
258+
/**
259+
* Creates the agent role based on the agent card and the message response if available.
260+
*
261+
* @param response The reponse message received from the agent.
262+
* @returns A new UiAgent object representing the agent that the user is chatting with.
263+
*/
264+
private createRole(response?: SendMessageSuccessResponse): UiAgent {
265+
const rootagentRole: UiAgent = {
266+
type: 'ui_agent',
267+
name: this.agentCard()?.name ?? 'Agent',
268+
iconUrl: this.agentCard()?.iconUrl ?? 'gemini-color.svg',
269+
};
270+
271+
const subagentCard = response?.result?.metadata?.['a2a_subagent'];
272+
if (!subagentCard) {
273+
return rootagentRole;
274+
}
275+
const agentRole: UiAgent = {
276+
...rootagentRole,
277+
subagentName: (subagentCard as AgentCard).name,
278+
}
279+
280+
return agentRole;
281+
}
260282
}

samples/client/angular/projects/a2a-chat-canvas/src/lib/types/ui-message.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export interface UiAgent {
3535
readonly name: string;
3636
/** The URL of the agent's icon. */
3737
readonly iconUrl: string;
38+
/** The display name of the sub-agent. */
39+
readonly subagentName?: string;
40+
/** The URL of the sub-agent's icon. */
41+
readonly subagentIconUrl?: string;
3842
}
3943

4044
/**

0 commit comments

Comments
 (0)