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,135 @@
|
|
|
1
|
+
<div data-controller="refresh" data-refresh-interval-value="30000">
|
|
2
|
+
<!-- Metrics Summary -->
|
|
3
|
+
<div class="grid grid-cols-1 md:grid-cols-5 gap-4 mb-6">
|
|
4
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
5
|
+
<div class="text-sm font-medium text-gray-500 dark:text-gray-400">Total Traces</div>
|
|
6
|
+
<div class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white">
|
|
7
|
+
<%= number_with_delimiter(@metrics[:total_traces]) %>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="text-xs text-gray-400">Last 24h</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
13
|
+
<div class="text-sm font-medium text-gray-500 dark:text-gray-400">Total Tokens</div>
|
|
14
|
+
<div class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white">
|
|
15
|
+
<%= number_to_human(@metrics[:total_tokens], precision: 2) %>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="text-xs text-gray-400">Last 24h</div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
21
|
+
<div class="text-sm font-medium text-gray-500 dark:text-gray-400">Avg Duration</div>
|
|
22
|
+
<div class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white">
|
|
23
|
+
<%= @metrics[:avg_duration_ms] >= 1000 ? "#{(@metrics[:avg_duration_ms] / 1000.0).round(2)}s" : "#{@metrics[:avg_duration_ms].round(0)}ms" %>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="text-xs text-gray-400">Last 24h</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
29
|
+
<div class="text-sm font-medium text-gray-500 dark:text-gray-400">Error Rate</div>
|
|
30
|
+
<div class="mt-1 text-2xl font-semibold <%= @metrics[:error_rate] > 5 ? 'text-red-600' : 'text-gray-900 dark:text-white' %>">
|
|
31
|
+
<%= @metrics[:error_rate] %>%
|
|
32
|
+
</div>
|
|
33
|
+
<div class="text-xs text-gray-400">Last 24h</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
|
37
|
+
<div class="text-sm font-medium text-gray-500 dark:text-gray-400">Active Agents</div>
|
|
38
|
+
<div class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white">
|
|
39
|
+
<%= @metrics[:unique_agents] %>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="text-xs text-gray-400">Last 24h</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<!-- Traces Table -->
|
|
46
|
+
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden" data-controller="traces">
|
|
47
|
+
<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center">
|
|
48
|
+
<h2 class="text-lg font-medium text-gray-900 dark:text-white">Recent Traces</h2>
|
|
49
|
+
<div class="flex gap-2">
|
|
50
|
+
<%= link_to "All", traces_path, class: "px-3 py-1 text-sm rounded #{params[:status].blank? ? 'bg-indigo-100 text-indigo-700' : 'text-gray-600 hover:bg-gray-100'}" %>
|
|
51
|
+
<%= link_to "Errors", traces_path(status: "error"), class: "px-3 py-1 text-sm rounded #{params[:status] == 'error' ? 'bg-red-100 text-red-700' : 'text-gray-600 hover:bg-gray-100'}" %>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<% if @traces.any? %>
|
|
56
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
57
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
58
|
+
<tr>
|
|
59
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Agent</th>
|
|
60
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
|
|
61
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Duration</th>
|
|
62
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tokens</th>
|
|
63
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th>
|
|
64
|
+
</tr>
|
|
65
|
+
</thead>
|
|
66
|
+
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
|
67
|
+
<% @traces.each do |trace| %>
|
|
68
|
+
<!-- Main Row -->
|
|
69
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700 cursor-pointer"
|
|
70
|
+
data-trace-id="<%= trace.id %>"
|
|
71
|
+
data-action="click->traces#toggle">
|
|
72
|
+
<td class="px-4 py-3">
|
|
73
|
+
<div class="flex items-center">
|
|
74
|
+
<span class="text-sm font-medium text-gray-900 dark:text-white">
|
|
75
|
+
<%= trace.agent_class || "Unknown" %>
|
|
76
|
+
</span>
|
|
77
|
+
<% if trace.agent_action %>
|
|
78
|
+
<span class="ml-2 text-sm text-gray-500 dark:text-gray-400">
|
|
79
|
+
.<%= trace.agent_action %>
|
|
80
|
+
</span>
|
|
81
|
+
<% end %>
|
|
82
|
+
</div>
|
|
83
|
+
<div class="text-xs text-gray-400 font-mono"><%= trace.trace_id&.first(8) %></div>
|
|
84
|
+
</td>
|
|
85
|
+
<td class="px-4 py-3">
|
|
86
|
+
<% if trace.error? %>
|
|
87
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200">
|
|
88
|
+
Error
|
|
89
|
+
</span>
|
|
90
|
+
<% else %>
|
|
91
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
|
|
92
|
+
OK
|
|
93
|
+
</span>
|
|
94
|
+
<% end %>
|
|
95
|
+
</td>
|
|
96
|
+
<td class="px-4 py-3 text-sm text-gray-900 dark:text-white">
|
|
97
|
+
<%= trace.formatted_duration %>
|
|
98
|
+
</td>
|
|
99
|
+
<td class="px-4 py-3">
|
|
100
|
+
<div class="flex items-center gap-2 text-sm">
|
|
101
|
+
<span class="text-gray-900 dark:text-white"><%= trace.formatted_tokens %></span>
|
|
102
|
+
<% if trace.total_thinking_tokens.to_i > 0 %>
|
|
103
|
+
<span class="text-xs text-purple-600 dark:text-purple-400" title="Thinking tokens">
|
|
104
|
+
+<%= number_to_human(trace.total_thinking_tokens, precision: 1) %> thinking
|
|
105
|
+
</span>
|
|
106
|
+
<% end %>
|
|
107
|
+
</div>
|
|
108
|
+
</td>
|
|
109
|
+
<td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
|
|
110
|
+
<%= time_ago_in_words(trace.timestamp || trace.created_at) %> ago
|
|
111
|
+
</td>
|
|
112
|
+
</tr>
|
|
113
|
+
|
|
114
|
+
<!-- Expanded Detail Row -->
|
|
115
|
+
<tr id="detail-<%= trace.id %>" class="hidden bg-gray-50 dark:bg-gray-900">
|
|
116
|
+
<td colspan="5" class="px-4 py-4">
|
|
117
|
+
<%= render partial: "trace_detail", locals: { trace: trace } %>
|
|
118
|
+
</td>
|
|
119
|
+
</tr>
|
|
120
|
+
<% end %>
|
|
121
|
+
</tbody>
|
|
122
|
+
</table>
|
|
123
|
+
<% else %>
|
|
124
|
+
<div class="px-4 py-12 text-center">
|
|
125
|
+
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
126
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
127
|
+
</svg>
|
|
128
|
+
<h3 class="mt-2 text-sm font-medium text-gray-900 dark:text-white">No traces yet</h3>
|
|
129
|
+
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
|
130
|
+
Traces will appear here when your agents generate responses.
|
|
131
|
+
</p>
|
|
132
|
+
</div>
|
|
133
|
+
<% end %>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<div data-controller="refresh" data-refresh-interval-value="60000">
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">Metrics Overview</h1>
|
|
3
|
+
|
|
4
|
+
<!-- Summary Cards -->
|
|
5
|
+
<div class="grid grid-cols-1 md:grid-cols-5 gap-4 mb-8">
|
|
6
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
|
7
|
+
<div class="flex items-center">
|
|
8
|
+
<div class="p-3 rounded-full bg-indigo-100 dark:bg-indigo-900">
|
|
9
|
+
<svg class="h-6 w-6 text-indigo-600 dark:text-indigo-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
10
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
11
|
+
</svg>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="ml-4">
|
|
14
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Total Traces</p>
|
|
15
|
+
<p class="text-2xl font-semibold text-gray-900 dark:text-white">
|
|
16
|
+
<%= number_with_delimiter(@metrics[:total_traces]) %>
|
|
17
|
+
</p>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
|
23
|
+
<div class="flex items-center">
|
|
24
|
+
<div class="p-3 rounded-full bg-blue-100 dark:bg-blue-900">
|
|
25
|
+
<svg class="h-6 w-6 text-blue-600 dark:text-blue-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
26
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
|
27
|
+
</svg>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="ml-4">
|
|
30
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Total Tokens</p>
|
|
31
|
+
<p class="text-2xl font-semibold text-gray-900 dark:text-white">
|
|
32
|
+
<%= number_to_human(@metrics[:total_tokens], precision: 2) %>
|
|
33
|
+
</p>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
|
39
|
+
<div class="flex items-center">
|
|
40
|
+
<div class="p-3 rounded-full bg-green-100 dark:bg-green-900">
|
|
41
|
+
<svg class="h-6 w-6 text-green-600 dark:text-green-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
42
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
43
|
+
</svg>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="ml-4">
|
|
46
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Avg Duration</p>
|
|
47
|
+
<p class="text-2xl font-semibold text-gray-900 dark:text-white">
|
|
48
|
+
<%= @metrics[:avg_duration_ms] >= 1000 ? "#{(@metrics[:avg_duration_ms] / 1000.0).round(2)}s" : "#{@metrics[:avg_duration_ms].round(0)}ms" %>
|
|
49
|
+
</p>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
|
55
|
+
<div class="flex items-center">
|
|
56
|
+
<div class="p-3 rounded-full <%= @metrics[:error_rate] > 5 ? 'bg-red-100 dark:bg-red-900' : 'bg-gray-100 dark:bg-gray-700' %>">
|
|
57
|
+
<svg class="h-6 w-6 <%= @metrics[:error_rate] > 5 ? 'text-red-600 dark:text-red-400' : 'text-gray-600 dark:text-gray-400' %>" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
58
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
|
59
|
+
</svg>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="ml-4">
|
|
62
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Error Rate</p>
|
|
63
|
+
<p class="text-2xl font-semibold <%= @metrics[:error_rate] > 5 ? 'text-red-600' : 'text-gray-900 dark:text-white' %>">
|
|
64
|
+
<%= @metrics[:error_rate] %>%
|
|
65
|
+
</p>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
|
71
|
+
<div class="flex items-center">
|
|
72
|
+
<div class="p-3 rounded-full bg-purple-100 dark:bg-purple-900">
|
|
73
|
+
<svg class="h-6 w-6 text-purple-600 dark:text-purple-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
74
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
|
75
|
+
</svg>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="ml-4">
|
|
78
|
+
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Active Agents</p>
|
|
79
|
+
<p class="text-2xl font-semibold text-gray-900 dark:text-white">
|
|
80
|
+
<%= @metrics[:unique_agents] %>
|
|
81
|
+
</p>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<!-- Agent Statistics -->
|
|
88
|
+
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden mb-8">
|
|
89
|
+
<div class="px-4 py-4 border-b border-gray-200 dark:border-gray-700">
|
|
90
|
+
<h2 class="text-lg font-medium text-gray-900 dark:text-white">Agent Statistics</h2>
|
|
91
|
+
<p class="text-sm text-gray-500 dark:text-gray-400">Performance breakdown by agent class (last 24h)</p>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<% if @agent_stats.any? %>
|
|
95
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
96
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
97
|
+
<tr>
|
|
98
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Agent</th>
|
|
99
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Traces</th>
|
|
100
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tokens</th>
|
|
101
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Avg Duration</th>
|
|
102
|
+
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Errors</th>
|
|
103
|
+
</tr>
|
|
104
|
+
</thead>
|
|
105
|
+
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
|
106
|
+
<% @agent_stats.each do |stat| %>
|
|
107
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
|
|
108
|
+
<td class="px-4 py-3">
|
|
109
|
+
<span class="text-sm font-medium text-gray-900 dark:text-white">
|
|
110
|
+
<%= stat.agent_class || "Unknown" %>
|
|
111
|
+
</span>
|
|
112
|
+
</td>
|
|
113
|
+
<td class="px-4 py-3 text-sm text-gray-900 dark:text-white">
|
|
114
|
+
<%= number_with_delimiter(stat.trace_count) %>
|
|
115
|
+
</td>
|
|
116
|
+
<td class="px-4 py-3 text-sm text-gray-900 dark:text-white">
|
|
117
|
+
<%= number_to_human(stat.total_tokens || 0, precision: 1) %>
|
|
118
|
+
</td>
|
|
119
|
+
<td class="px-4 py-3 text-sm text-gray-900 dark:text-white">
|
|
120
|
+
<% avg = stat.avg_duration.to_f %>
|
|
121
|
+
<%= avg >= 1000 ? "#{(avg / 1000.0).round(2)}s" : "#{avg.round(0)}ms" %>
|
|
122
|
+
</td>
|
|
123
|
+
<td class="px-4 py-3">
|
|
124
|
+
<% error_count = stat.error_count.to_i %>
|
|
125
|
+
<% if error_count > 0 %>
|
|
126
|
+
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200">
|
|
127
|
+
<%= error_count %>
|
|
128
|
+
</span>
|
|
129
|
+
<% else %>
|
|
130
|
+
<span class="text-sm text-gray-400">0</span>
|
|
131
|
+
<% end %>
|
|
132
|
+
</td>
|
|
133
|
+
</tr>
|
|
134
|
+
<% end %>
|
|
135
|
+
</tbody>
|
|
136
|
+
</table>
|
|
137
|
+
<% else %>
|
|
138
|
+
<div class="px-4 py-8 text-center text-gray-500 dark:text-gray-400">
|
|
139
|
+
No agent data available yet.
|
|
140
|
+
</div>
|
|
141
|
+
<% end %>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<div class="mb-4">
|
|
2
|
+
<%= link_to "← Back to traces", traces_path, class: "text-indigo-600 hover:text-indigo-800 text-sm" %>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
<div class="bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden">
|
|
6
|
+
<div class="px-4 py-4 border-b border-gray-200 dark:border-gray-700">
|
|
7
|
+
<div class="flex items-center justify-between">
|
|
8
|
+
<div>
|
|
9
|
+
<h1 class="text-xl font-semibold text-gray-900 dark:text-white">
|
|
10
|
+
<%= @trace.display_name %>
|
|
11
|
+
</h1>
|
|
12
|
+
<p class="text-sm text-gray-500 dark:text-gray-400 font-mono">
|
|
13
|
+
<%= @trace.trace_id %>
|
|
14
|
+
</p>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="flex items-center gap-4">
|
|
17
|
+
<% if @trace.error? %>
|
|
18
|
+
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200">
|
|
19
|
+
Error
|
|
20
|
+
</span>
|
|
21
|
+
<% else %>
|
|
22
|
+
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
|
|
23
|
+
Success
|
|
24
|
+
</span>
|
|
25
|
+
<% end %>
|
|
26
|
+
<span class="text-sm text-gray-500">
|
|
27
|
+
<%= @trace.timestamp&.strftime("%Y-%m-%d %H:%M:%S") %>
|
|
28
|
+
</span>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="p-4">
|
|
34
|
+
<%= render partial: "trace_detail", locals: { trace: @trace } %>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" class="h-full">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>ActiveAgent Dashboard</title>
|
|
7
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
8
|
+
<script src="https://unpkg.com/@hotwired/turbo@7.3.0/dist/turbo.es2017-esm.js" type="module"></script>
|
|
9
|
+
<script src="https://unpkg.com/@hotwired/stimulus@3.2.2/dist/stimulus.umd.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
[data-turbo-preview] { opacity: 0.5; }
|
|
12
|
+
.span-bar { transition: all 0.2s ease; }
|
|
13
|
+
.span-bar:hover { transform: scaleY(1.1); }
|
|
14
|
+
</style>
|
|
15
|
+
<script>
|
|
16
|
+
// Initialize Stimulus
|
|
17
|
+
const application = Stimulus.Application.start();
|
|
18
|
+
|
|
19
|
+
// Traces controller for expandable rows
|
|
20
|
+
application.register("traces", class extends Stimulus.Controller {
|
|
21
|
+
static targets = ["row", "detail"]
|
|
22
|
+
|
|
23
|
+
toggle(event) {
|
|
24
|
+
const traceId = event.currentTarget.dataset.traceId;
|
|
25
|
+
const detail = document.getElementById(`detail-${traceId}`);
|
|
26
|
+
if (detail) {
|
|
27
|
+
detail.classList.toggle("hidden");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Auto-refresh controller
|
|
33
|
+
application.register("refresh", class extends Stimulus.Controller {
|
|
34
|
+
static values = { interval: Number }
|
|
35
|
+
|
|
36
|
+
connect() {
|
|
37
|
+
if (this.intervalValue > 0) {
|
|
38
|
+
this.startRefresh();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
disconnect() {
|
|
43
|
+
this.stopRefresh();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
startRefresh() {
|
|
47
|
+
this.timer = setInterval(() => {
|
|
48
|
+
Turbo.visit(window.location.href, { action: "replace" });
|
|
49
|
+
}, this.intervalValue);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
stopRefresh() {
|
|
53
|
+
if (this.timer) clearInterval(this.timer);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
</script>
|
|
57
|
+
</head>
|
|
58
|
+
<body class="h-full bg-gray-50 dark:bg-gray-900">
|
|
59
|
+
<div class="min-h-full">
|
|
60
|
+
<!-- Header -->
|
|
61
|
+
<nav class="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
|
|
62
|
+
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
|
63
|
+
<div class="flex h-16 items-center justify-between">
|
|
64
|
+
<div class="flex items-center">
|
|
65
|
+
<div class="flex-shrink-0">
|
|
66
|
+
<span class="text-xl font-bold text-indigo-600 dark:text-indigo-400">
|
|
67
|
+
ActiveAgent
|
|
68
|
+
</span>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="ml-10 flex items-baseline space-x-4">
|
|
71
|
+
<%= link_to "Traces",
|
|
72
|
+
active_agent_dashboard.traces_path,
|
|
73
|
+
class: "px-3 py-2 rounded-md text-sm font-medium #{request.path == active_agent_dashboard.traces_path ? 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900 dark:text-indigo-200' : 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'}" %>
|
|
74
|
+
<%= link_to "Metrics",
|
|
75
|
+
active_agent_dashboard.metrics_traces_path,
|
|
76
|
+
class: "px-3 py-2 rounded-md text-sm font-medium #{request.path == active_agent_dashboard.metrics_traces_path ? 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900 dark:text-indigo-200' : 'text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700'}" %>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
<div class="text-sm text-gray-500 dark:text-gray-400">
|
|
80
|
+
Local Telemetry
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</nav>
|
|
85
|
+
|
|
86
|
+
<!-- Main content -->
|
|
87
|
+
<main>
|
|
88
|
+
<div class="mx-auto max-w-7xl py-6 px-4 sm:px-6 lg:px-8">
|
|
89
|
+
<%= yield %>
|
|
90
|
+
</div>
|
|
91
|
+
</main>
|
|
92
|
+
</div>
|
|
93
|
+
</body>
|
|
94
|
+
</html>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
ActiveAgent::Dashboard::Engine.routes.draw do
|
|
4
|
+
# Dashboard root
|
|
5
|
+
root to: "dashboard#index"
|
|
6
|
+
|
|
7
|
+
# Dashboard
|
|
8
|
+
get "dashboard", to: "dashboard#index"
|
|
9
|
+
|
|
10
|
+
# Traces
|
|
11
|
+
resources :traces, only: [ :index, :show ] do
|
|
12
|
+
collection do
|
|
13
|
+
get :metrics
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Agents
|
|
18
|
+
resources :agents do
|
|
19
|
+
member do
|
|
20
|
+
post :execute
|
|
21
|
+
post :test
|
|
22
|
+
get :versions
|
|
23
|
+
post :restore_version
|
|
24
|
+
end
|
|
25
|
+
resources :runs, controller: "agent_runs", only: [ :index, :show ] do
|
|
26
|
+
member do
|
|
27
|
+
post :cancel
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Agent Templates
|
|
33
|
+
resources :templates, only: [ :index, :show ] do
|
|
34
|
+
member do
|
|
35
|
+
post :create_agent
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Sandbox Sessions
|
|
40
|
+
resources :sandboxes, controller: "sandbox_sessions" do
|
|
41
|
+
member do
|
|
42
|
+
post :provision
|
|
43
|
+
post :execute
|
|
44
|
+
post :expire
|
|
45
|
+
end
|
|
46
|
+
resources :runs, controller: "sandbox_runs", only: [ :index, :show ]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Session Recordings
|
|
50
|
+
resources :recordings, controller: "session_recordings", only: [ :index, :show ] do
|
|
51
|
+
member do
|
|
52
|
+
get :timeline
|
|
53
|
+
get :playback
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# API namespace
|
|
58
|
+
namespace :api do
|
|
59
|
+
namespace :v1 do
|
|
60
|
+
# Telemetry ingestion
|
|
61
|
+
resources :traces, only: [ :create ]
|
|
62
|
+
|
|
63
|
+
# Agent execution API
|
|
64
|
+
resources :agents, only: [ :index, :show ] do
|
|
65
|
+
member do
|
|
66
|
+
post :execute
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Sandbox API
|
|
71
|
+
resources :sandboxes, only: [ :create, :show ] do
|
|
72
|
+
member do
|
|
73
|
+
post :execute
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveAgent
|
|
4
|
+
module Dashboard
|
|
5
|
+
# Rails Engine for the ActiveAgent Dashboard.
|
|
6
|
+
#
|
|
7
|
+
# Provides a full-featured dashboard for managing agents, viewing telemetry,
|
|
8
|
+
# running sandboxes, and recording sessions.
|
|
9
|
+
#
|
|
10
|
+
# Mount in your routes:
|
|
11
|
+
# mount ActiveAgent::Dashboard::Engine => "/active_agent"
|
|
12
|
+
#
|
|
13
|
+
class Engine < ::Rails::Engine
|
|
14
|
+
isolate_namespace ActiveAgent::Dashboard
|
|
15
|
+
|
|
16
|
+
# Use a unique engine name to avoid conflicts
|
|
17
|
+
engine_name "active_agent"
|
|
18
|
+
|
|
19
|
+
# Override engine root to point to the dashboard directory
|
|
20
|
+
# This must be set before paths are computed
|
|
21
|
+
def self.root
|
|
22
|
+
@root ||= Pathname.new(File.expand_path("..", __FILE__))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Alias for consistency with existing code
|
|
26
|
+
def self.dashboard_root
|
|
27
|
+
root
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
config.active_agent_dashboard = ActiveSupport::OrderedOptions.new
|
|
31
|
+
|
|
32
|
+
initializer "active_agent.dashboard.append_view_paths" do
|
|
33
|
+
ActiveSupport.on_load(:action_controller) do
|
|
34
|
+
prepend_view_path ActiveAgent::Dashboard::Engine.root.join("app", "views").to_s
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_agent/dashboard/engine"
|
|
4
|
+
|
|
5
|
+
module ActiveAgent
|
|
6
|
+
# Dashboard engine for visualizing telemetry data and managing agents.
|
|
7
|
+
#
|
|
8
|
+
# Mount the engine in your routes to access the full dashboard:
|
|
9
|
+
#
|
|
10
|
+
# # config/routes.rb
|
|
11
|
+
# mount ActiveAgent::Dashboard::Engine => "/active_agent"
|
|
12
|
+
#
|
|
13
|
+
# The dashboard provides:
|
|
14
|
+
# - Agent management: Create, edit, version, and execute agents
|
|
15
|
+
# - Traces view: See all agent invocations with spans, timing, and token usage
|
|
16
|
+
# - Metrics view: Aggregate statistics and charts
|
|
17
|
+
# - Sandbox execution: Run agents in isolated environments
|
|
18
|
+
# - Session recordings: Capture and replay browser sessions
|
|
19
|
+
#
|
|
20
|
+
# = Configuration Modes
|
|
21
|
+
#
|
|
22
|
+
# == Local Mode (default)
|
|
23
|
+
# For self-hosted, single-tenant deployments:
|
|
24
|
+
#
|
|
25
|
+
# ActiveAgent::Dashboard.configure do |config|
|
|
26
|
+
# config.authentication_method = ->(controller) { controller.authenticate_admin! }
|
|
27
|
+
# config.sandbox_service = :local # Docker/Incus
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# == Multi-tenant Mode
|
|
31
|
+
# For SaaS platforms with multiple accounts:
|
|
32
|
+
#
|
|
33
|
+
# ActiveAgent::Dashboard.configure do |config|
|
|
34
|
+
# config.multi_tenant = true
|
|
35
|
+
# config.account_class = "Account"
|
|
36
|
+
# config.user_class = "User"
|
|
37
|
+
# config.current_account_method = :current_account
|
|
38
|
+
# config.current_user_method = :current_user
|
|
39
|
+
# config.authentication_method = ->(controller) { controller.authenticate_user! }
|
|
40
|
+
# config.sandbox_service = :cloud_run # Managed
|
|
41
|
+
# config.use_inertia = true
|
|
42
|
+
# end
|
|
43
|
+
#
|
|
44
|
+
module Dashboard
|
|
45
|
+
class << self
|
|
46
|
+
# Authentication method to call on controllers
|
|
47
|
+
# @return [Proc, nil] A proc that receives the controller instance
|
|
48
|
+
attr_accessor :authentication_method
|
|
49
|
+
|
|
50
|
+
# Enable multi-tenant mode (requires account association)
|
|
51
|
+
# @return [Boolean]
|
|
52
|
+
attr_accessor :multi_tenant
|
|
53
|
+
|
|
54
|
+
# Class name for the Account model (multi-tenant mode)
|
|
55
|
+
# @return [String, nil]
|
|
56
|
+
attr_accessor :account_class
|
|
57
|
+
|
|
58
|
+
# Class name for the User model
|
|
59
|
+
# @return [String, nil]
|
|
60
|
+
attr_accessor :user_class
|
|
61
|
+
|
|
62
|
+
# Method to call on controller to get current account (multi-tenant mode)
|
|
63
|
+
# @return [Symbol, nil]
|
|
64
|
+
attr_accessor :current_account_method
|
|
65
|
+
|
|
66
|
+
# Method to call on controller to get current user
|
|
67
|
+
# @return [Symbol, nil]
|
|
68
|
+
attr_accessor :current_user_method
|
|
69
|
+
|
|
70
|
+
# Custom trace model class (for host app overrides)
|
|
71
|
+
# @return [String, nil]
|
|
72
|
+
attr_accessor :trace_model_class
|
|
73
|
+
|
|
74
|
+
# Enable React/Inertia frontend instead of ERB
|
|
75
|
+
# @return [Boolean]
|
|
76
|
+
attr_accessor :use_inertia
|
|
77
|
+
|
|
78
|
+
# Custom layout for the dashboard
|
|
79
|
+
# @return [String, nil]
|
|
80
|
+
attr_accessor :layout
|
|
81
|
+
|
|
82
|
+
# Sandbox service type (:local, :cloud_run, :kubernetes)
|
|
83
|
+
# @return [Symbol]
|
|
84
|
+
attr_accessor :sandbox_service
|
|
85
|
+
|
|
86
|
+
# Custom sandbox limits (overrides defaults)
|
|
87
|
+
# @return [Hash, nil]
|
|
88
|
+
attr_accessor :sandbox_limits
|
|
89
|
+
|
|
90
|
+
# Storage service for screenshots/snapshots
|
|
91
|
+
# @return [Object, nil] Object responding to #signed_url_for and #fetch_snapshot
|
|
92
|
+
attr_accessor :storage_service
|
|
93
|
+
|
|
94
|
+
# Base controller class for dashboard controllers
|
|
95
|
+
# @return [String]
|
|
96
|
+
attr_accessor :base_controller_class
|
|
97
|
+
|
|
98
|
+
# Returns whether multi-tenant mode is enabled.
|
|
99
|
+
#
|
|
100
|
+
# @return [Boolean]
|
|
101
|
+
def multi_tenant?
|
|
102
|
+
@multi_tenant == true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Returns the trace model class to use.
|
|
106
|
+
#
|
|
107
|
+
# @return [Class] The trace model class
|
|
108
|
+
def trace_model
|
|
109
|
+
if trace_model_class
|
|
110
|
+
trace_model_class.constantize
|
|
111
|
+
else
|
|
112
|
+
ActiveAgent::TelemetryTrace
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Returns the agent model class to use.
|
|
117
|
+
#
|
|
118
|
+
# @return [Class] The agent model class
|
|
119
|
+
def agent_model
|
|
120
|
+
ActiveAgent::Dashboard::Agent
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Configures the dashboard.
|
|
124
|
+
#
|
|
125
|
+
# @yield [config] Configuration block
|
|
126
|
+
def configure
|
|
127
|
+
yield self
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Reset configuration to defaults
|
|
131
|
+
def reset!
|
|
132
|
+
@authentication_method = nil
|
|
133
|
+
@multi_tenant = false
|
|
134
|
+
@account_class = nil
|
|
135
|
+
@user_class = nil
|
|
136
|
+
@current_account_method = nil
|
|
137
|
+
@current_user_method = nil
|
|
138
|
+
@trace_model_class = nil
|
|
139
|
+
@use_inertia = false
|
|
140
|
+
@layout = nil
|
|
141
|
+
@sandbox_service = :local
|
|
142
|
+
@sandbox_limits = nil
|
|
143
|
+
@storage_service = nil
|
|
144
|
+
@base_controller_class = "ActionController::Base"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Set defaults
|
|
149
|
+
reset!
|
|
150
|
+
end
|
|
151
|
+
end
|