Skip to main content

claude_agent/session/
mod.rs

1//! Session management for stateful conversations.
2
3pub mod compact;
4pub mod manager;
5pub mod persistence;
6#[cfg(feature = "jsonl")]
7pub mod persistence_jsonl;
8#[cfg(feature = "postgres")]
9pub mod persistence_postgres;
10#[cfg(feature = "redis-backend")]
11pub mod persistence_redis;
12pub mod queue;
13pub mod session_state;
14pub mod state;
15pub mod types;
16
17pub use crate::types::TokenUsage;
18pub use compact::{CompactExecutor, CompactStrategy};
19pub use manager::SessionManager;
20pub use persistence::{MemoryPersistence, Persistence, PersistenceFactory};
21#[cfg(feature = "jsonl")]
22pub use persistence_jsonl::{
23    JsonlConfig, JsonlConfigBuilder, JsonlEntry, JsonlPersistence, SyncMode,
24};
25#[cfg(feature = "postgres")]
26pub use persistence_postgres::{
27    PgPoolConfig, PostgresConfig, PostgresPersistence, PostgresSchema, SchemaIssue,
28};
29#[cfg(feature = "redis-backend")]
30pub use persistence_redis::{RedisConfig, RedisPersistence};
31pub use queue::{InputQueue, MergedInput, QueueError, QueuedInput, SharedInputQueue};
32pub use session_state::{ExecutionGuard, ToolState};
33pub use state::{
34    MessageId, MessageMetadata, PermissionPolicy, Session, SessionConfig, SessionId,
35    SessionMessage, SessionMode, SessionState, SessionType,
36};
37pub use types::{
38    CompactRecord, CompactTrigger, EnvironmentContext, Plan, PlanStatus, QueueItem, QueueOperation,
39    QueueStatus, SessionStats, SessionTree, SummarySnapshot, TodoItem, TodoStatus, ToolExecution,
40};
41
42use thiserror::Error;
43
44#[derive(Error, Debug)]
45pub enum SessionError {
46    #[error("Session not found: {id}")]
47    NotFound { id: String },
48
49    #[error("Session expired: {id}")]
50    Expired { id: String },
51
52    #[error("Permission denied: {reason}")]
53    PermissionDenied { reason: String },
54
55    #[error("Storage error: {message}")]
56    Storage { message: String },
57
58    #[error("Serialization error: {0}")]
59    Serialization(#[from] serde_json::Error),
60
61    #[error("Compact error: {message}")]
62    Compact { message: String },
63
64    #[error("Context error: {0}")]
65    Context(#[from] crate::context::ContextError),
66
67    #[error("Plan error: {message}")]
68    Plan { message: String },
69}
70
71pub type SessionResult<T> = std::result::Result<T, SessionError>;
72
73/// Extension trait for converting errors to SessionError::Storage.
74pub trait StorageResultExt<T> {
75    fn storage_err(self) -> SessionResult<T>;
76    fn storage_err_ctx(self, context: &str) -> SessionResult<T>;
77}
78
79impl<T, E: std::fmt::Display> StorageResultExt<T> for std::result::Result<T, E> {
80    fn storage_err(self) -> SessionResult<T> {
81        self.map_err(|e| SessionError::Storage {
82            message: e.to_string(),
83        })
84    }
85
86    fn storage_err_ctx(self, context: &str) -> SessionResult<T> {
87        self.map_err(|e| SessionError::Storage {
88            message: format!("{}: {}", context, e),
89        })
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_session_error_display() {
99        let err = SessionError::NotFound {
100            id: "test-123".to_string(),
101        };
102        assert!(err.to_string().contains("test-123"));
103    }
104
105    #[test]
106    fn test_session_error_expired() {
107        let err = SessionError::Expired {
108            id: "sess-456".to_string(),
109        };
110        assert!(err.to_string().contains("expired"));
111    }
112}