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}
35
36impl std::fmt::Display for SubagentStatus {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 match self {
39 SubagentStatus::Spawning => write!(f, "spawning"),
40 SubagentStatus::Running => write!(f, "running"),
41 SubagentStatus::Completed => write!(f, "completed"),
42 SubagentStatus::Failed => write!(f, "failed"),
43 SubagentStatus::Cancelled => write!(f, "cancelled"),
44 SubagentStatus::MaxIterationsReached => write!(f, "max_iterations_reached"),
45 }
46 }
47}
48
49impl From<&str> for SubagentStatus {
50 fn from(s: &str) -> Self {
51 match s {
52 "spawning" => SubagentStatus::Spawning,
53 "running" => SubagentStatus::Running,
54 "completed" => SubagentStatus::Completed,
55 "failed" => SubagentStatus::Failed,
56 "cancelled" => SubagentStatus::Cancelled,
57 "max_iterations_reached" => SubagentStatus::MaxIterationsReached,
58 _ => SubagentStatus::Spawning,
59 }
60 }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
69#[cfg_attr(feature = "openapi", derive(ToSchema))]
70#[serde(rename_all = "lowercase")]
71pub enum SessionStatus {
72 Started,
74 Active,
76 Idle,
78 WaitingForToolResults,
80 Paused,
82}
83
84impl std::fmt::Display for SessionStatus {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 match self {
87 SessionStatus::Started => write!(f, "started"),
88 SessionStatus::Active => write!(f, "active"),
89 SessionStatus::Idle => write!(f, "idle"),
90 SessionStatus::WaitingForToolResults => write!(f, "waiting_for_tool_results"),
91 SessionStatus::Paused => write!(f, "paused"),
92 }
93 }
94}
95
96impl From<&str> for SessionStatus {
97 fn from(s: &str) -> Self {
98 match s {
99 "active" => SessionStatus::Active,
100 "idle" => SessionStatus::Idle,
101 "waiting_for_tool_results" => SessionStatus::WaitingForToolResults,
102 "paused" => SessionStatus::Paused,
103 "running" => SessionStatus::Active,
105 "pending" | "completed" | "failed" => SessionStatus::Idle,
106 _ => SessionStatus::Started,
107 }
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
114#[cfg_attr(feature = "openapi", derive(ToSchema))]
115pub struct Session {
116 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "session_01933b5a00007000800000000000001"))]
118 pub id: SessionId,
119 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "org_00000000000000000000000000000001"))]
121 pub organization_id: String,
122 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "wsp_01933b5a00007000800000000000001"))]
126 pub workspace_id: WorkspaceId,
127 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "harness_01933b5a00007000800000000000001"))]
129 pub harness_id: HarnessId,
130 #[serde(skip_serializing_if = "Option::is_none")]
132 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "agent_01933b5a00007000800000000000001"))]
133 pub agent_id: Option<AgentId>,
134 #[serde(skip_serializing_if = "Option::is_none")]
136 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "agentver_01933b5a00007000800000000000001"))]
137 pub agent_version_id: Option<AgentVersionId>,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "identity_01933b5a00007000800000000000001"))]
141 pub agent_identity_id: Option<AgentIdentityId>,
142 #[cfg_attr(feature = "openapi", schema(value_type = String, example = "principal_01933b5a000070008000000000000001"))]
144 pub owner_principal_id: PrincipalId,
145 #[serde(skip_serializing_if = "Option::is_none")]
147 #[cfg_attr(
148 feature = "openapi",
149 schema(example = "550e8400-e29b-41d4-a716-446655440000")
150 )]
151 pub resolved_owner_user_id: Option<uuid::Uuid>,
152 #[serde(skip_serializing_if = "Option::is_none")]
154 pub owner: Option<PrincipalSummary>,
155 #[serde(skip_serializing_if = "Option::is_none")]
157 pub effective_owner: Option<PrincipalSummary>,
158 #[serde(skip_serializing_if = "Option::is_none")]
160 #[cfg_attr(feature = "openapi", schema(example = "Q3 marketing brief"))]
161 pub title: Option<String>,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 #[cfg_attr(feature = "openapi", schema(example = "en-US"))]
165 pub locale: Option<String>,
166 #[serde(skip_serializing_if = "Option::is_none")]
168 #[cfg_attr(
169 feature = "openapi",
170 schema(example = "Help me draft the Q3 marketing plan")
171 )]
172 pub preview: Option<String>,
173 #[serde(skip_serializing_if = "Option::is_none")]
175 #[cfg_attr(
176 feature = "openapi",
177 schema(example = "Here is a Q3 plan covering the three pillars we discussed...")
178 )]
179 pub output_preview: Option<String>,
180 #[serde(default)]
182 #[cfg_attr(feature = "openapi", schema(example = json!(["marketing", "q3", "draft"])))]
183 pub tags: Vec<String>,
184 #[serde(skip_serializing_if = "Option::is_none")]
187 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "model_01933b5a00007000800000000000001"))]
188 pub model_id: Option<ModelId>,
189 #[serde(default, skip_serializing_if = "Vec::is_empty")]
192 pub capabilities: Vec<AgentCapabilityConfig>,
193 #[serde(default, skip_serializing_if = "Vec::is_empty")]
195 pub tools: Vec<ToolDefinition>,
196 #[serde(
198 default,
199 rename = "mcpServers",
200 alias = "mcp_servers",
201 skip_serializing_if = "scoped_mcp_servers_is_empty"
202 )]
203 pub mcp_servers: ScopedMcpServers,
204 #[serde(default, skip_serializing_if = "Option::is_none")]
207 pub system_prompt: Option<String>,
208 #[serde(default, skip_serializing_if = "Vec::is_empty")]
211 pub initial_files: Vec<crate::session_file::InitialFile>,
212 #[serde(default, skip_serializing_if = "Option::is_none")]
218 pub hints: Option<std::collections::HashMap<String, serde_json::Value>>,
219 #[serde(default, skip_serializing_if = "Option::is_none")]
222 pub network_access: Option<NetworkAccessList>,
223 #[serde(default, skip_serializing_if = "Option::is_none")]
225 #[cfg_attr(feature = "openapi", schema(example = 50))]
226 pub max_iterations: Option<usize>,
227 #[serde(default, skip_serializing_if = "Option::is_none")]
234 #[cfg_attr(feature = "openapi", schema(example = true))]
235 pub parallel_tool_calls: Option<bool>,
236 pub status: SessionStatus,
238 #[cfg_attr(feature = "openapi", schema(example = "2026-05-25T10:00:00Z"))]
240 pub created_at: DateTime<Utc>,
241 #[cfg_attr(feature = "openapi", schema(example = "2026-05-25T10:14:32Z"))]
243 pub updated_at: DateTime<Utc>,
244 #[serde(skip_serializing_if = "Option::is_none")]
246 #[cfg_attr(feature = "openapi", schema(example = "2026-05-25T10:00:01Z"))]
247 pub started_at: Option<DateTime<Utc>>,
248 #[serde(skip_serializing_if = "Option::is_none")]
250 #[cfg_attr(feature = "openapi", schema(example = "2026-05-25T10:14:32Z"))]
251 pub finished_at: Option<DateTime<Utc>>,
252 #[serde(skip_serializing_if = "Option::is_none")]
254 pub usage: Option<TokenUsage>,
255 #[serde(skip_serializing_if = "Option::is_none")]
258 #[cfg_attr(feature = "openapi", schema(example = false))]
259 pub is_pinned: Option<bool>,
260 #[serde(skip_serializing_if = "Option::is_none")]
263 #[cfg_attr(feature = "openapi", schema(example = 2))]
264 pub active_schedule_count: Option<u32>,
265 #[serde(default, skip_serializing_if = "Vec::is_empty")]
270 #[cfg_attr(feature = "openapi", schema(example = json!(["file_system", "secrets"])))]
271 pub features: Vec<String>,
272
273 #[serde(skip_serializing_if = "Option::is_none")]
277 #[cfg_attr(feature = "openapi", schema(value_type = Option<String>))]
278 pub parent_session_id: Option<SessionId>,
279
280 #[serde(skip_serializing_if = "Option::is_none")]
284 #[cfg_attr(feature = "openapi", schema(example = "blueprint_research_pack"))]
285 pub blueprint_id: Option<String>,
286 #[serde(skip_serializing_if = "Option::is_none")]
289 #[cfg_attr(feature = "openapi", schema(value_type = Option<Object>))]
290 pub blueprint_config: Option<serde_json::Value>,
291}