import { pgTable, uuid, text, boolean, timestamp, index } from 'drizzle-orm/pg-core'; /** * A configured connection to a model: adapter + model + credentials. * * ── Why this is a row and the adapter is not ── * * "OpenAI" is not a thing you can generate with. "OpenAI's gpt-image-1, with this key" is. The two * differ in how often they change: an ADAPTER is code that learns a vendor's HTTP API and is written * once; a PROVIDER is a decision — which model, whose key, is it on — and you make several of those * per adapter and change them at runtime. * * So `openai + gpt-image-1` and `openai + dall-e-3` are two rows sharing one adapter and possibly one * key. The previous design keyed configuration on the adapter name, which made that unsayable: there * was exactly one OpenAI, and its model was a property of it rather than the point of it. * * Nothing here constrains `model` against the adapter. Vendors ship models faster than a list in this * repo is updated, and refusing a new one on release day is a worse failure than passing it through * and letting the vendor answer. */ export const providers = pgTable( 'providers', { id: uuid('id').primaryKey().defaultRandom(), /** What a human calls it — "OpenAI · gpt-image-1". Unique, so it can be named in a request. */ name: text('name').notNull().unique(), /** Which adapter drives it. Text, not an enum: adding an adapter must not be a schema change. */ adapter: text('adapter').notNull(), model: text('model').notNull(), /** AES-256-GCM via servers/crypto.ts. Never leaves the server and never appears in a response. */ apiKeyEncrypted: text('api_key_encrypted'), enabled: boolean('enabled').notNull().default(true), /** * The one to use when a request names no provider and no model, or names a model nothing serves. * * A column rather than "the oldest row" because it is a decision the owner makes and should be * able to change without deleting and recreating rows. Exactly one row should carry it; the * queries below enforce that by clearing the others when one is set. */ isDefault: boolean('is_default').notNull().default(false), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(), }, (table) => [ // Resolving a request by model is the hot path: every generation does it once. index('providers_model_idx').on(table.model, table.enabled), ], );