flagon-io/g1t

public

Git for AI scale: a forge for thousands of agents working on the same code at once.

g1t/crates/contracts/src/events.rs

295 lines9,574 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.

Events service in Rust, with RFC 3339 times and accurate push events1//! Events published on the bus, and the events service that carries them.
2//! Mirrors `packages/contracts/src/events.ts`.
Rust repos service with shipping; pull requests kept in the model3
4use serde::Serialize;
5
6/// What a publisher supplies; the bus fills in the id and time.
7#[derive(Debug, Serialize)]
8#[serde(rename_all = "camelCase")]
9pub struct NewEvent<T: Serialize> {
10 #[serde(rename = "type")]
11 pub kind: &'static str,
12 /// The service that published it.
13 pub source: &'static str,
14 /// The repo the event concerns.
15 pub repo_id: Option<String>,
16 /// The user or agent that caused it, if any.
17 pub actor: Option<String>,
18 pub data: T,
19}
20
21#[derive(Debug, Serialize)]
22#[serde(rename_all = "camelCase")]
23pub struct RepoCreated {
24 pub repo_id: String,
25 pub namespace: String,
26 pub name: String,
27 pub is_private: bool,
28}
29
30#[derive(Debug, Serialize)]
31#[serde(rename_all = "camelCase")]
32pub struct RepoForked {
33 pub repo_id: String,
34 pub source_repo_id: String,
Issues and pull requests replace intents and attempts35 pub pull_id: String,
Rust repos service with shipping; pull requests kept in the model36}
37
GitHub Actions on g1t, part one: reading workflows38/// One branch or tag moved by a push. `after` is the commit it points to now.
Rust repos service with shipping; pull requests kept in the model39#[derive(Debug, Serialize)]
40#[serde(rename_all = "camelCase")]
41pub struct GitPush {
42 pub repo_id: String,
Events service in Rust, with RFC 3339 times and accurate push events43 /// The full ref, such as `refs/heads/main`.
Rust repos service with shipping; pull requests kept in the model44 #[serde(rename = "ref")]
45 pub git_ref: String,
GitHub Actions on g1t, part one: reading workflows46 /// Where it pointed before; absent for a new branch or tag.
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub before: Option<String>,
Rust repos service with shipping; pull requests kept in the model49 pub after: String,
Events service in Rust, with RFC 3339 times and accurate push events50 /// Whether the ref is the repository's default branch.
51 pub default_branch: bool,
Rust repos service with shipping; pull requests kept in the model52}
Work service in Rust, with RFC 3339 timestamps53
Agents as a team: lifecycle, merge queue, billing and a new shell54/// The payload of `issue.opened`, `issue.updated`, `issue.assigned`,
55/// `issue.closed` and `issue.reopened`; each uses the fields that apply to it.
Issues and pull requests replace intents and attempts56#[derive(Debug, Default, Serialize)]
Work service in Rust, with RFC 3339 timestamps57#[serde(rename_all = "camelCase")]
Issues and pull requests replace intents and attempts58pub struct IssueEvent {
59 pub issue_id: String,
Work service in Rust, with RFC 3339 timestamps60 pub repo_id: String,
61 pub number: u32,
Issues and pull requests replace intents and attempts62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub title: Option<String>,
64 /// On close: `completed` or `not_planned`.
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub reason: Option<&'static str>,
67 /// On close: the number of the pull request whose merge closed it.
68 #[serde(skip_serializing_if = "Option::is_none")]
69 pub resolved_by: Option<u32>,
Agents as a team: lifecycle, merge queue, billing and a new shell70 /// On `issue.assigned`: the people it is now assigned to.
71 #[serde(skip_serializing_if = "Option::is_none")]
72 pub assignees: Option<Vec<String>>,
Work service in Rust, with RFC 3339 timestamps73}
74
Acceptance checks in sandboxes, line comments and review verdicts75/// The payload of `pull.opened`, `pull.ready`, `pull.updated` (its head
76/// moved), `pull.closed` and `pull.merged`; each uses the fields that apply to it.
Work service in Rust, with RFC 3339 timestamps77#[derive(Debug, Default, Serialize)]
78#[serde(rename_all = "camelCase")]
Issues and pull requests replace intents and attempts79pub struct PullEvent {
80 pub pull_id: String,
Work service in Rust, with RFC 3339 timestamps81 pub repo_id: String,
Issues and pull requests replace intents and attempts82 pub number: u32,
83 /// The number of the issue it is for.
84 #[serde(skip_serializing_if = "Option::is_none")]
85 pub issue: Option<u32>,
Work service in Rust, with RFC 3339 timestamps86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub agent: Option<String>,
Workflows run when an agent's pull request is marked ready88 /// On merge: the commit the branch now points to. On update and when
89 /// marked ready: the head of the change.
Work service in Rust, with RFC 3339 timestamps90 #[serde(skip_serializing_if = "Option::is_none")]
Issues and pull requests replace intents and attempts91 pub commit: Option<String>,
92 /// On close: the pull request that was merged instead.
Work service in Rust, with RFC 3339 timestamps93 #[serde(skip_serializing_if = "Option::is_none")]
Issues and pull requests replace intents and attempts94 pub superseded_by: Option<u32>,
Work service in Rust, with RFC 3339 timestamps95}
96
Acceptance checks in sandboxes, line comments and review verdicts97/// `checks.completed`: a run of an issue's acceptance checks against a pull
98/// request finished.
99#[derive(Debug, Serialize)]
100#[serde(rename_all = "camelCase")]
101pub struct ChecksEvent {
102 pub pull_id: String,
103 pub repo_id: String,
104 pub number: u32,
105 /// `passed`, `failed` or `errored`.
106 pub status: &'static str,
107 /// The commit that was checked.
108 pub commit: String,
109}
110
Actions: workflow_run, workflow.completed, artifacts on the run page, Node 24111/// `workflow.completed`: a GitHub Actions run finished.
112#[derive(Debug, Serialize)]
113#[serde(rename_all = "camelCase")]
114pub struct WorkflowEvent {
115 pub run_id: String,
116 pub repo_id: String,
117 /// The workflow's name, and its file.
118 pub workflow: String,
119 pub path: String,
120 /// The run's number among the workflow's runs.
121 pub number: u64,
122 /// The GitHub event that started it, such as `push`.
123 pub event: String,
124 /// `success`, `failure`, `cancelled` or `skipped`.
125 pub conclusion: String,
126 #[serde(rename = "ref")]
127 pub git_ref: String,
128 pub sha: String,
129 /// The pull request it ran for, if any.
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub pull: Option<u32>,
132}
133
Agents as a team: lifecycle, merge queue, billing and a new shell134/// `review.completed`: a g1t agent finished reviewing a pull request, or
135/// could not.
136#[derive(Debug, Serialize)]
137#[serde(rename_all = "camelCase")]
138pub struct ReviewEvent {
139 pub pull_id: String,
140 pub repo_id: String,
141 pub number: u32,
142 /// `approve` or `request_changes`; absent when no review was written.
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub verdict: Option<&'static str>,
145}
146
Issues and pull requests replace intents and attempts147/// `comment.created`. `number` is the issue or pull request commented on.
Work service in Rust, with RFC 3339 timestamps148#[derive(Debug, Serialize)]
149#[serde(rename_all = "camelCase")]
Issues and pull requests replace intents and attempts150pub struct CommentCreated {
151 pub comment_id: String,
152 pub repo_id: String,
153 pub number: u32,
Agents as a team: lifecycle, merge queue, billing and a new shell154 /// Set when the comment is on a pull request.
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub pull_id: Option<String>,
157 /// Set when the comment is a review: approve or request changes.
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub verdict: Option<crate::work::Verdict>,
Issues and pull requests replace intents and attempts160}
161
162#[derive(Debug, Serialize)]
163#[serde(rename_all = "camelCase")]
Work service in Rust, with RFC 3339 timestamps164pub struct SessionAppended {
Issues and pull requests replace intents and attempts165 pub pull_id: String,
166 pub repo_id: String,
167 pub number: u32,
Work service in Rust, with RFC 3339 timestamps168 pub count: u32,
169}
170
Events service in Rust, with RFC 3339 times and accurate push events171/// An event as stored in the log and delivered to subscribers. `data` is
172/// left as JSON; each reader decodes the types it cares about.
173#[derive(Clone, Debug, Serialize, serde::Deserialize)]
174#[serde(rename_all = "camelCase")]
175pub struct Event {
176 /// Sorts by the time the event was published.
177 pub id: String,
178 #[serde(rename = "type")]
179 pub kind: String,
180 /// The service that published it.
181 pub source: String,
182 /// RFC 3339.
183 pub time: String,
184 /// The repo the event concerns.
185 pub repo_id: Option<String>,
186 /// The user or agent that caused it, if any.
187 pub actor: Option<String>,
188 pub data: serde_json::Value,
189}
190
191/// `publish`, as a publisher sends it. Returns nothing.
192#[derive(Debug, Serialize)]
193pub struct Publish<T: Serialize> {
194 pub events: Vec<NewEvent<T>>,
195}
196
197/// `publish`, as the events service reads it.
198#[derive(Debug, serde::Deserialize)]
199pub struct PublishArgs {
200 pub events: Vec<Published>,
201}
202
203/// A [`NewEvent`] of any type, as received.
Work service in Rust, with RFC 3339 timestamps204#[derive(Debug, serde::Deserialize)]
205#[serde(rename_all = "camelCase")]
Events service in Rust, with RFC 3339 times and accurate push events206pub struct Published {
Work service in Rust, with RFC 3339 timestamps207 #[serde(rename = "type")]
208 pub kind: String,
Events service in Rust, with RFC 3339 times and accurate push events209 pub source: String,
210 #[serde(default)]
Work service in Rust, with RFC 3339 timestamps211 pub repo_id: Option<String>,
Events service in Rust, with RFC 3339 times and accurate push events212 #[serde(default)]
213 pub actor: Option<String>,
Work service in Rust, with RFC 3339 timestamps214 pub data: serde_json::Value,
215}
Events service in Rust, with RFC 3339 times and accurate push events216
217/// `list`: events from the log, newest first. Returns `Vec<Event>`.
218#[derive(Debug, Default, Serialize, serde::Deserialize)]
219#[serde(rename_all = "camelCase")]
220pub struct ListArgs {
221 #[serde(default)]
222 pub repo_id: Option<String>,
223 /// Only these types; all types when empty.
224 #[serde(default)]
225 pub types: Vec<String>,
226 /// Only events older than this event id.
227 #[serde(default)]
228 pub before: Option<String>,
229 #[serde(default)]
230 pub limit: Option<u32>,
231}
Agents as a team: lifecycle, merge queue, billing and a new shell232
Agents and memory, checks and conflicts, profiles, slug renames, custom domains233/// `workspace.renamed`: a workspace's slug changed from `from` to `to`.
234/// Every service that stores a slug moves its rows to the workspace's
235/// *current* slug (ask identity by `workspace_id`), so that a repeated or
236/// late delivery after a second rename still lands in the right place.
237#[derive(Clone, Debug, Serialize, serde::Deserialize)]
238#[serde(rename_all = "camelCase")]
239pub struct WorkspaceRenamed {
240 pub workspace_id: String,
241 pub from: String,
242 pub to: String,
243}
244
245impl WorkspaceRenamed {
246 /// The slugs whose rows move to `current`: the two this rename names,
247 /// minus `current` itself. Moving rows keyed by either converges on the
248 /// current slug whatever order renames are delivered in.
249 pub fn stale_slugs(&self, current: &str) -> Vec<String> {
250 let mut slugs: Vec<String> = Vec::new();
251 for slug in [&self.from, &self.to] {
252 if slug != current && !slugs.contains(slug) {
253 slugs.push(slug.clone());
254 }
255 }
256 slugs
257 }
258}
259
Agents as a team: lifecycle, merge queue, billing and a new shell260/// `queue.changed`: a repository's merge queue gained, lost or settled an
261/// entry, so the next batch may be ready to test.
262#[derive(Debug, Serialize)]
263#[serde(rename_all = "camelCase")]
264pub struct QueueChanged {
265 pub repo_id: String,
266}
Agents and memory, checks and conflicts, profiles, slug renames, custom domains267
268#[cfg(test)]
269mod tests {
270 use super::*;
271
272 fn renamed(from: &str, to: &str) -> WorkspaceRenamed {
273 WorkspaceRenamed {
274 workspace_id: "wsp_1".into(),
275 from: from.into(),
276 to: to.into(),
277 }
278 }
279
280 #[test]
281 fn stale_slugs_leave_out_the_current_one() {
282 assert_eq!(renamed("a", "b").stale_slugs("b"), vec!["a"]);
283 // Delivered after a second rename, b → c: both move to c.
284 assert_eq!(renamed("a", "b").stale_slugs("c"), vec!["a", "b"]);
285 // Renamed back: a → b → a.
286 assert_eq!(renamed("a", "b").stale_slugs("a"), vec!["b"]);
287 }
288
289 #[test]
290 fn reads_the_published_payload() {
291 let data = serde_json::json!({ "workspaceId": "wsp_1", "from": "a", "to": "b" });
292 let event: WorkspaceRenamed = serde_json::from_value(data).unwrap();
293 assert_eq!((event.from.as_str(), event.to.as_str()), ("a", "b"));
294 }
295}