starpod-session
Channel-aware session lifecycle management with usage tracking and message persistence.
API
rust
let mgr = SessionManager::new(&db_path, &sessions_dir).await?;
// Resolve or create a session
let decision = mgr.resolve_session(&Channel::Main, "session-key", None).await?;
match decision {
SessionDecision::Continue(id) => { /* use existing session */ }
SessionDecision::New { closed_session_id } => {
// closed_session_id is Some(id) when a previous session was auto-closed
let id = mgr.create_session(&Channel::Main, "session-key").await?;
}
}
// Session lifecycle
mgr.touch_session(&id).await?; // Update timestamp
mgr.set_title_if_empty(&id, "Title").await?; // Auto-title
mgr.close_session(&id, "summary").await?; // Close with summary
// Messages
mgr.save_message(&id, "user", "Hello").await?;
let messages = mgr.get_messages(&id).await?;
// Usage
mgr.record_usage(&id, &usage_record, turn).await?;
let summary = mgr.session_usage(&id).await?;
// Cost overview (with optional time filter)
let since = Some("2026-03-01T00:00:00Z");
let overview = mgr.cost_overview(since).await?;
// overview.total_cost_usd, overview.by_user, overview.by_model
// Compaction logging
mgr.record_compaction(&id, "auto", 150_000, "Summary text", 12).await?;
// Read state
mgr.mark_read(&id, false).await?; // Mark unread
mgr.mark_read(&id, true).await?; // Mark read
// Listing
let sessions = mgr.list_sessions(20).await?;
let session = mgr.get_session(&id).await?;Channel Enum
rust
pub enum Channel {
Main, // Explicit sessions (web, REPL, CLI)
Telegram, // Time-gap sessions (6h threshold)
}Session Resolution
- Main: Always continues if session exists with same key
- Telegram: Continues if last message within the gap threshold; otherwise auto-closes old session and returns
New { closed_session_id: Some(id) }
The Telegram inactivity threshold defaults to 6 hours (360 minutes) and is configurable via [channels.telegram] gap_minutes in agent.toml.
Session Export on Close
When a session is auto-closed, closed_session_id is returned so the caller (typically StarpodAgent) can export the transcript to memory. See Memory — Session Transcript Export.
Types
rust
pub struct SessionMeta {
pub id: String,
pub created_at: String,
pub last_message_at: String,
pub is_closed: bool,
pub summary: Option<String>,
pub title: Option<String>,
pub message_count: i64,
pub channel: String,
pub channel_session_key: Option<String>,
pub user_id: String,
pub is_read: bool,
}
pub struct UsageRecord {
pub input_tokens: u64,
pub output_tokens: u64,
pub cache_read: u64,
pub cache_write: u64,
pub cost_usd: f64,
pub model: String,
pub user_id: String,
}
pub struct UsageSummary {
pub total_input_tokens: u64,
pub total_output_tokens: u64,
pub total_cache_read: u64,
pub total_cache_write: u64,
pub total_cost_usd: f64,
pub total_turns: u32,
}
pub struct CostOverview {
pub total_cost_usd: f64,
pub total_input_tokens: u64,
pub total_output_tokens: u64,
pub total_turns: u32,
pub by_user: Vec<UserCostSummary>,
pub by_model: Vec<ModelCostSummary>,
}
pub struct UserCostSummary {
pub user_id: String,
pub total_cost_usd: f64,
pub total_input_tokens: u64,
pub total_output_tokens: u64,
pub total_turns: u32,
}
pub struct ModelCostSummary {
pub model: String,
pub total_cost_usd: f64,
pub total_input_tokens: u64,
pub total_output_tokens: u64,
pub total_turns: u32,
}Tests
26 unit tests covering channel resolution, time-gap auto-close, session isolation, usage tracking, cost overview (by user, by model, time filtering), compaction logging, closed session ID propagation, and read/unread state management.