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

Method handle_tool_use

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

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

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