1use crate::kernel::{ExecutionId, StepId, StepType};
20use crate::runner::TraceContext;
21
22pub struct ExecutionSpanAttributes {
24 pub execution_id: String,
26 pub parent_id: Option<String>,
28 pub parent_type: Option<String>,
30 pub tenant_id: Option<String>,
32 pub user_id: Option<String>,
34}
35
36impl ExecutionSpanAttributes {
37 pub fn new(execution_id: &ExecutionId) -> Self {
39 Self {
40 execution_id: execution_id.as_str().to_string(),
41 parent_id: None,
42 parent_type: None,
43 tenant_id: None,
44 user_id: None,
45 }
46 }
47
48 pub fn with_parent(
50 mut self,
51 parent_id: impl Into<String>,
52 parent_type: impl Into<String>,
53 ) -> Self {
54 self.parent_id = Some(parent_id.into());
55 self.parent_type = Some(parent_type.into());
56 self
57 }
58
59 pub fn with_tenant(mut self, tenant_id: impl Into<String>) -> Self {
61 self.tenant_id = Some(tenant_id.into());
62 self
63 }
64
65 pub fn with_user(mut self, user_id: impl Into<String>) -> Self {
67 self.user_id = Some(user_id.into());
68 self
69 }
70
71 pub fn to_attributes(&self) -> Vec<(&'static str, String)> {
73 let mut attrs = vec![("enact.execution_id", self.execution_id.clone())];
74
75 if let Some(ref parent_id) = self.parent_id {
76 attrs.push(("enact.parent_id", parent_id.clone()));
77 }
78 if let Some(ref parent_type) = self.parent_type {
79 attrs.push(("enact.parent_type", parent_type.clone()));
80 }
81 if let Some(ref tenant_id) = self.tenant_id {
82 attrs.push(("enact.tenant_id", tenant_id.clone()));
83 }
84 if let Some(ref user_id) = self.user_id {
85 attrs.push(("enact.user_id", user_id.clone()));
86 }
87
88 attrs
89 }
90}
91
92pub struct StepSpanAttributes {
94 pub execution_id: String,
96 pub step_id: String,
98 pub step_type: String,
100 pub name: String,
102}
103
104impl StepSpanAttributes {
105 pub fn new(
107 execution_id: &ExecutionId,
108 step_id: &StepId,
109 step_type: StepType,
110 name: impl Into<String>,
111 ) -> Self {
112 Self {
113 execution_id: execution_id.as_str().to_string(),
114 step_id: step_id.as_str().to_string(),
115 step_type: step_type.to_string(),
116 name: name.into(),
117 }
118 }
119
120 pub fn to_attributes(&self) -> Vec<(&'static str, String)> {
122 vec![
123 ("enact.execution_id", self.execution_id.clone()),
124 ("enact.step_id", self.step_id.clone()),
125 ("enact.step_type", self.step_type.clone()),
126 ("enact.step_name", self.name.clone()),
127 ]
128 }
129}
130
131pub struct ToolSpanAttributes {
133 pub execution_id: String,
135 pub step_id: String,
137 pub tool_name: String,
139}
140
141impl ToolSpanAttributes {
142 pub fn new(execution_id: &ExecutionId, step_id: &StepId, tool_name: impl Into<String>) -> Self {
144 Self {
145 execution_id: execution_id.as_str().to_string(),
146 step_id: step_id.as_str().to_string(),
147 tool_name: tool_name.into(),
148 }
149 }
150
151 pub fn to_attributes(&self) -> Vec<(&'static str, String)> {
153 vec![
154 ("enact.execution_id", self.execution_id.clone()),
155 ("enact.step_id", self.step_id.clone()),
156 ("enact.tool_name", self.tool_name.clone()),
157 ]
158 }
159}
160
161pub struct LlmSpanAttributes {
163 pub execution_id: String,
165 pub step_id: String,
167 pub provider: String,
169 pub model: String,
171 pub input_tokens: Option<u32>,
173 pub output_tokens: Option<u32>,
175}
176
177impl LlmSpanAttributes {
178 pub fn new(
180 execution_id: &ExecutionId,
181 step_id: &StepId,
182 provider: impl Into<String>,
183 model: impl Into<String>,
184 ) -> Self {
185 Self {
186 execution_id: execution_id.as_str().to_string(),
187 step_id: step_id.as_str().to_string(),
188 provider: provider.into(),
189 model: model.into(),
190 input_tokens: None,
191 output_tokens: None,
192 }
193 }
194
195 pub fn with_tokens(mut self, input: u32, output: u32) -> Self {
197 self.input_tokens = Some(input);
198 self.output_tokens = Some(output);
199 self
200 }
201
202 pub fn to_attributes(&self) -> Vec<(&'static str, String)> {
204 let mut attrs = vec![
205 ("enact.execution_id", self.execution_id.clone()),
206 ("enact.step_id", self.step_id.clone()),
207 ("gen_ai.system", self.provider.clone()),
208 ("gen_ai.request.model", self.model.clone()),
209 ];
210
211 if let Some(tokens) = self.input_tokens {
212 attrs.push(("gen_ai.usage.input_tokens", tokens.to_string()));
213 }
214 if let Some(tokens) = self.output_tokens {
215 attrs.push(("gen_ai.usage.output_tokens", tokens.to_string()));
216 }
217
218 attrs
219 }
220}
221
222pub fn execution_span_name(execution_id: &ExecutionId) -> String {
224 format!("execution:{}", execution_id.as_str())
225}
226
227pub fn step_span_name(step_type: &StepType, name: &str) -> String {
229 format!("step:{}:{}", step_type, name)
230}
231
232pub fn tool_span_name(tool_name: &str) -> String {
234 format!("tool:{}", tool_name)
235}
236
237pub fn llm_span_name(provider: &str, model: &str) -> String {
239 format!("llm:{}:{}", provider, model)
240}
241
242pub fn extract_trace_context(trace: &TraceContext) -> (String, String) {
244 (trace.trace_id.clone(), trace.span_id.clone())
245}