fix(agent): prevent runner from exiting while sustained goal is active

`long_task` registers a sustained objective, but `AgentRunner` would
still exit with `stop_reason="completed"` when the LLM produced a final
text response without calling `complete_goal`. This defeated the purpose
of sustained goals.

Add `goal_active_predicate` and `goal_continue_message` to `AgentRunSpec`.
When the predicate returns `True` at the natural completion checkpoint,
inject a continuation message via the existing `_try_drain_injections`
machinery, forcing the runner to continue looping.

Also extract the default continuation prompt to
`nanobot/utils/runtime.py` alongside the existing recovery-message
builders.
This commit is contained in:
chengyongru
2026-05-26 00:53:38 +08:00
committed by Xubin Ren
parent 418cb23da2
commit 7bbd9c7103
4 changed files with 221 additions and 2 deletions
+10
View File
@@ -29,6 +29,11 @@ LENGTH_RECOVERY_PROMPT = (
"— no recap, no apology. Break remaining work into smaller steps if needed."
)
SUSTAINED_GOAL_CONTINUE_PROMPT = (
"You have an active sustained goal. Please continue working toward the "
"objective using your tools, or call complete_goal if the work is truly finished."
)
def empty_tool_result_message(tool_name: str) -> str:
"""Short prompt-safe marker for tools that completed without visible output."""
@@ -65,6 +70,11 @@ def build_length_recovery_message() -> dict[str, str]:
return {"role": "user", "content": LENGTH_RECOVERY_PROMPT}
def build_goal_continue_message(custom: str | None = None) -> dict[str, str]:
"""Prompt the model to continue when a sustained goal is still active."""
return {"role": "user", "content": custom or SUSTAINED_GOAL_CONTINUE_PROMPT}
def external_lookup_signature(tool_name: str, arguments: dict[str, Any]) -> str | None:
"""Stable signature for repeated external lookups we want to throttle."""
if tool_name == "web_fetch":