feat(ai): add the storage for an OpenAI-compatible gateway provider

Three dedicated User columns — base URL, optional bearer, model — for a
provider whose endpoint the user chooses. They are separate from the
OpenAI columns on purpose: the OpenAI arm pins api.openai.com, so it must
share no column with a user-supplied host, and a gateway must never
receive the key issued for OpenAI.

The bearer joins the encrypted-column registry and the rotation script;
the three columns join the account-wipe reset set.
This commit is contained in:
Marc-André Bombeck committed 2026-07-26 22:27:48 +02:00
1 parent d10ae9e71c
commit d11019aebc
5 files changed
+40 -1

No files matched your search

@@ -0,0 +1,17 @@
-- The OpenAI-compatible gateway provider (#470): a user-configured endpoint
-- that speaks `/v1/chat/completions` — LiteLLM, OpenRouter, vLLM, or anything
-- else on that wire — with its own base URL, its own optional bearer, and its
-- own model.
--
-- Three dedicated columns instead of reusing `ai_base_url` / the OpenAI key.
-- The OpenAI arm pins `api.openai.com` on purpose, so it must have no column
-- in common with a provider whose host the user chooses; and the gateway must
-- never receive the key the user issued for OpenAI. Separating the storage
-- makes both properties structural rather than a comment someone can delete.
--
-- All three are nullable and additive: an install that never configures the
-- provider carries three NULLs and resolves exactly as before.
ALTER TABLE "users" ADD COLUMN "ai_compat_base_url" TEXT;
ALTER TABLE "users" ADD COLUMN "ai_compat_key_encrypted" TEXT;
ALTER TABLE "users" ADD COLUMN "ai_compat_model" TEXT;
+12
View File
@@ -311,6 +311,18 @@ model User {
// before storage.
aiOpenaiKeyEncrypted String? @map("ai_openai_key_encrypted")
// v1.33.1 (#470) — the OpenAI-compatible gateway provider (LiteLLM,
// OpenRouter, vLLM, any endpoint speaking `/v1/chat/completions`).
// Three DEDICATED columns rather than a reuse of `aiBaseUrl` /
// `aiOpenaiKeyEncrypted`: the OpenAI arm pins `api.openai.com` and must
// never be able to read a user-supplied host, and the gateway credential
// must never be the OpenAI key. Separate columns make that structural
// instead of a comment. The base URL passes the same SSRF floor as the
// Local provider (`isPublicUrl` unless the operator allowlisted the host).
aiCompatBaseUrl String? @map("ai_compat_base_url")
aiCompatKeyEncrypted String? @map("ai_compat_key_encrypted")
aiCompatModel String? @map("ai_compat_model")
// v1.4.16 phase B5b — ordered fallback chain for multi-provider AI
// redundancy. Each entry is `{ providerType, priority, enabled }`,
// sorted by ascending priority at runtime. Credentials live in the