Skip to content

Commit 204faaa

Browse files
committed
fix: pr comments
1 parent 426f411 commit 204faaa

File tree

2 files changed

+85
-20
lines changed

2 files changed

+85
-20
lines changed

src/strands/multiagent/a2a/server.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def __init__(
3232
host: str = "0.0.0.0",
3333
port: int = 9000,
3434
version: str = "0.0.1",
35-
skills: list[AgentSkill] | None,
35+
skills: list[AgentSkill] | None = None,
3636
):
3737
"""Initialize an A2A-compatible agent from a Strands agent.
3838
@@ -58,7 +58,7 @@ def __init__(
5858
agent_executor=StrandsA2AExecutor(self.strands_agent),
5959
task_store=InMemoryTaskStore(),
6060
)
61-
self._agent_skills = skills or self._get_skills_from_tools()
61+
self._agent_skills = skills
6262
logger.info("Strands' integration with A2A is experimental. Be aware of frequent breaking changes.")
6363

6464
@property
@@ -108,7 +108,7 @@ def _get_skills_from_tools(self) -> list[AgentSkill]:
108108
@property
109109
def agent_skills(self) -> list[AgentSkill]:
110110
"""Get the list of skills this agent provides."""
111-
return self._agent_skills
111+
return self._agent_skills if self._agent_skills is not None else self._get_skills_from_tools()
112112

113113
@agent_skills.setter
114114
def agent_skills(self, skills: list[AgentSkill]) -> None:

tests/multiagent/a2a/test_server.py

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from a2a.types import AgentCapabilities, AgentCard
77
from fastapi import FastAPI
88
from starlette.applications import Starlette
9-
109
from strands.multiagent.a2a.server import A2AServer
1110

1211

@@ -16,7 +15,7 @@ def test_a2a_agent_initialization(mock_strands_agent):
1615
mock_tool_config = {"test_tool": {"name": "test_tool", "description": "A test tool"}}
1716
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
1817

19-
a2a_agent = A2AServer(mock_strands_agent, skills=None)
18+
a2a_agent = A2AServer(mock_strands_agent)
2019

2120
assert a2a_agent.strands_agent == mock_strands_agent
2221
assert a2a_agent.name == "Test Agent"
@@ -26,7 +25,6 @@ def test_a2a_agent_initialization(mock_strands_agent):
2625
assert a2a_agent.http_url == "http://0.0.0.0:9000/"
2726
assert a2a_agent.version == "0.0.1"
2827
assert isinstance(a2a_agent.capabilities, AgentCapabilities)
29-
# Should have skills from tools
3028
assert len(a2a_agent.agent_skills) == 1
3129
assert a2a_agent.agent_skills[0].name == "test_tool"
3230

@@ -38,7 +36,6 @@ def test_a2a_agent_initialization_with_custom_values(mock_strands_agent):
3836
host="127.0.0.1",
3937
port=8080,
4038
version="1.0.0",
41-
skills=None,
4239
)
4340

4441
assert a2a_agent.host == "127.0.0.1"
@@ -110,7 +107,7 @@ def test_agent_skills_empty_registry(mock_strands_agent):
110107
# Mock empty tool registry
111108
mock_strands_agent.tool_registry.get_all_tools_config.return_value = {}
112109

113-
a2a_agent = A2AServer(mock_strands_agent, skills=None)
110+
a2a_agent = A2AServer(mock_strands_agent)
114111
skills = a2a_agent.agent_skills
115112

116113
assert isinstance(skills, list)
@@ -123,7 +120,7 @@ def test_agent_skills_with_single_tool(mock_strands_agent):
123120
mock_tool_config = {"calculator": {"name": "calculator", "description": "Performs basic mathematical calculations"}}
124121
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
125122

126-
a2a_agent = A2AServer(mock_strands_agent, skills=None)
123+
a2a_agent = A2AServer(mock_strands_agent)
127124
skills = a2a_agent.agent_skills
128125

129126
assert isinstance(skills, list)
@@ -146,7 +143,7 @@ def test_agent_skills_with_multiple_tools(mock_strands_agent):
146143
}
147144
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
148145

149-
a2a_agent = A2AServer(mock_strands_agent, skills=None)
146+
a2a_agent = A2AServer(mock_strands_agent)
150147
skills = a2a_agent.agent_skills
151148

152149
assert isinstance(skills, list)
@@ -186,7 +183,7 @@ def test_agent_skills_with_complex_tool_config(mock_strands_agent):
186183
}
187184
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
188185

189-
a2a_agent = A2AServer(mock_strands_agent, skills=None)
186+
a2a_agent = A2AServer(mock_strands_agent)
190187
skills = a2a_agent.agent_skills
191188

192189
assert isinstance(skills, list)
@@ -213,7 +210,7 @@ def test_agent_skills_preserves_tool_order(mock_strands_agent):
213210
)
214211
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
215212

216-
a2a_agent = A2AServer(mock_strands_agent, skills=None)
213+
a2a_agent = A2AServer(mock_strands_agent)
217214
skills = a2a_agent.agent_skills
218215

219216
assert len(skills) == 3
@@ -233,9 +230,11 @@ def test_agent_skills_handles_missing_description(mock_strands_agent):
233230
}
234231
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
235232

236-
# This should raise a KeyError during initialization when trying to access missing description
233+
a2a_agent = A2AServer(mock_strands_agent)
234+
235+
# This should raise a KeyError when accessing agent_skills due to missing description
237236
with pytest.raises(KeyError):
238-
A2AServer(mock_strands_agent, skills=None)
237+
_ = a2a_agent.agent_skills
239238

240239

241240
def test_agent_skills_handles_missing_name(mock_strands_agent):
@@ -249,9 +248,11 @@ def test_agent_skills_handles_missing_name(mock_strands_agent):
249248
}
250249
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
251250

252-
# This should raise a KeyError during initialization when trying to access missing name
251+
a2a_agent = A2AServer(mock_strands_agent)
252+
253+
# This should raise a KeyError when accessing agent_skills due to missing name
253254
with pytest.raises(KeyError):
254-
A2AServer(mock_strands_agent, skills=None)
255+
_ = a2a_agent.agent_skills
255256

256257

257258
def test_agent_skills_setter(mock_strands_agent):
@@ -262,9 +263,9 @@ def test_agent_skills_setter(mock_strands_agent):
262263
mock_tool_config = {"test_tool": {"name": "test_tool", "description": "A test tool"}}
263264
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
264265

265-
a2a_agent = A2AServer(mock_strands_agent, skills=None)
266+
a2a_agent = A2AServer(mock_strands_agent)
266267

267-
# Initially should get skills from tools
268+
# Initially should get skills from tools (lazy loaded)
268269
initial_skills = a2a_agent.agent_skills
269270
assert len(initial_skills) == 1
270271
assert initial_skills[0].name == "test_tool"
@@ -293,7 +294,7 @@ def test_get_skills_from_tools_method(mock_strands_agent):
293294
}
294295
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
295296

296-
a2a_agent = A2AServer(mock_strands_agent, skills=None)
297+
a2a_agent = A2AServer(mock_strands_agent)
297298
skills = a2a_agent._get_skills_from_tools()
298299

299300
assert isinstance(skills, list)
@@ -317,7 +318,7 @@ def test_initialization_with_none_skills_uses_tools(mock_strands_agent):
317318

318319
a2a_agent = A2AServer(mock_strands_agent, skills=None)
319320

320-
# Should get skills from tools
321+
# Should get skills from tools (lazy loaded)
321322
skills = a2a_agent.agent_skills
322323
assert len(skills) == 1
323324
assert skills[0].name == "test_tool"
@@ -334,6 +335,70 @@ def test_initialization_with_empty_skills_list(mock_strands_agent):
334335
assert len(skills) == 0
335336

336337

338+
def test_lazy_loading_behavior(mock_strands_agent):
339+
"""Test that skills are only loaded from tools when accessed and no explicit skills are provided."""
340+
mock_tool_config = {"test_tool": {"name": "test_tool", "description": "A test tool"}}
341+
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
342+
343+
# Create agent without explicit skills
344+
a2a_agent = A2AServer(mock_strands_agent)
345+
346+
# Verify that _agent_skills is None initially (not loaded yet)
347+
assert a2a_agent._agent_skills is None
348+
349+
# Access agent_skills property - this should trigger lazy loading
350+
skills = a2a_agent.agent_skills
351+
352+
# Verify skills were loaded from tools
353+
assert len(skills) == 1
354+
assert skills[0].name == "test_tool"
355+
356+
# Verify that _agent_skills is still None (lazy loading doesn't cache)
357+
assert a2a_agent._agent_skills is None
358+
359+
360+
def test_explicit_skills_override_tools(mock_strands_agent):
361+
"""Test that explicitly provided skills override tool-based skills."""
362+
from a2a.types import AgentSkill
363+
364+
# Mock tool registry with tools
365+
mock_tool_config = {"test_tool": {"name": "test_tool", "description": "A test tool"}}
366+
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
367+
368+
# Provide explicit skills
369+
explicit_skills = [AgentSkill(name="explicit_skill", id="explicit_skill", description="An explicit skill", tags=[])]
370+
371+
a2a_agent = A2AServer(mock_strands_agent, skills=explicit_skills)
372+
373+
# Should use explicit skills, not tools
374+
skills = a2a_agent.agent_skills
375+
assert len(skills) == 1
376+
assert skills[0].name == "explicit_skill"
377+
assert skills[0].description == "An explicit skill"
378+
379+
380+
def test_skills_not_loaded_during_initialization(mock_strands_agent):
381+
"""Test that skills are not loaded from tools during initialization."""
382+
# Create a mock that would raise an exception if called
383+
mock_strands_agent.tool_registry.get_all_tools_config.side_effect = Exception("Should not be called during init")
384+
385+
# This should not raise an exception because tools are not accessed during initialization
386+
a2a_agent = A2AServer(mock_strands_agent)
387+
388+
# Verify that _agent_skills is None
389+
assert a2a_agent._agent_skills is None
390+
391+
# Reset the mock to return proper data for when skills are actually accessed
392+
mock_tool_config = {"test_tool": {"name": "test_tool", "description": "A test tool"}}
393+
mock_strands_agent.tool_registry.get_all_tools_config.side_effect = None
394+
mock_strands_agent.tool_registry.get_all_tools_config.return_value = mock_tool_config
395+
396+
# Now accessing skills should work
397+
skills = a2a_agent.agent_skills
398+
assert len(skills) == 1
399+
assert skills[0].name == "test_tool"
400+
401+
337402
def test_public_agent_card_with_custom_skills(mock_strands_agent):
338403
"""Test that public_agent_card includes custom skills."""
339404
from a2a.types import AgentSkill

0 commit comments

Comments
 (0)