Fix run cancellation and live activity stability

This commit is contained in:
wuyang6
2026-05-14 12:23:53 +08:00
parent 105d287ebd
commit 22960c5e02
6 changed files with 117 additions and 43 deletions
+23 -4
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
import json
import os
from typing import Any, Iterator
from urllib import error, request
@@ -31,6 +32,7 @@ ANTHROPIC_MESSAGES_MODEL_PREFIXES = (
ANTHROPIC_VERSION = '2023-06-01'
ANTHROPIC_MAX_TOKENS = 4096
DEFAULT_MODEL_IDLE_TIMEOUT_SECONDS = 60.0
def _join_url(base_url: str, suffix: str) -> str:
@@ -274,6 +276,23 @@ class OpenAICompatClient:
def __init__(self, config: ModelConfig) -> None:
self.config = config
def _request_timeout_seconds(self) -> float:
"""Return per-socket model timeout.
`ModelConfig.timeout_seconds` is the whole request budget used by the
product, but urllib applies it as an idle socket timeout. Keeping it at
one hour makes a bad upstream stream hold a session lock for an hour.
Use a shorter idle timeout by default; any normally streaming response
keeps extending this naturally because bytes continue to arrive.
"""
raw = os.environ.get('CLAW_MODEL_IDLE_TIMEOUT_SECONDS', '').strip()
try:
configured = float(raw) if raw else DEFAULT_MODEL_IDLE_TIMEOUT_SECONDS
except ValueError:
configured = DEFAULT_MODEL_IDLE_TIMEOUT_SECONDS
configured = max(5.0, configured)
return min(float(self.config.timeout_seconds), configured)
def complete(
self,
messages: list[dict[str, Any]],
@@ -351,7 +370,7 @@ class OpenAICompatClient:
method='POST',
)
try:
with request.urlopen(req, timeout=self.config.timeout_seconds) as response:
with request.urlopen(req, timeout=self._request_timeout_seconds()) as response:
yield StreamEvent(type='message_start')
for event_payload in self._iter_sse_payloads(response):
yield from self._parse_stream_payload(event_payload)
@@ -380,7 +399,7 @@ class OpenAICompatClient:
method='POST',
)
try:
with request.urlopen(req, timeout=self.config.timeout_seconds) as response:
with request.urlopen(req, timeout=self._request_timeout_seconds()) as response:
raw = response.read()
except error.HTTPError as exc:
detail = exc.read().decode('utf-8', errors='replace')
@@ -521,7 +540,7 @@ class OpenAICompatClient:
method='POST',
)
try:
with request.urlopen(req, timeout=self.config.timeout_seconds) as response:
with request.urlopen(req, timeout=self._request_timeout_seconds()) as response:
raw = response.read()
except error.HTTPError as exc:
detail = exc.read().decode('utf-8', errors='replace')
@@ -561,7 +580,7 @@ class OpenAICompatClient:
method='POST',
)
try:
with request.urlopen(req, timeout=self.config.timeout_seconds) as response:
with request.urlopen(req, timeout=self._request_timeout_seconds()) as response:
yield StreamEvent(type='message_start')
tool_block_indexes: dict[int, int] = {}
next_tool_index = 0