ruby_llm-agents 3.5.5 → 3.7.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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -0
  3. data/app/controllers/ruby_llm/agents/dashboard_controller.rb +155 -10
  4. data/app/controllers/ruby_llm/agents/executions_controller.rb +1 -3
  5. data/app/helpers/ruby_llm/agents/application_helper.rb +15 -28
  6. data/app/models/ruby_llm/agents/execution/replayable.rb +124 -0
  7. data/app/models/ruby_llm/agents/execution/scopes.rb +42 -1
  8. data/app/models/ruby_llm/agents/execution.rb +50 -1
  9. data/app/models/ruby_llm/agents/tenant/budgetable.rb +28 -4
  10. data/app/views/layouts/ruby_llm/agents/application.html.erb +41 -28
  11. data/app/views/ruby_llm/agents/agents/show.html.erb +16 -1
  12. data/app/views/ruby_llm/agents/dashboard/_top_tenants.html.erb +47 -0
  13. data/app/views/ruby_llm/agents/dashboard/index.html.erb +404 -107
  14. data/app/views/ruby_llm/agents/system_config/show.html.erb +0 -13
  15. data/lib/generators/ruby_llm_agents/rename_agent_generator.rb +53 -0
  16. data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +0 -15
  17. data/lib/generators/ruby_llm_agents/templates/rename_agent_migration.rb.tt +19 -0
  18. data/lib/ruby_llm/agents/agent_tool.rb +125 -0
  19. data/lib/ruby_llm/agents/audio/speaker.rb +5 -3
  20. data/lib/ruby_llm/agents/audio/speech_pricing.rb +63 -187
  21. data/lib/ruby_llm/agents/audio/transcriber.rb +5 -3
  22. data/lib/ruby_llm/agents/audio/transcription_pricing.rb +5 -7
  23. data/lib/ruby_llm/agents/base_agent.rb +144 -5
  24. data/lib/ruby_llm/agents/core/configuration.rb +178 -53
  25. data/lib/ruby_llm/agents/core/errors.rb +3 -77
  26. data/lib/ruby_llm/agents/core/instrumentation.rb +0 -17
  27. data/lib/ruby_llm/agents/core/version.rb +1 -1
  28. data/lib/ruby_llm/agents/dsl/base.rb +0 -8
  29. data/lib/ruby_llm/agents/dsl/queryable.rb +124 -0
  30. data/lib/ruby_llm/agents/dsl.rb +1 -0
  31. data/lib/ruby_llm/agents/eval/eval_result.rb +73 -0
  32. data/lib/ruby_llm/agents/eval/eval_run.rb +124 -0
  33. data/lib/ruby_llm/agents/eval/eval_suite.rb +264 -0
  34. data/lib/ruby_llm/agents/eval.rb +5 -0
  35. data/lib/ruby_llm/agents/image/concerns/image_operation_execution.rb +2 -1
  36. data/lib/ruby_llm/agents/image/generator/pricing.rb +75 -217
  37. data/lib/ruby_llm/agents/image/generator.rb +5 -3
  38. data/lib/ruby_llm/agents/infrastructure/attempt_tracker.rb +8 -0
  39. data/lib/ruby_llm/agents/infrastructure/circuit_breaker.rb +4 -2
  40. data/lib/ruby_llm/agents/pipeline/builder.rb +43 -0
  41. data/lib/ruby_llm/agents/pipeline/context.rb +11 -1
  42. data/lib/ruby_llm/agents/pipeline/executor.rb +1 -25
  43. data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +26 -1
  44. data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +18 -0
  45. data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +90 -0
  46. data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +29 -0
  47. data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +11 -4
  48. data/lib/ruby_llm/agents/pipeline.rb +0 -92
  49. data/lib/ruby_llm/agents/results/background_removal_result.rb +11 -1
  50. data/lib/ruby_llm/agents/results/base.rb +23 -1
  51. data/lib/ruby_llm/agents/results/embedding_result.rb +14 -1
  52. data/lib/ruby_llm/agents/results/image_analysis_result.rb +11 -1
  53. data/lib/ruby_llm/agents/results/image_edit_result.rb +11 -1
  54. data/lib/ruby_llm/agents/results/image_generation_result.rb +12 -3
  55. data/lib/ruby_llm/agents/results/image_pipeline_result.rb +11 -1
  56. data/lib/ruby_llm/agents/results/image_transform_result.rb +11 -1
  57. data/lib/ruby_llm/agents/results/image_upscale_result.rb +11 -1
  58. data/lib/ruby_llm/agents/results/image_variation_result.rb +11 -1
  59. data/lib/ruby_llm/agents/results/speech_result.rb +20 -1
  60. data/lib/ruby_llm/agents/results/transcription_result.rb +20 -1
  61. data/lib/ruby_llm/agents/text/embedder.rb +23 -18
  62. data/lib/ruby_llm/agents.rb +73 -5
  63. data/lib/tasks/ruby_llm_agents.rake +21 -0
  64. metadata +11 -6
  65. data/lib/ruby_llm/agents/infrastructure/reliability/breaker_manager.rb +0 -80
  66. data/lib/ruby_llm/agents/infrastructure/reliability/execution_constraints.rb +0 -69
  67. data/lib/ruby_llm/agents/infrastructure/reliability/executor.rb +0 -125
  68. data/lib/ruby_llm/agents/infrastructure/reliability/fallback_routing.rb +0 -72
  69. data/lib/ruby_llm/agents/infrastructure/reliability/retry_strategy.rb +0 -82
@@ -42,6 +42,7 @@ module RubyLLM
42
42
  # Create "running" record immediately (SYNC - must appear on dashboard)
43
43
  execution = create_running_execution(context)
44
44
  context.execution_id = execution&.id
45
+ emit_start_notification(context)
45
46
  status_update_completed = false
46
47
  raised_exception = nil
47
48
 
@@ -55,6 +56,8 @@ module RubyLLM
55
56
  rescue
56
57
  # Let ensure block handle via mark_execution_failed!
57
58
  end
59
+
60
+ emit_complete_notification(context, "success")
58
61
  rescue => e
59
62
  context.completed_at = Time.current
60
63
  context.error = e
@@ -67,6 +70,7 @@ module RubyLLM
67
70
  # Let ensure block handle via mark_execution_failed!
68
71
  end
69
72
 
73
+ emit_complete_notification(context, determine_error_status(e))
70
74
  raise
71
75
  ensure
72
76
  # Emergency fallback if update failed
@@ -93,6 +97,12 @@ module RubyLLM
93
97
  data = build_running_execution_data(context)
94
98
  execution = Execution.create!(data)
95
99
 
100
+ # Root executions point root_execution_id at themselves
101
+ if execution.parent_execution_id.nil? && execution.root_execution_id.nil?
102
+ execution.update_column(:root_execution_id, execution.id)
103
+ end
104
+ context.root_execution_id = execution.root_execution_id || execution.id
105
+
96
106
  # Create detail record with parameters
97
107
  params = sanitize_parameters(context)
98
108
  if params.present? && params != {}
@@ -181,6 +191,61 @@ module RubyLLM
181
191
  error.is_a?(Timeout::Error) ? "timeout" : "error"
182
192
  end
183
193
 
194
+ # Emits an AS::Notification for execution start
195
+ #
196
+ # Fires even when DB tracking is disabled — observability should
197
+ # work independently of persistence.
198
+ #
199
+ # @param context [Context] The execution context
200
+ def emit_start_notification(context)
201
+ ActiveSupport::Notifications.instrument(
202
+ "ruby_llm_agents.execution.start",
203
+ agent_type: context.agent_class&.name,
204
+ model: context.model,
205
+ tenant_id: context.tenant_id,
206
+ execution_id: context.execution_id
207
+ )
208
+ rescue
209
+ # Never let notifications break execution
210
+ end
211
+
212
+ # Emits an AS::Notification for execution completion or error
213
+ #
214
+ # Uses execution.complete for success, execution.error for failures.
215
+ # Fires even when DB tracking is disabled.
216
+ #
217
+ # @param context [Context] The execution context
218
+ # @param status [String] "success", "error", or "timeout"
219
+ def emit_complete_notification(context, status)
220
+ event = (status == "success") ? "ruby_llm_agents.execution.complete" : "ruby_llm_agents.execution.error"
221
+
222
+ ActiveSupport::Notifications.instrument(
223
+ event,
224
+ agent_type: context.agent_class&.name,
225
+ agent_type_symbol: context.agent_type,
226
+ execution_id: context.execution_id,
227
+ model: context.model,
228
+ model_used: context.model_used,
229
+ tenant_id: context.tenant_id,
230
+ status: status,
231
+ duration_ms: context.duration_ms,
232
+ input_tokens: context.input_tokens,
233
+ output_tokens: context.output_tokens,
234
+ total_tokens: context.total_tokens,
235
+ input_cost: context.input_cost,
236
+ output_cost: context.output_cost,
237
+ total_cost: context.total_cost,
238
+ cached: context.cached?,
239
+ attempts_made: context.attempts_made,
240
+ finish_reason: context.finish_reason,
241
+ time_to_first_token_ms: context.time_to_first_token_ms,
242
+ error_class: context.error&.class&.name,
243
+ error_message: context.error&.message
244
+ )
245
+ rescue
246
+ # Never let notifications break execution
247
+ end
248
+
184
249
  # Builds data for initial running execution record
185
250
  #
186
251
  # @param context [Context] The execution context
@@ -208,6 +273,22 @@ module RubyLLM
208
273
  data[:metadata] = agent_meta.transform_keys(&:to_s)
209
274
  end
210
275
 
276
+ # Track replay source if this is a replayed execution
277
+ replay_source_id = begin
278
+ context.agent_instance&.send(:options)&.dig(:_replay_source_id)
279
+ rescue
280
+ nil
281
+ end
282
+ if replay_source_id
283
+ data[:metadata] = (data[:metadata] || {}).merge("replay_source_id" => replay_source_id.to_s)
284
+ end
285
+
286
+ # Execution hierarchy (agent-as-tool)
287
+ if context.parent_execution_id.present?
288
+ data[:parent_execution_id] = context.parent_execution_id
289
+ data[:root_execution_id] = context.root_execution_id || context.parent_execution_id
290
+ end
291
+
211
292
  data
212
293
  end
213
294
 
@@ -442,6 +523,10 @@ module RubyLLM
442
523
  params[key] = "[REDACTED]" if params.key?(key)
443
524
  end
444
525
 
526
+ INTERNAL_KEYS.each do |key|
527
+ params.delete(key)
528
+ end
529
+
445
530
  params
446
531
  end
447
532
 
@@ -469,6 +554,11 @@ module RubyLLM
469
554
  access_token refresh_token private_key secret_key
470
555
  ].freeze
471
556
 
557
+ # Internal keys that should be stripped from persisted parameters
558
+ INTERNAL_KEYS = %w[
559
+ _replay_source_id _ask_message _parent_execution_id _root_execution_id
560
+ ].freeze
561
+
472
562
  # Truncates error message to prevent database issues
473
563
  #
474
564
  # @param message [String] The error message
@@ -120,6 +120,17 @@ module RubyLLM
120
120
 
121
121
  if result
122
122
  context[:reliability_attempts] = tracker.to_json_array
123
+
124
+ # Emit fallback_used if a non-primary model succeeded
125
+ if current_model != models_to_try.first
126
+ emit_reliability_notification(
127
+ "ruby_llm_agents.reliability.fallback_used",
128
+ primary_model: models_to_try.first,
129
+ used_model: current_model,
130
+ attempts_made: context.attempts_made
131
+ )
132
+ end
133
+
123
134
  return result
124
135
  end
125
136
 
@@ -131,6 +142,11 @@ module RubyLLM
131
142
  context[:reliability_attempts] = tracker.to_json_array
132
143
 
133
144
  # All models exhausted
145
+ emit_reliability_notification(
146
+ "ruby_llm_agents.reliability.all_models_exhausted",
147
+ models_tried: models_to_try
148
+ )
149
+
134
150
  raise Agents::Reliability::AllModelsExhaustedError.new(
135
151
  models_to_try, last_error,
136
152
  attempts: tracker.to_json_array
@@ -292,6 +308,19 @@ module RubyLLM
292
308
  )
293
309
  end
294
310
 
311
+ # Emits an AS::Notification for reliability events
312
+ #
313
+ # @param event [String] The notification event name
314
+ # @param extras [Hash] Additional payload fields
315
+ def emit_reliability_notification(event, **extras)
316
+ ActiveSupport::Notifications.instrument(
317
+ event,
318
+ {agent_type: @agent_class&.name}.merge(extras)
319
+ )
320
+ rescue
321
+ # Never let notifications break execution
322
+ end
323
+
295
324
  # Sleeps without blocking other fibers when in async context
296
325
  #
297
326
  # @param seconds [Numeric] Duration to sleep
@@ -59,10 +59,17 @@ module RubyLLM
59
59
  case tenant_value
60
60
  when nil
61
61
  # No explicit tenant - fall back to configured tenant_resolver
62
- resolved_id = RubyLLM::Agents.configuration.current_tenant_id
63
- context.tenant_id = resolved_id&.to_s
64
- context.tenant_object = nil
65
- context.tenant_config = nil
62
+ resolved_value = RubyLLM::Agents.configuration.current_tenant_id
63
+
64
+ if resolved_value.respond_to?(:llm_tenant_id)
65
+ context.tenant_id = resolved_value.llm_tenant_id&.to_s
66
+ context.tenant_object = resolved_value
67
+ context.tenant_config = extract_tenant_config(resolved_value)
68
+ else
69
+ context.tenant_id = resolved_value&.to_s
70
+ context.tenant_object = nil
71
+ context.tenant_config = nil
72
+ end
66
73
 
67
74
  when Hash
68
75
  # Hash format: { id: "tenant_id", object: tenant, ... }
@@ -40,98 +40,6 @@ require_relative "pipeline/middleware/reliability"
40
40
  module RubyLLM
41
41
  module Agents
42
42
  module Pipeline
43
- # Represents an error result from a failed step
44
- #
45
- # Used to track errors that occurred during step execution while
46
- # allowing the workflow to continue (for optional steps).
47
- #
48
- # @api public
49
- class ErrorResult
50
- attr_reader :step_name, :error_class, :error_message
51
-
52
- def initialize(step_name:, error_class:, error_message:)
53
- @step_name = step_name
54
- @error_class = error_class
55
- @error_message = error_message
56
- end
57
-
58
- def content
59
- nil
60
- end
61
-
62
- def success?
63
- false
64
- end
65
-
66
- def error?
67
- true
68
- end
69
-
70
- def skipped?
71
- false
72
- end
73
-
74
- def input_tokens
75
- 0
76
- end
77
-
78
- def output_tokens
79
- 0
80
- end
81
-
82
- def total_tokens
83
- 0
84
- end
85
-
86
- def cached_tokens
87
- 0
88
- end
89
-
90
- def input_cost
91
- 0.0
92
- end
93
-
94
- def output_cost
95
- 0.0
96
- end
97
-
98
- def total_cost
99
- 0.0
100
- end
101
-
102
- def to_h
103
- {
104
- error: true,
105
- step_name: step_name,
106
- error_class: error_class,
107
- error_message: error_message
108
- }
109
- end
110
- end
111
-
112
- class << self
113
- # Build a pipeline for an agent class with default middleware
114
- #
115
- # This is a convenience method that combines Builder.for with build.
116
- #
117
- # @param agent_class [Class] The agent class
118
- # @param executor [#call] The core executor
119
- # @return [#call] The complete pipeline
120
- def build(agent_class, executor)
121
- Builder.for(agent_class).build(executor)
122
- end
123
-
124
- # Build an empty pipeline (no middleware)
125
- #
126
- # Useful for testing or when you want direct execution.
127
- #
128
- # @param agent_class [Class] The agent class
129
- # @param executor [#call] The core executor
130
- # @return [#call] The executor (no middleware wrapping)
131
- def build_empty(agent_class, executor)
132
- Builder.empty(agent_class).build(executor)
133
- end
134
- end
135
43
  end
136
44
  end
137
45
  end
@@ -19,6 +19,7 @@ module RubyLLM
19
19
  :alpha_matting, :refine_edges,
20
20
  :started_at, :completed_at, :tenant_id, :remover_class,
21
21
  :error_class, :error_message
22
+ attr_accessor :execution_id
22
23
 
23
24
  # Initialize a new result
24
25
  #
@@ -51,6 +52,14 @@ module RubyLLM
51
52
  @remover_class = remover_class
52
53
  @error_class = error_class
53
54
  @error_message = error_message
55
+ @execution_id = nil
56
+ end
57
+
58
+ # Loads the associated Execution record from the database
59
+ #
60
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
61
+ def execution
62
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
54
63
  end
55
64
 
56
65
  # Status helpers
@@ -196,7 +205,8 @@ module RubyLLM
196
205
  tenant_id: tenant_id,
197
206
  remover_class: remover_class,
198
207
  error_class: error_class,
199
- error_message: error_message
208
+ error_message: error_message,
209
+ execution_id: execution_id
200
210
  }
201
211
  end
202
212
 
@@ -102,6 +102,11 @@ module RubyLLM
102
102
  # @return [Integer, nil] Number of tokens used for thinking
103
103
  attr_reader :thinking_text, :thinking_signature, :thinking_tokens
104
104
 
105
+ # @!group Execution Record
106
+ # @!attribute [r] execution_id
107
+ # @return [Integer, nil] Database ID of the associated Execution record
108
+ attr_reader :execution_id
109
+
105
110
  # Creates a new Result instance
106
111
  #
107
112
  # @param content [Hash, String] The processed response content
@@ -151,6 +156,22 @@ module RubyLLM
151
156
  @thinking_text = options[:thinking_text]
152
157
  @thinking_signature = options[:thinking_signature]
153
158
  @thinking_tokens = options[:thinking_tokens]
159
+
160
+ # Execution record
161
+ @execution_id = options[:execution_id]
162
+ end
163
+
164
+ # Loads the associated Execution record from the database
165
+ #
166
+ # Useful for debugging in the Rails console to inspect the full
167
+ # execution record after an agent call.
168
+ #
169
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
170
+ # @example
171
+ # result = MyAgent.call(query: "test")
172
+ # result.execution # => #<RubyLLM::Agents::Execution id: 42, ...>
173
+ def execution
174
+ @execution ||= Execution.find_by(id: execution_id) if execution_id
154
175
  end
155
176
 
156
177
  # Returns total tokens (input + output)
@@ -240,7 +261,8 @@ module RubyLLM
240
261
  tool_calls_count: tool_calls_count,
241
262
  thinking_text: thinking_text,
242
263
  thinking_signature: thinking_signature,
243
- thinking_tokens: thinking_tokens
264
+ thinking_tokens: thinking_tokens,
265
+ execution_id: execution_id
244
266
  }
245
267
  end
246
268
 
@@ -73,6 +73,10 @@ module RubyLLM
73
73
  # @return [String, nil] Exception message if failed
74
74
  attr_reader :error_message
75
75
 
76
+ # @!attribute [r] execution_id
77
+ # @return [Integer, nil] Database ID of the associated Execution record
78
+ attr_reader :execution_id
79
+
76
80
  # Creates a new EmbeddingResult instance
77
81
  #
78
82
  # @param attributes [Hash] Result attributes
@@ -101,6 +105,14 @@ module RubyLLM
101
105
  @tenant_id = attributes[:tenant_id]
102
106
  @error_class = attributes[:error_class]
103
107
  @error_message = attributes[:error_message]
108
+ @execution_id = attributes[:execution_id]
109
+ end
110
+
111
+ # Loads the associated Execution record from the database
112
+ #
113
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
114
+ def execution
115
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
104
116
  end
105
117
 
106
118
  # Returns whether this result contains a single embedding
@@ -215,7 +227,8 @@ module RubyLLM
215
227
  completed_at: completed_at,
216
228
  tenant_id: tenant_id,
217
229
  error_class: error_class,
218
- error_message: error_message
230
+ error_message: error_message,
231
+ execution_id: execution_id
219
232
  }
220
233
  end
221
234
 
@@ -21,6 +21,7 @@ module RubyLLM
21
21
  :caption, :description, :tags, :objects, :colors, :text,
22
22
  :raw_response, :started_at, :completed_at, :tenant_id, :analyzer_class,
23
23
  :error_class, :error_message
24
+ attr_accessor :execution_id
24
25
 
25
26
  # Initialize a new result
26
27
  #
@@ -59,6 +60,14 @@ module RubyLLM
59
60
  @analyzer_class = analyzer_class
60
61
  @error_class = error_class
61
62
  @error_message = error_message
63
+ @execution_id = nil
64
+ end
65
+
66
+ # Loads the associated Execution record from the database
67
+ #
68
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
69
+ def execution
70
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
62
71
  end
63
72
 
64
73
  # Status helpers
@@ -205,7 +214,8 @@ module RubyLLM
205
214
  tenant_id: tenant_id,
206
215
  analyzer_class: analyzer_class,
207
216
  error_class: error_class,
208
- error_message: error_message
217
+ error_message: error_message,
218
+ execution_id: execution_id
209
219
  }
210
220
  end
211
221
 
@@ -20,6 +20,7 @@ module RubyLLM
20
20
  attr_reader :images, :source_image, :mask, :prompt, :model_id, :size,
21
21
  :started_at, :completed_at, :tenant_id, :editor_class,
22
22
  :error_class, :error_message
23
+ attr_accessor :execution_id
23
24
 
24
25
  # Initialize a new result
25
26
  #
@@ -50,6 +51,14 @@ module RubyLLM
50
51
  @editor_class = editor_class
51
52
  @error_class = error_class
52
53
  @error_message = error_message
54
+ @execution_id = nil
55
+ end
56
+
57
+ # Loads the associated Execution record from the database
58
+ #
59
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
60
+ def execution
61
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
53
62
  end
54
63
 
55
64
  # Status helpers
@@ -175,7 +184,8 @@ module RubyLLM
175
184
  tenant_id: tenant_id,
176
185
  editor_class: editor_class,
177
186
  error_class: error_class,
178
- error_message: error_message
187
+ error_message: error_message,
188
+ execution_id: execution_id
179
189
  }
180
190
  end
181
191
 
@@ -22,7 +22,7 @@ module RubyLLM
22
22
  class ImageGenerationResult
23
23
  attr_reader :images, :prompt, :model_id, :size, :quality, :style,
24
24
  :started_at, :completed_at, :tenant_id, :generator_class,
25
- :error_class, :error_message
25
+ :error_class, :error_message, :execution_id
26
26
 
27
27
  # Initialize a new result
28
28
  #
@@ -40,7 +40,7 @@ module RubyLLM
40
40
  # @param error_message [String, nil] Error message if failed
41
41
  def initialize(images:, prompt:, model_id:, size:, quality:, style:,
42
42
  started_at:, completed_at:, tenant_id:, generator_class:,
43
- error_class: nil, error_message: nil)
43
+ error_class: nil, error_message: nil, execution_id: nil)
44
44
  @images = images
45
45
  @prompt = prompt
46
46
  @model_id = model_id
@@ -53,6 +53,14 @@ module RubyLLM
53
53
  @generator_class = generator_class
54
54
  @error_class = error_class
55
55
  @error_message = error_message
56
+ @execution_id = execution_id
57
+ end
58
+
59
+ # Loads the associated Execution record from the database
60
+ #
61
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
62
+ def execution
63
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
56
64
  end
57
65
 
58
66
  # Status helpers
@@ -257,7 +265,8 @@ module RubyLLM
257
265
  tenant_id: tenant_id,
258
266
  generator_class: generator_class,
259
267
  error_class: error_class,
260
- error_message: error_message
268
+ error_message: error_message,
269
+ execution_id: execution_id
261
270
  }
262
271
  end
263
272
 
@@ -23,6 +23,7 @@ module RubyLLM
23
23
  class ImagePipelineResult
24
24
  attr_reader :step_results, :started_at, :completed_at, :tenant_id,
25
25
  :pipeline_class, :context, :error_class, :error_message
26
+ attr_accessor :execution_id
26
27
 
27
28
  # Initialize a new pipeline result
28
29
  #
@@ -44,6 +45,14 @@ module RubyLLM
44
45
  @context = context
45
46
  @error_class = error_class
46
47
  @error_message = error_message
48
+ @execution_id = nil
49
+ end
50
+
51
+ # Loads the associated Execution record from the database
52
+ #
53
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
54
+ def execution
55
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
47
56
  end
48
57
 
49
58
  # Status helpers
@@ -315,7 +324,8 @@ module RubyLLM
315
324
  tenant_id: tenant_id,
316
325
  pipeline_class: pipeline_class,
317
326
  error_class: error_class,
318
- error_message: error_message
327
+ error_message: error_message,
328
+ execution_id: execution_id
319
329
  }
320
330
  end
321
331
 
@@ -20,6 +20,7 @@ module RubyLLM
20
20
  attr_reader :images, :source_image, :prompt, :model_id, :size, :strength,
21
21
  :started_at, :completed_at, :tenant_id, :transformer_class,
22
22
  :error_class, :error_message
23
+ attr_accessor :execution_id
23
24
 
24
25
  # Initialize a new result
25
26
  #
@@ -50,6 +51,14 @@ module RubyLLM
50
51
  @transformer_class = transformer_class
51
52
  @error_class = error_class
52
53
  @error_message = error_message
54
+ @execution_id = nil
55
+ end
56
+
57
+ # Loads the associated Execution record from the database
58
+ #
59
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
60
+ def execution
61
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
53
62
  end
54
63
 
55
64
  # Status helpers
@@ -176,7 +185,8 @@ module RubyLLM
176
185
  tenant_id: tenant_id,
177
186
  transformer_class: transformer_class,
178
187
  error_class: error_class,
179
- error_message: error_message
188
+ error_message: error_message,
189
+ execution_id: execution_id
180
190
  }
181
191
  end
182
192
 
@@ -18,6 +18,7 @@ module RubyLLM
18
18
  attr_reader :image, :source_image, :model_id, :scale, :output_size, :face_enhance,
19
19
  :started_at, :completed_at, :tenant_id, :upscaler_class,
20
20
  :error_class, :error_message
21
+ attr_accessor :execution_id
21
22
 
22
23
  # Initialize a new result
23
24
  #
@@ -48,6 +49,14 @@ module RubyLLM
48
49
  @upscaler_class = upscaler_class
49
50
  @error_class = error_class
50
51
  @error_message = error_message
52
+ @execution_id = nil
53
+ end
54
+
55
+ # Loads the associated Execution record from the database
56
+ #
57
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
58
+ def execution
59
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
51
60
  end
52
61
 
53
62
  # Status helpers
@@ -171,7 +180,8 @@ module RubyLLM
171
180
  tenant_id: tenant_id,
172
181
  upscaler_class: upscaler_class,
173
182
  error_class: error_class,
174
- error_message: error_message
183
+ error_message: error_message,
184
+ execution_id: execution_id
175
185
  }
176
186
  end
177
187
 
@@ -17,6 +17,7 @@ module RubyLLM
17
17
  attr_reader :images, :source_image, :model_id, :size, :variation_strength,
18
18
  :started_at, :completed_at, :tenant_id, :variator_class,
19
19
  :error_class, :error_message
20
+ attr_accessor :execution_id
20
21
 
21
22
  # Initialize a new result
22
23
  #
@@ -45,6 +46,14 @@ module RubyLLM
45
46
  @variator_class = variator_class
46
47
  @error_class = error_class
47
48
  @error_message = error_message
49
+ @execution_id = nil
50
+ end
51
+
52
+ # Loads the associated Execution record from the database
53
+ #
54
+ # @return [RubyLLM::Agents::Execution, nil] The execution record, or nil
55
+ def execution
56
+ @execution ||= RubyLLM::Agents::Execution.find_by(id: execution_id) if execution_id
48
57
  end
49
58
 
50
59
  # Status helpers
@@ -162,7 +171,8 @@ module RubyLLM
162
171
  tenant_id: tenant_id,
163
172
  variator_class: variator_class,
164
173
  error_class: error_class,
165
- error_message: error_message
174
+ error_message: error_message,
175
+ execution_id: execution_id
166
176
  }
167
177
  end
168
178