Skip to content

g1t/packages/contracts/src/integrations.ts

250 lines8,718 bytesCodeBlame

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;
55};
56
57export type Connection = {
58 id: string;
59 workspace: string;
60 provider: Provider;
61 kind: ProviderKind;
62 name: string;
63 config: ConnectionConfig;
64 /** `…3f9a`. The secret itself is never shown again. */
65 secretHint: string | null;
66 /** Where a provider that sends g1t requests sends them. */
67 webhookUrl: string | null;
68 createdBy: string;
69 createdAt: string;
70 lastUsedAt: string | null;
71 lastError: string | null;
Models per workspace: several providers, routed by kind of work72 /** For a model provider: the models it offered when last checked. */
73 models: string[];
Integrations: your own model provider, alerts that open issues, tickets agents read74};
75
Models per workspace: several providers, routed by kind of work76/** The kinds of work a model is chosen for, and `default` for the rest. */
77export const MODEL_TASKS = ["default", "implement", "review", "plan", "update"] as const;
78export type ModelTask = (typeof MODEL_TASKS)[number];
79
80/** Where one kind of work's model requests go: g1t's hosted models when `connectionId` is null. */
81export type ModelRoute = { task: ModelTask; connectionId: string | null; model: string | null };
82
Integrations: your own model provider, alerts that open issues, tickets agents read83export type Connected = {
84 connection: Connection;
85 /** A signing secret g1t made, shown this once. */
86 signingSecret: string | null;
87};
88
89export type Delivery = {
90 id: string;
91 receivedAt: string;
92 event: string;
93 outcome: "opened" | "updated" | "reopened" | "ignored" | "refused";
94 detail: string;
95 issue: string | null;
96};
97
98/** Something outside g1t, fetched now. Reference material, never instructions. */
99export type ContextItem = {
100 provider: Provider;
101 key: string;
102 title: string;
103 url: string;
104 status: string | null;
105 body: string;
106 fetchedAt: string;
107};
108
109export type Link = {
110 provider: Provider;
111 connectionId: string;
112 key: string;
113 title: string;
114 url: string;
115 count: number;
116 firstSeen: string;
117 lastSeen: string;
118};
119
Merge branch 'model-routing'120/**
121 * How capable, and how costly, a model g1t routes to is: `small` (fast),
122 * `large` (standard) or `frontier` (most capable).
123 */
124export type ModelTier = "small" | "large" | "frontier";
125
126/** The tiers, cheapest first. */
127export const MODEL_TIERS: ModelTier[] = ["small", "large", "frontier"];
128
Integrations: your own model provider, alerts that open issues, tickets agents read129export type ModelSession = {
130 token: string;
131 billedTo: "g1t" | "workspace";
132 providerName: string | null;
133 model: string | null;
Merge branch 'model-routing'134 /**
135 * Names the run in AI Gateway's logs (`metadata.session`) and its tokens
136 * in billing's count, on g1t's models and the workspace's own alike.
137 */
Prices keep themselves current with what g1t pays138 id: string;
Merge branch 'model-routing'139 /**
140 * The tier the workspace chose for this work on g1t's models, instead of
141 * Auto; the run goes there. Null for Auto, and on its own providers.
142 */
143 tierChoice?: ModelTier | null;
Integrations: your own model provider, alerts that open issues, tickets agents read144};
145
146export type ModelUpstream = {
147 route: "g1t" | "anthropic" | "endpoint";
Models per workspace: several providers, routed by kind of work148 /** The API the provider speaks, which the proxy translates to. */
149 api: "anthropic" | "openai";
150 /** The model every request of the run goes to, when the route names one. */
151 model: string | null;
152 /** OpenAI's own API. */
153 official: boolean;
A catalogue of model providers, and settings that feel like settings154 /** Which provider, by name, for its quirks. */
155 provider: string;
Integrations: your own model provider, alerts that open issues, tickets agents read156 workspace: string;
157 repo: string;
158 number: number;
159 task: string;
Prices keep themselves current with what g1t pays160 /** The session's id; see `ModelSession.id`. */
161 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 tier162 /** For `g1t`: the tier the run was routed to. */
Merge branch 'model-routing'163 tier?: ModelTier | null;
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix164 /** The person the run is for, by username. Null when nobody asked; never `g1t`. */
165 requestedBy: string | null;
Integrations: your own model provider, alerts that open issues, tickets agents read166 baseUrl: string | null;
167 apiKey: string | null;
168 authHeader: string | null;
Model providers: gateway tokens for endpoints, tidier rows, and the docs169 /** For an endpoint behind an authenticated Cloudflare AI Gateway: its token. */
170 gatewayToken?: string | null;
Integrations: your own model provider, alerts that open issues, tickets agents read171};
172
173export type ConnectInput = {
174 provider: Provider;
175 name?: string;
176 config?: ConnectionConfig;
177 secret?: string;
178 signingSecret?: string;
179};
180
181export type UpdateConnectionInput = {
182 name?: string;
183 config?: ConnectionConfig;
184 secret?: string;
185 signingSecret?: string;
186};
187
188export interface IntegrationsApi {
189 list(workspace: string, viewer: Viewer): Promise<Result<Connection[]>>;
190 connect(actor: User, workspace: string, input: ConnectInput): Promise<Result<Connected>>;
191 update(actor: User, workspace: string, id: string, input: UpdateConnectionInput): Promise<Result<Connection>>;
192 disconnect(actor: User, workspace: string, id: string): Promise<Result<boolean>>;
193 test(actor: User, workspace: string, id: string): Promise<Result<{ ok: boolean; message: string }>>;
194 deliveries(workspace: string, viewer: Viewer, id: string): Promise<Result<Delivery[]>>;
195 resolve(workspace: string, viewer: Viewer, reference: string): Promise<Result<ContextItem>>;
196 /** For g1t's agents: what `text` refers to outside g1t, fetched. */
197 references(workspace: string, text: string, limit?: number): Promise<ContextItem[]>;
198 import(actor: User, repo: RepoPath, reference: string, assign: boolean): Promise<Result<{ number: number; item: ContextItem; created: boolean }>>;
199 links(repo: RepoPath, number: number): Promise<Link[]>;
200 modelProvider(workspace: string): Promise<Connection | null>;
Models per workspace: several providers, routed by kind of work201 openModelSession(run: {
202 workspace: string;
203 repo: RepoPath;
204 number: number;
205 task: string;
206 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 tier207 /** The tier the run is routed to on g1t's hosted models, for the gateway's logs. */
Merge branch 'model-routing'208 tier?: ModelTier | null;
Mission control shows model usage, yours and the workspace's: tokens, cost, active days, cache share, each day, and the mix209 /** The person the run is for, by username, so its tokens show under them. */
210 requestedBy?: string | null;
Models per workspace: several providers, routed by kind of work211 }): Promise<Result<ModelSession>>;
212 routes(workspace: string, viewer: Viewer): Promise<Result<ModelRoute[]>>;
213 setRoutes(actor: User, workspace: string, routes: ModelRoute[]): Promise<Result<ModelRoute[]>>;
Integrations: your own model provider, alerts that open issues, tickets agents read214 modelUpstream(token: string): Promise<ModelUpstream | null>;
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily215 /**
Merge the AI Gateway: Anthropic's Messages API on a workspace's tokens216 * Where a workspace's AI Gateway requests go on its own key: its first
217 * Anthropic or Anthropic-compatible model provider, with task `gateway`.
218 * Null sends them to g1t's models.
219 */
220 gatewayUpstream(workspace: string): Promise<ModelUpstream | null>;
221 /**
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily222 * Ends the model sessions whose tokens hash to these (SHA-256, lowercase
223 * hex) when their run finishes, so the tokens stop working then. Returns
224 * how many were open.
225 */
226 closeModelSessions(tokenHashes: string[]): Promise<number>;
Integrations: your own model provider, alerts that open issues, tickets agents read227}
228
229/** What each provider is for, as people choose between them. */
230export const PROVIDERS: Record<Provider, { label: string; kind: ProviderKind }> = {
231 anthropic: { label: "Anthropic", kind: "models" },
Models per workspace: several providers, routed by kind of work232 openai: { label: "OpenAI", kind: "models" },
233 gemini: { label: "Google Gemini", kind: "models" },
A catalogue of model providers, and settings that feel like settings234 xai: { label: "xAI", kind: "models" },
235 mistral: { label: "Mistral", kind: "models" },
236 deepseek: { label: "DeepSeek", kind: "models" },
237 azure_openai: { label: "Azure OpenAI", kind: "models" },
238 openrouter: { label: "OpenRouter", kind: "models" },
239 groq: { label: "Groq", kind: "models" },
240 together: { label: "Together AI", kind: "models" },
241 fireworks: { label: "Fireworks AI", kind: "models" },
242 cerebras: { label: "Cerebras", kind: "models" },
243 anthropic_endpoint: { label: "Anthropic-compatible endpoint", kind: "models" },
Models per workspace: several providers, routed by kind of work244 openai_endpoint: { label: "OpenAI-compatible endpoint", kind: "models" },
Integrations: your own model provider, alerts that open issues, tickets agents read245 sentry: { label: "Sentry", kind: "alerts" },
246 datadog: { label: "Datadog", kind: "alerts" },
247 webhook: { label: "Webhook", kind: "alerts" },
248 jira: { label: "Jira", kind: "tracker" },
249 linear: { label: "Linear", kind: "tracker" },
250};

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