Skip to content

AI: optional per-project provider config (falls back to the server default)#83

Merged
jwicks31 merged 1 commit into
mainfrom
claude/per-project-ai
Jun 13, 2026
Merged

AI: optional per-project provider config (falls back to the server default)#83
jwicks31 merged 1 commit into
mainfrom
claude/per-project-ai

Conversation

@jwicks31

Copy link
Copy Markdown
Owner

What

Lets a project point /v1/ai/chat at its own provider/model/key/gateway, while anyone who doesn't opt in keeps using the server's instance-wide AI_PROVIDER default. One server can now serve tenants with different AI backends.

Fallback (as asked): effective(project) returns the project's override ?? config.ai — so no override (or after DELETE) means the env-configured server provider is used, unchanged. Covered by a cross-tenant test.

API

GET / PUT / DELETE /v1/ai/config (key-gated, per-project). PUT takes a flat { provider, model?, maxTokens?, apiKey?, baseUrl?, headers?, region? }. Secrets are stored server-side and never read backGET returns a redacted view (hasApiKey / hasHeaders, plus provider/model/baseUrl/region).

How

  • The flat input is built into a full AiConfig (the shape getProvider(ai) already accepts), so the chat route just resolves the effective config (override → instance default) and passes it through — no provider-factory changes.
  • /v1/stats reports each project's effective provider/model. The effective config is cached briefly so chat requests skip the DB. New project_ai table on both backends.
  • SDK: client.ai.getConfig/setConfig/clearConfig; discovery advertises the endpoint.

Verification

  • SQLite 71/71 + Postgres 53/53 (Postgres 16): override + secret redaction + provider validation (400) + reset-to-default, and cross-tenant isolation — project A's openai override leaves project C on the anthropic instance default.
  • Docs updated: README (AI section) + /docs (AI REST).

Last item today after this: verifiable identity (JWT/OIDC).

https://claude.ai/code/session_018efxvWw3MRjdtvE5xgBqya


Generated by Claude Code

Let a project point /v1/ai/chat at its own provider/model/key/gateway, falling
back to the instance-wide AI_PROVIDER default when unset — so one server can
serve tenants with different AI backends.

- GET/PUT/DELETE /v1/ai/config (key-gated, per-project). PUT takes a flat
  { provider, model?, maxTokens?, apiKey?, baseUrl?, headers?, region? } and
  stores it as a full AiConfig; the existing getProvider(ai) is already
  parameterized, so the chat route just resolves the effective config and passes
  it through. Secrets are stored server-side and never read back (GET returns a
  redacted view with hasApiKey/hasHeaders).
- The effective config (project override, else config.ai) is resolved by the chat
  route and /v1/stats (so stats reflects each project's provider), cached briefly
  to keep chat requests off the DB. New project_ai table on both backends.
- SDK: client.ai.getConfig/setConfig/clearConfig; discovery advertises the endpoint.

Verification: 71/71 SQLite + 53/53 Postgres 16 — override + redaction + validation
+ reset, and cross-tenant isolation (project A's openai override doesn't change
project C's effective provider). Docs updated (README, /docs).
@jwicks31 jwicks31 merged commit d692e17 into main Jun 13, 2026
2 checks passed
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.

2 participants