fix(agent): let subagents recover from tool errors

This commit is contained in:
chengyongru
2026-08-25 11:54:40 +08:00
committed by chengyongru
parent 2e7ebeb1ca
commit 8332c604da
12 changed files with 140 additions and 252 deletions
+22 -10
View File
@@ -450,7 +450,9 @@ class TestSubagentCancellation:
mgr._announce_result.assert_awaited_once()
@pytest.mark.asyncio
async def test_subagent_announces_error_when_tool_execution_fails(self, monkeypatch, tmp_path):
async def test_subagent_announces_success_after_recovering_from_tool_failure(
self, monkeypatch, tmp_path
):
from nanobot.agent.subagent import SubagentManager
from nanobot.bus.queue import MessageBus
from nanobot.providers.base import LLMResponse, ToolCallRequest
@@ -458,10 +460,21 @@ class TestSubagentCancellation:
bus = MessageBus()
provider = MagicMock()
provider.get_default_model.return_value = "test-model"
provider.chat_with_retry = AsyncMock(return_value=LLMResponse(
content="thinking",
tool_calls=[ToolCallRequest(id="call_1", name="list_dir", arguments={"path": "."})],
))
provider.chat_with_retry = AsyncMock(side_effect=[
LLMResponse(
content="first attempt",
tool_calls=[
ToolCallRequest(id="call_1", name="list_dir", arguments={"path": "."})
],
),
LLMResponse(
content="retrying",
tool_calls=[
ToolCallRequest(id="call_2", name="list_dir", arguments={"path": "."})
],
),
LLMResponse(content="recovered after tool failure", tool_calls=[]),
])
mgr = SubagentManager(
workspace=tmp_path,
bus=bus,
@@ -492,11 +505,10 @@ class TestSubagentCancellation:
mgr._announce_result.assert_awaited_once()
args = mgr._announce_result.await_args.args
assert "Completed steps:" in args[3]
assert "- list_dir: first result" in args[3]
assert "Failure:" in args[3]
assert "- list_dir: boom" in args[3]
assert args[5] == "error"
assert args[3] == "recovered after tool failure"
assert args[5] == "ok"
assert calls["n"] == 2
assert provider.chat_with_retry.await_count == 3
@pytest.mark.asyncio
async def test_cancel_by_session_cancels_running_subagent_tool(self, monkeypatch, tmp_path):