llm: restore request logging lost in the agent-loop migration
Nightly Build / build (push) Successful in 6m50s
Nightly Build / build (push) Successful in 6m50s
The LLM-requests page has been empty since 24ee5b8: deleting
`session/handler/llm_call.rs` dropped both halves of the request log.
The kernel builds the `ModelRequest` itself and sets `log: None`, so the
`LoggingModel` decorator — wrapped once per model by `LlmManager` — wrote
every metadata row with a NULL `user_id`, while the page (and the detail
endpoint) filter on it. Nothing wrote `llm_request_payloads` at all any
more, so the payload viewer had nothing to show either.
Correlation cannot come from `LlmManager`: it builds one shared client
per model and does not know whose traffic it serves. It now comes from
the `ModelSelector`, the one component that knows both the model and the
owner: `SkaldSelector::with_log(RequestLogTarget)` wraps the model it
hands out, so metadata lands in `llm_requests` attributed to the user and
the payload lands in that user's own encrypted DB, keyed by `request_id`.
Session and frame are read off the request's `conversation`/`frame`,
which makes kernel rounds, sub-agent frames and compaction summaries all
attributed with no extra plumbing (`ModelRequest::log` stays unused).
The compactor's summariser call is attributed too, which it never was:
`try_compact`/`force_compact` now take the owner (its selector is built
per compaction, so it can carry the target).
Three tests in `llm::logging` lock this down — the owner/session/frame
columns, the error row with the provider's rejected body, and the
metadata-only path when no owner pool is available.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,7 +34,6 @@ use std::sync::Arc;
|
||||
use agent_loop::compaction::{CompactionMode, should_compact};
|
||||
use agent_loop::manager::LoopManager;
|
||||
use agent_loop::model::ModelHint;
|
||||
use serde_json::json;
|
||||
use sqlx::SqlitePool;
|
||||
use tracing::{info, warn};
|
||||
|
||||
@@ -45,6 +44,7 @@ use crate::config::CompactionConfig;
|
||||
use crate::config_store::GlobalConfigManager;
|
||||
use crate::db::chat_history;
|
||||
use crate::llm::LlmManager;
|
||||
use crate::llm::logging::RequestLogTarget;
|
||||
use crate::loop_adapters::history::SqliteHistory;
|
||||
use crate::loop_adapters::selector::SkaldSelector;
|
||||
|
||||
@@ -112,7 +112,8 @@ impl ContextCompactor {
|
||||
pub async fn try_compact(
|
||||
&self,
|
||||
manager: &Arc<LoopManager>,
|
||||
pool: &SqlitePool,
|
||||
pool: &Arc<SqlitePool>,
|
||||
user_id: &str,
|
||||
session_id: i64,
|
||||
stack_id: i64,
|
||||
last_input_tokens: u32,
|
||||
@@ -136,7 +137,7 @@ impl ContextCompactor {
|
||||
"compactor: threshold exceeded, starting compaction"
|
||||
);
|
||||
|
||||
self.do_compact(manager, session_id, stack_id, effective_tokens).await
|
||||
self.do_compact(manager, pool, user_id, session_id, stack_id, effective_tokens).await
|
||||
}
|
||||
|
||||
/// Force compaction regardless of the token threshold.
|
||||
@@ -146,7 +147,8 @@ impl ContextCompactor {
|
||||
pub async fn force_compact(
|
||||
&self,
|
||||
manager: &Arc<LoopManager>,
|
||||
pool: &SqlitePool,
|
||||
pool: &Arc<SqlitePool>,
|
||||
user_id: &str,
|
||||
session_id: i64,
|
||||
stack_id: i64,
|
||||
is_ephemeral: bool,
|
||||
@@ -162,7 +164,7 @@ impl ContextCompactor {
|
||||
"compactor: manual compaction triggered"
|
||||
);
|
||||
|
||||
self.do_compact(manager, session_id, stack_id, effective_tokens).await
|
||||
self.do_compact(manager, pool, user_id, session_id, stack_id, effective_tokens).await
|
||||
}
|
||||
|
||||
/// Runs the library's compaction on the frame with Skald's model policy,
|
||||
@@ -171,9 +173,12 @@ impl ContextCompactor {
|
||||
/// Model: the instance-wide Settings pick (`compaction_model`) wins; empty,
|
||||
/// unset, or naming a model that no longer exists all degrade to AUTO
|
||||
/// selection by `compaction.strength` from config.yml.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn do_compact(
|
||||
&self,
|
||||
manager: &Arc<LoopManager>,
|
||||
pool: &Arc<SqlitePool>,
|
||||
user_id: &str,
|
||||
session_id: i64,
|
||||
stack_id: i64,
|
||||
effective_tokens: u32,
|
||||
@@ -184,13 +189,14 @@ impl ContextCompactor {
|
||||
let outcome = manager
|
||||
.new_compaction(conv, agent_loop::ids::FrameId(stack_id))
|
||||
.mode(CompactionMode::Auto { keep_tail: self.config.keep_recent })
|
||||
// Strength is Skald's, captured here (D14): a pin bypasses it.
|
||||
.selector(Arc::new(SkaldSelector::new(
|
||||
Arc::clone(&self.llm_manager),
|
||||
self.config.strength,
|
||||
)))
|
||||
// Strength is Skald's, captured here (D14): a pin bypasses it. The
|
||||
// owner rides along so the summariser's call shows up in the
|
||||
// requests log like any other (session/frame come from the request).
|
||||
.selector(Arc::new(
|
||||
SkaldSelector::new(Arc::clone(&self.llm_manager), self.config.strength)
|
||||
.with_log(RequestLogTarget::user(user_id, Arc::clone(pool))),
|
||||
))
|
||||
.model(hint)
|
||||
.log(json!({ "session_id": session_id, "stack_id": stack_id }))
|
||||
.run()
|
||||
.await?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user