feat: BYOP provider + tunnel wizard + SVG architecture diagram
Custom Provider (Bring Your Own): - Add custom:URL format to provider factory (any OpenAI-compatible API) - Works with LiteLLM, LocalAI, vLLM, text-generation-webui, LM Studio, etc. - Example: default_provider = 'custom:http://localhost:1234' - 4 new tests for custom provider (URL, localhost, no-key, empty-URL error) Setup Wizard (6 steps, 5-year-old friendly): - Add '🔧 Custom' tier to provider selection with guided BYOP flow - Add Step 4: Tunnel setup (Cloudflare, Tailscale, ngrok, Custom, or skip) - Emoji labels on all provider categories for visual clarity - Renumber wizard to 6 steps (was 5) Architecture Diagram: - New SVG diagram at docs/architecture.svg (dark theme, color-coded) - Shows: Chat Apps → Security → Agent Loop → AI Providers - Shows: Tunnel layer, Sandbox, Context, Heartbeat/Cron - Shows: Setup Wizard 6-step flow at bottom - Replace ASCII art in README with SVG embed 657 tests passing, 0 clippy warnings, cargo fmt clean
This commit is contained in:
parent
390cbc0a6c
commit
cc6fc6ce8d
4 changed files with 516 additions and 60 deletions
|
|
@ -88,8 +88,24 @@ pub fn create_provider(name: &str, api_key: Option<&str>) -> anyhow::Result<Box<
|
|||
"Cohere", "https://api.cohere.com/compatibility", api_key, AuthStyle::Bearer,
|
||||
))),
|
||||
|
||||
// ── Bring Your Own Provider (custom URL) ───────────
|
||||
// Format: "custom:https://your-api.com" or "custom:http://localhost:1234"
|
||||
name if name.starts_with("custom:") => {
|
||||
let base_url = name.strip_prefix("custom:").unwrap_or("");
|
||||
if base_url.is_empty() {
|
||||
anyhow::bail!("Custom provider requires a URL. Format: custom:https://your-api.com");
|
||||
}
|
||||
Ok(Box::new(OpenAiCompatibleProvider::new(
|
||||
"Custom",
|
||||
base_url,
|
||||
api_key,
|
||||
AuthStyle::Bearer,
|
||||
)))
|
||||
}
|
||||
|
||||
_ => anyhow::bail!(
|
||||
"Unknown provider: {name}. Run `zeroclaw integrations list -c ai` to see all available providers."
|
||||
"Unknown provider: {name}. Run `zeroclaw integrations list -c ai` to see all available providers.\n\
|
||||
Tip: Use \"custom:https://your-api.com\" for any OpenAI-compatible endpoint."
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -231,6 +247,37 @@ mod tests {
|
|||
assert!(create_provider("cohere", Some("key")).is_ok());
|
||||
}
|
||||
|
||||
// ── Custom / BYOP provider ─────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn factory_custom_url() {
|
||||
let p = create_provider("custom:https://my-llm.example.com", Some("key"));
|
||||
assert!(p.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn factory_custom_localhost() {
|
||||
let p = create_provider("custom:http://localhost:1234", Some("key"));
|
||||
assert!(p.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn factory_custom_no_key() {
|
||||
let p = create_provider("custom:https://my-llm.example.com", None);
|
||||
assert!(p.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn factory_custom_empty_url_errors() {
|
||||
match create_provider("custom:", None) {
|
||||
Err(e) => assert!(
|
||||
e.to_string().contains("requires a URL"),
|
||||
"Expected 'requires a URL', got: {e}"
|
||||
),
|
||||
Ok(_) => panic!("Expected error for empty custom URL"),
|
||||
}
|
||||
}
|
||||
|
||||
// ── Error cases ──────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue