ruby_llm-agents 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  <div class="mb-6">
2
- <%= link_to ruby_llm_agents.agents_path, class: "text-blue-600 hover:underline" do %>
2
+ <%= link_to ruby_llm_agents.agents_path, class: "text-blue-600 dark:text-blue-400 hover:underline" do %>
3
3
  <span class="inline-flex items-center">
4
4
  <svg
5
5
  class="w-4 h-4 mr-1"
@@ -20,11 +20,11 @@
20
20
  </div>
21
21
 
22
22
  <!-- Header -->
23
- <div class="bg-white rounded-lg shadow p-6 mb-6">
23
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-6">
24
24
  <div class="flex items-start justify-between">
25
25
  <div>
26
26
  <div class="flex items-center space-x-3">
27
- <h1 class="text-2xl font-bold text-gray-900">
27
+ <h1 class="text-2xl font-bold text-gray-900 dark:text-gray-100">
28
28
  <%= @agent_type.gsub(/Agent$/, '') %>
29
29
  </h1>
30
30
 
@@ -32,7 +32,7 @@
32
32
  <span
33
33
  class="
34
34
  inline-flex items-center px-2.5 py-0.5 rounded-full text-xs
35
- font-medium bg-green-100 text-green-800
35
+ font-medium bg-green-100 dark:bg-green-900/50 text-green-800 dark:text-green-300
36
36
  "
37
37
  >
38
38
  Active
@@ -41,7 +41,7 @@
41
41
  <span
42
42
  class="
43
43
  inline-flex items-center px-2.5 py-0.5 rounded-full text-xs
44
- font-medium bg-gray-100 text-gray-600
44
+ font-medium bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-400
45
45
  "
46
46
  >
47
47
  Deleted
@@ -49,19 +49,19 @@
49
49
  <% end %>
50
50
 
51
51
  <% if @config %>
52
- <span class="text-sm text-gray-500">v<%= @config[:version] %></span>
52
+ <span class="text-sm text-gray-500 dark:text-gray-400">v<%= @config[:version] %></span>
53
53
  <% end %>
54
54
  </div>
55
55
 
56
56
  <% if @config %>
57
- <p class="text-gray-500 mt-1">
57
+ <p class="text-gray-500 dark:text-gray-400 mt-1">
58
58
  <%= @config[:model] %> &middot; temp <%= @config[:temperature] %>
59
59
  &middot; timeout <%= @config[:timeout] %>s
60
60
  </p>
61
61
  <% end %>
62
62
  </div>
63
63
 
64
- <div class="text-right text-sm text-gray-500">
64
+ <div class="text-right text-sm text-gray-500 dark:text-gray-400">
65
65
  <p><%= @stats[:count] %> total executions</p>
66
66
  </div>
67
67
  </div>
@@ -110,8 +110,8 @@
110
110
  <!-- Charts Section -->
111
111
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
112
112
  <!-- Executions Over Time -->
113
- <div class="bg-white rounded-lg shadow p-6 pb-20 overflow-hidden">
114
- <h3 class="text-lg font-semibold text-gray-900 mb-4">
113
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 pb-20 overflow-hidden">
114
+ <h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">
115
115
  Executions (30 days)
116
116
  </h3>
117
117
 
@@ -127,8 +127,8 @@
127
127
  </div>
128
128
 
129
129
  <!-- Cost Over Time -->
130
- <div class="bg-white rounded-lg shadow p-6 pb-8 overflow-hidden">
131
- <h3 class="text-lg font-semibold text-gray-900 mb-4">Cost (30 days)</h3>
130
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 pb-8 overflow-hidden">
131
+ <h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">Cost (30 days)</h3>
132
132
 
133
133
  <div id="cost-chart" style="height: 250px;">
134
134
  <% cost_data = @trend_data.map { |d| [d[:date].strftime("%b %d"), d[:total_cost].to_f.round(4)] }.to_h %>
@@ -139,9 +139,9 @@
139
139
  </div>
140
140
 
141
141
  <!-- Status Distribution (compact) -->
142
- <div class="bg-white rounded-lg shadow p-4 mb-6">
142
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-4 mb-6">
143
143
  <div class="flex items-center justify-between">
144
- <p class="text-sm text-gray-500 uppercase">Status Distribution</p>
144
+ <p class="text-sm text-gray-500 dark:text-gray-400 uppercase">Status Distribution</p>
145
145
 
146
146
  <div class="flex flex-wrap gap-4">
147
147
  <% status_colors = {
@@ -158,9 +158,9 @@
158
158
  style="background-color: <%= status_colors[status] || '#6B7280' %>"
159
159
  ></span>
160
160
 
161
- <span class="text-sm text-gray-700 capitalize"><%= status %></span>
161
+ <span class="text-sm text-gray-700 dark:text-gray-300 capitalize"><%= status %></span>
162
162
 
163
- <span class="text-sm font-medium text-gray-900 ml-1">
163
+ <span class="text-sm font-medium text-gray-900 dark:text-gray-100 ml-1">
164
164
  (<%= number_with_delimiter(count) %>)
165
165
  </span>
166
166
  </div>
@@ -171,29 +171,29 @@
171
171
 
172
172
  <% if @config %>
173
173
  <!-- Configuration -->
174
- <div class="bg-white rounded-lg shadow p-6 mb-6">
175
- <h3 class="text-lg font-semibold text-gray-900 mb-4">Configuration</h3>
174
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-6">
175
+ <h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">Configuration</h3>
176
176
 
177
177
  <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4">
178
178
  <div>
179
- <p class="text-sm text-gray-500">Model</p>
180
- <p class="font-medium"><%= @config[:model] %></p>
179
+ <p class="text-sm text-gray-500 dark:text-gray-400">Model</p>
180
+ <p class="font-medium text-gray-900 dark:text-gray-100"><%= @config[:model] %></p>
181
181
  </div>
182
182
 
183
183
  <div>
184
- <p class="text-sm text-gray-500">Temperature</p>
185
- <p class="font-medium"><%= @config[:temperature] %></p>
184
+ <p class="text-sm text-gray-500 dark:text-gray-400">Temperature</p>
185
+ <p class="font-medium text-gray-900 dark:text-gray-100"><%= @config[:temperature] %></p>
186
186
  </div>
187
187
 
188
188
  <div>
189
- <p class="text-sm text-gray-500">Timeout</p>
190
- <p class="font-medium"><%= @config[:timeout] %> seconds</p>
189
+ <p class="text-sm text-gray-500 dark:text-gray-400">Timeout</p>
190
+ <p class="font-medium text-gray-900 dark:text-gray-100"><%= @config[:timeout] %> seconds</p>
191
191
  </div>
192
192
 
193
193
  <div>
194
- <p class="text-sm text-gray-500">Cache</p>
194
+ <p class="text-sm text-gray-500 dark:text-gray-400">Cache</p>
195
195
 
196
- <p class="font-medium">
196
+ <p class="font-medium text-gray-900 dark:text-gray-100">
197
197
  <% if @config[:cache_enabled] %>
198
198
  Enabled (
199
199
  <%= @config[:cache_ttl].inspect %>
@@ -206,26 +206,26 @@
206
206
  </div>
207
207
 
208
208
  <% if @config[:params].present? && @config[:params].any? %>
209
- <div class="border-t border-gray-100 pt-4">
210
- <p class="text-sm text-gray-500 mb-2">Parameters</p>
209
+ <div class="border-t border-gray-100 dark:border-gray-700 pt-4">
210
+ <p class="text-sm text-gray-500 dark:text-gray-400 mb-2">Parameters</p>
211
211
 
212
212
  <div class="space-y-2">
213
213
  <% @config[:params].each do |name, opts| %>
214
214
  <div class="flex items-center text-sm">
215
- <code class="bg-gray-100 px-2 py-0.5 rounded font-mono">
215
+ <code class="bg-gray-100 dark:bg-gray-700 dark:text-gray-200 px-2 py-0.5 rounded font-mono">
216
216
  <%= name %>
217
217
  </code>
218
218
 
219
219
  <% if opts[:required] %>
220
- <span class="ml-2 text-xs text-red-500 font-medium">
220
+ <span class="ml-2 text-xs text-red-500 dark:text-red-400 font-medium">
221
221
  required
222
222
  </span>
223
223
  <% elsif opts[:default].present? %>
224
- <span class="ml-2 text-xs text-gray-400">
224
+ <span class="ml-2 text-xs text-gray-400 dark:text-gray-500">
225
225
  default: <%= opts[:default].inspect %>
226
226
  </span>
227
227
  <% else %>
228
- <span class="ml-2 text-xs text-gray-400">optional</span>
228
+ <span class="ml-2 text-xs text-gray-400 dark:text-gray-500">optional</span>
229
229
  <% end %>
230
230
  </div>
231
231
  <% end %>
@@ -236,8 +236,8 @@
236
236
  <% end %>
237
237
 
238
238
  <!-- Executions -->
239
- <div class="bg-white rounded-lg shadow p-6">
240
- <h3 class="text-lg font-semibold text-gray-900 mb-4">Executions</h3>
239
+ <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
240
+ <h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-4">Executions</h3>
241
241
 
242
242
  <%= turbo_frame_tag "executions_table" do %>
243
243
  <%
@@ -249,10 +249,10 @@
249
249
  %>
250
250
 
251
251
  <%= form_with url: ruby_llm_agents.agent_path(@agent_type), method: :get, data: { turbo_frame: "executions_table" }, id: "agent-filters-form" do |f| %>
252
- <div class="flex flex-wrap items-center gap-3 mb-4 pb-4 border-b border-gray-100">
252
+ <div class="flex flex-wrap items-center gap-3 mb-4 pb-4 border-b border-gray-100 dark:border-gray-700">
253
253
  <!-- Status Filter (Multi-select) -->
254
254
  <div class="relative filter-dropdown" data-filter="statuses">
255
- <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 border border-gray-200 rounded-lg hover:bg-gray-100 transition-colors <%= selected_statuses.any? ? 'ring-2 ring-blue-500 ring-offset-1' : '' %>">
255
+ <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors <%= selected_statuses.any? ? 'ring-2 ring-blue-500 ring-offset-1 dark:ring-offset-gray-800' : '' %>">
256
256
  <% if selected_statuses.length == 1
257
257
  status_color = case selected_statuses.first
258
258
  when 'success' then 'bg-green-500'
@@ -265,7 +265,7 @@
265
265
  status_color = 'bg-gray-400'
266
266
  end %>
267
267
  <span class="w-2 h-2 rounded-full <%= status_color %>"></span>
268
- <span class="dropdown-label text-gray-700">
268
+ <span class="dropdown-label text-gray-700 dark:text-gray-200">
269
269
  <% if selected_statuses.empty? %>
270
270
  All Statuses
271
271
  <% elsif selected_statuses.length == 1 %>
@@ -274,34 +274,34 @@
274
274
  <%= selected_statuses.length %> Statuses
275
275
  <% end %>
276
276
  </span>
277
- <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
277
+ <svg class="w-4 h-4 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
278
278
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
279
279
  </svg>
280
280
  </button>
281
- <div class="dropdown-menu hidden absolute z-10 mt-1 w-44 bg-white rounded-lg shadow-lg border border-gray-200 py-1">
282
- <div class="px-3 py-2 border-b border-gray-100">
281
+ <div class="dropdown-menu hidden absolute z-10 mt-1 w-44 bg-white dark:bg-gray-700 rounded-lg shadow-lg border border-gray-200 dark:border-gray-600 py-1">
282
+ <div class="px-3 py-2 border-b border-gray-100 dark:border-gray-600">
283
283
  <label class="flex items-center gap-2 cursor-pointer">
284
- <input type="checkbox" class="select-all-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="toggleAllOptions(this, 'statuses')" <%= selected_statuses.empty? ? 'checked' : '' %>>
285
- <span class="text-sm font-medium text-gray-700">All Statuses</span>
284
+ <input type="checkbox" class="select-all-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="toggleAllOptions(this, 'statuses')" <%= selected_statuses.empty? ? 'checked' : '' %>>
285
+ <span class="text-sm font-medium text-gray-700 dark:text-gray-200">All Statuses</span>
286
286
  </label>
287
287
  </div>
288
- <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 cursor-pointer">
289
- <input type="checkbox" name="statuses[]" value="success" class="filter-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="updateMultiSelect('statuses')" <%= selected_statuses.include?('success') ? 'checked' : '' %>>
288
+ <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 cursor-pointer">
289
+ <input type="checkbox" name="statuses[]" value="success" class="filter-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="updateMultiSelect('statuses')" <%= selected_statuses.include?('success') ? 'checked' : '' %>>
290
290
  <span class="w-2 h-2 rounded-full bg-green-500"></span>
291
291
  Success
292
292
  </label>
293
- <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 cursor-pointer">
294
- <input type="checkbox" name="statuses[]" value="error" class="filter-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="updateMultiSelect('statuses')" <%= selected_statuses.include?('error') ? 'checked' : '' %>>
293
+ <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 cursor-pointer">
294
+ <input type="checkbox" name="statuses[]" value="error" class="filter-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="updateMultiSelect('statuses')" <%= selected_statuses.include?('error') ? 'checked' : '' %>>
295
295
  <span class="w-2 h-2 rounded-full bg-red-500"></span>
296
296
  Error
297
297
  </label>
298
- <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 cursor-pointer">
299
- <input type="checkbox" name="statuses[]" value="running" class="filter-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="updateMultiSelect('statuses')" <%= selected_statuses.include?('running') ? 'checked' : '' %>>
298
+ <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 cursor-pointer">
299
+ <input type="checkbox" name="statuses[]" value="running" class="filter-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="updateMultiSelect('statuses')" <%= selected_statuses.include?('running') ? 'checked' : '' %>>
300
300
  <span class="w-2 h-2 rounded-full bg-blue-500 animate-pulse"></span>
301
301
  Running
302
302
  </label>
303
- <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 cursor-pointer">
304
- <input type="checkbox" name="statuses[]" value="timeout" class="filter-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="updateMultiSelect('statuses')" <%= selected_statuses.include?('timeout') ? 'checked' : '' %>>
303
+ <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 cursor-pointer">
304
+ <input type="checkbox" name="statuses[]" value="timeout" class="filter-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="updateMultiSelect('statuses')" <%= selected_statuses.include?('timeout') ? 'checked' : '' %>>
305
305
  <span class="w-2 h-2 rounded-full bg-yellow-500"></span>
306
306
  Timeout
307
307
  </label>
@@ -311,11 +311,11 @@
311
311
  <!-- Version Filter (Multi-select) -->
312
312
  <% if @versions.any? %>
313
313
  <div class="relative filter-dropdown" data-filter="versions">
314
- <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 border border-gray-200 rounded-lg hover:bg-gray-100 transition-colors <%= selected_versions.any? ? 'ring-2 ring-blue-500 ring-offset-1' : '' %>">
314
+ <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors <%= selected_versions.any? ? 'ring-2 ring-blue-500 ring-offset-1 dark:ring-offset-gray-800' : '' %>">
315
315
  <svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
316
316
  <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"/>
317
317
  </svg>
318
- <span class="dropdown-label text-gray-700">
318
+ <span class="dropdown-label text-gray-700 dark:text-gray-200">
319
319
  <% if selected_versions.empty? %>
320
320
  All Versions
321
321
  <% elsif selected_versions.length == 1 %>
@@ -324,20 +324,20 @@
324
324
  <%= selected_versions.length %> Versions
325
325
  <% end %>
326
326
  </span>
327
- <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
327
+ <svg class="w-4 h-4 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
328
328
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
329
329
  </svg>
330
330
  </button>
331
- <div class="dropdown-menu hidden absolute z-10 mt-1 w-44 bg-white rounded-lg shadow-lg border border-gray-200 py-1 max-h-64 overflow-y-auto">
332
- <div class="px-3 py-2 border-b border-gray-100">
331
+ <div class="dropdown-menu hidden absolute z-10 mt-1 w-44 bg-white dark:bg-gray-700 rounded-lg shadow-lg border border-gray-200 dark:border-gray-600 py-1 max-h-64 overflow-y-auto">
332
+ <div class="px-3 py-2 border-b border-gray-100 dark:border-gray-600">
333
333
  <label class="flex items-center gap-2 cursor-pointer">
334
- <input type="checkbox" class="select-all-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="toggleAllOptions(this, 'versions')" <%= selected_versions.empty? ? 'checked' : '' %>>
335
- <span class="text-sm font-medium text-gray-700">All Versions</span>
334
+ <input type="checkbox" class="select-all-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="toggleAllOptions(this, 'versions')" <%= selected_versions.empty? ? 'checked' : '' %>>
335
+ <span class="text-sm font-medium text-gray-700 dark:text-gray-200">All Versions</span>
336
336
  </label>
337
337
  </div>
338
338
  <% @versions.each do |version| %>
339
- <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 cursor-pointer">
340
- <input type="checkbox" name="versions[]" value="<%= version %>" class="filter-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="updateMultiSelect('versions')" <%= selected_versions.include?(version.to_s) ? 'checked' : '' %>>
339
+ <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 cursor-pointer">
340
+ <input type="checkbox" name="versions[]" value="<%= version %>" class="filter-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="updateMultiSelect('versions')" <%= selected_versions.include?(version.to_s) ? 'checked' : '' %>>
341
341
  v<%= version %>
342
342
  </label>
343
343
  <% end %>
@@ -348,11 +348,11 @@
348
348
  <!-- Model Filter (Multi-select) -->
349
349
  <% if @models.length > 1 %>
350
350
  <div class="relative filter-dropdown" data-filter="models">
351
- <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 border border-gray-200 rounded-lg hover:bg-gray-100 transition-colors <%= selected_models.any? ? 'ring-2 ring-blue-500 ring-offset-1' : '' %>">
351
+ <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors <%= selected_models.any? ? 'ring-2 ring-blue-500 ring-offset-1 dark:ring-offset-gray-800' : '' %>">
352
352
  <svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
353
353
  <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"/>
354
354
  </svg>
355
- <span class="dropdown-label text-gray-700">
355
+ <span class="dropdown-label text-gray-700 dark:text-gray-200">
356
356
  <% if selected_models.empty? %>
357
357
  All Models
358
358
  <% elsif selected_models.length == 1 %>
@@ -361,20 +361,20 @@
361
361
  <%= selected_models.length %> Models
362
362
  <% end %>
363
363
  </span>
364
- <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
364
+ <svg class="w-4 h-4 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
365
365
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
366
366
  </svg>
367
367
  </button>
368
- <div class="dropdown-menu hidden absolute z-10 mt-1 w-56 bg-white rounded-lg shadow-lg border border-gray-200 py-1 max-h-64 overflow-y-auto">
369
- <div class="px-3 py-2 border-b border-gray-100">
368
+ <div class="dropdown-menu hidden absolute z-10 mt-1 w-56 bg-white dark:bg-gray-700 rounded-lg shadow-lg border border-gray-200 dark:border-gray-600 py-1 max-h-64 overflow-y-auto">
369
+ <div class="px-3 py-2 border-b border-gray-100 dark:border-gray-600">
370
370
  <label class="flex items-center gap-2 cursor-pointer">
371
- <input type="checkbox" class="select-all-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="toggleAllOptions(this, 'models')" <%= selected_models.empty? ? 'checked' : '' %>>
372
- <span class="text-sm font-medium text-gray-700">All Models</span>
371
+ <input type="checkbox" class="select-all-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="toggleAllOptions(this, 'models')" <%= selected_models.empty? ? 'checked' : '' %>>
372
+ <span class="text-sm font-medium text-gray-700 dark:text-gray-200">All Models</span>
373
373
  </label>
374
374
  </div>
375
375
  <% @models.each do |model| %>
376
- <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 cursor-pointer">
377
- <input type="checkbox" name="models[]" value="<%= model %>" class="filter-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="updateMultiSelect('models')" <%= selected_models.include?(model) ? 'checked' : '' %>>
376
+ <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 cursor-pointer">
377
+ <input type="checkbox" name="models[]" value="<%= model %>" class="filter-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="updateMultiSelect('models')" <%= selected_models.include?(model) ? 'checked' : '' %>>
378
378
  <%= model %>
379
379
  </label>
380
380
  <% end %>
@@ -385,11 +385,11 @@
385
385
  <!-- Temperature Filter (Multi-select) -->
386
386
  <% if @temperatures.length > 1 %>
387
387
  <div class="relative filter-dropdown" data-filter="temperatures">
388
- <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 border border-gray-200 rounded-lg hover:bg-gray-100 transition-colors <%= selected_temperatures.any? ? 'ring-2 ring-blue-500 ring-offset-1' : '' %>">
388
+ <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors <%= selected_temperatures.any? ? 'ring-2 ring-blue-500 ring-offset-1 dark:ring-offset-gray-800' : '' %>">
389
389
  <svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
390
390
  <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"/>
391
391
  </svg>
392
- <span class="dropdown-label text-gray-700">
392
+ <span class="dropdown-label text-gray-700 dark:text-gray-200">
393
393
  <% if selected_temperatures.empty? %>
394
394
  All Temps
395
395
  <% elsif selected_temperatures.length == 1 %>
@@ -398,20 +398,20 @@
398
398
  <%= selected_temperatures.length %> Temps
399
399
  <% end %>
400
400
  </span>
401
- <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
401
+ <svg class="w-4 h-4 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
402
402
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
403
403
  </svg>
404
404
  </button>
405
- <div class="dropdown-menu hidden absolute z-10 mt-1 w-36 bg-white rounded-lg shadow-lg border border-gray-200 py-1 max-h-64 overflow-y-auto">
406
- <div class="px-3 py-2 border-b border-gray-100">
405
+ <div class="dropdown-menu hidden absolute z-10 mt-1 w-36 bg-white dark:bg-gray-700 rounded-lg shadow-lg border border-gray-200 dark:border-gray-600 py-1 max-h-64 overflow-y-auto">
406
+ <div class="px-3 py-2 border-b border-gray-100 dark:border-gray-600">
407
407
  <label class="flex items-center gap-2 cursor-pointer">
408
- <input type="checkbox" class="select-all-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="toggleAllOptions(this, 'temperatures')" <%= selected_temperatures.empty? ? 'checked' : '' %>>
409
- <span class="text-sm font-medium text-gray-700">All Temps</span>
408
+ <input type="checkbox" class="select-all-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="toggleAllOptions(this, 'temperatures')" <%= selected_temperatures.empty? ? 'checked' : '' %>>
409
+ <span class="text-sm font-medium text-gray-700 dark:text-gray-200">All Temps</span>
410
410
  </label>
411
411
  </div>
412
412
  <% @temperatures.each do |temp| %>
413
- <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 cursor-pointer">
414
- <input type="checkbox" name="temperatures[]" value="<%= temp %>" class="filter-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500" onchange="updateMultiSelect('temperatures')" <%= selected_temperatures.include?(temp.to_s) ? 'checked' : '' %>>
413
+ <label class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 cursor-pointer">
414
+ <input type="checkbox" name="temperatures[]" value="<%= temp %>" class="filter-checkbox rounded border-gray-300 dark:border-gray-500 text-blue-600 focus:ring-blue-500 dark:bg-gray-600" onchange="updateMultiSelect('temperatures')" <%= selected_temperatures.include?(temp.to_s) ? 'checked' : '' %>>
415
415
  <%= temp %>
416
416
  </label>
417
417
  <% end %>
@@ -421,11 +421,11 @@
421
421
 
422
422
  <!-- Time Range Filter -->
423
423
  <div class="relative filter-dropdown" data-filter="days">
424
- <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 border border-gray-200 rounded-lg hover:bg-gray-100 transition-colors <%= params[:days].present? ? 'ring-2 ring-blue-500 ring-offset-1' : '' %>">
424
+ <button type="button" onclick="toggleDropdown(this)" class="flex items-center gap-2 px-3 py-2 text-sm bg-gray-50 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 transition-colors <%= params[:days].present? ? 'ring-2 ring-blue-500 ring-offset-1 dark:ring-offset-gray-800' : '' %>">
425
425
  <svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
426
426
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/>
427
427
  </svg>
428
- <span class="dropdown-label text-gray-700">
428
+ <span class="dropdown-label text-gray-700 dark:text-gray-200">
429
429
  <% case params[:days]
430
430
  when '1' then %>Today<%
431
431
  when '7' then %>Last 7 Days<%
@@ -433,21 +433,21 @@
433
433
  else %>All Time<%
434
434
  end %>
435
435
  </span>
436
- <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
436
+ <svg class="w-4 h-4 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
437
437
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
438
438
  </svg>
439
439
  </button>
440
- <div class="dropdown-menu hidden absolute z-10 mt-1 w-40 bg-white rounded-lg shadow-lg border border-gray-200 py-1">
441
- <a href="#" onclick="selectSingleFilter('days', '', 'All Time'); return false;" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 <%= params[:days].blank? ? 'bg-blue-50 text-blue-700' : '' %>">
440
+ <div class="dropdown-menu hidden absolute z-10 mt-1 w-40 bg-white dark:bg-gray-700 rounded-lg shadow-lg border border-gray-200 dark:border-gray-600 py-1">
441
+ <a href="#" onclick="selectSingleFilter('days', '', 'All Time'); return false;" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 <%= params[:days].blank? ? 'bg-blue-50 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300' : '' %>">
442
442
  All Time
443
443
  </a>
444
- <a href="#" onclick="selectSingleFilter('days', '1', 'Today'); return false;" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 <%= params[:days] == '1' ? 'bg-blue-50 text-blue-700' : '' %>">
444
+ <a href="#" onclick="selectSingleFilter('days', '1', 'Today'); return false;" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 <%= params[:days] == '1' ? 'bg-blue-50 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300' : '' %>">
445
445
  Today
446
446
  </a>
447
- <a href="#" onclick="selectSingleFilter('days', '7', 'Last 7 Days'); return false;" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 <%= params[:days] == '7' ? 'bg-blue-50 text-blue-700' : '' %>">
447
+ <a href="#" onclick="selectSingleFilter('days', '7', 'Last 7 Days'); return false;" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 <%= params[:days] == '7' ? 'bg-blue-50 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300' : '' %>">
448
448
  Last 7 Days
449
449
  </a>
450
- <a href="#" onclick="selectSingleFilter('days', '30', 'Last 30 Days'); return false;" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 <%= params[:days] == '30' ? 'bg-blue-50 text-blue-700' : '' %>">
450
+ <a href="#" onclick="selectSingleFilter('days', '30', 'Last 30 Days'); return false;" class="flex items-center gap-2 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600 <%= params[:days] == '30' ? 'bg-blue-50 dark:bg-blue-900/50 text-blue-700 dark:text-blue-300' : '' %>">
451
451
  Last 30 Days
452
452
  </a>
453
453
  </div>
@@ -456,7 +456,7 @@
456
456
 
457
457
  <!-- Clear Filters -->
458
458
  <% if has_filters %>
459
- <%= link_to ruby_llm_agents.agent_path(@agent_type), data: { turbo_frame: "executions_table" }, class: "flex items-center gap-1 px-3 py-2 text-sm text-red-500 hover:text-red-600 hover:bg-red-50 rounded-lg transition-colors" do %>
459
+ <%= link_to ruby_llm_agents.agent_path(@agent_type), data: { turbo_frame: "executions_table" }, class: "flex items-center gap-1 px-3 py-2 text-sm text-red-500 dark:text-red-400 hover:text-red-600 dark:hover:text-red-300 hover:bg-red-50 dark:hover:bg-red-900/30 rounded-lg transition-colors" do %>
460
460
  <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
461
461
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
462
462
  </svg>
@@ -465,11 +465,11 @@
465
465
  <% end %>
466
466
 
467
467
  <!-- Stats Summary (right aligned) -->
468
- <div class="ml-auto flex items-center gap-4 text-sm text-gray-500">
468
+ <div class="ml-auto flex items-center gap-4 text-sm text-gray-500 dark:text-gray-400">
469
469
  <span><%= number_with_delimiter(@filter_stats[:total_count]) %> executions</span>
470
- <span class="text-gray-300">|</span>
470
+ <span class="text-gray-300 dark:text-gray-600">|</span>
471
471
  <span>$<%= number_with_precision(@filter_stats[:total_cost] || 0, precision: 4) %></span>
472
- <span class="text-gray-300">|</span>
472
+ <span class="text-gray-300 dark:text-gray-600">|</span>
473
473
  <span><%= number_with_delimiter(@filter_stats[:total_tokens] || 0) %> tokens</span>
474
474
  </div>
475
475
  </div>
@@ -1,4 +1,4 @@
1
- <div id="execution-<%= execution.id %>" class="py-3 hover:bg-gray-50 -mx-2 px-2 rounded-lg transition-colors">
1
+ <div id="execution-<%= execution.id %>" class="py-3 hover:bg-gray-50 dark:hover:bg-gray-700 -mx-2 px-2 rounded-lg transition-colors">
2
2
  <%= link_to ruby_llm_agents.execution_path(execution), data: { turbo: false }, class: "block" do %>
3
3
  <div class="flex items-start space-x-3">
4
4
  <!-- Timeline indicator -->
@@ -10,35 +10,35 @@
10
10
  <div class="flex-1 min-w-0">
11
11
  <div class="flex items-center justify-between">
12
12
  <div class="flex items-center space-x-2">
13
- <p class="font-medium text-gray-900 text-sm">
13
+ <p class="font-medium text-gray-900 dark:text-gray-100 text-sm">
14
14
  <%= execution.agent_type.gsub(/Agent$/, '') %>
15
15
  </p>
16
- <span class="text-xs text-gray-400">v<%= execution.agent_version %></span>
16
+ <span class="text-xs text-gray-400 dark:text-gray-500">v<%= execution.agent_version %></span>
17
17
  <% if execution.status_running? %>
18
- <span class="text-xs text-blue-600 font-medium">Running...</span>
18
+ <span class="text-xs text-blue-600 dark:text-blue-400 font-medium">Running...</span>
19
19
  <% end %>
20
20
  </div>
21
- <p class="text-xs text-gray-400">
21
+ <p class="text-xs text-gray-400 dark:text-gray-500">
22
22
  <%= time_ago_in_words(execution.created_at) %> ago
23
23
  </p>
24
24
  </div>
25
25
 
26
26
  <% if execution.status_running? %>
27
- <p class="text-xs text-blue-500 mt-1">
27
+ <p class="text-xs text-blue-500 dark:text-blue-400 mt-1">
28
28
  In progress...
29
29
  </p>
30
30
  <% else %>
31
- <p class="text-xs text-gray-500 mt-1">
31
+ <p class="text-xs text-gray-500 dark:text-gray-400 mt-1">
32
32
  <%= number_to_human_short(execution.total_tokens || 0) %> tokens
33
- <span class="text-gray-300 mx-1">&middot;</span>
33
+ <span class="text-gray-300 dark:text-gray-600 mx-1">&middot;</span>
34
34
  <%= number_to_human_short(execution.total_cost || 0, prefix: "$", precision: 2) %>
35
- <span class="text-gray-300 mx-1">&middot;</span>
35
+ <span class="text-gray-300 dark:text-gray-600 mx-1">&middot;</span>
36
36
  <%= number_to_human_short(execution.duration_ms || 0) %>ms
37
37
  </p>
38
38
  <% end %>
39
39
 
40
40
  <% if execution.status_error? && execution.error_message.present? %>
41
- <p class="text-xs text-red-600 mt-1.5 bg-red-50 rounded px-2 py-1">
41
+ <p class="text-xs text-red-600 dark:text-red-400 mt-1.5 bg-red-50 dark:bg-red-900/30 rounded px-2 py-1">
42
42
  <%= execution.error_class %>: <%= truncate(execution.error_message, length: 80) %>
43
43
  </p>
44
44
  <% end %>
@@ -28,11 +28,11 @@
28
28
  </div>
29
29
 
30
30
  <!-- Activity Chart -->
31
- <div class="bg-white rounded-xl shadow-sm border border-gray-100 mb-8 pb-24">
32
- <div class="px-6 py-4 border-b border-gray-100">
31
+ <div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700 mb-8 pb-24">
32
+ <div class="px-6 py-4 border-b border-gray-100 dark:border-gray-700">
33
33
  <div class="flex justify-between items-center">
34
- <h3 class="text-lg font-semibold text-gray-900">Today's Activity</h3>
35
- <span class="text-xs text-gray-400">Hourly executions</span>
34
+ <h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100">Today's Activity</h3>
35
+ <span class="text-xs text-gray-400 dark:text-gray-500">Hourly executions</span>
36
36
  </div>
37
37
  </div>
38
38
 
@@ -55,13 +55,13 @@
55
55
  </div>
56
56
 
57
57
  <!-- Activity Feed -->
58
- <div class="bg-white rounded-xl shadow-sm border border-gray-100">
59
- <div class="px-6 py-4 border-b border-gray-100">
58
+ <div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-100 dark:border-gray-700">
59
+ <div class="px-6 py-4 border-b border-gray-100 dark:border-gray-700">
60
60
  <div class="flex justify-between items-center">
61
61
  <div class="flex items-center space-x-3">
62
- <h3 class="text-lg font-semibold text-gray-900">Activity Feed</h3>
62
+ <h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100">Activity Feed</h3>
63
63
 
64
- <div class="flex items-center space-x-3 text-xs text-gray-400">
64
+ <div class="flex items-center space-x-3 text-xs text-gray-400 dark:text-gray-500">
65
65
  <span class="flex items-center">
66
66
  <span class="w-2 h-2 bg-blue-500 rounded-full mr-1 animate-pulse"></span>
67
67
  running
@@ -84,7 +84,7 @@
84
84
  </div>
85
85
  </div>
86
86
 
87
- <%= link_to "View All", ruby_llm_agents.executions_path, data: { turbo: false }, class: "text-blue-600 hover:text-blue-700 text-sm font-medium" %>
87
+ <%= link_to "View All", ruby_llm_agents.executions_path, data: { turbo: false }, class: "text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 text-sm font-medium" %>
88
88
  </div>
89
89
  </div>
90
90
 
@@ -98,9 +98,9 @@
98
98
  <%= render partial: "rubyllm/agents/dashboard/execution_item", locals: { execution: execution } %>
99
99
  <% end %>
100
100
  <% else %>
101
- <div id="empty-state" class="py-10 text-center text-gray-500">
101
+ <div id="empty-state" class="py-10 text-center text-gray-500 dark:text-gray-400">
102
102
  <svg
103
- class="w-12 h-12 mx-auto mb-3 text-gray-300"
103
+ class="w-12 h-12 mx-auto mb-3 text-gray-300 dark:text-gray-600"
104
104
  fill="none"
105
105
  stroke="currentColor"
106
106
  viewBox="0 0 24 24"