Voice (Phase 10): - voice.rs: OpenAI Whisper (STT) + TTS Backend - ChatPanel: Mikrofon-Button, VAD (Pause 1.5s), Live-Pegel - SettingsPanel: OpenAI-Key Konfiguration Phase 9 Nacharbeiten: - Auto-Extract vor Compacting (Entscheidungen/TODOs/Insights) - get_tool_hints() - relevante KB-Eintraege bei Tool-Start - activeKnowledgeHints Store, Anzeige im KnowledgePanel Tech-Schulden: - Dead-Code in memory.rs entfernt (MemorySystem struct) - cargo-check Warnings behoben Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
132 lines
4.3 KiB
Rust
132 lines
4.3 KiB
Rust
// Claude Desktop — Autonomes Gedächtnis-System
|
|
// Lädt Zugänge, Patterns, Vorgehensweisen automatisch und behält sie im Kontext
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use std::collections::HashMap;
|
|
use std::sync::{Arc, Mutex};
|
|
use tauri::{AppHandle, Manager};
|
|
|
|
use crate::db;
|
|
|
|
/// Kategorien für Sticky Context (werden nie vergessen)
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
pub enum ContextCategory {
|
|
Critical, // API-Keys, Server-URLs, Projekt-Pfade
|
|
Pattern, // Bekannte Fehler und Workarounds
|
|
Preference, // Benutzer-Präferenzen
|
|
GuardRail, // Freigabe-Regeln
|
|
Hook, // Aktive Hooks
|
|
Skill, // Verfügbare Skills
|
|
}
|
|
|
|
/// Ein Eintrag im Gedächtnis
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct MemoryEntry {
|
|
pub id: String,
|
|
pub category: ContextCategory,
|
|
pub key: String,
|
|
pub value: serde_json::Value,
|
|
pub sticky: bool, // Wird nie durch Compacting entfernt
|
|
pub auto_load: bool, // Wird beim Start automatisch geladen
|
|
pub last_used: Option<String>,
|
|
pub use_count: u32,
|
|
}
|
|
|
|
// MemorySystem Struct entfernt - Dead Code, Funktionalität läuft über Tauri-Commands
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct MemoryStats {
|
|
pub total: usize,
|
|
pub sticky: usize,
|
|
pub by_category: HashMap<String, usize>,
|
|
}
|
|
|
|
/// Vorgehensweise / Pattern
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Pattern {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub description: String,
|
|
pub trigger: String, // Wann wird es angewendet
|
|
pub old_approach: String, // Was wurde vorher gemacht
|
|
pub new_approach: String, // Was ist die Korrektur
|
|
pub reason: String, // Warum wurde korrigiert
|
|
pub occurrence_count: u32, // Wie oft ist das Problem aufgetreten
|
|
pub auto_corrected: bool, // Wurde automatisch korrigiert
|
|
pub created_at: String,
|
|
pub updated_at: String,
|
|
}
|
|
|
|
// Tauri-Commands
|
|
|
|
/// Lädt das Gedächtnis beim Start
|
|
#[tauri::command]
|
|
pub async fn load_memory(app: AppHandle) -> Result<MemoryStats, String> {
|
|
println!("🧠 Lade Gedächtnis-System...");
|
|
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db_lock = state.lock().unwrap();
|
|
let entries = db_lock.load_memory_entries().map_err(|e| e.to_string())?;
|
|
|
|
let mut by_category: HashMap<String, usize> = HashMap::new();
|
|
let mut sticky_count = 0;
|
|
for entry in &entries {
|
|
let cat = format!("{:?}", entry.category);
|
|
*by_category.entry(cat).or_insert(0) += 1;
|
|
if entry.sticky {
|
|
sticky_count += 1;
|
|
}
|
|
}
|
|
|
|
println!("🧠 {} Einträge geladen ({} sticky)", entries.len(), sticky_count);
|
|
|
|
Ok(MemoryStats {
|
|
total: entries.len(),
|
|
sticky: sticky_count,
|
|
by_category,
|
|
})
|
|
}
|
|
|
|
/// Holt die Sticky-Memory-Einträge (veraltet, nutze context::get_sticky_context)
|
|
#[tauri::command]
|
|
pub async fn get_sticky_memory_entries(app: AppHandle) -> Result<Vec<MemoryEntry>, String> {
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db_lock = state.lock().unwrap();
|
|
let entries = db_lock.load_memory_entries().map_err(|e| e.to_string())?;
|
|
Ok(entries.into_iter().filter(|e| e.sticky).collect())
|
|
}
|
|
|
|
/// Speichert eine neue Vorgehensweise
|
|
#[tauri::command]
|
|
pub async fn save_pattern(app: AppHandle, pattern: Pattern) -> Result<(), String> {
|
|
println!("📝 Speichere Vorgehensweise: {}", pattern.name);
|
|
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db_lock = state.lock().unwrap();
|
|
db_lock.save_pattern(&pattern).map_err(|e| e.to_string())
|
|
}
|
|
|
|
/// Erkennt ein Problem und schlägt Korrektur vor
|
|
#[tauri::command]
|
|
pub async fn detect_issue(
|
|
app: AppHandle,
|
|
error_message: String,
|
|
_context: String,
|
|
) -> Result<Option<Pattern>, String> {
|
|
let preview_len = error_message.len().min(50);
|
|
println!("🔍 Prüfe auf bekannte Probleme: {}", &error_message[..preview_len]);
|
|
|
|
let state = app.state::<Arc<Mutex<db::Database>>>();
|
|
let db_lock = state.lock().unwrap();
|
|
let patterns = db_lock.load_patterns().map_err(|e| e.to_string())?;
|
|
|
|
// Einfaches Pattern-Matching: Trigger im Fehlertext suchen
|
|
let error_lower = error_message.to_lowercase();
|
|
for pattern in patterns {
|
|
if error_lower.contains(&pattern.trigger.to_lowercase()) {
|
|
return Ok(Some(pattern));
|
|
}
|
|
}
|
|
|
|
Ok(None)
|
|
}
|