crw_server/routes/
capabilities.rs1use axum::Json;
9use axum::extract::State;
10use serde::Serialize;
11
12use crate::state::AppState;
13
14#[derive(Debug, Serialize)]
15#[serde(rename_all = "camelCase")]
16pub struct Capabilities {
17 pub version: &'static str,
18 pub llm: LlmCapabilities,
19 pub formats: FormatCapabilities,
20 pub search: SearchCapabilities,
21}
22
23#[derive(Debug, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub struct LlmCapabilities {
26 pub providers: Vec<&'static str>,
28 pub supports_base_url: bool,
29 pub server_key_configured: bool,
33 pub max_concurrency: usize,
36 #[serde(skip_serializing_if = "Option::is_none")]
39 pub require_byok_header: Option<String>,
40}
41
42#[derive(Debug, Serialize)]
43#[serde(rename_all = "camelCase")]
44pub struct FormatCapabilities {
45 pub supported: Vec<&'static str>,
46 pub change_tracking_modes: Vec<&'static str>,
50}
51
52#[derive(Debug, Serialize)]
53#[serde(rename_all = "camelCase")]
54pub struct SearchCapabilities {
55 pub answer: bool,
56 pub summarize_results: bool,
57}
58
59pub async fn capabilities(State(state): State<AppState>) -> Json<Capabilities> {
60 let llm_cfg = state.config.extraction.llm.as_ref();
61 Json(Capabilities {
62 version: env!("CARGO_PKG_VERSION"),
63 llm: LlmCapabilities {
64 providers: vec![
65 "anthropic",
66 "openai",
67 "deepseek",
68 "openai-compatible",
69 "azure",
70 ],
71 supports_base_url: true,
72 server_key_configured: llm_cfg.map(|c| !c.api_key.is_empty()).unwrap_or(false),
73 max_concurrency: llm_cfg.map(|c| c.max_concurrency).unwrap_or(0),
74 require_byok_header: llm_cfg.and_then(|c| c.require_byok_header.clone()),
75 },
76 formats: FormatCapabilities {
77 supported: vec![
78 "markdown",
79 "html",
80 "rawHtml",
81 "plainText",
82 "links",
83 "json",
84 "summary",
85 "changeTracking",
86 ],
87 change_tracking_modes: vec!["gitDiff", "json"],
88 },
89 search: SearchCapabilities {
90 answer: true,
91 summarize_results: true,
92 },
93 })
94}