generated from coulomb/repo-seed
Honour explicit OpenRouter --model when it equals the adapter default
The adapter compared self._model to _DEFAULT_MODEL ("anthropic/claude-sonnet-4")
to decide whether to honour the constructor's model. When a caller passes
that exact value via --model, the comparison treats it as "not specified"
and falls through to RunConfig.model_name, which defaults to "gpt-4". So
every llm-connect call started with --provider openrouter --model
anthropic/claude-sonnet-4 actually landed on OpenAI's gpt-4 — and on
gpt-4 OpenAI's structured-output response_format requires a model with
schema support that gpt-4 lacks, returning 400. The CUST-WP-0045 canary
hit this for hours; the smoke probes that worked were the ones with no
json_schema, where gpt-4 returned fine.
Track _explicit_model separately so a constructor or LLMConfig that
matches the default is still treated as a real intent.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,14 @@ class OpenRouterAdapter(LLMAdapter):
|
|||||||
max_retries: Optional[int] = None,
|
max_retries: Optional[int] = None,
|
||||||
):
|
):
|
||||||
self._config = config or LLMConfig()
|
self._config = config or LLMConfig()
|
||||||
|
# Track whether the model was explicitly supplied (constructor or
|
||||||
|
# LLMConfig). Comparing self._model to _DEFAULT_MODEL is not enough —
|
||||||
|
# callers who pass --model anthropic/claude-sonnet-4 happen to match
|
||||||
|
# the default and would otherwise be misrouted to RunConfig.model_name
|
||||||
|
# (which defaults to "gpt-4" — quietly sending every call to OpenAI's
|
||||||
|
# gpt-4 model, which is what broke the activity-core CUST-WP-0045
|
||||||
|
# canary on 2026-06-02).
|
||||||
|
self._explicit_model = model is not None or self._config.model is not None
|
||||||
self._model = model or self._config.model or _DEFAULT_MODEL
|
self._model = model or self._config.model or _DEFAULT_MODEL
|
||||||
self._api_base = (api_base or self._config.api_base).rstrip("/")
|
self._api_base = (api_base or self._config.api_base).rstrip("/")
|
||||||
self._system_prompt = system_prompt
|
self._system_prompt = system_prompt
|
||||||
@@ -56,7 +64,14 @@ class OpenRouterAdapter(LLMAdapter):
|
|||||||
|
|
||||||
def execute_prompt(self, prompt: str, config: RunConfig) -> LLMResponse:
|
def execute_prompt(self, prompt: str, config: RunConfig) -> LLMResponse:
|
||||||
self._preflight_budget(config)
|
self._preflight_budget(config)
|
||||||
model = self._model if self._model != _DEFAULT_MODEL else (config.model_name or self._model)
|
# Explicit constructor/LLMConfig model wins; only fall back to the
|
||||||
|
# per-call RunConfig.model_name when the adapter wasn't told what to
|
||||||
|
# use. RunConfig.model_name defaults to "gpt-4", so falling back
|
||||||
|
# unconditionally would silently misroute callers.
|
||||||
|
if self._explicit_model:
|
||||||
|
model = self._model
|
||||||
|
else:
|
||||||
|
model = config.model_name or self._model
|
||||||
|
|
||||||
messages: list[Dict[str, str]] = []
|
messages: list[Dict[str, str]] = []
|
||||||
if self._system_prompt:
|
if self._system_prompt:
|
||||||
|
|||||||
Reference in New Issue
Block a user