traits.rs (3670B)
1 use crate::messages::DaveApiResponse; 2 use crate::tools::Tool; 3 use claude_agent_sdk_rs::PermissionMode; 4 use std::collections::HashMap; 5 use std::path::PathBuf; 6 use std::sync::mpsc; 7 use std::sync::Arc; 8 9 /// Backend type selection 10 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 11 pub enum BackendType { 12 OpenAI, 13 Claude, 14 Codex, 15 /// No local AI — only view/control remote agentic sessions from ndb 16 Remote, 17 } 18 19 impl BackendType { 20 pub fn display_name(&self) -> &'static str { 21 match self { 22 BackendType::OpenAI => "OpenAI", 23 BackendType::Claude => "Claude Code", 24 BackendType::Codex => "Codex", 25 BackendType::Remote => "Remote", 26 } 27 } 28 29 pub fn is_agentic(&self) -> bool { 30 matches!(self, BackendType::Claude | BackendType::Codex) 31 } 32 33 pub fn default_model(&self) -> &'static str { 34 match self { 35 BackendType::OpenAI => "gpt-4.1-mini", 36 BackendType::Claude => "claude-sonnet-4.5", 37 BackendType::Codex => "gpt-5.2-codex", 38 BackendType::Remote => "", 39 } 40 } 41 42 /// Stable string for Nostr event tags. 43 pub fn as_str(&self) -> &'static str { 44 match self { 45 BackendType::OpenAI => "openai", 46 BackendType::Claude => "claude", 47 BackendType::Codex => "codex", 48 BackendType::Remote => "remote", 49 } 50 } 51 52 /// Parse from a Nostr event tag value. 53 pub fn from_tag_str(s: &str) -> Option<BackendType> { 54 match s { 55 "openai" => Some(BackendType::OpenAI), 56 "claude" => Some(BackendType::Claude), 57 "codex" => Some(BackendType::Codex), 58 "remote" => Some(BackendType::Remote), 59 _ => None, 60 } 61 } 62 } 63 64 /// Trait for AI backend implementations 65 pub trait AiBackend: Send + Sync { 66 /// Stream a request to the AI backend 67 /// 68 /// Returns a receiver that will receive tokens and tool calls as they arrive, 69 /// plus an optional JoinHandle to the spawned task for cleanup on session deletion. 70 /// 71 /// If `resume_session_id` is Some, the backend should resume the specified Claude 72 /// session instead of starting a new conversation. 73 #[allow(clippy::too_many_arguments)] 74 fn stream_request( 75 &self, 76 messages: Vec<crate::Message>, 77 tools: Arc<HashMap<String, Tool>>, 78 model: String, 79 user_id: String, 80 session_id: String, 81 cwd: Option<PathBuf>, 82 resume_session_id: Option<String>, 83 ctx: egui::Context, 84 ) -> ( 85 mpsc::Receiver<DaveApiResponse>, 86 Option<tokio::task::JoinHandle<()>>, 87 ); 88 89 /// Clean up resources associated with a session. 90 /// Called when a session is deleted to allow backends to shut down any persistent connections. 91 fn cleanup_session(&self, session_id: String); 92 93 /// Interrupt the current query for a session. 94 /// This stops any in-progress work but preserves the session history. 95 fn interrupt_session(&self, session_id: String, ctx: egui::Context); 96 97 /// Set the permission mode for a session. 98 /// Plan mode makes Claude plan actions without executing them. 99 fn set_permission_mode(&self, session_id: String, mode: PermissionMode, ctx: egui::Context); 100 101 /// Trigger manual context compaction for a session. 102 /// Returns a receiver for CompactionStarted/CompactionComplete events. 103 /// Default implementation does nothing (backends that don't support it). 104 fn compact_session( 105 &self, 106 _session_id: String, 107 _ctx: egui::Context, 108 ) -> Option<mpsc::Receiver<DaveApiResponse>> { 109 None 110 } 111 }