activeagent 1.0.1 → 1.0.2
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/README.md +10 -4
- data/lib/active_agent/base.rb +3 -2
- data/lib/active_agent/concerns/provider.rb +6 -2
- data/lib/active_agent/concerns/rescue.rb +39 -0
- data/lib/active_agent/concerns/streaming.rb +2 -1
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/api/traces_controller.rb +117 -0
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/application_controller.rb +54 -0
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/dashboard_controller.rb +126 -0
- data/lib/active_agent/dashboard/app/controllers/active_agent/dashboard/traces_controller.rb +103 -0
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/agent_execution_job.rb +56 -0
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/application_job.rb +14 -0
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/sandbox_cleanup_job.rb +49 -0
- data/lib/active_agent/dashboard/app/jobs/active_agent/dashboard/sandbox_provision_job.rb +65 -0
- data/lib/active_agent/dashboard/app/jobs/active_agent/process_telemetry_traces_job.rb +77 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent.rb +256 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_run.rb +113 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_template.rb +208 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/agent_version.rb +60 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/application_record.rb +46 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/recording_action.rb +125 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/recording_snapshot.rb +83 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/sandbox_run.rb +52 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/sandbox_session.rb +169 -0
- data/lib/active_agent/dashboard/app/models/active_agent/dashboard/session_recording.rb +193 -0
- data/lib/active_agent/dashboard/app/models/active_agent/telemetry_trace.rb +198 -0
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/_trace_detail.html.erb +105 -0
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/index.html.erb +135 -0
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/metrics.html.erb +143 -0
- data/lib/active_agent/dashboard/app/views/active_agent/dashboard/traces/show.html.erb +36 -0
- data/lib/active_agent/dashboard/app/views/layouts/active_agent/dashboard/application.html.erb +94 -0
- data/lib/active_agent/dashboard/config/routes.rb +78 -0
- data/lib/active_agent/dashboard/engine.rb +39 -0
- data/lib/active_agent/dashboard.rb +151 -0
- data/lib/active_agent/providers/_base_provider.rb +2 -1
- data/lib/active_agent/providers/anthropic_provider.rb +14 -4
- data/lib/active_agent/providers/azure/_types.rb +5 -0
- data/lib/active_agent/providers/azure/options.rb +111 -0
- data/lib/active_agent/providers/azure_open_ai_provider.rb +2 -0
- data/lib/active_agent/providers/azure_openai_provider.rb +2 -0
- data/lib/active_agent/providers/azure_provider.rb +133 -0
- data/lib/active_agent/providers/azureopenai_provider.rb +2 -0
- data/lib/active_agent/providers/bedrock/_types.rb +8 -0
- data/lib/active_agent/providers/bedrock/bearer_client.rb +109 -0
- data/lib/active_agent/providers/bedrock/options.rb +77 -0
- data/lib/active_agent/providers/bedrock_provider.rb +84 -0
- data/lib/active_agent/providers/common/messages/_types.rb +6 -2
- data/lib/active_agent/providers/concerns/exception_handler.rb +1 -0
- data/lib/active_agent/providers/gemini/_types.rb +19 -0
- data/lib/active_agent/providers/gemini/options.rb +41 -0
- data/lib/active_agent/providers/gemini_provider.rb +94 -0
- data/lib/active_agent/providers/open_ai/chat/transforms.rb +37 -1
- data/lib/active_agent/providers/open_ai/chat_provider.rb +2 -0
- data/lib/active_agent/providers/ruby_llm/_types.rb +77 -0
- data/lib/active_agent/providers/ruby_llm/embedding_request.rb +16 -0
- data/lib/active_agent/providers/ruby_llm/messages/_types.rb +109 -0
- data/lib/active_agent/providers/ruby_llm/messages/assistant.rb +27 -0
- data/lib/active_agent/providers/ruby_llm/messages/base.rb +48 -0
- data/lib/active_agent/providers/ruby_llm/messages/system.rb +18 -0
- data/lib/active_agent/providers/ruby_llm/messages/tool.rb +24 -0
- data/lib/active_agent/providers/ruby_llm/messages/user.rb +18 -0
- data/lib/active_agent/providers/ruby_llm/options.rb +28 -0
- data/lib/active_agent/providers/ruby_llm/request.rb +30 -0
- data/lib/active_agent/providers/ruby_llm/tool_proxy.rb +45 -0
- data/lib/active_agent/providers/ruby_llm_provider.rb +407 -0
- data/lib/active_agent/railtie.rb +32 -1
- data/lib/active_agent/telemetry/configuration.rb +213 -0
- data/lib/active_agent/telemetry/instrumentation.rb +155 -0
- data/lib/active_agent/telemetry/reporter.rb +176 -0
- data/lib/active_agent/telemetry/span.rb +267 -0
- data/lib/active_agent/telemetry/tracer.rb +184 -0
- data/lib/active_agent/telemetry.rb +162 -0
- data/lib/active_agent/version.rb +1 -1
- data/lib/active_agent.rb +2 -0
- data/lib/generators/active_agent/dashboard/install/install_generator.rb +96 -0
- data/lib/generators/active_agent/dashboard/install/templates/initializer.rb +89 -0
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_runs.rb +42 -0
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_templates.rb +38 -0
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agent_versions.rb +22 -0
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_agents.rb +53 -0
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_sandbox_runs.rb +28 -0
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_sandbox_sessions.rb +43 -0
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_session_recordings.rb +44 -0
- data/lib/generators/active_agent/dashboard/install/templates/migrations/create_active_agent_telemetry_traces.rb +56 -0
- data/lib/generators/active_agent/dashboard/install_generator.rb +64 -0
- data/lib/generators/active_agent/dashboard/templates/active_agent_dashboard.rb.erb +30 -0
- data/lib/generators/active_agent/dashboard/templates/create_active_agent_telemetry_traces.rb.erb +30 -0
- metadata +99 -13
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAgent
|
|
4
|
+
module Telemetry
|
|
5
|
+
# Manages trace creation and lifecycle.
|
|
6
|
+
#
|
|
7
|
+
# The Tracer creates traces, manages the current trace context,
|
|
8
|
+
# and coordinates with the Reporter for async transmission.
|
|
9
|
+
#
|
|
10
|
+
# @example Basic usage
|
|
11
|
+
# tracer = Tracer.new(configuration)
|
|
12
|
+
# tracer.trace("MyAgent.greet") do |span|
|
|
13
|
+
# span.set_attribute("user_id", 123)
|
|
14
|
+
# span.add_span("llm.generate", span_type: :llm)
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
class Tracer
|
|
18
|
+
# @return [Configuration] Telemetry configuration
|
|
19
|
+
attr_reader :configuration
|
|
20
|
+
|
|
21
|
+
# @return [Reporter] The reporter for sending traces
|
|
22
|
+
attr_reader :reporter
|
|
23
|
+
|
|
24
|
+
# Thread-local storage for current trace context
|
|
25
|
+
CURRENT_SPAN_KEY = :active_agent_telemetry_current_span
|
|
26
|
+
|
|
27
|
+
def initialize(configuration)
|
|
28
|
+
@configuration = configuration
|
|
29
|
+
@reporter = Reporter.new(configuration)
|
|
30
|
+
@mutex = Mutex.new
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Creates and executes a new trace.
|
|
34
|
+
#
|
|
35
|
+
# @param name [String] Trace name (typically "AgentClass.action")
|
|
36
|
+
# @param attributes [Hash] Root span attributes
|
|
37
|
+
# @yield [span] Yields the root span for adding child spans
|
|
38
|
+
# @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)
|
|
48
|
+
return yield(Telemetry::NullSpan.new) unless should_trace?
|
|
49
|
+
|
|
50
|
+
trace_id = generate_trace_id
|
|
51
|
+
root_span = Span.new(
|
|
52
|
+
name,
|
|
53
|
+
trace_id: trace_id,
|
|
54
|
+
span_type: :root,
|
|
55
|
+
**default_attributes.merge(attributes)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
with_span(root_span) do
|
|
59
|
+
result = yield(root_span)
|
|
60
|
+
root_span.finish
|
|
61
|
+
report_trace(root_span)
|
|
62
|
+
result
|
|
63
|
+
end
|
|
64
|
+
rescue StandardError => e
|
|
65
|
+
root_span&.record_error(e)
|
|
66
|
+
root_span&.finish
|
|
67
|
+
report_trace(root_span) if root_span
|
|
68
|
+
raise
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Creates a standalone span (not within a trace block).
|
|
72
|
+
#
|
|
73
|
+
# @param name [String] Span name
|
|
74
|
+
# @param attributes [Hash] Span attributes
|
|
75
|
+
# @return [Span] The created span
|
|
76
|
+
def span(name, **attributes)
|
|
77
|
+
return Telemetry::NullSpan.new unless should_trace?
|
|
78
|
+
|
|
79
|
+
current = current_span
|
|
80
|
+
if current
|
|
81
|
+
current.add_span(name, **attributes)
|
|
82
|
+
else
|
|
83
|
+
Span.new(name, trace_id: generate_trace_id, **default_attributes.merge(attributes))
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Returns the current span from thread-local storage.
|
|
88
|
+
#
|
|
89
|
+
# @return [Span, nil] Current span or nil
|
|
90
|
+
def current_span
|
|
91
|
+
Thread.current[CURRENT_SPAN_KEY]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Flushes buffered traces immediately.
|
|
95
|
+
#
|
|
96
|
+
# @return [void]
|
|
97
|
+
def flush
|
|
98
|
+
reporter.flush
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Shuts down the tracer and reporter.
|
|
102
|
+
#
|
|
103
|
+
# @return [void]
|
|
104
|
+
def shutdown
|
|
105
|
+
reporter.shutdown
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
# 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
|
+
def with_span(span)
|
|
116
|
+
previous = Thread.current[CURRENT_SPAN_KEY]
|
|
117
|
+
Thread.current[CURRENT_SPAN_KEY] = span
|
|
118
|
+
yield
|
|
119
|
+
ensure
|
|
120
|
+
Thread.current[CURRENT_SPAN_KEY] = previous
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Reports a completed trace to the reporter.
|
|
124
|
+
#
|
|
125
|
+
# @param span [Span] Root span of the trace
|
|
126
|
+
def report_trace(span)
|
|
127
|
+
reporter.report(build_trace_payload(span))
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Builds the trace payload for transmission.
|
|
131
|
+
#
|
|
132
|
+
# @param root_span [Span] Root span
|
|
133
|
+
# @return [Hash] Trace payload
|
|
134
|
+
def build_trace_payload(root_span)
|
|
135
|
+
{
|
|
136
|
+
trace_id: root_span.trace_id,
|
|
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
|
+
}
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Flattens span hierarchy into array.
|
|
146
|
+
#
|
|
147
|
+
# @param span [Span] Root span
|
|
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))
|
|
153
|
+
end
|
|
154
|
+
result
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Returns whether this trace should be sampled.
|
|
158
|
+
#
|
|
159
|
+
# @return [Boolean]
|
|
160
|
+
def should_trace?
|
|
161
|
+
configuration.enabled? && configuration.configured? && configuration.should_sample?
|
|
162
|
+
end
|
|
163
|
+
|
|
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
|
+
# Returns default attributes for all spans.
|
|
172
|
+
#
|
|
173
|
+
# @return [Hash] Default attributes
|
|
174
|
+
def default_attributes
|
|
175
|
+
{
|
|
176
|
+
"service.name" => configuration.resolved_service_name,
|
|
177
|
+
"service.environment" => configuration.environment,
|
|
178
|
+
"telemetry.sdk.name" => "activeagent",
|
|
179
|
+
"telemetry.sdk.version" => ActiveAgent::VERSION
|
|
180
|
+
}
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "securerandom"
|
|
6
|
+
|
|
7
|
+
module ActiveAgent
|
|
8
|
+
# Telemetry module for collecting and reporting agent traces.
|
|
9
|
+
#
|
|
10
|
+
# Provides optional observability by capturing agent generation traces,
|
|
11
|
+
# tool calls, token usage, and errors. Reports to a configured endpoint
|
|
12
|
+
# (self-hosted or ActiveAgents.ai hosted service).
|
|
13
|
+
#
|
|
14
|
+
# = Features
|
|
15
|
+
#
|
|
16
|
+
# * **Trace Collection**: Captures full generation lifecycle with spans
|
|
17
|
+
# * **Token Tracking**: Records input/output/thinking tokens per generation
|
|
18
|
+
# * **Tool Call Tracing**: Captures tool invocations with arguments and results
|
|
19
|
+
# * **Error Tracking**: Records errors with backtraces
|
|
20
|
+
# * **Async Reporting**: Non-blocking HTTP reporting with background thread
|
|
21
|
+
#
|
|
22
|
+
# = Configuration
|
|
23
|
+
#
|
|
24
|
+
# Configure in your Rails initializer or activeagent.yml:
|
|
25
|
+
#
|
|
26
|
+
# @example Basic configuration
|
|
27
|
+
# ActiveAgent::Telemetry.configure do |config|
|
|
28
|
+
# config.enabled = true
|
|
29
|
+
# config.endpoint = "https://api.activeagents.ai/v1/traces"
|
|
30
|
+
# config.api_key = Rails.application.credentials.dig(:activeagents, :api_key)
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# @example YAML configuration (config/activeagent.yml)
|
|
34
|
+
# telemetry:
|
|
35
|
+
# enabled: true
|
|
36
|
+
# endpoint: https://api.activeagents.ai/v1/traces
|
|
37
|
+
# api_key: <%= Rails.application.credentials.dig(:activeagents, :api_key) %>
|
|
38
|
+
# sample_rate: 1.0
|
|
39
|
+
# batch_size: 100
|
|
40
|
+
# flush_interval: 5
|
|
41
|
+
#
|
|
42
|
+
# @example Self-hosted endpoint
|
|
43
|
+
# ActiveAgent::Telemetry.configure do |config|
|
|
44
|
+
# config.endpoint = "https://observability.mycompany.com/v1/traces"
|
|
45
|
+
# config.api_key = ENV["TELEMETRY_API_KEY"]
|
|
46
|
+
# end
|
|
47
|
+
#
|
|
48
|
+
# @see ActiveAgent::Telemetry::Configuration
|
|
49
|
+
# @see ActiveAgent::Telemetry::Tracer
|
|
50
|
+
module Telemetry
|
|
51
|
+
extend ActiveSupport::Autoload
|
|
52
|
+
|
|
53
|
+
autoload :Configuration
|
|
54
|
+
autoload :Tracer
|
|
55
|
+
autoload :Span
|
|
56
|
+
autoload :Reporter
|
|
57
|
+
autoload :Instrumentation
|
|
58
|
+
|
|
59
|
+
class << self
|
|
60
|
+
# Returns the telemetry configuration instance.
|
|
61
|
+
#
|
|
62
|
+
# @return [Configuration] The configuration instance
|
|
63
|
+
def configuration
|
|
64
|
+
@configuration ||= Configuration.new
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Configures telemetry with a block.
|
|
68
|
+
#
|
|
69
|
+
# @yield [config] Yields the configuration instance
|
|
70
|
+
# @yieldparam config [Configuration] The configuration to modify
|
|
71
|
+
# @return [Configuration] The modified configuration
|
|
72
|
+
#
|
|
73
|
+
# @example
|
|
74
|
+
# ActiveAgent::Telemetry.configure do |config|
|
|
75
|
+
# config.enabled = true
|
|
76
|
+
# config.endpoint = "https://api.activeagents.ai/v1/traces"
|
|
77
|
+
# config.api_key = "your-api-key"
|
|
78
|
+
# end
|
|
79
|
+
def configure
|
|
80
|
+
yield configuration if block_given?
|
|
81
|
+
configuration
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Resets the configuration to defaults.
|
|
85
|
+
#
|
|
86
|
+
# @return [Configuration] New default configuration
|
|
87
|
+
def reset_configuration!
|
|
88
|
+
@configuration = Configuration.new
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Returns whether telemetry is enabled and configured.
|
|
92
|
+
#
|
|
93
|
+
# @return [Boolean] True if telemetry should collect and report
|
|
94
|
+
def enabled?
|
|
95
|
+
configuration.enabled? && configuration.configured?
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Returns the global tracer instance.
|
|
99
|
+
#
|
|
100
|
+
# @return [Tracer] The tracer instance
|
|
101
|
+
def tracer
|
|
102
|
+
@tracer ||= Tracer.new(configuration)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Starts a new trace for an agent generation.
|
|
106
|
+
#
|
|
107
|
+
# @param name [String] Name of the trace (typically agent.action)
|
|
108
|
+
# @param attributes [Hash] Additional trace attributes
|
|
109
|
+
# @yield [trace] Yields the trace for adding spans
|
|
110
|
+
# @return [Span] The root span of the trace
|
|
111
|
+
#
|
|
112
|
+
# @example
|
|
113
|
+
# ActiveAgent::Telemetry.trace("WeatherAgent.forecast") do |trace|
|
|
114
|
+
# trace.add_span("llm.generate", provider: "anthropic")
|
|
115
|
+
# trace.set_tokens(input: 100, output: 50)
|
|
116
|
+
# end
|
|
117
|
+
def trace(name, **attributes, &block)
|
|
118
|
+
return yield(NullSpan.new) unless enabled?
|
|
119
|
+
|
|
120
|
+
tracer.trace(name, **attributes, &block)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Records a standalone span (outside of a trace context).
|
|
124
|
+
#
|
|
125
|
+
# @param name [String] Span name
|
|
126
|
+
# @param attributes [Hash] Span attributes
|
|
127
|
+
# @return [Span] The created span
|
|
128
|
+
def span(name, **attributes)
|
|
129
|
+
return NullSpan.new unless enabled?
|
|
130
|
+
|
|
131
|
+
tracer.span(name, **attributes)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Flushes any buffered traces immediately.
|
|
135
|
+
#
|
|
136
|
+
# @return [void]
|
|
137
|
+
def flush
|
|
138
|
+
tracer.flush if enabled?
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Shuts down telemetry, flushing remaining traces.
|
|
142
|
+
#
|
|
143
|
+
# @return [void]
|
|
144
|
+
def shutdown
|
|
145
|
+
tracer.shutdown if @tracer
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Null span implementation for when telemetry is disabled.
|
|
150
|
+
#
|
|
151
|
+
# Provides no-op methods that match Span interface to avoid
|
|
152
|
+
# nil checks throughout the codebase.
|
|
153
|
+
class NullSpan
|
|
154
|
+
def add_span(name, **attributes); self; end
|
|
155
|
+
def set_attribute(key, value); self; end
|
|
156
|
+
def set_tokens(input: 0, output: 0, thinking: 0); self; end
|
|
157
|
+
def set_status(status, message = nil); self; end
|
|
158
|
+
def record_error(error); self; end
|
|
159
|
+
def finish; self; end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
data/lib/active_agent/version.rb
CHANGED
data/lib/active_agent.rb
CHANGED
|
@@ -106,6 +106,8 @@ module ActiveAgent
|
|
|
106
106
|
autoload :Rescue, "active_agent/concerns/rescue"
|
|
107
107
|
autoload :Tooling, "active_agent/concerns/tooling"
|
|
108
108
|
autoload :View, "active_agent/concerns/view"
|
|
109
|
+
autoload :Telemetry
|
|
110
|
+
autoload :Dashboard
|
|
109
111
|
|
|
110
112
|
class << self
|
|
111
113
|
# Eagerly loads all ActiveAgent components and descendant agent classes.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/active_record"
|
|
5
|
+
|
|
6
|
+
module ActiveAgent
|
|
7
|
+
module Dashboard
|
|
8
|
+
module Generators
|
|
9
|
+
# Generator for installing the ActiveAgent Dashboard engine.
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# rails generate active_agent:dashboard:install
|
|
13
|
+
#
|
|
14
|
+
# This will:
|
|
15
|
+
# - Copy migration files for all dashboard models
|
|
16
|
+
# - Create an initializer for configuration
|
|
17
|
+
# - Add the engine mount to routes.rb
|
|
18
|
+
# - Seed default agent templates
|
|
19
|
+
#
|
|
20
|
+
class InstallGenerator < Rails::Generators::Base
|
|
21
|
+
include ActiveRecord::Generators::Migration
|
|
22
|
+
|
|
23
|
+
source_root File.expand_path("templates", __dir__)
|
|
24
|
+
|
|
25
|
+
class_option :multi_tenant, type: :boolean, default: false,
|
|
26
|
+
desc: "Configure for multi-tenant mode with account association"
|
|
27
|
+
|
|
28
|
+
class_option :skip_migrations, type: :boolean, default: false,
|
|
29
|
+
desc: "Skip copying migration files"
|
|
30
|
+
|
|
31
|
+
class_option :skip_routes, type: :boolean, default: false,
|
|
32
|
+
desc: "Skip adding route mount"
|
|
33
|
+
|
|
34
|
+
def copy_migrations
|
|
35
|
+
return if options[:skip_migrations]
|
|
36
|
+
|
|
37
|
+
migration_template "migrations/create_active_agent_agents.rb",
|
|
38
|
+
"db/migrate/create_active_agent_agents.rb"
|
|
39
|
+
|
|
40
|
+
migration_template "migrations/create_active_agent_agent_versions.rb",
|
|
41
|
+
"db/migrate/create_active_agent_agent_versions.rb"
|
|
42
|
+
|
|
43
|
+
migration_template "migrations/create_active_agent_agent_runs.rb",
|
|
44
|
+
"db/migrate/create_active_agent_agent_runs.rb"
|
|
45
|
+
|
|
46
|
+
migration_template "migrations/create_active_agent_agent_templates.rb",
|
|
47
|
+
"db/migrate/create_active_agent_agent_templates.rb"
|
|
48
|
+
|
|
49
|
+
migration_template "migrations/create_active_agent_sandbox_sessions.rb",
|
|
50
|
+
"db/migrate/create_active_agent_sandbox_sessions.rb"
|
|
51
|
+
|
|
52
|
+
migration_template "migrations/create_active_agent_sandbox_runs.rb",
|
|
53
|
+
"db/migrate/create_active_agent_sandbox_runs.rb"
|
|
54
|
+
|
|
55
|
+
migration_template "migrations/create_active_agent_session_recordings.rb",
|
|
56
|
+
"db/migrate/create_active_agent_session_recordings.rb"
|
|
57
|
+
|
|
58
|
+
migration_template "migrations/create_active_agent_telemetry_traces.rb",
|
|
59
|
+
"db/migrate/create_active_agent_telemetry_traces.rb"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def create_initializer
|
|
63
|
+
template "initializer.rb", "config/initializers/active_agent_dashboard.rb"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def mount_engine
|
|
67
|
+
return if options[:skip_routes]
|
|
68
|
+
|
|
69
|
+
route 'mount ActiveAgent::Dashboard::Engine => "/active_agent"'
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def show_post_install
|
|
73
|
+
say ""
|
|
74
|
+
say "ActiveAgent Dashboard installed!", :green
|
|
75
|
+
say ""
|
|
76
|
+
say "Next steps:"
|
|
77
|
+
say " 1. Run migrations: rails db:migrate"
|
|
78
|
+
say " 2. Seed templates: rails active_agent:dashboard:seed"
|
|
79
|
+
say " 3. Configure authentication in config/initializers/active_agent_dashboard.rb"
|
|
80
|
+
say " 4. Visit /active_agent to access the dashboard"
|
|
81
|
+
say ""
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def migration_version
|
|
87
|
+
"[#{ActiveRecord::Migration.current_version}]"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def multi_tenant?
|
|
91
|
+
options[:multi_tenant]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# ActiveAgent Dashboard Configuration
|
|
4
|
+
#
|
|
5
|
+
# This initializer configures the ActiveAgent Dashboard engine.
|
|
6
|
+
# See https://docs.activeagents.ai/dashboard for full documentation.
|
|
7
|
+
|
|
8
|
+
ActiveAgent::Dashboard.configure do |config|
|
|
9
|
+
# ==========================================================================
|
|
10
|
+
# Authentication
|
|
11
|
+
# ==========================================================================
|
|
12
|
+
|
|
13
|
+
# Set an authentication method that will be called on all dashboard controllers.
|
|
14
|
+
# This should authenticate the user and redirect/raise if unauthorized.
|
|
15
|
+
#
|
|
16
|
+
# Examples:
|
|
17
|
+
# config.authentication_method = ->(controller) { controller.authenticate_admin! }
|
|
18
|
+
# config.authentication_method = ->(controller) { controller.authenticate_user! }
|
|
19
|
+
#
|
|
20
|
+
# config.authentication_method = nil
|
|
21
|
+
|
|
22
|
+
<% if multi_tenant? -%>
|
|
23
|
+
# ==========================================================================
|
|
24
|
+
# Multi-tenant Mode
|
|
25
|
+
# ==========================================================================
|
|
26
|
+
|
|
27
|
+
# Enable multi-tenant mode for SaaS deployments with multiple accounts.
|
|
28
|
+
config.multi_tenant = true
|
|
29
|
+
|
|
30
|
+
# The Account model class name
|
|
31
|
+
config.account_class = "Account"
|
|
32
|
+
|
|
33
|
+
# The User model class name
|
|
34
|
+
config.user_class = "User"
|
|
35
|
+
|
|
36
|
+
# Method to call on controllers to get the current account
|
|
37
|
+
config.current_account_method = :current_account
|
|
38
|
+
|
|
39
|
+
# Method to call on controllers to get the current user
|
|
40
|
+
config.current_user_method = :current_user
|
|
41
|
+
|
|
42
|
+
<% else -%>
|
|
43
|
+
# ==========================================================================
|
|
44
|
+
# Local Mode (default)
|
|
45
|
+
# ==========================================================================
|
|
46
|
+
|
|
47
|
+
# Multi-tenant mode is disabled by default.
|
|
48
|
+
# Set to true if you're building a SaaS platform with multiple accounts.
|
|
49
|
+
# config.multi_tenant = false
|
|
50
|
+
|
|
51
|
+
# Optional: Associate agents with users
|
|
52
|
+
# config.user_class = "User"
|
|
53
|
+
# config.current_user_method = :current_user
|
|
54
|
+
|
|
55
|
+
<% end -%>
|
|
56
|
+
# ==========================================================================
|
|
57
|
+
# Sandbox Configuration
|
|
58
|
+
# ==========================================================================
|
|
59
|
+
|
|
60
|
+
# Sandbox service type for agent execution environments.
|
|
61
|
+
# Options: :local (Docker/Incus), :cloud_run, :kubernetes
|
|
62
|
+
config.sandbox_service = :local
|
|
63
|
+
|
|
64
|
+
# Custom sandbox limits (optional)
|
|
65
|
+
# config.sandbox_limits = {
|
|
66
|
+
# max_runs: 10,
|
|
67
|
+
# timeout_seconds: 300,
|
|
68
|
+
# max_tokens: 50_000,
|
|
69
|
+
# session_duration_minutes: 15
|
|
70
|
+
# }
|
|
71
|
+
|
|
72
|
+
# ==========================================================================
|
|
73
|
+
# UI Configuration
|
|
74
|
+
# ==========================================================================
|
|
75
|
+
|
|
76
|
+
# Use Inertia.js with React for the frontend (requires additional setup)
|
|
77
|
+
# config.use_inertia = false
|
|
78
|
+
|
|
79
|
+
# Custom layout for dashboard views
|
|
80
|
+
# config.layout = "application"
|
|
81
|
+
|
|
82
|
+
# ==========================================================================
|
|
83
|
+
# Storage Configuration
|
|
84
|
+
# ==========================================================================
|
|
85
|
+
|
|
86
|
+
# Storage service for screenshots and snapshots.
|
|
87
|
+
# Must respond to #signed_url_for(key, expires_in:) and #fetch_snapshot(key)
|
|
88
|
+
# config.storage_service = MyStorageService.new
|
|
89
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateActiveAgentAgentRuns < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def change
|
|
5
|
+
create_table :active_agent_agent_runs do |t|
|
|
6
|
+
t.references :agent, null: false, foreign_key: { to_table: :active_agent_agents }
|
|
7
|
+
|
|
8
|
+
# Input
|
|
9
|
+
t.text :input_prompt
|
|
10
|
+
t.jsonb :input_params, default: {}
|
|
11
|
+
|
|
12
|
+
# Output
|
|
13
|
+
t.text :output
|
|
14
|
+
t.jsonb :output_metadata, default: {}
|
|
15
|
+
|
|
16
|
+
# Execution details
|
|
17
|
+
t.integer :status, default: 0, null: false
|
|
18
|
+
t.integer :duration_ms
|
|
19
|
+
t.datetime :started_at
|
|
20
|
+
t.datetime :completed_at
|
|
21
|
+
|
|
22
|
+
# Token usage
|
|
23
|
+
t.integer :input_tokens
|
|
24
|
+
t.integer :output_tokens
|
|
25
|
+
t.integer :total_tokens
|
|
26
|
+
|
|
27
|
+
# Error tracking
|
|
28
|
+
t.text :error_message
|
|
29
|
+
t.text :error_backtrace
|
|
30
|
+
|
|
31
|
+
# Trace for debugging
|
|
32
|
+
t.string :trace_id
|
|
33
|
+
t.jsonb :logs, default: []
|
|
34
|
+
|
|
35
|
+
t.timestamps
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
add_index :active_agent_agent_runs, :status
|
|
39
|
+
add_index :active_agent_agent_runs, :trace_id
|
|
40
|
+
add_index :active_agent_agent_runs, :created_at
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateActiveAgentAgentTemplates < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def change
|
|
5
|
+
create_table :active_agent_agent_templates do |t|
|
|
6
|
+
t.string :name, null: false
|
|
7
|
+
t.string :slug, null: false
|
|
8
|
+
t.text :description
|
|
9
|
+
t.string :category
|
|
10
|
+
|
|
11
|
+
# Template configuration (same as agents)
|
|
12
|
+
t.string :provider, default: "openai"
|
|
13
|
+
t.string :model, default: "gpt-4o-mini"
|
|
14
|
+
t.text :instructions
|
|
15
|
+
t.string :preset_type
|
|
16
|
+
t.jsonb :appearance, default: {}
|
|
17
|
+
t.jsonb :instruction_sets, default: []
|
|
18
|
+
t.jsonb :tools, default: []
|
|
19
|
+
t.jsonb :mcp_servers, default: {}
|
|
20
|
+
t.jsonb :model_config, default: {}
|
|
21
|
+
|
|
22
|
+
# Metadata
|
|
23
|
+
t.string :icon
|
|
24
|
+
t.integer :usage_count, default: 0
|
|
25
|
+
t.boolean :featured, default: false
|
|
26
|
+
t.boolean :public, default: true
|
|
27
|
+
t.boolean :free_tier, default: true
|
|
28
|
+
|
|
29
|
+
t.timestamps
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
add_index :active_agent_agent_templates, :slug, unique: true
|
|
33
|
+
add_index :active_agent_agent_templates, :category
|
|
34
|
+
add_index :active_agent_agent_templates, :featured
|
|
35
|
+
add_index :active_agent_agent_templates, :usage_count
|
|
36
|
+
add_index :active_agent_agent_templates, :free_tier
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateActiveAgentAgentVersions < ActiveRecord::Migration<%= migration_version %>
|
|
4
|
+
def change
|
|
5
|
+
create_table :active_agent_agent_versions do |t|
|
|
6
|
+
t.references :agent, null: false, foreign_key: { to_table: :active_agent_agents }
|
|
7
|
+
|
|
8
|
+
t.integer :version_number, null: false, default: 1
|
|
9
|
+
t.string :change_summary
|
|
10
|
+
|
|
11
|
+
# Snapshot of agent configuration at this version
|
|
12
|
+
t.jsonb :configuration_snapshot, null: false, default: {}
|
|
13
|
+
|
|
14
|
+
# Who made the change
|
|
15
|
+
t.string :created_by
|
|
16
|
+
|
|
17
|
+
t.timestamps
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
add_index :active_agent_agent_versions, [:agent_id, :version_number], unique: true
|
|
21
|
+
end
|
|
22
|
+
end
|