use agentic_logging::CallTimer;
use agentic_logging::LogWriter;
use agentic_logging::ToolCallRecord;
use agentic_logging::chrono::DateTime;
use agentic_logging::chrono::Utc;
use agentic_logging::classify_failure_kind;
use thoughts_tool::active_logs_dir;
pub struct ToolLogCtx {
pub timer: CallTimer,
writer: Option<LogWriter>,
server: String,
tool: String,
}
impl ToolLogCtx {
pub fn start(tool: &str) -> Self {
let timer = CallTimer::start();
let writer = active_logs_dir().ok().map(LogWriter::new);
Self {
timer,
writer,
server: "pr_comments".to_string(),
tool: tool.to_string(),
}
}
#[expect(clippy::too_many_arguments)]
pub fn finish(
self,
request: serde_json::Value,
response_file: Option<String>,
success: bool,
error: Option<String>,
summary: Option<serde_json::Value>,
model: Option<String>,
completed_at: Option<DateTime<Utc>>,
) {
let Some(writer) = self.writer else {
return;
};
let (completed_at, duration_ms) = match completed_at {
Some(ts) => (ts, self.timer.elapsed_ms()),
None => self.timer.finish(),
};
let record = ToolCallRecord {
call_id: self.timer.call_id,
server: self.server,
tool: self.tool,
started_at: self.timer.started_at,
completed_at,
duration_ms,
request,
response_file,
success,
failure_kind: classify_failure_kind(success, error.as_deref()),
error,
model,
token_usage: None,
summary,
};
if let Err(e) = writer.append_jsonl(&record) {
tracing::warn!("Failed to append JSONL log: {e}");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tool_log_ctx_creation() {
let ctx = ToolLogCtx::start("test_tool");
assert_eq!(ctx.tool, "test_tool");
assert_eq!(ctx.server, "pr_comments");
assert!(!ctx.timer.call_id.is_empty());
}
#[test]
fn test_finish_without_writer_is_noop() {
let ctx = ToolLogCtx::start("test_tool");
ctx.finish(
serde_json::json!({"test": true}),
None,
true,
None,
None,
None,
None,
);
}
#[test]
fn test_logging_failure_isolation_with_error_result() {
let ctx = ToolLogCtx::start("failing_tool");
ctx.finish(
serde_json::json!({"input": "bad"}),
None,
false, Some("Something went wrong".into()),
None,
None,
None,
);
}
}