LLM policy: admin-driven providers + curated local models

↗ view on GitHub · Claude · 2026-05-16 · 76030d6f

Replaces the hardcoded model picker with a server-driven list keyed
on org_settings. Adds /admin/llm so an admin can pick which
providers are enabled, override the local LLM base URL at runtime,
and curate which Ollama models appear in the picker. The per-user
API keys surface is removed; only env-supplied keys (set in
install.sh / .env.compose) are honoured.

Schema (migration 0019):
- org_settings.providers_enabled JSONB (master switch per provider).
- org_settings.local_llm_base_url text (runtime override; NULL falls
  back to the env var).
- org_settings.local_llm_models JSONB (curated [{id,label}]).

Backend:
- New lib/llmPolicy.ts: loadLlmPolicy, availableModels,
  assertModelAllowed, orgApiKeys. Centralises gating.
- New lib/localDiscovery.ts: probes /api/tags on the OpenAI-compat
  host to list installed Ollama models.
- New routes: GET /me/models (filtered list for users),
  GET/PATCH /admin/llm, POST /admin/llm/refresh-local.
- llm/index.ts dispatcher now consults the policy on every
  streamChatWithTools / completeText. EXTERNAL_AI_DISABLED env still
  wins for the three external providers.
- Boot reads org_settings.local_llm_base_url and sets
  process.env.LOCAL_LLM_BASE_URL so the local adapter picks it up.
- /user/api-keys GET/PUT removed. user_api_keys table left in place
  for now; a follow-up migration can drop it once we are confident
  no encrypted data needs preservation.
- userSettings.getUserApiKeys now returns env-only keys.
- userApiKeys.ts deleted.

Frontend:
- ModelToggle fetches /me/models on mount, dropping the hardcoded
  catalogue. Empty list prompts the user to ask an admin.
- New /admin/llm page: per-provider toggles, base-URL field, refresh
  button, curated-model checkboxes.
- /account/models page, ApiKeyMissingModal, modelAvailability lib
  all removed. apiKeyStatus / apiKeys / saveApiKey stripped from
  pipApi.ts and UserProfileContext.
- ChatInput, TabularReviewView, TRChatPanel: drop apiKeys plumbing.
  Backend rejection is now the only gate.
- useSelectedModel: persist whatever the picker emits; ModelToggle
  reconciles against the live list on mount.
Repository cpatpa/PIP
Author Claude <noreply@anthropic.com>
Authored
Parents 684223b9
Stats 23 files changed , +1013 , -1036
Part of LLM policy - admin-driven providers, curated local models, rate-limit tuning

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-76030d6f.md from inside the repo you want the change in.

⬇ Download capture-commit-76030d6f.md