use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::capability_types::AgentCapabilityConfig;
use crate::events::TokenUsage;
use crate::mcp_server::{ScopedMcpServers, scoped_mcp_servers_is_empty};
use crate::network_access::NetworkAccessList;
use crate::principal::PrincipalSummary;
use crate::tool_types::ToolDefinition;
use crate::typed_id::{
AgentId, AgentIdentityId, AgentVersionId, HarnessId, ModelId, PrincipalId, SessionId,
};
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "snake_case")]
pub enum SubagentStatus {
Spawning,
Running,
Completed,
Failed,
Cancelled,
MaxIterationsReached,
}
impl std::fmt::Display for SubagentStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SubagentStatus::Spawning => write!(f, "spawning"),
SubagentStatus::Running => write!(f, "running"),
SubagentStatus::Completed => write!(f, "completed"),
SubagentStatus::Failed => write!(f, "failed"),
SubagentStatus::Cancelled => write!(f, "cancelled"),
SubagentStatus::MaxIterationsReached => write!(f, "max_iterations_reached"),
}
}
}
impl From<&str> for SubagentStatus {
fn from(s: &str) -> Self {
match s {
"spawning" => SubagentStatus::Spawning,
"running" => SubagentStatus::Running,
"completed" => SubagentStatus::Completed,
"failed" => SubagentStatus::Failed,
"cancelled" => SubagentStatus::Cancelled,
"max_iterations_reached" => SubagentStatus::MaxIterationsReached,
_ => SubagentStatus::Spawning,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "lowercase")]
pub enum SessionStatus {
Started,
Active,
Idle,
WaitingForToolResults,
Paused,
}
impl std::fmt::Display for SessionStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SessionStatus::Started => write!(f, "started"),
SessionStatus::Active => write!(f, "active"),
SessionStatus::Idle => write!(f, "idle"),
SessionStatus::WaitingForToolResults => write!(f, "waiting_for_tool_results"),
SessionStatus::Paused => write!(f, "paused"),
}
}
}
impl From<&str> for SessionStatus {
fn from(s: &str) -> Self {
match s {
"active" => SessionStatus::Active,
"idle" => SessionStatus::Idle,
"waiting_for_tool_results" => SessionStatus::WaitingForToolResults,
"paused" => SessionStatus::Paused,
"running" => SessionStatus::Active,
"pending" | "completed" | "failed" => SessionStatus::Idle,
_ => SessionStatus::Started,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct Session {
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "session_01933b5a00007000800000000000001"))]
pub id: SessionId,
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "org_00000000000000000000000000000001"))]
pub organization_id: String,
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "harness_01933b5a00007000800000000000001"))]
pub harness_id: HarnessId,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "agent_01933b5a00007000800000000000001"))]
pub agent_id: Option<AgentId>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "agentver_01933b5a00007000800000000000001"))]
pub agent_version_id: Option<AgentVersionId>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "identity_01933b5a00007000800000000000001"))]
pub agent_identity_id: Option<AgentIdentityId>,
#[cfg_attr(feature = "openapi", schema(value_type = String, example = "principal_01933b5a000070008000000000000001"))]
pub owner_principal_id: PrincipalId,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolved_owner_user_id: Option<uuid::Uuid>,
#[serde(skip_serializing_if = "Option::is_none")]
pub owner: Option<PrincipalSummary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub effective_owner: Option<PrincipalSummary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub locale: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preview: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output_preview: Option<String>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "openapi", schema(value_type = Option<String>, example = "model_01933b5a00007000800000000000001"))]
pub model_id: Option<ModelId>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub capabilities: Vec<AgentCapabilityConfig>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tools: Vec<ToolDefinition>,
#[serde(
default,
rename = "mcpServers",
alias = "mcp_servers",
skip_serializing_if = "scoped_mcp_servers_is_empty"
)]
pub mcp_servers: ScopedMcpServers,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub system_prompt: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub initial_files: Vec<crate::session_file::InitialFile>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub hints: Option<std::collections::HashMap<String, serde_json::Value>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub network_access: Option<NetworkAccessList>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max_iterations: Option<usize>,
pub status: SessionStatus,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
pub started_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub finished_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage: Option<TokenUsage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_pinned: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub active_schedule_count: Option<u32>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub features: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "openapi", schema(value_type = Option<String>))]
pub parent_session_id: Option<SessionId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subagent_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subagent_task: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subagent_status: Option<SubagentStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub blueprint_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub blueprint_config: Option<serde_json::Value>,
}