ruby_llm-agents 0.4.0 → 0.5.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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +46 -13
  3. data/app/controllers/ruby_llm/agents/api_configurations_controller.rb +214 -0
  4. data/app/controllers/ruby_llm/agents/{settings_controller.rb → system_config_controller.rb} +3 -3
  5. data/app/controllers/ruby_llm/agents/tenants_controller.rb +109 -0
  6. data/app/models/ruby_llm/agents/api_configuration.rb +386 -0
  7. data/app/models/ruby_llm/agents/tenant_budget.rb +62 -7
  8. data/app/views/layouts/ruby_llm/agents/application.html.erb +3 -1
  9. data/app/views/ruby_llm/agents/api_configurations/_api_key_field.html.erb +34 -0
  10. data/app/views/ruby_llm/agents/api_configurations/_form.html.erb +288 -0
  11. data/app/views/ruby_llm/agents/api_configurations/edit.html.erb +95 -0
  12. data/app/views/ruby_llm/agents/api_configurations/edit_tenant.html.erb +97 -0
  13. data/app/views/ruby_llm/agents/api_configurations/show.html.erb +211 -0
  14. data/app/views/ruby_llm/agents/api_configurations/tenant.html.erb +179 -0
  15. data/app/views/ruby_llm/agents/dashboard/_action_center.html.erb +1 -1
  16. data/app/views/ruby_llm/agents/executions/show.html.erb +82 -0
  17. data/app/views/ruby_llm/agents/{settings → system_config}/show.html.erb +1 -1
  18. data/app/views/ruby_llm/agents/tenants/_form.html.erb +150 -0
  19. data/app/views/ruby_llm/agents/tenants/edit.html.erb +13 -0
  20. data/app/views/ruby_llm/agents/tenants/index.html.erb +129 -0
  21. data/app/views/ruby_llm/agents/tenants/show.html.erb +374 -0
  22. data/config/routes.rb +12 -1
  23. data/lib/generators/ruby_llm_agents/api_configuration_generator.rb +100 -0
  24. data/lib/generators/ruby_llm_agents/templates/create_api_configurations_migration.rb.tt +90 -0
  25. data/lib/ruby_llm/agents/base/execution.rb +83 -0
  26. data/lib/ruby_llm/agents/base.rb +1 -0
  27. data/lib/ruby_llm/agents/budget_tracker.rb +285 -23
  28. data/lib/ruby_llm/agents/configuration.rb +38 -1
  29. data/lib/ruby_llm/agents/engine.rb +1 -0
  30. data/lib/ruby_llm/agents/instrumentation.rb +71 -3
  31. data/lib/ruby_llm/agents/resolved_config.rb +348 -0
  32. data/lib/ruby_llm/agents/version.rb +1 -1
  33. metadata +19 -3
@@ -245,7 +245,9 @@ module RubyLLM
245
245
  metadata: metadata,
246
246
  system_prompt: config.persist_prompts ? redacted_system_prompt : nil,
247
247
  user_prompt: config.persist_prompts ? redacted_user_prompt : nil,
248
- streaming: self.class.streaming
248
+ streaming: self.class.streaming,
249
+ messages_count: resolved_messages.size,
250
+ messages_summary: config.persist_messages_summary ? messages_summary : {}
249
251
  }
250
252
 
251
253
  # Extract tracing fields from metadata if present
@@ -326,6 +328,9 @@ module RubyLLM
326
328
  Rails.logger.warn("[RubyLLM::Agents] Cost calculation failed: #{cost_error.message}")
327
329
  end
328
330
  end
331
+
332
+ # Record token usage for budget tracking
333
+ record_token_usage(execution)
329
334
  rescue ActiveRecord::RecordInvalid => e
330
335
  Rails.logger.error("[RubyLLM::Agents] Validation failed for execution #{execution&.id}: #{e.record.errors.full_messages.join(', ')}")
331
336
  if Rails.env.development? || Rails.env.test?
@@ -415,6 +420,9 @@ module RubyLLM
415
420
  Rails.logger.warn("[RubyLLM::Agents] Cost calculation failed: #{cost_error.message}")
416
421
  end
417
422
  end
423
+
424
+ # Record token usage for budget tracking
425
+ record_token_usage(execution)
418
426
  rescue ActiveRecord::RecordInvalid => e
419
427
  Rails.logger.error("[RubyLLM::Agents] Validation failed for execution #{execution&.id}: #{e.record.errors.full_messages.join(', ')}")
420
428
  if Rails.env.development? || Rails.env.test?
@@ -440,6 +448,8 @@ module RubyLLM
440
448
  # @param error [Exception, nil] The exception if failed
441
449
  # @return [void]
442
450
  def legacy_log_execution(completed_at:, status:, response: nil, error: nil)
451
+ config = RubyLLM::Agents.configuration
452
+
443
453
  execution_data = {
444
454
  agent_type: self.class.name,
445
455
  agent_version: self.class.version,
@@ -452,7 +462,9 @@ module RubyLLM
452
462
  parameters: sanitized_parameters,
453
463
  metadata: execution_metadata,
454
464
  system_prompt: safe_system_prompt,
455
- user_prompt: safe_user_prompt
465
+ user_prompt: safe_user_prompt,
466
+ messages_count: resolved_messages.size,
467
+ messages_summary: config.persist_messages_summary ? messages_summary : {}
456
468
  }
457
469
 
458
470
  # Add response data if available (using safe extraction)
@@ -516,6 +528,38 @@ module RubyLLM
516
528
  Redactor.redact_string(prompt)
517
529
  end
518
530
 
531
+ # Returns a summary of messages (first and last, truncated)
532
+ #
533
+ # Creates a summary of the conversation messages containing the first
534
+ # and last messages (if different) with content truncated for storage.
535
+ #
536
+ # @return [Hash] Summary with :first and :last message hashes, or empty hash
537
+ def messages_summary
538
+ msgs = resolved_messages
539
+ return {} if msgs.blank?
540
+
541
+ max_len = RubyLLM::Agents.configuration.messages_summary_max_length || 500
542
+
543
+ summary = {}
544
+
545
+ if msgs.first
546
+ summary[:first] = {
547
+ role: msgs.first[:role].to_s,
548
+ content: Redactor.redact_string(msgs.first[:content].to_s).truncate(max_len)
549
+ }
550
+ end
551
+
552
+ # Only add last if there are multiple messages and last is different from first
553
+ if msgs.size > 1 && msgs.last
554
+ summary[:last] = {
555
+ role: msgs.last[:role].to_s,
556
+ content: Redactor.redact_string(msgs.last[:content].to_s).truncate(max_len)
557
+ }
558
+ end
559
+
560
+ summary
561
+ end
562
+
519
563
  # Returns the response with redaction applied
520
564
  #
521
565
  # @param response [RubyLLM::Message] The LLM response
@@ -773,7 +817,9 @@ module RubyLLM
773
817
  total_cost: 0,
774
818
  parameters: redacted_parameters,
775
819
  metadata: execution_metadata,
776
- streaming: self.class.streaming
820
+ streaming: self.class.streaming,
821
+ messages_count: resolved_messages.size,
822
+ messages_summary: config.persist_messages_summary ? messages_summary : {}
777
823
  }
778
824
 
779
825
  # Add tracing fields from metadata if present
@@ -798,6 +844,28 @@ module RubyLLM
798
844
  Rails.logger.error("[RubyLLM::Agents] Failed to record cache hit execution: #{e.message}")
799
845
  end
800
846
 
847
+ # Records token usage to the BudgetTracker
848
+ #
849
+ # @param execution [Execution] The completed execution record
850
+ # @return [void]
851
+ def record_token_usage(execution)
852
+ return unless execution&.total_tokens && execution.total_tokens > 0
853
+
854
+ begin
855
+ tenant_id = respond_to?(:resolved_tenant_id) ? resolved_tenant_id : nil
856
+ tenant_config = respond_to?(:runtime_tenant_config) ? runtime_tenant_config : nil
857
+
858
+ BudgetTracker.record_tokens!(
859
+ self.class.name,
860
+ execution.total_tokens,
861
+ tenant_id: tenant_id,
862
+ tenant_config: tenant_config
863
+ )
864
+ rescue StandardError => e
865
+ Rails.logger.warn("[RubyLLM::Agents] Failed to record token usage: #{e.message}")
866
+ end
867
+ end
868
+
801
869
  # Emergency fallback to mark execution as failed
802
870
  #
803
871
  # Uses update_all to bypass ActiveRecord callbacks and validations,
@@ -0,0 +1,348 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Agents
5
+ # Resolves API configuration with priority chain
6
+ #
7
+ # Resolution order:
8
+ # 1. Tenant-specific database config (if tenant_id provided)
9
+ # 2. Global database config
10
+ # 3. RubyLLM.configuration (set via initializer or environment)
11
+ #
12
+ # This class provides a unified interface for accessing configuration
13
+ # values regardless of their source, and can apply the resolved
14
+ # configuration to RubyLLM.
15
+ #
16
+ # @example Basic resolution
17
+ # resolved = ResolvedConfig.new(
18
+ # tenant_config: ApiConfiguration.for_tenant("acme"),
19
+ # global_config: ApiConfiguration.global,
20
+ # ruby_llm_config: RubyLLM.configuration
21
+ # )
22
+ #
23
+ # resolved.openai_api_key # => Returns from highest priority source
24
+ # resolved.source_for(:openai_api_key) # => "tenant:acme"
25
+ #
26
+ # @example Applying to RubyLLM
27
+ # resolved.apply_to_ruby_llm! # Applies all resolved values
28
+ #
29
+ # @see ApiConfiguration
30
+ # @api public
31
+ class ResolvedConfig
32
+ # Returns all resolvable attributes (API keys + settings)
33
+ # Lazy-loaded to avoid circular dependency with ApiConfiguration
34
+ #
35
+ # @return [Array<Symbol>]
36
+ def self.resolvable_attributes
37
+ @resolvable_attributes ||= (
38
+ ApiConfiguration::API_KEY_ATTRIBUTES +
39
+ ApiConfiguration::NON_KEY_ATTRIBUTES
40
+ ).freeze
41
+ end
42
+
43
+ # @return [ApiConfiguration, nil] Tenant-specific configuration
44
+ attr_reader :tenant_config
45
+
46
+ # @return [ApiConfiguration, nil] Global database configuration
47
+ attr_reader :global_config
48
+
49
+ # @return [Object] RubyLLM configuration object
50
+ attr_reader :ruby_llm_config
51
+
52
+ # Creates a new resolved configuration
53
+ #
54
+ # @param tenant_config [ApiConfiguration, nil] Tenant-specific config
55
+ # @param global_config [ApiConfiguration, nil] Global database config
56
+ # @param ruby_llm_config [Object] RubyLLM.configuration
57
+ def initialize(tenant_config:, global_config:, ruby_llm_config:)
58
+ @tenant_config = tenant_config
59
+ @global_config = global_config
60
+ @ruby_llm_config = ruby_llm_config
61
+ @resolved_cache = {}
62
+ end
63
+
64
+ # Resolves a specific attribute value using the priority chain
65
+ #
66
+ # @param attr_name [Symbol, String] The attribute name
67
+ # @return [Object, nil] The resolved value
68
+ def resolve(attr_name)
69
+ attr_sym = attr_name.to_sym
70
+ return @resolved_cache[attr_sym] if @resolved_cache.key?(attr_sym)
71
+
72
+ @resolved_cache[attr_sym] = resolve_attribute(attr_sym)
73
+ end
74
+
75
+ # Returns the source of a resolved attribute value
76
+ #
77
+ # @param attr_name [Symbol, String] The attribute name
78
+ # @return [String] Source label: "tenant:ID", "global_db", "ruby_llm_config", or "not_set"
79
+ def source_for(attr_name)
80
+ attr_sym = attr_name.to_sym
81
+
82
+ # Check tenant config first (if present and inherits or has value)
83
+ if tenant_config&.has_value?(attr_sym)
84
+ return "tenant:#{tenant_config.scope_id}"
85
+ end
86
+
87
+ # Check global DB config (only if tenant inherits or no tenant)
88
+ if should_check_global?(attr_sym) && global_config&.has_value?(attr_sym)
89
+ return "global_db"
90
+ end
91
+
92
+ # Check RubyLLM config
93
+ if ruby_llm_value_present?(attr_sym)
94
+ return "ruby_llm_config"
95
+ end
96
+
97
+ "not_set"
98
+ end
99
+
100
+ # Returns all resolved values as a hash
101
+ #
102
+ # @return [Hash] All resolved configuration values
103
+ def to_hash
104
+ self.class.resolvable_attributes.each_with_object({}) do |attr, hash|
105
+ value = resolve(attr)
106
+ hash[attr] = value if value.present?
107
+ end
108
+ end
109
+
110
+ # Returns a hash suitable for RubyLLM configuration
111
+ #
112
+ # Only includes values that differ from or override the current
113
+ # RubyLLM configuration.
114
+ #
115
+ # @return [Hash] Configuration hash for RubyLLM
116
+ def to_ruby_llm_options
117
+ to_hash.slice(*ruby_llm_configurable_attributes)
118
+ end
119
+
120
+ # Applies the resolved configuration to RubyLLM
121
+ #
122
+ # This temporarily overrides RubyLLM.configuration with the
123
+ # resolved values. Useful for per-request configuration.
124
+ #
125
+ # @return [void]
126
+ def apply_to_ruby_llm!
127
+ options = to_ruby_llm_options
128
+ return if options.empty?
129
+
130
+ RubyLLM.configure do |config|
131
+ options.each do |key, value|
132
+ setter = "#{key}="
133
+ config.public_send(setter, value) if config.respond_to?(setter)
134
+ end
135
+ end
136
+ end
137
+
138
+ # Dynamic accessor for resolvable attributes
139
+ # Uses method_missing to provide accessors without eager loading constants
140
+ #
141
+ # @param method_name [Symbol] The method being called
142
+ # @param args [Array] Method arguments
143
+ # @return [Object] The resolved value for the attribute
144
+ def method_missing(method_name, *args)
145
+ if self.class.resolvable_attributes.include?(method_name)
146
+ resolve(method_name)
147
+ else
148
+ super
149
+ end
150
+ end
151
+
152
+ # Indicates which dynamic methods are supported
153
+ #
154
+ # @param method_name [Symbol] The method name to check
155
+ # @param include_private [Boolean] Whether to include private methods
156
+ # @return [Boolean] True if the method is a resolvable attribute
157
+ def respond_to_missing?(method_name, include_private = false)
158
+ self.class.resolvable_attributes.include?(method_name) || super
159
+ end
160
+
161
+ # Returns provider status with source information
162
+ #
163
+ # @return [Array<Hash>] Provider status with source info
164
+ def provider_statuses_with_source
165
+ ApiConfiguration::PROVIDERS.map do |key, info|
166
+ key_attr = info[:key_attr]
167
+ value = resolve(key_attr)
168
+
169
+ {
170
+ key: key,
171
+ name: info[:name],
172
+ configured: value.present?,
173
+ masked_key: value.present? ? mask_string(value) : nil,
174
+ source: source_for(key_attr),
175
+ capabilities: info[:capabilities]
176
+ }
177
+ end
178
+ end
179
+
180
+ # Checks if any database configuration exists
181
+ #
182
+ # @return [Boolean]
183
+ def has_db_config?
184
+ tenant_config.present? || global_config.present?
185
+ end
186
+
187
+ # Returns summary of configuration sources
188
+ #
189
+ # @return [Hash] Summary with counts per source
190
+ def source_summary
191
+ summary = Hash.new(0)
192
+
193
+ self.class.resolvable_attributes.each do |attr|
194
+ source = source_for(attr)
195
+ summary[source] += 1 if resolve(attr).present?
196
+ end
197
+
198
+ summary
199
+ end
200
+
201
+ # Public method to get raw RubyLLM config value for an attribute
202
+ # This returns the value from RubyLLM.configuration (initializer/ENV)
203
+ # regardless of any database overrides.
204
+ #
205
+ # @param attr_name [Symbol, String] The attribute name
206
+ # @return [Object, nil] The RubyLLM config value
207
+ def ruby_llm_value_for(attr_name)
208
+ ruby_llm_value(attr_name.to_sym)
209
+ end
210
+
211
+ # Masks a string for display (public wrapper)
212
+ #
213
+ # @param value [String] The string to mask
214
+ # @return [String] Masked string
215
+ def mask_string(value)
216
+ return nil if value.blank?
217
+ return "****" if value.length <= 8
218
+
219
+ "#{value[0..1]}****#{value[-4..]}"
220
+ end
221
+
222
+ private
223
+
224
+ # Resolves a single attribute using the priority chain
225
+ #
226
+ # @param attr_sym [Symbol] The attribute name
227
+ # @return [Object, nil] The resolved value
228
+ def resolve_attribute(attr_sym)
229
+ # 1. Check tenant config
230
+ if tenant_config&.has_value?(attr_sym)
231
+ return tenant_config.send(attr_sym)
232
+ end
233
+
234
+ # 2. Check global DB config (if tenant allows inheritance or no tenant)
235
+ if should_check_global?(attr_sym)
236
+ if global_config&.has_value?(attr_sym)
237
+ return global_config.send(attr_sym)
238
+ end
239
+ end
240
+
241
+ # 3. Fall back to RubyLLM config
242
+ ruby_llm_value(attr_sym)
243
+ end
244
+
245
+ # Determines if we should check global config
246
+ #
247
+ # @param attr_sym [Symbol] The attribute name
248
+ # @return [Boolean]
249
+ def should_check_global?(attr_sym)
250
+ return true unless tenant_config
251
+
252
+ # If tenant has inherit_global_defaults enabled, check global
253
+ tenant_config.inherit_global_defaults != false
254
+ end
255
+
256
+ # Gets a value from RubyLLM configuration
257
+ #
258
+ # @param attr_sym [Symbol] The attribute name
259
+ # @return [Object, nil]
260
+ def ruby_llm_value(attr_sym)
261
+ return nil unless ruby_llm_config
262
+
263
+ # Map our attribute names to RubyLLM config method names
264
+ method_name = ruby_llm_config_mapping(attr_sym)
265
+ return nil unless method_name
266
+
267
+ if ruby_llm_config.respond_to?(method_name)
268
+ ruby_llm_config.send(method_name)
269
+ end
270
+ rescue StandardError
271
+ nil
272
+ end
273
+
274
+ # Checks if a RubyLLM config value is present
275
+ #
276
+ # @param attr_sym [Symbol] The attribute name
277
+ # @return [Boolean]
278
+ def ruby_llm_value_present?(attr_sym)
279
+ value = ruby_llm_value(attr_sym)
280
+ value.present?
281
+ end
282
+
283
+ # Maps our attribute names to RubyLLM configuration method names
284
+ #
285
+ # @param attr_sym [Symbol] Our attribute name
286
+ # @return [Symbol, nil] RubyLLM config method name
287
+ def ruby_llm_config_mapping(attr_sym)
288
+ # Most attributes map directly
289
+ mapping = {
290
+ openai_api_key: :openai_api_key,
291
+ anthropic_api_key: :anthropic_api_key,
292
+ gemini_api_key: :gemini_api_key,
293
+ deepseek_api_key: :deepseek_api_key,
294
+ mistral_api_key: :mistral_api_key,
295
+ perplexity_api_key: :perplexity_api_key,
296
+ openrouter_api_key: :openrouter_api_key,
297
+ gpustack_api_key: :gpustack_api_key,
298
+ xai_api_key: :xai_api_key,
299
+ ollama_api_key: :ollama_api_key,
300
+ bedrock_api_key: :bedrock_api_key,
301
+ bedrock_secret_key: :bedrock_secret_key,
302
+ bedrock_session_token: :bedrock_session_token,
303
+ bedrock_region: :bedrock_region,
304
+ vertexai_credentials: :vertexai_credentials,
305
+ vertexai_project_id: :vertexai_project_id,
306
+ vertexai_location: :vertexai_location,
307
+ openai_api_base: :openai_api_base,
308
+ gemini_api_base: :gemini_api_base,
309
+ ollama_api_base: :ollama_api_base,
310
+ gpustack_api_base: :gpustack_api_base,
311
+ xai_api_base: :xai_api_base,
312
+ openai_organization_id: :openai_organization_id,
313
+ openai_project_id: :openai_project_id,
314
+ default_model: :default_model,
315
+ default_embedding_model: :default_embedding_model,
316
+ default_image_model: :default_image_model,
317
+ default_moderation_model: :default_moderation_model,
318
+ request_timeout: :request_timeout,
319
+ max_retries: :max_retries,
320
+ retry_interval: :retry_interval,
321
+ retry_backoff_factor: :retry_backoff_factor,
322
+ retry_interval_randomness: :retry_interval_randomness,
323
+ http_proxy: :http_proxy
324
+ }
325
+
326
+ mapping[attr_sym]
327
+ end
328
+
329
+ # Returns attributes that can be set on RubyLLM configuration
330
+ #
331
+ # @return [Array<Symbol>]
332
+ def ruby_llm_configurable_attributes
333
+ ApiConfiguration::API_KEY_ATTRIBUTES +
334
+ ApiConfiguration::ENDPOINT_ATTRIBUTES +
335
+ ApiConfiguration::MODEL_ATTRIBUTES +
336
+ ApiConfiguration::CONNECTION_ATTRIBUTES +
337
+ %i[
338
+ openai_organization_id
339
+ openai_project_id
340
+ bedrock_region
341
+ vertexai_project_id
342
+ vertexai_location
343
+ ]
344
+ end
345
+
346
+ end
347
+ end
348
+ end
@@ -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.4.0"
7
+ VERSION = "0.5.0"
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.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - adham90
@@ -65,10 +65,13 @@ files:
65
65
  - app/controllers/concerns/ruby_llm/agents/filterable.rb
66
66
  - app/controllers/concerns/ruby_llm/agents/paginatable.rb
67
67
  - app/controllers/ruby_llm/agents/agents_controller.rb
68
+ - app/controllers/ruby_llm/agents/api_configurations_controller.rb
68
69
  - app/controllers/ruby_llm/agents/dashboard_controller.rb
69
70
  - app/controllers/ruby_llm/agents/executions_controller.rb
70
- - app/controllers/ruby_llm/agents/settings_controller.rb
71
+ - app/controllers/ruby_llm/agents/system_config_controller.rb
72
+ - app/controllers/ruby_llm/agents/tenants_controller.rb
71
73
  - app/helpers/ruby_llm/agents/application_helper.rb
74
+ - app/models/ruby_llm/agents/api_configuration.rb
72
75
  - app/models/ruby_llm/agents/execution.rb
73
76
  - app/models/ruby_llm/agents/execution/analytics.rb
74
77
  - app/models/ruby_llm/agents/execution/metrics.rb
@@ -83,6 +86,12 @@ files:
83
86
  - app/views/ruby_llm/agents/agents/_workflow.html.erb
84
87
  - app/views/ruby_llm/agents/agents/index.html.erb
85
88
  - app/views/ruby_llm/agents/agents/show.html.erb
89
+ - app/views/ruby_llm/agents/api_configurations/_api_key_field.html.erb
90
+ - app/views/ruby_llm/agents/api_configurations/_form.html.erb
91
+ - app/views/ruby_llm/agents/api_configurations/edit.html.erb
92
+ - app/views/ruby_llm/agents/api_configurations/edit_tenant.html.erb
93
+ - app/views/ruby_llm/agents/api_configurations/show.html.erb
94
+ - app/views/ruby_llm/agents/api_configurations/tenant.html.erb
86
95
  - app/views/ruby_llm/agents/dashboard/_action_center.html.erb
87
96
  - app/views/ruby_llm/agents/dashboard/_agent_comparison.html.erb
88
97
  - app/views/ruby_llm/agents/dashboard/_alerts_feed.html.erb
@@ -100,7 +109,6 @@ files:
100
109
  - app/views/ruby_llm/agents/executions/dry_run.html.erb
101
110
  - app/views/ruby_llm/agents/executions/index.html.erb
102
111
  - app/views/ruby_llm/agents/executions/show.html.erb
103
- - app/views/ruby_llm/agents/settings/show.html.erb
104
112
  - app/views/ruby_llm/agents/shared/_breadcrumbs.html.erb
105
113
  - app/views/ruby_llm/agents/shared/_executions_table.html.erb
106
114
  - app/views/ruby_llm/agents/shared/_filter_dropdown.html.erb
@@ -111,8 +119,14 @@ files:
111
119
  - app/views/ruby_llm/agents/shared/_status_dot.html.erb
112
120
  - app/views/ruby_llm/agents/shared/_tenant_filter.html.erb
113
121
  - app/views/ruby_llm/agents/shared/_workflow_type_badge.html.erb
122
+ - app/views/ruby_llm/agents/system_config/show.html.erb
123
+ - app/views/ruby_llm/agents/tenants/_form.html.erb
124
+ - app/views/ruby_llm/agents/tenants/edit.html.erb
125
+ - app/views/ruby_llm/agents/tenants/index.html.erb
126
+ - app/views/ruby_llm/agents/tenants/show.html.erb
114
127
  - config/routes.rb
115
128
  - lib/generators/ruby_llm_agents/agent_generator.rb
129
+ - lib/generators/ruby_llm_agents/api_configuration_generator.rb
116
130
  - lib/generators/ruby_llm_agents/install_generator.rb
117
131
  - lib/generators/ruby_llm_agents/multi_tenancy_generator.rb
118
132
  - lib/generators/ruby_llm_agents/templates/add_attempts_migration.rb.tt
@@ -127,6 +141,7 @@ files:
127
141
  - lib/generators/ruby_llm_agents/templates/add_workflow_migration.rb.tt
128
142
  - lib/generators/ruby_llm_agents/templates/agent.rb.tt
129
143
  - lib/generators/ruby_llm_agents/templates/application_agent.rb.tt
144
+ - lib/generators/ruby_llm_agents/templates/create_api_configurations_migration.rb.tt
130
145
  - lib/generators/ruby_llm_agents/templates/create_tenant_budgets_migration.rb.tt
131
146
  - lib/generators/ruby_llm_agents/templates/initializer.rb.tt
132
147
  - lib/generators/ruby_llm_agents/templates/migration.rb.tt
@@ -160,6 +175,7 @@ files:
160
175
  - lib/ruby_llm/agents/reliability/executor.rb
161
176
  - lib/ruby_llm/agents/reliability/fallback_routing.rb
162
177
  - lib/ruby_llm/agents/reliability/retry_strategy.rb
178
+ - lib/ruby_llm/agents/resolved_config.rb
163
179
  - lib/ruby_llm/agents/result.rb
164
180
  - lib/ruby_llm/agents/version.rb
165
181
  - lib/ruby_llm/agents/workflow.rb