ruby_llm-agents 0.3.3 → 0.3.4
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/app/controllers/ruby_llm/agents/dashboard_controller.rb +68 -4
- data/app/models/ruby_llm/agents/execution/analytics.rb +114 -13
- data/app/models/ruby_llm/agents/execution.rb +19 -58
- data/app/views/layouts/rubyllm/agents/application.html.erb +92 -350
- data/app/views/rubyllm/agents/agents/show.html.erb +331 -385
- data/app/views/rubyllm/agents/dashboard/_agent_comparison.html.erb +46 -0
- data/app/views/rubyllm/agents/dashboard/_budgets_bar.html.erb +0 -90
- data/app/views/rubyllm/agents/dashboard/_now_strip.html.erb +79 -5
- data/app/views/rubyllm/agents/dashboard/_top_errors.html.erb +49 -0
- data/app/views/rubyllm/agents/dashboard/index.html.erb +76 -121
- data/app/views/rubyllm/agents/executions/show.html.erb +134 -85
- data/app/views/rubyllm/agents/settings/show.html.erb +1 -1
- data/app/views/rubyllm/agents/shared/_breadcrumbs.html.erb +48 -0
- data/app/views/rubyllm/agents/shared/_nav_link.html.erb +27 -0
- data/config/routes.rb +2 -0
- data/lib/ruby_llm/agents/base/caching.rb +43 -0
- data/lib/ruby_llm/agents/base/cost_calculation.rb +103 -0
- data/lib/ruby_llm/agents/base/dsl.rb +261 -0
- data/lib/ruby_llm/agents/base/execution.rb +206 -0
- data/lib/ruby_llm/agents/base/reliability_execution.rb +131 -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 +15 -805
- data/lib/ruby_llm/agents/version.rb +1 -1
- metadata +12 -20
- 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/rubyllm/agents/dashboard/_now_strip_values.html.erb +0 -71
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
|
|
31
31
|
<!-- Highcharts for charts -->
|
|
32
32
|
<script src="https://code.highcharts.com/highcharts.js"></script>
|
|
33
|
-
<script src="https://cdn.jsdelivr.net/npm/chartkick@5.0.1"></script>
|
|
34
33
|
|
|
35
34
|
<!-- Configure Highcharts defaults -->
|
|
36
35
|
<script>
|
|
@@ -62,11 +61,6 @@
|
|
|
62
61
|
});
|
|
63
62
|
</script>
|
|
64
63
|
|
|
65
|
-
<!-- Stimulus -->
|
|
66
|
-
<script
|
|
67
|
-
src="https://unpkg.com/@hotwired/stimulus@3.2.2/dist/stimulus.umd.js"
|
|
68
|
-
></script>
|
|
69
|
-
|
|
70
64
|
<!-- Alpine.js -->
|
|
71
65
|
<script
|
|
72
66
|
defer
|
|
@@ -75,117 +69,7 @@
|
|
|
75
69
|
|
|
76
70
|
<style>[x-cloak] { display: none !important; }</style>
|
|
77
71
|
|
|
78
|
-
<!--
|
|
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 -->
|
|
72
|
+
<!-- Clock and clickable rows -->
|
|
189
73
|
<script type="module">
|
|
190
74
|
function updateClock() {
|
|
191
75
|
const clock = document.getElementById('live-clock');
|
|
@@ -194,17 +78,14 @@
|
|
|
194
78
|
clock.textContent = now.toLocaleTimeString('en-US', {
|
|
195
79
|
hour: '2-digit',
|
|
196
80
|
minute: '2-digit',
|
|
197
|
-
second: '2-digit',
|
|
198
81
|
hour12: false
|
|
199
82
|
});
|
|
200
83
|
}
|
|
201
84
|
}
|
|
202
85
|
|
|
203
|
-
//
|
|
86
|
+
// Initialize on page load
|
|
204
87
|
document.addEventListener('turbo:load', function() {
|
|
205
|
-
if (window.rubyLLMAgentsClock) clearInterval(window.rubyLLMAgentsClock);
|
|
206
88
|
updateClock();
|
|
207
|
-
window.rubyLLMAgentsClock = setInterval(updateClock, 1000);
|
|
208
89
|
|
|
209
90
|
// Handle data-href clickable rows (semantic alternative to onclick)
|
|
210
91
|
document.querySelectorAll('[data-href]').forEach(function(element) {
|
|
@@ -215,72 +96,47 @@
|
|
|
215
96
|
});
|
|
216
97
|
});
|
|
217
98
|
});
|
|
99
|
+
|
|
100
|
+
// Also run on DOMContentLoaded for non-Turbo loads
|
|
101
|
+
document.addEventListener('DOMContentLoaded', updateClock);
|
|
218
102
|
</script>
|
|
219
103
|
|
|
220
|
-
<!--
|
|
104
|
+
<!-- Theme Switcher (Alpine.js) -->
|
|
221
105
|
<script>
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
})();
|
|
106
|
+
function themeManager() {
|
|
107
|
+
return {
|
|
108
|
+
preference: localStorage.getItem('ruby_llm_agents_theme') || 'auto',
|
|
109
|
+
init() {
|
|
110
|
+
this.applyTheme();
|
|
111
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
|
112
|
+
if (this.preference === 'auto') this.applyTheme();
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
setTheme(value) {
|
|
116
|
+
this.preference = value;
|
|
117
|
+
localStorage.setItem('ruby_llm_agents_theme', value);
|
|
118
|
+
this.applyTheme();
|
|
119
|
+
},
|
|
120
|
+
applyTheme() {
|
|
121
|
+
const isDark = this.preference === 'dark' ||
|
|
122
|
+
(this.preference === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
|
123
|
+
document.documentElement.classList.toggle('dark', isDark);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
280
127
|
</script>
|
|
281
128
|
|
|
282
129
|
<style>
|
|
283
130
|
/* Custom styles for the dashboard */
|
|
131
|
+
|
|
132
|
+
/* Standard card components */
|
|
133
|
+
.card {
|
|
134
|
+
@apply bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-6 mb-6;
|
|
135
|
+
}
|
|
136
|
+
.card-compact {
|
|
137
|
+
@apply bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl p-4 mb-4;
|
|
138
|
+
}
|
|
139
|
+
|
|
284
140
|
.stat-card {
|
|
285
141
|
@apply bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 p-4 transition-shadow;
|
|
286
142
|
}
|
|
@@ -331,6 +187,35 @@
|
|
|
331
187
|
.badge-orange {
|
|
332
188
|
@apply bg-orange-100 dark:bg-orange-900/50 text-orange-700 dark:text-orange-300;
|
|
333
189
|
}
|
|
190
|
+
|
|
191
|
+
/* Turbo loading states */
|
|
192
|
+
turbo-frame[busy] {
|
|
193
|
+
position: relative;
|
|
194
|
+
opacity: 0.6;
|
|
195
|
+
pointer-events: none;
|
|
196
|
+
}
|
|
197
|
+
turbo-frame[busy]::after {
|
|
198
|
+
content: '';
|
|
199
|
+
position: absolute;
|
|
200
|
+
top: 50%;
|
|
201
|
+
left: 50%;
|
|
202
|
+
width: 24px;
|
|
203
|
+
height: 24px;
|
|
204
|
+
margin: -12px 0 0 -12px;
|
|
205
|
+
border: 2px solid #e5e7eb;
|
|
206
|
+
border-top-color: #3b82f6;
|
|
207
|
+
border-radius: 50%;
|
|
208
|
+
animation: spin 0.8s linear infinite;
|
|
209
|
+
}
|
|
210
|
+
@keyframes spin {
|
|
211
|
+
to { transform: rotate(360deg); }
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Form submitting state */
|
|
215
|
+
form[data-turbo-submitting] {
|
|
216
|
+
opacity: 0.6;
|
|
217
|
+
pointer-events: none;
|
|
218
|
+
}
|
|
334
219
|
</style>
|
|
335
220
|
</head>
|
|
336
221
|
|
|
@@ -355,80 +240,17 @@
|
|
|
355
240
|
<% end %>
|
|
356
241
|
|
|
357
242
|
<!-- Desktop Navigation -->
|
|
243
|
+
<%
|
|
244
|
+
nav_items = [
|
|
245
|
+
{ path: ruby_llm_agents.root_path, label: "Dashboard", icon: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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" />' },
|
|
246
|
+
{ path: ruby_llm_agents.agents_path, label: "Agents", icon: '<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" />' },
|
|
247
|
+
{ path: ruby_llm_agents.executions_path, label: "Executions", icon: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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" />' },
|
|
248
|
+
{ path: ruby_llm_agents.settings_path, label: "Settings", icon: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" 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" /><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />' }
|
|
249
|
+
]
|
|
250
|
+
%>
|
|
358
251
|
<nav class="hidden md:flex items-center space-x-1">
|
|
359
|
-
|
|
360
|
-
|
|
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
|
|
252
|
+
<% nav_items.each do |item| %>
|
|
253
|
+
<%= render "rubyllm/agents/shared/nav_link", path: item[:path], label: item[:label], icon: item[:icon], mobile: false %>
|
|
432
254
|
<% end %>
|
|
433
255
|
</nav>
|
|
434
256
|
</div>
|
|
@@ -441,13 +263,16 @@
|
|
|
441
263
|
>
|
|
442
264
|
<span id="live-clock" class="tabular-nums"></span>
|
|
443
265
|
|
|
444
|
-
<
|
|
445
|
-
id="
|
|
446
|
-
|
|
266
|
+
<button
|
|
267
|
+
id="refresh-button"
|
|
268
|
+
onclick="window.location.reload()"
|
|
269
|
+
title="Refresh page"
|
|
270
|
+
class="p-1.5 rounded-md text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
|
447
271
|
>
|
|
448
|
-
<
|
|
449
|
-
|
|
450
|
-
|
|
272
|
+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
273
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
274
|
+
</svg>
|
|
275
|
+
</button>
|
|
451
276
|
|
|
452
277
|
<!-- Mobile menu button -->
|
|
453
278
|
<button
|
|
@@ -501,79 +326,8 @@
|
|
|
501
326
|
"
|
|
502
327
|
>
|
|
503
328
|
<nav class="max-w-7xl mx-auto px-4 py-3 space-y-1">
|
|
504
|
-
|
|
505
|
-
|
|
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
|
|
329
|
+
<% nav_items.each do |item| %>
|
|
330
|
+
<%= render "rubyllm/agents/shared/nav_link", path: item[:path], label: item[:label], icon: item[:icon], mobile: true %>
|
|
577
331
|
<% end %>
|
|
578
332
|
</nav>
|
|
579
333
|
</div>
|
|
@@ -587,37 +341,25 @@
|
|
|
587
341
|
<!-- Footer -->
|
|
588
342
|
<footer
|
|
589
343
|
class="border-t bg-white dark:bg-gray-800 dark:border-gray-700 mt-auto"
|
|
590
|
-
data
|
|
344
|
+
x-data="themeManager()"
|
|
591
345
|
>
|
|
592
346
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
|
|
593
347
|
<div class="flex flex-col sm:flex-row items-center sm:justify-between gap-3 sm:gap-0">
|
|
594
348
|
<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
|
-
|
|
349
|
+
<label for="theme-select" class="text-sm text-gray-500 dark:text-gray-400">Theme:</label>
|
|
602
350
|
<select
|
|
603
351
|
id="theme-select"
|
|
604
|
-
|
|
605
|
-
|
|
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
|
-
"
|
|
352
|
+
x-model="preference"
|
|
353
|
+
@change="setTheme($event.target.value)"
|
|
354
|
+
class="text-sm border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 py-1 px-2"
|
|
611
355
|
>
|
|
612
356
|
<option value="light">Light</option>
|
|
613
357
|
<option value="dark">Dark</option>
|
|
614
358
|
<option value="auto">Auto</option>
|
|
615
359
|
</select>
|
|
616
360
|
</div>
|
|
617
|
-
|
|
618
361
|
<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>
|
|
362
|
+
Powered by <a href="https://github.com/adham90/ruby_llm-agents" class="text-blue-600 dark:text-blue-400 hover:underline">ruby_llm-agents</a>
|
|
621
363
|
</p>
|
|
622
364
|
</div>
|
|
623
365
|
</div>
|