use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub use praxis_llm::TokenUsage;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeObservation {
pub span_id: String,
pub run_id: String,
pub conversation_id: String,
pub node_type: String,
pub started_at: chrono::DateTime<chrono::Utc>,
pub duration_ms: u64,
pub data: NodeObservationData,
pub metadata: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "output_type", rename_all = "snake_case")]
pub enum NodeOutput {
Reasoning {
id: String,
content: String,
},
Message {
id: String,
content: String,
},
ToolCalls {
calls: Vec<ToolCallInfo>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum NodeObservationData {
Llm {
input_messages: Vec<LangfuseMessage>,
outputs: Vec<NodeOutput>,
model: String,
#[serde(skip_serializing_if = "Option::is_none")]
usage: Option<TokenUsage>,
},
Tool {
tool_calls: Vec<ToolCallInfo>,
tool_results: Vec<ToolResultInfo>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LangfuseMessage {
pub role: String,
pub content: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_call_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCallInfo>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCallInfo {
pub id: String,
pub name: String,
pub arguments: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolResultInfo {
pub tool_call_id: String,
pub tool_name: String,
pub result: String,
pub is_error: bool,
pub duration_ms: u64,
}
#[derive(Debug, Clone)]
pub struct TraceContext {
pub trace_id: String,
pub run_id: String,
pub conversation_id: String,
pub started_at: chrono::DateTime<chrono::Utc>,
pub span_counter: u32,
}
impl TraceContext {
pub fn new(run_id: String, conversation_id: String) -> Self {
Self {
trace_id: uuid::Uuid::new_v4().to_string(),
run_id,
conversation_id,
started_at: chrono::Utc::now(),
span_counter: 0,
}
}
pub fn next_span_id(&mut self) -> String {
self.span_counter += 1;
format!("{}-span-{}", self.trace_id, self.span_counter)
}
}