feat(agent): support inline subagent consultation

This commit is contained in:
Xubin Ren
2026-07-24 19:13:51 +08:00
parent 8e4fe9cfaf
commit 3a400e0207
3 changed files with 163 additions and 16 deletions
+65
View File
@@ -19,6 +19,37 @@ def _runtime(provider: MagicMock, model: str = "test-model") -> LLMRuntime:
return LLMRuntime.capture(provider, model, context_window_tokens=128_000)
@pytest.mark.asyncio
async def test_run_inline_returns_result_without_announcement(tmp_path):
"""Inline subagents return directly instead of injecting a follow-up."""
from nanobot.agent.subagent import SubagentManager
from nanobot.bus.queue import MessageBus
provider = MagicMock()
manager = SubagentManager(
workspace=tmp_path,
bus=MessageBus(),
max_tool_result_chars=_MAX_TOOL_RESULT_CHARS,
)
manager.runner.run = AsyncMock(return_value=SimpleNamespace(
stop_reason="done",
final_content="review result",
error=None,
tool_events=[],
))
manager._announce_result = AsyncMock()
result = await manager.run_inline(
task="review this",
session_key="test:c1",
runtime=_runtime(provider),
)
assert result == "review result"
manager._announce_result.assert_not_awaited()
assert manager._task_statuses == {}
@pytest.mark.asyncio
async def test_subagent_exec_tool_receives_allowed_env_keys(tmp_path):
"""allowed_env_keys from ExecToolConfig must be forwarded to the subagent's ExecTool."""
@@ -200,6 +231,40 @@ async def test_spawn_tool_rejects_when_at_concurrency_limit(tmp_path):
await asyncio.gather(*mgr._running_tasks.values(), return_exceptions=True)
@pytest.mark.asyncio
async def test_spawn_tool_waits_for_inline_result():
from nanobot.agent.tools.context import RequestContext, request_context
from nanobot.agent.tools.spawn import SpawnTool
class Manager:
max_concurrent_subagents = 1
def __init__(self):
self.inline = AsyncMock(return_value="review result")
self.spawn = AsyncMock(return_value="started")
def get_running_count(self):
return 0
async def run_inline(self, **kwargs):
return await self.inline(**kwargs)
manager = Manager()
tool = SpawnTool(manager)
runtime = _runtime(MagicMock())
with request_context(RequestContext(
channel="test",
chat_id="c1",
session_key="test:c1",
runtime=runtime,
)):
result = await tool.execute(task="review this", wait=True)
assert result == "review result"
manager.inline.assert_awaited_once()
manager.spawn.assert_not_awaited()
def test_subagent_default_max_concurrent_matches_agent_defaults(tmp_path):
"""Direct SubagentManager construction should use the agent default concurrency limit."""
from nanobot.agent.subagent import SubagentManager