- rework chat backend (chat.rs, chat_tools.rs, ai.rs, models, state) around tool calls - add OpenRouter provider alongside Ollama/Fireworks in settings - drop inline AiBar, ResultsPanel explain/fix UI and ChartPreview in favour of the chat panel - add frontend chat tool-registry
123 lines
3.4 KiB
Rust
123 lines
3.4 KiB
Rust
use serde::{Deserialize, Deserializer, Serialize};
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Default)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum AiProvider {
|
|
#[default]
|
|
Ollama,
|
|
Fireworks,
|
|
OpenRouter,
|
|
}
|
|
|
|
/// Deserialize a provider string, coercing legacy `openai`/`anthropic` and any
|
|
/// unknown value to `Ollama`. Keeps existing config files loadable after the
|
|
/// stub providers were removed.
|
|
impl<'de> Deserialize<'de> for AiProvider {
|
|
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
|
let s = String::deserialize(d)?;
|
|
Ok(match s.as_str() {
|
|
"fireworks" => AiProvider::Fireworks,
|
|
"openrouter" => AiProvider::OpenRouter,
|
|
_ => AiProvider::Ollama,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct AiSettings {
|
|
pub provider: AiProvider,
|
|
pub ollama_url: String,
|
|
#[serde(default)]
|
|
pub fireworks_api_key: Option<String>,
|
|
#[serde(default)]
|
|
pub openrouter_api_key: Option<String>,
|
|
pub model: String,
|
|
}
|
|
|
|
impl Default for AiSettings {
|
|
fn default() -> Self {
|
|
Self {
|
|
provider: AiProvider::Ollama,
|
|
ollama_url: "http://localhost:11434".to_string(),
|
|
fireworks_api_key: None,
|
|
openrouter_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,
|
|
pub content: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize)]
|
|
pub struct OllamaChatRequest {
|
|
pub model: String,
|
|
pub messages: Vec<OllamaChatMessage>,
|
|
pub stream: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub format: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct OllamaChatResponse {
|
|
pub message: OllamaChatMessage,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
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,
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// OpenAI-compatible chat-completions (Fireworks, OpenRouter)
|
|
// These request/response shapes are shared by every OpenAI-compatible provider;
|
|
// the `Fireworks*` names are retained for historical reasons.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#[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,
|
|
}
|