fix(agent): disable LLM wall-clock timeout during sustained goals

This commit is contained in:
Xubin Ren 2026-05-16 05:27:40 +00:00
parent 90632469f6
commit 2144af7cd0
3 changed files with 35 additions and 1 deletions

View File

@ -32,7 +32,11 @@ from nanobot.command import CommandContext, CommandRouter, register_builtin_comm
from nanobot.config.schema import AgentDefaults, ModelPresetConfig
from nanobot.providers.base import LLMProvider
from nanobot.providers.factory import ProviderSnapshot
from nanobot.session.goal_state import goal_state_runtime_lines, goal_state_ws_blob
from nanobot.session.goal_state import (
goal_state_runtime_lines,
goal_state_ws_blob,
sustained_goal_active,
)
from nanobot.session.manager import Session, SessionManager
from nanobot.utils.artifacts import generated_image_paths_from_messages
from nanobot.utils.document import extract_documents
@ -789,6 +793,13 @@ class AgentLoop:
retry_wait_callback=on_retry_wait,
checkpoint_callback=_checkpoint,
injection_callback=_drain_pending,
# Sustained goals may legitimately exceed NANOBOT_LLM_TIMEOUT_S; idle stall
# is still capped by NANOBOT_STREAM_IDLE_TIMEOUT_S in streaming providers.
llm_timeout_s=(
0.0
if session is not None and sustained_goal_active(session.metadata)
else None
),
))
finally:
reset_file_states(file_state_token)

View File

@ -35,6 +35,12 @@ def goal_state_raw(metadata: Mapping[str, Any] | None) -> Any:
return _session_goal_raw(metadata)
def sustained_goal_active(metadata: Mapping[str, Any] | None) -> bool:
"""True when this session has an active sustained objective (``long_task`` bookkeeping)."""
goal = parse_goal_state(goal_state_raw(metadata))
return isinstance(goal, dict) and goal.get("status") == "active"
def parse_goal_state(blob: Any) -> dict[str, Any] | None:
if blob is None:
return None

View File

@ -8,6 +8,7 @@ from nanobot.session.goal_state import (
goal_state_runtime_lines,
goal_state_ws_blob,
parse_goal_state,
sustained_goal_active,
)
@ -88,3 +89,19 @@ def test_goal_state_ws_blob_active_shape():
"ui_summary": "feat",
"objective": "Build feature.",
}
def test_sustained_goal_active_false_when_missing_or_completed():
assert sustained_goal_active(None) is False
assert sustained_goal_active({}) is False
assert sustained_goal_active({GOAL_STATE_KEY: {"status": "completed", "objective": "x"}}) is False
def test_sustained_goal_active_true_when_active():
meta = {GOAL_STATE_KEY: {"status": "active", "objective": "Run long task."}}
assert sustained_goal_active(meta) is True
def test_sustained_goal_active_respects_legacy_thread_goal_key():
meta = {"thread_goal": {"status": "active", "objective": "Legacy."}}
assert sustained_goal_active(meta) is True