217 lines7,252 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 shell1//! The billing service: what agents cost, charged to the workspace they
2//! worked for.
3//!
4//! A workspace buys credit and each agent run deducts what it cost, plus
5//! g1t's margin. With no credit, no agent starts. Money is held in
6//! millionths of a US dollar, so that a run costing a fraction of a cent is
7//! recorded exactly.
8//!
9//! Each `*Args` struct is the argument of the method of the same name,
10//! served at `POST /rpc/<method>`.
11
12use serde::{Deserialize, Serialize};
13
14use crate::repos::RepoPath;
15use crate::{User, Viewer};
16
17/// Millionths of a US dollar in one dollar.
18pub const MICROS_PER_DOLLAR: i64 = 1_000_000;
19
20/// Whether workspaces are charged for agents at all, and with real money.
21/// `status` takes nothing and returns this.
22#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)]
23pub struct Status {
24 /// False when no payment provider is configured: nothing is charged,
25 /// and who may run agents is decided some other way.
26 pub enabled: bool,
27 /// False while the payment provider is in its test mode, where cards
28 /// are not real.
29 pub live: bool,
30}
31
32/// A workspace's standing.
33#[derive(Clone, Debug, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct Account {
36 pub workspace: String,
37 /// Credit left, in millionths of a dollar. Can dip below zero by the
38 /// cost of the runs that were under way when it ran out.
39 pub balance_micros: i64,
40 pub status: Status,
41 /// What is added to a run's cost, in percent.
42 pub margin_percent: u32,
Integrations: your own model provider, alerts that open issues, tickets agents read43 /// What a run on the workspace's own model provider is charged: g1t's
44 /// sandbox and orchestration, with the model paid for elsewhere.
45 pub orchestration_fee_micros: i64,
Agents as a team: lifecycle, merge queue, billing and a new shell46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
49#[serde(rename_all = "snake_case")]
50pub enum EntryKind {
51 /// Credit bought with a card.
52 TopUp,
53 /// An agent's run.
54 Usage,
55}
56
57/// One line of a workspace's statement.
58#[derive(Clone, Debug, Serialize, Deserialize)]
59#[serde(rename_all = "camelCase")]
60pub struct LedgerEntry {
61 pub id: String,
62 pub kind: EntryKind,
63 /// Positive for credit added, negative for usage.
64 pub amount_micros: i64,
65 pub description: String,
66 /// For usage: the repository and pull request the agent worked on.
67 pub repo: Option<String>,
68 pub number: Option<u32>,
69 /// For usage: `implement`, `review` or `update`.
70 pub task: Option<String>,
71 /// For usage: the model, by its public name.
72 pub model: Option<String>,
Integrations: your own model provider, alerts that open issues, tickets agents read73 /// For usage: `g1t` when g1t paid the model provider, `workspace` when
74 /// the workspace's own account did and only orchestration is charged.
75 #[serde(default = "g1t")]
76 pub billed_to: String,
Agents as a team: lifecycle, merge queue, billing and a new shell77 /// For a top-up: the username of whoever paid.
78 pub created_by: Option<String>,
79 /// RFC 3339.
80 pub created_at: String,
81}
82
Integrations: your own model provider, alerts that open issues, tickets agents read83fn g1t() -> String {
84 "g1t".to_owned()
85}
86
Agents as a team: lifecycle, merge queue, billing and a new shell87/// `account` (`Outcome<Account>`) and `ledger` (`Outcome<Vec<LedgerEntry>>`,
88/// newest first). Members of the workspace only.
89#[derive(Debug, Serialize, Deserialize)]
90pub struct AccountArgs {
91 pub workspace: String,
92 pub viewer: Viewer,
93}
94
95/// `checkout`: starts a card payment for credit. Owners of the workspace
96/// only. Returns `Outcome<Checkout>`.
97#[derive(Debug, Serialize, Deserialize)]
98#[serde(rename_all = "camelCase")]
99pub struct CheckoutArgs {
100 pub actor: User,
101 pub workspace: String,
102 /// How much credit to buy, in cents.
103 pub amount_cents: u32,
104 /// Where the payment page sends the person afterwards. The payment's
105 /// id is appended as `session`.
106 pub return_url: String,
107}
108
109#[derive(Debug, Serialize, Deserialize)]
110pub struct Checkout {
111 /// The payment page to send the person to.
112 pub url: String,
113}
114
115/// `confirm`: credits a payment once the provider says it was made. Safe
116/// to call any number of times. Returns `Outcome<Account>`.
117#[derive(Debug, Serialize, Deserialize)]
118pub struct ConfirmArgs {
119 pub workspace: String,
120 pub viewer: Viewer,
121 /// The payment's id, as returned to `return_url`.
122 pub session: String,
123}
124
125/// `can_start`: whether a workspace may start an agent now, asked before
126/// anything is opened for it. Returns `Outcome<bool>`: a failure, with the
127/// reason to show, when it has no credit.
128#[derive(Debug, Serialize, Deserialize)]
129pub struct CanStartArgs {
130 pub workspace: String,
131}
132
133/// `start_run`: asks whether a workspace may start an agent, and opens the
134/// run it will be charged for. Called by the runner service. Returns
135/// `Outcome<Option<RunTicket>>`: no ticket when billing is off, a failure
136/// when the workspace has no credit.
137#[derive(Debug, Serialize, Deserialize)]
138pub struct StartRunArgs {
139 pub workspace: String,
140 pub repo: RepoPath,
141 pub number: u32,
142 /// `implement`, `review` or `update`.
143 pub task: String,
144 /// The model, by its public name.
145 pub model: String,
Integrations: your own model provider, alerts that open issues, tickets agents read146 /// `workspace` when the run uses the workspace's own model provider.
147 #[serde(default = "g1t")]
148 pub billed_to: String,
Agents as a team: lifecycle, merge queue, billing and a new shell149}
150
151#[derive(Clone, Debug, Serialize, Deserialize)]
152#[serde(rename_all = "camelCase")]
153pub struct RunTicket {
154 pub run_id: String,
155 /// Lets the sandbox, and nothing else, report what this run cost.
156 pub token: String,
157}
158
159/// `finish_run`: what a run cost, as its sandbox reports it. Charged once.
160/// Returns `Outcome<bool>`.
161#[derive(Debug, Serialize, Deserialize)]
162#[serde(rename_all = "camelCase")]
163pub struct FinishRunArgs {
164 pub run_id: String,
165 pub token: String,
166 /// What the model provider charged, in US dollars.
167 pub cost_usd: f64,
168 #[serde(default)]
169 pub turns: u32,
170}
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request171
172
173/// `usage`: what a workspace's agents cost over a period, broken down.
174/// Members only. Returns `Outcome<Usage>`.
175#[derive(Debug, Serialize, Deserialize)]
176pub struct UsageArgs {
177 pub workspace: String,
178 pub viewer: Viewer,
179 /// RFC 3339: the start of the period. The period runs to now.
180 pub since: String,
181}
182
183/// One slice of usage: what it was for, what it cost, how many runs.
184#[derive(Clone, Debug, Serialize, Deserialize)]
185#[serde(rename_all = "camelCase")]
186pub struct UsageSlice {
187 pub key: String,
188 pub micros: i64,
189 pub runs: u32,
190}
191
192/// What a workspace's agents cost over a period.
193#[derive(Clone, Debug, Serialize, Deserialize)]
194#[serde(rename_all = "camelCase")]
195pub struct Usage {
196 pub since: String,
197 /// Charged, including g1t's margin.
198 pub spent_micros: i64,
Integrations: your own model provider, alerts that open issues, tickets agents read199 /// What g1t's model provider charged, before the margin.
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request200 pub cost_micros: i64,
Integrations: your own model provider, alerts that open issues, tickets agents read201 /// What runs on the workspace's own provider cost there, as the harness
202 /// estimated it. Not charged by g1t.
203 pub provider_micros: i64,
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request204 pub runs: u32,
205 /// Spend per day (`YYYY-MM-DD`) and task, as `day/task` keys.
206 pub by_day: Vec<UsageSlice>,
207 /// Per task: implement, review, revise, update, plan.
208 pub by_task: Vec<UsageSlice>,
209 /// Per repository, `namespace/name`.
210 pub by_repo: Vec<UsageSlice>,
211 /// The pull requests that cost most, as `namespace/name#number`.
212 pub by_pull: Vec<UsageSlice>,
213 /// Per model, by its public name.
214 pub by_model: Vec<UsageSlice>,
215 /// Credit bought in the period.
216 pub added_micros: i64,
217}