refactor(agent): unify request context routing

This commit is contained in:
chengyongru
2026-07-10 17:54:34 +08:00
committed by Xubin Ren
parent bb3b449e09
commit 42d7ad34a4
20 changed files with 363 additions and 423 deletions
+61 -68
View File
@@ -2,6 +2,7 @@ import os
import pytest
from nanobot.agent.tools.context import RequestContext, request_context
from nanobot.agent.tools.message import MessageTool
from nanobot.bus.events import OutboundMessage
from nanobot.config.paths import get_workspace_path
@@ -108,11 +109,9 @@ async def test_message_tool_inherits_metadata_for_same_target() -> None:
tool = MessageTool(send_callback=_send)
slack_meta = {"slack": {"thread_ts": "111.222", "channel_type": "channel"}}
from nanobot.agent.tools.context import RequestContext
tool.set_context(RequestContext(channel="slack", chat_id="C123", metadata=slack_meta))
await tool.execute(content="thread reply")
with request_context(RequestContext(channel="slack", chat_id="C123", metadata=slack_meta)):
await tool.execute(content="thread reply")
assert sent[0].metadata == slack_meta
@@ -125,18 +124,23 @@ async def test_message_tool_clears_metadata_when_context_has_none() -> None:
sent.append(msg)
tool = MessageTool(send_callback=_send)
from nanobot.agent.tools.context import RequestContext
rich_context = RequestContext(
channel="slack",
chat_id="C123",
metadata={"slack": {"thread_ts": "111.222", "channel_type": "channel"}},
)
with request_context(rich_context):
await tool.execute(content="thread reply")
sent.clear()
tool.set_context(
with request_context(
RequestContext(
channel="slack",
chat_id="C123",
metadata={"slack": {"thread_ts": "111.222", "channel_type": "channel"}},
metadata={},
),
)
tool.set_context(RequestContext(channel="slack", chat_id="C123", metadata={}))
await tool.execute(content="plain reply")
):
await tool.execute(content="plain reply")
assert sent[0].metadata == {}
@@ -149,17 +153,14 @@ async def test_message_tool_does_not_inherit_metadata_for_cross_target() -> None
sent.append(msg)
tool = MessageTool(send_callback=_send)
from nanobot.agent.tools.context import RequestContext
tool.set_context(
with request_context(
RequestContext(
channel="slack",
chat_id="C123",
metadata={"slack": {"thread_ts": "111.222", "channel_type": "channel"}},
),
)
await tool.execute(content="channel reply", channel="slack", chat_id="C999")
):
await tool.execute(content="channel reply", channel="slack", chat_id="C999")
assert sent[0].metadata == {}
@@ -337,15 +338,17 @@ async def test_message_tool_tracks_turn_media_for_same_target(tmp_path) -> None:
sent.append(msg)
tool = MessageTool(send_callback=_send)
from nanobot.agent.tools.context import RequestContext
tool.set_context(RequestContext(channel="websocket", chat_id="chat-1", metadata={}))
tool.start_turn()
f = tmp_path / "doc.md"
f.write_text("hello", encoding="utf-8")
await tool.execute(content="see file", channel="websocket", chat_id="chat-1", media=[str(f)])
assert tool.turn_delivered_media_paths() == [str(f.resolve())]
with request_context(RequestContext(channel="websocket", chat_id="chat-1", metadata={})):
tool.start_turn()
await tool.execute(
content="see file",
channel="websocket",
chat_id="chat-1",
media=[str(f)],
)
assert tool.turn_delivered_media_paths() == [str(f.resolve())]
@pytest.mark.asyncio
@@ -354,15 +357,13 @@ async def test_message_tool_start_turn_clears_tracked_media(tmp_path) -> None:
pass
tool = MessageTool(send_callback=_send)
from nanobot.agent.tools.context import RequestContext
tool.set_context(RequestContext(channel="websocket", chat_id="chat-1", metadata={}))
tool.start_turn()
f = tmp_path / "doc.md"
f.write_text("hello", encoding="utf-8")
await tool.execute(content="see file", media=[str(f)])
tool.start_turn()
assert tool.turn_delivered_media_paths() == []
with request_context(RequestContext(channel="websocket", chat_id="chat-1", metadata={})):
tool.start_turn()
await tool.execute(content="see file", media=[str(f)])
tool.start_turn()
assert tool.turn_delivered_media_paths() == []
@pytest.mark.asyncio
@@ -371,18 +372,16 @@ async def test_message_tool_cross_target_does_not_track_turn_media(tmp_path) ->
pass
tool = MessageTool(send_callback=_send)
from nanobot.agent.tools.context import RequestContext
tool.set_context(RequestContext(channel="websocket", chat_id="chat-1", metadata={}))
f = tmp_path / "doc.md"
f.write_text("hello", encoding="utf-8")
await tool.execute(
content="see file",
channel="telegram",
chat_id="tg-other",
media=[str(f)],
)
assert tool.turn_delivered_media_paths() == []
with request_context(RequestContext(channel="websocket", chat_id="chat-1", metadata={})):
await tool.execute(
content="see file",
channel="telegram",
chat_id="tg-other",
media=[str(f)],
)
assert tool.turn_delivered_media_paths() == []
@pytest.mark.asyncio
@@ -393,18 +392,16 @@ async def test_message_tool_rejects_wrong_explicit_ws_chat_id(tmp_path) -> None:
sent.append(msg)
tool = MessageTool(send_callback=_send)
from nanobot.agent.tools.context import RequestContext
conv = "550e8400-e29b-41d4-a716-446655440000"
tool.set_context(RequestContext(channel="websocket", chat_id=conv, metadata={}))
f = tmp_path / "doc.md"
f.write_text("hello", encoding="utf-8")
result = await tool.execute(
content="see file",
channel="websocket",
chat_id="anon-deadbeefcafe",
media=[str(f)],
)
with request_context(RequestContext(channel="websocket", chat_id=conv, metadata={})):
result = await tool.execute(
content="see file",
channel="websocket",
chat_id="anon-deadbeefcafe",
media=[str(f)],
)
assert result.startswith("Error: chat_id does not match")
assert sent == []
@@ -417,18 +414,16 @@ async def test_message_tool_allows_ws_explicit_when_matches_context(tmp_path) ->
sent.append(msg)
tool = MessageTool(send_callback=_send)
from nanobot.agent.tools.context import RequestContext
conv = "550e8400-e29b-41d4-a716-446655440000"
tool.set_context(RequestContext(channel="websocket", chat_id=conv, metadata={}))
f = tmp_path / "doc.md"
f.write_text("hello", encoding="utf-8")
result = await tool.execute(
content="see file",
channel="websocket",
chat_id=conv,
media=[str(f)],
)
with request_context(RequestContext(channel="websocket", chat_id=conv, metadata={})):
result = await tool.execute(
content="see file",
channel="websocket",
chat_id=conv,
media=[str(f)],
)
assert result.startswith("Message sent")
assert sent[0].chat_id == conv
@@ -442,18 +437,16 @@ async def test_message_tool_cli_context_may_target_other_ws_chat(tmp_path) -> No
sent.append(msg)
tool = MessageTool(send_callback=_send)
from nanobot.agent.tools.context import RequestContext
target = "550e8400-e29b-41d4-a716-446655440000"
tool.set_context(RequestContext(channel="cli", chat_id="direct", metadata={}))
f = tmp_path / "doc.md"
f.write_text("hello", encoding="utf-8")
result = await tool.execute(
content="ping",
channel="websocket",
chat_id=target,
media=[str(f)],
)
with request_context(RequestContext(channel="cli", chat_id="direct", metadata={})):
result = await tool.execute(
content="ping",
channel="websocket",
chat_id=target,
media=[str(f)],
)
assert result.startswith("Message sent")
assert sent[0].channel == "websocket"
assert sent[0].chat_id == target