use axiom_engine::anthropic_forwarder::AnthropicForwarder;
use axiom_engine::config::AxiomConfig;
use axiom_engine::context_compressor::CompressorConfig;
use axiom_engine::inference::InferencePipeline;
use axiom_engine::server::{create_router, AppState};
use axum::body::{to_bytes, Body};
use axum::extract::State;
use axum::http::{Method, Request, StatusCode};
use axum::routing::post;
use axum::{Json, Router};
use candle_core::Device;
use serde_json::{json, Value};
use std::sync::{Arc, Mutex, OnceLock};
use tokio::sync::Mutex as AsyncMutex;
use tower::ServiceExt;
fn env_lock() -> &'static AsyncMutex<()> {
static LOCK: OnceLock<AsyncMutex<()>> = OnceLock::new();
LOCK.get_or_init(|| AsyncMutex::new(()))
}
#[derive(Clone, Default)]
struct Capture {
requests: Arc<Mutex<Vec<Value>>>,
}
fn tiny_pipeline() -> InferencePipeline {
let config = AxiomConfig {
d_model: 16,
n_layers: 1,
vocab_size: 64,
lr_inner: 1e-3,
norm_eps: 1e-6,
};
InferencePipeline::new(config, Device::Cpu).expect("pipeline init")
}
async fn start_capturing_upstream() -> (String, Capture, tokio::task::JoinHandle<()>) {
async fn handler(State(capture): State<Capture>, Json(body): Json<Value>) -> Json<Value> {
capture.requests.lock().unwrap().push(body);
Json(json!({
"id": "msg_test",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-5",
"content": [{"type": "text", "text": "ok"}],
"stop_reason": "end_turn",
"usage": {"input_tokens": 10, "output_tokens": 5}
}))
}
let capture = Capture::default();
let app = Router::new()
.route("/v1/messages", post(handler))
.with_state(capture.clone());
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let address = listener.local_addr().unwrap();
let task = tokio::spawn(async move { axum::serve(listener, app).await.unwrap() });
(format!("http://{address}"), capture, task)
}
async fn build_state(upstream: String) -> AppState {
let pipeline = tokio::task::spawn_blocking(tiny_pipeline).await.unwrap();
AppState::new(pipeline, "axiom-ttt-test".to_string())
.with_anthropic_forwarder(Some(AnthropicForwarder::new(None, Some(upstream))))
.with_compressor_config(CompressorConfig {
heavy_message_threshold_tokens: 5,
recall_top_k: 8,
enabled: true,
})
}
async fn post_messages(app: &Router, body: Value) -> StatusCode {
let req = Request::builder()
.method(Method::POST)
.uri("/v1/messages")
.header("content-type", "application/json")
.header("x-api-key", "sk-ant-test-key")
.body(Body::from(body.to_string()))
.unwrap();
let resp = app.clone().oneshot(req).await.unwrap();
let status = resp.status();
let _ = to_bytes(resp.into_body(), usize::MAX).await.unwrap();
status
}
const HEAVY_TEXT: &str =
"This paragraph is deliberately long padded content well past a five token heavy threshold for cache safety boundary testing purposes only repeated words repeated words repeated words";
#[tokio::test]
async fn frozen_prefix_content_is_never_compressed_mutable_tail_is() {
let _guard = env_lock().lock().await;
let (upstream, capture, _task) = start_capturing_upstream().await;
let state = build_state(upstream).await;
let app = create_router(state);
let session_id = "cache-safety-breakpoint";
let body = json!({
"model": "claude-sonnet-5",
"max_tokens": 16,
"session_id": session_id,
"messages": [
{"role": "user", "content": "short user turn zero"},
{"role": "assistant", "content": "short assistant reply one"},
{"role": "user", "content": HEAVY_TEXT},
{"role": "assistant", "content": [
{"type": "text", "text": "short assistant reply three",
"cache_control": {"type": "ephemeral"}}
]},
{"role": "user", "content": "short user turn four"},
{"role": "user", "content": HEAVY_TEXT},
],
});
let status = post_messages(&app, body).await;
assert_eq!(status, StatusCode::OK);
let captured = capture.requests.lock().unwrap();
assert_eq!(captured.len(), 1);
let sent = &captured[0];
let sent_messages = sent["messages"].as_array().unwrap();
let sent_json = serde_json::to_string(sent_messages).unwrap();
assert!(
sent_json.contains(HEAVY_TEXT),
"frozen-prefix heavy content must survive verbatim in the outbound payload"
);
let occurrences = sent_json.matches(HEAVY_TEXT).count();
assert_eq!(
occurrences, 1,
"only the frozen-prefix occurrence of the heavy text should survive verbatim; \
the mutable-tail occurrence should have been compressed away, got {occurrences} occurrences"
);
}
#[tokio::test]
async fn empty_mutable_tail_never_gains_a_phantom_carrier_turn() {
let _guard = env_lock().lock().await;
let (upstream, capture, _task) = start_capturing_upstream().await;
let state = build_state(upstream).await;
let app = create_router(state);
let body = json!({
"model": "claude-sonnet-5",
"max_tokens": 16,
"session_id": "cache-safety-empty-tail",
"messages": [
{"role": "user", "content": "hello"},
{"role": "system", "content": [],
"output_config": {"effort": "low"},
"cache_control": {"type": "ephemeral"}},
],
});
let status = post_messages(&app, body).await;
assert_eq!(status, StatusCode::OK);
let captured = capture.requests.lock().unwrap();
let sent_messages = captured[0]["messages"].as_array().unwrap();
assert_eq!(
sent_messages.len(), 2,
"no phantom carrier turn: exactly the original 2 messages, got {sent_messages:?}"
);
assert_eq!(sent_messages[0]["role"], json!("user"));
assert_eq!(sent_messages[1]["role"], json!("system"), "system message must end the array");
}
#[tokio::test]
async fn identical_mutable_tail_produces_byte_identical_outbound_messages() {
let _guard = env_lock().lock().await;
let (upstream, capture, _task) = start_capturing_upstream().await;
let state = build_state(upstream).await;
let app = create_router(state);
let session_id = "cache-safety-determinism";
let body = json!({
"model": "claude-sonnet-5",
"max_tokens": 16,
"session_id": session_id,
"messages": [
{"role": "user", "content": [
{"type": "text", "text": "stable prior turn",
"cache_control": {"type": "ephemeral"}}
]},
{"role": "user", "content": HEAVY_TEXT},
],
});
let s1 = post_messages(&app, body.clone()).await;
assert_eq!(s1, StatusCode::OK);
let s2 = post_messages(&app, body).await;
assert_eq!(s2, StatusCode::OK);
let captured = capture.requests.lock().unwrap();
assert_eq!(captured.len(), 2);
let messages_1 = serde_json::to_string(&captured[0]["messages"]).unwrap();
let messages_2 = serde_json::to_string(&captured[1]["messages"]).unwrap();
assert_eq!(
messages_1, messages_2,
"identical mutable-tail input must produce byte-identical outbound messages"
);
}
struct EnvVarGuard(&'static str);
impl Drop for EnvVarGuard {
fn drop(&mut self) {
std::env::remove_var(self.0);
}
}
#[tokio::test]
async fn cache_safe_disabled_falls_back_to_prior_behavior() {
let _guard = env_lock().lock().await;
std::env::set_var("AXIOM_CACHE_SAFE", "0");
let _env_cleanup = EnvVarGuard("AXIOM_CACHE_SAFE");
let (upstream, capture, _task) = start_capturing_upstream().await;
let state = build_state(upstream).await;
let app = create_router(state);
let body = json!({
"model": "claude-sonnet-5",
"max_tokens": 16,
"session_id": "cache-safety-disabled",
"messages": [
{"role": "user", "content": [
{"type": "text", "text": "x", "cache_control": {"type": "ephemeral"}}
]},
{"role": "user", "content": HEAVY_TEXT},
],
});
let status = post_messages(&app, body).await;
assert_eq!(status, StatusCode::OK);
assert_eq!(capture.requests.lock().unwrap().len(), 1);
}