| 1 | -- A workspace's AI providers are not integrations: they move out of |
| 2 | -- `connections` into a table of their own, and what Ask answers with into |
| 3 | -- `ai_routes`. Ids stay as they are, so sealed keys (bound to the id) still |
| 4 | -- open, and managed_agents and agent_runs still find their provider. |
| 5 | |
| 6 | CREATE TABLE ai_providers ( |
| 7 | id TEXT PRIMARY KEY, |
| 8 | -- The workspace's slug. |
| 9 | workspace TEXT NOT NULL, |
| 10 | -- anthropic, openai, …, anthropic_endpoint or openai_endpoint |
| 11 | -- (g1t_contracts::ai::AiProvider). |
| 12 | provider TEXT NOT NULL, |
| 13 | name TEXT NOT NULL, |
| 14 | -- Its address, key header and model, as JSON. Never its key. |
| 15 | config TEXT NOT NULL, |
| 16 | -- Its key, as JSON sealed with AES-256-GCM under the service's key and |
| 17 | -- bound to the id. Never returned. |
| 18 | secrets TEXT, |
| 19 | -- The last four characters of the key, to tell keys apart. |
| 20 | secret_hint TEXT, |
| 21 | -- The models it offered when last checked, as a JSON array. |
| 22 | models TEXT, |
| 23 | created_by TEXT NOT NULL, |
| 24 | created_at TEXT NOT NULL, |
| 25 | last_used_at TEXT, |
| 26 | last_error TEXT |
| 27 | ); |
| 28 | CREATE INDEX ai_providers_by_workspace ON ai_providers (workspace, id); |
| 29 | |
| 30 | INSERT INTO ai_providers |
| 31 | (id, workspace, provider, name, config, secrets, secret_hint, models, created_by, created_at, last_used_at, last_error) |
| 32 | SELECT id, workspace, provider, name, config, secrets, secret_hint, models, created_by, created_at, last_used_at, last_error |
| 33 | FROM connections |
| 34 | WHERE provider IN ( |
| 35 | 'anthropic', 'openai', 'gemini', 'xai', 'mistral', 'deepseek', 'azure_openai', 'openrouter', 'groq', |
| 36 | 'together', 'fireworks', 'cerebras', 'anthropic_endpoint', 'openai_endpoint' |
| 37 | ); |
| 38 | |
| 39 | DELETE FROM connections WHERE id IN (SELECT id FROM ai_providers); |
| 40 | |
| 41 | -- What each kind of AI work in a workspace answers with. Only `ask` is |
| 42 | -- used: the other tasks were for g1t's hosted agents, which are gone. |
| 43 | CREATE TABLE ai_routes ( |
| 44 | workspace TEXT NOT NULL, |
| 45 | task TEXT NOT NULL, |
| 46 | -- One of the workspace's ai_providers. |
| 47 | provider_id TEXT NOT NULL, |
| 48 | -- The model chosen; not read with `auto`. |
| 49 | model TEXT, |
| 50 | -- 1: Auto, a model of the provider's for each question. |
| 51 | auto INTEGER NOT NULL DEFAULT 0, |
| 52 | PRIMARY KEY (workspace, task) |
| 53 | ); |
| 54 | |
| 55 | INSERT INTO ai_routes (workspace, task, provider_id, model, auto) |
| 56 | SELECT workspace, task, connection_id, model, auto |
| 57 | FROM model_routes |
| 58 | WHERE task = 'ask' AND connection_id IN (SELECT id FROM ai_providers); |
| 59 | |
| 60 | DROP TABLE model_routes; |