Skip to content

Commit a177fab

Browse files
committed
Test adding the skills instead of just RemoteA2aAgent description
1 parent 2f4f561 commit a177fab

File tree

1 file changed

+120
-9
lines changed

1 file changed

+120
-9
lines changed

src/google/adk/flows/llm_flows/agent_transfer.py

Lines changed: 120 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@
3030
from ._base_llm_processor import BaseLlmRequestProcessor
3131

3232
if typing.TYPE_CHECKING:
33+
from a2a.types import AgentCard
34+
3335
from ...agents import BaseAgent
3436
from ...agents import LlmAgent
37+
from ...agents.remote_a2a_agent import RemoteA2aAgent
3538

3639

3740
class _AgentTransferLlmRequestProcessor(BaseLlmRequestProcessor):
@@ -50,11 +53,11 @@ async def run_async(
5053
if not transfer_targets:
5154
return
5255

53-
llm_request.append_instructions([
54-
_build_target_agents_instructions(
55-
invocation_context.agent, transfer_targets
56-
)
57-
])
56+
# Build instructions asynchronously to support A2A agent card resolution
57+
instructions = await _build_target_agents_instructions(
58+
invocation_context.agent, transfer_targets
59+
)
60+
llm_request.append_instructions([instructions])
5861

5962
transfer_to_agent_tool = FunctionTool(func=transfer_to_agent)
6063
tool_context = ToolContext(invocation_context)
@@ -69,7 +72,102 @@ async def run_async(
6972
request_processor = _AgentTransferLlmRequestProcessor()
7073

7174

75+
def _build_target_agent_info_from_card(
76+
target_agent: RemoteA2aAgent, agent_card: AgentCard
77+
) -> str:
78+
"""Build rich agent info from A2A Agent Card.
79+
80+
Args:
81+
target_agent: The RemoteA2aAgent instance
82+
agent_card: The resolved A2A Agent Card
83+
84+
Returns:
85+
Formatted string with detailed agent information from the card
86+
"""
87+
info_parts = [f'Agent name: {target_agent.name}']
88+
89+
# Use card description if available, fallback to agent description
90+
description = agent_card.description or target_agent.description
91+
if description:
92+
info_parts.append(f'Agent description: {description}')
93+
94+
# Add skills information from the card
95+
if agent_card.skills:
96+
skills_info = []
97+
for skill in agent_card.skills:
98+
skill_desc = f' - {skill.name}'
99+
if skill.description:
100+
skill_desc += f': {skill.description}'
101+
if skill.tags:
102+
skill_desc += f' (tags: {", ".join(skill.tags)})'
103+
skills_info.append(skill_desc)
104+
105+
info_parts.append(f'Agent skills:\n' + '\n'.join(skills_info))
106+
107+
# Add capabilities if available
108+
if agent_card.capabilities:
109+
caps = agent_card.capabilities
110+
cap_info = []
111+
if hasattr(caps, 'streaming') and caps.streaming:
112+
cap_info.append('supports streaming')
113+
if hasattr(caps, 'multimodal') and caps.multimodal:
114+
cap_info.append('supports multimodal input/output')
115+
116+
if cap_info:
117+
info_parts.append(f'Capabilities: {", ".join(cap_info)}')
118+
119+
# Add input/output modes
120+
if agent_card.default_input_modes:
121+
info_parts.append(
122+
f'Input modes: {", ".join(agent_card.default_input_modes)}'
123+
)
124+
if agent_card.default_output_modes:
125+
info_parts.append(
126+
f'Output modes: {", ".join(agent_card.default_output_modes)}'
127+
)
128+
129+
return '\n'.join(info_parts)
130+
131+
132+
async def _build_target_agents_info_async(target_agent: BaseAgent) -> str:
133+
"""Build agent info, using A2A Agent Card if available.
134+
135+
Args:
136+
target_agent: The agent to build info for
137+
138+
Returns:
139+
Formatted string with agent information
140+
"""
141+
from ...agents.remote_a2a_agent import RemoteA2aAgent
142+
143+
# Check if this is a RemoteA2aAgent and ensure it's resolved
144+
if isinstance(target_agent, RemoteA2aAgent):
145+
try:
146+
# Ensure the agent card is resolved
147+
await target_agent._ensure_resolved()
148+
149+
# If we have an agent card, use it to build rich info
150+
if target_agent._agent_card:
151+
return _build_target_agent_info_from_card(
152+
target_agent, target_agent._agent_card
153+
)
154+
except Exception:
155+
# If resolution fails, fall through to default behavior
156+
pass
157+
158+
# Fallback to original behavior for non-A2A agents or if card unavailable
159+
return _build_target_agents_info(target_agent)
160+
161+
72162
def _build_target_agents_info(target_agent: BaseAgent) -> str:
163+
"""Build basic agent info (fallback for non-A2A agents).
164+
165+
Args:
166+
target_agent: The agent to build info for
167+
168+
Returns:
169+
Formatted string with basic agent information
170+
"""
73171
return f"""
74172
Agent name: {target_agent.name}
75173
Agent description: {target_agent.description}
@@ -79,9 +177,18 @@ def _build_target_agents_info(target_agent: BaseAgent) -> str:
79177
line_break = '\n'
80178

81179

82-
def _build_target_agents_instructions(
180+
async def _build_target_agents_instructions(
83181
agent: LlmAgent, target_agents: list[BaseAgent]
84182
) -> str:
183+
"""Build instructions for agent transfer with detailed agent information.
184+
185+
Args:
186+
agent: The current agent
187+
target_agents: List of agents that can be transferred to
188+
189+
Returns:
190+
Formatted instructions string with agent transfer information
191+
"""
85192
# Build list of available agent names for the NOTE
86193
# target_agents already includes parent agent if applicable, so no need to add it again
87194
available_agent_names = [target_agent.name for target_agent in target_agents]
@@ -94,12 +201,16 @@ def _build_target_agents_instructions(
94201
f'`{name}`' for name in available_agent_names
95202
)
96203

204+
# Build agent info asynchronously to support A2A agent card resolution
205+
agent_info_list = []
206+
for target_agent in target_agents:
207+
agent_info = await _build_target_agents_info_async(target_agent)
208+
agent_info_list.append(agent_info)
209+
97210
si = f"""
98211
You have a list of other agents to transfer to:
99212
100-
{line_break.join([
101-
_build_target_agents_info(target_agent) for target_agent in target_agents
102-
])}
213+
{line_break.join(agent_info_list)}
103214
104215
If you are the best to answer the question according to your description, you
105216
can answer it.

0 commit comments

Comments
 (0)