fix(agent): refresh goal continuation context
This commit is contained in:
@@ -953,6 +953,41 @@ async def test_process_message_uses_explicit_session_metadata_for_goal_context(
|
||||
assert GOAL_STATE_KEY not in kwargs["session_metadata"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_agent_loop_goal_continue_message_reads_latest_metadata(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
from nanobot.agent.runner import AgentRunResult
|
||||
|
||||
loop = _make_full_loop(tmp_path)
|
||||
session = loop.sessions.get_or_create("websocket:late-goal")
|
||||
seen: dict[str, str | None] = {}
|
||||
|
||||
async def fake_run(spec):
|
||||
assert callable(spec.goal_continue_message)
|
||||
session.metadata[GOAL_STATE_KEY] = {
|
||||
"status": "active",
|
||||
"objective": "Goal created during this runner call.",
|
||||
}
|
||||
seen["goal_continue"] = spec.goal_continue_message()
|
||||
return AgentRunResult(
|
||||
final_content="ok",
|
||||
messages=[{"role": "assistant", "content": "ok"}],
|
||||
)
|
||||
|
||||
loop.runner.run = fake_run # type: ignore[method-assign]
|
||||
|
||||
await loop._run_agent_loop(
|
||||
[],
|
||||
session=session,
|
||||
channel="websocket",
|
||||
chat_id="late-goal",
|
||||
session_key=session.key,
|
||||
)
|
||||
|
||||
assert "Goal created during this runner call." in (seen["goal_continue"] or "")
|
||||
|
||||
|
||||
def test_set_tool_context_uses_effective_key_for_spawn_tool(tmp_path: Path) -> None:
|
||||
loop = _make_full_loop(tmp_path)
|
||||
spawn_tool = loop.tools.get("spawn")
|
||||
|
||||
@@ -210,3 +210,37 @@ async def test_runner_uses_custom_goal_continue_message():
|
||||
|
||||
user_msgs = [m for m in result.messages if m.get("role") == "user"]
|
||||
assert any(custom_msg in str(m.get("content", "")) for m in user_msgs)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_runner_resolves_goal_continue_message_lazily():
|
||||
"""The continuation text can depend on goal metadata created during the run."""
|
||||
from nanobot.agent.runner import AgentRunner, AgentRunSpec
|
||||
|
||||
provider = MagicMock(spec=LLMProvider)
|
||||
provider.chat_with_retry = AsyncMock(return_value=LLMResponse(
|
||||
content="still working", tool_calls=[], usage={},
|
||||
))
|
||||
tools = MagicMock()
|
||||
tools.get_definitions.return_value = []
|
||||
calls = {"n": 0}
|
||||
|
||||
def dynamic_msg() -> str:
|
||||
calls["n"] += 1
|
||||
return "Goal (active):\nWrite the article draft."
|
||||
|
||||
runner = AgentRunner(provider)
|
||||
result = await runner.run(AgentRunSpec(
|
||||
initial_messages=[{"role": "user", "content": "do task"}],
|
||||
tools=tools,
|
||||
model="test-model",
|
||||
max_iterations=1,
|
||||
max_tool_result_chars=_MAX_TOOL_RESULT_CHARS,
|
||||
goal_active_predicate=lambda: True,
|
||||
goal_continue_message=dynamic_msg,
|
||||
finalize_on_max_iterations=False,
|
||||
))
|
||||
|
||||
user_msgs = [m for m in result.messages if m.get("role") == "user"]
|
||||
assert calls["n"] == 1
|
||||
assert any("Write the article draft." in str(m.get("content", "")) for m in user_msgs)
|
||||
|
||||
Reference in New Issue
Block a user