@@ -116,7 +116,14 @@ async def _log_node_tree(self, node: Node) -> None:
116
116
117
117
# Log the current node based on its type
118
118
if node .node_type in ("agent" , "chain" ):
119
- self ._galileo_logger .add_workflow_span (input = input_ , output = output , name = name , metadata = metadata , tags = tags )
119
+ self ._galileo_logger .add_workflow_span (
120
+ input = input_ ,
121
+ output = output ,
122
+ name = name ,
123
+ duration_ns = node .span_params .get ("duration_ns" ),
124
+ metadata = metadata ,
125
+ tags = tags ,
126
+ )
120
127
is_workflow_span = True
121
128
elif node .node_type in ("llm" , "chat" ):
122
129
self ._galileo_logger .add_llm_span (
@@ -126,6 +133,7 @@ async def _log_node_tree(self, node: Node) -> None:
126
133
temperature = node .span_params .get ("temperature" ),
127
134
tools = node .span_params .get ("tools" ),
128
135
name = name ,
136
+ duration_ns = node .span_params .get ("duration_ns" ),
129
137
metadata = metadata ,
130
138
tags = tags ,
131
139
num_input_tokens = node .span_params .get ("num_input_tokens" ),
@@ -135,10 +143,22 @@ async def _log_node_tree(self, node: Node) -> None:
135
143
)
136
144
elif node .node_type == "retriever" :
137
145
self ._galileo_logger .add_retriever_span (
138
- input = input_ , output = output , name = name , metadata = metadata , tags = tags
146
+ input = input_ ,
147
+ output = output ,
148
+ name = name ,
149
+ duration_ns = node .span_params .get ("duration_ns" ),
150
+ metadata = metadata ,
151
+ tags = tags ,
139
152
)
140
153
elif node .node_type == "tool" :
141
- self ._galileo_logger .add_tool_span (input = input_ , output = output , name = name , metadata = metadata , tags = tags )
154
+ self ._galileo_logger .add_tool_span (
155
+ input = input_ ,
156
+ output = output ,
157
+ name = name ,
158
+ duration_ns = node .span_params .get ("duration_ns" ),
159
+ metadata = metadata ,
160
+ tags = tags ,
161
+ )
142
162
else :
143
163
_logger .warning (f"Unknown node type: { node .node_type } " )
144
164
@@ -187,6 +207,10 @@ async def _start_node(
187
207
188
208
# Create new node
189
209
node = Node (node_type = node_type , span_params = kwargs , run_id = run_id , parent_run_id = parent_run_id )
210
+
211
+ if "start_time" not in node .span_params :
212
+ node .span_params ["start_time" ] = time .perf_counter_ns ()
213
+
190
214
self ._nodes [node_id ] = node
191
215
192
216
# Set as root node if needed
@@ -222,6 +246,8 @@ async def _end_node(self, run_id: UUID, **kwargs: Any) -> None:
222
246
_logger .debug (f"No node exists for run_id { node_id } " )
223
247
return
224
248
249
+ node .span_params ["duration_ns" ] = time .perf_counter_ns () - node .span_params ["start_time" ]
250
+
225
251
# Update node parameters
226
252
node .span_params .update (** kwargs )
227
253
@@ -302,7 +328,7 @@ async def on_llm_start(
302
328
model = model ,
303
329
temperature = temperature ,
304
330
metadata = {k : str (v ) for k , v in metadata .items ()} if metadata else None ,
305
- start_time = time .perf_counter (),
331
+ start_time = time .perf_counter_ns (),
306
332
time_to_first_token_ns = None ,
307
333
)
308
334
@@ -315,7 +341,7 @@ async def on_llm_new_token(self, token: str, *, run_id: UUID, **kwargs: Any) ->
315
341
if "time_to_first_token_ns" not in node .span_params or node .span_params ["time_to_first_token_ns" ] is None :
316
342
start_time = node .span_params .get ("start_time" )
317
343
if start_time is not None :
318
- node .span_params ["time_to_first_token_ns" ] = ( time .perf_counter () - start_time ) * 1e9
344
+ node .span_params ["time_to_first_token_ns" ] = time .perf_counter_ns () - start_time
319
345
320
346
async def on_chat_model_start (
321
347
self ,
0 commit comments