From dafec2591bc0c4a7d7a4796b7fd9db2ffc64ac10 Mon Sep 17 00:00:00 2001 From: oabrivard Date: Tue, 24 Mar 2026 20:35:15 +0100 Subject: [PATCH] feat: API endpoint for LLM call logs by job_id Co-Authored-By: Claude Sonnet 4.6 --- backend/src/handlers/llm_logs.rs | 37 ++++++++++++++++++++++++++++++++ backend/src/handlers/mod.rs | 1 + backend/src/router.rs | 2 ++ 3 files changed, 40 insertions(+) create mode 100644 backend/src/handlers/llm_logs.rs diff --git a/backend/src/handlers/llm_logs.rs b/backend/src/handlers/llm_logs.rs new file mode 100644 index 0000000..f5d5b09 --- /dev/null +++ b/backend/src/handlers/llm_logs.rs @@ -0,0 +1,37 @@ +//! Handler for LLM call log viewing. + +use axum::extract::{Path, State}; +use axum::response::IntoResponse; +use axum::Json; +use uuid::Uuid; + +use crate::app_state::AppState; +use crate::db; +use crate::errors::AppError; +use crate::middleware::auth::AuthUser; + +/// GET /api/v1/llm-logs/:job_id +/// +/// Returns all LLM call log entries for a generation job. +pub async fn get_logs( + auth_user: AuthUser, + State(state): State, + Path(job_id): Path, +) -> Result { + // Verify the job_id belongs to a synthesis owned by this user + let synthesis = sqlx::query_scalar::<_, Uuid>( + "SELECT id FROM syntheses WHERE job_id = $1 AND user_id = $2 LIMIT 1", + ) + .bind(job_id) + .bind(auth_user.id) + .fetch_optional(&state.pool) + .await?; + + if synthesis.is_none() { + return Err(AppError::NotFound("No synthesis found for this job".into())); + } + + let logs = db::llm_call_log::list_by_job_id(&state.pool, auth_user.id, job_id).await?; + + Ok(Json(logs)) +} diff --git a/backend/src/handlers/mod.rs b/backend/src/handlers/mod.rs index 2bae72d..fd059f2 100644 --- a/backend/src/handlers/mod.rs +++ b/backend/src/handlers/mod.rs @@ -5,6 +5,7 @@ pub mod auth; pub mod config; pub mod generation; pub mod health; +pub mod llm_logs; pub mod settings; pub mod sources; pub mod syntheses; diff --git a/backend/src/router.rs b/backend/src/router.rs index 31f2f47..589cf8b 100644 --- a/backend/src/router.rs +++ b/backend/src/router.rs @@ -57,6 +57,8 @@ pub fn build_router(state: AppState, config: &AppConfig) -> Router { // Article history & provenance routes (authenticated) .route("/article-history", get(handlers::article_history::list_history)) .route("/syntheses/{id}/provenance", get(handlers::article_history::get_provenance)) + // LLM call log routes (authenticated) + .route("/llm-logs/{job_id}", get(handlers::llm_logs::get_logs)) // Syntheses CRUD routes (authenticated) .route("/syntheses", get(handlers::syntheses::list)) .route("/syntheses/{id}", get(handlers::syntheses::get))