diff --git a/backend/app/services/agent_tools.py b/backend/app/services/agent_tools.py index 99ca04a1..45872dae 100644 --- a/backend/app/services/agent_tools.py +++ b/backend/app/services/agent_tools.py @@ -2802,13 +2802,23 @@ async def _send_message_to_agent(from_agent_id: uuid.UUID, args: dict) -> str: timeout=120.0, ) try: + import asyncio + import httpx for _round in range(max_tool_rounds): - response = await llm_client.complete( - messages=full_msgs, - tools=tools_for_llm if tools_for_llm else None, - temperature=0.7, - max_tokens=4096, - ) + # Retry up to 3 times on transient LLM timeouts before aborting + for _attempt in range(3): + try: + response = await llm_client.complete( + messages=full_msgs, + tools=tools_for_llm if tools_for_llm else None, + temperature=0.7, + max_tokens=4096, + ) + break + except httpx.ReadTimeout: + if _attempt == 2: + raise + await asyncio.sleep(2 ** _attempt) # 1s, then 2s # Track tokens from API response real_tokens = extract_usage_tokens(response.usage) @@ -2920,7 +2930,8 @@ async def _send_message_to_agent(from_agent_id: uuid.UUID, args: dict) -> str: except Exception as e: import traceback traceback.print_exc() - return f"❌ Message send error: {str(e)[:200]}" + err_detail = str(e) or type(e).__name__ + return f"❌ Message send error: {err_detail[:200]}" diff --git a/frontend/src/pages/AgentDetail.tsx b/frontend/src/pages/AgentDetail.tsx index cd9ab3a7..c4fdce4e 100644 --- a/frontend/src/pages/AgentDetail.tsx +++ b/frontend/src/pages/AgentDetail.tsx @@ -863,8 +863,16 @@ function AgentDetailInner() { }; const selectSession = async (sess: any) => { + // Close the existing WS before switching so its onmessage can no longer + // write stale streaming data into the new session's message list. + if (wsRef.current && wsRef.current.readyState !== WebSocket.CLOSED) { + wsRef.current.close(); + wsRef.current = null; + } setChatMessages([]); setHistoryMsgs([]); + setIsStreaming(false); + setIsWaiting(false); setActiveSession(sess); // Always load stored messages for the selected session const tkn = localStorage.getItem('token'); @@ -1033,9 +1041,15 @@ function AgentDetailInner() { // Reset state whenever the viewed agent changes useEffect(() => { + if (wsRef.current && wsRef.current.readyState !== WebSocket.CLOSED) { + wsRef.current.close(); + wsRef.current = null; + } setActiveSession(null); setChatMessages([]); setHistoryMsgs([]); + setIsStreaming(false); + setIsWaiting(false); setChatScope('mine'); setAgentExpired(false); settingsInitRef.current = false;