synaptic_graph/
tool_node.rs1use async_trait::async_trait;
2use synaptic_core::{Message, SynapseError};
3use synaptic_tools::SerialToolExecutor;
4
5use crate::node::Node;
6use crate::state::MessageState;
7
8pub struct ToolNode {
10 executor: SerialToolExecutor,
11}
12
13impl ToolNode {
14 pub fn new(executor: SerialToolExecutor) -> Self {
15 Self { executor }
16 }
17}
18
19#[async_trait]
20impl Node<MessageState> for ToolNode {
21 async fn process(&self, mut state: MessageState) -> Result<MessageState, SynapseError> {
22 let last = state
23 .last_message()
24 .ok_or_else(|| SynapseError::Graph("no messages in state".to_string()))?;
25
26 let tool_calls = last.tool_calls().to_vec();
27 if tool_calls.is_empty() {
28 return Ok(state);
29 }
30
31 for call in &tool_calls {
32 let result = self
33 .executor
34 .execute(&call.name, call.arguments.clone())
35 .await?;
36 state
37 .messages
38 .push(Message::tool(result.to_string(), &call.id));
39 }
40
41 Ok(state)
42 }
43}