When APP_AI_BASIC_URL already ends with /v1 (e.g. openrouter.ai/api/v1), appending /v1/models produces /v1/v1/models. Detect trailing /v1 and only append /models in that case.
42 lines
1.2 KiB
Rust
42 lines
1.2 KiB
Rust
//! Model sync from OpenRouter — syncs AI model metadata into the local database.
|
|
|
|
use crate::error::AgentError;
|
|
|
|
/// Response from `GET /v1/models`.
|
|
#[derive(Debug, serde::Deserialize)]
|
|
pub struct ModelsListResponse {
|
|
pub data: Vec<ModelEntry>,
|
|
}
|
|
|
|
#[derive(Debug, serde::Deserialize)]
|
|
pub struct ModelEntry {
|
|
pub id: String,
|
|
}
|
|
|
|
/// List accessible model IDs from the AI endpoint.
|
|
pub async fn list_accessible_models(
|
|
client: &reqwest::Client,
|
|
base_url: &str,
|
|
api_key: &str,
|
|
) -> Result<std::collections::HashSet<String>, AgentError> {
|
|
let base = base_url.trim_end_matches('/');
|
|
let url = if base.ends_with("/v1") {
|
|
format!("{}/models", base)
|
|
} else {
|
|
format!("{}/v1/models", base)
|
|
};
|
|
let resp = client
|
|
.get(&url)
|
|
.header("Authorization", format!("Bearer {}", api_key))
|
|
.send()
|
|
.await
|
|
.map_err(|e| AgentError::Internal(format!("failed to list models: {}", e)))?;
|
|
|
|
let body: ModelsListResponse = resp
|
|
.json()
|
|
.await
|
|
.map_err(|e| AgentError::Internal(format!("failed to parse models response: {}", e)))?;
|
|
|
|
Ok(body.data.into_iter().map(|m| m.id).collect())
|
|
}
|