Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
M11-03: Classroom data persistence - New persist.rs: SQLite-backed ClassroomPersistence with open/load_all/save - Schema: classrooms (JSON blob) + classroom_chats tables - generate.rs: auto-persist classroom after generation - chat.rs: auto-persist chat messages after each exchange - mod.rs: init_persistence() for app setup integration M1-01: Gemini API key now uses x-goog-api-key header - No longer leaks API key in URL query params or debug logs M1-03/04: Mutex unwrap() replaced with unwrap_or_else(|e| e.into_inner()) - MemoryMiddleware and LoopGuardMiddleware recover from poison M2-08: Agent creation input validation - Reject empty names, out-of-range temperature (0-2), zero max_tokens M11-06: Classroom chat message ID uses crypto.randomUUID()
66 lines
2.3 KiB
Rust
66 lines
2.3 KiB
Rust
//! Classroom generation and interaction commands
|
|
//!
|
|
//! Tauri commands for the OpenMAIC-style interactive classroom:
|
|
//! - Generate classroom (4-stage pipeline with progress events)
|
|
//! - Multi-agent chat
|
|
//! - Export (HTML/Markdown/JSON)
|
|
|
|
use std::sync::Arc;
|
|
use tokio::sync::Mutex;
|
|
use tauri::Manager;
|
|
use zclaw_kernel::generation::Classroom;
|
|
|
|
pub mod chat;
|
|
pub mod export;
|
|
pub mod generate;
|
|
pub mod persist;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Shared state types
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// In-memory classroom store: classroom_id → Classroom
|
|
pub type ClassroomStore = Arc<Mutex<std::collections::HashMap<String, Classroom>>>;
|
|
|
|
/// Active generation tasks: topic → progress
|
|
pub type GenerationTasks = Arc<Mutex<std::collections::HashMap<String, zclaw_kernel::generation::GenerationProgress>>>;
|
|
|
|
// Re-export chat state type
|
|
// Re-export chat state type — used by lib.rs to construct managed state
|
|
#[allow(unused_imports)]
|
|
pub use chat::ChatStore;
|
|
pub use persist::ClassroomPersistence;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// State constructors
|
|
// ---------------------------------------------------------------------------
|
|
|
|
pub fn create_classroom_state() -> ClassroomStore {
|
|
Arc::new(Mutex::new(std::collections::HashMap::new()))
|
|
}
|
|
|
|
pub fn create_generation_tasks() -> GenerationTasks {
|
|
Arc::new(Mutex::new(std::collections::HashMap::new()))
|
|
}
|
|
|
|
/// Create and initialize the classroom persistence layer, loading saved data.
|
|
pub async fn init_persistence(
|
|
app_handle: &tauri::AppHandle,
|
|
store: &ClassroomStore,
|
|
chat_store: &ChatStore,
|
|
) -> Result<ClassroomPersistence, String> {
|
|
let app_dir = app_handle
|
|
.path()
|
|
.app_data_dir()
|
|
.map_err(|e| format!("Failed to get app data dir: {}", e))?;
|
|
|
|
let db_path = app_dir.join("classroom").join("classrooms.db");
|
|
std::fs::create_dir_all(db_path.parent().unwrap())
|
|
.map_err(|e| format!("Failed to create classroom dir: {}", e))?;
|
|
|
|
let persistence: ClassroomPersistence = ClassroomPersistence::open(db_path).await?;
|
|
let loaded = persistence.load_all(store, chat_store).await?;
|
|
tracing::info!("[ClassroomPersistence] Loaded {} classrooms from SQLite", loaded);
|
|
Ok(persistence)
|
|
}
|