Skip to content
303 linesCodeBlameRaw

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.

Integrations: your own model provider, alerts that open issues, tickets agents read1import type { User, Viewer } from "./identity";
2import type { RepoPath } from "./repos";
3import 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 */
9export type Provider =
10 | "anthropic"
Models per workspace: several providers, routed by kind of work11 | "openai"
12 | "gemini"
A catalogue of model providers, and settings that feel like settings13 | "xai"
14 | "mistral"
15 | "deepseek"
16 | "azure_openai"
17 | "openrouter"
18 | "groq"
19 | "together"
20 | "fireworks"
21 | "cerebras"
22 | "anthropic_endpoint"
Models per workspace: several providers, routed by kind of work23 | "openai_endpoint"
Integrations: your own model provider, alerts that open issues, tickets agents read24 | "sentry"
25 | "datadog"
26 | "webhook"
27 | "jira"
28 | "linear";
29
30export type ProviderKind = "models" | "alerts" | "tracker";
31
32export 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;
Models per workspace: several providers, routed by kind of work53 /** Models: the model used when a route to this connection names none. */
Integrations: your own model provider, alerts that open issues, tickets agents read54 model?: string;
AI Gateway: OpenAI's format, open models, and your own providers55 /**
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[];
Integrations: your own model provider, alerts that open issues, tickets agents read63};
64
AI Gateway: OpenAI's format, open models, and your own providers65/** One of a workspace's own model providers, for the AI Gateway. Carries its key: for the model proxy only. */
66export 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. */
87export function gatewayPatterns(provider: Provider, config: ConnectionConfig): string[] {
88 if (config.gatewayModels) return config.gatewayModels;
89 return provider === "anthropic" || provider === "anthropic_endpoint" ? ["claude-*"] : [];
90}
91
Integrations: your own model provider, alerts that open issues, tickets agents read92export 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;
Models per workspace: several providers, routed by kind of work107 /** For a model provider: the models it offered when last checked. */
108 models: string[];
Integrations: your own model provider, alerts that open issues, tickets agents read109};
110
Models per workspace: several providers, routed by kind of work111/** The kinds of work a model is chosen for, and `default` for the rest. */
112export const MODEL_TASKS = ["default", "implement", "review", "plan", "update"] as const;
113export 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. */
116export type ModelRoute = { task: ModelTask; connectionId: string | null; model: string | null };
117
Integrations: your own model provider, alerts that open issues, tickets agents read118export type Connected = {
119 connection: Connection;
120 /** A signing secret g1t made, shown this once. */
121 signingSecret: string | null;
122};
123
124export 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. */
134export 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
144export 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 */
159export type ModelTier = "small" | "large" | "frontier";
160
161/** The tiers, cheapest first. */
162export const MODEL_TIERS: ModelTier[] = ["small", "large", "frontier"];
163
Integrations: your own model provider, alerts that open issues, tickets agents read164export 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 pays173 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;
Integrations: your own model provider, alerts that open issues, tickets agents read179};
180
181export type ModelUpstream = {
182 route: "g1t" | "anthropic" | "endpoint";
Models per workspace: several providers, routed by kind of work183 /** 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;
A catalogue of model providers, and settings that feel like settings189 /** Which provider, by name, for its quirks. */
190 provider: string;
Integrations: your own model provider, alerts that open issues, tickets agents read191 workspace: string;
192 repo: string;
193 number: number;
194 task: string;
Prices keep themselves current with what g1t pays195 /** 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 tier197 /** 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 mix199 /** The person the run is for, by username. Null when nobody asked; never `g1t`. */
200 requestedBy: string | null;
Integrations: your own model provider, alerts that open issues, tickets agents read201 baseUrl: string | null;
202 apiKey: string | null;
203 authHeader: string | null;
Model providers: gateway tokens for endpoints, tidier rows, and the docs204 /** 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;
Integrations: your own model provider, alerts that open issues, tickets agents read212};
213
214export type ConnectInput = {
215 provider: Provider;
216 name?: string;
217 config?: ConnectionConfig;
218 secret?: string;
219 signingSecret?: string;
220};
221
222export type UpdateConnectionInput = {
223 name?: string;
224 config?: ConnectionConfig;
225 secret?: string;
226 signingSecret?: string;
227};
228
229export 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 }>>;
240 links(repo: RepoPath, number: number): Promise<Link[]>;
241 modelProvider(workspace: string): Promise<Connection | null>;
Models per workspace: several providers, routed by kind of work242 openModelSession(run: {
243 workspace: string;
244 repo: RepoPath;
245 number: number;
246 task: string;
247 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 tier248 /** The tier the run is routed to on g1t's hosted models, for the gateway's logs. */
Merge branch 'model-routing'249 tier?: ModelTier | null;
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix250 /** The person the run is for, by username, so its tokens show under them. */
251 requestedBy?: string | null;
Models per workspace: several providers, routed by kind of work252 }): Promise<Result<ModelSession>>;
253 routes(workspace: string, viewer: Viewer): Promise<Result<ModelRoute[]>>;
254 setRoutes(actor: User, workspace: string, routes: ModelRoute[]): Promise<Result<ModelRoute[]>>;
Integrations: your own model provider, alerts that open issues, tickets agents read255 modelUpstream(token: string): Promise<ModelUpstream | null>;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily256 /**
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens257 * Where a workspace's AI Gateway requests go on its own key: its first
258 * Anthropic or Anthropic-compatible model provider, with task `gateway`.
259 * Null sends them to g1t's models.
260 */
261 gatewayUpstream(workspace: string): Promise<ModelUpstream | null>;
262 /**
AI Gateway: OpenAI's format, open models, and your own providers263 * The workspace's own model providers, in the order they were connected,
264 * with their keys and which AI Gateway models each takes. For the model
265 * proxy only.
266 */
267 gatewayProviders(workspace: string): Promise<GatewayProvider[]>;
268 /**
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily269 * Ends the model sessions whose tokens hash to these (SHA-256, lowercase
270 * hex) when their run finishes, so the tokens stop working then. Returns
271 * how many were open.
272 */
273 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)274 /**
275 * Sets the most the runs whose model tokens hash to these may spend on
276 * models, in millionths of a dollar, which the model proxy holds them
277 * to. Zero clears it. Returns how many open sessions it set.
278 */
279 capModelSessions(tokenHashes: string[], capMicros: number): Promise<number>;
Integrations: your own model provider, alerts that open issues, tickets agents read280}
281
282/** What each provider is for, as people choose between them. */
283export const PROVIDERS: Record<Provider, { label: string; kind: ProviderKind }> = {
284 anthropic: { label: "Anthropic", kind: "models" },
Models per workspace: several providers, routed by kind of work285 openai: { label: "OpenAI", kind: "models" },
286 gemini: { label: "Google Gemini", kind: "models" },
A catalogue of model providers, and settings that feel like settings287 xai: { label: "xAI", kind: "models" },
288 mistral: { label: "Mistral", kind: "models" },
289 deepseek: { label: "DeepSeek", kind: "models" },
290 azure_openai: { label: "Azure OpenAI", kind: "models" },
291 openrouter: { label: "OpenRouter", kind: "models" },
292 groq: { label: "Groq", kind: "models" },
293 together: { label: "Together AI", kind: "models" },
294 fireworks: { label: "Fireworks AI", kind: "models" },
295 cerebras: { label: "Cerebras", kind: "models" },
296 anthropic_endpoint: { label: "Anthropic-compatible endpoint", kind: "models" },
Models per workspace: several providers, routed by kind of work297 openai_endpoint: { label: "OpenAI-compatible endpoint", kind: "models" },
Integrations: your own model provider, alerts that open issues, tickets agents read298 sentry: { label: "Sentry", kind: "alerts" },
299 datadog: { label: "Datadog", kind: "alerts" },
300 webhook: { label: "Webhook", kind: "alerts" },
301 jira: { label: "Jira", kind: "tracker" },
302 linear: { label: "Linear", kind: "tracker" },
303};

This file's history is long; its oldest lines are credited to the oldest commit read.