mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-19 16:12:30 +00:00
fix(tools): isolate plugin runtime state
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
043f0e67f7
commit
23312d683e
@ -99,7 +99,6 @@ class SubagentManager:
|
||||
self._running_tasks: dict[str, asyncio.Task[None]] = {}
|
||||
self._task_statuses: dict[str, SubagentStatus] = {}
|
||||
self._session_tasks: dict[str, set[str]] = {} # session_key -> {task_id, ...}
|
||||
self._tools_cache: ToolRegistry | None = None
|
||||
|
||||
def _subagent_tools_config(self) -> ToolsConfig:
|
||||
"""Build a ToolsConfig scoped for subagent use."""
|
||||
@ -110,9 +109,7 @@ class SubagentManager:
|
||||
)
|
||||
|
||||
def _build_tools(self) -> ToolRegistry:
|
||||
"""Build the subagent tool registry via ToolLoader (cached)."""
|
||||
if self._tools_cache is not None:
|
||||
return self._tools_cache
|
||||
"""Build an isolated subagent tool registry via ToolLoader."""
|
||||
registry = ToolRegistry()
|
||||
ctx = ToolContext(
|
||||
config=self._subagent_tools_config(),
|
||||
@ -120,7 +117,6 @@ class SubagentManager:
|
||||
file_state_store=FileStates(),
|
||||
)
|
||||
ToolLoader().load(ctx, registry, scope="subagent")
|
||||
self._tools_cache = registry
|
||||
return registry
|
||||
|
||||
def set_provider(self, provider: LLMProvider, model: str) -> None:
|
||||
|
||||
@ -79,8 +79,7 @@ class MessageTool(Tool, ContextAware):
|
||||
self._default_channel.set(ctx.channel)
|
||||
self._default_chat_id.set(ctx.chat_id)
|
||||
self._default_message_id.set(ctx.message_id)
|
||||
if ctx.metadata:
|
||||
self._default_metadata.set(ctx.metadata)
|
||||
self._default_metadata.set(dict(ctx.metadata or {}))
|
||||
|
||||
def set_send_callback(self, callback: Callable[[OutboundMessage], Awaitable[None]]) -> None:
|
||||
"""Set the callback for sending messages."""
|
||||
|
||||
@ -28,3 +28,27 @@ async def test_subagent_uses_tool_loader():
|
||||
assert tools.has("glob")
|
||||
assert not tools.has("message")
|
||||
assert not tools.has("spawn")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_subagent_build_tools_isolates_file_read_state(tmp_path):
|
||||
"""Each spawned subagent needs a fresh file-state cache."""
|
||||
(tmp_path / "note.txt").write_text("hello\n", encoding="utf-8")
|
||||
provider = MagicMock(spec=LLMProvider)
|
||||
provider.get_default_model.return_value = "test"
|
||||
sm = SubagentManager(
|
||||
provider=provider,
|
||||
workspace=tmp_path,
|
||||
bus=MessageBus(),
|
||||
model="test",
|
||||
max_tool_result_chars=16_000,
|
||||
)
|
||||
|
||||
first_read = sm._build_tools().get("read_file")
|
||||
second_read = sm._build_tools().get("read_file")
|
||||
|
||||
assert first_read is not second_read
|
||||
assert (await first_read.execute(path="note.txt")).startswith("1| hello")
|
||||
second_result = await second_read.execute(path="note.txt")
|
||||
assert second_result.startswith("1| hello")
|
||||
assert "File unchanged" not in second_result
|
||||
|
||||
@ -91,6 +91,29 @@ async def test_message_tool_inherits_metadata_for_same_target() -> None:
|
||||
assert sent[0].metadata == slack_meta
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_message_tool_clears_metadata_when_context_has_none() -> None:
|
||||
sent: list[OutboundMessage] = []
|
||||
|
||||
async def _send(msg: OutboundMessage) -> None:
|
||||
sent.append(msg)
|
||||
|
||||
tool = MessageTool(send_callback=_send)
|
||||
from nanobot.agent.tools.context import RequestContext
|
||||
tool.set_context(
|
||||
RequestContext(
|
||||
channel="slack",
|
||||
chat_id="C123",
|
||||
metadata={"slack": {"thread_ts": "111.222", "channel_type": "channel"}},
|
||||
),
|
||||
)
|
||||
tool.set_context(RequestContext(channel="slack", chat_id="C123", metadata={}))
|
||||
|
||||
await tool.execute(content="plain reply")
|
||||
|
||||
assert sent[0].metadata == {}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_message_tool_does_not_inherit_metadata_for_cross_target() -> None:
|
||||
sent: list[OutboundMessage] = []
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user