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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +68 -4
  3. data/app/models/ruby_llm/agents/execution/analytics.rb +114 -13
  4. data/app/models/ruby_llm/agents/execution.rb +19 -58
  5. data/app/views/layouts/rubyllm/agents/application.html.erb +92 -350
  6. data/app/views/rubyllm/agents/agents/show.html.erb +331 -385
  7. data/app/views/rubyllm/agents/dashboard/_agent_comparison.html.erb +46 -0
  8. data/app/views/rubyllm/agents/dashboard/_budgets_bar.html.erb +0 -90
  9. data/app/views/rubyllm/agents/dashboard/_now_strip.html.erb +79 -5
  10. data/app/views/rubyllm/agents/dashboard/_top_errors.html.erb +49 -0
  11. data/app/views/rubyllm/agents/dashboard/index.html.erb +76 -121
  12. data/app/views/rubyllm/agents/executions/show.html.erb +134 -85
  13. data/app/views/rubyllm/agents/settings/show.html.erb +1 -1
  14. data/app/views/rubyllm/agents/shared/_breadcrumbs.html.erb +48 -0
  15. data/app/views/rubyllm/agents/shared/_nav_link.html.erb +27 -0
  16. data/config/routes.rb +2 -0
  17. data/lib/ruby_llm/agents/base/caching.rb +43 -0
  18. data/lib/ruby_llm/agents/base/cost_calculation.rb +103 -0
  19. data/lib/ruby_llm/agents/base/dsl.rb +261 -0
  20. data/lib/ruby_llm/agents/base/execution.rb +206 -0
  21. data/lib/ruby_llm/agents/base/reliability_execution.rb +131 -0
  22. data/lib/ruby_llm/agents/base/response_building.rb +86 -0
  23. data/lib/ruby_llm/agents/base/tool_tracking.rb +57 -0
  24. data/lib/ruby_llm/agents/base.rb +15 -805
  25. data/lib/ruby_llm/agents/version.rb +1 -1
  26. metadata +12 -20
  27. data/app/channels/ruby_llm/agents/executions_channel.rb +0 -46
  28. data/app/javascript/ruby_llm/agents/controllers/filter_controller.js +0 -56
  29. data/app/javascript/ruby_llm/agents/controllers/index.js +0 -12
  30. data/app/javascript/ruby_llm/agents/controllers/refresh_controller.js +0 -83
  31. data/app/views/rubyllm/agents/dashboard/_now_strip_values.html.erb +0 -71
@@ -4,6 +4,6 @@ module RubyLLM
4
4
  module Agents
5
5
  # Current version of the RubyLLM::Agents gem
6
6
  # @return [String] Semantic version string
7
- VERSION = "0.3.3"
7
+ VERSION = "0.3.4"
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm-agents
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - adham90
@@ -65,20 +65,6 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '1.0'
68
- - !ruby/object:Gem::Dependency
69
- name: chartkick
70
- requirement: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- version: '5.0'
75
- type: :runtime
76
- prerelease: false
77
- version_requirements: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- version: '5.0'
82
68
  - !ruby/object:Gem::Dependency
83
69
  name: csv
84
70
  requirement: !ruby/object:Gem::Requirement
@@ -104,7 +90,6 @@ extra_rdoc_files: []
104
90
  files:
105
91
  - LICENSE.txt
106
92
  - README.md
107
- - app/channels/ruby_llm/agents/executions_channel.rb
108
93
  - app/controllers/concerns/ruby_llm/agents/filterable.rb
109
94
  - app/controllers/concerns/ruby_llm/agents/paginatable.rb
110
95
  - app/controllers/ruby_llm/agents/agents_controller.rb
@@ -112,9 +97,6 @@ files:
112
97
  - app/controllers/ruby_llm/agents/executions_controller.rb
113
98
  - app/controllers/ruby_llm/agents/settings_controller.rb
114
99
  - app/helpers/ruby_llm/agents/application_helper.rb
115
- - app/javascript/ruby_llm/agents/controllers/filter_controller.js
116
- - app/javascript/ruby_llm/agents/controllers/index.js
117
- - app/javascript/ruby_llm/agents/controllers/refresh_controller.js
118
100
  - app/models/ruby_llm/agents/execution.rb
119
101
  - app/models/ruby_llm/agents/execution/analytics.rb
120
102
  - app/models/ruby_llm/agents/execution/metrics.rb
@@ -126,12 +108,13 @@ files:
126
108
  - app/views/rubyllm/agents/agents/index.html.erb
127
109
  - app/views/rubyllm/agents/agents/show.html.erb
128
110
  - app/views/rubyllm/agents/dashboard/_action_center.html.erb
111
+ - app/views/rubyllm/agents/dashboard/_agent_comparison.html.erb
129
112
  - app/views/rubyllm/agents/dashboard/_alerts_feed.html.erb
130
113
  - app/views/rubyllm/agents/dashboard/_breaker_strip.html.erb
131
114
  - app/views/rubyllm/agents/dashboard/_budgets_bar.html.erb
132
115
  - app/views/rubyllm/agents/dashboard/_execution_item.html.erb
133
116
  - app/views/rubyllm/agents/dashboard/_now_strip.html.erb
134
- - app/views/rubyllm/agents/dashboard/_now_strip_values.html.erb
117
+ - app/views/rubyllm/agents/dashboard/_top_errors.html.erb
135
118
  - app/views/rubyllm/agents/dashboard/index.html.erb
136
119
  - app/views/rubyllm/agents/executions/_execution.html.erb
137
120
  - app/views/rubyllm/agents/executions/_filters.html.erb
@@ -141,8 +124,10 @@ files:
141
124
  - app/views/rubyllm/agents/executions/index.turbo_stream.erb
142
125
  - app/views/rubyllm/agents/executions/show.html.erb
143
126
  - app/views/rubyllm/agents/settings/show.html.erb
127
+ - app/views/rubyllm/agents/shared/_breadcrumbs.html.erb
144
128
  - app/views/rubyllm/agents/shared/_executions_table.html.erb
145
129
  - app/views/rubyllm/agents/shared/_filter_dropdown.html.erb
130
+ - app/views/rubyllm/agents/shared/_nav_link.html.erb
146
131
  - app/views/rubyllm/agents/shared/_select_dropdown.html.erb
147
132
  - app/views/rubyllm/agents/shared/_stat_card.html.erb
148
133
  - app/views/rubyllm/agents/shared/_status_badge.html.erb
@@ -168,6 +153,13 @@ files:
168
153
  - lib/ruby_llm/agents/alert_manager.rb
169
154
  - lib/ruby_llm/agents/attempt_tracker.rb
170
155
  - lib/ruby_llm/agents/base.rb
156
+ - lib/ruby_llm/agents/base/caching.rb
157
+ - lib/ruby_llm/agents/base/cost_calculation.rb
158
+ - lib/ruby_llm/agents/base/dsl.rb
159
+ - lib/ruby_llm/agents/base/execution.rb
160
+ - lib/ruby_llm/agents/base/reliability_execution.rb
161
+ - lib/ruby_llm/agents/base/response_building.rb
162
+ - lib/ruby_llm/agents/base/tool_tracking.rb
171
163
  - lib/ruby_llm/agents/budget_tracker.rb
172
164
  - lib/ruby_llm/agents/circuit_breaker.rb
173
165
  - lib/ruby_llm/agents/configuration.rb
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RubyLLM
4
- module Agents
5
- # ActionCable channel for real-time execution updates
6
- #
7
- # Broadcasts execution create/update events to subscribed clients.
8
- # Used by the dashboard to show live execution status changes.
9
- #
10
- # Inherits from the host app's ApplicationCable::Channel (note the :: prefix
11
- # to reference the root namespace, not the engine's namespace).
12
- #
13
- # @example JavaScript subscription
14
- # import { createConsumer } from "@rails/actioncable"
15
- # const consumer = createConsumer()
16
- # consumer.subscriptions.create("RubyLLM::Agents::ExecutionsChannel", {
17
- # received(data) {
18
- # console.log("Execution update:", data)
19
- # }
20
- # })
21
- #
22
- # @see Execution#broadcast_execution Broadcast trigger
23
- # @api private
24
- class ExecutionsChannel < ::ApplicationCable::Channel
25
- # Subscribes the client to the executions broadcast stream
26
- #
27
- # Called automatically when a client connects to this channel.
28
- # Streams from the "ruby_llm_agents:executions" channel name.
29
- #
30
- # @return [void]
31
- def subscribed
32
- stream_from "ruby_llm_agents:executions"
33
- logger.info "[RubyLLM::Agents] Client subscribed to executions channel"
34
- end
35
-
36
- # Cleans up when a client disconnects
37
- #
38
- # Called automatically when the WebSocket connection is closed.
39
- #
40
- # @return [void]
41
- def unsubscribed
42
- logger.info "[RubyLLM::Agents] Client unsubscribed from executions channel"
43
- end
44
- end
45
- end
46
- end
@@ -1,56 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus"
2
-
3
- // Filter controller for live filtering of executions
4
- //
5
- // Usage:
6
- // <form data-controller="filter">
7
- // <select data-action="change->filter#submit">...</select>
8
- // </form>
9
- //
10
- export default class extends Controller {
11
- static targets = ["form"]
12
- static values = {
13
- debounce: { type: Number, default: 300 }
14
- }
15
-
16
- connect() {
17
- this.timeout = null
18
- }
19
-
20
- disconnect() {
21
- if (this.timeout) {
22
- clearTimeout(this.timeout)
23
- }
24
- }
25
-
26
- // Submit the form with debouncing
27
- submit(event) {
28
- if (this.timeout) {
29
- clearTimeout(this.timeout)
30
- }
31
-
32
- this.timeout = setTimeout(() => {
33
- this.element.requestSubmit()
34
- }, this.debounceValue)
35
- }
36
-
37
- // Submit immediately without debounce
38
- submitNow(event) {
39
- this.element.requestSubmit()
40
- }
41
-
42
- // Update URL with current filter state
43
- updateUrl() {
44
- const formData = new FormData(this.element)
45
- const params = new URLSearchParams()
46
-
47
- for (const [key, value] of formData) {
48
- if (value) {
49
- params.set(key, value)
50
- }
51
- }
52
-
53
- const newUrl = `${window.location.pathname}?${params.toString()}`
54
- window.history.pushState({}, "", newUrl)
55
- }
56
- }
@@ -1,12 +0,0 @@
1
- // Entry point for RubyLLM::Agents Stimulus controllers
2
- // Import and register controllers with your Stimulus application
3
-
4
- import FilterController from "./filter_controller"
5
- import RefreshController from "./refresh_controller"
6
-
7
- export { FilterController, RefreshController }
8
-
9
- export function registerControllers(application) {
10
- application.register("filter", FilterController)
11
- application.register("refresh", RefreshController)
12
- }
@@ -1,83 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus"
2
-
3
- // Auto-refresh controller for dashboard with toggle support
4
- //
5
- // Usage:
6
- // <div data-controller="refresh"
7
- // data-refresh-interval-value="30000"
8
- // data-refresh-enabled-value="false">
9
- // <button data-action="refresh#toggle" data-refresh-target="button">
10
- // Live Poll: Off
11
- // </button>
12
- // </div>
13
- //
14
- export default class extends Controller {
15
- static values = {
16
- interval: { type: Number, default: 30000 },
17
- enabled: { type: Boolean, default: false }
18
- }
19
-
20
- static targets = ["button", "indicator"]
21
-
22
- connect() {
23
- this.updateUI()
24
- if (this.enabledValue) {
25
- this.startRefresh()
26
- }
27
- }
28
-
29
- disconnect() {
30
- this.stopRefresh()
31
- }
32
-
33
- toggle() {
34
- this.enabledValue = !this.enabledValue
35
-
36
- if (this.enabledValue) {
37
- this.startRefresh()
38
- this.refresh() // Immediate refresh when enabled
39
- } else {
40
- this.stopRefresh()
41
- }
42
-
43
- this.updateUI()
44
- }
45
-
46
- startRefresh() {
47
- if (this.intervalValue > 0 && !this.timer) {
48
- this.timer = setInterval(() => this.refresh(), this.intervalValue)
49
- }
50
- }
51
-
52
- stopRefresh() {
53
- if (this.timer) {
54
- clearInterval(this.timer)
55
- this.timer = null
56
- }
57
- }
58
-
59
- refresh() {
60
- const frame = this.element.closest("turbo-frame") ||
61
- this.element.querySelector("turbo-frame")
62
-
63
- if (frame && typeof frame.reload === "function") {
64
- frame.reload()
65
- }
66
- }
67
-
68
- updateUI() {
69
- if (this.hasButtonTarget) {
70
- if (this.enabledValue) {
71
- this.buttonTarget.classList.remove("bg-gray-100", "text-gray-600")
72
- this.buttonTarget.classList.add("bg-green-100", "text-green-700")
73
- } else {
74
- this.buttonTarget.classList.remove("bg-green-100", "text-green-700")
75
- this.buttonTarget.classList.add("bg-gray-100", "text-gray-600")
76
- }
77
- }
78
-
79
- if (this.hasIndicatorTarget) {
80
- this.indicatorTarget.textContent = this.enabledValue ? "On" : "Off"
81
- }
82
- }
83
- }
@@ -1,71 +0,0 @@
1
- <div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
2
- <!-- Running -->
3
- <div class="flex items-center bg-white dark:bg-gray-800 rounded-lg px-4 py-3 shadow-sm border border-gray-100 dark:border-gray-700">
4
- <div class="flex-shrink-0 w-8 h-8 bg-blue-100 dark:bg-blue-900 rounded-full flex items-center justify-center mr-3">
5
- <span class="w-2.5 h-2.5 bg-blue-500 rounded-full animate-pulse"></span>
6
- </div>
7
- <div>
8
- <p id="now-running" class="text-lg font-bold text-gray-900 dark:text-gray-100"><%= now_strip[:running] %></p>
9
- <p class="text-xs text-gray-500 dark:text-gray-400">Running</p>
10
- </div>
11
- </div>
12
-
13
- <!-- Success Today -->
14
- <div class="flex items-center bg-white dark:bg-gray-800 rounded-lg px-4 py-3 shadow-sm border border-gray-100 dark:border-gray-700">
15
- <div class="flex-shrink-0 w-8 h-8 bg-green-100 dark:bg-green-900 rounded-full flex items-center justify-center mr-3">
16
- <span class="w-2.5 h-2.5 bg-green-500 rounded-full"></span>
17
- </div>
18
- <div>
19
- <p id="now-success" class="text-lg font-bold text-green-600 dark:text-green-400"><%= now_strip[:success_today] %></p>
20
- <p class="text-xs text-gray-500 dark:text-gray-400">Success</p>
21
- </div>
22
- </div>
23
-
24
- <!-- Errors Today -->
25
- <div class="flex items-center bg-white dark:bg-gray-800 rounded-lg px-4 py-3 shadow-sm border border-gray-100 dark:border-gray-700">
26
- <div class="flex-shrink-0 w-8 h-8 <%= now_strip[:errors_today] > 0 ? 'bg-red-100 dark:bg-red-900' : 'bg-gray-100 dark:bg-gray-700' %> rounded-full flex items-center justify-center mr-3">
27
- <span class="w-2.5 h-2.5 <%= now_strip[:errors_today] > 0 ? 'bg-red-500' : 'bg-gray-400' %> rounded-full"></span>
28
- </div>
29
- <div>
30
- <p id="now-errors" class="text-lg font-bold <%= now_strip[:errors_today] > 0 ? 'text-red-600 dark:text-red-400' : 'text-gray-900 dark:text-gray-100' %>"><%= now_strip[:errors_today] %></p>
31
- <p class="text-xs text-gray-500 dark:text-gray-400">Errors</p>
32
- </div>
33
- </div>
34
-
35
- <!-- Timeouts Today -->
36
- <div class="flex items-center bg-white dark:bg-gray-800 rounded-lg px-4 py-3 shadow-sm border border-gray-100 dark:border-gray-700">
37
- <div class="flex-shrink-0 w-8 h-8 <%= now_strip[:timeouts_today] > 0 ? 'bg-yellow-100 dark:bg-yellow-900' : 'bg-gray-100 dark:bg-gray-700' %> rounded-full flex items-center justify-center mr-3">
38
- <span class="w-2.5 h-2.5 <%= now_strip[:timeouts_today] > 0 ? 'bg-yellow-500' : 'bg-gray-400' %> rounded-full"></span>
39
- </div>
40
- <div>
41
- <p id="now-timeouts" class="text-lg font-bold <%= now_strip[:timeouts_today] > 0 ? 'text-yellow-600 dark:text-yellow-400' : 'text-gray-900 dark:text-gray-100' %>"><%= now_strip[:timeouts_today] %></p>
42
- <p class="text-xs text-gray-500 dark:text-gray-400">Timeouts</p>
43
- </div>
44
- </div>
45
-
46
- <!-- Cost Today -->
47
- <div class="flex items-center bg-white dark:bg-gray-800 rounded-lg px-4 py-3 shadow-sm border border-gray-100 dark:border-gray-700">
48
- <div class="flex-shrink-0 w-8 h-8 bg-amber-100 dark:bg-amber-900 rounded-full flex items-center justify-center mr-3">
49
- <svg class="w-4 h-4 text-amber-600 dark:text-amber-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
50
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
51
- </svg>
52
- </div>
53
- <div>
54
- <p id="now-cost-today" class="text-lg font-bold text-gray-900 dark:text-gray-100">$<%= number_with_precision(now_strip[:cost_today], precision: 4) %></p>
55
- <p class="text-xs text-gray-500 dark:text-gray-400">Cost Today</p>
56
- </div>
57
- </div>
58
-
59
- <!-- Success Rate -->
60
- <div class="flex items-center bg-white dark:bg-gray-800 rounded-lg px-4 py-3 shadow-sm border border-gray-100 dark:border-gray-700">
61
- <div class="flex-shrink-0 w-8 h-8 bg-green-100 dark:bg-green-900 rounded-full flex items-center justify-center mr-3">
62
- <svg class="w-4 h-4 text-green-600 dark:text-green-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
63
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
64
- </svg>
65
- </div>
66
- <div>
67
- <p id="now-success-rate" class="text-lg font-bold text-gray-900 dark:text-gray-100"><%= now_strip[:success_rate] %>%</p>
68
- <p class="text-xs text-gray-500 dark:text-gray-400">Success Rate</p>
69
- </div>
70
- </div>
71
- </div>