mod exec;
mod plan;
#[cfg(test)]
mod tests;
use std::collections::HashSet;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll};
use std::time::Duration;
use anyllm_translate::openai::ChatCompletionRequest;
use axum::extract::{Path, State};
use axum::response::sse::{Event, KeepAlive, Sse};
use axum::response::{IntoResponse, Response};
use axum::Json;
use futures::stream::{Stream, StreamExt};
use runtime::{GenerationConfig, RuntimeError};
use tokenizer::ReasoningEffort;
pub(crate) const SSE_KEEP_ALIVE: Duration = Duration::from_secs(15);
pub(crate) use exec::*;
pub use plan::AppState;
pub(crate) use plan::*;
use crate::guardrails::run_guarded;
use crate::response::{
completion_chunk, completion_response, reasoning_delta, role_delta, text_delta, tool_call_delta,
};
#[derive(Clone, Default)]
pub(crate) struct RequestLeaseSlot(Arc<Mutex<Option<Box<dyn crate::registry::RequestUseLease>>>>);
impl RequestLeaseSlot {
fn store(&self, lease: Box<dyn crate::registry::RequestUseLease>) {
let mut slot = self.0.lock().unwrap_or_else(|p| p.into_inner());
debug_assert!(
slot.is_none(),
"one model-use lease is expected per request"
);
*slot = Some(lease);
}
fn take(&self) -> Option<Box<dyn crate::registry::RequestUseLease>> {
self.0.lock().unwrap_or_else(|p| p.into_inner()).take()
}
}
struct LeasedBodyStream<S> {
inner: Pin<Box<S>>,
lease: Option<Box<dyn crate::registry::RequestUseLease>>,
}
impl<S> LeasedBodyStream<S> {
fn new(inner: S, lease: Box<dyn crate::registry::RequestUseLease>) -> Self {
Self {
inner: Box::pin(inner),
lease: Some(lease),
}
}
}
impl<S: Stream> Stream for LeasedBodyStream<S> {
type Item = S::Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
match this.inner.as_mut().poll_next(cx) {
Poll::Ready(None) => {
this.lease.take();
Poll::Ready(None)
}
other => other,
}
}
}
pub(crate) async fn request_lease_layer(
mut request: axum::extract::Request,
next: axum::middleware::Next,
) -> Response {
let slot = RequestLeaseSlot::default();
request.extensions_mut().insert(slot.clone());
let response = next.run(request).await;
with_request_lease(response, slot.take())
}
fn with_request_lease(
response: Response,
lease: Option<Box<dyn crate::registry::RequestUseLease>>,
) -> Response {
let Some(lease) = lease else {
return response;
};
let (parts, body) = response.into_parts();
let body = axum::body::Body::from_stream(LeasedBodyStream::new(body.into_data_stream(), lease));
Response::from_parts(parts, body)
}
#[allow(clippy::result_large_err)]
pub(crate) async fn resolve_backend(
state: &crate::ServerState,
request_lease_slot: &RequestLeaseSlot,
tag: Option<crate::observe::RequestTag>,
requested: Option<&str>,
stream: bool,
) -> Result<AppState, Response> {
finish_resolution(
state,
request_lease_slot,
resolve_off_worker(
state,
requested,
crate::bounded_resolve::ResolutionKind::Chat,
)
.await?,
tag,
requested,
stream,
)
}
#[allow(clippy::result_large_err)]
pub(crate) async fn resolve_embedding_backend(
state: &crate::ServerState,
request_lease_slot: &RequestLeaseSlot,
tag: Option<crate::observe::RequestTag>,
requested: Option<&str>,
) -> Result<AppState, Response> {
finish_resolution(
state,
request_lease_slot,
resolve_off_worker(
state,
requested,
crate::bounded_resolve::ResolutionKind::Embedding,
)
.await?,
tag,
requested,
false,
)
}
#[allow(clippy::result_large_err)]
async fn resolve_off_worker(
state: &crate::ServerState,
requested: Option<&str>,
kind: crate::bounded_resolve::ResolutionKind,
) -> Result<crate::registry::Resolution, Response> {
use crate::bounded_resolve::ResolveError;
let requested = requested.map(str::to_owned);
match state
.resolve_executor
.resolve(Arc::clone(&state.registry), requested, kind)
.await
{
Ok(resolution) => Ok(resolution),
Err(ResolveError::Saturated) => Err((
axum::http::StatusCode::SERVICE_UNAVAILABLE,
Json(serde_json::json!({
"error": {
"message": "Model resolution is at capacity. Retry the request shortly.",
"type": "server_error",
"param": "model",
"code": "model_resolution_busy",
"retryable": true
}
})),
)
.into_response()),
Err(ResolveError::WorkerFailed) => Err((
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
Json(serde_json::json!({
"error": {
"message": "The model resolution task failed.",
"type": "server_error",
"code": "model_resolution_failed",
"retryable": false
}
})),
)
.into_response()),
}
}
#[allow(clippy::result_large_err)]
fn finish_resolution(
state: &crate::ServerState,
request_lease_slot: &RequestLeaseSlot,
resolution: crate::registry::Resolution,
tag: Option<crate::observe::RequestTag>,
requested: Option<&str>,
stream: bool,
) -> Result<AppState, Response> {
use crate::registry::Resolution;
match resolution {
Resolution::Model(resolved) => {
if let Some(lease) = resolved.request_lease {
request_lease_slot.store(lease);
}
let model = resolved.model;
let (Some(crate::observe::RequestTag(id)), Some(observer)) = (tag, &state.observer)
else {
return Ok(model);
};
let served = model.model_id().to_string();
observer.record(crate::observe::ServerEvent::RequestRouted {
id,
requested: requested.map(str::to_string),
served,
stream,
});
Ok(Arc::new(crate::observe::ReportingModel::new(
model,
Arc::clone(observer),
id,
)))
}
Resolution::Unknown {
requested,
available,
suggestions,
} => Err((
axum::http::StatusCode::NOT_FOUND,
Json(serde_json::json!({
"error": {
"message": format!(
"The model '{requested}' does not exist. This server has {} models \
attached: {}",
available.len(),
available.join(", ")
),
"type": "invalid_request_error",
"param": "model",
"code": "model_not_found",
"available": available,
"suggestions": suggestions
}
})),
)
.into_response()),
Resolution::LoadRefused(refusal) => Err((
axum::http::StatusCode::SERVICE_UNAVAILABLE,
Json(serde_json::json!({
"error": {
"message": "The requested installed model could not be loaded.",
"type": "server_error",
"code": "model_load_refused",
"retryable": true,
"refusal": refusal
}
})),
)
.into_response()),
Resolution::Empty => Err(error_response(
axum::http::StatusCode::SERVICE_UNAVAILABLE,
"no model capable of this request is loaded; attach one before sending requests"
.to_string(),
)),
}
}
pub(crate) fn error_response(status: axum::http::StatusCode, message: String) -> Response {
(
status,
Json(serde_json::json!({"error": {"message": message, "type": "invalid_request_error"}})),
)
.into_response()
}
pub(crate) fn status_for(e: &RuntimeError) -> axum::http::StatusCode {
match e {
RuntimeError::EmptyPrompt
| RuntimeError::ZeroBudget
| RuntimeError::ContextOverflow { .. }
| RuntimeError::Selection(_) => axum::http::StatusCode::BAD_REQUEST,
RuntimeError::Producer(_) | RuntimeError::SpeculationUnavailable(_) => {
axum::http::StatusCode::INTERNAL_SERVER_ERROR
}
}
}
pub(crate) fn gen_error_response(e: GenError) -> Response {
match e {
GenError::Runtime(e) => error_response(status_for(&e), e.to_string()),
GenError::Join(m) => error_response(axum::http::StatusCode::INTERNAL_SERVER_ERROR, m),
}
}
pub async fn health(State(state): State<crate::ServerState>) -> Response {
let rows = state.registry.rows();
let images_ready = state
.image_provider
.as_ref()
.is_some_and(|provider| !provider.models().is_empty());
let audio_ready = state
.audio
.as_ref()
.is_some_and(|audio| !audio.provider.models().is_empty());
Json(serde_json::json!({
"status": "ok",
"state": if rows.is_empty() && !images_ready && !audio_ready { "empty" } else { "ready" },
}))
.into_response()
}
pub async fn models(State(state): State<crate::ServerState>) -> Response {
let created = now_unix();
let mut data = state
.registry
.rows()
.into_iter()
.flat_map(|row| {
let max_context = row.max_context;
row.ids()
.map(|id| {
serde_json::json!({
"id": id,
"display_name": id,
"object": "model",
"created": created,
"owned_by": "mference",
"context_window": max_context,
})
})
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
if let Some(provider) = &state.image_provider {
data.extend(provider.models().into_iter().map(|id| {
serde_json::json!({
"display_name": id,
"id": id,
"object": "model",
"created": created,
"owned_by": "turbospark",
"capabilities": ["image_generation"],
})
}));
}
if let Some(audio) = &state.audio {
data.extend(audio.provider.models().into_iter().map(|m| {
serde_json::json!({
"display_name": m.id,
"id": m.id,
"object": "model",
"created": created,
"owned_by": "turbospark",
"capabilities": [m.task.as_str()],
})
}));
}
Json(serde_json::json!({
"object": "list",
"data": data,
}))
.into_response()
}
pub async fn model_detail(
State(state): State<crate::ServerState>,
Path(model_id): Path<String>,
) -> Response {
if let Some((id, max_context)) = state.registry.rows().into_iter().find_map(|row| {
let max_context = row.max_context;
row.ids()
.find(|id| *id == model_id)
.map(|id| (id.to_string(), max_context))
}) {
Json(serde_json::json!({
"id": id,
"object": "model",
"created": now_unix(),
"owned_by": "mference",
"context_window": max_context,
}))
.into_response()
} else if state
.image_provider
.as_ref()
.is_some_and(|provider| provider.models().contains(&model_id))
{
Json(serde_json::json!({
"id": model_id,
"object": "model",
"created": now_unix(),
"owned_by": "turbospark",
"capabilities": ["image_generation"],
}))
.into_response()
} else {
(
axum::http::StatusCode::NOT_FOUND,
Json(serde_json::json!({
"error": {
"message": format!("The model '{model_id}' does not exist"),
"type": "invalid_request_error",
"param": "model",
"code": "model_not_found"
}
})),
)
.into_response()
}
}
pub async fn chat_completions(
State(state): State<crate::ServerState>,
tag: Option<axum::Extension<crate::observe::RequestTag>>,
lease_slot: axum::Extension<RequestLeaseSlot>,
Json(request): Json<ChatCompletionRequest>,
) -> Response {
let model = match resolve_backend(
&state,
&lease_slot.0,
tag.map(|t| t.0),
Some(request.model.as_str()),
request.stream.unwrap_or(false),
)
.await
{
Ok(m) => m,
Err(response) => return response,
};
let planned = match plan(&model, &request) {
Ok(p) => p,
Err(e) => return error_response(axum::http::StatusCode::BAD_REQUEST, e),
};
let (prompt_ids, config, images, dropped_images) = (
planned.prompt_ids,
planned.config,
planned.images,
planned.dropped_images,
);
let tools = tool_names(&request);
let effort = reasoning_effort(&request, model.default_reasoning())
.unwrap_or_else(|_| model.default_reasoning());
let include_usage = request
.stream_options
.as_ref()
.map(|o| o.include_usage)
.unwrap_or(false);
let degraded = merge_degradation(openai_request_warnings(&request), dropped_images);
let cancel = crate::cancel::new_cancel();
let mut response = if request.stream.unwrap_or(false) {
stream_response(
model,
prompt_ids,
config,
images,
tools,
effort,
&request,
include_usage,
cancel,
)
} else {
let mut guard = crate::cancel::CancelGuard::new(cancel.clone());
let result = run_guarded(model, &request, effort, cancel).await;
guard.defuse();
let generated = match result {
Ok(r) => r,
Err(e) => return gen_error_response(e),
};
Json(completion_response(
request_id("chatcmpl-"),
now_unix(),
request.model,
generated.text,
generated.reasoning,
generated.calls,
generated.decode.reason,
generated.decode.prompt_tokens as u32,
generated.decode.new_tokens as u32,
))
.into_response()
};
if let Some(note) = degraded.and_then(|v| v.parse().ok()) {
response
.headers_mut()
.insert(crate::DEGRADATION_HEADER, note);
}
response
}
#[allow(clippy::too_many_arguments)]
fn stream_response(
model: AppState,
prompt_ids: Vec<foundation::TokenId>,
config: GenerationConfig,
images: Option<crate::vision::RequestImages>,
tools: HashSet<String>,
effort: ReasoningEffort,
request: &ChatCompletionRequest,
include_usage: bool,
cancel: crate::cancel::Cancel,
) -> Response {
if !tools.is_empty() && model.guardrails().active() {
return buffered_stream_response(model, request.clone(), effort, include_usage, cancel);
}
let model_name = request.model.clone();
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<Event>();
let id = request_id("chatcmpl-");
let created = now_unix();
let cancel_for_task = cancel.clone();
let gate = model.generation_queue();
let cancel_for_gate = cancel.clone();
tokio::spawn(async move {
let _ = crate::queue::run_gated(gate, &cancel_for_gate, move || {
let send = |chunk: anyllm_translate::openai::streaming::ChatCompletionChunk| {
if tx
.send(Event::default().data(serde_json::to_string(&chunk).unwrap_or_default()))
.is_err()
{
cancel_for_task.store(true, std::sync::atomic::Ordering::Relaxed);
}
};
send(completion_chunk(
id.clone(),
created,
model_name.clone(),
role_delta(),
None,
));
let mut call_index = 0u32;
let flag = crate::cancel::as_cancel_flag(&cancel_for_task);
let result = stream_blocking(
&model,
&prompt_ids,
&config,
images.as_ref(),
&tools,
effort,
&flag,
&mut |piece| {
let delta = match piece {
Piece::Text(text) => text_delta(text),
Piece::Reasoning(text) => reasoning_delta(text),
Piece::Tool(call) => {
call_index += 1;
tool_call_delta(call_index - 1, call)
}
};
send(completion_chunk(
id.clone(),
created,
model_name.clone(),
delta,
None,
));
},
);
match result {
Ok((r, _)) if r.reason == runtime::StopReason::Cancelled => return,
Ok((r, _)) => {
send(completion_chunk(
id.clone(),
created,
model_name.clone(),
Default::default(),
Some(crate::response::finish_reason_for(r.reason, call_index > 0)),
));
if include_usage {
send(crate::response::usage_chunk(
id.clone(),
created,
model_name.clone(),
r.prompt_tokens as u32,
r.new_tokens as u32,
));
}
}
Err(e) => {
let body = serde_json::json!({
"error": {"message": e.to_string(), "type": "server_error"}
});
let _ = tx.send(Event::default().event("error").data(body.to_string()));
return;
}
}
let _ = tx.send(Event::default().data("[DONE]"));
})
.await;
});
let stream: std::pin::Pin<
Box<dyn Stream<Item = Result<Event, std::convert::Infallible>> + Send>,
> = Box::pin(
crate::cancel::CancelOnDrop::new(
tokio_stream::wrappers::UnboundedReceiverStream::new(rx),
cancel,
)
.map(Ok),
);
Sse::new(stream)
.keep_alive(KeepAlive::new().interval(SSE_KEEP_ALIVE))
.into_response()
}
fn buffered_stream_response(
model: AppState,
request: ChatCompletionRequest,
effort: ReasoningEffort,
include_usage: bool,
cancel: crate::cancel::Cancel,
) -> Response {
let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<Event>();
let id = request_id("chatcmpl-");
let created = now_unix();
let model_name = request.model.clone();
let cancel_for_stream = cancel.clone();
tokio::spawn(async move {
let send = |chunk: anyllm_translate::openai::streaming::ChatCompletionChunk| {
let _ =
tx.send(Event::default().data(serde_json::to_string(&chunk).unwrap_or_default()));
};
let chunk = |delta, finish| {
completion_chunk(id.clone(), created, model_name.clone(), delta, finish)
};
match run_guarded(model, &request, effort, cancel).await {
Ok(generated) if generated.decode.reason == runtime::StopReason::Cancelled => return,
Ok(generated) => {
send(chunk(role_delta(), None));
if !generated.reasoning.is_empty() {
send(chunk(reasoning_delta(generated.reasoning), None));
}
if !generated.text.is_empty() {
send(chunk(text_delta(generated.text), None));
}
let has_calls = !generated.calls.is_empty();
for (index, call) in generated.calls.into_iter().enumerate() {
send(chunk(tool_call_delta(index as u32, call), None));
}
send(chunk(
Default::default(),
Some(crate::response::finish_reason_for(
generated.decode.reason,
has_calls,
)),
));
if include_usage {
send(crate::response::usage_chunk(
id.clone(),
created,
model_name.clone(),
generated.decode.prompt_tokens as u32,
generated.decode.new_tokens as u32,
));
}
}
Err(e) => {
let message = match e {
GenError::Runtime(e) => e.to_string(),
GenError::Join(m) => m,
};
let body = serde_json::json!({
"error": {"message": message, "type": "server_error"}
});
let _ = tx.send(Event::default().event("error").data(body.to_string()));
return;
}
}
let _ = tx.send(Event::default().data("[DONE]"));
});
let stream: std::pin::Pin<
Box<dyn Stream<Item = Result<Event, std::convert::Infallible>> + Send>,
> = Box::pin(
crate::cancel::CancelOnDrop::new(
tokio_stream::wrappers::UnboundedReceiverStream::new(rx),
cancel_for_stream,
)
.map(Ok),
);
Sse::new(stream)
.keep_alive(KeepAlive::new().interval(SSE_KEEP_ALIVE))
.into_response()
}