systemprompt_models/bridge/
profile.rs1use serde::{Deserialize, Serialize};
19
20use crate::services::{ApiSurface, ProviderRegistry};
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct BridgeProfileResponse {
24 pub inference_gateway_base_url: String,
25 pub auth_scheme: String,
26 #[serde(default)]
27 pub models: Vec<String>,
28 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub default_model: Option<String>,
32 #[serde(default)]
33 pub organization_uuid: Option<String>,
34 #[serde(default)]
35 pub providers: Vec<ProviderHealth>,
36}
37
38pub const KNOWN_HOSTS: &[&str] = &[
43 "claude-code",
44 "claude-desktop",
45 "codex-cli",
46 "hermes",
47 "opencode",
48];
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct ProviderHealth {
54 pub name: String,
55 pub surface: ApiSurface,
56 pub configured: bool,
57 #[serde(default)]
58 pub models: Vec<String>,
59 #[serde(default, skip_serializing_if = "Option::is_none")]
60 pub config_issue: Option<String>,
61}
62
63pub fn provider_health(
64 registry: &ProviderRegistry,
65 secret_present: impl Fn(&str) -> bool,
66) -> Vec<ProviderHealth> {
67 registry
68 .advertised_providers()
69 .map(|entry| {
70 let secret = entry.api_key_secret.as_str();
71 let configured = secret_present(secret);
72 ProviderHealth {
73 name: entry.name.as_str().to_owned(),
74 surface: entry.surface,
75 configured,
76 models: entry
77 .models
78 .iter()
79 .flat_map(|m| {
80 std::iter::once(m.id.as_str().to_owned())
81 .chain(m.aliases.iter().map(|a| a.as_str().to_owned()))
82 })
83 .collect(),
84 config_issue: (!configured)
85 .then(|| format!("API key secret '{secret}' is not configured")),
86 }
87 })
88 .collect()
89}
90
91#[derive(Debug, Clone)]
92pub struct BridgeProfileParams<'a> {
93 pub inference_gateway_base_url: String,
94 pub auth_scheme: String,
95 pub organization_uuid: Option<String>,
96 pub default_model: Option<String>,
97 pub registry: &'a ProviderRegistry,
98}
99
100#[must_use]
101pub fn build(
102 params: BridgeProfileParams<'_>,
103 secret_present: impl Fn(&str) -> bool,
104) -> BridgeProfileResponse {
105 let BridgeProfileParams {
106 inference_gateway_base_url,
107 auth_scheme,
108 organization_uuid,
109 default_model,
110 registry,
111 } = params;
112 BridgeProfileResponse {
113 inference_gateway_base_url,
114 auth_scheme,
115 models: registry.advertised_model_ids(&[ApiSurface::Anthropic]),
116 default_model,
117 organization_uuid,
118 providers: provider_health(registry, secret_present),
119 }
120}