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

Method handle_tool_use

atomic-agent/src/turn/orchestrator/turn.rs:372–453  ·  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

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

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