Add OpenAI/LiteLLM provider support with settings UI

- Add openai/ provider module with translator, client, convert, request/response translators
- Add shared provider/ types (ConversationMessage, MessageRole, ProviderConfig enum)
- Wire OpenAI-compatible provider dispatch alongside Bedrock in response_stream.rs
- Add ai.openai.* settings (enabled, base_url, api_key, model, models)
- Add OpenAI/LiteLLM settings page with model fetch, picker, and config UI
- Extend model menu items and llms.rs to surface LiteLLM models
- Update WARP.md with OpenAI provider architecture docs
This commit is contained in:
Ryan Ward
2026-06-17 14:14:40 -05:00
parent 59cfd0e2f5
commit 5ea378a38d
32 changed files with 2442 additions and 137 deletions
@@ -55,7 +55,8 @@ impl InputClassifier for HeuristicClassifier {
return InputType::Shell;
}
let result = self.classify_input(input, context)
let result = self
.classify_input(input, context)
.await
.map(|result| result.to_input_type())
.unwrap_or(context.current_input_type);
+1 -1
View File
@@ -2,8 +2,8 @@ mod generation;
mod model_loader;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use anyhow::{Context as _, Result};
use candle_core::{DType, Tensor};
@@ -91,7 +91,9 @@ impl InputClassificationTask {
temperature: 0.0,
top_p: 1.0,
};
let output = engine.generate_cancellable(&prompt, &config, cancel).await?;
let output = engine
.generate_cancellable(&prompt, &config, cancel)
.await?;
Ok(Self::parse_output(&output))
}
}
@@ -179,7 +179,11 @@ async fn scenario_tab_naming_development_contexts() {
},
TabCase {
label: "Python data science",
commands: vec!["jupyter notebook", "pip install pandas", "python analysis.py"],
commands: vec![
"jupyter notebook",
"pip install pandas",
"python analysis.py",
],
cwd: "/home/user/research/data-pipeline",
},
TabCase {
+8 -2
View File
@@ -270,7 +270,10 @@ async fn test_classify_multiple_sequential_calls() {
("git status", InputCategory::Shell),
("what does this error mean?", InputCategory::AgentPrompt),
("npm install express", InputCategory::Shell),
("refactor this to use async/await", InputCategory::AgentPrompt),
(
"refactor this to use async/await",
InputCategory::AgentPrompt,
),
];
for (input, expected_category) in inputs {
@@ -286,7 +289,10 @@ async fn test_classify_multiple_sequential_calls() {
.await
.expect("classification failed");
println!("\"{input}\" -> {:?} (confidence: {:.2})", result.category, result.confidence);
println!(
"\"{input}\" -> {:?} (confidence: {:.2})",
result.category, result.confidence
);
assert_eq!(
result.category, expected_category,
"expected {expected_category:?} for \"{input}\", got {:?}",