mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-20 00:22:31 +00:00
test(agent): add tests to ensure goal state does not leak across sessions
This commit is contained in:
parent
f97b960433
commit
387724c355
@ -299,6 +299,31 @@ class TestBuildMessages:
|
|||||||
assert "Goal (active):" in user_msg
|
assert "Goal (active):" in user_msg
|
||||||
assert "Finish docs migration." in user_msg
|
assert "Finish docs migration." in user_msg
|
||||||
|
|
||||||
|
def test_goal_state_does_not_leak_without_session_metadata(self, tmp_path):
|
||||||
|
builder = _builder(tmp_path)
|
||||||
|
other_session_meta = {
|
||||||
|
GOAL_STATE_KEY: {"status": "active", "objective": "Other chat goal."},
|
||||||
|
}
|
||||||
|
|
||||||
|
with_goal = builder.build_messages(
|
||||||
|
[],
|
||||||
|
"hi",
|
||||||
|
channel="websocket",
|
||||||
|
chat_id="chat-a",
|
||||||
|
session_metadata=other_session_meta,
|
||||||
|
)
|
||||||
|
without_goal = builder.build_messages(
|
||||||
|
[],
|
||||||
|
"hi",
|
||||||
|
channel="websocket",
|
||||||
|
chat_id="chat-b",
|
||||||
|
session_metadata={},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "Other chat goal." in str(with_goal[-1]["content"])
|
||||||
|
assert "Other chat goal." not in str(without_goal[-1]["content"])
|
||||||
|
assert "Goal (active):" not in str(without_goal[-1]["content"])
|
||||||
|
|
||||||
def test_consecutive_same_role_merged(self, tmp_path):
|
def test_consecutive_same_role_merged(self, tmp_path):
|
||||||
builder = _builder(tmp_path)
|
builder = _builder(tmp_path)
|
||||||
history = [{"role": "user", "content": "previous user message"}]
|
history = [{"role": "user", "content": "previous user message"}]
|
||||||
|
|||||||
@ -9,6 +9,7 @@ from nanobot.agent.loop import AgentLoop
|
|||||||
from nanobot.bus.events import InboundMessage
|
from nanobot.bus.events import InboundMessage
|
||||||
from nanobot.bus.queue import MessageBus
|
from nanobot.bus.queue import MessageBus
|
||||||
from nanobot.providers.base import LLMResponse
|
from nanobot.providers.base import LLMResponse
|
||||||
|
from nanobot.session.goal_state import GOAL_STATE_KEY
|
||||||
from nanobot.session.manager import Session
|
from nanobot.session.manager import Session
|
||||||
from nanobot.utils.webui_titles import (
|
from nanobot.utils.webui_titles import (
|
||||||
WEBUI_SESSION_METADATA_KEY,
|
WEBUI_SESSION_METADATA_KEY,
|
||||||
@ -493,6 +494,58 @@ async def test_process_message_uses_context_chat_id_for_runtime_prompt(tmp_path:
|
|||||||
assert loop._run_agent_loop.call_args.kwargs["chat_id"] == "thread-777"
|
assert loop._run_agent_loop.call_args.kwargs["chat_id"] == "thread-777"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_process_message_uses_explicit_session_metadata_for_goal_context(
|
||||||
|
tmp_path: Path,
|
||||||
|
) -> None:
|
||||||
|
loop = _make_full_loop(tmp_path)
|
||||||
|
loop.consolidator.maybe_consolidate_by_tokens = AsyncMock(return_value=False) # type: ignore[method-assign]
|
||||||
|
chat_session = loop.sessions.get_or_create("websocket:chat-with-goal")
|
||||||
|
chat_session.metadata[GOAL_STATE_KEY] = {
|
||||||
|
"status": "active",
|
||||||
|
"objective": "This chat goal must not leak into heartbeat.",
|
||||||
|
}
|
||||||
|
loop.sessions.save(chat_session)
|
||||||
|
system_session = loop.sessions.get_or_create("heartbeat")
|
||||||
|
system_session.metadata = {}
|
||||||
|
loop.sessions.save(system_session)
|
||||||
|
|
||||||
|
loop.context.build_messages = MagicMock( # type: ignore[method-assign]
|
||||||
|
return_value=[
|
||||||
|
{"role": "system", "content": "system"},
|
||||||
|
{"role": "user", "content": "runtime + heartbeat"},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
loop._run_agent_loop = AsyncMock(return_value=( # type: ignore[method-assign]
|
||||||
|
"ok",
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
{"role": "system", "content": "system"},
|
||||||
|
{"role": "user", "content": "runtime + heartbeat"},
|
||||||
|
{"role": "assistant", "content": "ok"},
|
||||||
|
],
|
||||||
|
"stop",
|
||||||
|
False,
|
||||||
|
))
|
||||||
|
|
||||||
|
result = await loop._process_message(
|
||||||
|
InboundMessage(
|
||||||
|
channel="websocket",
|
||||||
|
sender_id="heartbeat",
|
||||||
|
chat_id="chat-with-goal",
|
||||||
|
content="heartbeat work",
|
||||||
|
),
|
||||||
|
session_key="heartbeat",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result is not None
|
||||||
|
assert result.content == "ok"
|
||||||
|
kwargs = loop.context.build_messages.call_args.kwargs
|
||||||
|
assert kwargs["chat_id"] == "chat-with-goal"
|
||||||
|
assert kwargs["session_metadata"] is system_session.metadata
|
||||||
|
assert GOAL_STATE_KEY not in kwargs["session_metadata"]
|
||||||
|
|
||||||
|
|
||||||
def test_set_tool_context_uses_effective_key_for_spawn_tool(tmp_path: Path) -> None:
|
def test_set_tool_context_uses_effective_key_for_spawn_tool(tmp_path: Path) -> None:
|
||||||
loop = _make_full_loop(tmp_path)
|
loop = _make_full_loop(tmp_path)
|
||||||
spawn_tool = loop.tools.get("spawn")
|
spawn_tool = loop.tools.get("spawn")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user