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/crates/contracts/src/work.rs

1,637 lines53,741 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.

Issues and pull requests replace intents and attempts1//! The work service: issues, pull requests, comments and sessions.
Work service in Rust, with RFC 3339 timestamps2//!
3//! Each `*Args` struct is the argument of the method of the same name,
4//! served at `POST /rpc/<method>`.
Issues and pull requests replace intents and attempts5//!
6//! Issues and pull requests share one sequence of numbers per repository,
7//! so `#12` names exactly one of them.
Work service in Rust, with RFC 3339 timestamps8
9use serde::{Deserialize, Serialize};
10
Agents as a team: lifecycle, merge queue, billing and a new shell11use crate::repos::{CompareArgs, RepoPath};
Work service in Rust, with RFC 3339 timestamps12use crate::{User, Viewer};
13
Issues and pull requests replace intents and attempts14/// Labels every repository starts with. Any other label comes into being
15/// the first time it is put on an issue.
16pub const DEFAULT_LABELS: [&str; 5] = ["bug", "feature", "docs", "chore", "question"];
17
18/// `open` or `closed`: the filter on lists of issues and pull requests. An
19/// open pull request is a draft or one ready for review; a closed one was
20/// merged or closed without merging.
Work service in Rust, with RFC 3339 timestamps21#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
22#[serde(rename_all = "lowercase")]
Issues and pull requests replace intents and attempts23pub enum State {
Work service in Rust, with RFC 3339 timestamps24 Open,
Issues and pull requests replace intents and attempts25 Closed,
26}
27
28/// Why an issue was closed.
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
30#[serde(rename_all = "snake_case")]
31pub enum IssueReason {
32 /// The work was done. If a pull request did it, `resolved_by` names it.
33 Completed,
34 NotPlanned,
Work service in Rust, with RFC 3339 timestamps35}
36
Issues and pull requests replace intents and attempts37impl IssueReason {
38 pub fn as_str(self) -> &'static str {
39 match self {
40 IssueReason::Completed => "completed",
41 IssueReason::NotPlanned => "not_planned",
42 }
43 }
44}
45
46/// Something that should change in a repository: a bug, a feature, a
47/// question. Opened by a person, an agent or an integration. Pull requests
48/// are made against it; the one that is merged resolves it.
Work service in Rust, with RFC 3339 timestamps49#[derive(Clone, Debug, Serialize, Deserialize)]
50#[serde(rename_all = "camelCase")]
Issues and pull requests replace intents and attempts51pub struct Issue {
Work service in Rust, with RFC 3339 timestamps52 pub id: String,
53 pub repo_id: String,
Issues and pull requests replace intents and attempts54 /// Shown as `#12`.
Work service in Rust, with RFC 3339 timestamps55 pub number: u32,
56 pub title: String,
Issues and pull requests replace intents and attempts57 /// Markdown. Also what an agent is given to work from.
58 pub body: String,
59 pub labels: Vec<String>,
60 /// Commands that must pass for a pull request to be accepted.
Work service in Rust, with RFC 3339 timestamps61 pub checks: Vec<String>,
Issues and pull requests replace intents and attempts62 pub state: State,
63 /// Set when closed.
64 pub reason: Option<IssueReason>,
65 /// The number of the pull request whose merge closed this issue.
66 pub resolved_by: Option<u32>,
Work service in Rust, with RFC 3339 timestamps67 pub author: User,
68 /// RFC 3339.
69 pub created_at: String,
Issues and pull requests replace intents and attempts70 /// RFC 3339.
71 pub updated_at: String,
72 /// RFC 3339.
73 pub closed_at: Option<String>,
74 /// Pull requests made against this issue, in any state.
75 pub pull_count: u32,
76 pub comment_count: u32,
Agents as a team: lifecycle, merge queue, billing and a new shell77 /// Usernames of the people it is assigned to.
78 #[serde(default)]
79 pub assignees: Vec<String>,
80 /// The numbers of the issues that have to be merged before this one is
81 /// worked on.
82 #[serde(default)]
83 pub blocked_by: Vec<u32>,
84 /// Whether a g1t agent takes it as soon as it can: at once, or when
85 /// what it is blocked by has merged.
86 #[serde(default)]
87 pub queued: bool,
88 /// The agent working on it now: the one behind its newest pull request
89 /// that is still in progress in a fork, such as `g1t-agent`.
90 #[serde(default)]
91 pub agent: Option<String>,
Work service in Rust, with RFC 3339 timestamps92}
93
94#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
95#[serde(rename_all = "lowercase")]
Issues and pull requests replace intents and attempts96pub enum PullStatus {
97 /// Still being worked on.
98 Draft,
99 /// Ready for review.
100 Open,
101 Merged,
102 /// Closed without merging.
103 Closed,
Work service in Rust, with RFC 3339 timestamps104}
105
Issues and pull requests replace intents and attempts106impl PullStatus {
Work service in Rust, with RFC 3339 timestamps107 pub fn as_str(self) -> &'static str {
108 match self {
Issues and pull requests replace intents and attempts109 PullStatus::Draft => "draft",
110 PullStatus::Open => "open",
111 PullStatus::Merged => "merged",
112 PullStatus::Closed => "closed",
Work service in Rust, with RFC 3339 timestamps113 }
114 }
115
Issues and pull requests replace intents and attempts116 /// Whether the pull request can still be changed or merged.
Work service in Rust, with RFC 3339 timestamps117 pub fn is_active(self) -> bool {
Issues and pull requests replace intents and attempts118 matches!(self, PullStatus::Draft | PullStatus::Open)
Work service in Rust, with RFC 3339 timestamps119 }
120}
121
122/// Where the agent runs: on g1t's sandboxes, or in someone's own session.
123#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
124#[serde(rename_all = "lowercase")]
Issues and pull requests replace intents and attempts125pub enum Runtime {
Work service in Rust, with RFC 3339 timestamps126 Hosted,
127 External,
128}
129
Pull requests from branches130/// A proposed change. It is made either in a fork created for it, which is
131/// how agents work, or on a branch pushed to the repository itself.
Work service in Rust, with RFC 3339 timestamps132#[derive(Clone, Debug, Serialize, Deserialize)]
133#[serde(rename_all = "camelCase")]
Issues and pull requests replace intents and attempts134pub struct Pull {
Work service in Rust, with RFC 3339 timestamps135 pub id: String,
136 pub repo_id: String,
Issues and pull requests replace intents and attempts137 /// Shown as `#12`.
Work service in Rust, with RFC 3339 timestamps138 pub number: u32,
Issues and pull requests replace intents and attempts139 /// The number of the issue this is for, if any.
140 pub issue: Option<u32>,
141 pub title: String,
142 /// Markdown: what changed and why. Set when marked ready.
143 pub body: Option<String>,
Work service in Rust, with RFC 3339 timestamps144 /// A label for the agent doing the work, e.g. `claude-code`.
145 pub agent: String,
Issues and pull requests replace intents and attempts146 pub runtime: Runtime,
147 pub status: PullStatus,
Pull requests from branches148 /// The fork holding the change, unless it is on a branch.
149 pub fork: Option<RepoPath>,
Work service in Rust, with RFC 3339 timestamps150 /// The fork's repository id.
Pull requests from branches151 pub fork_repo_id: Option<String>,
152 /// The branch of the repository holding the change, unless it is in a
153 /// fork.
154 pub branch: Option<String>,
Work service in Rust, with RFC 3339 timestamps155 pub head_commit: Option<String>,
Issues and pull requests replace intents and attempts156 /// For a merged pull request, what the branch pointed to before the
157 /// merge. Comparing against it shows what the pull request changed.
158 pub merge_base: Option<String>,
159 /// Username of whoever merged it.
160 pub merged_by: Option<String>,
161 /// RFC 3339.
162 pub merged_at: Option<String>,
163 /// Set on a pull request closed because another one for the same issue
164 /// was merged: that one's number.
165 pub superseded_by: Option<u32>,
Acceptance checks in sandboxes, line comments and review verdicts166 /// Where the latest run of the issue's acceptance checks stands, if
167 /// there has been one against the current head.
168 pub check_status: Option<CheckStatus>,
Agents as a team: lifecycle, merge queue, billing and a new shell169 /// The files it changes, as of its latest push.
170 #[serde(default)]
171 pub files: Vec<ChangedFile>,
172 /// Usernames of the people it is assigned to.
173 #[serde(default)]
174 pub assignees: Vec<String>,
175 /// Those whose review was asked for: usernames, and `g1t-agent` when a
176 /// g1t agent was asked.
177 #[serde(default)]
178 pub reviewers: Vec<String>,
Issues and pull requests replace intents and attempts179 pub author: User,
Work service in Rust, with RFC 3339 timestamps180 /// RFC 3339.
181 pub created_at: String,
182 /// RFC 3339.
183 pub updated_at: String,
184}
185
Agents as a team: lifecycle, merge queue, billing and a new shell186/// One file a pull request changes, and by how much.
187#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
188pub struct ChangedFile {
189 pub path: String,
190 pub additions: u32,
191 pub deletions: u32,
192}
193
194/// Another pull request in progress that changes some of the same files.
195/// Two for the same issue are alternatives; two for different issues are
196/// heading for a conflict.
197#[derive(Clone, Debug, Serialize, Deserialize)]
198pub struct Overlap {
199 pub number: u32,
200 pub title: String,
201 /// The number of the issue the other pull request is for.
202 pub issue: Option<u32>,
203 /// The files both change.
204 pub paths: Vec<String>,
205}
206
207impl Pull {
208 /// What to ask the repos service to see what this pull request changes.
209 ///
210 /// A fork is compared as a whole. A branch is compared by name while
211 /// the pull request is open, and by the commit it was merged or closed
212 /// at afterwards, so later pushes to the branch do not change the record.
213 pub fn comparison(&self, viewer: &Viewer) -> CompareArgs {
214 let settled = matches!(self.status, PullStatus::Merged | PullStatus::Closed);
215 let (repo_id, head) = match &self.fork_repo_id {
216 Some(fork) => (fork.clone(), None),
217 None => (
218 self.repo_id.clone(),
219 self.head_commit
220 .clone()
221 .filter(|_| settled)
222 .or_else(|| self.branch.clone()),
223 ),
224 };
225 CompareArgs {
226 repo_id,
227 viewer: viewer.clone(),
228 base: self.merge_base.clone(),
229 head,
230 }
231 }
232}
233
Acceptance checks in sandboxes, line comments and review verdicts234#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
235#[serde(rename_all = "lowercase")]
236pub enum CheckStatus {
237 /// Waiting for a sandbox.
238 Queued,
239 Running,
240 Passed,
241 Failed,
242 /// The checks could not be run at all.
243 Errored,
244}
245
246impl CheckStatus {
247 pub fn as_str(self) -> &'static str {
248 match self {
249 CheckStatus::Queued => "queued",
250 CheckStatus::Running => "running",
251 CheckStatus::Passed => "passed",
252 CheckStatus::Failed => "failed",
253 CheckStatus::Errored => "errored",
254 }
255 }
256}
257
258/// How one acceptance check went.
259#[derive(Clone, Debug, Serialize, Deserialize)]
260#[serde(rename_all = "camelCase")]
261pub struct CheckResult {
262 pub command: String,
263 pub passed: bool,
264 /// Absent when the command was stopped for taking too long.
265 #[serde(default)]
266 pub exit_code: Option<i32>,
267 /// What the command printed, standard output and error together. The
268 /// end of it, when there was a lot.
269 #[serde(default)]
270 pub output: String,
271 #[serde(default)]
272 pub duration_ms: u64,
273}
274
275/// One run of an issue's acceptance checks against a pull request's head,
276/// in a sandbox that holds nothing but that commit.
277#[derive(Clone, Debug, Serialize, Deserialize)]
278#[serde(rename_all = "camelCase")]
279pub struct CheckRun {
280 pub id: String,
281 /// The commit that was checked.
282 pub head_commit: String,
283 pub status: CheckStatus,
284 pub results: Vec<CheckResult>,
285 /// Why the checks could not be run, when `status` is `errored`.
286 pub error: Option<String>,
287 /// RFC 3339.
288 pub created_at: String,
289 /// RFC 3339.
290 pub finished_at: Option<String>,
291}
292
293/// A reviewer's decision on a pull request.
294#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
295#[serde(rename_all = "snake_case")]
296pub enum Verdict {
297 Approve,
298 RequestChanges,
299}
300
301impl Verdict {
302 pub fn as_str(self) -> &'static str {
303 match self {
304 Verdict::Approve => "approve",
305 Verdict::RequestChanges => "request_changes",
306 }
307 }
308}
309
Agents as a team: lifecycle, merge queue, billing and a new shell310/// What an entry in a conversation is.
311#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
312#[serde(rename_all = "lowercase")]
313pub enum CommentKind {
314 /// Something a person or an agent wrote.
315 #[default]
316 Comment,
317 /// Something that happened: an assignment, a review asked for, a close.
318 Event,
319}
320
Acceptance checks in sandboxes, line comments and review verdicts321/// A comment on an issue or a pull request. On a pull request it can sit
322/// on one line of the change, and it can carry a reviewer's verdict.
Issues and pull requests replace intents and attempts323#[derive(Clone, Debug, Serialize, Deserialize)]
324#[serde(rename_all = "camelCase")]
325pub struct Comment {
326 pub id: String,
Agents as a team: lifecycle, merge queue, billing and a new shell327 /// Something a person wrote, or something that happened.
328 #[serde(default)]
329 pub kind: CommentKind,
Issues and pull requests replace intents and attempts330 pub author: User,
Agents as a team: lifecycle, merge queue, billing and a new shell331 /// Markdown. For an event, what its author did, as the rest of a
332 /// sentence that starts with their name: "assigned ana".
Issues and pull requests replace intents and attempts333 pub body: String,
Acceptance checks in sandboxes, line comments and review verdicts334 /// The file commented on, for a comment on a line.
335 pub path: Option<String>,
336 /// The line of that file, as numbered after the change.
337 pub line: Option<u32>,
338 pub verdict: Option<Verdict>,
Issues and pull requests replace intents and attempts339 /// RFC 3339.
340 pub created_at: String,
341}
342
Work service in Rust, with RFC 3339 timestamps343#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
344#[serde(rename_all = "snake_case")]
345pub enum SessionEntryKind {
346 Prompt,
347 Message,
348 ToolCall,
349 ToolResult,
350 Note,
351}
352
Issues and pull requests replace intents and attempts353/// One step of an agent's session: the "why" behind a pull request's commits.
Work service in Rust, with RFC 3339 timestamps354#[derive(Clone, Debug, Serialize, Deserialize)]
355pub struct SessionEntry {
356 pub seq: u32,
357 pub kind: SessionEntryKind,
358 pub text: String,
359 /// For tool calls and results.
360 pub tool: Option<String>,
361 /// The fork's head commit when this entry was recorded, if known.
362 pub commit: Option<String>,
363 /// RFC 3339.
364 pub at: String,
365}
366
367#[derive(Clone, Debug, Serialize, Deserialize)]
368pub struct NewSessionEntry {
369 pub kind: SessionEntryKind,
370 pub text: String,
371 #[serde(default)]
372 pub tool: Option<String>,
373 #[serde(default)]
374 pub commit: Option<String>,
375}
376
377#[derive(Clone, Debug, Serialize, Deserialize)]
Issues and pull requests replace intents and attempts378pub struct IssueDetail {
379 pub issue: Issue,
380 /// Every pull request made against it, oldest first.
381 pub pulls: Vec<Pull>,
382 pub comments: Vec<Comment>,
Work service in Rust, with RFC 3339 timestamps383}
384
385#[derive(Clone, Debug, Serialize, Deserialize)]
Issues and pull requests replace intents and attempts386pub struct PullDetail {
387 pub pull: Pull,
388 /// The issue it is for, if any.
389 pub issue: Option<Issue>,
390 pub comments: Vec<Comment>,
Acceptance checks in sandboxes, line comments and review verdicts391 /// The latest run of the issue's acceptance checks.
392 pub checks: Option<CheckRun>,
Agents as a team: lifecycle, merge queue, billing and a new shell393 /// Other pull requests in progress that change the same files.
394 #[serde(default)]
395 pub overlaps: Vec<Overlap>,
396 /// Whether the branch it would merge into has moved on without it, so
397 /// that it has to catch up before it can merge.
398 #[serde(default)]
399 pub behind: bool,
400 /// Whether a g1t agent is reviewing it right now.
401 #[serde(default)]
402 pub review_pending: bool,
403 /// Where it stands on its way to being merged, for a pull request g1t
404 /// is seeing through. Absent on anyone else's.
405 #[serde(default)]
406 pub lifecycle: Option<Lifecycle>,
407 /// A merge was asked for while it was behind: g1t is bringing it up to
408 /// date and will then land it.
409 #[serde(default)]
410 pub landing: bool,
411 /// Why g1t stopped working on it, if it did: a catch-up that could not
412 /// be completed, for example.
413 #[serde(default)]
414 pub stalled: Option<String>,
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request415 /// Messages people sent the agent while it worked, oldest first.
416 #[serde(default)]
417 pub messages: Vec<AgentMessage>,
GitHub Actions on g1t, part two: running workflows418 /// What workflow runs said about its head commit, one per workflow.
419 #[serde(default)]
420 pub statuses: Vec<CommitStatus>,
Agents and memory, checks and conflicts, profiles, slug renames, custom domains421 /// Whether it merges cleanly into the branch it targets, worked out
422 /// ahead of time whenever either side moves.
423 #[serde(default)]
424 pub mergeable: Mergeable,
425 /// When `mergeable` is `conflicting`: the files that conflict.
426 #[serde(default)]
427 pub conflicts: Vec<String>,
428 /// Earlier runs of its acceptance checks, newest first, without their
429 /// output.
430 #[serde(default)]
431 pub earlier_checks: Vec<CheckRun>,
432}
433
434/// Whether a pull request's change merges cleanly into the branch it
435/// targets.
436#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
437#[serde(rename_all = "lowercase")]
438pub enum Mergeable {
439 /// It merges without conflicts.
440 Clean,
441 /// Some files conflict: see `PullDetail::conflicts`.
442 Conflicting,
443 /// Not known: never worked out, or it could not be.
444 #[default]
445 Unknown,
446 /// Being worked out now.
447 Checking,
GitHub Actions on g1t, part two: running workflows448}
449
Agents and memory, checks and conflicts, profiles, slug renames, custom domains450impl Mergeable {
451 pub fn as_str(self) -> &'static str {
452 match self {
453 Mergeable::Clean => "clean",
454 Mergeable::Conflicting => "conflicting",
455 Mergeable::Unknown => "unknown",
456 Mergeable::Checking => "checking",
457 }
458 }
459
460 pub fn parse(value: Option<&str>) -> Mergeable {
461 match value {
462 Some("clean") => Mergeable::Clean,
463 Some("conflicting") => Mergeable::Conflicting,
464 Some("checking") => Mergeable::Checking,
465 _ => Mergeable::Unknown,
466 }
467 }
468}
469
470/// `start_mergecheck`: claims the probe of whether a pull request merges
471/// cleanly, which the work service asked for with a `pull.mergecheck`
472/// event. Called by the runner service, which starts the sandbox. Refused
473/// when it is no longer wanted, or when the repository already has as many
474/// probes running as it may. Returns `Outcome<MergecheckJob>`.
475#[derive(Debug, Serialize, Deserialize)]
476#[serde(rename_all = "camelCase")]
477pub struct StartMergecheckArgs {
478 pub pull_id: String,
479}
480
481/// What a sandbox needs to find out whether a pull request merges cleanly.
482#[derive(Debug, Serialize, Deserialize)]
483#[serde(rename_all = "camelCase")]
484pub struct MergecheckJob {
485 pub pull_id: String,
486 /// Lets the sandbox, and nothing else, report this probe.
487 pub token: String,
488 pub repo: RepoPath,
489 pub number: u32,
490 pub default_branch: String,
491 /// The default branch's commit to merge into.
492 pub base: String,
493 /// The repository holding the change: its fork, or the repository.
494 pub source: RepoPath,
495 /// The branch of `source` holding it.
496 pub branch: String,
497 /// The change's commit.
498 pub head: String,
499 /// Who opened the pull request, and so can read its source.
500 pub author: User,
501}
502
503/// `report_mergecheck`: what a sandbox found. Returns `Outcome<Mergeable>`.
504#[derive(Debug, Serialize, Deserialize)]
505#[serde(rename_all = "camelCase")]
506pub struct ReportMergecheckArgs {
507 pub pull_id: String,
508 pub token: String,
509 /// The files that conflict; empty when it merges cleanly.
510 #[serde(default)]
511 pub conflicts: Vec<String>,
512 /// Why it could not be found out.
513 #[serde(default)]
514 pub error: Option<String>,
515}
516
GitHub Actions on g1t, part two: running workflows517/// What a workflow run (or another tool) says about a commit.
518#[derive(Clone, Debug, Serialize, Deserialize)]
519#[serde(rename_all = "camelCase")]
520pub struct CommitStatus {
521 /// What reported it, such as `CI / push`.
522 pub context: String,
523 /// `pending`, `success`, `failure` or `error`.
524 pub state: String,
525 pub description: Option<String>,
526 /// Where to see more, such as the run's page.
527 pub target_url: Option<String>,
528 pub updated_at: String,
529}
530
531/// `set_commit_status`: for services only. Returns `Outcome<bool>`.
532#[derive(Debug, Serialize, Deserialize)]
533#[serde(rename_all = "camelCase")]
534pub struct SetCommitStatusArgs {
535 pub repo_id: String,
536 pub sha: String,
537 pub context: String,
538 pub state: String,
539 #[serde(default)]
540 pub description: Option<String>,
541 #[serde(default)]
542 pub target_url: Option<String>,
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request543}
544
545/// A message a person sent an agent at work on a pull request. The agent
546/// receives it at its next step.
547#[derive(Clone, Debug, Serialize, Deserialize)]
548#[serde(rename_all = "camelCase")]
549pub struct AgentMessage {
550 pub id: String,
551 pub author: String,
552 pub body: String,
553 /// RFC 3339.
554 pub created_at: String,
555 /// RFC 3339. When the agent received it; null until then.
556 pub delivered_at: Option<String>,
Agents ask each other, hand each other work, and answer557 /// `message` from a person, or from another pull request's agent a
558 /// `question`, a `handoff` of work, or the `answer` to one.
559 #[serde(default = "message_kind")]
560 pub kind: String,
561 /// The pull request whose agent sent it, when an agent did.
562 #[serde(default)]
563 pub from_number: Option<u32>,
564 /// The pull request it was sent to.
565 #[serde(default)]
566 pub to_number: u32,
567 /// For a question or handoff: the reply, once there is one.
568 #[serde(default)]
569 pub answer: Option<String>,
570 /// For a handoff: whether it was declined.
571 #[serde(default)]
572 pub declined: bool,
573 /// For the agent that sent it: what to expect, when the agent it asked
574 /// is not at work and will not answer soon.
575 #[serde(default, skip_serializing_if = "Option::is_none")]
576 pub hint: Option<String>,
577}
578
579fn message_kind() -> String {
580 "message".to_owned()
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request581}
582
583/// `message_agent`: sends the agent working on a pull request a message.
584/// The pull request's author and members of the workspace may. Returns
585/// `Outcome<AgentMessage>`.
586#[derive(Debug, Serialize, Deserialize)]
587pub struct MessageAgentArgs {
588 pub actor: User,
589 pub repo: RepoPath,
590 pub number: u32,
591 pub body: String,
Agents ask each other, hand each other work, and answer592 /// For an agent: `question` or `handoff`; a person's is a `message`.
593 #[serde(default)]
594 pub kind: Option<String>,
595 /// For an agent: the pull request it is working on, which the reply
596 /// goes back to.
597 #[serde(default)]
598 pub from_number: Option<u32>,
599}
600
601/// `answer_message`: replies to a question or a handoff an agent received,
602/// accepting or declining a handoff. The reply reaches the asking agent at
603/// its next step. Returns `Outcome<AgentMessage>`, the message answered.
604#[derive(Debug, Serialize, Deserialize)]
605pub struct AnswerMessageArgs {
606 pub actor: User,
607 pub repo: RepoPath,
608 pub id: String,
609 pub body: String,
610 #[serde(default)]
611 pub decline: bool,
Usage, like a hosting provider's: what agents cost, per day, task, repository and pull request612}
613
614/// `take_messages`: the messages not yet delivered to the agent working on
615/// a pull request, marked delivered. Only g1t's agents may. Returns
616/// `Outcome<Vec<AgentMessage>>`.
617#[derive(Debug, Serialize, Deserialize)]
618pub struct TakeMessagesArgs {
619 pub actor: User,
620 pub repo: RepoPath,
621 pub number: u32,
Agents as a team: lifecycle, merge queue, billing and a new shell622}
623
624/// A step on the way from an assigned issue to a pull request that is ready
625/// to merge. g1t takes each one without being asked.
626#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
627#[serde(rename_all = "snake_case")]
628pub enum Stage {
629 /// The agent is making the change.
630 Working,
631 /// The issue's acceptance checks are running against it.
632 Checking,
633 /// A g1t agent is reviewing it.
634 Reviewing,
635 /// The agent is addressing failed checks or a review.
636 Revising,
637 /// The agent is merging in the branch it would land on, which moved.
638 CatchingUp,
Agents asked while not at work are woken to answer639 /// Woken to answer a question another agent asked it, or a handoff.
640 Answering,
Agents as a team: lifecycle, merge queue, billing and a new shell641 /// In the repository's merge queue, being tested with what is ahead of
642 /// it before it lands.
643 Queued,
644 /// Checks passed, reviewed and approved, up to date. A person merges.
645 Ready,
646 /// g1t has stopped and a person has to decide what happens next.
647 NeedsYou,
648}
649
650/// Where a pull request made by a g1t agent stands. See [`Stage`].
651#[derive(Clone, Debug, Serialize, Deserialize)]
652pub struct Lifecycle {
653 pub stage: Stage,
654 /// One sentence saying what is happening, or why it stopped.
655 pub detail: String,
656 /// How many times the agent has been sent back to revise it.
657 pub revisions: u32,
658}
659
660/// `advance`: works out the next step for a pull request g1t is seeing
661/// through and, if there is one to take now, claims it, so that it is
662/// taken once however many times this is called. Called by the runner
663/// service, which carries the step out. Returns `Advance`.
664#[derive(Debug, Serialize, Deserialize)]
665#[serde(rename_all = "camelCase")]
666pub struct AdvanceArgs {
667 pub pull_id: String,
668}
669
670#[derive(Debug, Serialize, Deserialize)]
671#[serde(tag = "action", rename_all = "snake_case")]
672pub enum Advance {
673 /// Nothing to do now: a step is under way, or it is a person's turn.
674 None,
675 /// Have a g1t agent review it.
676 Review { job: LifecycleJob },
677 /// Send the agent back to address `job.feedback`.
678 Revise { job: LifecycleJob },
679 /// Merge in the branch it would land on.
680 CatchUp { job: LifecycleJob },
Work service in Rust, with RFC 3339 timestamps681}
682
Agents as a team: lifecycle, merge queue, billing and a new shell683/// What the runner needs to carry out a step of a pull request's lifecycle.
684#[derive(Debug, Serialize, Deserialize)]
685#[serde(rename_all = "camelCase")]
686pub struct LifecycleJob {
687 pub pull_id: String,
688 pub repo: RepoPath,
689 pub number: u32,
690 /// Who the pull request belongs to. Sandboxes act as them.
691 pub author: User,
692 /// The repository holding the change: its fork, or the repository
693 /// itself for one made on a branch.
694 pub source: RepoPath,
695 /// The branch of the source holding the change; its default branch
696 /// when absent.
697 #[serde(default)]
698 pub branch: Option<String>,
699 pub default_branch: String,
700 pub title: String,
701 pub description: String,
702 pub issue: Option<Issue>,
703 /// For a revision: the failed checks or the review to address.
704 pub feedback: String,
705 /// For a revision: which one this is, from 1.
706 pub round: u32,
707}
708
709/// How a repository wants its pull requests handled. A repository that has
710/// changed nothing has the defaults.
711#[derive(Clone, Debug, Serialize, Deserialize)]
712#[serde(rename_all = "camelCase", default)]
713pub struct RepoSettings {
714 /// Land a g1t agent's pull request without a person once it is ready:
715 /// checks passed and approved as the settings below require.
716 pub auto_merge: bool,
717 /// Refuse to merge a pull request that does not contain the default
718 /// branch's latest commits, so that what merges is what was checked.
719 /// When off, merging one that is behind brings it up to date first.
720 pub require_up_to_date: bool,
721 /// How many approving reviews a pull request needs before it may
722 /// merge. A reviewer who has since asked for changes blocks it.
723 pub required_approvals: u32,
724 /// Whether a g1t agent's approval counts towards `required_approvals`.
725 pub count_agent_approvals: bool,
726 /// Whether a member may merge although the acceptance checks did not
727 /// pass.
728 pub allow_ignoring_checks: bool,
729 /// Whether a g1t agent's pull request is reviewed by a second agent
730 /// without being asked.
731 pub agent_review: bool,
732 /// How many times a g1t agent is sent back to its pull request before
733 /// a person is asked instead.
734 pub max_revisions: u32,
735 /// Merge through a queue: pull requests are tested together with those
736 /// ahead of them, and only a combination that passed reaches the default
737 /// branch.
738 pub merge_queue: bool,
739 /// Username of the member who last changed the settings, if anyone has.
740 pub updated_by: Option<String>,
741 /// RFC 3339.
742 pub updated_at: Option<String>,
743}
744
745impl Default for RepoSettings {
746 fn default() -> Self {
747 RepoSettings {
748 auto_merge: false,
749 require_up_to_date: false,
750 required_approvals: 0,
751 count_agent_approvals: true,
752 allow_ignoring_checks: true,
753 agent_review: true,
754 max_revisions: 2,
755 merge_queue: false,
756 updated_by: None,
757 updated_at: None,
758 }
759 }
760}
761
762/// `update_settings`: replaces a repository's settings. Members of its
763/// workspace only. Returns `Outcome<RepoSettings>`. `get_settings` takes
764/// `ViewArgs` and returns the same.
765#[derive(Debug, Serialize, Deserialize)]
766pub struct UpdateSettingsArgs {
767 pub actor: User,
768 pub repo: RepoPath,
769 /// Who changed them and when are filled in by the service.
770 pub settings: RepoSettings,
771}
772
773/// `catch_up_job`: what the runner needs to bring a pull request up to date
774/// because a merge of it was asked for. Null if none was. Returns
775/// `Option<LifecycleJob>`.
776#[derive(Debug, Serialize, Deserialize)]
777#[serde(rename_all = "camelCase")]
778pub struct CatchUpJobArgs {
779 pub pull_id: String,
780}
781
Agents asked while not at work are woken to answer782/// `wake_for_messages`: the agent on a pull request was asked a question
783/// or handed work while it was not at work. Claims a short step for it to
784/// answer, and hands over what it was sent, marked read. Null when there
785/// is nothing waiting, or the pull request cannot take a step now.
786/// Returns `Option<Wake>`.
787#[derive(Debug, Serialize, Deserialize)]
788#[serde(rename_all = "camelCase")]
789pub struct WakeForMessagesArgs {
790 pub pull_id: String,
791}
792
793/// What an agent woken to answer needs: its pull request, and what it was
794/// sent, oldest first.
795#[derive(Debug, Serialize, Deserialize)]
796#[serde(rename_all = "camelCase")]
797pub struct Wake {
798 pub job: LifecycleJob,
799 pub messages: Vec<AgentMessage>,
800}
801
Agents as a team: lifecycle, merge queue, billing and a new shell802/// `stall`: records that a step could not be carried out, so that g1t
803/// stops and a person is asked. Returns `bool`.
804#[derive(Debug, Serialize, Deserialize)]
805#[serde(rename_all = "camelCase")]
806pub struct StallArgs {
807 pub pull_id: String,
808 pub reason: String,
809}
810
811/// `managed_pulls`: ids of the open pull requests g1t is seeing through,
812/// in one repository or in all of them. Returns `Vec<String>`.
813#[derive(Debug, Default, Serialize, Deserialize)]
814#[serde(rename_all = "camelCase")]
815pub struct ManagedPullsArgs {
816 #[serde(default)]
817 pub repo_id: Option<String>,
818}
819
Issues and pull requests replace intents and attempts820/// `open_issue`. Returns `Outcome<Issue>`.
Work service in Rust, with RFC 3339 timestamps821#[derive(Debug, Serialize, Deserialize)]
Issues and pull requests replace intents and attempts822pub struct OpenIssueArgs {
Work service in Rust, with RFC 3339 timestamps823 pub actor: User,
824 pub repo: RepoPath,
825 pub title: String,
826 #[serde(default)]
Issues and pull requests replace intents and attempts827 pub body: String,
828 #[serde(default)]
829 pub labels: Vec<String>,
Work service in Rust, with RFC 3339 timestamps830 #[serde(default)]
831 pub checks: Vec<String>,
832}
833
Issues and pull requests replace intents and attempts834/// `list_issues`, newest first. Returns `Outcome<Vec<Issue>>`.
Work service in Rust, with RFC 3339 timestamps835#[derive(Debug, Serialize, Deserialize)]
Issues and pull requests replace intents and attempts836pub struct ListIssuesArgs {
Work service in Rust, with RFC 3339 timestamps837 pub repo: RepoPath,
838 pub viewer: Viewer,
839 #[serde(default)]
Issues and pull requests replace intents and attempts840 pub state: Option<State>,
841 /// Only issues carrying this label.
842 #[serde(default)]
843 pub label: Option<String>,
Work service in Rust, with RFC 3339 timestamps844}
845
Issues and pull requests replace intents and attempts846/// `list_pulls`, newest first. Returns `Outcome<Vec<Pull>>`.
Work service in Rust, with RFC 3339 timestamps847#[derive(Debug, Serialize, Deserialize)]
Issues and pull requests replace intents and attempts848pub struct ListPullsArgs {
849 pub repo: RepoPath,
850 pub viewer: Viewer,
851 #[serde(default)]
852 pub state: Option<State>,
853}
854
855/// `get_issue` (`Outcome<IssueDetail>`), `get_pull` (`Outcome<PullDetail>`),
856/// `read_session` (`Outcome<Vec<SessionEntry>>`), `list_labels`
857/// (`Outcome<Vec<String>>`) and `counts` (`Outcome<Counts>`). The last two
858/// ignore `number`.
859#[derive(Debug, Serialize, Deserialize)]
860#[serde(rename_all = "camelCase")]
861pub struct ViewArgs {
Work service in Rust, with RFC 3339 timestamps862 pub repo: RepoPath,
Issues and pull requests replace intents and attempts863 #[serde(default)]
Work service in Rust, with RFC 3339 timestamps864 pub number: u32,
865 pub viewer: Viewer,
Issues and pull requests replace intents and attempts866 /// For `read_session`: only entries after this sequence number.
867 #[serde(default)]
868 pub after_seq: u32,
869}
870
871/// How many issues and pull requests are open on a repository.
872#[derive(Debug, Serialize, Deserialize)]
873pub struct Counts {
874 pub issues: u32,
875 pub pulls: u32,
876}
877
878/// `update_issue`: changes whichever fields are given. The author or a
879/// member of the workspace may. Returns `Outcome<Issue>`.
880#[derive(Debug, Serialize, Deserialize)]
881pub struct UpdateIssueArgs {
882 pub actor: User,
883 pub repo: RepoPath,
884 pub number: u32,
885 #[serde(default)]
886 pub title: Option<String>,
887 #[serde(default)]
888 pub body: Option<String>,
889 #[serde(default)]
890 pub labels: Option<Vec<String>>,
Agents as a team: lifecycle, merge queue, billing and a new shell891 /// Usernames of the people it is assigned to; replaces the whole set.
892 /// Assigning it to the g1t agent is the runner's `run`, not this.
893 #[serde(default)]
894 pub assignees: Option<Vec<String>>,
Work service in Rust, with RFC 3339 timestamps895}
896
Issues and pull requests replace intents and attempts897/// `close_issue` and `reopen_issue`. Each returns `Outcome<Issue>`.
Work service in Rust, with RFC 3339 timestamps898#[derive(Debug, Serialize, Deserialize)]
Issues and pull requests replace intents and attempts899pub struct IssueActionArgs {
Work service in Rust, with RFC 3339 timestamps900 pub actor: User,
Issues and pull requests replace intents and attempts901 pub repo: RepoPath,
902 pub number: u32,
903 /// For `close_issue`; `completed` if left out.
904 #[serde(default)]
905 pub reason: Option<IssueReason>,
Work service in Rust, with RFC 3339 timestamps906}
907
Acceptance checks in sandboxes, line comments and review verdicts908/// `add_comment`, on an issue or a pull request. On a pull request it may
909/// name a line of the change, and may carry a verdict; nobody can give a
910/// verdict on their own pull request. Returns `Outcome<Comment>`.
Work service in Rust, with RFC 3339 timestamps911#[derive(Debug, Serialize, Deserialize)]
Issues and pull requests replace intents and attempts912pub struct AddCommentArgs {
Work service in Rust, with RFC 3339 timestamps913 pub actor: User,
Issues and pull requests replace intents and attempts914 pub repo: RepoPath,
915 pub number: u32,
Acceptance checks in sandboxes, line comments and review verdicts916 /// May be empty when approving.
917 #[serde(default)]
Issues and pull requests replace intents and attempts918 pub body: String,
Acceptance checks in sandboxes, line comments and review verdicts919 #[serde(default)]
920 pub path: Option<String>,
921 #[serde(default)]
922 pub line: Option<u32>,
923 #[serde(default)]
924 pub verdict: Option<Verdict>,
Work service in Rust, with RFC 3339 timestamps925}
926
Pull requests from branches927/// `open_pull`. Without `branch`, forks the repo and returns a draft pull
928/// request to push to. With it, opens a pull request, ready for review,
929/// for a branch already pushed to the repo. Returns `Outcome<Pull>`.
Work service in Rust, with RFC 3339 timestamps930#[derive(Debug, Serialize, Deserialize)]
Issues and pull requests replace intents and attempts931pub struct OpenPullArgs {
932 pub actor: User,
933 pub repo: RepoPath,
934 /// The issue this is for.
Work service in Rust, with RFC 3339 timestamps935 #[serde(default)]
Issues and pull requests replace intents and attempts936 pub issue: Option<u32>,
937 /// Defaults to the issue's title; required without an issue.
938 #[serde(default)]
939 pub title: String,
Pull requests from branches940 /// What changed and why. Usually set later, when a draft is marked ready.
941 #[serde(default)]
942 pub body: String,
943 /// A branch of the repository that already holds the change.
944 #[serde(default)]
945 pub branch: Option<String>,
Issues and pull requests replace intents and attempts946 #[serde(default)]
947 pub agent: String,
948 pub runtime: Runtime,
Work service in Rust, with RFC 3339 timestamps949}
950
Issues and pull requests replace intents and attempts951/// `ready_pull`, `close_pull` and `merge_pull`. Each returns `Outcome<Pull>`.
Work service in Rust, with RFC 3339 timestamps952#[derive(Debug, Serialize, Deserialize)]
953#[serde(rename_all = "camelCase")]
Issues and pull requests replace intents and attempts954pub struct PullActionArgs {
Work service in Rust, with RFC 3339 timestamps955 pub actor: User,
Issues and pull requests replace intents and attempts956 pub repo: RepoPath,
957 pub number: u32,
958 /// For `ready_pull`: what changed and why.
Work service in Rust, with RFC 3339 timestamps959 #[serde(default)]
960 pub summary: String,
Issues and pull requests replace intents and attempts961 /// For `merge_pull`: leave the issue open and the other pull requests
962 /// for it untouched, because this one is only part of the work.
963 #[serde(default)]
964 pub keep_issue_open: bool,
Acceptance checks in sandboxes, line comments and review verdicts965 /// For `merge_pull`: merge although the acceptance checks have not
966 /// passed.
967 #[serde(default)]
968 pub ignore_checks: bool,
969}
970
Agents as a team: lifecycle, merge queue, billing and a new shell971/// Where a plan stands.
972#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
973#[serde(rename_all = "lowercase")]
974pub enum PlanStatus {
975 /// An agent is reading the repository and writing it.
976 Planning,
977 /// Written, and waiting for a person to read and apply it.
978 Ready,
979 /// It could not be written.
980 Failed,
981 /// Its issues have been opened.
982 Applied,
983}
984
985/// One issue a plan proposes.
986#[derive(Clone, Debug, Default, Serialize, Deserialize)]
987#[serde(rename_all = "camelCase", default)]
988pub struct PlannedIssue {
989 pub title: String,
990 /// Markdown: what to change, where, and why.
991 pub body: String,
992 pub labels: Vec<String>,
993 /// Commands that must pass once the change is made.
994 pub checks: Vec<String>,
995 /// The files it will most likely change.
996 pub files: Vec<String>,
997 /// The positions, counting from 1, of earlier issues in the plan that
998 /// have to be merged first. An agent writes this as `depends_on`.
999 #[serde(alias = "depends_on")]
1000 pub depends_on: Vec<u32>,
1001 /// Its number, once the plan has been applied and it was kept.
1002 pub number: Option<u32>,
1003}
1004
1005/// An outcome someone wrote, and the issues an agent proposes to get there.
1006#[derive(Clone, Debug, Serialize, Deserialize)]
1007#[serde(rename_all = "camelCase")]
1008pub struct Plan {
1009 pub id: String,
1010 pub repo_id: String,
1011 /// The outcome wanted, as written.
1012 pub brief: String,
1013 pub status: PlanStatus,
1014 /// The agent's account of how it split the work.
1015 pub summary: String,
1016 pub issues: Vec<PlannedIssue>,
1017 /// Why it could not be written, when `status` is `failed`.
1018 pub error: Option<String>,
1019 pub author: User,
1020 /// RFC 3339.
1021 pub created_at: String,
1022 /// RFC 3339.
1023 pub finished_at: Option<String>,
Dark gray base with lavender as an accent, and a live outcome view for plans1024 /// Once applied: where each issue it opened stands now, in plan order.
1025 /// Filled in by `get_plan` only.
1026 #[serde(default)]
1027 pub progress: Vec<IssueProgress>,
Agents ask each other, hand each other work, and answer1028 /// Questions and handoffs between the agents on its pull requests,
1029 /// newest first. Filled in by `get_plan` only.
1030 #[serde(default)]
1031 pub exchanges: Vec<AgentMessage>,
Dark gray base with lavender as an accent, and a live outcome view for plans1032}
1033
1034/// Where one issue of an applied plan stands.
1035#[derive(Clone, Debug, Serialize, Deserialize)]
1036#[serde(rename_all = "camelCase")]
1037pub struct IssueProgress {
1038 pub number: u32,
1039 pub title: String,
1040 /// `blocked` (waiting on issues it depends on), `waiting` (for an
1041 /// agent), `open` (nobody on it), one of the lifecycle stages
1042 /// (`working`, `checking`, `reviewing`, `revising`, `catching_up`,
Agents asked while not at work are woken to answer1043 /// `answering`, `queued`, `ready`, `needs_you`), `landed` or `closed`.
Dark gray base with lavender as an accent, and a live outcome view for plans1044 pub state: String,
1045 /// One sentence about where it stands.
1046 pub detail: String,
1047 /// The issues it is waiting on that are still open.
1048 pub blocked_by: Vec<u32>,
1049 /// The pull request carrying it, the newest if several.
1050 pub pull: Option<u32>,
1051 /// Who or what is working on it, e.g. `g1t-agent`.
1052 pub agent: Option<String>,
Agents as a team: lifecycle, merge queue, billing and a new shell1053}
1054
1055/// `start_plan`: records an outcome to plan for. Members of the
1056/// repository's workspace only. Called by the runner service, which starts
1057/// the sandbox. Returns `Outcome<PlanJob>`.
1058#[derive(Debug, Serialize, Deserialize)]
1059pub struct StartPlanArgs {
1060 pub actor: User,
1061 pub repo: RepoPath,
1062 pub brief: String,
1063}
1064
1065/// What a sandbox needs to write a plan.
1066#[derive(Debug, Serialize, Deserialize)]
1067#[serde(rename_all = "camelCase")]
1068pub struct PlanJob {
1069 pub plan_id: String,
1070 /// Lets the sandbox, and nothing else, report this plan.
1071 pub token: String,
1072 pub brief: String,
1073 pub repo: RepoPath,
1074}
1075
1076/// `report_plan`: the plan a sandbox's agent wrote, or why it could not
1077/// write one. Returns `Outcome<bool>`.
1078#[derive(Debug, Serialize, Deserialize)]
1079#[serde(rename_all = "camelCase")]
1080pub struct ReportPlanArgs {
1081 pub plan_id: String,
1082 pub token: String,
1083 #[serde(default)]
1084 pub summary: String,
1085 #[serde(default)]
1086 pub issues: Vec<PlannedIssue>,
1087 #[serde(default)]
1088 pub error: Option<String>,
1089}
1090
1091/// `get_plan`. Members only. Returns `Outcome<Plan>`. `list_plans` takes
1092/// `ViewArgs` and returns `Outcome<Vec<Plan>>`, newest first.
1093#[derive(Debug, Serialize, Deserialize)]
1094pub struct PlanArgs {
1095 pub repo: RepoPath,
1096 pub viewer: Viewer,
1097 pub id: String,
1098}
1099
1100/// `apply_plan`: opens a plan's issues, each blocked by the ones it depends
1101/// on. Members only, and once. Returns `Outcome<Plan>`, its issues now
1102/// carrying their numbers.
1103#[derive(Debug, Serialize, Deserialize)]
1104pub struct ApplyPlanArgs {
1105 pub actor: User,
1106 pub repo: RepoPath,
1107 pub id: String,
1108 /// Queue every issue for a g1t agent.
1109 #[serde(default)]
1110 pub assign: bool,
1111 /// The positions, counting from 1, of the issues to open. All of them
1112 /// when absent.
1113 #[serde(default)]
1114 pub keep: Option<Vec<u32>>,
1115}
1116
1117/// `queue_issue`: asks for a g1t agent to take an issue as soon as it can,
1118/// or withdraws that. The author or a member may. Returns `Outcome<bool>`.
1119#[derive(Debug, Serialize, Deserialize)]
1120pub struct QueueIssueArgs {
1121 pub actor: User,
1122 pub repo: RepoPath,
1123 pub number: u32,
1124 pub queued: bool,
1125}
1126
1127/// `ready_issues`: issues waiting for a g1t agent that can be given one
1128/// now, in one repository or in all. Called by the runner service. Returns
1129/// `Vec<ReadyIssue>`.
1130#[derive(Debug, Default, Serialize, Deserialize)]
1131#[serde(rename_all = "camelCase")]
1132pub struct ReadyIssuesArgs {
1133 #[serde(default)]
1134 pub repo_id: Option<String>,
1135}
1136
1137#[derive(Debug, Serialize, Deserialize)]
1138pub struct ReadyIssue {
1139 pub repo: RepoPath,
1140 pub number: u32,
1141 /// Who queued it, on whose say-so the agent works.
1142 pub actor: User,
1143}
1144
1145/// `update_pull`: changes who a pull request is assigned to and whose
1146/// review is asked for. Each list given replaces the whole set. Whoever
1147/// opened it, or a member of the workspace, may. Returns `Outcome<Pull>`.
1148#[derive(Debug, Serialize, Deserialize)]
1149pub struct UpdatePullArgs {
1150 pub actor: User,
1151 pub repo: RepoPath,
1152 pub number: u32,
1153 #[serde(default)]
1154 pub assignees: Option<Vec<String>>,
1155 /// May include `g1t-agent`. Asking for its review does not by itself
1156 /// start one; the runner's `review` does.
1157 #[serde(default)]
1158 pub reviewers: Option<Vec<String>>,
1159}
1160
Acceptance checks in sandboxes, line comments and review verdicts1161/// `start_checks`: begins a run of the acceptance checks for a pull request
1162/// that is ready for review. Called by the runner service, which starts the
1163/// sandbox. Returns `Outcome<CheckJob>`.
1164#[derive(Debug, Serialize, Deserialize)]
1165#[serde(rename_all = "camelCase")]
1166pub struct StartChecksArgs {
1167 pub pull_id: String,
1168}
1169
1170/// What a sandbox needs to carry out a check run.
1171#[derive(Debug, Serialize, Deserialize)]
1172#[serde(rename_all = "camelCase")]
1173pub struct CheckJob {
1174 pub run_id: String,
1175 /// Lets the sandbox, and nothing else, report this run's results.
1176 pub token: String,
1177 pub commands: Vec<String>,
1178 /// The repository holding the commit: the fork, or the repository itself.
1179 pub source: RepoPath,
1180 pub commit: String,
1181 /// Who opened the pull request, and so can read its source.
1182 pub author: User,
1183 /// Username of whoever wrote the checks: the issue's author.
1184 pub requested_by: String,
1185 pub repo: RepoPath,
1186 pub number: u32,
1187}
1188
1189/// `report_checks`: what a sandbox says about its run. With no results and
1190/// no error it has started. `skip` forgets the run, for one that will not
1191/// be carried out. Returns `Outcome<CheckRun>`.
1192#[derive(Debug, Serialize, Deserialize)]
1193#[serde(rename_all = "camelCase")]
1194pub struct ReportChecksArgs {
1195 pub run_id: String,
1196 pub token: String,
1197 #[serde(default)]
1198 pub results: Vec<CheckResult>,
1199 #[serde(default)]
1200 pub error: Option<String>,
1201 #[serde(default)]
1202 pub skip: bool,
Work service in Rust, with RFC 3339 timestamps1203}
1204
Issues and pull requests replace intents and attempts1205/// A pull request in progress, with where it lives.
1206#[derive(Debug, Serialize, Deserialize)]
1207pub struct ActivePull {
1208 pub pull: Pull,
1209 pub issue: Option<Issue>,
Agents as a team: lifecycle, merge queue, billing and a new shell1210 /// Where it stands, for one g1t is seeing through.
1211 #[serde(default)]
1212 pub lifecycle: Option<Lifecycle>,
Issues and pull requests replace intents and attempts1213}
1214
1215/// `list_active_pulls`: drafts and open pull requests the viewer started,
Agents as a team: lifecycle, merge queue, billing and a new shell1216/// most recently active first. Returns `Vec<ActivePull>`. Also
1217/// `list_assigned_issues`: open issues assigned to the viewer, most
1218/// recently changed first. Returns `Vec<Issue>`.
Work service in Rust, with RFC 3339 timestamps1219#[derive(Debug, Serialize, Deserialize)]
1220pub struct ViewerArgs {
1221 pub viewer: Viewer,
1222}
1223
1224/// `append_session`. Returns `Outcome<Appended>`.
1225#[derive(Debug, Serialize, Deserialize)]
1226pub struct AppendSessionArgs {
1227 pub actor: User,
Issues and pull requests replace intents and attempts1228 pub repo: RepoPath,
1229 pub number: u32,
Work service in Rust, with RFC 3339 timestamps1230 pub entries: Vec<NewSessionEntry>,
1231}
1232
1233#[derive(Debug, Serialize, Deserialize)]
1234pub struct Appended {
1235 pub count: u32,
1236}
Issues and pull requests replace intents and attempts1237
Agents as a team: lifecycle, merge queue, billing and a new shell1238/// `start_review`: begins a review of a pull request by a g1t agent. Called
1239/// by the runner service, which starts the sandbox. Returns
1240/// `Outcome<ReviewJob>`.
1241#[derive(Debug, Serialize, Deserialize)]
1242#[serde(rename_all = "camelCase")]
1243pub struct StartReviewArgs {
1244 pub pull_id: String,
1245}
1246
1247/// What a sandbox needs to review a pull request.
1248#[derive(Debug, Serialize, Deserialize)]
1249#[serde(rename_all = "camelCase")]
1250pub struct ReviewJob {
1251 pub run_id: String,
1252 /// Lets the sandbox, and nothing else, report this review.
1253 pub token: String,
1254 /// The repository holding the commit: the fork, or the repository itself.
1255 pub source: RepoPath,
1256 pub commit: String,
1257 pub repo: RepoPath,
1258 pub default_branch: String,
1259 pub number: u32,
1260 pub title: String,
1261 pub description: String,
1262 /// The issue the pull request is for, which says what it should achieve.
1263 pub issue: Option<Issue>,
1264 /// Who opened the pull request, and so can read its source.
1265 pub author: User,
1266}
1267
1268/// A comment on one line, as a reviewing agent reports it.
1269#[derive(Debug, Serialize, Deserialize)]
1270pub struct ReviewComment {
1271 pub path: String,
1272 #[serde(default)]
1273 pub line: u32,
1274 pub body: String,
1275}
1276
1277/// `report_review`: the review a sandbox's agent wrote, or why it could not
1278/// write one. Returns `Outcome<bool>`.
1279#[derive(Debug, Serialize, Deserialize)]
1280#[serde(rename_all = "camelCase")]
1281pub struct ReportReviewArgs {
1282 pub run_id: String,
1283 pub token: String,
1284 #[serde(default)]
1285 pub verdict: Option<Verdict>,
1286 #[serde(default)]
1287 pub body: String,
1288 #[serde(default)]
1289 pub comments: Vec<ReviewComment>,
1290 /// The model that wrote it, by its public name.
1291 #[serde(default)]
1292 pub model: Option<String>,
1293 #[serde(default)]
1294 pub error: Option<String>,
1295}
1296
Issues and pull requests replace intents and attempts1297/// Lowercases, trims and de-duplicates labels, dropping empty ones.
1298/// Returns `None` if there are too many or one is too long.
1299pub fn normalize_labels(labels: &[String]) -> Option<Vec<String>> {
1300 const MAX_LABELS: usize = 10;
1301 const MAX_LABEL_CHARS: usize = 40;
1302 let mut normalized: Vec<String> = Vec::new();
1303 for label in labels {
1304 let label = label
1305 .split_whitespace()
1306 .collect::<Vec<_>>()
1307 .join(" ")
1308 .to_lowercase();
1309 if label.is_empty() || normalized.contains(&label) {
1310 continue;
1311 }
1312 if label.chars().count() > MAX_LABEL_CHARS {
1313 return None;
1314 }
1315 normalized.push(label);
1316 }
1317 (normalized.len() <= MAX_LABELS).then_some(normalized)
1318}
1319
1320#[cfg(test)]
1321mod tests {
1322 use super::normalize_labels;
1323
1324 fn labels(names: &[&str]) -> Vec<String> {
1325 names.iter().map(|name| (*name).to_owned()).collect()
1326 }
1327
1328 #[test]
1329 fn labels_are_lowercased_trimmed_and_unique() {
1330 assert_eq!(
1331 normalize_labels(&labels(&[" Bug ", "bug", "", "Good First Issue"])),
1332 Some(labels(&["bug", "good first issue"]))
1333 );
1334 }
1335
1336 #[test]
1337 fn too_long_or_too_many_labels_are_refused() {
1338 assert_eq!(normalize_labels(&["x".repeat(41)]), None);
1339 let many: Vec<String> = (0..11).map(|i| format!("label-{i}")).collect();
1340 assert_eq!(normalize_labels(&many), None);
1341 }
1342}
Agents as a team: lifecycle, merge queue, billing and a new shell1343
1344
1345// --- Merge queue ----------------------------------------------------------
1346
1347/// Where a pull request in a merge queue stands.
1348#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1349#[serde(rename_all = "snake_case")]
1350pub enum QueueState {
1351 /// Waiting for its turn to be tested.
1352 Waiting,
1353 /// Its combined state is being built and checked.
1354 Testing,
1355 /// Its combined state passed; it lands once everything ahead has.
1356 Passed,
1357 /// Its combined state failed, or would not merge. It left the queue.
1358 Failed,
1359 /// On the default branch.
1360 Landed,
1361 /// Taken out of the queue by a person, or closed.
1362 Removed,
1363}
1364
1365impl QueueState {
1366 pub fn as_str(self) -> &'static str {
1367 match self {
1368 QueueState::Waiting => "waiting",
1369 QueueState::Testing => "testing",
1370 QueueState::Passed => "passed",
1371 QueueState::Failed => "failed",
1372 QueueState::Landed => "landed",
1373 QueueState::Removed => "removed",
1374 }
1375 }
1376
1377 /// Still in the queue.
1378 pub fn is_active(self) -> bool {
1379 matches!(
1380 self,
1381 QueueState::Waiting | QueueState::Testing | QueueState::Passed
1382 )
1383 }
1384}
1385
1386/// One pull request's place in a merge queue.
1387#[derive(Clone, Debug, Serialize, Deserialize)]
1388#[serde(rename_all = "camelCase")]
1389pub struct QueueEntry {
1390 pub id: String,
1391 pub number: u32,
1392 pub title: String,
1393 /// Who or what made the pull request, e.g. `g1t-agent`.
1394 pub agent: String,
1395 pub state: QueueState,
1396 /// The pull requests merged ahead of it in the state being tested, in
1397 /// queue order. Empty when it was tested on the default branch alone.
1398 pub ahead: Vec<u32>,
1399 /// The default branch's commit the tested state was built on.
1400 pub base_commit: Option<String>,
1401 /// The tested state: the default branch with everything ahead and this.
1402 pub combined_commit: Option<String>,
1403 /// Why it failed: a merge conflict or what could not be run.
1404 pub error: Option<String>,
1405 /// The checks run against the tested state.
1406 pub results: Vec<CheckResult>,
1407 /// Username of whoever merged it into the queue: a person, or `g1t`.
1408 pub enqueued_by: String,
1409 /// RFC 3339.
1410 pub created_at: String,
1411 /// RFC 3339. When it landed or left.
1412 pub finished_at: Option<String>,
1413}
1414
1415/// A repository's merge queue: what is in it, in order, and what recently
1416/// left it.
1417#[derive(Clone, Debug, Serialize, Deserialize)]
1418#[serde(rename_all = "camelCase")]
1419pub struct QueueView {
1420 /// Whether the repository merges through the queue.
1421 pub enabled: bool,
1422 pub active: Vec<QueueEntry>,
1423 /// Newest first.
1424 pub recent: Vec<QueueEntry>,
1425}
1426
1427/// `queue`: a repository's merge queue. Returns `Outcome<QueueView>`.
1428#[derive(Debug, Serialize, Deserialize)]
1429pub struct QueueArgs {
1430 pub repo: RepoPath,
1431 pub viewer: Viewer,
1432}
1433
1434/// `queue_build`: the next batch to test for a repository, if nothing is
1435/// being tested now. Returns `Vec<QueueJob>`, one per entry, each testing
1436/// the default branch with that entry and everything ahead of it.
1437#[derive(Debug, Serialize, Deserialize)]
1438#[serde(rename_all = "camelCase")]
1439pub struct QueueBuildArgs {
1440 pub repo_id: String,
1441}
1442
1443/// One pull request in a state being tested: where its change is.
1444#[derive(Clone, Debug, Serialize, Deserialize)]
1445#[serde(rename_all = "camelCase")]
1446pub struct QueueStackItem {
1447 pub number: u32,
1448 pub title: String,
1449 /// The repository holding the change: its fork, or the repository.
1450 pub source: RepoPath,
1451 /// The branch of `source` holding it.
1452 pub branch: String,
1453 pub commit: String,
1454}
1455
1456/// What a sandbox needs to build and check one combined state.
1457#[derive(Clone, Debug, Serialize, Deserialize)]
1458#[serde(rename_all = "camelCase")]
1459pub struct QueueJob {
1460 pub entry_id: String,
1461 /// Lets the sandbox, and nothing else, report this state's result.
1462 pub token: String,
1463 pub repo: RepoPath,
1464 pub default_branch: String,
1465 /// The default branch's commit to build on.
1466 pub base_commit: String,
1467 /// Where to push the tested state, in the repository itself.
1468 pub branch: String,
1469 /// The pull requests to merge in, in order; the last is the entry.
1470 pub stack: Vec<QueueStackItem>,
1471 /// Every acceptance check of every pull request in the stack.
1472 pub checks: Vec<String>,
1473 /// The checks of issues already completed: the default branch's
1474 /// contract. One that fails on the base alone is not held against the
1475 /// entry.
1476 #[serde(default)]
1477 pub contract_checks: Vec<String>,
1478 /// Who the sandbox acts as: a member who can push the tested state.
1479 pub actor: User,
1480}
1481
1482/// `report_queue`: a sandbox's result for one combined state. Returns
1483/// `Outcome<QueueState>`.
1484#[derive(Debug, Serialize, Deserialize)]
1485#[serde(rename_all = "camelCase")]
1486pub struct ReportQueueArgs {
1487 pub entry_id: String,
1488 pub token: String,
1489 #[serde(default)]
1490 pub combined_commit: Option<String>,
1491 #[serde(default)]
1492 pub results: Vec<CheckResult>,
1493 /// Set when the state could not be built or checked.
1494 #[serde(default)]
1495 pub error: Option<String>,
1496 /// For a merge conflict: the pull request whose change it collided with.
1497 #[serde(default)]
1498 pub conflict_with: Option<u32>,
Agents and memory, checks and conflicts, profiles, slug renames, custom domains1499 /// For a merge conflict: the files that conflicted.
1500 #[serde(default)]
1501 pub conflicts: Vec<String>,
Agents as a team: lifecycle, merge queue, billing and a new shell1502}
Record your own agent's sessions automatically1503
1504
1505/// `locate_pull`: where a pull request lives, by its id, for a tool that
1506/// knows only the fork it is working in (`g1t.sh/pulls/<id>`). Returns
1507/// `Outcome<LocatedPull>`; not found for anyone who cannot see it.
1508#[derive(Debug, Serialize, Deserialize)]
1509pub struct LocatePullArgs {
1510 pub id: String,
1511 pub viewer: Viewer,
1512}
1513
1514#[derive(Clone, Debug, Serialize, Deserialize)]
1515#[serde(rename_all = "camelCase")]
1516pub struct LocatedPull {
1517 pub repo: RepoPath,
1518 pub number: u32,
1519 pub title: String,
1520 pub status: PullStatus,
1521}
Agents and memory, checks and conflicts, profiles, slug renames, custom domains1522
1523// --- A person's work -------------------------------------------------------
1524
1525/// Issues or pull requests, on a person's profile.
1526#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1527#[serde(rename_all = "lowercase")]
1528pub enum AuthoredKind {
1529 Issue,
1530 Pull,
1531}
1532
1533/// The state filter on a person's work. `Closed` takes in merged pull
1534/// requests too; `Merged` is only those.
1535#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1536#[serde(rename_all = "lowercase")]
1537pub enum AuthoredState {
1538 Open,
1539 Closed,
1540 Merged,
1541}
1542
1543/// How a person's work is ordered.
1544#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
1545#[serde(rename_all = "lowercase")]
1546pub enum AuthoredSort {
1547 /// Newest first.
1548 #[default]
1549 Created,
1550 /// Most recently changed first.
1551 Updated,
1552 /// Oldest first.
1553 Oldest,
1554}
1555
1556/// The most items one `by_author` page holds.
1557pub const AUTHORED_PAGE: u32 = 25;
1558
1559/// `by_author`: the issues and pull requests a person opened, only on
1560/// repositories `viewer` may read, so a private title never reaches anyone
1561/// who could not open it. Returns `Outcome<Authored>`; not found for an
1562/// account that does not exist.
1563#[derive(Debug, Serialize, Deserialize)]
1564pub struct ByAuthorArgs {
1565 pub username: String,
1566 pub viewer: Viewer,
1567 #[serde(default)]
1568 pub kind: Option<AuthoredKind>,
1569 #[serde(default)]
1570 pub state: Option<AuthoredState>,
1571 /// Only work on this repository: `namespace/name`.
1572 #[serde(default)]
1573 pub repo: Option<String>,
1574 #[serde(default)]
1575 pub sort: AuthoredSort,
1576 /// The `next` of the page before, to read on from there.
1577 #[serde(default)]
1578 pub before: Option<String>,
1579 /// At most [`AUTHORED_PAGE`]; that when absent.
1580 #[serde(default)]
1581 pub limit: Option<u32>,
1582}
1583
1584/// One issue or pull request a person opened.
1585#[derive(Clone, Debug, Serialize, Deserialize)]
1586#[serde(rename_all = "camelCase")]
1587pub struct AuthoredItem {
1588 pub kind: AuthoredKind,
1589 pub repo: RepoPath,
1590 pub number: u32,
1591 pub title: String,
1592 /// Open or closed; a merged pull request is closed.
1593 pub state: State,
1594 /// A pull request's own status.
1595 pub status: Option<PullStatus>,
1596 /// Why an issue was closed.
1597 pub reason: Option<IssueReason>,
1598 pub draft: bool,
1599 pub merged: bool,
1600 /// RFC 3339.
1601 pub created_at: String,
1602 /// RFC 3339.
1603 pub updated_at: String,
1604 /// When a pull request was merged. RFC 3339.
1605 pub merged_at: Option<String>,
1606}
1607
1608/// What a person has done, as far as the viewer may see.
1609#[derive(Clone, Debug, Default, Serialize, Deserialize)]
1610#[serde(rename_all = "camelCase")]
1611pub struct AuthoredCounts {
1612 pub pulls_merged: u32,
1613 pub pulls_open: u32,
1614 pub pulls: u32,
1615 pub issues: u32,
1616 pub issues_open: u32,
1617}
1618
1619/// A repository a person has opened work on, with how much.
1620#[derive(Clone, Debug, Serialize, Deserialize)]
1621pub struct AuthoredRepo {
1622 pub repo: RepoPath,
1623 pub count: u32,
1624}
1625
1626/// A page of a person's work.
1627#[derive(Clone, Debug, Default, Serialize, Deserialize)]
1628#[serde(rename_all = "camelCase")]
1629pub struct Authored {
1630 pub items: Vec<AuthoredItem>,
1631 /// Pass as `before` for the next page; null on the last.
1632 pub next: Option<String>,
1633 /// Over every repository the viewer may read, whatever the filters.
1634 pub counts: AuthoredCounts,
1635 /// Those repositories, most work first.
1636 pub repos: Vec<AuthoredRepo>,
1637}