From 76aeb2ee526af38714c23778745bdbefad6c116b Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Fri, 23 Oct 2026 18:24:01 -0400 Subject: [PATCH 1/2] fix(agent): finish runner reset when skills_like mode has no tools Co-authored-by: Cursor --- .../agent/runners/tool_loop_agent_runner.py | 6 ++-- tests/test_tool_loop_agent_runner.py | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/astrbot/core/agent/runners/tool_loop_agent_runner.py b/astrbot/core/agent/runners/tool_loop_agent_runner.py index f8418fe4205..5867d7e59cb 100644 --- a/astrbot/core/agent/runners/tool_loop_agent_runner.py +++ b/astrbot/core/agent/runners/tool_loop_agent_runner.py @@ -301,10 +301,8 @@ async def reset( self.tool_schema_mode = tool_schema_mode self._tool_schema_param_set = None self._skill_like_raw_tool_set = None - if tool_schema_mode == "skills_like": - tool_set = self.req.func_tool - if not tool_set: - return + tool_set = self.req.func_tool + if tool_schema_mode == "skills_like" and tool_set: self._skill_like_raw_tool_set = tool_set light_set = tool_set.get_light_tool_set() self._tool_schema_param_set = tool_set.get_param_only_tool_set() diff --git a/tests/test_tool_loop_agent_runner.py b/tests/test_tool_loop_agent_runner.py index ef8e818bb5c..1c22340c34d 100644 --- a/tests/test_tool_loop_agent_runner.py +++ b/tests/test_tool_loop_agent_runner.py @@ -667,6 +667,35 @@ async def test_normal_completion_without_max_step( assert runner.req.func_tool is not None, "正常完成时工具不应该被禁用" +@pytest.mark.asyncio +async def test_skills_like_mode_without_tools_still_initializes_run( + runner, mock_provider, mock_tool_executor, mock_hooks +): + """skills_like mode with no tools must still build messages and stats.""" + request = ProviderRequest( + prompt="hello", system_prompt="sys", func_tool=None, contexts=[] + ) + + await runner.reset( + provider=mock_provider, + request=request, + run_context=ContextWrapper(context=None), + tool_executor=mock_tool_executor, + agent_hooks=mock_hooks, + streaming=False, + tool_schema_mode="skills_like", + ) + + assert [m.role for m in runner.run_context.messages] == ["system", "user"] + assert runner.stats.start_time > 0 + + async for _ in runner.step_until_done(3): + pass + + assert runner.done() + assert runner.stats.end_time >= runner.stats.start_time + + @pytest.mark.asyncio @pytest.mark.parametrize("streaming", [False, True]) async def test_stats_separate_latest_context_from_cumulative_usage( From 3c8f532efd404be79a44fc4ca0ce0779216ae32d Mon Sep 17 00:00:00 2001 From: Rudy Celekli Date: Mon, 26 Oct 2026 13:24:10 -0400 Subject: [PATCH 2/2] test(agent): pin reset clock and verify prompt contents --- tests/test_tool_loop_agent_runner.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/test_tool_loop_agent_runner.py b/tests/test_tool_loop_agent_runner.py index 1c22340c34d..c90c55897fd 100644 --- a/tests/test_tool_loop_agent_runner.py +++ b/tests/test_tool_loop_agent_runner.py @@ -669,9 +669,14 @@ async def test_normal_completion_without_max_step( @pytest.mark.asyncio async def test_skills_like_mode_without_tools_still_initializes_run( - runner, mock_provider, mock_tool_executor, mock_hooks + runner, mock_provider, mock_tool_executor, mock_hooks, monkeypatch ): """skills_like mode with no tools must still build messages and stats.""" + clock = {"now": 1000.0} + monkeypatch.setattr( + "astrbot.core.agent.runners.tool_loop_agent_runner.time", + SimpleNamespace(time=lambda: clock["now"]), + ) request = ProviderRequest( prompt="hello", system_prompt="sys", func_tool=None, contexts=[] ) @@ -687,13 +692,15 @@ async def test_skills_like_mode_without_tools_still_initializes_run( ) assert [m.role for m in runner.run_context.messages] == ["system", "user"] - assert runner.stats.start_time > 0 + assert [m.content for m in runner.run_context.messages] == ["sys", "hello"] + assert runner.stats.start_time == 1000.0 + clock["now"] = 1005.0 async for _ in runner.step_until_done(3): pass assert runner.done() - assert runner.stats.end_time >= runner.stats.start_time + assert runner.stats.end_time == 1005.0 @pytest.mark.asyncio