fn patch_store_path(state: &AppState) -> Option<PathBuf> {
(*state.heal_memory_path)
.as_ref()
.map(|p| p.with_file_name("axiom_patch_memory.json"))
}
async fn get_patches(State(state): State<AppState>) -> Response {
let Some(path) = patch_store_path(&state) else {
return (
StatusCode::SERVICE_UNAVAILABLE,
Json(serde_json::json!({"error": "patch memory not configured on this node"})),
)
.into_response();
};
let memory = crate::patch_memory::PatchMemory::load(&path);
let signed = memory.export_signed(fleet_key().as_deref());
Json(signed).into_response()
}
async fn post_patches_merge(State(state): State<AppState>, body: String) -> Response {
let Some(path) = patch_store_path(&state) else {
return (
StatusCode::SERVICE_UNAVAILABLE,
Json(serde_json::json!({"error": "patch memory not configured on this node"})),
)
.into_response();
};
let export: crate::provenance::SignedExport = match serde_json::from_str(&body) {
Ok(e) => e,
Err(_) => {
return (
StatusCode::BAD_REQUEST,
Json(serde_json::json!({
"error": "expected a signed patch export (the GET /v1/patches payload)"
})),
)
.into_response();
}
};
let mut memory = crate::patch_memory::PatchMemory::load(&path);
match memory.merge_signed_guarded(
&export,
fleet_key().as_deref(),
crate::patch_memory::FleetTrustPolicy::robust(),
) {
Ok(report) => {
if let Err(e) = memory.save(&path) {
return (
StatusCode::INTERNAL_SERVER_ERROR,
Json(serde_json::json!({
"error": format!("merge succeeded but save failed: {e}")
})),
)
.into_response();
}
Json(serde_json::json!({
"merged": true,
"new_candidates": report.new_candidates,
"reinforced": report.reinforced,
"byzantine_rejected": report.byzantine_rejected,
}))
.into_response()
}
Err(e) => (
StatusCode::UNAUTHORIZED,
Json(serde_json::json!({"error": format!("provenance rejected: {e}")})),
)
.into_response(),
}
}
#[cfg(feature = "experimental")]
async fn post_chimera_run(State(state): State<AppState>, body: String) -> axum::response::Response {
use axum::response::IntoResponse;
let source = match serde_json::from_str::<serde_json::Value>(&body) {
Ok(v) => v
.get("source")
.and_then(|s| s.as_str())
.map(|s| s.to_string()),
Err(_) => None,
};
let Some(source) = source else {
return (
StatusCode::BAD_REQUEST,
Json(serde_json::json!({"error": "expected JSON body {\"source\": \"...\"}"})),
)
.into_response();
};
let result = if state.router.is_some() {
let router_arc = state.router.clone();
let src = source.clone();
tokio::task::spawn_blocking(move || {
let router = router_arc.as_ref().as_ref().unwrap();
let adapter = crate::chimera::RouterAdapter { router };
crate::chimera::run_source(&src, Some(&adapter))
})
.await
.unwrap_or_else(|e| Err(format!("chimera execution task panicked: {e}")))
} else {
crate::chimera::run_source(&source, None)
};
match result {
Ok(res) => Json(serde_json::json!({
"emitted": res.emitted,
"beliefs": res.beliefs,
"guard_violations": res.guard_violations,
"trace": res.trace,
}))
.into_response(),
Err(e) => (
StatusCode::UNPROCESSABLE_ENTITY,
Json(serde_json::json!({"error": e})),
)
.into_response(),
}
}
fn mcp_unauthorized(state: &AppState, headers: &axum::http::HeaderMap) -> Option<Response> {
use axum::response::IntoResponse;
let expected = state.mcp_token.as_ref().as_ref()?; let presented = headers
.get(axum::http::header::AUTHORIZATION)
.and_then(|v| v.to_str().ok())
.and_then(|v| {
v.strip_prefix("Bearer ")
.or_else(|| v.strip_prefix("bearer "))
})
.map(str::trim);
if presented == Some(expected.as_str()) {
None
} else {
Some(
(
StatusCode::UNAUTHORIZED,
Json(serde_json::json!({
"error": "missing or invalid bearer token for /mcp (set Authorization: Bearer <AXIOM_MCP_TOKEN>)"
})),
)
.into_response(),
)
}
}
async fn post_mcp(
State(state): State<AppState>,
headers: axum::http::HeaderMap,
body: String,
) -> axum::response::Response {
use axum::response::IntoResponse;
if let Some(resp) = mcp_unauthorized(&state, &headers) {
return resp;
}
let ctx = match state.mcp.as_ref() {
Some(c) => c,
None => {
return (
StatusCode::SERVICE_UNAVAILABLE,
Json(serde_json::json!({
"error": "MCP HTTP transport disabled; start the server with AXIOM_MCP_HTTP=1"
})),
)
.into_response();
}
};
match crate::mcp_stdio::dispatch(&body, ctx).await {
Some(resp) => Json(resp).into_response(),
None => StatusCode::ACCEPTED.into_response(),
}
}
async fn mcp_http_sse(
State(state): State<AppState>,
headers: axum::http::HeaderMap,
) -> axum::response::Response {
use axum::response::IntoResponse;
if let Some(resp) = mcp_unauthorized(&state, &headers) {
return resp;
}
if state.mcp.is_none() {
return (
StatusCode::SERVICE_UNAVAILABLE,
"MCP HTTP transport disabled; start the server with AXIOM_MCP_HTTP=1",
)
.into_response();
}
let keepalive = stream::pending::<Result<Event, std::convert::Infallible>>();
Sse::new(keepalive)
.keep_alive(KeepAlive::default())
.into_response()
}
fn level_to_threshold(level: &str) -> Option<usize> {
match level.to_ascii_lowercase().as_str() {
"high" => Some(80), "medium" => Some(200), "low" => Some(400), _ => None,
}
}
fn threshold_to_level(t: usize) -> &'static str {
if t <= 120 {
"high"
} else if t <= 300 {
"medium"
} else {
"low"
}
}
async fn post_budget(
State(state): State<AppState>,
Json(body): Json<BudgetRequest>,
) -> impl IntoResponse {
let id = body.session_id.as_deref().unwrap_or("global");
let awareness = state.awareness.get_or_create(id);
awareness.set_budget(body.remaining_tokens, body.model.clone());
if let Some(target) = awareness.compression_target_tokens() {
let current = state.controls.threshold();
if target < current {
state.controls.set_threshold(target);
}
}
Json(serde_json::json!({
"ok": true,
"session_id": id,
"remaining_tokens": body.remaining_tokens,
"compression_threshold_tokens": state.controls.threshold(),
"model": body.model,
}))
}
async fn get_awareness(State(state): State<AppState>, Path(id): Path<String>) -> impl IntoResponse {
match state.awareness.get(&id) {
None => (
StatusCode::NOT_FOUND,
Json(serde_json::json!({ "error": "no awareness state for session", "id": id })),
)
.into_response(),
Some(a) => {
let (requests, msgs, bytes_in, bytes_out) = state.controls.counters();
let cost = a.cost_summary();
Json(serde_json::json!({
"session_id": id,
"budget_remaining": a.budget(),
"target_model": a.target_model.lock().ok().and_then(|g| g.clone()),
"tokens_spent_on_axiom": a.tokens_spent.load(std::sync::atomic::Ordering::Relaxed),
"tool_calls_total": a.tool_calls_total.load(std::sync::atomic::Ordering::Relaxed),
"expansion_calls": a.expansion_calls.load(std::sync::atomic::Ordering::Relaxed),
"compression_ratio": a.compression_ratio(),
"compression_target_tokens": a.compression_target_tokens(),
"is_tight": a.is_tight(),
"recommendation": a.recommendation(),
"cost": {
"usd_total": cost.usd_total,
"usd_uncached_equivalent": cost.usd_uncached_equivalent,
"uncached_input_tokens": cost.uncached_input_tokens,
"cache_write_tokens": cost.cache_write_tokens,
"cache_read_tokens": cost.cache_read_tokens,
"output_tokens": cost.output_tokens,
"cache_hit_rate": cost.cache_hit_rate(),
"estimated": cost.estimated,
},
"local_answers": {
"turns_answered_locally": cost.local_answered_turns,
},
"model_routing": {
"turns_downgraded": cost.routed_turns,
"route_fallbacks": cost.route_fallbacks,
"quota_units_saved": cost.routed_quota_saved_units,
},
"global_counters": {
"requests": requests,
"messages_compressed": msgs,
"bytes_in": bytes_in,
"bytes_out": bytes_out,
},
}))
.into_response()
}
}
}
async fn get_config(State(state): State<AppState>) -> impl IntoResponse {
let (requests, msgs, bytes_in, bytes_out) = state.controls.counters();
let enabled = state.controls.enabled();
let threshold = state.controls.threshold();
let savings_pct = if bytes_in > 0 {
(1.0 - (bytes_out as f64 / bytes_in as f64)) * 100.0
} else {
0.0
};
Json(serde_json::json!({
"enabled": enabled,
"level": if enabled { threshold_to_level(threshold) } else { "off" },
"threshold_tokens": threshold,
"recall_top_k": state.compressor_config.recall_top_k,
"forwarder_ready": state.anthropic_forwarder.is_some(),
"openai_forwarder_ready": state.openai_forwarder.is_some(),
"compression_active": state.compression_active(),
"openai_compression_active": state.openai_compression_active(),
"counters": {
"requests": requests,
"messages_compressed": msgs,
"bytes_in": bytes_in,
"bytes_out": bytes_out,
"savings_pct": (savings_pct * 10.0).round() / 10.0,
"degraded_fallbacks": state.controls.degraded_fallbacks(),
}
}))
}
async fn post_config(State(state): State<AppState>, Json(body): Json<Value>) -> impl IntoResponse {
if let Some(level) = body.get("level").and_then(Value::as_str) {
if level.eq_ignore_ascii_case("off") {
state.controls.set_enabled(false);
} else if let Some(t) = level_to_threshold(level) {
state.controls.set_threshold(t);
state.controls.set_enabled(true);
}
}
if let Some(enabled) = body.get("enabled").and_then(Value::as_bool) {
state.controls.set_enabled(enabled);
}
if let Some(t) = body.get("threshold_tokens").and_then(Value::as_u64) {
state.controls.set_threshold(t as usize);
}
let enabled = state.controls.enabled();
let threshold = state.controls.threshold();
Json(serde_json::json!({
"ok": true,
"enabled": enabled,
"level": if enabled { threshold_to_level(threshold) } else { "off" },
"threshold_tokens": threshold,
"compression_active": state.compression_active(),
"openai_compression_active": state.openai_compression_active(),
}))
}