Skip to main content

rightkit_agent_engine_protocol/
schedule.rs

1//! Canonical schedule-run types — the single definition in the workspace.
2//!
3//! Hoisted from the byte-near-identical duplicates that lived in
4//! `host app/src/scheduler.rs` (write side) and `host app/src/api_schedules.rs`
5//! (read side). The wire JSON is unchanged: all serde attributes moved with the
6//! struct. `ScheduleRunEvent` here is the SUPERSET — it includes the
7//! `schema_version`/`started_at`/`finished_at` evidence fields hermes plan #2
8//! added to the write side, so the read side now exposes them too.
9
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13pub fn default_job_mode() -> String {
14    "agent".to_string()
15}
16
17pub fn default_schema_version() -> u32 {
18    1
19}
20
21#[derive(Clone, Debug, Default, Serialize, Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct ScheduleRunState {
24    #[serde(default)]
25    pub last_claimed_minute: HashMap<String, i64>,
26    #[serde(default)]
27    pub history: Vec<ScheduleRunEvent>,
28}
29
30#[derive(Clone, Debug, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct ScheduleRunEvent {
33    #[serde(default = "default_schema_version")]
34    pub schema_version: u32,
35    pub schedule_id: String,
36    pub epoch_minute: i64,
37    pub status: String,
38    pub session_id: String,
39    pub message: String,
40    #[serde(default, skip_serializing_if = "String::is_empty")]
41    pub started_at: String,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub finished_at: Option<String>,
44    #[serde(default = "default_job_mode")]
45    pub mode: String,
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub toolset: Option<String>,
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub execution_backend: Option<String>,
50    #[serde(default, skip_serializing_if = "Option::is_none")]
51    pub resolved_execution_backend: Option<String>,
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub execution_workspace_id: Option<String>,
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub execution_workspace_path: Option<String>,
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub resource_limits: Option<ScheduleRunResourceLimits>,
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub workdir: Option<String>,
60    #[serde(default, skip_serializing_if = "Vec::is_empty")]
61    pub skills: Vec<String>,
62    #[serde(default, skip_serializing_if = "Vec::is_empty")]
63    pub delivery_kinds: Vec<String>,
64    #[serde(default, skip_serializing_if = "Option::is_none")]
65    pub source_recipe_id: Option<String>,
66    #[serde(default, skip_serializing_if = "Option::is_none")]
67    pub exit_code: Option<i32>,
68    #[serde(default, skip_serializing_if = "Option::is_none")]
69    pub artifact_path: Option<String>,
70    #[serde(default, skip_serializing_if = "Option::is_none")]
71    pub delivery_status: Option<String>,
72    #[serde(default, skip_serializing_if = "Vec::is_empty")]
73    pub delivery_errors: Vec<String>,
74}
75
76#[derive(Clone, Debug, Default, Serialize, Deserialize)]
77#[serde(rename_all = "camelCase")]
78pub struct ScheduleRunResourceLimits {
79    #[serde(default, skip_serializing_if = "Option::is_none")]
80    pub cpu: Option<u32>,
81    #[serde(default, skip_serializing_if = "Option::is_none")]
82    pub memory_mb: Option<u32>,
83    #[serde(default, skip_serializing_if = "Option::is_none")]
84    pub disk_mb: Option<u32>,
85}