- Anthropic outbound provider: /v1/messages, system extraction, x-api-key + anthropic-version; streaming translates Anthropic SSE -> unified OpenAI wire format - Anthropic inbound adapter (POST /v1/messages): non-streaming JSON + streaming SSE (OpenAI -> Anthropic event translation) - Embeddings: POST /v1/embeddings inbound + Provider::embed(); embedding models resolvable from the pool (registry no longer skips them) - protocols mounted always, gated on live flags; admin meta marks them implemented Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
53 lines
1.7 KiB
Rust
53 lines
1.7 KiB
Rust
//! Inbound OpenAI Embeddings adapter: `POST /v1/embeddings`.
|
|
//! Resolves an embedding model (explicit id, or the first `kind = "embedding"`),
|
|
//! calls the provider, and forwards the OpenAI-style response body.
|
|
|
|
use crate::error::{GatewayError, Result};
|
|
use crate::state::SharedState;
|
|
use axum::{extract::State, response::IntoResponse, routing::post, Json, Router};
|
|
use serde::Deserialize;
|
|
|
|
pub fn routes() -> Router<SharedState> {
|
|
Router::new().route("/v1/embeddings", post(handler))
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct EmbeddingsRequest {
|
|
#[serde(default)]
|
|
model: String,
|
|
input: serde_json::Value,
|
|
}
|
|
|
|
async fn handler(
|
|
State(state): State<SharedState>,
|
|
Json(req): Json<EmbeddingsRequest>,
|
|
) -> Result<impl IntoResponse> {
|
|
let live = state.live();
|
|
if !live.cfg.protocols.openai_embeddings {
|
|
return Err(GatewayError::InvalidRequest(
|
|
"openai_embeddings protocol is disabled".into(),
|
|
));
|
|
}
|
|
|
|
// resolve the embedding model: explicit real id, else first kind == "embedding"
|
|
let model_id = if !req.model.is_empty()
|
|
&& req.model != "cortiq-auto"
|
|
&& live.registry.get(&req.model).is_some()
|
|
{
|
|
req.model.clone()
|
|
} else {
|
|
live.cfg
|
|
.models
|
|
.iter()
|
|
.find(|m| m.kind == "embedding")
|
|
.map(|m| m.id.clone())
|
|
.ok_or_else(|| GatewayError::InvalidRequest("no embedding model configured".into()))?
|
|
};
|
|
|
|
let provider = live.registry.get(&model_id).ok_or_else(|| {
|
|
GatewayError::UpstreamUnavailable(format!("embedding model '{model_id}' is not available"))
|
|
})?;
|
|
let body = provider.embed(req.input).await?;
|
|
Ok(Json(body))
|
|
}
|