ruby_llm-agents 3.15.0 → 3.16.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/ruby_llm/agents/paginatable.rb +29 -8
  3. data/app/controllers/ruby_llm/agents/agents_controller.rb +48 -44
  4. data/app/controllers/ruby_llm/agents/analytics_controller.rb +38 -72
  5. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +69 -56
  6. data/app/controllers/ruby_llm/agents/executions_controller.rb +25 -41
  7. data/app/controllers/ruby_llm/agents/requests_controller.rb +117 -45
  8. data/app/controllers/ruby_llm/agents/tenants_controller.rb +67 -47
  9. data/app/models/ruby_llm/agents/execution/analytics.rb +174 -133
  10. data/app/models/ruby_llm/agents/execution/breakdown.rb +243 -0
  11. data/app/models/ruby_llm/agents/execution/scopes.rb +39 -3
  12. data/app/models/ruby_llm/agents/execution.rb +23 -5
  13. data/app/services/ruby_llm/agents/agent_registry.rb +75 -12
  14. data/app/views/ruby_llm/agents/agents/index.html.erb +24 -7
  15. data/app/views/ruby_llm/agents/agents/show.html.erb +3 -2
  16. data/app/views/ruby_llm/agents/executions/_filters.html.erb +12 -7
  17. data/app/views/ruby_llm/agents/executions/_list.html.erb +1 -52
  18. data/app/views/ruby_llm/agents/requests/index.html.erb +8 -57
  19. data/app/views/ruby_llm/agents/shared/_executions_table.html.erb +1 -52
  20. data/app/views/ruby_llm/agents/shared/_pagination.html.erb +66 -0
  21. data/app/views/ruby_llm/agents/shared/query_timeout.html.erb +18 -0
  22. data/app/views/ruby_llm/agents/system_config/show.html.erb +4 -0
  23. data/app/views/ruby_llm/agents/tenants/index.html.erb +1 -1
  24. data/app/views/ruby_llm/agents/tenants/show.html.erb +6 -5
  25. data/config/routes.rb +2 -2
  26. data/lib/generators/ruby_llm_agents/templates/add_executions_analytics_index_migration.rb.tt +50 -0
  27. data/lib/generators/ruby_llm_agents/templates/add_root_execution_list_index_migration.rb.tt +16 -0
  28. data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +5 -0
  29. data/lib/generators/ruby_llm_agents/templates/migration.rb.tt +26 -0
  30. data/lib/generators/ruby_llm_agents/upgrade_generator.rb +44 -0
  31. data/lib/ruby_llm/agents/audio/transcriber.rb +7 -121
  32. data/lib/ruby_llm/agents/core/configuration.rb +20 -0
  33. data/lib/ruby_llm/agents/core/version.rb +1 -1
  34. data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +39 -1
  35. data/lib/ruby_llm/agents/rails/engine.rb +87 -7
  36. metadata +7 -2
@@ -53,6 +53,7 @@ module RubyLLM
53
53
  layout "ruby_llm/agents/application"
54
54
  helper RubyLLM::Agents::ApplicationHelper
55
55
  before_action :authenticate_dashboard!
56
+ around_action :limit_query_time, if: -> { request.get? }
56
57
 
57
58
  rescue_from ::ActiveRecord::StatementInvalid do |e|
58
59
  if e.message.include?("ruby_llm_agents_")
@@ -65,8 +66,54 @@ module RubyLLM
65
66
  end
66
67
  end
67
68
 
69
+ # Declared after the StatementInvalid handler so it wins: a cancelled
70
+ # query is a StatementInvalid too, and must not be reported as a
71
+ # pending migration.
72
+ rescue_from ::ActiveRecord::QueryCanceled do
73
+ @query_timeout = RubyLLM::Agents.configuration.dashboard_query_timeout
74
+
75
+ if request.format.json?
76
+ render json: {error: "query_timeout"}, status: :service_unavailable
77
+ else
78
+ render "ruby_llm/agents/shared/query_timeout", formats: [:html], status: :service_unavailable
79
+ end
80
+ end
81
+
68
82
  private
69
83
 
84
+ # Runs the page under config.dashboard_query_timeout
85
+ #
86
+ # Every dashboard page aggregates over a user-chosen window of the
87
+ # executions table. Without a ceiling, a wide window on a large
88
+ # table keeps running after the web server has timed the request
89
+ # out — the user sees a 500 and the database keeps scanning. With
90
+ # it, the database cancels the query and the QueryCanceled handler
91
+ # above explains what to narrow.
92
+ #
93
+ # @return [void]
94
+ # @api private
95
+ def limit_query_time(&block)
96
+ RubyLLM::Agents::Execution.with_statement_timeout(
97
+ RubyLLM::Agents.configuration.dashboard_query_timeout, &block
98
+ )
99
+ end
100
+
101
+ # Caches an expensive dashboard aggregate for a short while
102
+ #
103
+ # Dashboard figures are read far more often than they meaningfully
104
+ # change (reloads, pagination, several people watching the same
105
+ # page), and each one is a scan of a time window. The current
106
+ # tenant is always part of the key.
107
+ #
108
+ # @param key [Array] Identifies the figure and its filters
109
+ # @param expires_in [ActiveSupport::Duration] How stale it may get
110
+ # @return [Object] The block's value (nil is cached too)
111
+ # @api private
112
+ def cached_stats(*key, expires_in: 1.minute, &block)
113
+ Rails.cache.fetch(["ruby_llm_agents", "stats", current_tenant_id, *key],
114
+ expires_in: expires_in, race_condition_ttl: 10.seconds, &block)
115
+ end
116
+
70
117
  # Authenticates dashboard access using configured method
71
118
  #
72
119
  # Authentication priority:
@@ -160,18 +207,12 @@ module RubyLLM
160
207
  # configured name; legacy or string-only tenants fall back to the raw
161
208
  # tenant_id so nothing disappears from the filter.
162
209
  #
163
- # Two queries total — one DISTINCT pluck on executions, one pluck on
164
- # tenants — regardless of how many tenant_ids exist.
165
- #
166
210
  # @return [Array<Hash>] Entries shaped as { value:, label: }
167
211
  # @api public
168
212
  def available_tenants
169
213
  return @available_tenants if defined?(@available_tenants)
170
214
 
171
- tenant_ids = RubyLLM::Agents::Execution
172
- .where.not(tenant_id: nil)
173
- .distinct
174
- .pluck(:tenant_id)
215
+ tenant_ids = cached_filter_options(:tenant_id)
175
216
 
176
217
  names_by_id = RubyLLM::Agents::Tenant
177
218
  .where(tenant_id: tenant_ids)
@@ -183,6 +224,45 @@ module RubyLLM
183
224
  .sort_by { |t| t[:label].downcase }
184
225
  end
185
226
  helper_method :available_tenants
227
+
228
+ # Distinct agent types in the execution history, sorted
229
+ #
230
+ # @return [Array<String>]
231
+ # @api public
232
+ def available_agent_types
233
+ cached_filter_options(:agent_type)
234
+ end
235
+
236
+ # Distinct model IDs in the execution history, sorted
237
+ #
238
+ # @return [Array<String>]
239
+ # @api public
240
+ def available_model_ids
241
+ cached_filter_options(:model_id)
242
+ end
243
+
244
+ # Distinct values of an executions column, for a filter dropdown
245
+ #
246
+ # Read with Execution.distinct_values, which walks the column's
247
+ # index rather than scanning the table, and cached on top of that:
248
+ # the lists only change when a brand-new agent, model or tenant
249
+ # appears, and several pages need two or three of them per request.
250
+ # A new value shows up in the dropdown within five minutes;
251
+ # filtering by it via URL params works immediately.
252
+ #
253
+ # The lists are deliberately not narrowed to the current tenant.
254
+ # Doing so means reading every one of that tenant's executions, and
255
+ # agent and model names are application configuration rather than
256
+ # tenant data.
257
+ #
258
+ # @param column [Symbol] :agent_type, :model_id or :tenant_id
259
+ # @return [Array<String>]
260
+ # @api private
261
+ def cached_filter_options(column)
262
+ Rails.cache.fetch(["ruby_llm_agents", "filter_options", column], expires_in: 5.minutes) do
263
+ RubyLLM::Agents::Execution.distinct_values(column)
264
+ end
265
+ end
186
266
  end)
187
267
  end
188
268
 
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: 3.15.0
4
+ version: 3.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - adham90
@@ -90,6 +90,7 @@ files:
90
90
  - app/models/ruby_llm/agents/agent_override.rb
91
91
  - app/models/ruby_llm/agents/execution.rb
92
92
  - app/models/ruby_llm/agents/execution/analytics.rb
93
+ - app/models/ruby_llm/agents/execution/breakdown.rb
93
94
  - app/models/ruby_llm/agents/execution/metrics.rb
94
95
  - app/models/ruby_llm/agents/execution/replayable.rb
95
96
  - app/models/ruby_llm/agents/execution/scopes.rb
@@ -131,11 +132,13 @@ files:
131
132
  - app/views/ruby_llm/agents/shared/_doc_link.html.erb
132
133
  - app/views/ruby_llm/agents/shared/_executions_table.html.erb
133
134
  - app/views/ruby_llm/agents/shared/_filter_dropdown.html.erb
135
+ - app/views/ruby_llm/agents/shared/_pagination.html.erb
134
136
  - app/views/ruby_llm/agents/shared/_select_dropdown.html.erb
135
137
  - app/views/ruby_llm/agents/shared/_sortable_header.html.erb
136
138
  - app/views/ruby_llm/agents/shared/_status_badge.html.erb
137
139
  - app/views/ruby_llm/agents/shared/_status_dot.html.erb
138
140
  - app/views/ruby_llm/agents/shared/_tenant_filter.html.erb
141
+ - app/views/ruby_llm/agents/shared/query_timeout.html.erb
139
142
  - app/views/ruby_llm/agents/system_config/show.html.erb
140
143
  - app/views/ruby_llm/agents/tenants/_form.html.erb
141
144
  - app/views/ruby_llm/agents/tenants/edit.html.erb
@@ -165,8 +168,10 @@ files:
165
168
  - lib/generators/ruby_llm_agents/templates/add_caching_migration.rb.tt
166
169
  - lib/generators/ruby_llm_agents/templates/add_dashboard_performance_indexes_migration.rb.tt
167
170
  - lib/generators/ruby_llm_agents/templates/add_execution_type_migration.rb.tt
171
+ - lib/generators/ruby_llm_agents/templates/add_executions_analytics_index_migration.rb.tt
168
172
  - lib/generators/ruby_llm_agents/templates/add_finish_reason_migration.rb.tt
169
173
  - lib/generators/ruby_llm_agents/templates/add_prompts_migration.rb.tt
174
+ - lib/generators/ruby_llm_agents/templates/add_root_execution_list_index_migration.rb.tt
170
175
  - lib/generators/ruby_llm_agents/templates/add_routing_migration.rb.tt
171
176
  - lib/generators/ruby_llm_agents/templates/add_streaming_migration.rb.tt
172
177
  - lib/generators/ruby_llm_agents/templates/add_tenant_to_executions_migration.rb.tt
@@ -359,7 +364,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
359
364
  - !ruby/object:Gem::Version
360
365
  version: '0'
361
366
  requirements: []
362
- rubygems_version: 4.0.7
367
+ rubygems_version: 3.6.9
363
368
  specification_version: 4
364
369
  summary: Agent framework for building LLM-powered agents with RubyLLM
365
370
  test_files: []