Skip to main content

a3s_code_core/store/
session_data.rs

1use crate::llm::{Message, TokenUsage, ToolDefinition};
2use crate::planning::Task;
3use crate::prompts::PlanningMode;
4use crate::queue::SessionQueueConfig;
5use serde::{Deserialize, Serialize};
6
7// ============================================================================
8// Serializable Session Data
9// ============================================================================
10
11/// Session state persisted with saved sessions.
12#[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/// Context usage statistics persisted with saved sessions.
23#[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
42/// Default auto-compact threshold (80% of context window).
43pub 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/// Serializable session configuration.
50#[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    /// Context usage percentage threshold to trigger auto-compaction (0.0 - 1.0).
58    /// Only used when `auto_compact` is true. Default: 0.80 (80%).
59    #[serde(default = "default_auto_compact_threshold")]
60    pub auto_compact_threshold: f32,
61    /// Storage type for this session.
62    #[serde(default)]
63    pub storage_type: crate::config::StorageBackend,
64    /// Optional advanced queue configuration.
65    ///
66    /// Queue infrastructure is initialized only when this is set. Ordinary
67    /// sessions stay queue-free.
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub queue_config: Option<SessionQueueConfig>,
70    /// Confirmation policy (optional, uses defaults if None).
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub confirmation_policy: Option<crate::hitl::ConfirmationPolicy>,
73    /// Permission policy (optional, uses defaults if None).
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub permission_policy: Option<crate::permissions::PermissionPolicy>,
76    /// Parent session ID (for delegated child sessions).
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub parent_id: Option<String>,
79    /// Security configuration (optional, enables security features).
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub security_config: Option<crate::security::SecurityConfig>,
82    /// Shared hook engine for lifecycle events.
83    #[serde(skip)]
84    pub hook_engine: Option<std::sync::Arc<dyn crate::hooks::HookExecutor>>,
85    /// Enable planning phase before execution.
86    #[serde(default)]
87    pub planning_mode: PlanningMode,
88    /// Enable goal tracking.
89    #[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/// Serializable session data for persistence
116///
117/// Contains only the fields that can be serialized.
118/// Non-serializable fields (event_tx, command_queue, etc.) are rebuilt on load.
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub struct SessionData {
121    /// Session ID
122    pub id: String,
123
124    /// Session configuration
125    pub config: SessionConfig,
126
127    /// Current state
128    pub state: SessionState,
129
130    /// Conversation history
131    pub messages: Vec<Message>,
132
133    /// Context usage statistics
134    pub context_usage: ContextUsage,
135
136    /// Total token usage
137    pub total_usage: TokenUsage,
138
139    /// Cumulative dollar cost for this session
140    #[serde(default)]
141    pub total_cost: f64,
142
143    /// Model name for cost calculation
144    #[serde(skip_serializing_if = "Option::is_none")]
145    pub model_name: Option<String>,
146
147    /// LLM cost records for this session
148    #[serde(default)]
149    pub cost_records: Vec<crate::telemetry::LlmCostRecord>,
150
151    /// Tool definitions (names only, rebuilt from executor on load)
152    pub tool_names: Vec<String>,
153
154    /// Whether thinking mode is enabled
155    pub thinking_enabled: bool,
156
157    /// Thinking budget if set
158    pub thinking_budget: Option<usize>,
159
160    /// Creation timestamp (Unix epoch seconds)
161    pub created_at: i64,
162
163    /// Last update timestamp (Unix epoch seconds)
164    pub updated_at: i64,
165
166    /// LLM configuration for per-session client (if set)
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub llm_config: Option<LlmConfigData>,
169
170    /// Task list for tracking
171    #[serde(default, alias = "todos")]
172    pub tasks: Vec<Task>,
173
174    /// Parent session ID (for delegated child sessions)
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub parent_id: Option<String>,
177}
178
179/// Serializable LLM configuration
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct LlmConfigData {
182    pub provider: String,
183    pub model: String,
184    /// API key is NOT stored - must be provided on session resume
185    #[serde(skip_serializing, default)]
186    pub api_key: Option<String>,
187    pub base_url: Option<String>,
188}
189
190impl SessionData {
191    /// Extract tool names from definitions
192    pub fn tool_names_from_definitions(tools: &[ToolDefinition]) -> Vec<String> {
193        tools.iter().map(|t| t.name.clone()).collect()
194    }
195}