use crate::error::Result;
use crate::models::run::RunType;
use crate::tracing::scope::RunScope;
use crate::tracing::tracer::Tracer;
use serde_json::Value;
pub struct GraphTrace {
root: RunScope,
}
impl GraphTrace {
pub async fn start_root(inputs: Value, thread_id: Option<String>) -> Result<Self> {
let mut root = RunScope::root_value("Graph", RunType::Chain, inputs);
if let Some(tid) = thread_id {
root = root.with_thread_id(tid);
}
root.post_start().await?;
Ok(Self { root })
}
pub fn root_scope(&self) -> &RunScope {
&self.root
}
pub fn root_tracer(&self) -> &Tracer {
self.root.tracer()
}
pub async fn start_node_iteration(&self, node_name: &str, inputs: Value) -> Result<RunScope> {
let mut step = self.root.child_value(node_name, RunType::Chain, inputs);
step.post_start().await?;
Ok(step)
}
pub async fn trace_llm_call(
&self,
parent_node: &RunScope,
llm_name: &str,
inputs: Value,
outputs: Value,
model_name: Option<&str>,
) -> Result<()> {
let mut llm_inputs = inputs;
if let Some(model) = model_name {
if let Some(obj) = llm_inputs.as_object_mut() {
obj.insert("model".to_string(), serde_json::json!(model));
}
}
let mut llm = parent_node.child_value(llm_name, RunType::Llm, llm_inputs);
llm.post_start().await?;
llm.end_ok(outputs).await
}
pub async fn trace_decision(
&self,
parent_node: &RunScope,
decision_name: &str,
inputs: Value,
outputs: Value,
) -> Result<()> {
let mut decision = parent_node.child_value(decision_name, RunType::Chain, inputs);
decision.post_start().await?;
decision.end_ok(outputs).await
}
pub async fn trace_tool_call(
&self,
parent_node: &RunScope,
tool_name: &str,
inputs: Value,
outputs: Value,
) -> Result<()> {
let formatted_name = format!("tool/{}", tool_name);
let mut tool = parent_node.child_value(&formatted_name, RunType::Tool, inputs);
tool.post_start().await?;
tool.end_ok(outputs).await
}
pub async fn end_root(self, outputs: Value) -> Result<()> {
self.root.end_ok(outputs).await
}
}