Skip to content

Commit a977aa3

Browse files
enjoykumawatxuanyang15
authored andcommitted
fix: handle None state values in skill_toolset after session rewind
Merge #5204 Co-authored-by: Xuan Yang <xygoogle@google.com> COPYBARA_INTEGRATE_REVIEW=#5204 from enjoykumawat:fix/load-skill-tool-none-guard ad027fc PiperOrigin-RevId: 900930037
1 parent d69477f commit a977aa3

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

src/google/adk/tools/skill_toolset.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ async def run_async(
165165
agent_name = tool_context.agent_name
166166
state_key = f"_adk_activated_skill_{agent_name}"
167167

168-
activated_skills = list(tool_context.state.get(state_key, []))
168+
activated_skills = list(tool_context.state.get(state_key) or [])
169169
if skill_name not in activated_skills:
170170
activated_skills.append(skill_name)
171171
tool_context.state[state_key] = activated_skills
@@ -732,7 +732,6 @@ async def run_async(
732732
"error_code": "SKILL_NOT_FOUND",
733733
}
734734

735-
script = None
736735
if file_path.startswith("scripts/"):
737736
script = skill.resources.get_script(file_path[len("scripts/") :])
738737
else:
@@ -845,7 +844,7 @@ async def _resolve_additional_tools_from_state(
845844

846845
agent_name = readonly_context.agent_name
847846
state_key = f"_adk_activated_skill_{agent_name}"
848-
activated_skills = readonly_context.state.get(state_key, [])
847+
activated_skills = readonly_context.state.get(state_key) or []
849848

850849
if not activated_skills:
851850
return []

tests/unittests/tools/test_skill_toolset.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,20 @@ async def test_get_tools(mock_skill1, mock_skill2):
186186
assert isinstance(tools[3], skill_toolset.RunSkillScriptTool)
187187

188188

189+
@pytest.mark.asyncio
190+
async def test_resolve_additional_tools_from_state_none(mock_skill1):
191+
toolset = skill_toolset.SkillToolset([mock_skill1])
192+
193+
# Mock ReadonlyContext
194+
readonly_context = mock.create_autospec(ReadonlyContext, instance=True)
195+
readonly_context.agent_name = "test_agent"
196+
readonly_context.state.get.return_value = None
197+
198+
result = await toolset._resolve_additional_tools_from_state(readonly_context)
199+
200+
assert not result
201+
202+
189203
@pytest.mark.asyncio
190204
async def test_list_skills_tool(
191205
mock_skill1, mock_skill2, tool_context_instance
@@ -238,6 +252,28 @@ async def test_load_skill_run_async(
238252
assert result == expected_result
239253

240254

255+
@pytest.mark.asyncio
256+
async def test_load_skill_run_async_state_none(
257+
mock_skill1, tool_context_instance
258+
):
259+
toolset = skill_toolset.SkillToolset([mock_skill1])
260+
tool = skill_toolset.LoadSkillTool(toolset)
261+
262+
# Mock state to return None for the key
263+
state_key = "_adk_activated_skill_test_agent"
264+
tool_context_instance.state.get.return_value = None
265+
266+
result = await tool.run_async(
267+
args={"skill_name": "skill1"}, tool_context=tool_context_instance
268+
)
269+
270+
assert result["skill_name"] == "skill1"
271+
# Verify that it correctly set the list in state
272+
tool_context_instance.state.__setitem__.assert_called_with(
273+
state_key, ["skill1"]
274+
)
275+
276+
241277
@pytest.mark.asyncio
242278
@pytest.mark.parametrize(
243279
"args, expected_result",

0 commit comments

Comments
 (0)