activeagent 1.0.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +132 -0
- data/README.md +39 -3
- data/lib/active_agent/base.rb +4 -0
- data/lib/active_agent/model_capabilities.rb +89 -0
- data/lib/active_agent/providers/_base_provider.rb +23 -2
- data/lib/active_agent/providers/concerns/exception_handler.rb +12 -1
- data/lib/active_agent/providers/errors.rb +140 -0
- data/lib/active_agent/providers/ollama/chat/transforms.rb +9 -3
- data/lib/active_agent/railtie.rb +5 -0
- data/lib/active_agent/telemetry/configuration.rb +115 -171
- data/lib/active_agent/telemetry/instrumentation.rb +141 -14
- data/lib/active_agent/telemetry/reporter.rb +12 -165
- data/lib/active_agent/telemetry/span.rb +18 -245
- data/lib/active_agent/telemetry/tool_origin.rb +90 -0
- data/lib/active_agent/telemetry/tracer.rb +67 -70
- data/lib/active_agent/telemetry.rb +2 -2
- data/lib/active_agent/version.rb +1 -1
- data/lib/active_agent.rb +1 -1
- metadata +38 -42
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/api/traces_controller.rb +0 -117
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/application_controller.rb +0 -54
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/dashboard_controller.rb +0 -126
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/traces_controller.rb +0 -103
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/agent_execution_job.rb +0 -56
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/application_job.rb +0 -14
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/sandbox_cleanup_job.rb +0 -49
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/sandbox_provision_job.rb +0 -65
- data/lib/active_agent/dashboard/app/jobs/active_agent/process_telemetry_traces_job.rb +0 -77
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent.rb +0 -256
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_run.rb +0 -113
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_template.rb +0 -208
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_version.rb +0 -60
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/application_record.rb +0 -46
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/recording_action.rb +0 -125
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/recording_snapshot.rb +0 -83
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/sandbox_run.rb +0 -52
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/sandbox_session.rb +0 -169
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/session_recording.rb +0 -193
- data/lib/active_agent/dashboard/app/models/active_agent/telemetry_trace.rb +0 -198
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/_trace_detail.html.erb +0 -105
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/index.html.erb +0 -135
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/metrics.html.erb +0 -143
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/show.html.erb +0 -36
- data/lib/active_agent/dashboard/app/views/layouts/active_agent/dashboard/application.html.erb +0 -94
- data/lib/active_agent/dashboard/config/routes.rb +0 -78
- data/lib/active_agent/dashboard/engine.rb +0 -39
- data/lib/active_agent/dashboard.rb +0 -151
- data/lib/generators/active_agent/dashboard/install/install_generator.rb +0 -96
- data/lib/generators/active_agent/dashboard/install/templates/initializer.rb +0 -89
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_runs.rb +0 -42
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_templates.rb +0 -38
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_versions.rb +0 -22
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agents.rb +0 -53
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_sandbox_runs.rb +0 -28
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_sandbox_sessions.rb +0 -43
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_session_recordings.rb +0 -44
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_telemetry_traces.rb +0 -56
- data/lib/generators/active_agent/dashboard/install_generator.rb +0 -64
- data/lib/generators/active_agent/dashboard/templates/active_agent_dashboard.rb.erb +0 -30
- data/lib/generators/active_agent/dashboard/templates/create_active_agent_telemetry_traces.rb.erb +0 -30
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
module ActiveAgent
|
|
4
4
|
module Telemetry
|
|
5
|
-
# Manages trace creation and lifecycle
|
|
5
|
+
# Manages trace creation and lifecycle on the activeagents-telemetry
|
|
6
|
+
# core: builds an ActiveAgents::Telemetry::Trace per unit of work, tracks
|
|
7
|
+
# the current span in thread-local storage, and hands finished traces to
|
|
8
|
+
# the Reporter.
|
|
6
9
|
#
|
|
7
|
-
#
|
|
8
|
-
# and coordinates with the Reporter for async transmission.
|
|
9
|
-
#
|
|
10
|
-
# @example Basic usage
|
|
10
|
+
# @example
|
|
11
11
|
# tracer = Tracer.new(configuration)
|
|
12
12
|
# tracer.trace("MyAgent.greet") do |span|
|
|
13
13
|
# span.set_attribute("user_id", 123)
|
|
14
14
|
# span.add_span("llm.generate", span_type: :llm)
|
|
15
15
|
# end
|
|
16
|
-
#
|
|
17
16
|
class Tracer
|
|
18
17
|
# @return [Configuration] Telemetry configuration
|
|
19
18
|
attr_reader :configuration
|
|
@@ -27,44 +26,47 @@ module ActiveAgent
|
|
|
27
26
|
def initialize(configuration)
|
|
28
27
|
@configuration = configuration
|
|
29
28
|
@reporter = Reporter.new(configuration)
|
|
30
|
-
@mutex = Mutex.new
|
|
31
29
|
end
|
|
32
30
|
|
|
33
31
|
# Creates and executes a new trace.
|
|
34
32
|
#
|
|
33
|
+
# Callers may supply the trace id (instrumentation passes the
|
|
34
|
+
# generation's prompt_options[:trace_id]) so external records — e.g.
|
|
35
|
+
# solid_agent's persisted generations — can correlate with this trace;
|
|
36
|
+
# otherwise one is generated.
|
|
37
|
+
#
|
|
35
38
|
# @param name [String] Trace name (typically "AgentClass.action")
|
|
36
|
-
# @param attributes [Hash] Root span attributes
|
|
39
|
+
# @param attributes [Hash] Root span attributes; :trace_id and
|
|
40
|
+
# :span_type are extracted rather than recorded
|
|
37
41
|
# @yield [span] Yields the root span for adding child spans
|
|
38
42
|
# @return [Object] Result of the block
|
|
39
|
-
|
|
40
|
-
# @example
|
|
41
|
-
# tracer.trace("WeatherAgent.forecast") do |span|
|
|
42
|
-
# span.set_attribute("location", "Seattle")
|
|
43
|
-
# result = do_llm_call
|
|
44
|
-
# span.set_tokens(input: 100, output: 50)
|
|
45
|
-
# result
|
|
46
|
-
# end
|
|
47
|
-
def trace(name, **attributes, &block)
|
|
43
|
+
def trace(name, **attributes)
|
|
48
44
|
return yield(Telemetry::NullSpan.new) unless should_trace?
|
|
49
45
|
|
|
50
|
-
trace_id =
|
|
46
|
+
trace_id = attributes.delete(:trace_id) || SecureRandom.hex(16)
|
|
47
|
+
span_type = attributes.delete(:span_type) || :root
|
|
48
|
+
|
|
49
|
+
trace = build_trace(trace_id)
|
|
51
50
|
root_span = Span.new(
|
|
52
51
|
name,
|
|
53
52
|
trace_id: trace_id,
|
|
54
|
-
span_type:
|
|
53
|
+
span_type: span_type,
|
|
55
54
|
**default_attributes.merge(attributes)
|
|
56
55
|
)
|
|
56
|
+
trace.add_span(root_span)
|
|
57
57
|
|
|
58
58
|
with_span(root_span) do
|
|
59
59
|
result = yield(root_span)
|
|
60
60
|
root_span.finish
|
|
61
|
-
|
|
61
|
+
reporter.report(redact_trace!(trace))
|
|
62
62
|
result
|
|
63
63
|
end
|
|
64
64
|
rescue StandardError => e
|
|
65
|
-
root_span
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
if root_span && !root_span.finished?
|
|
66
|
+
root_span.record_error(e)
|
|
67
|
+
root_span.finish
|
|
68
|
+
reporter.report(redact_trace!(trace))
|
|
69
|
+
end
|
|
68
70
|
raise
|
|
69
71
|
end
|
|
70
72
|
|
|
@@ -76,11 +78,12 @@ module ActiveAgent
|
|
|
76
78
|
def span(name, **attributes)
|
|
77
79
|
return Telemetry::NullSpan.new unless should_trace?
|
|
78
80
|
|
|
81
|
+
span_type = attributes.delete(:span_type) || :root
|
|
79
82
|
current = current_span
|
|
80
83
|
if current
|
|
81
|
-
current.add_span(name, **attributes)
|
|
84
|
+
current.add_span(name, span_type: span_type, **attributes)
|
|
82
85
|
else
|
|
83
|
-
Span.new(name, trace_id:
|
|
86
|
+
Span.new(name, trace_id: SecureRandom.hex(16), span_type: span_type, **default_attributes.merge(attributes))
|
|
84
87
|
end
|
|
85
88
|
end
|
|
86
89
|
|
|
@@ -91,7 +94,9 @@ module ActiveAgent
|
|
|
91
94
|
Thread.current[CURRENT_SPAN_KEY]
|
|
92
95
|
end
|
|
93
96
|
|
|
94
|
-
# Flushes buffered traces
|
|
97
|
+
# Flushes buffered traces and waits for delivery to complete, so
|
|
98
|
+
# callers (tests, rails runner, job shutdown) can rely on the traces
|
|
99
|
+
# having been delivered/stored when this returns.
|
|
95
100
|
#
|
|
96
101
|
# @return [void]
|
|
97
102
|
def flush
|
|
@@ -107,11 +112,16 @@ module ActiveAgent
|
|
|
107
112
|
|
|
108
113
|
private
|
|
109
114
|
|
|
115
|
+
def build_trace(trace_id)
|
|
116
|
+
ActiveAgents::Telemetry::Trace.new(
|
|
117
|
+
trace_id: trace_id,
|
|
118
|
+
service_name: configuration.resolved_service_name,
|
|
119
|
+
environment: configuration.resolved_environment,
|
|
120
|
+
resource_attributes: configuration.resource_attributes
|
|
121
|
+
)
|
|
122
|
+
end
|
|
123
|
+
|
|
110
124
|
# Executes block with span as current context.
|
|
111
|
-
#
|
|
112
|
-
# @param span [Span] Span to set as current
|
|
113
|
-
# @yield Block to execute
|
|
114
|
-
# @return [Object] Result of block
|
|
115
125
|
def with_span(span)
|
|
116
126
|
previous = Thread.current[CURRENT_SPAN_KEY]
|
|
117
127
|
Thread.current[CURRENT_SPAN_KEY] = span
|
|
@@ -120,61 +130,48 @@ module ActiveAgent
|
|
|
120
130
|
Thread.current[CURRENT_SPAN_KEY] = previous
|
|
121
131
|
end
|
|
122
132
|
|
|
123
|
-
#
|
|
124
|
-
#
|
|
125
|
-
#
|
|
126
|
-
|
|
127
|
-
|
|
133
|
+
# Redacts span (and span-event) attributes whose keys match any
|
|
134
|
+
# configured redact_attributes entry, before the trace is handed to
|
|
135
|
+
# the reporter. Matching is case-insensitive substring — deliberately
|
|
136
|
+
# over-broad: better to redact a harmless "max_tokens" than to ship
|
|
137
|
+
# an "api_key". (Ported from the pre-shared-core payload builder,
|
|
138
|
+
# which no longer exists — the gem's reporter ships the trace as-is.)
|
|
139
|
+
REDACTED = "[REDACTED]"
|
|
140
|
+
|
|
141
|
+
def redact_trace!(trace)
|
|
142
|
+
patterns = Array(configuration.redact_attributes).map(&:to_s).reject(&:empty?)
|
|
143
|
+
return trace if patterns.empty?
|
|
144
|
+
|
|
145
|
+
matcher = Regexp.union(patterns.map { |pattern| Regexp.new(Regexp.escape(pattern), Regexp::IGNORECASE) })
|
|
146
|
+
Array(trace.spans).each { |span| redact_span!(span, matcher) }
|
|
147
|
+
trace
|
|
128
148
|
end
|
|
129
149
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
service_name: configuration.resolved_service_name,
|
|
138
|
-
environment: configuration.environment,
|
|
139
|
-
timestamp: Time.current.iso8601(6),
|
|
140
|
-
resource_attributes: configuration.resource_attributes,
|
|
141
|
-
spans: flatten_spans(root_span)
|
|
142
|
-
}
|
|
150
|
+
def redact_span!(span, matcher)
|
|
151
|
+
redact_hash!(span.attributes, matcher) if span.attributes.is_a?(Hash)
|
|
152
|
+
Array(span.events).each do |event|
|
|
153
|
+
attributes = event.is_a?(Hash) ? (event["attributes"] || event[:attributes]) : nil
|
|
154
|
+
redact_hash!(attributes, matcher) if attributes.is_a?(Hash)
|
|
155
|
+
end
|
|
156
|
+
Array(span.children).each { |child| redact_span!(child, matcher) }
|
|
143
157
|
end
|
|
144
158
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
# @return [Array<Hash>] Flattened span data
|
|
149
|
-
def flatten_spans(span)
|
|
150
|
-
result = [ span.to_h.except(:children) ]
|
|
151
|
-
span.children.each do |child|
|
|
152
|
-
result.concat(flatten_spans(child))
|
|
159
|
+
def redact_hash!(attributes, matcher)
|
|
160
|
+
attributes.each_key do |key|
|
|
161
|
+
attributes[key] = REDACTED if key.to_s.match?(matcher)
|
|
153
162
|
end
|
|
154
|
-
result
|
|
155
163
|
end
|
|
156
164
|
|
|
157
|
-
# Returns whether this trace should be
|
|
158
|
-
#
|
|
159
|
-
# @return [Boolean]
|
|
165
|
+
# Returns whether this trace should be collected at all.
|
|
160
166
|
def should_trace?
|
|
161
167
|
configuration.enabled? && configuration.configured? && configuration.should_sample?
|
|
162
168
|
end
|
|
163
169
|
|
|
164
|
-
# Generates a unique trace ID.
|
|
165
|
-
#
|
|
166
|
-
# @return [String] 32-character hex trace ID
|
|
167
|
-
def generate_trace_id
|
|
168
|
-
SecureRandom.hex(16)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
170
|
# Returns default attributes for all spans.
|
|
172
|
-
#
|
|
173
|
-
# @return [Hash] Default attributes
|
|
174
171
|
def default_attributes
|
|
175
172
|
{
|
|
176
173
|
"service.name" => configuration.resolved_service_name,
|
|
177
|
-
"service.environment" => configuration.
|
|
174
|
+
"service.environment" => configuration.resolved_environment,
|
|
178
175
|
"telemetry.sdk.name" => "activeagent",
|
|
179
176
|
"telemetry.sdk.version" => ActiveAgent::VERSION
|
|
180
177
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "net/http"
|
|
4
|
-
require "json"
|
|
5
3
|
require "securerandom"
|
|
4
|
+
require "activeagents/telemetry"
|
|
6
5
|
|
|
7
6
|
module ActiveAgent
|
|
8
7
|
# Telemetry module for collecting and reporting agent traces.
|
|
@@ -55,6 +54,7 @@ module ActiveAgent
|
|
|
55
54
|
autoload :Span
|
|
56
55
|
autoload :Reporter
|
|
57
56
|
autoload :Instrumentation
|
|
57
|
+
autoload :ToolOrigin
|
|
58
58
|
|
|
59
59
|
class << self
|
|
60
60
|
# Returns the telemetry configuration instance.
|
data/lib/active_agent/version.rb
CHANGED
data/lib/active_agent.rb
CHANGED
|
@@ -101,13 +101,13 @@ module ActiveAgent
|
|
|
101
101
|
autoload :Preview, "active_agent/concerns/preview"
|
|
102
102
|
autoload :Previews, "active_agent/concerns/preview"
|
|
103
103
|
autoload :GenerationJob
|
|
104
|
+
autoload :ModelCapabilities
|
|
104
105
|
autoload :Observers, "active_agent/concerns/observers"
|
|
105
106
|
autoload :Provider, "active_agent/concerns/provider"
|
|
106
107
|
autoload :Rescue, "active_agent/concerns/rescue"
|
|
107
108
|
autoload :Tooling, "active_agent/concerns/tooling"
|
|
108
109
|
autoload :View, "active_agent/concerns/view"
|
|
109
110
|
autoload :Telemetry
|
|
110
|
-
autoload :Dashboard
|
|
111
111
|
|
|
112
112
|
class << self
|
|
113
113
|
# Eagerly loads all ActiveAgent components and descendant agent classes.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activeagent
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Bowen
|
|
@@ -109,6 +109,40 @@ dependencies:
|
|
|
109
109
|
- - "<="
|
|
110
110
|
- !ruby/object:Gem::Version
|
|
111
111
|
version: '9.0'
|
|
112
|
+
- !ruby/object:Gem::Dependency
|
|
113
|
+
name: railties
|
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: '7.2'
|
|
119
|
+
- - "<="
|
|
120
|
+
- !ruby/object:Gem::Version
|
|
121
|
+
version: '9.0'
|
|
122
|
+
type: :runtime
|
|
123
|
+
prerelease: false
|
|
124
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
125
|
+
requirements:
|
|
126
|
+
- - ">="
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: '7.2'
|
|
129
|
+
- - "<="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '9.0'
|
|
132
|
+
- !ruby/object:Gem::Dependency
|
|
133
|
+
name: activeagents-telemetry
|
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0.1'
|
|
139
|
+
type: :runtime
|
|
140
|
+
prerelease: false
|
|
141
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - "~>"
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0.1'
|
|
112
146
|
- !ruby/object:Gem::Dependency
|
|
113
147
|
name: jbuilder
|
|
114
148
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -386,38 +420,11 @@ files:
|
|
|
386
420
|
- lib/active_agent/concerns/tooling.rb
|
|
387
421
|
- lib/active_agent/concerns/view.rb
|
|
388
422
|
- lib/active_agent/configuration.rb
|
|
389
|
-
- lib/active_agent/dashboard.rb
|
|
390
|
-
- lib/active_agent/dashboard/app/controllers/active_agent/dashboard/api/traces_controller.rb
|
|
391
|
-
- lib/active_agent/dashboard/app/controllers/active_agent/dashboard/application_controller.rb
|
|
392
|
-
- lib/active_agent/dashboard/app/controllers/active_agent/dashboard/dashboard_controller.rb
|
|
393
|
-
- lib/active_agent/dashboard/app/controllers/active_agent/dashboard/traces_controller.rb
|
|
394
|
-
- lib/active_agent/dashboard/app/jobs/active_agent/dashboard/agent_execution_job.rb
|
|
395
|
-
- lib/active_agent/dashboard/app/jobs/active_agent/dashboard/application_job.rb
|
|
396
|
-
- lib/active_agent/dashboard/app/jobs/active_agent/dashboard/sandbox_cleanup_job.rb
|
|
397
|
-
- lib/active_agent/dashboard/app/jobs/active_agent/dashboard/sandbox_provision_job.rb
|
|
398
|
-
- lib/active_agent/dashboard/app/jobs/active_agent/process_telemetry_traces_job.rb
|
|
399
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/agent.rb
|
|
400
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_run.rb
|
|
401
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_template.rb
|
|
402
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_version.rb
|
|
403
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/application_record.rb
|
|
404
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/recording_action.rb
|
|
405
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/recording_snapshot.rb
|
|
406
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/sandbox_run.rb
|
|
407
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/sandbox_session.rb
|
|
408
|
-
- lib/active_agent/dashboard/app/models/active_agent/dashboard/session_recording.rb
|
|
409
|
-
- lib/active_agent/dashboard/app/models/active_agent/telemetry_trace.rb
|
|
410
|
-
- lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/_trace_detail.html.erb
|
|
411
|
-
- lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/index.html.erb
|
|
412
|
-
- lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/metrics.html.erb
|
|
413
|
-
- lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/show.html.erb
|
|
414
|
-
- lib/active_agent/dashboard/app/views/layouts/active_agent/dashboard/application.html.erb
|
|
415
|
-
- lib/active_agent/dashboard/config/routes.rb
|
|
416
|
-
- lib/active_agent/dashboard/engine.rb
|
|
417
423
|
- lib/active_agent/deprecator.rb
|
|
418
424
|
- lib/active_agent/generation.rb
|
|
419
425
|
- lib/active_agent/generation_job.rb
|
|
420
426
|
- lib/active_agent/inline_preview_interceptor.rb
|
|
427
|
+
- lib/active_agent/model_capabilities.rb
|
|
421
428
|
- lib/active_agent/providers/_base_provider.rb
|
|
422
429
|
- lib/active_agent/providers/anthropic/_types.rb
|
|
423
430
|
- lib/active_agent/providers/anthropic/options.rb
|
|
@@ -453,6 +460,7 @@ files:
|
|
|
453
460
|
- lib/active_agent/providers/concerns/instrumentation.rb
|
|
454
461
|
- lib/active_agent/providers/concerns/previewable.rb
|
|
455
462
|
- lib/active_agent/providers/concerns/tool_choice_clearing.rb
|
|
463
|
+
- lib/active_agent/providers/errors.rb
|
|
456
464
|
- lib/active_agent/providers/gemini/_types.rb
|
|
457
465
|
- lib/active_agent/providers/gemini/options.rb
|
|
458
466
|
- lib/active_agent/providers/gemini_provider.rb
|
|
@@ -535,24 +543,12 @@ files:
|
|
|
535
543
|
- lib/active_agent/telemetry/instrumentation.rb
|
|
536
544
|
- lib/active_agent/telemetry/reporter.rb
|
|
537
545
|
- lib/active_agent/telemetry/span.rb
|
|
546
|
+
- lib/active_agent/telemetry/tool_origin.rb
|
|
538
547
|
- lib/active_agent/telemetry/tracer.rb
|
|
539
548
|
- lib/active_agent/version.rb
|
|
540
549
|
- lib/activeagent.rb
|
|
541
550
|
- lib/generators/active_agent/agent/USAGE
|
|
542
551
|
- lib/generators/active_agent/agent/agent_generator.rb
|
|
543
|
-
- lib/generators/active_agent/dashboard/install/install_generator.rb
|
|
544
|
-
- lib/generators/active_agent/dashboard/install/templates/initializer.rb
|
|
545
|
-
- lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_runs.rb
|
|
546
|
-
- lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_templates.rb
|
|
547
|
-
- lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_versions.rb
|
|
548
|
-
- lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agents.rb
|
|
549
|
-
- lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_sandbox_runs.rb
|
|
550
|
-
- lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_sandbox_sessions.rb
|
|
551
|
-
- lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_session_recordings.rb
|
|
552
|
-
- lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_telemetry_traces.rb
|
|
553
|
-
- lib/generators/active_agent/dashboard/install_generator.rb
|
|
554
|
-
- lib/generators/active_agent/dashboard/templates/active_agent_dashboard.rb.erb
|
|
555
|
-
- lib/generators/active_agent/dashboard/templates/create_active_agent_telemetry_traces.rb.erb
|
|
556
552
|
- lib/generators/active_agent/install/USAGE
|
|
557
553
|
- lib/generators/active_agent/install/install_generator.rb
|
|
558
554
|
- lib/generators/active_agent/templates/active_agent.yml
|
data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/api/traces_controller.rb
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ActiveAgent
|
|
4
|
-
module Dashboard
|
|
5
|
-
module Api
|
|
6
|
-
# Telemetry ingestion endpoint.
|
|
7
|
-
#
|
|
8
|
-
# Receives traces from ActiveAgent::Telemetry::Reporter and stores them
|
|
9
|
-
# for analysis and visualization in the dashboard.
|
|
10
|
-
#
|
|
11
|
-
# Supports two modes:
|
|
12
|
-
# - Local mode: No authentication, synchronous processing
|
|
13
|
-
# - Multi-tenant mode: Bearer token auth, async processing via job
|
|
14
|
-
#
|
|
15
|
-
# @example Local mode request
|
|
16
|
-
# POST /active_agent/api/traces
|
|
17
|
-
# Content-Type: application/json
|
|
18
|
-
#
|
|
19
|
-
# {
|
|
20
|
-
# "traces": [...],
|
|
21
|
-
# "sdk": { "name": "activeagent", "version": "0.5.0" }
|
|
22
|
-
# }
|
|
23
|
-
#
|
|
24
|
-
# @example Multi-tenant mode request
|
|
25
|
-
# POST /active_agent/api/traces
|
|
26
|
-
# Authorization: Bearer <api_key>
|
|
27
|
-
# Content-Type: application/json
|
|
28
|
-
#
|
|
29
|
-
# {
|
|
30
|
-
# "traces": [...],
|
|
31
|
-
# "sdk": { "name": "activeagent", "version": "0.5.0" }
|
|
32
|
-
# }
|
|
33
|
-
#
|
|
34
|
-
class TracesController < ActionController::API
|
|
35
|
-
before_action :authenticate_api_key!, if: -> { ActiveAgent::Dashboard.multi_tenant? }
|
|
36
|
-
|
|
37
|
-
# POST /active_agent/api/traces
|
|
38
|
-
def create
|
|
39
|
-
traces = params[:traces] || []
|
|
40
|
-
sdk_info = params[:sdk] || {}
|
|
41
|
-
|
|
42
|
-
return head :accepted if traces.empty?
|
|
43
|
-
|
|
44
|
-
if ActiveAgent::Dashboard.multi_tenant?
|
|
45
|
-
# Multi-tenant mode: process in background
|
|
46
|
-
ActiveAgent::ProcessTelemetryTracesJob.perform_later(
|
|
47
|
-
account_id: @account&.id,
|
|
48
|
-
traces: traces.as_json,
|
|
49
|
-
sdk_info: sdk_info.as_json,
|
|
50
|
-
received_at: Time.current.iso8601(6)
|
|
51
|
-
)
|
|
52
|
-
else
|
|
53
|
-
# Local mode: process synchronously
|
|
54
|
-
process_traces_synchronously(traces, sdk_info)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
head :accepted
|
|
58
|
-
rescue ActionController::ParameterMissing => e
|
|
59
|
-
render json: { error: e.message }, status: :bad_request
|
|
60
|
-
rescue StandardError => e
|
|
61
|
-
Rails.logger.error("[ActiveAgent::Dashboard] Trace ingestion error: #{e.message}")
|
|
62
|
-
render json: { error: "Internal server error" }, status: :internal_server_error
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
private
|
|
66
|
-
|
|
67
|
-
# Authenticates the request using Bearer token from Authorization header.
|
|
68
|
-
# Only used in multi-tenant mode.
|
|
69
|
-
def authenticate_api_key!
|
|
70
|
-
token = extract_bearer_token
|
|
71
|
-
|
|
72
|
-
if token.blank?
|
|
73
|
-
render json: { error: "Missing Authorization header" }, status: :unauthorized
|
|
74
|
-
return
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
account_class = ActiveAgent::Dashboard.account_class.constantize
|
|
78
|
-
@account = account_class.find_by(telemetry_api_key: token)
|
|
79
|
-
|
|
80
|
-
if @account.nil?
|
|
81
|
-
render json: { error: "Invalid API key" }, status: :unauthorized
|
|
82
|
-
return
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Track usage for rate limiting (if the account responds to it)
|
|
86
|
-
@account.increment_telemetry_usage! if @account.respond_to?(:increment_telemetry_usage!)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Extracts Bearer token from Authorization header.
|
|
90
|
-
def extract_bearer_token
|
|
91
|
-
auth_header = request.headers["Authorization"]
|
|
92
|
-
return nil if auth_header.blank?
|
|
93
|
-
|
|
94
|
-
match = auth_header.match(/^Bearer\s+(.+)$/i)
|
|
95
|
-
match[1] if match
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Process traces synchronously for local development.
|
|
99
|
-
def process_traces_synchronously(traces, sdk_info)
|
|
100
|
-
model = ActiveAgent::Dashboard.trace_model
|
|
101
|
-
|
|
102
|
-
traces.each do |trace|
|
|
103
|
-
# Skip if trace already exists (idempotency)
|
|
104
|
-
next if model.exists?(trace_id: trace["trace_id"])
|
|
105
|
-
|
|
106
|
-
model.create_from_payload(trace, sdk_info)
|
|
107
|
-
rescue StandardError => e
|
|
108
|
-
Rails.logger.error(
|
|
109
|
-
"[ActiveAgent::Dashboard] Failed to process trace #{trace['trace_id']}: " \
|
|
110
|
-
"#{e.class} - #{e.message}"
|
|
111
|
-
)
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/application_controller.rb
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ActiveAgent
|
|
4
|
-
module Dashboard
|
|
5
|
-
# Base controller for the ActiveAgent Dashboard.
|
|
6
|
-
#
|
|
7
|
-
# Handles authentication and provides helper methods for multi-tenant mode.
|
|
8
|
-
class ApplicationController < ActionController::Base
|
|
9
|
-
protect_from_forgery with: :exception
|
|
10
|
-
|
|
11
|
-
before_action :authenticate_dashboard!
|
|
12
|
-
|
|
13
|
-
# Add the engine's view path
|
|
14
|
-
prepend_view_path ActiveAgent::Dashboard::Engine.dashboard_root.join("app", "views").to_s
|
|
15
|
-
|
|
16
|
-
# Use custom layout if configured, otherwise use engine layout
|
|
17
|
-
layout -> { ActiveAgent::Dashboard.layout || "active_agent/dashboard/application" }
|
|
18
|
-
|
|
19
|
-
helper_method :current_user, :current_owner
|
|
20
|
-
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
def authenticate_dashboard!
|
|
24
|
-
return if ActiveAgent::Dashboard.authentication_method.nil?
|
|
25
|
-
|
|
26
|
-
result = ActiveAgent::Dashboard.authentication_method.call(self)
|
|
27
|
-
head :unauthorized unless result
|
|
28
|
-
rescue StandardError => e
|
|
29
|
-
Rails.logger.error("[ActiveAgent::Dashboard] Authentication error: #{e.message}")
|
|
30
|
-
head :unauthorized
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Returns the current user from the host application.
|
|
34
|
-
def current_user
|
|
35
|
-
return nil unless ActiveAgent::Dashboard.current_user_method
|
|
36
|
-
|
|
37
|
-
send(ActiveAgent::Dashboard.current_user_method)
|
|
38
|
-
rescue NoMethodError
|
|
39
|
-
nil
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Returns the current owner (account in multi-tenant, user otherwise).
|
|
43
|
-
def current_owner
|
|
44
|
-
if ActiveAgent::Dashboard.multi_tenant? && ActiveAgent::Dashboard.current_account_method
|
|
45
|
-
send(ActiveAgent::Dashboard.current_account_method)
|
|
46
|
-
else
|
|
47
|
-
current_user
|
|
48
|
-
end
|
|
49
|
-
rescue NoMethodError
|
|
50
|
-
nil
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/dashboard_controller.rb
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ActiveAgent
|
|
4
|
-
module Dashboard
|
|
5
|
-
# Main dashboard controller showing overview metrics and recent activity.
|
|
6
|
-
#
|
|
7
|
-
class DashboardController < ApplicationController
|
|
8
|
-
def index
|
|
9
|
-
@agents = fetch_agents.limit(10)
|
|
10
|
-
@recent_runs = fetch_recent_runs.limit(10)
|
|
11
|
-
@recent_traces = fetch_recent_traces.limit(10)
|
|
12
|
-
@metrics = calculate_metrics
|
|
13
|
-
|
|
14
|
-
if ActiveAgent::Dashboard.use_inertia && defined?(InertiaRails)
|
|
15
|
-
render inertia: "Dashboard", props: {
|
|
16
|
-
agents: serialize_agents(@agents),
|
|
17
|
-
recentRuns: serialize_runs(@recent_runs),
|
|
18
|
-
recentTraces: serialize_traces(@recent_traces),
|
|
19
|
-
metrics: @metrics,
|
|
20
|
-
user: current_user_props,
|
|
21
|
-
account: current_account_props
|
|
22
|
-
}
|
|
23
|
-
else
|
|
24
|
-
render :index
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def fetch_agents
|
|
31
|
-
agents = Agent.order(updated_at: :desc)
|
|
32
|
-
agents = agents.for_owner(current_owner) if current_owner
|
|
33
|
-
agents
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def fetch_recent_runs
|
|
37
|
-
runs = AgentRun.includes(:agent).recent
|
|
38
|
-
if current_owner && ActiveAgent::Dashboard.multi_tenant?
|
|
39
|
-
runs = runs.joins(:agent).where(agents: { account_id: current_owner.id })
|
|
40
|
-
end
|
|
41
|
-
runs
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def fetch_recent_traces
|
|
45
|
-
traces = ActiveAgent::Dashboard.trace_model.recent
|
|
46
|
-
traces = traces.for_account(current_owner) if current_owner && ActiveAgent::Dashboard.multi_tenant?
|
|
47
|
-
traces
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def calculate_metrics
|
|
51
|
-
traces_24h = ActiveAgent::Dashboard.trace_model.where("created_at > ?", 24.hours.ago)
|
|
52
|
-
runs_24h = AgentRun.where("created_at > ?", 24.hours.ago)
|
|
53
|
-
|
|
54
|
-
if current_owner && ActiveAgent::Dashboard.multi_tenant?
|
|
55
|
-
traces_24h = traces_24h.for_account(current_owner)
|
|
56
|
-
runs_24h = runs_24h.joins(:agent).where(agents: { account_id: current_owner.id })
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
{
|
|
60
|
-
total_agents: fetch_agents.count,
|
|
61
|
-
active_agents: fetch_agents.active_agents.count,
|
|
62
|
-
total_runs_24h: runs_24h.count,
|
|
63
|
-
successful_runs_24h: runs_24h.successful.count,
|
|
64
|
-
failed_runs_24h: runs_24h.failed_runs.count,
|
|
65
|
-
total_traces_24h: traces_24h.count,
|
|
66
|
-
total_tokens_24h: traces_24h.sum(:total_input_tokens).to_i + traces_24h.sum(:total_output_tokens).to_i,
|
|
67
|
-
avg_duration_ms: runs_24h.where.not(duration_ms: nil).average(:duration_ms)&.round || 0
|
|
68
|
-
}
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def serialize_agents(agents)
|
|
72
|
-
agents.map do |agent|
|
|
73
|
-
{
|
|
74
|
-
id: agent.id,
|
|
75
|
-
name: agent.name,
|
|
76
|
-
slug: agent.slug,
|
|
77
|
-
description: agent.description,
|
|
78
|
-
provider: agent.provider,
|
|
79
|
-
model: agent.model,
|
|
80
|
-
status: agent.status,
|
|
81
|
-
presetType: agent.preset_type,
|
|
82
|
-
versionCount: agent.version_count,
|
|
83
|
-
updatedAt: agent.updated_at.iso8601
|
|
84
|
-
}
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def serialize_runs(runs)
|
|
89
|
-
runs.map(&:summary)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def serialize_traces(traces)
|
|
93
|
-
traces.map do |trace|
|
|
94
|
-
{
|
|
95
|
-
id: trace.id,
|
|
96
|
-
traceId: trace.trace_id,
|
|
97
|
-
displayName: trace.display_name,
|
|
98
|
-
status: trace.status,
|
|
99
|
-
duration: trace.formatted_duration,
|
|
100
|
-
tokens: trace.formatted_tokens,
|
|
101
|
-
timestamp: trace.timestamp&.iso8601
|
|
102
|
-
}
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def current_user_props
|
|
107
|
-
return nil unless current_user
|
|
108
|
-
|
|
109
|
-
{
|
|
110
|
-
id: current_user.id,
|
|
111
|
-
name: current_user.try(:display_name) || current_user.try(:name) || current_user.try(:email),
|
|
112
|
-
email: current_user.try(:email)
|
|
113
|
-
}
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def current_account_props
|
|
117
|
-
return nil unless current_owner && ActiveAgent::Dashboard.multi_tenant?
|
|
118
|
-
|
|
119
|
-
{
|
|
120
|
-
id: current_owner.id,
|
|
121
|
-
name: current_owner.try(:name)
|
|
122
|
-
}
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
end
|