feat: fetch openrouter supported models in goose configure (#3347)

This commit is contained in:
Best Codes
2025-07-13 19:52:20 -05:00
committed by GitHub
parent ad1e322854
commit 5db89aaf65

View File

@@ -278,4 +278,95 @@ impl Provider for OpenRouterProvider {
emit_debug_trace(&self.model, &payload, &response, &usage); emit_debug_trace(&self.model, &payload, &response, &usage);
Ok((message, ProviderUsage::new(model, usage))) Ok((message, ProviderUsage::new(model, usage)))
} }
/// Fetch supported models from OpenRouter API (only models with tool support)
async fn fetch_supported_models_async(&self) -> Result<Option<Vec<String>>, ProviderError> {
let base_url = Url::parse(&self.host)
.map_err(|e| ProviderError::RequestFailed(format!("Invalid base URL: {e}")))?;
let url = base_url.join("api/v1/models").map_err(|e| {
ProviderError::RequestFailed(format!("Failed to construct models URL: {e}"))
})?;
// Handle request failures gracefully
// If the request fails, fall back to manual entry
let response = match self
.client
.get(url)
.header("Authorization", format!("Bearer {}", self.api_key))
.header("HTTP-Referer", "https://block.github.io/goose")
.header("X-Title", "Goose")
.send()
.await
{
Ok(response) => response,
Err(e) => {
tracing::warn!("Failed to fetch models from OpenRouter API: {}, falling back to manual model entry", e);
return Ok(None);
}
};
// Handle JSON parsing failures gracefully
let json: serde_json::Value = match response.json().await {
Ok(json) => json,
Err(e) => {
tracing::warn!("Failed to parse OpenRouter API response as JSON: {}, falling back to manual model entry", e);
return Ok(None);
}
};
// Check for error in response
if let Some(err_obj) = json.get("error") {
let msg = err_obj
.get("message")
.and_then(|v| v.as_str())
.unwrap_or("unknown error");
tracing::warn!("OpenRouter API returned an error: {}", msg);
return Ok(None);
}
let data = json.get("data").and_then(|v| v.as_array()).ok_or_else(|| {
ProviderError::UsageError("Missing data field in JSON response".into())
})?;
let mut models: Vec<String> = data
.iter()
.filter_map(|model| {
// Get the model ID
let id = model.get("id").and_then(|v| v.as_str())?;
// Check if the model supports tools
let supported_params =
match model.get("supported_parameters").and_then(|v| v.as_array()) {
Some(params) => params,
None => {
// If supported_parameters is missing, skip this model (assume no tool support)
tracing::debug!(
"Model '{}' missing supported_parameters field, skipping",
id
);
return None;
}
};
let has_tool_support = supported_params
.iter()
.any(|param| param.as_str() == Some("tools"));
if has_tool_support {
Some(id.to_string())
} else {
None
}
})
.collect();
// If no models with tool support were found, fall back to manual entry
if models.is_empty() {
tracing::warn!("No models with tool support found in OpenRouter API response, falling back to manual model entry");
return Ok(None);
}
models.sort();
Ok(Some(models))
}
} }