MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / handle_tool_use

Method handle_tool_use

atomic-agent/src/turn/orchestrator/turn.rs:353–434  ·  view source on GitHub ↗

Handle a PreToolUse or PostToolUse event. Currently tracks tool usage for informational purposes. Future enhancements may create sub-turn recordings for sub-agent (Task) tools.

(
        &mut self,
        event: TurnEvent,
    )

Source from the content-addressed store, hash-verified

351 /// Currently tracks tool usage for informational purposes. Future
352 /// enhancements may create sub-turn recordings for sub-agent (Task) tools.
353 pub(super) async fn handle_tool_use(
354 &mut self,
355 event: TurnEvent,
356 ) -> AgentResult<DispatchResult> {
357 let session_id = &event.session_id;
358
359 let session = self.load_or_create_session(session_id, &event)?;
360
361 // Log tool usage
362 if let Some(ref tool_name) = event.tool_name {
363 log::info!(
364 "Session {} tool use: {} ({})",
365 session_id,
366 tool_name,
367 event.event_type,
368 );
369 }
370
371 // Provenance: append tool call nodes on PostToolUse.
372 //
373 // PreToolUse doesn't have output or duration yet, so we only
374 // record on PostToolUse where the full picture is available.
375 // The classifier uses tool name + input + output to determine
376 // the node kind (Exploration, Commitment, Verification, etc.).
377 if event.event_type == HookType::PostToolUse {
378 if let Some(mut acc) = self.load_accumulator(session_id) {
379 let tool_name = event.tool_name.as_deref().unwrap_or("unknown");
380 let tool_call_id = event.tool_use_id.as_deref();
381
382 // Extract tool_input, tool_output, status, duration from raw_json.
383 //
384 // The enriched OpenCode plugin sends top-level fields alongside
385 // tool_input: filediff, diagnostics, title, file_path, exit_code.
386 // We merge these INTO tool_input so the accumulator's classify
387 // and detail-building functions can find them without changing
388 // their signature.
389 let raw = event.raw_json.as_ref();
390 let tool_output = raw.and_then(|r| r.get("tool_output").and_then(|v| v.as_str()));
391 let status = raw.and_then(|r| r.get("status").and_then(|v| v.as_str()));
392 let duration_ms = raw.and_then(|r| r.get("duration").and_then(|v| v.as_u64()));
393
394 // Build a merged tool_input that includes both the original
395 // tool_input fields AND the top-level enriched fields.
396 let merged_input: Option<serde_json::Value> = raw.map(|r| {
397 let mut merged = r
398 .get("tool_input")
399 .and_then(|v| v.as_object().cloned())
400 .unwrap_or_default();
401
402 // Merge enriched top-level fields into tool_input
403 for key in &[
404 "filediff",
405 "diagnostics",
406 "title",
407 "file_path",
408 "exit_code",
409 "diff",
410 ] {

Callers 1

dispatchMethod · 0.80

Calls 11

load_accumulatorMethod · 0.80
as_refMethod · 0.80
as_u64Method · 0.80
append_tool_callMethod · 0.80
save_accumulatorMethod · 0.80
getMethod · 0.65
as_strMethod · 0.45
insertMethod · 0.45
cloneMethod · 0.45
timestampMethod · 0.45

Tested by

no test coverage detected