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 kind: WorkflowKind,
68 pub harness: Option<HarnessId>,
70 pub terminal_id: TerminalId,
73 pub agents: Vec<Agent>,
75 pub status: WorkflowStatus,
76 pub started_at: u64,
77 pub ended_at: Option<u64>,
78 pub restored: bool,
80 pub terminal_history: Vec<WorkflowTerminal>,
82 pub run: Option<Box<crate::WorkflowRun>>,
84}
85
86#[derive(Clone, Debug, Eq, PartialEq)]
87pub struct WorkflowTerminal {
88 pub terminal_id: TerminalId,
89 pub agent_id: Option<AgentId>,
90}
91
92#[derive(Clone, Debug, Eq, PartialEq)]
94pub struct Agent {
95 pub agent_id: AgentId,
96 pub role: String,
97 pub terminal_id: TerminalId,
99}
100
101impl Workflow {
102 pub(crate) fn shells(&self) -> Vec<TerminalId> {
105 match self.kind {
106 WorkflowKind::Draft | WorkflowKind::Terminal | WorkflowKind::SingleAgent => {
107 vec![self.terminal_id]
108 }
109 WorkflowKind::Agents => self.agents.iter().map(|agent| agent.terminal_id).collect(),
110 }
111 }
112
113 pub(crate) fn terminal_ids(&self) -> Vec<TerminalId> {
115 self.shells()
116 .into_iter()
117 .filter(|terminal_id| terminal_id.value() != 0)
118 .filter(|id| {
119 !self.restored
120 || !(self.kind == WorkflowKind::SingleAgent || self.run.is_some())
121 || !self
122 .terminal_history
123 .iter()
124 .any(|entry| entry.terminal_id == *id)
125 })
126 .collect()
127 }
128}
129
130#[derive(Clone, Debug, Default, Eq, PartialEq)]
131pub struct WorkflowState {
132 pub sessions_initialized: bool,
134 pub session: Option<Session>,
136 pub sessions: Vec<Session>,
137 pub workflows: Vec<Workflow>,
139}
140
141pub(crate) fn valid_name(name: &str) -> bool {
143 !name.is_empty() && name.chars().count() <= 200 && !name.chars().any(char::is_control)
144}
145
146pub(crate) fn timestamp() -> u64 {
147 u64::try_from(
148 SystemTime::now()
149 .duration_since(UNIX_EPOCH)
150 .unwrap_or_default()
151 .as_millis(),
152 )
153 .unwrap_or(u64::MAX)
154}