Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| The contracts no longer describe g1t's own agents, and workspaces can keep their AI providers. Every consumer had already stopped using them, so the TypeScript and Rust contracts drop the workspace-agent, ability, look, skill-library, context, runner-agent and mention modules, the chat and docs RPCs agents posted and read through, the folio agent methods, the agent_waiting notification, agent.asked and memory.changed events, AI credit, token and gateway billing types, model routes and sessions, team agents, agent tokens, plan, review, message and confidence types, command rules, cost caps and confidence rules. The agents:run and models:* scopes are no longer offered by any preset, OAuth default or permission form, but a stored token or grant that names them still reads; and the removed operations are gone from the scope table, so the API's check that every operation has exactly one scope is strict again. What stored data needs in order to parse (old run and credential kinds, an agent team lead, retired rules and webhook events, old guardrail and integration settings) still parses, and a run's token is still PrincipalKind::Agent, which now means a run's token and the @g1t rows written before. The customize, marketplace, skills and claude-plugin contracts stay only until the mobile app drops its Customize screens. | 1 | /** |
| 2 | * The AI providers a workspace can keep credentials for, as people are | |
| 3 | * shown them: grouped, with a line each, a mark, and where to get a key. | |
| 4 | */ | |
| 5 | import type { Provider } from "@g1t/contracts"; | |
| 6 | ||
| 7 | export type AiProviderGroup = "labs" | "platforms" | "any"; | |
| 8 | ||
| 9 | export type AiProviderEntry = { | |
| 10 | group: AiProviderGroup; | |
| 11 | blurb: string; | |
| 12 | /** The provider's colour, for its mark. */ | |
| 13 | color: string; | |
| 14 | /** What the mark shows: an initial or two. Empty for an icon. */ | |
| 15 | mark: string; | |
| 16 | /** Where to get a key. */ | |
| 17 | keyUrl?: string; | |
| 18 | keyPlaceholder?: string; | |
| 19 | /** A model to suggest. */ | |
| 20 | model?: string; | |
| 21 | }; | |
| 22 | ||
| 23 | /** Every AI provider, in the order people are shown them. */ | |
| 24 | export const AI_PROVIDERS: Partial<Record<Provider, AiProviderEntry>> = { | |
| 25 | anthropic: { | |
| 26 | group: "labs", | |
| 27 | blurb: "Claude, on your own Anthropic key.", | |
| 28 | color: "#d97757", | |
| 29 | mark: "A", | |
| 30 | keyUrl: "https://console.anthropic.com/settings/keys", | |
| 31 | keyPlaceholder: "sk-ant-…", | |
| 32 | }, | |
| 33 | openai: { | |
| 34 | group: "labs", | |
| 35 | blurb: "GPT and the o-series, on your own OpenAI key.", | |
| 36 | color: "#10a37f", | |
| 37 | mark: "O", | |
| 38 | keyUrl: "https://platform.openai.com/api-keys", | |
| 39 | keyPlaceholder: "sk-…", | |
| 40 | model: "gpt-5", | |
| 41 | }, | |
| 42 | gemini: { | |
| 43 | group: "labs", | |
| 44 | blurb: "Gemini, on your own Google AI Studio key.", | |
| 45 | color: "#4285f4", | |
| 46 | mark: "G", | |
| 47 | keyUrl: "https://aistudio.google.com/apikey", | |
| 48 | model: "gemini-2.5-pro", | |
| 49 | }, | |
| 50 | xai: { | |
| 51 | group: "labs", | |
| 52 | blurb: "Grok, on your own xAI key.", | |
| 53 | color: "#e5e5e5", | |
| 54 | mark: "x", | |
| 55 | keyUrl: "https://console.x.ai", | |
| 56 | keyPlaceholder: "xai-…", | |
| 57 | model: "grok-4", | |
| 58 | }, | |
| 59 | mistral: { | |
| 60 | group: "labs", | |
| 61 | blurb: "Mistral and Codestral, on your own key.", | |
| 62 | color: "#fa520f", | |
| 63 | mark: "M", | |
| 64 | keyUrl: "https://console.mistral.ai/api-keys", | |
| 65 | model: "mistral-large-latest", | |
| 66 | }, | |
| 67 | deepseek: { | |
| 68 | group: "labs", | |
| 69 | blurb: "DeepSeek's chat and reasoning models.", | |
| 70 | color: "#4d6bfe", | |
| 71 | mark: "D", | |
| 72 | keyUrl: "https://platform.deepseek.com/api_keys", | |
| 73 | keyPlaceholder: "sk-…", | |
| 74 | model: "deepseek-chat", | |
| 75 | }, | |
| 76 | azure_openai: { | |
| 77 | group: "platforms", | |
| 78 | blurb: "OpenAI's models on your own Azure resource and contract.", | |
| 79 | color: "#0078d4", | |
| 80 | mark: "Az", | |
| 81 | }, | |
| 82 | openrouter: { | |
| 83 | group: "platforms", | |
| 84 | blurb: "Hundreds of models from every lab, on one key.", | |
| 85 | color: "#7c7ff5", | |
| 86 | mark: "OR", | |
| 87 | keyUrl: "https://openrouter.ai/keys", | |
| 88 | keyPlaceholder: "sk-or-…", | |
| 89 | model: "anthropic/claude-sonnet-4.5", | |
| 90 | }, | |
| 91 | groq: { | |
| 92 | group: "platforms", | |
| 93 | blurb: "Open models at very high speed.", | |
| 94 | color: "#f55036", | |
| 95 | mark: "Gq", | |
| 96 | keyUrl: "https://console.groq.com/keys", | |
| 97 | keyPlaceholder: "gsk_…", | |
| 98 | model: "moonshotai/kimi-k2-instruct", | |
| 99 | }, | |
| 100 | together: { | |
| 101 | group: "platforms", | |
| 102 | blurb: "Open models: Llama, Qwen, DeepSeek, Kimi.", | |
| 103 | color: "#0f6fff", | |
| 104 | mark: "T", | |
| 105 | keyUrl: "https://api.together.ai/settings/api-keys", | |
| 106 | model: "Qwen/Qwen3-Coder-480B-A35B-Instruct-FP8", | |
| 107 | }, | |
| 108 | fireworks: { | |
| 109 | group: "platforms", | |
| 110 | blurb: "Fast open models, and your own fine-tunes.", | |
| 111 | color: "#7c3aed", | |
| 112 | mark: "F", | |
| 113 | keyUrl: "https://fireworks.ai/account/api-keys", | |
| 114 | model: "accounts/fireworks/models/kimi-k2-instruct", | |
| 115 | }, | |
| 116 | cerebras: { | |
| 117 | group: "platforms", | |
| 118 | blurb: "Open models on wafer-scale chips.", | |
| 119 | color: "#f05a28", | |
| 120 | mark: "C", | |
| 121 | keyUrl: "https://cloud.cerebras.ai", | |
| 122 | keyPlaceholder: "csk-…", | |
| 123 | model: "qwen-3-coder-480b", | |
| 124 | }, | |
| 125 | anthropic_endpoint: { | |
| 126 | group: "any", | |
| 127 | blurb: "Anything that speaks Anthropic's API: your own gateway, LiteLLM, Bedrock or Vertex behind a proxy.", | |
| 128 | color: "#a1a1aa", | |
| 129 | mark: "", | |
| 130 | }, | |
| 131 | openai_endpoint: { | |
| 132 | group: "any", | |
| 133 | blurb: "Anything that speaks OpenAI's API: vLLM, Ollama behind a tunnel, LiteLLM, a gateway.", | |
| 134 | color: "#a1a1aa", | |
| 135 | mark: "", | |
| 136 | }, | |
| 137 | }; | |
| 138 | ||
| 139 | export const AI_PROVIDER_GROUPS: { group: AiProviderGroup; title: string }[] = [ | |
| 140 | { group: "labs", title: "Labs" }, | |
| 141 | { group: "platforms", title: "Platforms" }, | |
| 142 | { group: "any", title: "Any endpoint" }, | |
| 143 | ]; | |
| 144 | ||
| 145 | /** The AI providers in one group, in catalogue order. */ | |
| 146 | export function aiProvidersIn(group: AiProviderGroup): Provider[] { | |
| 147 | return (Object.keys(AI_PROVIDERS) as Provider[]).filter((provider) => AI_PROVIDERS[provider]!.group === group); | |
| 148 | } | |
| 149 | ||
| 150 | /** Whether a provider is one whose own endpoint the connection gives. */ | |
| 151 | export function isEndpoint(provider: Provider): boolean { | |
| 152 | return provider === "anthropic_endpoint" || provider === "openai_endpoint"; | |
| 153 | } |