Skip to content

Commit 1157b06

Browse files
March-77rohityan
authored andcommitted
fix(a2a): Support instruction providers in cards
Agent cards are static and have no ReadonlyContext, so passing callable instructions into description or example regexes crashes card generation. Include only static strings and leave runtime providers unexecuted. Fixes #6450
1 parent 4b002c4 commit 1157b06

2 files changed

Lines changed: 59 additions & 7 deletions

File tree

src/google/adk/a2a/utils/agent_card_builder.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -350,20 +350,20 @@ def _build_agent_description(agent: BaseNode) -> str:
350350

351351

352352
def _build_llm_agent_description_with_instructions(agent: LlmAgent) -> str:
353-
"""Build agent description including instructions for LlmAgents."""
353+
"""Build agent description including static instructions for LlmAgents."""
354354
description_parts = []
355355

356356
# Add agent description
357357
if agent.description:
358358
description_parts.append(agent.description)
359359

360-
# Add instruction (with pronoun replacement) - only for LlmAgent
361-
if agent.instruction:
360+
# Instruction providers require runtime context, which is unavailable while
361+
# building a static agent card.
362+
if isinstance(agent.instruction, str) and agent.instruction:
362363
instruction = _replace_pronouns(agent.instruction)
363364
description_parts.append(instruction)
364365

365-
# Add global instruction (with pronoun replacement) - only for LlmAgent
366-
if agent.global_instruction:
366+
if isinstance(agent.global_instruction, str) and agent.global_instruction:
367367
global_instruction = _replace_pronouns(agent.global_instruction)
368368
description_parts.append(global_instruction)
369369

@@ -551,8 +551,9 @@ async def _extract_examples_from_agent(
551551
except Exception as e:
552552
logger.warning('Failed to extract examples from tools: %s', e)
553553

554-
# If no example_tool found, try to extract examples from instruction
555-
if agent.instruction:
554+
# Dynamic instructions need runtime context and cannot provide static
555+
# examples for an agent card.
556+
if isinstance(agent.instruction, str) and agent.instruction:
556557
return _extract_examples_from_instruction(agent.instruction)
557558

558559
return None

tests/unittests/a2a/utils/test_agent_card_builder.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from unittest.mock import AsyncMock
1516
from unittest.mock import Mock
1617
from unittest.mock import patch
1718

@@ -322,6 +323,56 @@ async def test_build_succeeds_for_llm_agent(self):
322323
skill_ids = [skill.id for skill in card.skills]
323324
assert "writer" in skill_ids
324325

326+
async def test_build_omits_sync_instruction_provider(self):
327+
"""A static card omits a sync instruction that needs runtime context."""
328+
instruction_provider = Mock(return_value="You use runtime context.")
329+
agent = LlmAgent(
330+
name="provider_agent",
331+
description="Uses runtime instructions.",
332+
instruction=instruction_provider,
333+
)
334+
335+
card = await AgentCardBuilder(agent=agent).build()
336+
337+
assert card.skills[0].description == "Uses runtime instructions."
338+
instruction_provider.assert_not_called()
339+
340+
async def test_build_omits_async_instruction_provider(self):
341+
"""A static card omits an async instruction that needs runtime context."""
342+
instruction_provider = AsyncMock(
343+
return_value="You use async runtime context."
344+
)
345+
agent = LlmAgent(
346+
name="async_provider_agent",
347+
description="Uses async runtime instructions.",
348+
instruction=instruction_provider,
349+
)
350+
351+
card = await AgentCardBuilder(agent=agent).build()
352+
353+
assert card.skills[0].description == "Uses async runtime instructions."
354+
instruction_provider.assert_not_called()
355+
356+
async def test_build_omits_global_instruction_provider(self):
357+
"""A static card omits a global instruction that needs runtime context."""
358+
global_instruction_provider = Mock(
359+
return_value="You use global runtime context."
360+
)
361+
agent = LlmAgent(
362+
name="global_provider_agent",
363+
description="Answers questions.",
364+
instruction="You answer user questions.",
365+
global_instruction=global_instruction_provider,
366+
)
367+
368+
card = await AgentCardBuilder(agent=agent).build()
369+
370+
assert (
371+
card.skills[0].description
372+
== "Answers questions. I answer user questions."
373+
)
374+
global_instruction_provider.assert_not_called()
375+
325376
async def test_build_succeeds_for_workflow_with_llm_agent_node(self):
326377
"""AgentCardBuilder.build succeeds for a Workflow (no sub_agents)."""
327378
writer = LlmAgent(

0 commit comments

Comments
 (0)