chat: tolerant model resolution instead of throwing on stale ids

↗ view on GitHub · Claude · 2026-05-16 · 532738c5

A user-visible chat would hard-fail with "External AI providers are
disabled by organisation policy. (model='gemini-3-flash-preview', ...)"
when the request body carried a model id that's no longer allowed
by the current policy. This happened most reliably on the
auto-send path from InitialView -> /assistant/chat/<id>: the new
chat's queued first message has whatever model the InitialView's
ChatInput held at submit time, and that can be stale if the bundle
was loaded before /admin/llm was configured.

Add resolveAllowedModel(requested, policy) to llmPolicy: returns
the requested id if allowed, otherwise the first allowed id, or
null when no provider is enabled at all.

POST /chat and POST /projects/:id/chat now resolve before
dispatching. Substitutions are logged so admins can see them. A
truly empty policy (no provider enabled) returns 503 with a clear
"ask an admin" message rather than a generic 500.

assertModelAllowed is still used by streamChatWithTools as the
hard gate for direct calls (e.g. tabular extraction); the chat
streaming path now never reaches it with a forbidden id.
Repository cpatpa/PIP
Author Claude <noreply@anthropic.com>
Authored
Parents 30fa8010
Stats 3 files changed , +67 , -2
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-532738c5.md from inside the repo you want the change in.

⬇ Download capture-commit-532738c5.md