1use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8
9use crate::capability_types::AgentCapabilityConfig;
10use crate::events::TokenUsage;
11use crate::mcp_server::{ScopedMcpServers, scoped_mcp_servers_is_empty};
12use crate::network_access::NetworkAccessList;
13use crate::principal::PrincipalSummary;
14use crate::tool_types::ToolDefinition;
15use crate::typed_id::{
16 AgentId, AgentIdentityId, AgentVersionId, HarnessId, ModelId, PrincipalId, SessionId,
17 WorkspaceId,
18};
19
20#[cfg(feature = "openapi")]
21use utoipa::ToSchema;
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
25#[cfg_attr(feature = "openapi", derive(ToSchema))]
26#[serde(rename_all = "snake_case")]
27pub enum SubagentStatus {
28 Spawning,
29 Running,
30 Completed,
31 Failed,
32 Cancelled,
33 MaxIterationsReached,
34 Sealed,
40}
41
42impl std::fmt::Display for SubagentStatus {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match self {
45 SubagentStatus::Spawning => write!(f, "spawning"),
46 SubagentStatus::Running => write!(f, "running"),
47 SubagentStatus::Completed => write!(f, "completed"),
48 SubagentStatus::Failed => write!(f, "failed"),
49 SubagentStatus::Cancelled => write!(f, "cancelled"),
50 SubagentStatus::MaxIterationsReached => write!(f, "max_iterations_reached"),
51 SubagentStatus::Sealed => write!(f, "sealed"),
52 }
53 }
54}
55
56impl From<&str> for SubagentStatus {
57 fn from(s: &str) -> Self {
58 match s {
59 "spawning" => SubagentStatus::Spawning,
60 "running" => SubagentStatus::Running,
61 "completed" => SubagentStatus::Completed,
62 "failed" => SubagentStatus::Failed,
63 "cancelled" => SubagentStatus::Cancelled,
64 "max_iterations_reached" => SubagentStatus::MaxIterationsReached,
65 "sealed" => SubagentStatus::Sealed,
66 _ => SubagentStatus::Spawning,
67 }
68 }
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
77#[cfg_attr(feature = "openapi", derive(ToSchema))]
78#[serde(rename_all = "lowercase")]
79pub enum SessionStatus {
80 Started,
82 Active,
84 Idle,
86 WaitingForToolResults,
88 Paused,
90}
91
92impl std::fmt::Display for SessionStatus {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 match self {
95 SessionStatus::Started => write!(f, "started"),
96 SessionStatus::Active => write!(f, "active"),
97 SessionStatus::Idle => write!(f, "idle"),
98 SessionStatus::WaitingForToolResults => write!(f, "waiting_for_tool_results"),
99 SessionStatus::Paused => write!(f, "paused"),
100 }
101 }
102}
103
104impl From<&str> for SessionStatus {
105 fn from(s: &str) -> Self {
106 match s {
107 "active" => SessionStatus::Active,
108 "idle" => SessionStatus::Idle,
109 "waiting_for_tool_results" => SessionStatus::WaitingForToolResults,
110 "paused" => SessionStatus::Paused,
111 "running" => SessionStatus::Active,
113 "pending" | "completed" | "failed" => SessionStatus::Idle,
114 _ => SessionStatus::Started,
115 }
116 }
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
122#[cfg_attr(feature = "openapi", derive(ToSchema))]
123pub struct Session {
124 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "session_01933b5a00007000800000000000001"))]
126 pub id: SessionId,
127 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "org_00000000000000000000000000000001"))]
129 pub organization_id: String,
130 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "wsp_01933b5a00007000800000000000001"))]
134 pub workspace_id: WorkspaceId,
135 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "harness_01933b5a00007000800000000000001"))]
137 pub harness_id: HarnessId,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "agent_01933b5a00007000800000000000001"))]
141 pub agent_id: Option<AgentId>,
142 #[serde(skip_serializing_if = "Option::is_none")]
144 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "agentver_01933b5a00007000800000000000001"))]
145 pub agent_version_id: Option<AgentVersionId>,
146 #[serde(skip_serializing_if = "Option::is_none")]
148 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "identity_01933b5a00007000800000000000001"))]
149 pub agent_identity_id: Option<AgentIdentityId>,
150 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "principal_01933b5a000070008000000000000001"))]
152 pub owner_principal_id: PrincipalId,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 #[cfg_attr(
156 feature = "openapi",
157 schema(example = "550e8400-e29b-41d4-a716-446655440000")
158 )]
159 pub resolved_owner_user_id: Option<uuid::Uuid>,
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub owner: Option<PrincipalSummary>,
163 #[serde(skip_serializing_if = "Option::is_none")]
165 pub effective_owner: Option<PrincipalSummary>,
166 #[serde(skip_serializing_if = "Option::is_none")]
168 #[cfg_attr(feature = "openapi", schema(example = "Q3 marketing brief"))]
169 pub title: Option<String>,
170 #[serde(skip_serializing_if = "Option::is_none")]
172 #[cfg_attr(feature = "openapi", schema(example = "en-US"))]
173 pub locale: Option<String>,
174 #[serde(skip_serializing_if = "Option::is_none")]
176 #[cfg_attr(
177 feature = "openapi",
178 schema(example = "Help me draft the Q3 marketing plan")
179 )]
180 pub preview: Option<String>,
181 #[serde(skip_serializing_if = "Option::is_none")]
183 #[cfg_attr(
184 feature = "openapi",
185 schema(example = "Here is a Q3 plan covering the three pillars we discussed...")
186 )]
187 pub output_preview: Option<String>,
188 #[serde(default)]
190 #[cfg_attr(feature = "openapi", schema(example = json!(["marketing", "q3", "draft"])))]
191 pub tags: Vec<String>,
192 #[serde(skip_serializing_if = "Option::is_none")]
195 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "model_01933b5a00007000800000000000001"))]
196 pub model_id: Option<ModelId>,
197 #[serde(default, skip_serializing_if = "Vec::is_empty")]
200 pub capabilities: Vec<AgentCapabilityConfig>,
201 #[serde(default, skip_serializing_if = "Vec::is_empty")]
203 pub tools: Vec<ToolDefinition>,
204 #[serde(
206 default,
207 rename = "mcpServers",
208 alias = "mcp_servers",
209 skip_serializing_if = "scoped_mcp_servers_is_empty"
210 )]
211 pub mcp_servers: ScopedMcpServers,
212 #[serde(default, skip_serializing_if = "Option::is_none")]
215 pub system_prompt: Option<String>,
216 #[serde(default, skip_serializing_if = "Vec::is_empty")]
219 pub initial_files: Vec<crate::session_file::InitialFile>,
220 #[serde(default, skip_serializing_if = "Option::is_none")]
226 pub hints: Option<std::collections::HashMap<String, serde_json::Value>>,
227 #[serde(default, skip_serializing_if = "Option::is_none")]
230 pub network_access: Option<NetworkAccessList>,
231 #[serde(default, skip_serializing_if = "Option::is_none")]
233 #[cfg_attr(feature = "openapi", schema(example = 50))]
234 pub max_iterations: Option<usize>,
235 #[serde(default, skip_serializing_if = "Option::is_none")]
242 #[cfg_attr(feature = "openapi", schema(example = true))]
243 pub parallel_tool_calls: Option<bool>,
244 pub status: SessionStatus,
246 #[cfg_attr(feature = "openapi", schema(example = "2026-05-25T10:00:00Z"))]
248 pub created_at: DateTime<Utc>,
249 #[cfg_attr(feature = "openapi", schema(example = "2026-05-25T10:14:32Z"))]
251 pub updated_at: DateTime<Utc>,
252 #[serde(skip_serializing_if = "Option::is_none")]
254 #[cfg_attr(feature = "openapi", schema(example = "2026-05-25T10:00:01Z"))]
255 pub started_at: Option<DateTime<Utc>>,
256 #[serde(skip_serializing_if = "Option::is_none")]
258 #[cfg_attr(feature = "openapi", schema(example = "2026-05-25T10:14:32Z"))]
259 pub finished_at: Option<DateTime<Utc>>,
260 #[serde(skip_serializing_if = "Option::is_none")]
262 pub usage: Option<TokenUsage>,
263 #[serde(skip_serializing_if = "Option::is_none")]
266 #[cfg_attr(feature = "openapi", schema(example = false))]
267 pub is_pinned: Option<bool>,
268 #[serde(skip_serializing_if = "Option::is_none")]
271 #[cfg_attr(feature = "openapi", schema(example = 2))]
272 pub active_schedule_count: Option<u32>,
273 #[serde(default, skip_serializing_if = "Vec::is_empty")]
278 #[cfg_attr(feature = "openapi", schema(example = json!(["file_system", "secrets"])))]
279 pub features: Vec<String>,
280
281 #[serde(skip_serializing_if = "Option::is_none")]
285 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>))]
286 pub parent_session_id: Option<SessionId>,
287
288 #[serde(default, skip_serializing_if = "Option::is_none")]
293 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>))]
294 pub forked_from_session_id: Option<SessionId>,
295 #[serde(default, skip_serializing_if = "Option::is_none")]
298 #[cfg_attr(feature = "openapi", schema(example = 42))]
299 pub forked_from_sequence: Option<i32>,
300
301 #[serde(skip_serializing_if = "Option::is_none")]
305 #[cfg_attr(feature = "openapi", schema(example = "blueprint_research_pack"))]
306 pub blueprint_id: Option<String>,
307 #[serde(skip_serializing_if = "Option::is_none")]
310 #[cfg_attr(feature = "openapi", schema(value_type = Option<Object>))]
311 pub blueprint_config: Option<serde_json::Value>,
312}