| 53 | /// Returns the new node's ID. |
| 54 | #[allow(clippy::too_many_arguments)] |
| 55 | pub fn append_tool_call( |
| 56 | &mut self, |
| 57 | tool_name: &str, |
| 58 | tool_call_id: Option<&str>, |
| 59 | tool_input: Option<&serde_json::Value>, |
| 60 | tool_output: Option<&str>, |
| 61 | status: Option<&str>, |
| 62 | duration_ms: Option<u64>, |
| 63 | timestamp: i64, |
| 64 | ) -> String { |
| 65 | let kind = classify_tool_call(tool_name, tool_input, tool_output, status); |
| 66 | let summary = summarize_tool_call(tool_name, kind, tool_input, tool_output, status); |
| 67 | |
| 68 | let mut node = |
| 69 | GraphNode::new(self.next_id(), kind, timestamp, summary).with_tool_name(tool_name); |
| 70 | |
| 71 | if let Some(id) = tool_call_id { |
| 72 | node = node.with_tool_call_id(id); |
| 73 | } |
| 74 | if let Some(ms) = duration_ms { |
| 75 | node = node.with_duration_ms(ms); |
| 76 | } |
| 77 | |
| 78 | // Attach detail based on kind |
| 79 | node.detail = build_tool_detail(kind, tool_name, tool_input, tool_output); |
| 80 | |
| 81 | let node_id = node.id.clone(); |
| 82 | |
| 83 | // Infer edges based on the classified kind |
| 84 | self.infer_edges(&node_id, kind); |
| 85 | |
| 86 | self.push_node(node); |
| 87 | node_id |
| 88 | } |
| 89 | |
| 90 | /// Append a reasoning/thinking node (chain-of-thought from the model). |
| 91 | /// |