Skip to main content

chasm/providers/
discovery.rs

1// Copyright (c) 2024-2026 Nervosys LLC
2// SPDX-License-Identifier: AGPL-3.0-only
3//! Provider discovery utilities
4
5use super::{ProviderRegistry, ProviderType};
6use colored::*;
7
8/// Discover all available LLM providers and return a summary
9pub fn discover_all_providers() -> ProviderRegistry {
10    ProviderRegistry::new()
11}
12
13/// Print a summary of discovered providers
14pub fn print_provider_summary(registry: &ProviderRegistry) {
15    println!("{}", "Discovered LLM Providers:".bold());
16    println!();
17
18    let available: Vec<_> = registry.available_providers();
19    let all_providers = registry.providers();
20
21    if all_providers.is_empty() {
22        println!("  {}", "No providers discovered".dimmed());
23        return;
24    }
25
26    for provider in all_providers {
27        let status = if provider.is_available() {
28            "+".green()
29        } else {
30            "x".red()
31        };
32
33        let name = provider.name();
34        let provider_type = provider.provider_type();
35
36        print!("  {} {}", status, name.bold());
37
38        if provider.is_available() {
39            if let Some(path) = provider.sessions_path() {
40                print!(" ({})", path.display().to_string().dimmed());
41            }
42        } else {
43            print!(" {}", "(not available)".dimmed());
44        }
45
46        // Show default endpoint for server-based providers
47        if provider_type.is_openai_compatible() {
48            if let Some(endpoint) = provider_type.default_endpoint() {
49                print!(" [{}]", endpoint.dimmed());
50            }
51        }
52
53        println!();
54    }
55
56    println!();
57    println!(
58        "  {} {} available, {} total",
59        "Summary:".bold(),
60        available.len().to_string().green(),
61        all_providers.len()
62    );
63}
64
65/// Check if a specific provider is available
66pub fn is_provider_available(provider_type: ProviderType) -> bool {
67    let registry = ProviderRegistry::new();
68    registry
69        .get_provider(provider_type)
70        .is_some_and(|p| p.is_available())
71}
72
73/// Get provider endpoints for display
74pub fn get_provider_endpoints() -> Vec<(ProviderType, Option<&'static str>)> {
75    vec![
76        (ProviderType::Copilot, None),
77        (ProviderType::Cursor, None),
78        (ProviderType::ClaudeCode, None),
79        (ProviderType::CodexCli, None),
80        (ProviderType::DroidCli, None),
81        (ProviderType::GeminiCli, None),
82        (ProviderType::OpenCode, None),
83        (ProviderType::OpenClaw, None),
84        (ProviderType::Antigravity, None),
85        (
86            ProviderType::Ollama,
87            ProviderType::Ollama.default_endpoint(),
88        ),
89        (ProviderType::Vllm, ProviderType::Vllm.default_endpoint()),
90        (
91            ProviderType::Foundry,
92            ProviderType::Foundry.default_endpoint(),
93        ),
94        (
95            ProviderType::OpenAI,
96            ProviderType::OpenAI.default_endpoint(),
97        ),
98        (
99            ProviderType::LmStudio,
100            ProviderType::LmStudio.default_endpoint(),
101        ),
102        (
103            ProviderType::LocalAI,
104            ProviderType::LocalAI.default_endpoint(),
105        ),
106        (
107            ProviderType::TextGenWebUI,
108            ProviderType::TextGenWebUI.default_endpoint(),
109        ),
110        (ProviderType::Jan, ProviderType::Jan.default_endpoint()),
111        (
112            ProviderType::Gpt4All,
113            ProviderType::Gpt4All.default_endpoint(),
114        ),
115        (
116            ProviderType::Llamafile,
117            ProviderType::Llamafile.default_endpoint(),
118        ),
119    ]
120}