flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/packages/contracts/src/billing.ts

237 lines8,870 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.

Agents as a team: lifecycle, merge queue, billing and a new shell1import type { User, Viewer } from "./identity";
2import type { RepoPath } from "./repos";
3import type { Result } from "./result";
4
5/** Millionths of a US dollar in one dollar: the unit money is held in. */
6export const MICROS_PER_DOLLAR = 1_000_000;
7
8/** Whether workspaces are charged for agents at all, and with real money. */
9export type BillingStatus = {
10 /**
11 * False when no card processor is configured: nothing is charged, and who
12 * may run agents is decided some other way.
13 */
14 enabled: boolean;
15 /** False while the card processor is in its test mode, where cards are not real. */
16 live: boolean;
Free while g1t is being built out; agents can check out their own forks17 /**
18 * True while g1t is being built out: runs are recorded with what they
19 * cost, but nothing is charged and no credit is needed. Not forever.
20 */
21 free?: boolean;
Agents as a team: lifecycle, merge queue, billing and a new shell22};
23
24/** A workspace's standing. */
25export type BillingAccount = {
26 workspace: string;
27 /**
28 * Credit left, in millionths of a dollar. Can dip below zero by the cost
29 * of the runs that were under way when it ran out.
30 */
31 balanceMicros: number;
32 status: BillingStatus;
33 /** What is added to a run's cost, in percent. */
34 marginPercent: number;
Integrations: your own model provider, alerts that open issues, tickets agents read35 /** What a run on the workspace's own model provider is charged instead. */
36 orchestrationFeeMicros: number;
Agents as a team: lifecycle, merge queue, billing and a new shell37};
38
39/** One line of a workspace's statement. */
40export type LedgerEntry = {
41 id: string;
42 /** Credit bought with a card, or an agent's run. */
43 kind: "top_up" | "usage";
44 /** Positive for credit added, negative for usage. */
45 amountMicros: number;
46 description: string;
47 /** For usage: the repository and pull request the agent worked on. */
48 repo: string | null;
49 number: number | null;
50 /** For usage: `implement`, `review` or `update`. */
51 task: string | null;
52 /** For usage: the model, by its public name. */
53 model: string | null;
Integrations: your own model provider, alerts that open issues, tickets agents read54 /** For usage: who paid the model provider. */
55 billedTo: "g1t" | "workspace";
Agents as a team: lifecycle, merge queue, billing and a new shell56 /** For a top-up: the username of whoever paid. */
57 createdBy: string | null;
58 /** RFC 3339. */
59 createdAt: string;
60};
61
62/** What lets a sandbox, and nothing else, report what its run cost. */
63export type RunTicket = { runId: string; token: string };
64
65/**
66 * What agents cost, charged to the workspace they worked for. A workspace
67 * buys credit; each run deducts its cost plus g1t's margin; with no credit,
68 * no agent starts.
69 */
A free allowance on g1t's models, so anyone can try its agents70/**
71 * The free allowance on g1t's hosted models for a workspace not otherwise
72 * open to them: a few dollars of model cost each, out of one pool, until a
73 * date. Mirrors `Trial` in `crates/contracts/src/billing.rs`.
74 */
75export type Trial = {
76 open: boolean;
77 usedMicros: number;
78 limitMicros: number;
79 endsAt: string | null;
80 /** Why it is closed: `off`, `ended`, `used` (this workspace's) or `pool` (everyone's). */
81 reason: "off" | "ended" | "used" | "pool" | null;
82};
83
Paid features: a workspace turns on Deployments with a monthly plan84/**
85 * A paid feature a workspace turns on with a monthly plan, as Cloudflare's
86 * Workers for Platforms or Vercel's Pro are bought. Never free: neither
87 * `free` nor the model allowance covers it. Mirrors `Feature` in
88 * `crates/contracts/src/billing.rs`.
89 */
90export type Feature = "deployments";
91
92/** What the Deployments plan includes each month. Mirrors `deployments_allowance`. */
93export const DEPLOYMENTS_ALLOWANCE = {
94 apps: 10,
95 requests: 1_000_000,
96 cpuMs: 3_000_000,
97 /** What Cloudflare charges g1t past that, in millionths of a dollar. */
98 microsPerAppMonth: 20_000,
99 microsPerMillionRequests: 300_000,
100 microsPerMillionCpuMs: 20_000,
Deployments: a preview for every pull request, production on g1t.page101 /** One second of a build's sandbox; builds are charged, not included. */
102 microsPerBuildSecond: 21,
Paid features: a workspace turns on Deployments with a monthly plan103} as const;
104
105export type FeaturePlan = {
106 feature: Feature;
107 title: string;
108 /** Charged every month while the plan is on, in cents. */
109 monthlyCents: number;
110 /** What the price includes, one line each. */
111 includes: string[];
112 /** How usage past the allowance is charged. */
113 overage: string;
114};
115
116export type SubscriptionStatus = "active" | "canceling" | "past_due" | "canceled";
117
118export type Subscription = {
119 feature: Feature;
120 status: SubscriptionStatus;
121 /** RFC 3339: when the period paid for ends. */
122 periodEnd: string | null;
123 startedBy: string;
124 startedAt: string;
125};
126
127/** A feature as a workspace sees it. */
128export type FeatureState = {
129 plan: FeaturePlan;
130 subscription: Subscription | null;
131 /** Whether the feature works for the workspace now. */
132 on: boolean;
133};
134
Agents as a team: lifecycle, merge queue, billing and a new shell135export interface BillingApi {
136 status(): Promise<BillingStatus>;
137 /** Members of the workspace only. */
138 account(workspace: string, viewer: Viewer): Promise<Result<BillingAccount>>;
139 /** Newest first. Members of the workspace only. */
140 ledger(workspace: string, viewer: Viewer): Promise<Result<LedgerEntry[]>>;
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request141 /** What the workspace's agents cost since `since`, broken down. Members only. */
142 usage(workspace: string, viewer: Viewer, since: string): Promise<Result<Usage>>;
Agents as a team: lifecycle, merge queue, billing and a new shell143 /**
144 * Starts a card payment for credit and returns the page to send the
145 * person to. Owners only. The payment's id comes back to `returnUrl` as
146 * `session`.
147 */
148 checkout(actor: User, workspace: string, amountCents: number, returnUrl: string): Promise<Result<{ url: string }>>;
149 /** Credits a payment once the processor says it was made. Safe to repeat. */
150 confirm(workspace: string, viewer: Viewer, session: string): Promise<Result<BillingAccount>>;
151 /**
152 * Whether a workspace may start an agent now, asked before anything is
153 * opened for it. A failure, with the reason to show, when it has no credit.
154 */
155 canStart(workspace: string): Promise<Result<boolean>>;
A free allowance on g1t's models, so anyone can try its agents156 /** A workspace's free allowance on g1t's hosted models; `exempt` are open to them anyway. */
157 trial(workspace: string, exempt: string[]): Promise<Trial>;
Agents as a team: lifecycle, merge queue, billing and a new shell158 /**
159 * Asks whether a workspace may start an agent and opens the run it will be
160 * charged for. Null when billing is off; a failure when there is no credit.
161 */
Paid features: a workspace turns on Deployments with a monthly plan162 /** Every paid feature and the workspace's plan for each. Members only. */
163 features(workspace: string, viewer: Viewer): Promise<Result<FeatureState[]>>;
164 /**
165 * Starts the card page for a feature's monthly plan. Owners only. The
166 * page's id comes back to `returnUrl` as `session`.
167 */
168 subscribe(actor: User, workspace: string, feature: Feature, returnUrl: string): Promise<Result<{ url: string }>>;
169 /** Turns the feature on once the plan is paid for. Safe to repeat. */
170 confirmSubscription(workspace: string, viewer: Viewer, session: string): Promise<Result<FeatureState>>;
171 /** Ends a plan at the end of its period, or (`resume`) takes that back. Owners only. */
172 cancelSubscription(actor: User, workspace: string, feature: Feature, resume?: boolean): Promise<Result<FeatureState>>;
173 /** Whether a feature works for a workspace now; a failure with the reason when not. */
174 hasFeature(workspace: string, feature: Feature): Promise<Result<boolean>>;
175 /**
176 * Usage past a plan's allowance, charged from credit at cost plus the
177 * margin, once per `reference`. False if it was charged before.
178 */
179 chargeFeature(charge: {
180 workspace: string;
181 feature: Feature;
182 costMicros: number;
183 description: string;
184 repo?: string | null;
185 reference: string;
186 }): Promise<Result<boolean>>;
Every sandbox is metered by the second187 /**
188 * How long a sandbox ran for a workspace, reported when it stops. Its
189 * cost is always recorded; seconds past the month's free minutes are
190 * charged. False if `reference` was recorded before.
191 */
192 recordSandbox(usage: {
193 workspace: string;
194 seconds: number;
195 description: string;
196 repo?: string | null;
197 reference: string;
198 }): Promise<Result<boolean>>;
Agents as a team: lifecycle, merge queue, billing and a new shell199 startRun(run: {
200 workspace: string;
201 repo: RepoPath;
202 number: number;
203 task: string;
204 model: string;
Integrations: your own model provider, alerts that open issues, tickets agents read205 /** `workspace` when the run uses the workspace's own model provider. */
206 billedTo?: "g1t" | "workspace";
Agents as a team: lifecycle, merge queue, billing and a new shell207 }): Promise<Result<RunTicket | null>>;
208}
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request209
210
211/** One slice of usage: what it was for, what it cost, how many runs. */
212export type UsageSlice = { key: string; micros: number; runs: number };
213
214/** What a workspace's agents cost over a period. */
215export type Usage = {
216 since: string;
217 /** Charged, including g1t's margin. */
218 spentMicros: number;
Integrations: your own model provider, alerts that open issues, tickets agents read219 /** What g1t's model provider charged, before the margin. */
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request220 costMicros: number;
Integrations: your own model provider, alerts that open issues, tickets agents read221 /** What runs on the workspace's own provider cost there, estimated. Not charged by g1t. */
222 providerMicros: number;
Usage while free is shown at cost; agents get rustfmt and clippy223 /** What the runs used, at cost: g1t's models and the workspace's own provider together. */
224 usedMicros: number;
225 /** g1t charges nothing for now; the slices then measure usage at cost. */
226 free: boolean;
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request227 runs: number;
228 /** Spend per day and task, keyed `YYYY-MM-DD/task`. */
229 byDay: UsageSlice[];
230 byTask: UsageSlice[];
231 byRepo: UsageSlice[];
232 /** Keyed `namespace/name#number`. */
233 byPull: UsageSlice[];
234 byModel: UsageSlice[];
235 /** Credit bought in the period. */
236 addedMicros: number;
237};