1use std::path::PathBuf;
4use std::time::{SystemTime, UNIX_EPOCH};
5
6use crate::harness::HarnessId;
7use crate::terminal::TerminalId;
8
9#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
10pub struct SessionId(pub u64);
11
12#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
13pub struct WorkflowId(pub u64);
14
15#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
16pub struct AgentId(pub u64);
17
18pub(crate) const MAX_AGENTS: usize = crate::workflow_type::MAX_PARALLEL_AGENTS as usize;
21
22#[derive(Clone, Copy, Debug, Eq, PartialEq)]
23pub enum WorkflowKind {
24 Draft,
25 Terminal,
26 SingleAgent,
27 Agents,
30}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub enum WorkflowStatus {
34 Running,
35 Completed,
36 Exited,
37 Failed,
38 Cancelled,
40 Interrupted,
42 Closed,
43}
44
45#[derive(Clone, Copy, Debug, Eq, PartialEq)]
46pub enum SessionStatus {
47 Active,
48 Closed,
49}
50
51#[derive(Clone, Debug, Eq, PartialEq)]
52pub struct Session {
53 pub session_id: SessionId,
54 pub name: String,
55 pub folder: PathBuf,
56 pub status: SessionStatus,
57 pub started_at: u64,
59 pub ended_at: Option<u64>,
60}
61
62#[derive(Clone, Debug, Eq, PartialEq)]
63pub struct Workflow {
64 pub workflow_id: WorkflowId,
65 pub session_id: SessionId,
66 pub name: String,
67 pub custom_name: Option<String>,
69 pub archived: bool,
71 pub kind: WorkflowKind,
72 pub harness: Option<HarnessId>,
74 pub terminal_id: TerminalId,
77 pub agents: Vec<Agent>,
79 pub status: WorkflowStatus,
80 pub started_at: u64,
81 pub ended_at: Option<u64>,
82 pub restored: bool,
84 pub terminal_history: Vec<WorkflowTerminal>,
86 pub run: Option<Box<crate::WorkflowRun>>,
88}
89
90#[derive(Clone, Debug, Eq, PartialEq)]
91pub struct WorkflowTerminal {
92 pub terminal_id: TerminalId,
93 pub agent_id: Option<AgentId>,
94}
95
96#[derive(Clone, Debug, Eq, PartialEq)]
98pub struct Agent {
99 pub agent_id: AgentId,
100 pub role: String,
101 pub terminal_id: TerminalId,
103}
104
105impl Workflow {
106 pub(crate) fn shells(&self) -> Vec<TerminalId> {
109 match self.kind {
110 WorkflowKind::Draft | WorkflowKind::Terminal | WorkflowKind::SingleAgent => {
111 vec![self.terminal_id]
112 }
113 WorkflowKind::Agents => self.agents.iter().map(|agent| agent.terminal_id).collect(),
114 }
115 }
116
117 pub(crate) fn terminal_ids(&self) -> Vec<TerminalId> {
119 if self.archived {
120 return Vec::new();
121 }
122 self.shells()
123 .into_iter()
124 .filter(|terminal_id| terminal_id.value() != 0)
125 .filter(|id| {
126 !self.restored
127 || !(self.kind == WorkflowKind::SingleAgent || self.run.is_some())
128 || !self
129 .terminal_history
130 .iter()
131 .any(|entry| entry.terminal_id == *id)
132 })
133 .collect()
134 }
135}
136
137#[derive(Clone, Debug, Default, Eq, PartialEq)]
138pub struct WorkflowState {
139 pub sessions_initialized: bool,
141 pub session: Option<Session>,
143 pub sessions: Vec<Session>,
144 pub workflows: Vec<Workflow>,
146}
147
148pub(crate) fn valid_name(name: &str) -> bool {
150 !name.is_empty() && name.chars().count() <= 200 && !name.chars().any(char::is_control)
151}
152
153pub(crate) fn timestamp() -> u64 {
154 u64::try_from(
155 SystemTime::now()
156 .duration_since(UNIX_EPOCH)
157 .unwrap_or_default()
158 .as_millis(),
159 )
160 .unwrap_or(u64::MAX)
161}