mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 16:13:15 +00:00
When the primary model raises a transient provider error (5xx, 429, connection/timeout) the request is retried once against a fallback model from the other provider. Anthropic primaries fall back to OpenAI and vice versa. Also bumps the SDK max_retries from the default 2 to 6 so quick blips stay on the primary and keep prompt caching warm. Triggered by 529 OverloadedError traces that ended runs silently with no Slack/Linear/PR reply.
48 lines
1.6 KiB
Python
48 lines
1.6 KiB
Python
from typing import Literal, TypedDict, Unpack
|
|
|
|
from langchain.chat_models import init_chat_model
|
|
|
|
OPENAI_RESPONSES_WS_BASE_URL = "wss://api.openai.com/v1"
|
|
|
|
# Anthropic SDK default is 2; a 529 burst can outlive that. Bump to give the
|
|
# primary provider a fair chance before the fallback middleware kicks in.
|
|
DEFAULT_MAX_RETRIES = 6
|
|
|
|
|
|
OpenAIReasoningEffort = Literal["none", "low", "medium", "high", "xhigh"]
|
|
|
|
|
|
class OpenAIReasoning(TypedDict, total=False):
|
|
effort: OpenAIReasoningEffort
|
|
|
|
|
|
class ModelKwargs(TypedDict, total=False):
|
|
max_tokens: int | None
|
|
reasoning: OpenAIReasoning | None
|
|
temperature: float | None
|
|
max_retries: int | None
|
|
|
|
|
|
def make_model(model_id: str, **kwargs: Unpack[ModelKwargs]):
|
|
model_kwargs: dict[str, object] = kwargs.copy()
|
|
model_kwargs.setdefault("max_retries", DEFAULT_MAX_RETRIES)
|
|
|
|
if model_id.startswith("openai:"):
|
|
model_kwargs["base_url"] = OPENAI_RESPONSES_WS_BASE_URL
|
|
model_kwargs["use_responses_api"] = True
|
|
|
|
return init_chat_model(model=model_id, **model_kwargs)
|
|
|
|
|
|
def fallback_model_id_for(primary_model_id: str) -> str | None:
|
|
"""Return the cross-provider fallback model id for a given primary, if any.
|
|
|
|
Anthropic primaries fall back to OpenAI and vice versa. Returns ``None``
|
|
when the provider has no configured cross-provider fallback (e.g. local
|
|
or self-hosted providers we don't want to silently route off-host).
|
|
"""
|
|
if primary_model_id.startswith("anthropic:"):
|
|
return "openai:gpt-5.5"
|
|
if primary_model_id.startswith("openai:"):
|
|
return "anthropic:claude-opus-4-5"
|
|
return None
|