pr_01m47d24b0e6n91zwymwxg0vpx/packages/contracts/src/integrations.ts

209 lines7,036 bytesCodeBlame
1import 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"
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
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;
53 /** Models: the model used when a route to this connection names none. */
54 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;
72 /** For a model provider: the models it offered when last checked. */
73 models: string[];
74};
75
76/** 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
83export 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
120export type ModelSession = {
121 token: string;
122 billedTo: "g1t" | "workspace";
123 providerName: string | null;
124 model: string | null;
125};
126
127export type ModelUpstream = {
128 route: "g1t" | "anthropic" | "endpoint";
129 /** The API the provider speaks, which the proxy translates to. */
130 api: "anthropic" | "openai";
131 /** The model every request of the run goes to, when the route names one. */
132 model: string | null;
133 /** OpenAI's own API. */
134 official: boolean;
135 /** Which provider, by name, for its quirks. */
136 provider: string;
137 workspace: string;
138 repo: string;
139 number: number;
140 task: string;
141 baseUrl: string | null;
142 apiKey: string | null;
143 authHeader: string | null;
144 /** For an endpoint behind an authenticated Cloudflare AI Gateway: its token. */
145 gatewayToken?: string | null;
146};
147
148export type ConnectInput = {
149 provider: Provider;
150 name?: string;
151 config?: ConnectionConfig;
152 secret?: string;
153 signingSecret?: string;
154};
155
156export type UpdateConnectionInput = {
157 name?: string;
158 config?: ConnectionConfig;
159 secret?: string;
160 signingSecret?: string;
161};
162
163export interface IntegrationsApi {
164 list(workspace: string, viewer: Viewer): Promise<Result<Connection[]>>;
165 connect(actor: User, workspace: string, input: ConnectInput): Promise<Result<Connected>>;
166 update(actor: User, workspace: string, id: string, input: UpdateConnectionInput): Promise<Result<Connection>>;
167 disconnect(actor: User, workspace: string, id: string): Promise<Result<boolean>>;
168 test(actor: User, workspace: string, id: string): Promise<Result<{ ok: boolean; message: string }>>;
169 deliveries(workspace: string, viewer: Viewer, id: string): Promise<Result<Delivery[]>>;
170 resolve(workspace: string, viewer: Viewer, reference: string): Promise<Result<ContextItem>>;
171 /** For g1t's agents: what `text` refers to outside g1t, fetched. */
172 references(workspace: string, text: string, limit?: number): Promise<ContextItem[]>;
173 import(actor: User, repo: RepoPath, reference: string, assign: boolean): Promise<Result<{ number: number; item: ContextItem; created: boolean }>>;
174 links(repo: RepoPath, number: number): Promise<Link[]>;
175 modelProvider(workspace: string): Promise<Connection | null>;
176 openModelSession(run: {
177 workspace: string;
178 repo: RepoPath;
179 number: number;
180 task: string;
181 hostedOpen: boolean;
182 }): Promise<Result<ModelSession>>;
183 routes(workspace: string, viewer: Viewer): Promise<Result<ModelRoute[]>>;
184 setRoutes(actor: User, workspace: string, routes: ModelRoute[]): Promise<Result<ModelRoute[]>>;
185 modelUpstream(token: string): Promise<ModelUpstream | null>;
186}
187
188/** What each provider is for, as people choose between them. */
189export const PROVIDERS: Record<Provider, { label: string; kind: ProviderKind }> = {
190 anthropic: { label: "Anthropic", kind: "models" },
191 openai: { label: "OpenAI", kind: "models" },
192 gemini: { label: "Google Gemini", kind: "models" },
193 xai: { label: "xAI", kind: "models" },
194 mistral: { label: "Mistral", kind: "models" },
195 deepseek: { label: "DeepSeek", kind: "models" },
196 azure_openai: { label: "Azure OpenAI", kind: "models" },
197 openrouter: { label: "OpenRouter", kind: "models" },
198 groq: { label: "Groq", kind: "models" },
199 together: { label: "Together AI", kind: "models" },
200 fireworks: { label: "Fireworks AI", kind: "models" },
201 cerebras: { label: "Cerebras", kind: "models" },
202 anthropic_endpoint: { label: "Anthropic-compatible endpoint", kind: "models" },
203 openai_endpoint: { label: "OpenAI-compatible endpoint", kind: "models" },
204 sentry: { label: "Sentry", kind: "alerts" },
205 datadog: { label: "Datadog", kind: "alerts" },
206 webhook: { label: "Webhook", kind: "alerts" },
207 jira: { label: "Jira", kind: "tracker" },
208 linear: { label: "Linear", kind: "tracker" },
209};