Class: Agents::Instrumentation::TracingCallbacks
- Inherits:
-
Object
- Object
- Agents::Instrumentation::TracingCallbacks
show all
- Includes:
- Constants
- Defined in:
- lib/agents/instrumentation/tracing_callbacks.rb
Overview
Produces OTel spans for agent execution, compatible with Langfuse.
Span hierarchy:
root (<trace_name>)
├── agent.<name> ← container per agent (no gen_ai.request.model)
│ ├── .generation ← GENERATION with model + tokens
│ └── .tool.<name> ← TOOL observation
└── .handoff ← point event on root
Only GENERATION spans carry gen_ai.request.model to avoid Langfuse double-counting costs. Tracing state lives in context, unique per run (thread-safe).
Constant Summary
Constants included
from Constants
Constants::ATTR_GEN_AI_PROVIDER, Constants::ATTR_GEN_AI_REQUEST_MODEL, Constants::ATTR_GEN_AI_USAGE_INPUT, Constants::ATTR_GEN_AI_USAGE_OUTPUT, Constants::ATTR_LANGFUSE_OBS_INPUT, Constants::ATTR_LANGFUSE_OBS_OUTPUT, Constants::ATTR_LANGFUSE_OBS_TYPE, Constants::ATTR_LANGFUSE_SESSION_ID, Constants::ATTR_LANGFUSE_TRACE_INPUT, Constants::ATTR_LANGFUSE_TRACE_OUTPUT, Constants::ATTR_LANGFUSE_TRACE_TAGS, Constants::ATTR_LANGFUSE_USER_ID, Constants::EVENT_HANDOFF, Constants::SPAN_LLM_CALL, Constants::SPAN_RUN, Constants::SPAN_TOOL
Instance Method Summary
collapse
-
#initialize(tracer:, trace_name: SPAN_RUN, span_attributes: {}, attribute_provider: nil) ⇒ TracingCallbacks
constructor
A new instance of TracingCallbacks.
-
#on_agent_complete(_agent_name, _result, _error, context_wrapper) ⇒ Object
-
#on_agent_handoff(from_agent, to_agent, reason, context_wrapper) ⇒ Object
-
#on_agent_thinking(agent_name, input, context_wrapper) ⇒ Object
-
#on_chat_created(chat, agent_name, model, context_wrapper) ⇒ Object
-
#on_llm_call_complete(_agent_name, _model, _response, _context_wrapper) ⇒ Object
No-op: LLM spans are handled by on_end_message hook (see on_chat_created).
-
#on_run_complete(_agent_name, result, context_wrapper) ⇒ Object
-
#on_run_start(agent_name, input, context_wrapper) ⇒ Object
-
#on_tool_complete(_tool_name, result, context_wrapper) ⇒ Object
-
#on_tool_start(tool_name, args, context_wrapper) ⇒ Object
Constructor Details
#initialize(tracer:, trace_name: SPAN_RUN, span_attributes: {}, attribute_provider: nil) ⇒ TracingCallbacks
Returns a new instance of TracingCallbacks.
21
22
23
24
25
26
27
28
29
30
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 21
def initialize(tracer:, trace_name: SPAN_RUN, span_attributes: {}, attribute_provider: nil)
@tracer = tracer
@trace_name = trace_name
@llm_span_name = "#{trace_name}.generation"
@tool_span_name = "#{trace_name}.tool.%s"
@agent_span_name = "#{trace_name}.agent.%s"
@handoff_event_name = "#{trace_name}.handoff"
@span_attributes = span_attributes
@attribute_provider = attribute_provider
end
|
Instance Method Details
#on_agent_complete(_agent_name, _result, _error, context_wrapper) ⇒ Object
62
63
64
65
66
67
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 62
def on_agent_complete(_agent_name, _result, _error, context_wrapper)
tracing = tracing_state(context_wrapper)
return unless tracing
finish_agent_span(tracing)
end
|
#on_agent_handoff(from_agent, to_agent, reason, context_wrapper) ⇒ Object
110
111
112
113
114
115
116
117
118
119
120
121
122
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 110
def on_agent_handoff(from_agent, to_agent, reason, context_wrapper)
tracing = tracing_state(context_wrapper)
return unless tracing
tracing[:root_span]&.add_event(
@handoff_event_name,
attributes: {
"handoff.from" => from_agent,
"handoff.to" => to_agent,
"handoff.reason" => reason.to_s
}
)
end
|
#on_agent_thinking(agent_name, input, context_wrapper) ⇒ Object
47
48
49
50
51
52
53
54
55
56
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 47
def on_agent_thinking(agent_name, input, context_wrapper)
tracing = tracing_state(context_wrapper)
return unless tracing
tracing[:pending_llm_input] = serialize_output(input)
return if tracing[:current_agent_name] == agent_name
start_agent_span(tracing, agent_name)
end
|
#on_chat_created(chat, agent_name, model, context_wrapper) ⇒ Object
69
70
71
72
73
74
75
76
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 69
def on_chat_created(chat, agent_name, model, context_wrapper)
tracing = tracing_state(context_wrapper)
return unless tracing
chat.on_end_message do |message|
handle_end_message(chat, agent_name, model, message, context_wrapper)
end
end
|
#on_llm_call_complete(_agent_name, _model, _response, _context_wrapper) ⇒ Object
No-op: LLM spans are handled by on_end_message hook (see on_chat_created). Kept because the callback interface requires it.
60
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 60
def on_llm_call_complete(_agent_name, _model, _response, _context_wrapper); end
|
#on_run_complete(_agent_name, result, context_wrapper) ⇒ Object
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 124
def on_run_complete(_agent_name, result, context_wrapper)
tracing = tracing_state(context_wrapper)
return unless tracing
finish_dangling_spans(tracing)
root_span = tracing[:root_span]
return unless root_span
set_run_output_attributes(root_span, result)
set_run_error_status(root_span, result)
root_span.finish
cleanup_tracing_state(context_wrapper)
end
|
#on_run_start(agent_name, input, context_wrapper) ⇒ Object
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 32
def on_run_start(agent_name, input, context_wrapper)
attributes = build_root_attributes(agent_name, input, context_wrapper)
root_span = @tracer.start_span(@trace_name, attributes: attributes)
root_context = OpenTelemetry::Trace.context_with_span(root_span)
store_tracing_state(context_wrapper,
root_span: root_span,
root_context: root_context,
current_tool_span: nil,
current_agent_name: nil,
current_agent_span: nil,
current_agent_context: nil)
end
|
98
99
100
101
102
103
104
105
106
107
108
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 98
def on_tool_complete(_tool_name, result, context_wrapper)
tracing = tracing_state(context_wrapper)
return unless tracing
tool_span = tracing[:current_tool_span]
return unless tool_span
tool_span.set_attribute(ATTR_LANGFUSE_OBS_OUTPUT, serialize_output(result))
tool_span.finish
tracing[:current_tool_span] = nil
end
|
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
# File 'lib/agents/instrumentation/tracing_callbacks.rb', line 78
def on_tool_start(tool_name, args, context_wrapper)
tracing = tracing_state(context_wrapper)
return unless tracing
span_name = format(@tool_span_name, tool_name)
attributes = {
ATTR_LANGFUSE_OBS_TYPE => "tool",
ATTR_LANGFUSE_OBS_INPUT => serialize_output(args)
}
parent = handoff_tool?(tool_name) ? tracing[:root_context] : parent_context(tracing)
tool_span = @tracer.start_span(
span_name,
with_parent: parent,
attributes: attributes
)
tracing[:current_tool_span] = tool_span
end
|