fix: add 570s total timeout to agent runner
Wraps the tool-calling loop in asyncio.wait_for so long-running tasks (e.g. consultation summary generation) return a clean Hebrew message instead of being abruptly cut when PHP closes the connection at 600s. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Callable
|
from typing import Any, Callable
|
||||||
@@ -84,6 +85,7 @@ class AgentRunner:
|
|||||||
model: str = "sonnet",
|
model: str = "sonnet",
|
||||||
max_tokens: int = 4096,
|
max_tokens: int = 4096,
|
||||||
max_iterations: int = 10,
|
max_iterations: int = 10,
|
||||||
|
total_timeout: float = 570.0,
|
||||||
):
|
):
|
||||||
self.client = AsyncOpenAI(
|
self.client = AsyncOpenAI(
|
||||||
base_url=f"{ai_gateway_url.rstrip('/')}/v1",
|
base_url=f"{ai_gateway_url.rstrip('/')}/v1",
|
||||||
@@ -92,6 +94,7 @@ class AgentRunner:
|
|||||||
self.model = model
|
self.model = model
|
||||||
self.max_tokens = max_tokens
|
self.max_tokens = max_tokens
|
||||||
self.max_iterations = max_iterations
|
self.max_iterations = max_iterations
|
||||||
|
self.total_timeout = total_timeout
|
||||||
|
|
||||||
async def run(
|
async def run(
|
||||||
self,
|
self,
|
||||||
@@ -108,7 +111,45 @@ class AgentRunner:
|
|||||||
kb_topic_name: str | None = None,
|
kb_topic_name: str | None = None,
|
||||||
on_event: Callable[[dict], None] | None = None,
|
on_event: Callable[[dict], None] | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Run a conversation with tool-calling loop. Returns the final text response.
|
"""Run a conversation with tool-calling loop, bounded by total_timeout seconds."""
|
||||||
|
try:
|
||||||
|
return await asyncio.wait_for(
|
||||||
|
self._run_impl(
|
||||||
|
system_prompt=system_prompt,
|
||||||
|
messages=messages,
|
||||||
|
context=context,
|
||||||
|
espocrm_url=espocrm_url,
|
||||||
|
espocrm_api_key=espocrm_api_key,
|
||||||
|
depth=depth,
|
||||||
|
blocked_tools=blocked_tools,
|
||||||
|
allowed_toolsets=allowed_toolsets,
|
||||||
|
kb_sources_used=kb_sources_used,
|
||||||
|
kb_topic_id=kb_topic_id,
|
||||||
|
kb_topic_name=kb_topic_name,
|
||||||
|
on_event=on_event,
|
||||||
|
),
|
||||||
|
timeout=self.total_timeout,
|
||||||
|
)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
logger.warning("[agent] total timeout (%.0fs) reached", self.total_timeout)
|
||||||
|
return "⏱️ המשימה לקחה יותר זמן מהמותר. נסי לפצל אותה לחלקים קטנים — למשל: קודם בקשי לקרוא מסמך ספציפי, ואז לכתוב את הסיכום."
|
||||||
|
|
||||||
|
async def _run_impl(
|
||||||
|
self,
|
||||||
|
system_prompt: str,
|
||||||
|
messages: list[dict[str, str]],
|
||||||
|
context: dict,
|
||||||
|
espocrm_url: str,
|
||||||
|
espocrm_api_key: str,
|
||||||
|
depth: int = 0,
|
||||||
|
blocked_tools: set[str] | None = None,
|
||||||
|
allowed_toolsets: list[str] | None = None,
|
||||||
|
kb_sources_used: list[dict] | None = None,
|
||||||
|
kb_topic_id: int | None = None,
|
||||||
|
kb_topic_name: str | None = None,
|
||||||
|
on_event: Callable[[dict], None] | None = None,
|
||||||
|
) -> str:
|
||||||
|
"""Internal tool-calling loop. Returns the final text response.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
depth: Current delegation depth. 0 = main conversation, 1 = child agent.
|
depth: Current delegation depth. 0 = main conversation, 1 = child agent.
|
||||||
|
|||||||
Reference in New Issue
Block a user