LLM dispatcher: self-heal stale model ids at the deepest layer

↗ view on GitHub · Claude · 2026-05-16 · dc31b293

The chat dispatch had been crashing with "External AI providers
are disabled (model='gemini-3-flash-preview', provider='google')"
even after the chat.ts route added a tolerant resolveAllowedModel
substitution. That route-level fix only covers /chat and
/projects/:id/chat; tabular and any future caller would still
trip the original assertModelAllowed.

Move the resolve logic INTO streamChatWithTools and completeText.
Now any caller that hands the dispatcher a stale model id sees
the dispatcher substitute the first allowed model, log a warning,
and proceed. The only way to surface an error to the user is
truly empty policy (no provider enabled), which throws with a
clear "ask an admin" message.

Net effect:
- /chat, /projects/:id/chat: route-level resolve runs first, no
  change for happy path.
- Tabular review and any other path that calls runLLMStream /
  streamChatWithTools / completeText: now also tolerant.
- Title generation: already nullable; falls through here too.

The assertModelAllowed helper stays in llmPolicy.ts for callers
that genuinely want a hard gate, but the LLM dispatcher no longer
uses it on the streaming chat path.
Repository cpatpa/PIP
Author Claude <noreply@anthropic.com>
Authored
Parents 532738c5
Stats 1 file changed , +40 , -15
Part of LLM dispatch - stale model id resolution and external-disabled fallbacks

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-dc31b293.md from inside the repo you want the change in.

⬇ Download capture-commit-dc31b293.md