mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-31 00:03:01 +03:00
fix(agent): time out no-tools model requests
This commit is contained in:
committed by
chengyongru
parent
04974b7607
commit
f5e467626d
+30
-13
@@ -922,18 +922,7 @@ class AgentRunner:
|
||||
conversation_state: ProviderConversationStateController,
|
||||
provider_context: ProviderCallContext | None = None,
|
||||
) -> LLMResponse:
|
||||
timeout_s: float | None = spec.llm_timeout_s
|
||||
if timeout_s is None:
|
||||
# Default to a finite timeout to avoid per-session lock starvation when an LLM
|
||||
# request hangs indefinitely (e.g. gateway/network stall).
|
||||
# Set NANOBOT_LLM_TIMEOUT_S=0 to disable.
|
||||
raw = os.environ.get("NANOBOT_LLM_TIMEOUT_S", "300").strip()
|
||||
try:
|
||||
timeout_s = float(raw)
|
||||
except (TypeError, ValueError):
|
||||
timeout_s = 300.0
|
||||
if timeout_s <= 0:
|
||||
timeout_s = None
|
||||
timeout_s = self._resolve_llm_timeout_s(spec)
|
||||
|
||||
kwargs = self._build_request_kwargs(
|
||||
spec,
|
||||
@@ -1302,10 +1291,38 @@ class AgentRunner:
|
||||
messages,
|
||||
tools=None,
|
||||
)
|
||||
return await spec.runtime.provider.chat_with_retry(
|
||||
coro = spec.runtime.provider.chat_with_retry(
|
||||
**kwargs,
|
||||
provider_context=provider_context,
|
||||
)
|
||||
timeout_s = self._resolve_llm_timeout_s(spec)
|
||||
try:
|
||||
return (
|
||||
await coro
|
||||
if timeout_s is None
|
||||
else await asyncio.wait_for(coro, timeout=timeout_s)
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
return LLMResponse(
|
||||
content=f"Error calling LLM: timed out after {timeout_s:g}s",
|
||||
finish_reason="error",
|
||||
error_kind="timeout",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _resolve_llm_timeout_s(spec: AgentRunSpec) -> float | None:
|
||||
"""Resolve the wall-clock limit shared by every model request path."""
|
||||
timeout_s = spec.llm_timeout_s
|
||||
if timeout_s is None:
|
||||
# Default to a finite timeout to avoid per-session lock starvation when an LLM
|
||||
# request hangs indefinitely (e.g. gateway/network stall).
|
||||
# Set NANOBOT_LLM_TIMEOUT_S=0 to disable.
|
||||
raw = os.environ.get("NANOBOT_LLM_TIMEOUT_S", "300").strip()
|
||||
try:
|
||||
timeout_s = float(raw)
|
||||
except (TypeError, ValueError):
|
||||
timeout_s = 300.0
|
||||
return timeout_s if timeout_s > 0 else None
|
||||
|
||||
@staticmethod
|
||||
def _budget_exhausted_finalization_messages(
|
||||
|
||||
@@ -499,6 +499,55 @@ async def test_runner_times_out_hung_llm_request():
|
||||
assert "timed out" in (result.final_content or "").lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_runner_times_out_hung_max_iteration_finalization():
|
||||
from nanobot.agent.runner import AgentRunner
|
||||
|
||||
provider = MagicMock()
|
||||
calls = 0
|
||||
|
||||
async def chat_with_retry(**kwargs):
|
||||
nonlocal calls
|
||||
calls += 1
|
||||
if calls == 1:
|
||||
return LLMResponse(
|
||||
content="",
|
||||
tool_calls=[
|
||||
ToolCallRequest(
|
||||
id="call_1",
|
||||
name="probe",
|
||||
arguments={},
|
||||
)
|
||||
],
|
||||
finish_reason="tool_calls",
|
||||
)
|
||||
await asyncio.Event().wait()
|
||||
|
||||
provider.chat_with_retry = chat_with_retry
|
||||
tools = MagicMock()
|
||||
tools.get_definitions.return_value = []
|
||||
tools.execute = AsyncMock(return_value="ok")
|
||||
|
||||
result = await asyncio.wait_for(
|
||||
AgentRunner().run(make_run_spec(
|
||||
provider,
|
||||
initial_messages=[{"role": "user", "content": "run the probe"}],
|
||||
tools=tools,
|
||||
model="test-model",
|
||||
max_iterations=1,
|
||||
max_tool_result_chars=_MAX_TOOL_RESULT_CHARS,
|
||||
max_iterations_message="fallback after {max_iterations} iteration",
|
||||
llm_timeout_s=0.01,
|
||||
)),
|
||||
timeout=1.0,
|
||||
)
|
||||
|
||||
assert calls == 2
|
||||
assert result.stop_reason == "max_iterations"
|
||||
assert result.error is None
|
||||
assert result.final_content == "fallback after 1 iteration"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_runner_applies_outer_wall_timeout_to_streaming_requests():
|
||||
from nanobot.agent.hook import AgentHook, AgentHookContext
|
||||
|
||||
Reference in New Issue
Block a user