1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use crate::fs::{next_id, now_ms};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub enum TaskStatus {
12 Running,
13 Succeeded,
14 Failed,
15 Cancelled,
16 Interrupted,
17}
18
19impl TaskStatus {
20 pub fn is_terminal(self) -> bool {
21 matches!(
22 self,
23 Self::Succeeded | Self::Failed | Self::Cancelled | Self::Interrupted
24 )
25 }
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct TaskRuntimeInstance {
38 pub instance_id: String,
39 pub pid: u32,
40 pub started_at_ms: u64,
41}
42
43impl TaskRuntimeInstance {
44 pub fn current() -> Self {
45 Self {
46 instance_id: next_id("runtime"),
47 pid: std::process::id(),
48 started_at_ms: now_ms(),
49 }
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct HarnessTask {
57 pub id: String,
58 pub title: String,
59 pub instructions: String,
60 pub status: TaskStatus,
61 pub created_at_ms: u64,
62 pub updated_at_ms: u64,
63 #[serde(default)]
64 pub requested_by: Option<String>,
65 #[serde(default)]
66 pub tags: Vec<String>,
67 #[serde(default)]
68 pub metadata: Option<Value>,
69 #[serde(default)]
70 pub runtime: Option<TaskRuntimeInstance>,
71 #[serde(default)]
72 pub origin_call_id: Option<String>,
73 #[serde(default)]
74 pub summary: Option<String>,
75 #[serde(default)]
76 pub last_error: Option<String>,
77}
78
79#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct NewRunningTask {
84 pub title: String,
85 pub instructions: String,
86 pub runtime: TaskRuntimeInstance,
87 #[serde(default)]
88 pub requested_by: Option<String>,
89 #[serde(default)]
90 pub tags: Vec<String>,
91 #[serde(default)]
92 pub metadata: Option<Value>,
93 #[serde(default)]
94 pub origin_call_id: Option<String>,
95}
96
97#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99#[serde(rename_all = "camelCase")]
100pub struct TaskResult {
101 pub task_id: String,
102 pub completed_at_ms: u64,
103 #[serde(default)]
104 pub summary: Option<String>,
105 pub output: Value,
106}
107
108#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
110#[serde(rename_all = "camelCase")]
111pub struct TaskEvent {
112 pub sequence: u64,
113 pub recorded_at_ms: u64,
114 #[serde(flatten)]
115 pub kind: TaskEventKind,
116}
117
118#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
120#[serde(tag = "type", rename_all = "camelCase")]
121pub enum TaskEventKind {
122 Created,
123 Started {
124 runtime_instance_id: String,
125 pid: u32,
126 },
127 Progress {
128 message: String,
129 #[serde(default)]
130 details: Option<Value>,
131 },
132 Succeeded {
133 #[serde(default)]
134 summary: Option<String>,
135 },
136 Failed {
137 message: String,
138 },
139 Cancelled {
140 #[serde(default)]
141 reason: Option<String>,
142 },
143 Interrupted {
144 #[serde(default)]
145 runtime_instance_id: Option<String>,
146 #[serde(default)]
147 pid: Option<u32>,
148 reason: String,
149 },
150}
151
152#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct TaskDetail {
156 pub task: HarnessTask,
157 #[serde(default)]
158 pub result: Option<TaskResult>,
159 #[serde(default)]
160 pub events: Vec<TaskEvent>,
161}