1use crate::llm::{Message, TokenUsage, ToolDefinition};
2use crate::planning::Task;
3use crate::prompts::PlanningMode;
4use crate::queue::SessionQueueConfig;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
13pub enum SessionState {
14 #[default]
15 Unknown = 0,
16 Active = 1,
17 Paused = 2,
18 Completed = 3,
19 Error = 4,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct ContextUsage {
25 pub used_tokens: usize,
26 pub max_tokens: usize,
27 pub percent: f32,
28 pub turns: usize,
29}
30
31impl Default for ContextUsage {
32 fn default() -> Self {
33 Self {
34 used_tokens: 0,
35 max_tokens: 200_000,
36 percent: 0.0,
37 turns: 0,
38 }
39 }
40}
41
42pub const DEFAULT_AUTO_COMPACT_THRESHOLD: f32 = 0.80;
44
45pub(crate) fn default_auto_compact_threshold() -> f32 {
46 DEFAULT_AUTO_COMPACT_THRESHOLD
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct SessionConfig {
52 pub name: String,
53 pub workspace: String,
54 pub system_prompt: Option<String>,
55 pub max_context_length: u32,
56 pub auto_compact: bool,
57 #[serde(default = "default_auto_compact_threshold")]
60 pub auto_compact_threshold: f32,
61 #[serde(default)]
63 pub storage_type: crate::config::StorageBackend,
64 #[serde(skip_serializing_if = "Option::is_none")]
69 pub queue_config: Option<SessionQueueConfig>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub confirmation_policy: Option<crate::hitl::ConfirmationPolicy>,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub permission_policy: Option<crate::permissions::PermissionPolicy>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub parent_id: Option<String>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub security_config: Option<crate::security::SecurityConfig>,
82 #[serde(skip)]
84 pub hook_engine: Option<std::sync::Arc<dyn crate::hooks::HookExecutor>>,
85 #[serde(default)]
87 pub planning_mode: PlanningMode,
88 #[serde(default)]
90 pub goal_tracking: bool,
91}
92
93impl Default for SessionConfig {
94 fn default() -> Self {
95 Self {
96 name: String::new(),
97 workspace: String::new(),
98 system_prompt: None,
99 max_context_length: 0,
100 auto_compact: false,
101 auto_compact_threshold: DEFAULT_AUTO_COMPACT_THRESHOLD,
102 storage_type: crate::config::StorageBackend::default(),
103 queue_config: None,
104 confirmation_policy: None,
105 permission_policy: None,
106 parent_id: None,
107 security_config: None,
108 hook_engine: None,
109 planning_mode: PlanningMode::default(),
110 goal_tracking: false,
111 }
112 }
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct SessionData {
121 pub id: String,
123
124 pub config: SessionConfig,
126
127 pub state: SessionState,
129
130 pub messages: Vec<Message>,
132
133 pub context_usage: ContextUsage,
135
136 pub total_usage: TokenUsage,
138
139 #[serde(default)]
141 pub total_cost: f64,
142
143 #[serde(skip_serializing_if = "Option::is_none")]
145 pub model_name: Option<String>,
146
147 #[serde(default)]
149 pub cost_records: Vec<crate::telemetry::LlmCostRecord>,
150
151 pub tool_names: Vec<String>,
153
154 pub thinking_enabled: bool,
156
157 pub thinking_budget: Option<usize>,
159
160 pub created_at: i64,
162
163 pub updated_at: i64,
165
166 #[serde(skip_serializing_if = "Option::is_none")]
168 pub llm_config: Option<LlmConfigData>,
169
170 #[serde(default, alias = "todos")]
172 pub tasks: Vec<Task>,
173
174 #[serde(skip_serializing_if = "Option::is_none")]
176 pub parent_id: Option<String>,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct LlmConfigData {
182 pub provider: String,
183 pub model: String,
184 #[serde(skip_serializing, default)]
186 pub api_key: Option<String>,
187 pub base_url: Option<String>,
188}
189
190impl SessionData {
191 pub fn tool_names_from_definitions(tools: &[ToolDefinition]) -> Vec<String> {
193 tools.iter().map(|t| t.name.clone()).collect()
194 }
195}