ruby_llm-agents 0.3.3 → 0.3.5
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 +132 -1263
- data/app/controllers/concerns/ruby_llm/agents/filterable.rb +5 -1
- data/app/controllers/concerns/ruby_llm/agents/paginatable.rb +2 -1
- data/app/controllers/ruby_llm/agents/agents_controller.rb +21 -2
- data/app/controllers/ruby_llm/agents/dashboard_controller.rb +137 -9
- data/app/controllers/ruby_llm/agents/executions_controller.rb +83 -5
- data/app/models/ruby_llm/agents/execution/analytics.rb +103 -12
- data/app/models/ruby_llm/agents/execution/scopes.rb +25 -0
- data/app/models/ruby_llm/agents/execution/workflow.rb +299 -0
- data/app/models/ruby_llm/agents/execution.rb +28 -59
- data/app/models/ruby_llm/agents/tenant_budget.rb +165 -0
- data/app/services/ruby_llm/agents/agent_registry.rb +118 -7
- data/app/views/layouts/ruby_llm/agents/application.html.erb +430 -0
- data/app/views/ruby_llm/agents/agents/_empty_state.html.erb +23 -0
- data/app/views/ruby_llm/agents/agents/_workflow.html.erb +125 -0
- data/app/views/ruby_llm/agents/agents/index.html.erb +93 -0
- data/app/views/ruby_llm/agents/agents/show.html.erb +775 -0
- data/app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb +112 -0
- data/app/views/ruby_llm/agents/dashboard/_budgets_bar.html.erb +75 -0
- data/app/views/{rubyllm → ruby_llm}/agents/dashboard/_execution_item.html.erb +7 -4
- data/app/views/ruby_llm/agents/dashboard/_now_strip.html.erb +84 -0
- data/app/views/ruby_llm/agents/dashboard/_tenant_budget.html.erb +115 -0
- data/app/views/ruby_llm/agents/dashboard/_top_errors.html.erb +49 -0
- data/app/views/ruby_llm/agents/dashboard/index.html.erb +155 -0
- data/app/views/{rubyllm → ruby_llm}/agents/executions/_execution.html.erb +1 -1
- data/app/views/{rubyllm → ruby_llm}/agents/executions/_filters.html.erb +39 -11
- data/app/views/{rubyllm → ruby_llm}/agents/executions/_list.html.erb +19 -9
- data/app/views/ruby_llm/agents/executions/_workflow_summary.html.erb +101 -0
- data/app/views/ruby_llm/agents/executions/index.html.erb +88 -0
- data/app/views/{rubyllm → ruby_llm}/agents/executions/show.html.erb +260 -200
- data/app/views/{rubyllm → ruby_llm}/agents/settings/show.html.erb +1 -1
- data/app/views/ruby_llm/agents/shared/_breadcrumbs.html.erb +48 -0
- data/app/views/ruby_llm/agents/shared/_executions_table.html.erb +251 -0
- data/app/views/{rubyllm → ruby_llm}/agents/shared/_filter_dropdown.html.erb +1 -1
- data/app/views/ruby_llm/agents/shared/_nav_link.html.erb +27 -0
- data/app/views/{rubyllm → ruby_llm}/agents/shared/_select_dropdown.html.erb +1 -1
- data/app/views/{rubyllm → ruby_llm}/agents/shared/_status_badge.html.erb +1 -1
- data/app/views/{rubyllm → ruby_llm}/agents/shared/_status_dot.html.erb +1 -1
- data/app/views/ruby_llm/agents/shared/_tenant_filter.html.erb +26 -0
- data/app/views/ruby_llm/agents/shared/_workflow_type_badge.html.erb +61 -0
- data/config/routes.rb +2 -0
- data/lib/generators/ruby_llm_agents/multi_tenancy_generator.rb +97 -0
- data/lib/generators/ruby_llm_agents/templates/add_attempts_migration.rb.tt +3 -3
- data/lib/generators/ruby_llm_agents/templates/add_tenant_to_executions_migration.rb.tt +23 -0
- data/lib/generators/ruby_llm_agents/templates/add_tool_calls_migration.rb.tt +2 -2
- data/lib/generators/ruby_llm_agents/templates/add_workflow_migration.rb.tt +38 -0
- data/lib/generators/ruby_llm_agents/templates/create_tenant_budgets_migration.rb.tt +45 -0
- data/lib/generators/ruby_llm_agents/templates/migration.rb.tt +17 -5
- data/lib/generators/ruby_llm_agents/upgrade_generator.rb +13 -0
- data/lib/ruby_llm/agents/alert_manager.rb +20 -16
- data/lib/ruby_llm/agents/base/caching.rb +40 -0
- data/lib/ruby_llm/agents/base/cost_calculation.rb +105 -0
- data/lib/ruby_llm/agents/base/dsl.rb +261 -0
- data/lib/ruby_llm/agents/base/execution.rb +258 -0
- data/lib/ruby_llm/agents/base/reliability_execution.rb +136 -0
- data/lib/ruby_llm/agents/base/response_building.rb +86 -0
- data/lib/ruby_llm/agents/base/tool_tracking.rb +57 -0
- data/lib/ruby_llm/agents/base.rb +37 -801
- data/lib/ruby_llm/agents/budget_tracker.rb +250 -139
- data/lib/ruby_llm/agents/cache_helper.rb +98 -0
- data/lib/ruby_llm/agents/circuit_breaker.rb +48 -30
- data/lib/ruby_llm/agents/configuration.rb +40 -1
- data/lib/ruby_llm/agents/engine.rb +65 -1
- data/lib/ruby_llm/agents/inflections.rb +14 -0
- data/lib/ruby_llm/agents/instrumentation.rb +66 -0
- data/lib/ruby_llm/agents/reliability.rb +8 -2
- data/lib/ruby_llm/agents/version.rb +1 -1
- data/lib/ruby_llm/agents/workflow/instrumentation.rb +254 -0
- data/lib/ruby_llm/agents/workflow/parallel.rb +282 -0
- data/lib/ruby_llm/agents/workflow/pipeline.rb +306 -0
- data/lib/ruby_llm/agents/workflow/result.rb +390 -0
- data/lib/ruby_llm/agents/workflow/router.rb +429 -0
- data/lib/ruby_llm/agents/workflow.rb +232 -0
- data/lib/ruby_llm/agents.rb +1 -0
- metadata +57 -75
- data/app/channels/ruby_llm/agents/executions_channel.rb +0 -46
- data/app/javascript/ruby_llm/agents/controllers/filter_controller.js +0 -56
- data/app/javascript/ruby_llm/agents/controllers/index.js +0 -12
- data/app/javascript/ruby_llm/agents/controllers/refresh_controller.js +0 -83
- data/app/views/layouts/rubyllm/agents/application.html.erb +0 -626
- data/app/views/rubyllm/agents/agents/index.html.erb +0 -20
- data/app/views/rubyllm/agents/agents/show.html.erb +0 -772
- data/app/views/rubyllm/agents/dashboard/_budgets_bar.html.erb +0 -165
- data/app/views/rubyllm/agents/dashboard/_now_strip.html.erb +0 -10
- data/app/views/rubyllm/agents/dashboard/_now_strip_values.html.erb +0 -71
- data/app/views/rubyllm/agents/dashboard/index.html.erb +0 -197
- data/app/views/rubyllm/agents/executions/index.html.erb +0 -28
- data/app/views/rubyllm/agents/executions/index.turbo_stream.erb +0 -18
- data/app/views/rubyllm/agents/shared/_executions_table.html.erb +0 -193
- /data/app/views/{rubyllm → ruby_llm}/agents/agents/_agent.html.erb +0 -0
- /data/app/views/{rubyllm → ruby_llm}/agents/agents/_version_comparison.html.erb +0 -0
- /data/app/views/{rubyllm → ruby_llm}/agents/dashboard/_action_center.html.erb +0 -0
- /data/app/views/{rubyllm → ruby_llm}/agents/dashboard/_alerts_feed.html.erb +0 -0
- /data/app/views/{rubyllm → ruby_llm}/agents/dashboard/_breaker_strip.html.erb +0 -0
- /data/app/views/{rubyllm → ruby_llm}/agents/executions/dry_run.html.erb +0 -0
- /data/app/views/{rubyllm → ruby_llm}/agents/shared/_stat_card.html.erb +0 -0
|
@@ -1,626 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
|
|
3
|
-
<html lang="en">
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="utf-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
-
|
|
8
|
-
<title>RubyLLM Agents Dashboard</title>
|
|
9
|
-
|
|
10
|
-
<!-- Prevent flash of wrong theme - must run before any rendering -->
|
|
11
|
-
<script>
|
|
12
|
-
(function() {
|
|
13
|
-
const preference = localStorage.getItem('ruby_llm_agents_theme') || 'auto';
|
|
14
|
-
const isDark = preference === 'dark' ||
|
|
15
|
-
(preference === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
16
|
-
if (isDark) {
|
|
17
|
-
document.documentElement.classList.add('dark');
|
|
18
|
-
}
|
|
19
|
-
})();
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<!-- Tailwind CSS via CDN -->
|
|
23
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
24
|
-
|
|
25
|
-
<script>
|
|
26
|
-
tailwind.config = {
|
|
27
|
-
darkMode: 'class'
|
|
28
|
-
}
|
|
29
|
-
</script>
|
|
30
|
-
|
|
31
|
-
<!-- Highcharts for charts -->
|
|
32
|
-
<script src="https://code.highcharts.com/highcharts.js"></script>
|
|
33
|
-
<script src="https://cdn.jsdelivr.net/npm/chartkick@5.0.1"></script>
|
|
34
|
-
|
|
35
|
-
<!-- Configure Highcharts defaults -->
|
|
36
|
-
<script>
|
|
37
|
-
Highcharts.setOptions({
|
|
38
|
-
credits: { enabled: false },
|
|
39
|
-
chart: {
|
|
40
|
-
backgroundColor: 'transparent',
|
|
41
|
-
style: { fontFamily: 'inherit' }
|
|
42
|
-
},
|
|
43
|
-
title: { text: null },
|
|
44
|
-
xAxis: {
|
|
45
|
-
labels: { style: { color: '#9CA3AF' } },
|
|
46
|
-
lineColor: 'rgba(156, 163, 175, 0.2)',
|
|
47
|
-
tickColor: 'rgba(156, 163, 175, 0.2)'
|
|
48
|
-
},
|
|
49
|
-
yAxis: {
|
|
50
|
-
labels: { style: { color: '#9CA3AF' } },
|
|
51
|
-
gridLineColor: 'rgba(156, 163, 175, 0.2)'
|
|
52
|
-
},
|
|
53
|
-
legend: {
|
|
54
|
-
itemStyle: { color: '#9CA3AF' },
|
|
55
|
-
itemHoverStyle: { color: '#D1D5DB' }
|
|
56
|
-
},
|
|
57
|
-
tooltip: {
|
|
58
|
-
backgroundColor: 'rgba(17, 24, 39, 0.9)',
|
|
59
|
-
borderColor: 'rgba(75, 85, 99, 0.5)',
|
|
60
|
-
style: { color: '#F3F4F6' }
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
</script>
|
|
64
|
-
|
|
65
|
-
<!-- Stimulus -->
|
|
66
|
-
<script
|
|
67
|
-
src="https://unpkg.com/@hotwired/stimulus@3.2.2/dist/stimulus.umd.js"
|
|
68
|
-
></script>
|
|
69
|
-
|
|
70
|
-
<!-- Alpine.js -->
|
|
71
|
-
<script
|
|
72
|
-
defer
|
|
73
|
-
src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"
|
|
74
|
-
></script>
|
|
75
|
-
|
|
76
|
-
<style>[x-cloak] { display: none !important; }</style>
|
|
77
|
-
|
|
78
|
-
<!-- Auto-refresh for dashboard updates -->
|
|
79
|
-
<script>
|
|
80
|
-
(function() {
|
|
81
|
-
// Simple polling for real-time updates (5 second interval)
|
|
82
|
-
const POLL_INTERVAL = 5000
|
|
83
|
-
let pollTimer = null
|
|
84
|
-
|
|
85
|
-
function startPolling() {
|
|
86
|
-
if (pollTimer) return
|
|
87
|
-
|
|
88
|
-
// Update indicator to show polling is active
|
|
89
|
-
const indicator = document.getElementById("live-indicator")
|
|
90
|
-
if (indicator) {
|
|
91
|
-
indicator.className = "hidden sm:flex items-center text-blue-600 dark:text-blue-400"
|
|
92
|
-
indicator.innerHTML = '<span class="w-1.5 h-1.5 bg-blue-500 rounded-full mr-1 animate-pulse"></span><span class="hidden sm:inline">Auto</span>'
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
pollTimer = setInterval(() => {
|
|
96
|
-
// Dashboard page - detected by presence of activity feed
|
|
97
|
-
if (document.getElementById("activity-feed")) {
|
|
98
|
-
fetch(window.location.href, {
|
|
99
|
-
headers: { "Accept": "text/html" }
|
|
100
|
-
})
|
|
101
|
-
.then(response => response.text())
|
|
102
|
-
.then(html => {
|
|
103
|
-
const parser = new DOMParser()
|
|
104
|
-
const doc = parser.parseFromString(html, "text/html")
|
|
105
|
-
|
|
106
|
-
// Update activity feed
|
|
107
|
-
const newFeed = doc.getElementById("activity-feed")
|
|
108
|
-
const currentFeed = document.getElementById("activity-feed")
|
|
109
|
-
if (newFeed && currentFeed) {
|
|
110
|
-
currentFeed.innerHTML = newFeed.innerHTML
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Update now strip
|
|
114
|
-
const newStrip = doc.getElementById("now-strip-values")
|
|
115
|
-
const currentStrip = document.getElementById("now-strip-values")
|
|
116
|
-
if (newStrip && currentStrip) {
|
|
117
|
-
currentStrip.innerHTML = newStrip.innerHTML
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Note: Chart has its own 1-second live update built-in
|
|
121
|
-
|
|
122
|
-
// Update action center
|
|
123
|
-
const newActionCenter = doc.getElementById("action-center")
|
|
124
|
-
const currentActionCenter = document.getElementById("action-center")
|
|
125
|
-
if (newActionCenter && currentActionCenter) {
|
|
126
|
-
currentActionCenter.outerHTML = newActionCenter.outerHTML
|
|
127
|
-
} else if (newActionCenter && !currentActionCenter) {
|
|
128
|
-
// Insert action center if it appeared
|
|
129
|
-
const main = document.querySelector("main")
|
|
130
|
-
if (main) main.insertAdjacentHTML("afterbegin", newActionCenter.outerHTML)
|
|
131
|
-
} else if (!newActionCenter && currentActionCenter) {
|
|
132
|
-
// Remove action center if it disappeared
|
|
133
|
-
currentActionCenter.remove()
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
.catch(err => console.log("[RubyLLM::Agents] Poll error:", err))
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Execution show page - detected by presence of execution-detail element
|
|
140
|
-
const executionDetail = document.getElementById("execution-detail")
|
|
141
|
-
if (executionDetail) {
|
|
142
|
-
const currentStatus = executionDetail.dataset.status
|
|
143
|
-
|
|
144
|
-
// Only poll if execution is still running
|
|
145
|
-
if (currentStatus === "running") {
|
|
146
|
-
fetch(window.location.href, {
|
|
147
|
-
headers: { "Accept": "text/html" }
|
|
148
|
-
})
|
|
149
|
-
.then(response => response.text())
|
|
150
|
-
.then(html => {
|
|
151
|
-
const parser = new DOMParser()
|
|
152
|
-
const doc = parser.parseFromString(html, "text/html")
|
|
153
|
-
|
|
154
|
-
// Update the main content area when status changes
|
|
155
|
-
const newContent = doc.getElementById("execution-detail")
|
|
156
|
-
if (newContent && newContent.dataset.status !== "running") {
|
|
157
|
-
// Execution completed - do a full content update
|
|
158
|
-
executionDetail.outerHTML = newContent.outerHTML
|
|
159
|
-
}
|
|
160
|
-
})
|
|
161
|
-
.catch(err => console.log("[RubyLLM::Agents] Poll error:", err))
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}, POLL_INTERVAL)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function stopPolling() {
|
|
168
|
-
if (pollTimer) {
|
|
169
|
-
clearInterval(pollTimer)
|
|
170
|
-
pollTimer = null
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Start polling on page load
|
|
175
|
-
document.addEventListener("DOMContentLoaded", startPolling)
|
|
176
|
-
|
|
177
|
-
// Handle visibility changes - pause when tab is hidden
|
|
178
|
-
document.addEventListener("visibilitychange", () => {
|
|
179
|
-
if (document.hidden) {
|
|
180
|
-
stopPolling()
|
|
181
|
-
} else {
|
|
182
|
-
startPolling()
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
|
-
})()
|
|
186
|
-
</script>
|
|
187
|
-
|
|
188
|
-
<!-- Live Clock Script -->
|
|
189
|
-
<script type="module">
|
|
190
|
-
function updateClock() {
|
|
191
|
-
const clock = document.getElementById('live-clock');
|
|
192
|
-
if (clock) {
|
|
193
|
-
const now = new Date();
|
|
194
|
-
clock.textContent = now.toLocaleTimeString('en-US', {
|
|
195
|
-
hour: '2-digit',
|
|
196
|
-
minute: '2-digit',
|
|
197
|
-
second: '2-digit',
|
|
198
|
-
hour12: false
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Start clock on page load
|
|
204
|
-
document.addEventListener('turbo:load', function() {
|
|
205
|
-
if (window.rubyLLMAgentsClock) clearInterval(window.rubyLLMAgentsClock);
|
|
206
|
-
updateClock();
|
|
207
|
-
window.rubyLLMAgentsClock = setInterval(updateClock, 1000);
|
|
208
|
-
|
|
209
|
-
// Handle data-href clickable rows (semantic alternative to onclick)
|
|
210
|
-
document.querySelectorAll('[data-href]').forEach(function(element) {
|
|
211
|
-
element.addEventListener('click', function(e) {
|
|
212
|
-
// Don't navigate if clicking on a link or button inside the row
|
|
213
|
-
if (e.target.closest('a, button')) return;
|
|
214
|
-
window.location = element.dataset.href;
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
</script>
|
|
219
|
-
|
|
220
|
-
<!-- Stimulus Controllers -->
|
|
221
|
-
<script>
|
|
222
|
-
(function() {
|
|
223
|
-
// Initialize Stimulus immediately (works with Turbo)
|
|
224
|
-
if (!window.Stimulus) {
|
|
225
|
-
window.Stimulus = {};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const Stimulus = window.Stimulus;
|
|
229
|
-
|
|
230
|
-
// Only initialize once
|
|
231
|
-
if (!Stimulus.application) {
|
|
232
|
-
Stimulus.application = Stimulus.Application.start();
|
|
233
|
-
|
|
234
|
-
// Theme Controller - handles dark mode switching
|
|
235
|
-
Stimulus.application.register("theme", class extends Stimulus.Controller {
|
|
236
|
-
static targets = ["select"]
|
|
237
|
-
|
|
238
|
-
connect() {
|
|
239
|
-
this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
|
240
|
-
this.applyTheme(this.getPreference())
|
|
241
|
-
this.boundHandleSystemChange = this.handleSystemChange.bind(this)
|
|
242
|
-
this.mediaQuery.addEventListener('change', this.boundHandleSystemChange)
|
|
243
|
-
|
|
244
|
-
// Set the select value to match stored preference
|
|
245
|
-
if (this.hasSelectTarget) {
|
|
246
|
-
this.selectTarget.value = this.getPreference()
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
disconnect() {
|
|
251
|
-
this.mediaQuery.removeEventListener('change', this.boundHandleSystemChange)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
change(event) {
|
|
255
|
-
const preference = event.target.value
|
|
256
|
-
localStorage.setItem('ruby_llm_agents_theme', preference)
|
|
257
|
-
this.applyTheme(preference)
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
getPreference() {
|
|
261
|
-
return localStorage.getItem('ruby_llm_agents_theme') || 'auto'
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
applyTheme(preference) {
|
|
265
|
-
const isDark = preference === 'dark' ||
|
|
266
|
-
(preference === 'auto' && this.mediaQuery.matches)
|
|
267
|
-
document.documentElement.classList.toggle('dark', isDark)
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
handleSystemChange() {
|
|
271
|
-
if (this.getPreference() === 'auto') {
|
|
272
|
-
this.applyTheme('auto')
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
console.log('[RubyLLM::Agents] Stimulus initialized');
|
|
278
|
-
}
|
|
279
|
-
})();
|
|
280
|
-
</script>
|
|
281
|
-
|
|
282
|
-
<style>
|
|
283
|
-
/* Custom styles for the dashboard */
|
|
284
|
-
.stat-card {
|
|
285
|
-
@apply bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 p-4 transition-shadow;
|
|
286
|
-
}
|
|
287
|
-
.stat-card:hover {
|
|
288
|
-
@apply shadow-md;
|
|
289
|
-
}
|
|
290
|
-
.stat-value {
|
|
291
|
-
@apply text-2xl font-bold text-gray-900 dark:text-gray-100 mt-2;
|
|
292
|
-
}
|
|
293
|
-
@media (min-width: 1024px) {
|
|
294
|
-
.stat-value {
|
|
295
|
-
font-size: 1.5rem;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
.stat-label {
|
|
299
|
-
@apply text-xs text-gray-500 dark:text-gray-400 uppercase tracking-wide font-medium;
|
|
300
|
-
}
|
|
301
|
-
.chart-card {
|
|
302
|
-
@apply bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 p-6;
|
|
303
|
-
}
|
|
304
|
-
.nav-link {
|
|
305
|
-
@apply px-4 py-2 text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors;
|
|
306
|
-
}
|
|
307
|
-
.nav-link.active {
|
|
308
|
-
@apply bg-blue-50 dark:bg-blue-900 text-blue-700 dark:text-blue-300;
|
|
309
|
-
}
|
|
310
|
-
.badge {
|
|
311
|
-
@apply inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium;
|
|
312
|
-
}
|
|
313
|
-
.badge-running {
|
|
314
|
-
@apply bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200;
|
|
315
|
-
}
|
|
316
|
-
.badge-success {
|
|
317
|
-
@apply bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200;
|
|
318
|
-
}
|
|
319
|
-
.badge-error {
|
|
320
|
-
@apply bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200;
|
|
321
|
-
}
|
|
322
|
-
.badge-timeout {
|
|
323
|
-
@apply bg-yellow-100 dark:bg-yellow-900 text-yellow-800 dark:text-yellow-200;
|
|
324
|
-
}
|
|
325
|
-
.badge-cyan {
|
|
326
|
-
@apply bg-cyan-100 dark:bg-cyan-900/50 text-cyan-700 dark:text-cyan-300;
|
|
327
|
-
}
|
|
328
|
-
.badge-purple {
|
|
329
|
-
@apply bg-purple-100 dark:bg-purple-900/50 text-purple-700 dark:text-purple-300;
|
|
330
|
-
}
|
|
331
|
-
.badge-orange {
|
|
332
|
-
@apply bg-orange-100 dark:bg-orange-900/50 text-orange-700 dark:text-orange-300;
|
|
333
|
-
}
|
|
334
|
-
</style>
|
|
335
|
-
</head>
|
|
336
|
-
|
|
337
|
-
<body class="bg-gray-50 dark:bg-gray-900 min-h-screen flex flex-col">
|
|
338
|
-
<!-- Header -->
|
|
339
|
-
<header
|
|
340
|
-
class="
|
|
341
|
-
bg-white dark:bg-gray-800 border-b border-gray-200
|
|
342
|
-
dark:border-gray-700
|
|
343
|
-
"
|
|
344
|
-
x-data="{ mobileMenuOpen: false }"
|
|
345
|
-
>
|
|
346
|
-
<div class="max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center">
|
|
347
|
-
<div class="flex justify-between items-center w-full">
|
|
348
|
-
<div class="flex items-center space-x-8">
|
|
349
|
-
<%= link_to ruby_llm_agents.root_path, class: "flex items-center space-x-2" do %>
|
|
350
|
-
<span class="text-lg">🤖</span>
|
|
351
|
-
|
|
352
|
-
<span class="font-semibold text-gray-900 dark:text-gray-100">
|
|
353
|
-
RubyLLM Agents
|
|
354
|
-
</span>
|
|
355
|
-
<% end %>
|
|
356
|
-
|
|
357
|
-
<!-- Desktop Navigation -->
|
|
358
|
-
<nav class="hidden md:flex items-center space-x-1">
|
|
359
|
-
<%= link_to ruby_llm_agents.root_path, class: "inline-flex items-center px-3 py-1.5 text-sm font-medium rounded-md #{current_page?(ruby_llm_agents.root_path) ? 'bg-gray-200 dark:bg-gray-700 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700'}" do %>
|
|
360
|
-
<svg
|
|
361
|
-
class="w-4 h-4 mr-1.5"
|
|
362
|
-
fill="none"
|
|
363
|
-
stroke="currentColor"
|
|
364
|
-
viewBox="0 0 24 24"
|
|
365
|
-
>
|
|
366
|
-
<path
|
|
367
|
-
stroke-linecap="round"
|
|
368
|
-
stroke-linejoin="round"
|
|
369
|
-
stroke-width="2"
|
|
370
|
-
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
|
|
371
|
-
/>
|
|
372
|
-
</svg>
|
|
373
|
-
Dashboard
|
|
374
|
-
<% end %>
|
|
375
|
-
|
|
376
|
-
<%= link_to ruby_llm_agents.agents_path, class: "inline-flex items-center px-3 py-1.5 text-sm font-medium rounded-md #{request.path.start_with?(ruby_llm_agents.agents_path) ? 'bg-gray-200 dark:bg-gray-700 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700'}" do %>
|
|
377
|
-
<svg
|
|
378
|
-
class="w-4 h-4 mr-1.5"
|
|
379
|
-
fill="none"
|
|
380
|
-
stroke="currentColor"
|
|
381
|
-
viewBox="0 0 24 24"
|
|
382
|
-
>
|
|
383
|
-
<path
|
|
384
|
-
stroke-linecap="round"
|
|
385
|
-
stroke-linejoin="round"
|
|
386
|
-
stroke-width="2"
|
|
387
|
-
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
|
|
388
|
-
/>
|
|
389
|
-
</svg>
|
|
390
|
-
Agents
|
|
391
|
-
<% end %>
|
|
392
|
-
|
|
393
|
-
<%= link_to ruby_llm_agents.executions_path, class: "inline-flex items-center px-3 py-1.5 text-sm font-medium rounded-md #{current_page?(ruby_llm_agents.executions_path) ? 'bg-gray-200 dark:bg-gray-700 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700'}" do %>
|
|
394
|
-
<svg
|
|
395
|
-
class="w-4 h-4 mr-1.5"
|
|
396
|
-
fill="none"
|
|
397
|
-
stroke="currentColor"
|
|
398
|
-
viewBox="0 0 24 24"
|
|
399
|
-
>
|
|
400
|
-
<path
|
|
401
|
-
stroke-linecap="round"
|
|
402
|
-
stroke-linejoin="round"
|
|
403
|
-
stroke-width="2"
|
|
404
|
-
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"
|
|
405
|
-
/>
|
|
406
|
-
</svg>
|
|
407
|
-
Executions
|
|
408
|
-
<% end %>
|
|
409
|
-
|
|
410
|
-
<%= link_to ruby_llm_agents.settings_path, class: "inline-flex items-center px-3 py-1.5 text-sm font-medium rounded-md #{current_page?(ruby_llm_agents.settings_path) ? 'bg-gray-200 dark:bg-gray-700 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700'}" do %>
|
|
411
|
-
<svg
|
|
412
|
-
class="w-4 h-4 mr-1.5"
|
|
413
|
-
fill="none"
|
|
414
|
-
stroke="currentColor"
|
|
415
|
-
viewBox="0 0 24 24"
|
|
416
|
-
>
|
|
417
|
-
<path
|
|
418
|
-
stroke-linecap="round"
|
|
419
|
-
stroke-linejoin="round"
|
|
420
|
-
stroke-width="2"
|
|
421
|
-
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
|
422
|
-
/>
|
|
423
|
-
|
|
424
|
-
<path
|
|
425
|
-
stroke-linecap="round"
|
|
426
|
-
stroke-linejoin="round"
|
|
427
|
-
stroke-width="2"
|
|
428
|
-
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
429
|
-
/>
|
|
430
|
-
</svg>
|
|
431
|
-
Settings
|
|
432
|
-
<% end %>
|
|
433
|
-
</nav>
|
|
434
|
-
</div>
|
|
435
|
-
|
|
436
|
-
<div
|
|
437
|
-
class="
|
|
438
|
-
flex items-center space-x-2 text-xs text-gray-500
|
|
439
|
-
dark:text-gray-400
|
|
440
|
-
"
|
|
441
|
-
>
|
|
442
|
-
<span id="live-clock" class="tabular-nums"></span>
|
|
443
|
-
|
|
444
|
-
<span
|
|
445
|
-
id="live-indicator"
|
|
446
|
-
class="hidden sm:flex items-center text-blue-600 dark:text-blue-400"
|
|
447
|
-
>
|
|
448
|
-
<span class="w-1.5 h-1.5 bg-blue-500 rounded-full mr-1 animate-pulse"></span>
|
|
449
|
-
<span class="hidden sm:inline">Auto</span>
|
|
450
|
-
</span>
|
|
451
|
-
|
|
452
|
-
<!-- Mobile menu button -->
|
|
453
|
-
<button
|
|
454
|
-
type="button"
|
|
455
|
-
@click="mobileMenuOpen = !mobileMenuOpen"
|
|
456
|
-
:aria-expanded="mobileMenuOpen"
|
|
457
|
-
aria-controls="mobile-menu"
|
|
458
|
-
class="
|
|
459
|
-
md:hidden inline-flex items-center justify-center p-2
|
|
460
|
-
rounded-md text-gray-500 dark:text-gray-400
|
|
461
|
-
hover:text-gray-900 dark:hover:text-gray-100
|
|
462
|
-
hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none
|
|
463
|
-
focus:ring-2 focus:ring-inset focus:ring-blue-500
|
|
464
|
-
"
|
|
465
|
-
>
|
|
466
|
-
<span class="sr-only">Open main menu</span>
|
|
467
|
-
|
|
468
|
-
<svg
|
|
469
|
-
class="w-5 h-5"
|
|
470
|
-
fill="none"
|
|
471
|
-
stroke="currentColor"
|
|
472
|
-
viewBox="0 0 24 24"
|
|
473
|
-
>
|
|
474
|
-
<path
|
|
475
|
-
stroke-linecap="round"
|
|
476
|
-
stroke-linejoin="round"
|
|
477
|
-
stroke-width="2"
|
|
478
|
-
d="M4 6h16M4 12h16M4 18h16"
|
|
479
|
-
/>
|
|
480
|
-
</svg>
|
|
481
|
-
</button>
|
|
482
|
-
</div>
|
|
483
|
-
</div>
|
|
484
|
-
</div>
|
|
485
|
-
|
|
486
|
-
<!-- Mobile Navigation Menu -->
|
|
487
|
-
<div
|
|
488
|
-
id="mobile-menu"
|
|
489
|
-
x-show="mobileMenuOpen"
|
|
490
|
-
x-cloak
|
|
491
|
-
x-transition:enter="transition ease-out duration-200"
|
|
492
|
-
x-transition:enter-start="opacity-0 -translate-y-1"
|
|
493
|
-
x-transition:enter-end="opacity-100 translate-y-0"
|
|
494
|
-
x-transition:leave="transition ease-in duration-150"
|
|
495
|
-
x-transition:leave-start="opacity-100 translate-y-0"
|
|
496
|
-
x-transition:leave-end="opacity-0 -translate-y-1"
|
|
497
|
-
@click.outside="mobileMenuOpen = false"
|
|
498
|
-
class="
|
|
499
|
-
md:hidden border-t border-gray-200 dark:border-gray-700 bg-white
|
|
500
|
-
dark:bg-gray-800
|
|
501
|
-
"
|
|
502
|
-
>
|
|
503
|
-
<nav class="max-w-7xl mx-auto px-4 py-3 space-y-1">
|
|
504
|
-
<%= link_to ruby_llm_agents.root_path, "x-on:click": "mobileMenuOpen = false", class: "flex items-center px-3 py-2 text-base font-medium rounded-md #{current_page?(ruby_llm_agents.root_path) ? 'bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700'}" do %>
|
|
505
|
-
<svg
|
|
506
|
-
class="w-5 h-5 mr-3"
|
|
507
|
-
fill="none"
|
|
508
|
-
stroke="currentColor"
|
|
509
|
-
viewBox="0 0 24 24"
|
|
510
|
-
>
|
|
511
|
-
<path
|
|
512
|
-
stroke-linecap="round"
|
|
513
|
-
stroke-linejoin="round"
|
|
514
|
-
stroke-width="2"
|
|
515
|
-
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"
|
|
516
|
-
/>
|
|
517
|
-
</svg>
|
|
518
|
-
Dashboard
|
|
519
|
-
<% end %>
|
|
520
|
-
|
|
521
|
-
<%= link_to ruby_llm_agents.agents_path, "x-on:click": "mobileMenuOpen = false", class: "flex items-center px-3 py-2 text-base font-medium rounded-md #{request.path.start_with?(ruby_llm_agents.agents_path) ? 'bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700'}" do %>
|
|
522
|
-
<svg
|
|
523
|
-
class="w-5 h-5 mr-3"
|
|
524
|
-
fill="none"
|
|
525
|
-
stroke="currentColor"
|
|
526
|
-
viewBox="0 0 24 24"
|
|
527
|
-
>
|
|
528
|
-
<path
|
|
529
|
-
stroke-linecap="round"
|
|
530
|
-
stroke-linejoin="round"
|
|
531
|
-
stroke-width="2"
|
|
532
|
-
d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"
|
|
533
|
-
/>
|
|
534
|
-
</svg>
|
|
535
|
-
Agents
|
|
536
|
-
<% end %>
|
|
537
|
-
|
|
538
|
-
<%= link_to ruby_llm_agents.executions_path, "x-on:click": "mobileMenuOpen = false", class: "flex items-center px-3 py-2 text-base font-medium rounded-md #{current_page?(ruby_llm_agents.executions_path) ? 'bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700'}" do %>
|
|
539
|
-
<svg
|
|
540
|
-
class="w-5 h-5 mr-3"
|
|
541
|
-
fill="none"
|
|
542
|
-
stroke="currentColor"
|
|
543
|
-
viewBox="0 0 24 24"
|
|
544
|
-
>
|
|
545
|
-
<path
|
|
546
|
-
stroke-linecap="round"
|
|
547
|
-
stroke-linejoin="round"
|
|
548
|
-
stroke-width="2"
|
|
549
|
-
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"
|
|
550
|
-
/>
|
|
551
|
-
</svg>
|
|
552
|
-
Executions
|
|
553
|
-
<% end %>
|
|
554
|
-
|
|
555
|
-
<%= link_to ruby_llm_agents.settings_path, "x-on:click": "mobileMenuOpen = false", class: "flex items-center px-3 py-2 text-base font-medium rounded-md #{current_page?(ruby_llm_agents.settings_path) ? 'bg-gray-200 dark:bg-gray-700 text-gray-900 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700'}" do %>
|
|
556
|
-
<svg
|
|
557
|
-
class="w-5 h-5 mr-3"
|
|
558
|
-
fill="none"
|
|
559
|
-
stroke="currentColor"
|
|
560
|
-
viewBox="0 0 24 24"
|
|
561
|
-
>
|
|
562
|
-
<path
|
|
563
|
-
stroke-linecap="round"
|
|
564
|
-
stroke-linejoin="round"
|
|
565
|
-
stroke-width="2"
|
|
566
|
-
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
|
567
|
-
/>
|
|
568
|
-
|
|
569
|
-
<path
|
|
570
|
-
stroke-linecap="round"
|
|
571
|
-
stroke-linejoin="round"
|
|
572
|
-
stroke-width="2"
|
|
573
|
-
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
|
574
|
-
/>
|
|
575
|
-
</svg>
|
|
576
|
-
Settings
|
|
577
|
-
<% end %>
|
|
578
|
-
</nav>
|
|
579
|
-
</div>
|
|
580
|
-
</header>
|
|
581
|
-
|
|
582
|
-
<!-- Main content -->
|
|
583
|
-
<main class="max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-8 h-full">
|
|
584
|
-
<%= yield %>
|
|
585
|
-
</main>
|
|
586
|
-
|
|
587
|
-
<!-- Footer -->
|
|
588
|
-
<footer
|
|
589
|
-
class="border-t bg-white dark:bg-gray-800 dark:border-gray-700 mt-auto"
|
|
590
|
-
data-controller="theme"
|
|
591
|
-
>
|
|
592
|
-
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
|
593
|
-
<div class="flex flex-col sm:flex-row items-center sm:justify-between gap-3 sm:gap-0">
|
|
594
|
-
<div class="flex items-center space-x-2">
|
|
595
|
-
<label
|
|
596
|
-
for="theme-select"
|
|
597
|
-
class="text-sm text-gray-500 dark:text-gray-400"
|
|
598
|
-
>
|
|
599
|
-
Theme:
|
|
600
|
-
</label>
|
|
601
|
-
|
|
602
|
-
<select
|
|
603
|
-
id="theme-select"
|
|
604
|
-
data-theme-target="select"
|
|
605
|
-
data-action="change->theme#change"
|
|
606
|
-
class="
|
|
607
|
-
text-sm border border-gray-300 dark:border-gray-600
|
|
608
|
-
dark:bg-gray-700 dark:text-gray-200 rounded-md shadow-sm
|
|
609
|
-
focus:ring-blue-500 focus:border-blue-500 py-1 px-2
|
|
610
|
-
"
|
|
611
|
-
>
|
|
612
|
-
<option value="light">Light</option>
|
|
613
|
-
<option value="dark">Dark</option>
|
|
614
|
-
<option value="auto">Auto</option>
|
|
615
|
-
</select>
|
|
616
|
-
</div>
|
|
617
|
-
|
|
618
|
-
<p class="text-sm text-gray-500 dark:text-gray-400 text-center">
|
|
619
|
-
Powered by
|
|
620
|
-
<a href="https://github.com/adham90/ruby_llm-agents" class="text-blue-600 dark:text-blue-400 hover:underline">ruby_llm-agents</a>
|
|
621
|
-
</p>
|
|
622
|
-
</div>
|
|
623
|
-
</div>
|
|
624
|
-
</footer>
|
|
625
|
-
</body>
|
|
626
|
-
</html>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<div class="mb-6">
|
|
2
|
-
<h1 class="text-2xl font-bold text-gray-900 dark:text-gray-100">Agents</h1>
|
|
3
|
-
<p class="text-gray-500 dark:text-gray-400 mt-1">All available agents and their execution statistics</p>
|
|
4
|
-
</div>
|
|
5
|
-
|
|
6
|
-
<% if @agents.empty? %>
|
|
7
|
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow p-8 text-center">
|
|
8
|
-
<svg class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
9
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
|
10
|
-
</svg>
|
|
11
|
-
<h3 class="mt-2 text-sm font-medium text-gray-900 dark:text-gray-100">No agents found</h3>
|
|
12
|
-
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Create an agent by running <code class="bg-gray-100 dark:bg-gray-700 dark:text-gray-200 px-1 rounded">rails g ruby_llm_agents:agent YourAgentName</code></p>
|
|
13
|
-
</div>
|
|
14
|
-
<% else %>
|
|
15
|
-
<div class="space-y-3 sm:space-y-4">
|
|
16
|
-
<% @agents.each do |agent| %>
|
|
17
|
-
<%= render partial: "rubyllm/agents/agents/agent", locals: { agent: agent } %>
|
|
18
|
-
<% end %>
|
|
19
|
-
</div>
|
|
20
|
-
<% end %>
|