feat: add Fireworks AI provider for chat agent
Routes chat-completions through a managed OpenAI-compatible inference endpoint as an alternative to local Ollama, useful when the agent needs fast multi-hop reasoning that local hardware can't sustain. - backend: rename `call_ollama_chat_messages` → `call_chat_messages`, dispatch by provider; add `call_fireworks` branch (Bearer auth, `response_format: json_object` mapped from internal `format="json"`) and `list_fireworks_models` Tauri command - settings: extend `AiProvider` enum + `AiSettings.fireworks_api_key` (serde-default for legacy config compat); Fireworks base URL hardcoded - UI: provider selector in both popover and AppSettingsSheet (only ollama+fireworks shown; legacy openai/anthropic kept for serde-compat but normalized to ollama in UI); password input + dynamic model list for Fireworks; switching provider clears stale model selection - 4 unit tests: serde round-trip, legacy settings deserialization, Fireworks chat-completions parsing, models-list parsing
This commit is contained in:
@@ -7,14 +7,19 @@ pub enum AiProvider {
|
||||
Ollama,
|
||||
OpenAi,
|
||||
Anthropic,
|
||||
Fireworks,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AiSettings {
|
||||
pub provider: AiProvider,
|
||||
pub ollama_url: String,
|
||||
#[serde(default)]
|
||||
pub openai_api_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub anthropic_api_key: Option<String>,
|
||||
#[serde(default)]
|
||||
pub fireworks_api_key: Option<String>,
|
||||
pub model: String,
|
||||
}
|
||||
|
||||
@@ -25,11 +30,14 @@ impl Default for AiSettings {
|
||||
ollama_url: "http://localhost:11434".to_string(),
|
||||
openai_api_key: None,
|
||||
anthropic_api_key: None,
|
||||
fireworks_api_key: None,
|
||||
model: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic chat message used by all chat providers (Ollama, Fireworks, OpenAI-compatible).
|
||||
/// `{role, content}` shape is identical across these APIs.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OllamaChatMessage {
|
||||
pub role: String,
|
||||
@@ -55,7 +63,48 @@ pub struct OllamaTagsResponse {
|
||||
pub models: Vec<OllamaModel>,
|
||||
}
|
||||
|
||||
/// Generic chat-model descriptor exposed to the UI dropdown.
|
||||
/// Reused as the return shape for both Ollama and Fireworks model listings.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OllamaModel {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Fireworks (OpenAI-compatible chat-completions)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct FireworksChatRequest {
|
||||
pub model: String,
|
||||
pub messages: Vec<OllamaChatMessage>,
|
||||
pub temperature: f32,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub response_format: Option<FireworksResponseFormat>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct FireworksResponseFormat {
|
||||
#[serde(rename = "type")]
|
||||
pub kind: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct FireworksChatResponse {
|
||||
pub choices: Vec<FireworksChoice>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct FireworksChoice {
|
||||
pub message: OllamaChatMessage,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct FireworksModelsResponse {
|
||||
pub data: Vec<FireworksModelEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct FireworksModelEntry {
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user