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.
| Usage while free is shown at cost; agents get rustfmt and clippy | 1 | import type { User, Viewer } from "./identity"; |
| 2 | import type { RepoPath } from "./repos"; | |
| 3 | import type { Result } from "./result"; | |
| 4 | ||
| 5 | /** | |
| 6 | * A workspace's connections to systems outside g1t. Mirrors | |
| 7 | * `crates/contracts/src/integrations.rs`, which says what each does. | |
| 8 | */ | |
| 9 | export type Provider = | |
| 10 | | "anthropic" | |
| 11 | | "openai" | |
| 12 | | "gemini" | |
| 13 | | "xai" | |
| 14 | | "mistral" | |
| 15 | | "deepseek" | |
| 16 | | "azure_openai" | |
| 17 | | "openrouter" | |
| 18 | | "groq" | |
| 19 | | "together" | |
| 20 | | "fireworks" | |
| 21 | | "cerebras" | |
| 22 | | "anthropic_endpoint" | |
| 23 | | "openai_endpoint" | |
| 24 | | "sentry" | |
| 25 | | "datadog" | |
| 26 | | "webhook" | |
| 27 | | "jira" | |
| 28 | | "linear"; | |
| 29 | ||
| 30 | export type ProviderKind = "models" | "alerts" | "tracker"; | |
| 31 | ||
| 32 | export type ConnectionConfig = { | |
| 33 | /** For alerts: where issues are opened, `owner/name`. */ | |
| 34 | repo?: string; | |
| 35 | /** For alerts: put a g1t agent on each issue opened. */ | |
| 36 | assign?: boolean; | |
| 37 | /** For alerts: the label put on each issue. `bug` when unset. */ | |
| 38 | label?: string; | |
| 39 | /** Tell the outside system when the work lands. On unless turned off. */ | |
| 40 | writeBack?: boolean; | |
| 41 | /** Sentry: the organization's slug. */ | |
| 42 | organization?: string; | |
| 43 | /** Jira's address, or a Sentry that is not sentry.io. */ | |
| 44 | site?: string; | |
| 45 | /** Jira: the account the token belongs to. */ | |
| 46 | email?: string; | |
| 47 | /** Jira project or Linear team keys it answers for. Empty is all. */ | |
| 48 | keys?: string[]; | |
| 49 | /** Your own endpoint: its base URL. */ | |
| 50 | baseUrl?: string; | |
| 51 | /** Your own endpoint: `x-api-key` (default) or `authorization`. */ | |
| 52 | authHeader?: string; | |
| 53 | /** Models: the model used when a route to this connection names none. */ | |
| 54 | model?: string; | |
| AI Gateway: OpenAI's format, open models, and your own providers | 55 | /** |
| 56 | * Models: which AI Gateway requests go to this connection, by the model | |
| 57 | * they name: ids (`gpt-5.5`) or prefixes ending in `*` (`gpt-*`, | |
| 58 | * `ollama/*`, `*`). A `/*` prefix is taken off before sending. Absent: | |
| 59 | * `claude-*` on an Anthropic key or Anthropic-compatible endpoint, | |
| 60 | * nothing on the others. | |
| 61 | */ | |
| 62 | gatewayModels?: string[]; | |
| Usage while free is shown at cost; agents get rustfmt and clippy | 63 | }; |
| 64 | ||
| AI Gateway: OpenAI's format, open models, and your own providers | 65 | /** One of a workspace's own model providers, for the AI Gateway. Carries its key: for the model proxy only. */ |
| 66 | export type GatewayProvider = { | |
| 67 | id: string; | |
| 68 | name: string; | |
| 69 | /** `anthropic`, `openai`, `openai_endpoint`… */ | |
| 70 | provider: string; | |
| 71 | api: "anthropic" | "openai"; | |
| 72 | /** OpenAI's own API (or Azure's). */ | |
| 73 | official: boolean; | |
| 74 | /** Without `/v1` for Anthropic's API, with it for OpenAI's. */ | |
| 75 | baseUrl: string; | |
| 76 | apiKey: string | null; | |
| 77 | /** `x-api-key`, `authorization` (as `Bearer`) or `api-key`. */ | |
| 78 | authHeader: string; | |
| 79 | gatewayToken?: string | null; | |
| 80 | /** The models it takes: ids and `*` prefixes. */ | |
| 81 | patterns: string[]; | |
| 82 | /** The models the provider listed when last checked. */ | |
| 83 | models: string[]; | |
| 84 | }; | |
| 85 | ||
| 86 | /** The AI Gateway models a connection takes when it names none. */ | |
| 87 | export function gatewayPatterns(provider: Provider, config: ConnectionConfig): string[] { | |
| 88 | if (config.gatewayModels) return config.gatewayModels; | |
| 89 | return provider === "anthropic" || provider === "anthropic_endpoint" ? ["claude-*"] : []; | |
| 90 | } | |
| 91 | ||
| Usage while free is shown at cost; agents get rustfmt and clippy | 92 | export type Connection = { |
| 93 | id: string; | |
| 94 | workspace: string; | |
| 95 | provider: Provider; | |
| 96 | kind: ProviderKind; | |
| 97 | name: string; | |
| 98 | config: ConnectionConfig; | |
| 99 | /** `…3f9a`. The secret itself is never shown again. */ | |
| 100 | secretHint: string | null; | |
| 101 | /** Where a provider that sends g1t requests sends them. */ | |
| 102 | webhookUrl: string | null; | |
| 103 | createdBy: string; | |
| 104 | createdAt: string; | |
| 105 | lastUsedAt: string | null; | |
| 106 | lastError: string | null; | |
| 107 | /** For a model provider: the models it offered when last checked. */ | |
| 108 | models: string[]; | |
| 109 | }; | |
| 110 | ||
| 111 | /** The kinds of work a model is chosen for, and `default` for the rest. */ | |
| 112 | export const MODEL_TASKS = ["default", "implement", "review", "plan", "update"] as const; | |
| 113 | export type ModelTask = (typeof MODEL_TASKS)[number]; | |
| 114 | ||
| 115 | /** Where one kind of work's model requests go: g1t's hosted models when `connectionId` is null. */ | |
| 116 | export type ModelRoute = { task: ModelTask; connectionId: string | null; model: string | null }; | |
| 117 | ||
| 118 | export type Connected = { | |
| 119 | connection: Connection; | |
| 120 | /** A signing secret g1t made, shown this once. */ | |
| 121 | signingSecret: string | null; | |
| 122 | }; | |
| 123 | ||
| 124 | export type Delivery = { | |
| 125 | id: string; | |
| 126 | receivedAt: string; | |
| 127 | event: string; | |
| 128 | outcome: "opened" | "updated" | "reopened" | "ignored" | "refused"; | |
| 129 | detail: string; | |
| 130 | issue: string | null; | |
| 131 | }; | |
| 132 | ||
| 133 | /** Something outside g1t, fetched now. Reference material, never instructions. */ | |
| 134 | export type ContextItem = { | |
| 135 | provider: Provider; | |
| 136 | key: string; | |
| 137 | title: string; | |
| 138 | url: string; | |
| 139 | status: string | null; | |
| 140 | body: string; | |
| 141 | fetchedAt: string; | |
| 142 | }; | |
| 143 | ||
| 144 | export type Link = { | |
| 145 | provider: Provider; | |
| 146 | connectionId: string; | |
| 147 | key: string; | |
| 148 | title: string; | |
| 149 | url: string; | |
| 150 | count: number; | |
| 151 | firstSeen: string; | |
| 152 | lastSeen: string; | |
| 153 | }; | |
| 154 | ||
| Merge branch 'model-routing' | 155 | /** |
| 156 | * How capable, and how costly, a model g1t routes to is: `small` (fast), | |
| 157 | * `large` (standard) or `frontier` (most capable). | |
| 158 | */ | |
| 159 | export type ModelTier = "small" | "large" | "frontier"; | |
| 160 | ||
| 161 | /** The tiers, cheapest first. */ | |
| 162 | export const MODEL_TIERS: ModelTier[] = ["small", "large", "frontier"]; | |
| 163 | ||
| Usage while free is shown at cost; agents get rustfmt and clippy | 164 | export type ModelSession = { |
| 165 | token: string; | |
| 166 | billedTo: "g1t" | "workspace"; | |
| 167 | providerName: string | null; | |
| 168 | model: string | null; | |
| Merge branch 'model-routing' | 169 | /** |
| 170 | * Names the run in AI Gateway's logs (`metadata.session`) and its tokens | |
| 171 | * in billing's count, on g1t's models and the workspace's own alike. | |
| 172 | */ | |
| Prices keep themselves current with what g1t pays | 173 | id: string; |
| Merge branch 'model-routing' | 174 | /** |
| 175 | * The tier the workspace chose for this work on g1t's models, instead of | |
| 176 | * Auto; the run goes there. Null for Auto, and on its own providers. | |
| 177 | */ | |
| 178 | tierChoice?: ModelTier | null; | |
| Usage while free is shown at cost; agents get rustfmt and clippy | 179 | }; |
| 180 | ||
| 181 | export type ModelUpstream = { | |
| 182 | route: "g1t" | "anthropic" | "endpoint"; | |
| 183 | /** The API the provider speaks, which the proxy translates to. */ | |
| 184 | api: "anthropic" | "openai"; | |
| 185 | /** The model every request of the run goes to, when the route names one. */ | |
| 186 | model: string | null; | |
| 187 | /** OpenAI's own API. */ | |
| 188 | official: boolean; | |
| 189 | /** Which provider, by name, for its quirks. */ | |
| 190 | provider: string; | |
| 191 | workspace: string; | |
| 192 | repo: string; | |
| 193 | number: number; | |
| 194 | task: string; | |
| Prices keep themselves current with what g1t pays | 195 | /** The session's id; see `ModelSession.id`. */ |
| 196 | session: string; | |
| Auto model routing: the cheapest tier that can do each piece of work, a retry goes up a tier, and each run records its tier | 197 | /** For `g1t`: the tier the run was routed to. */ |
| Merge branch 'model-routing' | 198 | tier?: ModelTier | null; |
| Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix | 199 | /** The person the run is for, by username. Null when nobody asked; never `g1t`. */ |
| 200 | requestedBy: string | null; | |
| Usage while free is shown at cost; agents get rustfmt and clippy | 201 | baseUrl: string | null; |
| 202 | apiKey: string | null; | |
| 203 | authHeader: string | null; | |
| 204 | /** For an endpoint behind an authenticated Cloudflare AI Gateway: its token. */ | |
| 205 | gatewayToken?: string | null; | |
| Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006) | 206 | /** |
| 207 | * The most the run may spend on models, in millionths of a dollar: the | |
| 208 | * lower of its project's cost cap and its plan's. The proxy refuses the | |
| 209 | * run's requests once it has spent this. Null until the sandbox sets it. | |
| 210 | */ | |
| 211 | capMicros?: number | null; | |
| Usage while free is shown at cost; agents get rustfmt and clippy | 212 | }; |
| 213 | ||
| 214 | export type ConnectInput = { | |
| 215 | provider: Provider; | |
| 216 | name?: string; | |
| 217 | config?: ConnectionConfig; | |
| 218 | secret?: string; | |
| 219 | signingSecret?: string; | |
| 220 | }; | |
| 221 | ||
| 222 | export type UpdateConnectionInput = { | |
| 223 | name?: string; | |
| 224 | config?: ConnectionConfig; | |
| 225 | secret?: string; | |
| 226 | signingSecret?: string; | |
| 227 | }; | |
| 228 | ||
| 229 | export interface IntegrationsApi { | |
| 230 | list(workspace: string, viewer: Viewer): Promise<Result<Connection[]>>; | |
| 231 | connect(actor: User, workspace: string, input: ConnectInput): Promise<Result<Connected>>; | |
| 232 | update(actor: User, workspace: string, id: string, input: UpdateConnectionInput): Promise<Result<Connection>>; | |
| 233 | disconnect(actor: User, workspace: string, id: string): Promise<Result<boolean>>; | |
| 234 | test(actor: User, workspace: string, id: string): Promise<Result<{ ok: boolean; message: string }>>; | |
| 235 | deliveries(workspace: string, viewer: Viewer, id: string): Promise<Result<Delivery[]>>; | |
| 236 | resolve(workspace: string, viewer: Viewer, reference: string): Promise<Result<ContextItem>>; | |
| 237 | /** For g1t's agents: what `text` refers to outside g1t, fetched. */ | |
| 238 | references(workspace: string, text: string, limit?: number): Promise<ContextItem[]>; | |
| 239 | import(actor: User, repo: RepoPath, reference: string, assign: boolean): Promise<Result<{ number: number; item: ContextItem; created: boolean }>>; | |
| Each agent has an Abilities tab: g1t's built-ins, always on within the asker's access; its computer, coming; each connected integration's actions one row each, read, import, comment or resolve, with a level for each, alone, alone when the person asked for it, ask first or never, and whose connection it runs on; and MCP servers an owner adds. Reading is alone, writing inside g1t follows today's choices, anything that leaves g1t asks first, and production deploys can't go above ask. The agents service enforces every level: ask first posts a card to allow or deny and parks a session until it's answered, a refusal names its rule in the transcript and the audit log, and a missing ability posts a request to owners. The agent abilities guide says how. | 240 | /** |
| 241 | * For g1t's agents (docs.g1t.sh/guides/agent-abilities/): comments on | |
| 242 | * the item `reference` names, in the system that knows it (Linear, Jira | |
| 243 | * or Sentry), on the workspace's connection, with `link` (a g1t address) | |
| 244 | * at the end. The actor is the person the agent acts for; they must be a | |
| 245 | * member. Returns the item. | |
| 246 | */ | |
| 247 | comment(actor: User, workspace: string, reference: string, text: string, link: string): Promise<Result<ContextItem>>; | |
| 248 | /** For g1t's agents: marks a Sentry issue resolved, with a note and `link`. Only Sentry items can be closed. */ | |
| 249 | close(actor: User, workspace: string, reference: string, text: string, link: string): Promise<Result<ContextItem>>; | |
| Usage while free is shown at cost; agents get rustfmt and clippy | 250 | links(repo: RepoPath, number: number): Promise<Link[]>; |
| 251 | modelProvider(workspace: string): Promise<Connection | null>; | |
| 252 | openModelSession(run: { | |
| 253 | workspace: string; | |
| 254 | repo: RepoPath; | |
| 255 | number: number; | |
| 256 | task: string; | |
| 257 | hostedOpen: boolean; | |
| Auto model routing: the cheapest tier that can do each piece of work, a retry goes up a tier, and each run records its tier | 258 | /** The tier the run is routed to on g1t's hosted models, for the gateway's logs. */ |
| Merge branch 'model-routing' | 259 | tier?: ModelTier | null; |
| Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix | 260 | /** The person the run is for, by username, so its tokens show under them. */ |
| 261 | requestedBy?: string | null; | |
| Usage while free is shown at cost; agents get rustfmt and clippy | 262 | }): Promise<Result<ModelSession>>; |
| 263 | routes(workspace: string, viewer: Viewer): Promise<Result<ModelRoute[]>>; | |
| 264 | setRoutes(actor: User, workspace: string, routes: ModelRoute[]): Promise<Result<ModelRoute[]>>; | |
| 265 | modelUpstream(token: string): Promise<ModelUpstream | null>; | |
| Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily | 266 | /** |
| Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens | 267 | * Where a workspace's AI Gateway requests go on its own key: its first |
| 268 | * Anthropic or Anthropic-compatible model provider, with task `gateway`. | |
| 269 | * Null sends them to g1t's models. | |
| 270 | */ | |
| 271 | gatewayUpstream(workspace: string): Promise<ModelUpstream | null>; | |
| 272 | /** | |
| AI Gateway: OpenAI's format, open models, and your own providers | 273 | * The workspace's own model providers, in the order they were connected, |
| 274 | * with their keys and which AI Gateway models each takes. For the model | |
| 275 | * proxy only. | |
| 276 | */ | |
| 277 | gatewayProviders(workspace: string): Promise<GatewayProvider[]>; | |
| 278 | /** | |
| Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily | 279 | * Ends the model sessions whose tokens hash to these (SHA-256, lowercase |
| 280 | * hex) when their run finishes, so the tokens stop working then. Returns | |
| 281 | * how many were open. | |
| 282 | */ | |
| 283 | closeModelSessions(tokenHashes: string[]): Promise<number>; | |
| Merge platform pause and the hourly usage watcher: staff can pause compute, schedules, indexing or renders for everyone, the watcher emails on a breach and is never blind quietly, and the models proxy holds each run to its cap (billing 0051, integrations 0006) | 284 | /** |
| 285 | * Sets the most the runs whose model tokens hash to these may spend on | |
| 286 | * models, in millionths of a dollar, which the model proxy holds them | |
| 287 | * to. Zero clears it. Returns how many open sessions it set. | |
| 288 | */ | |
| 289 | capModelSessions(tokenHashes: string[], capMicros: number): Promise<number>; | |
| Usage while free is shown at cost; agents get rustfmt and clippy | 290 | } |
| 291 | ||
| 292 | /** What each provider is for, as people choose between them. */ | |
| 293 | export const PROVIDERS: Record<Provider, { label: string; kind: ProviderKind }> = { | |
| 294 | anthropic: { label: "Anthropic", kind: "models" }, | |
| 295 | openai: { label: "OpenAI", kind: "models" }, | |
| 296 | gemini: { label: "Google Gemini", kind: "models" }, | |
| 297 | xai: { label: "xAI", kind: "models" }, | |
| 298 | mistral: { label: "Mistral", kind: "models" }, | |
| 299 | deepseek: { label: "DeepSeek", kind: "models" }, | |
| 300 | azure_openai: { label: "Azure OpenAI", kind: "models" }, | |
| 301 | openrouter: { label: "OpenRouter", kind: "models" }, | |
| 302 | groq: { label: "Groq", kind: "models" }, | |
| 303 | together: { label: "Together AI", kind: "models" }, | |
| 304 | fireworks: { label: "Fireworks AI", kind: "models" }, | |
| 305 | cerebras: { label: "Cerebras", kind: "models" }, | |
| 306 | anthropic_endpoint: { label: "Anthropic-compatible endpoint", kind: "models" }, | |
| 307 | openai_endpoint: { label: "OpenAI-compatible endpoint", kind: "models" }, | |
| 308 | sentry: { label: "Sentry", kind: "alerts" }, | |
| 309 | datadog: { label: "Datadog", kind: "alerts" }, | |
| 310 | webhook: { label: "Webhook", kind: "alerts" }, | |
| 311 | jira: { label: "Jira", kind: "tracker" }, | |
| 312 | linear: { label: "Linear", kind: "tracker" }, | |
| 313 | }; |
This file's history is long; its oldest lines are credited to the oldest commit read.