Skip to main content

ai_crew_sync/
model.rs

1//! Wire types returned by the MCP tools.
2//!
3//! Timestamps are RFC 3339 strings rather than typed datetimes: the consumer is
4//! a language model, and a plain string is both unambiguous and free of extra
5//! schema dependencies.
6
7use schemars::JsonSchema;
8use serde::Serialize;
9
10pub fn ts(dt: chrono::DateTime<chrono::Utc>) -> String {
11    dt.to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
12}
13
14pub fn ts_opt(dt: Option<chrono::DateTime<chrono::Utc>>) -> Option<String> {
15    dt.map(ts)
16}
17
18#[derive(Debug, Serialize, JsonSchema)]
19pub struct WhoAmI {
20    /// Your agent handle. Other agents address you by this name.
21    pub agent: String,
22    pub agent_id: String,
23    pub team: String,
24    pub team_id: String,
25    /// Number of unread direct messages waiting for you.
26    pub unread_direct_messages: i64,
27    /// Tasks currently claimed by you and not yet completed.
28    pub open_claimed_tasks: i64,
29}
30
31// ------------------------------------------------------------------ agents --
32
33#[derive(Debug, Serialize, JsonSchema)]
34pub struct AgentInfo {
35    pub name: String,
36    pub display_name: Option<String>,
37    /// One of `active`, `idle`, `offline`. `offline` means the presence lease
38    /// expired, i.e. the agent has not sent a heartbeat recently.
39    pub status: String,
40    pub repo: Option<String>,
41    pub branch: Option<String>,
42    /// Free-text description of what this agent is currently doing.
43    pub activity: Option<String>,
44    pub last_seen: Option<String>,
45    pub online: bool,
46}
47
48#[derive(Debug, Serialize, JsonSchema)]
49pub struct AgentList {
50    pub agents: Vec<AgentInfo>,
51    pub online_count: usize,
52}
53
54// -------------------------------------------------------------- messaging --
55
56#[derive(Debug, Serialize, JsonSchema)]
57pub struct ChannelInfo {
58    pub name: String,
59    pub topic: Option<String>,
60    pub message_count: i64,
61    pub created_at: String,
62}
63
64#[derive(Debug, Serialize, JsonSchema)]
65pub struct ChannelList {
66    pub channels: Vec<ChannelInfo>,
67}
68
69#[derive(Debug, Serialize, JsonSchema)]
70pub struct MessageInfo {
71    pub id: i64,
72    pub from: String,
73    /// Channel name for channel messages; `null` for direct messages.
74    pub channel: Option<String>,
75    /// Recipient handle for direct messages; `null` for channel messages.
76    pub to: Option<String>,
77    pub body: String,
78    pub reply_to: Option<i64>,
79    pub metadata: serde_json::Value,
80    pub created_at: String,
81}
82
83#[derive(Debug, Serialize, JsonSchema)]
84pub struct PostMessageResult {
85    pub message: MessageInfo,
86    /// Handles that can now see this message.
87    pub delivered_to: Vec<String>,
88}
89
90#[derive(Debug, Serialize, JsonSchema)]
91pub struct MessageList {
92    pub messages: Vec<MessageInfo>,
93    /// The scope that was actually read, after normalisation.
94    pub scope: String,
95    /// Read cursor position after this call. Messages at or below this id will
96    /// not be returned again when `only_new` is true.
97    pub cursor: i64,
98    /// True when the result hit `limit` and older/newer messages remain.
99    pub truncated: bool,
100}
101
102// ------------------------------------------------------------------ tasks --
103
104#[derive(Debug, Serialize, JsonSchema)]
105pub struct TaskInfo {
106    pub key: String,
107    pub title: String,
108    pub description: Option<String>,
109    /// One of `open`, `claimed`, `done`, `cancelled`.
110    pub status: String,
111    /// Keys of tasks this one depends on.
112    pub depends_on: Vec<String>,
113    /// True while any dependency is not yet done/cancelled. Blocked tasks
114    /// cannot be claimed.
115    pub blocked: bool,
116    pub claimed_by: Option<String>,
117    pub claimed_at: Option<String>,
118    /// When the current claim expires. After this instant another agent may
119    /// steal the task, so renew the lease if you are still working on it.
120    pub lease_expires_at: Option<String>,
121    /// True when the claim has already lapsed.
122    pub lease_expired: bool,
123    pub result: Option<String>,
124    pub metadata: serde_json::Value,
125    pub created_by: Option<String>,
126    pub created_at: String,
127    pub updated_at: String,
128}
129
130#[derive(Debug, Serialize, JsonSchema)]
131pub struct TaskList {
132    pub tasks: Vec<TaskInfo>,
133    pub open: i64,
134    pub claimed: i64,
135}
136
137#[derive(Debug, Serialize, JsonSchema)]
138pub struct ClaimResult {
139    pub claimed: bool,
140    pub task: Option<TaskInfo>,
141    /// Present when `claimed` is false: why the claim did not succeed.
142    pub reason: Option<String>,
143}
144
145#[derive(Debug, Serialize, JsonSchema)]
146pub struct TaskEventInfo {
147    pub event: String,
148    pub agent: Option<String>,
149    pub detail: Option<String>,
150    pub created_at: String,
151}
152
153#[derive(Debug, Serialize, JsonSchema)]
154pub struct TaskDetail {
155    pub task: TaskInfo,
156    pub history: Vec<TaskEventInfo>,
157}
158
159// ------------------------------------------------------------------ notes --
160
161#[derive(Debug, Serialize, JsonSchema)]
162pub struct NoteInfo {
163    pub scope: String,
164    pub key: String,
165    pub value: String,
166    pub tags: Vec<String>,
167    pub updated_by: Option<String>,
168    pub updated_at: String,
169}
170
171#[derive(Debug, Serialize, JsonSchema)]
172pub struct NoteList {
173    pub notes: Vec<NoteInfo>,
174}
175
176#[derive(Debug, Serialize, JsonSchema)]
177pub struct NoteRef {
178    pub scope: String,
179    pub key: String,
180    pub found: bool,
181    pub note: Option<NoteInfo>,
182}
183
184#[derive(Debug, Serialize, JsonSchema)]
185pub struct Ack {
186    pub ok: bool,
187    pub detail: String,
188}
189
190// ------------------------------------------------------------------ locks --
191
192#[derive(Debug, Serialize, JsonSchema)]
193pub struct LockInfo {
194    pub name: String,
195    pub holder: String,
196    pub purpose: Option<String>,
197    pub acquired_at: String,
198    /// When the lock lapses on its own if not renewed.
199    pub expires_at: String,
200}
201
202#[derive(Debug, Serialize, JsonSchema)]
203pub struct LockList {
204    pub locks: Vec<LockInfo>,
205}
206
207#[derive(Debug, Serialize, JsonSchema)]
208pub struct LockResult {
209    pub acquired: bool,
210    pub lock: Option<LockInfo>,
211    /// Present when `acquired` is false: who holds it and until when.
212    pub reason: Option<String>,
213}
214
215// ----------------------------------------------------------------- events --
216
217#[derive(Debug, Serialize, JsonSchema)]
218pub struct WaitEvent {
219    /// One of `message`, `task`, `lock`, `note`.
220    pub kind: String,
221    /// Human-readable one-liner of what happened.
222    pub summary: String,
223}
224
225#[derive(Debug, Serialize, JsonSchema)]
226pub struct WaitResult {
227    /// True when something happened; false when the timeout elapsed quietly.
228    pub woke: bool,
229    pub timed_out: bool,
230    pub events: Vec<WaitEvent>,
231    /// Unread direct messages after the wait — if > 0, call read_messages.
232    pub unread_direct_messages: i64,
233    /// What to do next, e.g. which tool to call to fetch the details.
234    pub suggestion: String,
235}
236
237#[derive(Debug, Serialize, JsonSchema)]
238pub struct AskResult {
239    /// True when the teammate answered before the timeout.
240    pub answered: bool,
241    /// The agent the question was addressed to.
242    pub to: String,
243    /// Id of the question message. On timeout, pass it back as
244    /// `resume_message_id` to keep waiting without re-sending the question.
245    pub question_message_id: i64,
246    /// The answer: their reply to the question, or failing that their first
247    /// direct message to you after it.
248    pub answer: Option<MessageInfo>,
249    /// What to do next.
250    pub suggestion: String,
251}
252
253// ----------------------------------------------------------------- digest --
254
255#[derive(Debug, Serialize, JsonSchema)]
256pub struct DigestMessage {
257    pub from: String,
258    pub body: String,
259    pub at: String,
260}
261
262#[derive(Debug, Serialize, JsonSchema)]
263pub struct DigestChannel {
264    pub name: String,
265    pub message_count: i64,
266    pub last_messages: Vec<DigestMessage>,
267}
268
269#[derive(Debug, Serialize, JsonSchema)]
270pub struct DigestTask {
271    pub key: String,
272    pub title: String,
273    pub status: String,
274    pub claimed_by: Option<String>,
275    pub result: Option<String>,
276    pub updated_at: String,
277}
278
279#[derive(Debug, Serialize, JsonSchema)]
280pub struct DigestNote {
281    pub scope: String,
282    pub key: String,
283    pub updated_by: Option<String>,
284    pub updated_at: String,
285}
286
287#[derive(Debug, Serialize, JsonSchema)]
288pub struct DigestAgent {
289    pub name: String,
290    pub activity: Option<String>,
291    pub last_seen: Option<String>,
292    pub online: bool,
293}
294
295#[derive(Debug, Serialize, JsonSchema)]
296pub struct DigestResult {
297    /// Window covered, in hours.
298    pub hours: i64,
299    pub channels: Vec<DigestChannel>,
300    /// Tasks whose state changed inside the window, newest first.
301    pub tasks_moved: Vec<DigestTask>,
302    pub open_tasks: i64,
303    pub claimed_tasks: i64,
304    pub notes_updated: Vec<DigestNote>,
305    pub agents_seen: Vec<DigestAgent>,
306    pub active_locks: Vec<LockInfo>,
307}