feat(providers): extend request_timeout_seconds to all client paths
Follow-up on top of mvanhorn's cherry-picked commit. Original PR only wired request_timeout_seconds into the explicit-creds OpenAI branch at run_agent.py init; router-based implicit auth, native Anthropic, and the fallback chain were still hardcoded to SDK defaults. - agent/anthropic_adapter.py: build_anthropic_client() accepts an optional timeout kwarg (default 900s preserved when unset/invalid). - run_agent.py: resolve per-provider/per-model timeout once at init; apply to Anthropic native init + post-refresh rebuild + stale/interrupt rebuilds + switch_model + _restore_primary_runtime + the OpenAI implicit-auth path + _try_activate_fallback (with immediate client rebuild so the first fallback request carries the configured timeout). - tests: cover anthropic adapter kwarg honoring; widen mock signatures to accept the new timeout kwarg. - docs/example: clarify that the knob now applies to every transport, the fallback chain, and rebuilds after credential rotation.
This commit is contained in:
46
run_agent.py
46
run_agent.py
@@ -964,6 +964,12 @@ class AIAgent:
|
||||
self._anthropic_client = None
|
||||
self._is_anthropic_oauth = False
|
||||
|
||||
# Resolve per-provider / per-model request timeout once up front so
|
||||
# every client construction path below (Anthropic native, OpenAI-wire,
|
||||
# router-based implicit auth) can apply it consistently. Bedrock
|
||||
# Claude uses its own timeout path and is not covered here.
|
||||
_provider_timeout = get_provider_request_timeout(self.provider, self.model)
|
||||
|
||||
if self.api_mode == "anthropic_messages":
|
||||
from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token
|
||||
# Bedrock + Claude → use AnthropicBedrock SDK for full feature parity
|
||||
@@ -995,7 +1001,7 @@ class AIAgent:
|
||||
self._anthropic_base_url = base_url
|
||||
from agent.anthropic_adapter import _is_oauth_token as _is_oat
|
||||
self._is_anthropic_oauth = _is_oat(effective_key)
|
||||
self._anthropic_client = build_anthropic_client(effective_key, base_url)
|
||||
self._anthropic_client = build_anthropic_client(effective_key, base_url, timeout=_provider_timeout)
|
||||
# No OpenAI client needed for Anthropic mode
|
||||
self.client = None
|
||||
self._client_kwargs = {}
|
||||
@@ -1035,7 +1041,6 @@ class AIAgent:
|
||||
# Explicit credentials from CLI/gateway — construct directly.
|
||||
# The runtime provider resolver already handled auth for us.
|
||||
client_kwargs = {"api_key": api_key, "base_url": base_url}
|
||||
_provider_timeout = get_provider_request_timeout(self.provider, self.model)
|
||||
if _provider_timeout is not None:
|
||||
client_kwargs["timeout"] = _provider_timeout
|
||||
if self.provider == "copilot-acp":
|
||||
@@ -1068,6 +1073,8 @@ class AIAgent:
|
||||
"api_key": _routed_client.api_key,
|
||||
"base_url": str(_routed_client.base_url),
|
||||
}
|
||||
if _provider_timeout is not None:
|
||||
client_kwargs["timeout"] = _provider_timeout
|
||||
# Preserve any default_headers the router set
|
||||
if hasattr(_routed_client, '_default_headers') and _routed_client._default_headers:
|
||||
client_kwargs["default_headers"] = dict(_routed_client._default_headers)
|
||||
@@ -1796,6 +1803,7 @@ class AIAgent:
|
||||
self._anthropic_base_url = base_url or getattr(self, "_anthropic_base_url", None)
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
effective_key, self._anthropic_base_url,
|
||||
timeout=get_provider_request_timeout(self.provider, self.model),
|
||||
)
|
||||
self._is_anthropic_oauth = _is_oauth_token(effective_key)
|
||||
self.client = None
|
||||
@@ -1807,6 +1815,9 @@ class AIAgent:
|
||||
"api_key": effective_key,
|
||||
"base_url": effective_base,
|
||||
}
|
||||
_sm_timeout = get_provider_request_timeout(self.provider, self.model)
|
||||
if _sm_timeout is not None:
|
||||
self._client_kwargs["timeout"] = _sm_timeout
|
||||
self.client = self._create_openai_client(
|
||||
dict(self._client_kwargs),
|
||||
reason="switch_model",
|
||||
@@ -5233,7 +5244,11 @@ class AIAgent:
|
||||
pass
|
||||
|
||||
try:
|
||||
self._anthropic_client = build_anthropic_client(new_token, getattr(self, "_anthropic_base_url", None))
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
new_token,
|
||||
getattr(self, "_anthropic_base_url", None),
|
||||
timeout=get_provider_request_timeout(self.provider, self.model),
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to rebuild Anthropic client after credential refresh: %s", exc)
|
||||
return False
|
||||
@@ -5275,7 +5290,10 @@ class AIAgent:
|
||||
|
||||
self._anthropic_api_key = runtime_key
|
||||
self._anthropic_base_url = runtime_base
|
||||
self._anthropic_client = build_anthropic_client(runtime_key, runtime_base)
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
runtime_key, runtime_base,
|
||||
timeout=get_provider_request_timeout(self.provider, self.model),
|
||||
)
|
||||
self._is_anthropic_oauth = _is_oauth_token(runtime_key)
|
||||
self.api_key = runtime_key
|
||||
self.base_url = runtime_base
|
||||
@@ -5487,6 +5505,7 @@ class AIAgent:
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
self._anthropic_api_key,
|
||||
getattr(self, "_anthropic_base_url", None),
|
||||
timeout=get_provider_request_timeout(self.provider, self.model),
|
||||
)
|
||||
else:
|
||||
rc = request_client_holder.get("client")
|
||||
@@ -5518,6 +5537,7 @@ class AIAgent:
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
self._anthropic_api_key,
|
||||
getattr(self, "_anthropic_base_url", None),
|
||||
timeout=get_provider_request_timeout(self.provider, self.model),
|
||||
)
|
||||
else:
|
||||
request_client = request_client_holder.get("client")
|
||||
@@ -6246,6 +6266,7 @@ class AIAgent:
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
self._anthropic_api_key,
|
||||
getattr(self, "_anthropic_base_url", None),
|
||||
timeout=get_provider_request_timeout(self.provider, self.model),
|
||||
)
|
||||
else:
|
||||
request_client = request_client_holder.get("client")
|
||||
@@ -6402,6 +6423,11 @@ class AIAgent:
|
||||
self.api_mode = fb_api_mode
|
||||
self._fallback_activated = True
|
||||
|
||||
# Honor per-provider / per-model request_timeout_seconds for the
|
||||
# fallback target (same knob the primary client uses). None = use
|
||||
# SDK default.
|
||||
_fb_timeout = get_provider_request_timeout(fb_provider, fb_model)
|
||||
|
||||
if fb_api_mode == "anthropic_messages":
|
||||
# Build native Anthropic client instead of using OpenAI client
|
||||
from agent.anthropic_adapter import build_anthropic_client, resolve_anthropic_token, _is_oauth_token
|
||||
@@ -6409,7 +6435,9 @@ class AIAgent:
|
||||
self.api_key = effective_key
|
||||
self._anthropic_api_key = effective_key
|
||||
self._anthropic_base_url = fb_base_url
|
||||
self._anthropic_client = build_anthropic_client(effective_key, self._anthropic_base_url)
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
effective_key, self._anthropic_base_url, timeout=_fb_timeout,
|
||||
)
|
||||
self._is_anthropic_oauth = _is_oauth_token(effective_key)
|
||||
self.client = None
|
||||
self._client_kwargs = {}
|
||||
@@ -6433,6 +6461,12 @@ class AIAgent:
|
||||
"base_url": fb_base_url,
|
||||
**({"default_headers": dict(fb_headers)} if fb_headers else {}),
|
||||
}
|
||||
if _fb_timeout is not None:
|
||||
self._client_kwargs["timeout"] = _fb_timeout
|
||||
# Rebuild the shared OpenAI client so the configured
|
||||
# timeout takes effect on the very next fallback request,
|
||||
# not only after a later credential-rotation rebuild.
|
||||
self._replace_primary_openai_client(reason="fallback_timeout_apply")
|
||||
|
||||
# Re-evaluate prompt caching for the new provider/model
|
||||
is_native_anthropic = fb_api_mode == "anthropic_messages" and fb_provider == "anthropic"
|
||||
@@ -6506,6 +6540,7 @@ class AIAgent:
|
||||
self._anthropic_base_url = rt["anthropic_base_url"]
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
rt["anthropic_api_key"], rt["anthropic_base_url"],
|
||||
timeout=get_provider_request_timeout(self.provider, self.model),
|
||||
)
|
||||
self._is_anthropic_oauth = rt["is_anthropic_oauth"]
|
||||
self.client = None
|
||||
@@ -6602,6 +6637,7 @@ class AIAgent:
|
||||
self._anthropic_base_url = rt["anthropic_base_url"]
|
||||
self._anthropic_client = build_anthropic_client(
|
||||
rt["anthropic_api_key"], rt["anthropic_base_url"],
|
||||
timeout=get_provider_request_timeout(self.provider, self.model),
|
||||
)
|
||||
self._is_anthropic_oauth = rt["is_anthropic_oauth"]
|
||||
self.client = None
|
||||
|
||||
Reference in New Issue
Block a user