Add session persistence and browser functionality
Some checks failed
Release / Build aarch64-unknown-linux-gnu (push) Has been cancelled
Release / Build aarch64-unknown-linux-musl (push) Has been cancelled
Release / Build armv7-unknown-linux-gnueabihf (push) Has been cancelled
Release / Build armv7-unknown-linux-musleabihf (push) Has been cancelled
Release / Build x86_64-unknown-linux-gnu (push) Has been cancelled
Release / Build x86_64-unknown-linux-musl (push) Has been cancelled
Release / Build aarch64-apple-darwin (push) Has been cancelled
Release / Build x86_64-apple-darwin (push) Has been cancelled
Release / Build aarch64-pc-windows-msvc (push) Has been cancelled
Release / Build x86_64-pc-windows-msvc (push) Has been cancelled
Release / Create Release (push) Has been cancelled

- Implement `StorageManager` for saving, loading, and managing sessions.
- Introduce platform-specific session directories for persistence.
- Add session browser UI for listing, loading, and deleting saved sessions.
- Enable AI-generated descriptions for session summaries.
- Update configurations to support storage settings and description generation.
- Extend README and tests to document and validate new functionality.
This commit is contained in:
2025-10-02 01:33:49 +02:00
parent 1ad6cb8b3f
commit 6b8774f0aa
12 changed files with 818 additions and 26 deletions

View File

@@ -238,18 +238,20 @@ impl Default for UiSettings {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StorageSettings {
#[serde(default = "StorageSettings::default_conversation_dir")]
pub conversation_dir: String,
pub conversation_dir: Option<String>,
#[serde(default = "StorageSettings::default_auto_save")]
pub auto_save_sessions: bool,
#[serde(default = "StorageSettings::default_max_sessions")]
pub max_saved_sessions: usize,
#[serde(default = "StorageSettings::default_session_timeout")]
pub session_timeout_minutes: u64,
#[serde(default = "StorageSettings::default_generate_descriptions")]
pub generate_descriptions: bool,
}
impl StorageSettings {
fn default_conversation_dir() -> String {
"~/.local/share/owlen/conversations".to_string()
fn default_conversation_dir() -> Option<String> {
None
}
fn default_auto_save() -> bool {
@@ -264,19 +266,35 @@ impl StorageSettings {
120
}
fn default_generate_descriptions() -> bool {
true
}
/// Resolve storage directory path
/// Uses platform-specific data directory if not explicitly configured:
/// - Linux: ~/.local/share/owlen/sessions
/// - Windows: %APPDATA%\owlen\sessions
/// - macOS: ~/Library/Application Support/owlen/sessions
pub fn conversation_path(&self) -> PathBuf {
PathBuf::from(shellexpand::tilde(&self.conversation_dir).as_ref())
if let Some(ref dir) = self.conversation_dir {
PathBuf::from(shellexpand::tilde(dir).as_ref())
} else {
// Use platform-specific data directory
dirs::data_local_dir()
.map(|d| d.join("owlen").join("sessions"))
.unwrap_or_else(|| PathBuf::from("./owlen_sessions"))
}
}
}
impl Default for StorageSettings {
fn default() -> Self {
Self {
conversation_dir: Self::default_conversation_dir(),
conversation_dir: None, // Use platform-specific defaults
auto_save_sessions: Self::default_auto_save(),
max_saved_sessions: Self::default_max_sessions(),
session_timeout_minutes: Self::default_session_timeout(),
generate_descriptions: Self::default_generate_descriptions(),
}
}
}
@@ -340,3 +358,48 @@ pub fn ensure_ollama_config(config: &mut Config) -> &ProviderConfig {
pub fn session_timeout(config: &Config) -> Duration {
Duration::from_secs(config.storage.session_timeout_minutes.max(1) * 60)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_storage_platform_specific_paths() {
let config = Config::default();
let path = config.storage.conversation_path();
// Verify it contains owlen/sessions
assert!(path.to_string_lossy().contains("owlen"));
assert!(path.to_string_lossy().contains("sessions"));
// Platform-specific checks
#[cfg(target_os = "linux")]
{
// Linux should use ~/.local/share/owlen/sessions
assert!(path.to_string_lossy().contains(".local/share"));
}
#[cfg(target_os = "windows")]
{
// Windows should use AppData
assert!(path.to_string_lossy().contains("AppData"));
}
#[cfg(target_os = "macos")]
{
// macOS should use ~/Library/Application Support
assert!(path.to_string_lossy().contains("Library/Application Support"));
}
println!("Config conversation path: {}", path.display());
}
#[test]
fn test_storage_custom_path() {
let mut config = Config::default();
config.storage.conversation_dir = Some("~/custom/path".to_string());
let path = config.storage.conversation_path();
assert!(path.to_string_lossy().contains("custom/path"));
}
}