Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion crates/protocols/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
use std::collections::HashSet;

use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::model_card::ModelCard;
use super::{model_card::ModelCard, worker::ProviderType};

/// A single model entry in the `/v1/models` response.
#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
Expand Down Expand Up @@ -47,4 +48,23 @@ impl ListModelsResponse {
data,
}
}

/// Parse an upstream `/v1/models` JSON response into [`ModelCard`]s.
///
/// Handles both OpenAI and Anthropic response schemas — both use
/// `data[].id` for the model identifier. Returns an empty vec if
/// the JSON does not contain a valid `data` array.
pub fn parse_upstream(json: &Value, provider: Option<ProviderType>) -> Vec<ModelCard> {
let Some(data) = json.get("data").and_then(|d| d.as_array()) else {
return Vec::new();
};
data.iter()
.filter_map(|m| m.get("id").and_then(|id| id.as_str()))
.map(|id| {
let mut card = ModelCard::new(id);
card.provider.clone_from(&provider);
card
})
.collect()
}
}
1 change: 0 additions & 1 deletion model_gateway/src/routers/anthropic/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
pub(crate) mod context;
pub(crate) mod mcp;
pub mod models;
pub(crate) mod non_streaming;
mod router;
pub(crate) mod sse;
Expand Down
32 changes: 0 additions & 32 deletions model_gateway/src/routers/anthropic/models.rs

This file was deleted.

9 changes: 2 additions & 7 deletions model_gateway/src/routers/anthropic/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
use std::{any::Any, collections::HashMap, fmt, sync::Arc, time::Duration};

use async_trait::async_trait;
use axum::{body::Body, extract::Request, http::HeaderMap, response::Response};
use axum::{http::HeaderMap, response::Response};
use openai_protocol::messages::CreateMessageRequest;
use tracing::{error, info};

use super::{
context::{RequestContext, RouterContext},
mcp, models, non_streaming, streaming, worker,
mcp, non_streaming, streaming, worker,
};
use crate::{
app_context::AppContext,
Expand Down Expand Up @@ -157,11 +157,6 @@ impl RouterTrait for AnthropicRouter {
}
}

/// Get available models from Anthropic API
async fn get_models(&self, req: Request<Body>) -> Response {
models::handle_list_models(self, req)
}

fn router_type(&self) -> &'static str {
"anthropic"
}
Expand Down
23 changes: 1 addition & 22 deletions model_gateway/src/routers/gemini/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@ use std::{
};

use async_trait::async_trait;
use axum::{
body::Body,
extract::Request,
http::{HeaderMap, StatusCode},
response::{IntoResponse, Response},
Json,
};
use axum::{http::HeaderMap, response::Response};
use openai_protocol::interactions::InteractionsRequest;

use super::{
Expand Down Expand Up @@ -72,21 +66,6 @@ impl RouterTrait for GeminiRouter {
"gemini"
}

async fn get_models(&self, _req: Request<Body>) -> Response {
let cards = self
.shared_components
.worker_registry
.get_all()
.iter()
.flat_map(|w| w.models())
.collect::<Vec<_>>();
if cards.is_empty() {
return (StatusCode::SERVICE_UNAVAILABLE, "No models available").into_response();
}
let resp = openai_protocol::models::ListModelsResponse::from_model_cards(cards);
(StatusCode::OK, Json(resp)).into_response()
}

async fn route_interactions(
&self,
headers: Option<&HeaderMap>,
Expand Down
14 changes: 0 additions & 14 deletions model_gateway/src/routers/http/pd_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,20 +1238,6 @@ impl RouterTrait for PDRouter {
.await
}

async fn get_models(&self, _req: Request<Body>) -> Response {
let cards = self
.worker_registry
.get_all()
.iter()
.flat_map(|w| w.models())
.collect::<Vec<_>>();
if cards.is_empty() {
return (StatusCode::SERVICE_UNAVAILABLE, "No models available").into_response();
}
let resp = openai_protocol::models::ListModelsResponse::from_model_cards(cards);
(StatusCode::OK, axum::Json(resp)).into_response()
}

async fn get_model_info(&self, req: Request<Body>) -> Response {
// Extract headers first to avoid Send issues
let headers = header_utils::copy_request_headers(&req);
Expand Down
20 changes: 0 additions & 20 deletions model_gateway/src/routers/http/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -671,26 +671,6 @@ impl RouterTrait for Router {
self.proxy_get_request(req, "get_server_info").await
}

async fn get_models(&self, _req: Request<Body>) -> Response {
let cards: Vec<_> = self
.worker_registry
.get_workers_filtered(
None,
Some(WorkerType::Regular),
Some(ConnectionMode::Http),
None,
false,
)
.iter()
.flat_map(|w| w.models())
.collect();
if cards.is_empty() {
return (StatusCode::SERVICE_UNAVAILABLE, "No models available").into_response();
}
let resp = openai_protocol::models::ListModelsResponse::from_model_cards(cards);
(StatusCode::OK, Json(resp)).into_response()
}

async fn get_model_info(&self, req: Request<Body>) -> Response {
self.proxy_get_request(req, "get_model_info").await
}
Expand Down
18 changes: 0 additions & 18 deletions model_gateway/src/routers/openai/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,24 +549,6 @@ impl crate::routers::RouterTrait for OpenAIRouter {
(StatusCode::OK, info.to_string()).into_response()
}

async fn get_models(&self, req: Request<Body>) -> Response {
let external_workers = self.external_workers();
if external_workers.is_empty() {
return error::service_unavailable(
"service_unavailable",
"No external workers registered",
);
}

let auth_header = extract_auth_header(Some(req.headers()), None);
self.refresh_external_models(auth_header.as_ref()).await;

let cards = external_workers.iter().flat_map(|w| w.models());
let resp = openai_protocol::models::ListModelsResponse::from_model_cards(cards);

(StatusCode::OK, Json(resp)).into_response()
}

async fn route_chat(
&self,
headers: Option<&HeaderMap>,
Expand Down
Loading