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

Method handle_tool_use

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

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

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