Skip to content

fix(bridge): self-heal an unroutable model instead of failing every turn - #419

Open
Ivancheng7 wants to merge 2 commits into
xvirobotics:mainfrom
Ivancheng7:fix/self-heal-unknown-model
Open

Ivancheng7 wants to merge 2 commits into
xvirobotics:mainfrom
Ivancheng7:fix/self-heal-unknown-model

Conversation

@Ivancheng7

Copy link
Copy Markdown
Contributor

Problem

A session-level model override (/model <name>) is stored with the session and outlives the endpoint that used to route that name. When an Anthropic-compatible gateway changes its alias set — or a model is retired — every later turn of that session fails with the same

API Error: 400 unknown provider for model <name>

and keeps failing, because the override is never invalidated. The user has to know about /model reset to recover. The same applies when the bot-level model in bots.json is the unroutable one.

Change

  • error-classifiers.ts: isUnknownModelError() / modelFromUnknownModelError() recognize the rejection (observed: unknown provider for model ..., plus the common unknown model, invalid model, no such model, model ... does not exist phrasings).
  • message-bridge.ts: new retryAfterUnknownModel(). On this error it clears the session override (setSessionModel(chatId, undefined)), audits a task_model_fallback event, and re-runs the same turn with no model flag, so the endpoint resolves its own default. Wired into three places, mirroring the existing stale-session retry: the chat turn at stream end, the chat turn's thrown-error path, and the API task path — all before the error card is rendered.
  • executor-registry.ts: acquire({ ignoreRegistryDefaultModel: true }) spawns/respawns without a model flag instead of falling back to the registry default (which can itself be the unroutable name). runOneTurn forwards forceEndpointDefaultModel to it and drops model on the legacy path.

If the retry also fails, the error card explains what was attempted; the turn is not silently swallowed.

Tests

tests/model-fallback-classifier.test.ts (new): the observed proxy 400 and the common phrasings match; unrelated failures (context overflow, connection refused) do not; model-name extraction.

Full local suite: no new failures.

A session-level model override lives in the session store and outlives the
endpoint that routed it. When an Anthropic-compatible gateway changes its
alias set (or a model is retired), every later turn of that session fails
with the same "API Error: 400 unknown provider for model <name>" and the
user has to know about /model reset to recover.

- error-classifiers: isUnknownModelError() / modelFromUnknownModelError().
- message-bridge: retryAfterUnknownModel() clears the session override,
  audits task_model_fallback and re-runs the same turn with no model flag, so
  the endpoint resolves its own default; wired into the chat turn (stream end
  and thrown-error paths) and the API task path before the error card.
- executor-registry: acquire({ ignoreRegistryDefaultModel: true }) spawns
  without a model flag instead of falling back to the registry default (the
  bot-level model can be the unroutable one).
- audit: task_model_fallback event.
- Tests: classifier phrasings, including the observed proxy 400.
no-useless-escape: '/' inside a character class needs no backslash.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant