Skip to content

fix(agent): finish runner reset when skills_like mode has no tools - #10707

Open
rudycelekli wants to merge 2 commits into
AstrBotDevs:masterfrom
rudycelekli:fix/agent-runner-skills-like-no-tools
Open

rudycelekli wants to merge 2 commits into
AstrBotDevs:masterfrom
rudycelekli:fix/agent-runner-skills-like-no-tools

Conversation

@rudycelekli

@rudycelekli rudycelekli commented Oct 23, 2026 •

Copy link
Copy Markdown

Fixes #10698

ToolLoopAgentRunner.reset() returns early when tool_schema_mode == "skills_like" and the request has no tools (req.func_tool is None/empty). That early return skips everything after the skills_like block:

  • self.run_context.messages is never built, so the system prompt, history and current user message are not sent;
  • self.stats is never created, so the first step() crashes with AttributeError: 'ToolLoopAgentRunner' object has no attribute 'stats'.

self.stats is only assigned at the very end of reset(), and reset() is always awaited before stepping, so this early return is the only way to reach step() without stats. It is hit by any request that ends up with no tools in skills_like mode (for example active replies or sessions where all tools are disabled). Older configs that were migrated still carry tool_schema_mode: "skills_like".

Modifications / 改动点

  • astrbot/core/agent/runners/tool_loop_agent_runner.py: only apply the light/param-only tool schema split when tools are present, instead of returning from reset(). Behavior with tools is unchanged.

  • tests/test_tool_loop_agent_runner.py: regression test for skills_like mode with func_tool=None.

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

Without the fix the new test fails (assert [] == ['system', 'user']); with the fix:

$ uv run pytest tests/test_tool_loop_agent_runner.py -q
61 passed

ruff format / ruff check pass.


Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc. / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above. / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
  • 📚 No WebUI navigation, page structure or labels changed, so no documentation update is needed. / 未改动 WebUI 入口、页面结构或术语,无需更新文档。
  • 🤓 I have ensured that no new dependencies are introduced. / 我确保没有引入新依赖库。
  • 😮 My changes do not introduce malicious code. / 我的更改没有引入恶意代码。

Summary by Sourcery

Complete runner reset initialization for skills_like requests that have no tools.

Bug Fixes:

  • Ensure tool-loop runners fully initialize messages and statistics when skills_like mode receives a request without tools, preventing first-step failures.

Tests:

  • Add regression coverage for no-tool skills_like requests through reset and completion.

Review follow-up (2026-10-26)

Updated both assertions: the runner module now receives a controlled clock (1000 at reset, 1005 at completion), and the test checks exact system/user contents (sys, hello) as well as their roles. The clock stub is local to the runner module rather than replacing the global time module. Full tests/test_tool_loop_agent_runner.py: 61 passed. Whole-repository Ruff lint and format checks pass. Tested under isolated Python 3.13.5 with existing dependencies; hosted Python 3.12 CI remains separate. No live provider calls.

Co-authored-by: Cursor <cursoragent@cursor.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tests/test_tool_loop_agent_runner.py" line_range="696" />
<code_context>
+        pass
+
+    assert runner.done()
+    assert runner.stats.end_time >= runner.stats.start_time
+
+
</code_context>
<issue_to_address>
**Clock rollback flakes completion check**

When the system clock moves backwards between `reset()` and completion, the test compares `end_time` with `start_time` at line 696, so a backward system-clock adjustment between `reset()` and completion makes this assertion fail even when the run completes correctly.

Use a controlled clock in the test or avoid relying on wall-clock ordering for this assertion.
</issue_to_address>

### Comment 2
<location path="tests/test_tool_loop_agent_runner.py" line_range="689" />
<code_context>
+        tool_schema_mode="skills_like",
+    )
+
+    assert [m.role for m in runner.run_context.messages] == ["system", "user"]
+    assert runner.stats.start_time > 0
+
</code_context>
<issue_to_address>
**Prompt contents can be dropped unnoticed**

When the system and user messages are present but their contents are empty, the test checks only role names at line 689, so empty `system` and `user` contents still satisfy the assertion; `MockProvider.text_chat()` does not inspect the messages and returns a final reply, letting the run pass without sending either prompt.

Assert the expected message contents, or verify that the provider receives them.
</issue_to_address>

Sourcery assessment

Approval pending. 2 findings to address first.

Blocking findings: tests/test_tool_loop_agent_runner.py:696, tests/test_tool_loop_agent_runner.py:689


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread tests/test_tool_loop_agent_runner.py Outdated
Comment thread tests/test_tool_loop_agent_runner.py

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sourcery assessment

Approved.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] 开启 active_reply 后必崩:'ToolLoopAgentRunner' object has no attribute 'stats'

1 participant