link-assistant-router 1.10.1

Link.Assistant.Router — Claude MAX OAuth proxy and token gateway for Anthropic APIs
Documentation
use std::collections::HashSet;

use axum::http::StatusCode;
use serde_json::{Map, Value, json};

const MAX_ANTHROPIC_PAGE: usize = 1_000;
const DEFAULT_ANTHROPIC_PAGE: usize = 20;

pub(super) fn project(
    path: &str,
    query: Option<&str>,
    catalog: &Value,
) -> Result<Option<Value>, NativeCatalogError> {
    let data = catalog
        .get("data")
        .and_then(Value::as_array)
        .ok_or_else(|| NativeCatalogError::internal("model catalog has no data array"))?;
    if path == "/api/services/anthropic/v1/models" {
        return anthropic(data, query).map(Some);
    }
    if matches!(
        path,
        "/api/services/openai/v1/models"
            | "/api/services/codex/v1/models"
            | "/api/services/qwen/v1/models"
    ) {
        return Ok(Some(openai(data)?));
    }
    Ok(None)
}

fn anthropic(data: &[Value], query: Option<&str>) -> Result<Value, NativeCatalogError> {
    let models = deduplicated(data, anthropic_model)?;
    let page = AnthropicPage::parse(query, &models)?;
    let visible = models[page.start..page.end].to_vec();
    let first_id = visible.first().and_then(|model| model.get("id")).cloned();
    let last_id = visible.last().and_then(|model| model.get("id")).cloned();
    Ok(json!({
        "data": visible,
        "first_id": first_id,
        "has_more": page.has_more,
        "last_id": last_id,
    }))
}

fn openai(data: &[Value]) -> Result<Value, NativeCatalogError> {
    Ok(json!({
        "object": "list",
        "data": deduplicated(data, openai_model)?,
    }))
}

fn deduplicated(
    data: &[Value],
    project: fn(&Map<String, Value>, &str) -> Map<String, Value>,
) -> Result<Vec<Value>, NativeCatalogError> {
    let mut seen = HashSet::new();
    let mut models = Vec::with_capacity(data.len());
    for value in data {
        let Some(raw) = value.as_object() else {
            continue;
        };
        let Some(id) = raw.get("id").and_then(Value::as_str) else {
            continue;
        };
        if id.is_empty() {
            continue;
        }
        if !seen.insert(id.to_string()) {
            return Err(NativeCatalogError::conflict(format!(
                "exact model id '{id}' is advertised more than once"
            )));
        }
        models.push(Value::Object(project(raw, id)));
    }
    Ok(models)
}

fn anthropic_model(raw: &Map<String, Value>, id: &str) -> Map<String, Value> {
    let mut model = Map::from_iter([
        ("id".into(), Value::String(id.to_string())),
        ("type".into(), Value::String("model".into())),
    ]);
    copy_string(raw, &mut model, "display_name");
    copy_string(raw, &mut model, "created_at");
    copy_number(raw, &mut model, "max_input_tokens");
    copy_number(raw, &mut model, "max_tokens");
    if let Some(capabilities) = raw.get("capabilities").and_then(Value::as_object) {
        model.insert("capabilities".into(), Value::Object(capabilities.clone()));
    }
    model
}

fn openai_model(raw: &Map<String, Value>, id: &str) -> Map<String, Value> {
    let mut model = Map::from_iter([
        ("id".into(), Value::String(id.to_string())),
        ("object".into(), Value::String("model".into())),
    ]);
    copy_number(raw, &mut model, "created");
    copy_string(raw, &mut model, "owned_by");
    model
}

fn copy_string(source: &Map<String, Value>, target: &mut Map<String, Value>, key: &str) {
    if let Some(value) = source.get(key).filter(|value| value.is_string()) {
        target.insert(key.to_string(), value.clone());
    }
}

fn copy_number(source: &Map<String, Value>, target: &mut Map<String, Value>, key: &str) {
    if let Some(value) = source.get(key).filter(|value| value.is_number()) {
        target.insert(key.to_string(), value.clone());
    }
}

struct AnthropicPage {
    start: usize,
    end: usize,
    has_more: bool,
}

impl AnthropicPage {
    fn parse(query: Option<&str>, models: &[Value]) -> Result<Self, NativeCatalogError> {
        let mut after_id = None;
        let mut before_id = None;
        let mut limit = None;
        for (key, value) in url::form_urlencoded::parse(query.unwrap_or_default().as_bytes()) {
            match key.as_ref() {
                "after_id" => set_once(&mut after_id, value.into_owned(), "after_id")?,
                "before_id" => set_once(&mut before_id, value.into_owned(), "before_id")?,
                "limit" => set_once(&mut limit, value.into_owned(), "limit")?,
                _ => {}
            }
        }
        if after_id.is_some() && before_id.is_some() {
            return Err(NativeCatalogError::invalid(
                "after_id and before_id cannot be used together",
            ));
        }
        let limit = limit.map_or(Ok(DEFAULT_ANTHROPIC_PAGE), |limit| {
            limit
                .parse::<usize>()
                .ok()
                .filter(|limit| (1..=MAX_ANTHROPIC_PAGE).contains(limit))
                .ok_or_else(|| NativeCatalogError::invalid("limit must be between 1 and 1000"))
        })?;
        let id_at = |wanted: &str| {
            if wanted.is_empty() {
                return None;
            }
            models
                .iter()
                .position(|model| model.get("id").and_then(Value::as_str) == Some(wanted))
        };
        if let Some(before) = before_id {
            let cursor = id_at(&before).ok_or_else(|| {
                NativeCatalogError::invalid(format!("before_id cursor '{before}' was not found"))
            })?;
            let start = cursor.saturating_sub(limit);
            return Ok(Self {
                start,
                end: cursor,
                has_more: start > 0,
            });
        }
        let start = after_id.map_or(Ok(0), |after| {
            id_at(&after).map(|cursor| cursor + 1).ok_or_else(|| {
                NativeCatalogError::invalid(format!("after_id cursor '{after}' was not found"))
            })
        })?;
        let end = start.saturating_add(limit).min(models.len());
        Ok(Self {
            start,
            end,
            has_more: end < models.len(),
        })
    }
}

fn set_once(
    target: &mut Option<String>,
    value: String,
    name: &str,
) -> Result<(), NativeCatalogError> {
    if target.replace(value).is_some() {
        return Err(NativeCatalogError::invalid(format!(
            "{name} may be supplied only once"
        )));
    }
    Ok(())
}

#[derive(Debug)]
pub(super) struct NativeCatalogError {
    pub status: StatusCode,
    pub error_type: &'static str,
    pub message: String,
}

impl NativeCatalogError {
    fn invalid(message: impl Into<String>) -> Self {
        Self {
            status: StatusCode::BAD_REQUEST,
            error_type: "invalid_request_error",
            message: message.into(),
        }
    }

    fn conflict(message: impl Into<String>) -> Self {
        Self {
            status: StatusCode::CONFLICT,
            error_type: "invalid_provider_state",
            message: message.into(),
        }
    }

    fn internal(message: impl Into<String>) -> Self {
        Self {
            status: StatusCode::INTERNAL_SERVER_ERROR,
            error_type: "api_error",
            message: message.into(),
        }
    }
}

#[cfg(test)]
#[path = "model_routing_native_catalog_tests.rs"]
mod tests;