use crate::models::field_names;
use axum::{
Json,
extract::State,
http::{HeaderMap, StatusCode},
response::{IntoResponse, Response},
};
use serde_json::json;
#[cfg(feature = "sal")]
use super::store_err_to_response;
use super::{AppState, JsonOrBadRequest};
use crate::mcp::{MemoryCaptureTurnRequest, prepare_capture_turn};
fn capture_turn_ok(result: &crate::models::CaptureTurnResult, attest_level: &str) -> Response {
if result.dedup_hit {
(
StatusCode::OK,
Json(json!({
"memory_id": result.memory_id,
"dedup_hit": true,
"layer": "L4",
})),
)
.into_response()
} else {
(
StatusCode::CREATED,
Json(json!({
"memory_id": result.memory_id,
"dedup_hit": false,
"layer": "L4",
(field_names::ATTEST_LEVEL): attest_level,
})),
)
.into_response()
}
}
pub async fn capture_turn(
State(app): State<AppState>,
headers: HeaderMap,
JsonOrBadRequest(req): JsonOrBadRequest<MemoryCaptureTurnRequest>,
) -> impl IntoResponse {
let header_agent_id = headers
.get(crate::HEADER_AGENT_ID)
.and_then(|v| v.to_str().ok());
let agent_id = match crate::identity::resolve_http_agent_id(None, header_agent_id) {
Ok(c) => c,
Err(e) => {
return (
StatusCode::BAD_REQUEST,
Json(json!({ "error": e.to_string() })),
)
.into_response();
}
};
let write = match prepare_capture_turn(&req, &agent_id) {
Ok(w) => w,
Err(msg) => {
return (StatusCode::BAD_REQUEST, Json(json!({ "error": msg }))).into_response();
}
};
let attest_level = write.signed_event.attest_level.clone();
#[cfg(feature = "sal")]
let response = {
let ctx = crate::store::CallerContext::for_agent(agent_id);
match app.store.capture_turn_idempotent(&ctx, &write).await {
Ok(result) => capture_turn_ok(&result, &attest_level),
Err(e) => store_err_to_response(e),
}
};
#[cfg(not(feature = "sal"))]
let response = {
let state = app.db.clone();
let lock = state.lock().await;
match crate::storage::capture_turn_idempotent(&lock.0, &write) {
Ok(result) => capture_turn_ok(&result, &attest_level),
Err(msg) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({ "error": msg })),
)
.into_response(),
}
};
response
}