fix(tools): isolate plugin runtime state

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xubin Ren
2026-05-12 11:28:20 +08:00
committed by Xubin Ren
co-authored by Cursor
parent 043f0e67f7
commit 23312d683e
4 changed files with 49 additions and 7 deletions
+24
View File
@@ -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
+23
View File
@@ -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] = []