chasm_cli/providers/
mod.rs1#[allow(dead_code)]
30pub mod cloud;
31pub mod config;
32pub mod cursor;
33#[allow(dead_code)]
34pub mod discovery;
35pub mod ollama;
36pub mod openai_compat;
37#[allow(dead_code)]
38pub mod session_format;
39
40#[allow(unused_imports)]
41pub use cloud::{CloudConversation, CloudMessage, CloudProvider, FetchOptions};
42pub use config::ProviderType;
43#[allow(unused_imports)]
44pub use config::{CsmConfig, ProviderConfig};
45#[allow(unused_imports)]
46pub use discovery::discover_all_providers;
47#[allow(unused_imports)]
48pub use session_format::{GenericMessage, GenericSession};
49
50use crate::models::ChatSession;
51use anyhow::Result;
52use std::path::PathBuf;
53
54pub trait ChatProvider: Send + Sync {
56 fn provider_type(&self) -> ProviderType;
58
59 fn name(&self) -> &str;
61
62 fn is_available(&self) -> bool;
64
65 fn sessions_path(&self) -> Option<PathBuf>;
67
68 fn list_sessions(&self) -> Result<Vec<ChatSession>>;
70
71 fn import_session(&self, session_id: &str) -> Result<ChatSession>;
73
74 #[allow(dead_code)]
76 fn export_session(&self, session: &ChatSession) -> Result<()>;
77}
78
79pub struct ProviderRegistry {
81 providers: Vec<Box<dyn ChatProvider>>,
82}
83
84impl ProviderRegistry {
85 pub fn new() -> Self {
87 let mut registry = Self {
88 providers: Vec::new(),
89 };
90 registry.discover_providers();
91 registry
92 }
93
94 fn discover_providers(&mut self) {
96 if let Some(provider) = cursor::CursorProvider::discover() {
98 self.providers.push(Box::new(provider));
99 }
100
101 if let Some(provider) = ollama::OllamaProvider::discover() {
103 self.providers.push(Box::new(provider));
104 }
105
106 for provider in openai_compat::discover_openai_compatible_providers() {
108 self.providers.push(Box::new(provider));
109 }
110 }
111
112 pub fn providers(&self) -> &[Box<dyn ChatProvider>] {
114 &self.providers
115 }
116
117 pub fn available_providers(&self) -> Vec<&dyn ChatProvider> {
119 self.providers
120 .iter()
121 .filter(|p| p.is_available())
122 .map(|p| p.as_ref())
123 .collect()
124 }
125
126 pub fn get_provider(&self, provider_type: ProviderType) -> Option<&dyn ChatProvider> {
128 self.providers
129 .iter()
130 .find(|p| p.provider_type() == provider_type)
131 .map(|p| p.as_ref())
132 }
133
134 #[allow(dead_code)]
136 pub fn list_all_sessions(&self) -> Result<Vec<(ProviderType, ChatSession)>> {
137 let mut all_sessions = Vec::new();
138
139 for provider in &self.providers {
140 if provider.is_available() {
141 if let Ok(sessions) = provider.list_sessions() {
142 for session in sessions {
143 all_sessions.push((provider.provider_type(), session));
144 }
145 }
146 }
147 }
148
149 Ok(all_sessions)
150 }
151}
152
153impl Default for ProviderRegistry {
154 fn default() -> Self {
155 Self::new()
156 }
157}