ruby_llm-agents 3.8.0 → 3.9.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.
- checksums.yaml +4 -4
- data/README.md +30 -10
- data/app/controllers/ruby_llm/agents/requests_controller.rb +117 -0
- data/app/views/layouts/ruby_llm/agents/application.html.erb +4 -2
- data/app/views/ruby_llm/agents/requests/index.html.erb +153 -0
- data/app/views/ruby_llm/agents/requests/show.html.erb +136 -0
- data/config/routes.rb +2 -0
- data/lib/generators/ruby_llm_agents/agent_generator.rb +2 -2
- data/lib/generators/ruby_llm_agents/demo_generator.rb +102 -0
- data/lib/generators/ruby_llm_agents/doctor_generator.rb +196 -0
- data/lib/generators/ruby_llm_agents/install_generator.rb +7 -19
- data/lib/generators/ruby_llm_agents/templates/agent.rb.tt +27 -80
- data/lib/generators/ruby_llm_agents/templates/application_agent.rb.tt +18 -51
- data/lib/generators/ruby_llm_agents/templates/initializer.rb.tt +19 -17
- data/lib/ruby_llm/agents/base_agent.rb +68 -7
- data/lib/ruby_llm/agents/core/base.rb +4 -0
- data/lib/ruby_llm/agents/core/configuration.rb +10 -0
- data/lib/ruby_llm/agents/core/version.rb +1 -1
- data/lib/ruby_llm/agents/pipeline/context.rb +26 -0
- data/lib/ruby_llm/agents/pipeline/middleware/base.rb +58 -4
- data/lib/ruby_llm/agents/pipeline/middleware/budget.rb +17 -15
- data/lib/ruby_llm/agents/pipeline/middleware/cache.rb +34 -22
- data/lib/ruby_llm/agents/pipeline/middleware/instrumentation.rb +105 -50
- data/lib/ruby_llm/agents/pipeline/middleware/reliability.rb +7 -5
- data/lib/ruby_llm/agents/pipeline/middleware/tenant.rb +6 -4
- data/lib/ruby_llm/agents/rails/engine.rb +11 -0
- data/lib/ruby_llm/agents/results/background_removal_result.rb +7 -1
- data/lib/ruby_llm/agents/results/base.rb +24 -2
- data/lib/ruby_llm/agents/results/embedding_result.rb +4 -0
- data/lib/ruby_llm/agents/results/image_analysis_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_edit_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_generation_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_pipeline_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_transform_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_upscale_result.rb +7 -1
- data/lib/ruby_llm/agents/results/image_variation_result.rb +7 -1
- data/lib/ruby_llm/agents/results/speech_result.rb +6 -0
- data/lib/ruby_llm/agents/results/trackable.rb +25 -0
- data/lib/ruby_llm/agents/results/transcription_result.rb +6 -0
- data/lib/ruby_llm/agents/text/embedder.rb +7 -4
- data/lib/ruby_llm/agents/track_report.rb +127 -0
- data/lib/ruby_llm/agents/tracker.rb +32 -0
- data/lib/ruby_llm/agents.rb +208 -0
- data/lib/tasks/ruby_llm_agents.rake +6 -0
- metadata +10 -2
|
@@ -107,6 +107,16 @@ module RubyLLM
|
|
|
107
107
|
# @return [Integer, nil] Database ID of the associated Execution record
|
|
108
108
|
attr_reader :execution_id
|
|
109
109
|
|
|
110
|
+
# @!group Tracking
|
|
111
|
+
# @!attribute [r] agent_class_name
|
|
112
|
+
# @return [String, nil] The agent class that produced this result
|
|
113
|
+
attr_reader :agent_class_name
|
|
114
|
+
|
|
115
|
+
# @!group Debug
|
|
116
|
+
# @!attribute [r] trace
|
|
117
|
+
# @return [Array<Hash>, nil] Pipeline trace entries (when debug: true)
|
|
118
|
+
attr_reader :trace
|
|
119
|
+
|
|
110
120
|
# Creates a new Result instance
|
|
111
121
|
#
|
|
112
122
|
# @param content [Hash, String] The processed response content
|
|
@@ -159,6 +169,16 @@ module RubyLLM
|
|
|
159
169
|
|
|
160
170
|
# Execution record
|
|
161
171
|
@execution_id = options[:execution_id]
|
|
172
|
+
|
|
173
|
+
# Tracking
|
|
174
|
+
@agent_class_name = options[:agent_class_name]
|
|
175
|
+
|
|
176
|
+
# Debug trace
|
|
177
|
+
@trace = options[:trace]
|
|
178
|
+
|
|
179
|
+
# Register with active tracker
|
|
180
|
+
tracker = Thread.current[:ruby_llm_agents_tracker]
|
|
181
|
+
tracker << self if tracker
|
|
162
182
|
end
|
|
163
183
|
|
|
164
184
|
# Loads the associated Execution record from the database
|
|
@@ -264,8 +284,10 @@ module RubyLLM
|
|
|
264
284
|
thinking_text: thinking_text,
|
|
265
285
|
thinking_signature: thinking_signature,
|
|
266
286
|
thinking_tokens: thinking_tokens,
|
|
267
|
-
execution_id: execution_id
|
|
268
|
-
|
|
287
|
+
execution_id: execution_id,
|
|
288
|
+
agent_class_name: agent_class_name,
|
|
289
|
+
trace: trace
|
|
290
|
+
}.compact
|
|
269
291
|
end
|
|
270
292
|
|
|
271
293
|
# @!group Deprecated Hash Delegation
|
|
@@ -25,6 +25,8 @@ module RubyLLM
|
|
|
25
25
|
#
|
|
26
26
|
# @api public
|
|
27
27
|
class EmbeddingResult
|
|
28
|
+
include Trackable
|
|
29
|
+
|
|
28
30
|
# @!attribute [r] vectors
|
|
29
31
|
# @return [Array<Array<Float>>] The embedding vectors
|
|
30
32
|
attr_reader :vectors
|
|
@@ -106,6 +108,8 @@ module RubyLLM
|
|
|
106
108
|
@error_class = attributes[:error_class]
|
|
107
109
|
@error_message = attributes[:error_message]
|
|
108
110
|
@execution_id = attributes[:execution_id]
|
|
111
|
+
@agent_class_name = attributes[:agent_class_name]
|
|
112
|
+
register_with_tracker
|
|
109
113
|
end
|
|
110
114
|
|
|
111
115
|
# Loads the associated Execution record from the database
|
|
@@ -17,6 +17,8 @@ module RubyLLM
|
|
|
17
17
|
# result.success? # => true
|
|
18
18
|
#
|
|
19
19
|
class ImageAnalysisResult
|
|
20
|
+
include Trackable
|
|
21
|
+
|
|
20
22
|
attr_reader :image, :model_id, :analysis_type,
|
|
21
23
|
:caption, :description, :tags, :objects, :colors, :text,
|
|
22
24
|
:raw_response, :started_at, :completed_at, :tenant_id, :analyzer_class,
|
|
@@ -43,7 +45,7 @@ module RubyLLM
|
|
|
43
45
|
# @param error_message [String, nil] Error message if failed
|
|
44
46
|
def initialize(image:, model_id:, analysis_type:, caption:, description:, tags:,
|
|
45
47
|
objects:, colors:, text:, raw_response:, started_at:, completed_at:,
|
|
46
|
-
tenant_id:, analyzer_class:, error_class: nil, error_message: nil)
|
|
48
|
+
tenant_id:, analyzer_class:, error_class: nil, error_message: nil, agent_class_name: nil)
|
|
47
49
|
@image = image
|
|
48
50
|
@model_id = model_id
|
|
49
51
|
@analysis_type = analysis_type
|
|
@@ -61,6 +63,10 @@ module RubyLLM
|
|
|
61
63
|
@error_class = error_class
|
|
62
64
|
@error_message = error_message
|
|
63
65
|
@execution_id = nil
|
|
66
|
+
|
|
67
|
+
# Tracking
|
|
68
|
+
@agent_class_name = agent_class_name
|
|
69
|
+
register_with_tracker
|
|
64
70
|
end
|
|
65
71
|
|
|
66
72
|
# Loads the associated Execution record from the database
|
|
@@ -17,6 +17,8 @@ module RubyLLM
|
|
|
17
17
|
# result.success? # => true
|
|
18
18
|
#
|
|
19
19
|
class ImageEditResult
|
|
20
|
+
include Trackable
|
|
21
|
+
|
|
20
22
|
attr_reader :images, :source_image, :mask, :prompt, :model_id, :size,
|
|
21
23
|
:started_at, :completed_at, :tenant_id, :editor_class,
|
|
22
24
|
:error_class, :error_message
|
|
@@ -38,7 +40,7 @@ module RubyLLM
|
|
|
38
40
|
# @param error_message [String, nil] Error message if failed
|
|
39
41
|
def initialize(images:, source_image:, mask:, prompt:, model_id:, size:,
|
|
40
42
|
started_at:, completed_at:, tenant_id:, editor_class:,
|
|
41
|
-
error_class: nil, error_message: nil)
|
|
43
|
+
error_class: nil, error_message: nil, agent_class_name: nil)
|
|
42
44
|
@images = images
|
|
43
45
|
@source_image = source_image
|
|
44
46
|
@mask = mask
|
|
@@ -52,6 +54,10 @@ module RubyLLM
|
|
|
52
54
|
@error_class = error_class
|
|
53
55
|
@error_message = error_message
|
|
54
56
|
@execution_id = nil
|
|
57
|
+
|
|
58
|
+
# Tracking
|
|
59
|
+
@agent_class_name = agent_class_name
|
|
60
|
+
register_with_tracker
|
|
55
61
|
end
|
|
56
62
|
|
|
57
63
|
# Loads the associated Execution record from the database
|
|
@@ -20,6 +20,8 @@ module RubyLLM
|
|
|
20
20
|
# result.save_all("./logos")
|
|
21
21
|
#
|
|
22
22
|
class ImageGenerationResult
|
|
23
|
+
include Trackable
|
|
24
|
+
|
|
23
25
|
attr_reader :images, :prompt, :model_id, :size, :quality, :style,
|
|
24
26
|
:started_at, :completed_at, :tenant_id, :generator_class,
|
|
25
27
|
:error_class, :error_message, :execution_id
|
|
@@ -40,7 +42,7 @@ module RubyLLM
|
|
|
40
42
|
# @param error_message [String, nil] Error message if failed
|
|
41
43
|
def initialize(images:, prompt:, model_id:, size:, quality:, style:,
|
|
42
44
|
started_at:, completed_at:, tenant_id:, generator_class:,
|
|
43
|
-
error_class: nil, error_message: nil, execution_id: nil)
|
|
45
|
+
error_class: nil, error_message: nil, execution_id: nil, agent_class_name: nil)
|
|
44
46
|
@images = images
|
|
45
47
|
@prompt = prompt
|
|
46
48
|
@model_id = model_id
|
|
@@ -54,6 +56,10 @@ module RubyLLM
|
|
|
54
56
|
@error_class = error_class
|
|
55
57
|
@error_message = error_message
|
|
56
58
|
@execution_id = execution_id
|
|
59
|
+
|
|
60
|
+
# Tracking
|
|
61
|
+
@agent_class_name = agent_class_name
|
|
62
|
+
register_with_tracker
|
|
57
63
|
end
|
|
58
64
|
|
|
59
65
|
# Loads the associated Execution record from the database
|
|
@@ -21,6 +21,8 @@ module RubyLLM
|
|
|
21
21
|
# result.analysis # => Shortcut to analyzer step result
|
|
22
22
|
#
|
|
23
23
|
class ImagePipelineResult
|
|
24
|
+
include Trackable
|
|
25
|
+
|
|
24
26
|
attr_reader :step_results, :started_at, :completed_at, :tenant_id,
|
|
25
27
|
:pipeline_class, :context, :error_class, :error_message
|
|
26
28
|
attr_accessor :execution_id
|
|
@@ -36,7 +38,7 @@ module RubyLLM
|
|
|
36
38
|
# @param error_class [String, nil] Error class name if failed
|
|
37
39
|
# @param error_message [String, nil] Error message if failed
|
|
38
40
|
def initialize(step_results:, started_at:, completed_at:, tenant_id:,
|
|
39
|
-
pipeline_class:, context:, error_class: nil, error_message: nil)
|
|
41
|
+
pipeline_class:, context:, error_class: nil, error_message: nil, agent_class_name: nil)
|
|
40
42
|
@step_results = step_results
|
|
41
43
|
@started_at = started_at
|
|
42
44
|
@completed_at = completed_at
|
|
@@ -46,6 +48,10 @@ module RubyLLM
|
|
|
46
48
|
@error_class = error_class
|
|
47
49
|
@error_message = error_message
|
|
48
50
|
@execution_id = nil
|
|
51
|
+
|
|
52
|
+
# Tracking
|
|
53
|
+
@agent_class_name = agent_class_name
|
|
54
|
+
register_with_tracker
|
|
49
55
|
end
|
|
50
56
|
|
|
51
57
|
# Loads the associated Execution record from the database
|
|
@@ -17,6 +17,8 @@ module RubyLLM
|
|
|
17
17
|
# result.success? # => true
|
|
18
18
|
#
|
|
19
19
|
class ImageTransformResult
|
|
20
|
+
include Trackable
|
|
21
|
+
|
|
20
22
|
attr_reader :images, :source_image, :prompt, :model_id, :size, :strength,
|
|
21
23
|
:started_at, :completed_at, :tenant_id, :transformer_class,
|
|
22
24
|
:error_class, :error_message
|
|
@@ -38,7 +40,7 @@ module RubyLLM
|
|
|
38
40
|
# @param error_message [String, nil] Error message if failed
|
|
39
41
|
def initialize(images:, source_image:, prompt:, model_id:, size:, strength:,
|
|
40
42
|
started_at:, completed_at:, tenant_id:, transformer_class:,
|
|
41
|
-
error_class: nil, error_message: nil)
|
|
43
|
+
error_class: nil, error_message: nil, agent_class_name: nil)
|
|
42
44
|
@images = images
|
|
43
45
|
@source_image = source_image
|
|
44
46
|
@prompt = prompt
|
|
@@ -52,6 +54,10 @@ module RubyLLM
|
|
|
52
54
|
@error_class = error_class
|
|
53
55
|
@error_message = error_message
|
|
54
56
|
@execution_id = nil
|
|
57
|
+
|
|
58
|
+
# Tracking
|
|
59
|
+
@agent_class_name = agent_class_name
|
|
60
|
+
register_with_tracker
|
|
55
61
|
end
|
|
56
62
|
|
|
57
63
|
# Loads the associated Execution record from the database
|
|
@@ -15,6 +15,8 @@ module RubyLLM
|
|
|
15
15
|
# result.success? # => true
|
|
16
16
|
#
|
|
17
17
|
class ImageUpscaleResult
|
|
18
|
+
include Trackable
|
|
19
|
+
|
|
18
20
|
attr_reader :image, :source_image, :model_id, :scale, :output_size, :face_enhance,
|
|
19
21
|
:started_at, :completed_at, :tenant_id, :upscaler_class,
|
|
20
22
|
:error_class, :error_message
|
|
@@ -36,7 +38,7 @@ module RubyLLM
|
|
|
36
38
|
# @param error_message [String, nil] Error message if failed
|
|
37
39
|
def initialize(image:, source_image:, model_id:, scale:, output_size:, face_enhance:,
|
|
38
40
|
started_at:, completed_at:, tenant_id:, upscaler_class:,
|
|
39
|
-
error_class: nil, error_message: nil)
|
|
41
|
+
error_class: nil, error_message: nil, agent_class_name: nil)
|
|
40
42
|
@image = image
|
|
41
43
|
@source_image = source_image
|
|
42
44
|
@model_id = model_id
|
|
@@ -50,6 +52,10 @@ module RubyLLM
|
|
|
50
52
|
@error_class = error_class
|
|
51
53
|
@error_message = error_message
|
|
52
54
|
@execution_id = nil
|
|
55
|
+
|
|
56
|
+
# Tracking
|
|
57
|
+
@agent_class_name = agent_class_name
|
|
58
|
+
register_with_tracker
|
|
53
59
|
end
|
|
54
60
|
|
|
55
61
|
# Loads the associated Execution record from the database
|
|
@@ -14,6 +14,8 @@ module RubyLLM
|
|
|
14
14
|
# result.success? # => true
|
|
15
15
|
#
|
|
16
16
|
class ImageVariationResult
|
|
17
|
+
include Trackable
|
|
18
|
+
|
|
17
19
|
attr_reader :images, :source_image, :model_id, :size, :variation_strength,
|
|
18
20
|
:started_at, :completed_at, :tenant_id, :variator_class,
|
|
19
21
|
:error_class, :error_message
|
|
@@ -34,7 +36,7 @@ module RubyLLM
|
|
|
34
36
|
# @param error_message [String, nil] Error message if failed
|
|
35
37
|
def initialize(images:, source_image:, model_id:, size:, variation_strength:,
|
|
36
38
|
started_at:, completed_at:, tenant_id:, variator_class:,
|
|
37
|
-
error_class: nil, error_message: nil)
|
|
39
|
+
error_class: nil, error_message: nil, agent_class_name: nil)
|
|
38
40
|
@images = images
|
|
39
41
|
@source_image = source_image
|
|
40
42
|
@model_id = model_id
|
|
@@ -47,6 +49,10 @@ module RubyLLM
|
|
|
47
49
|
@error_class = error_class
|
|
48
50
|
@error_message = error_message
|
|
49
51
|
@execution_id = nil
|
|
52
|
+
|
|
53
|
+
# Tracking
|
|
54
|
+
@agent_class_name = agent_class_name
|
|
55
|
+
register_with_tracker
|
|
50
56
|
end
|
|
51
57
|
|
|
52
58
|
# Loads the associated Execution record from the database
|
|
@@ -23,6 +23,8 @@ module RubyLLM
|
|
|
23
23
|
#
|
|
24
24
|
# @api public
|
|
25
25
|
class SpeechResult
|
|
26
|
+
include Trackable
|
|
27
|
+
|
|
26
28
|
# @!group Audio Content
|
|
27
29
|
|
|
28
30
|
# @!attribute [r] audio
|
|
@@ -229,6 +231,10 @@ module RubyLLM
|
|
|
229
231
|
|
|
230
232
|
# Execution record
|
|
231
233
|
@execution_id = attributes[:execution_id]
|
|
234
|
+
|
|
235
|
+
# Tracking
|
|
236
|
+
@agent_class_name = attributes[:agent_class_name]
|
|
237
|
+
register_with_tracker
|
|
232
238
|
end
|
|
233
239
|
|
|
234
240
|
# Loads the associated Execution record from the database
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Agents
|
|
5
|
+
# Mixin that registers a result object with the active Tracker.
|
|
6
|
+
#
|
|
7
|
+
# Included in every result class so that RubyLLM::Agents.track
|
|
8
|
+
# can collect results automatically.
|
|
9
|
+
#
|
|
10
|
+
# @api private
|
|
11
|
+
module Trackable
|
|
12
|
+
def self.included(base)
|
|
13
|
+
base.attr_reader :agent_class_name unless base.method_defined?(:agent_class_name)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Call from the end of initialize to register with the active tracker
|
|
19
|
+
def register_with_tracker
|
|
20
|
+
tracker = Thread.current[:ruby_llm_agents_tracker]
|
|
21
|
+
tracker << self if tracker
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -26,6 +26,8 @@ module RubyLLM
|
|
|
26
26
|
#
|
|
27
27
|
# @api public
|
|
28
28
|
class TranscriptionResult
|
|
29
|
+
include Trackable
|
|
30
|
+
|
|
29
31
|
# @!group Content
|
|
30
32
|
|
|
31
33
|
# @!attribute [r] text
|
|
@@ -250,6 +252,10 @@ module RubyLLM
|
|
|
250
252
|
|
|
251
253
|
# Execution record
|
|
252
254
|
@execution_id = attributes[:execution_id]
|
|
255
|
+
|
|
256
|
+
# Tracking
|
|
257
|
+
@agent_class_name = attributes[:agent_class_name]
|
|
258
|
+
register_with_tracker
|
|
253
259
|
end
|
|
254
260
|
|
|
255
261
|
# Loads the associated Execution record from the database
|
|
@@ -337,11 +337,14 @@ module RubyLLM
|
|
|
337
337
|
embed_options = {model: context&.model || resolved_model}
|
|
338
338
|
embed_options[:dimensions] = resolved_dimensions if resolved_dimensions
|
|
339
339
|
|
|
340
|
-
#
|
|
340
|
+
# Use scoped RubyLLM::Context for thread-safe per-tenant API keys.
|
|
341
|
+
# RubyLLM::Context#embed creates an Embedding with the scoped config.
|
|
341
342
|
llm_ctx = context&.llm
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
343
|
+
response = if llm_ctx.is_a?(RubyLLM::Context)
|
|
344
|
+
llm_ctx.embed(preprocessed, **embed_options)
|
|
345
|
+
else
|
|
346
|
+
RubyLLM.embed(preprocessed, **embed_options)
|
|
347
|
+
end
|
|
345
348
|
|
|
346
349
|
# ruby_llm returns vectors as an array (even for single text)
|
|
347
350
|
vectors = response.vectors
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Agents
|
|
5
|
+
# Aggregated read-only report returned by RubyLLM::Agents.track.
|
|
6
|
+
#
|
|
7
|
+
# Provides totals and breakdowns across all agent calls made
|
|
8
|
+
# inside the tracked block.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# report = RubyLLM::Agents.track do
|
|
12
|
+
# TranscribeAgent.call(with: audio_path)
|
|
13
|
+
# ChatAgent.call(message: "hello")
|
|
14
|
+
# end
|
|
15
|
+
# report.total_cost # => 0.0078
|
|
16
|
+
# report.call_count # => 2
|
|
17
|
+
#
|
|
18
|
+
# @api public
|
|
19
|
+
class TrackReport
|
|
20
|
+
attr_reader :value, :error, :results, :request_id
|
|
21
|
+
attr_reader :started_at, :completed_at
|
|
22
|
+
|
|
23
|
+
def initialize(value:, error:, results:, request_id:, started_at:, completed_at:)
|
|
24
|
+
@value = value
|
|
25
|
+
@error = error
|
|
26
|
+
@results = results.freeze
|
|
27
|
+
@request_id = request_id
|
|
28
|
+
@started_at = started_at
|
|
29
|
+
@completed_at = completed_at
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def successful?
|
|
33
|
+
@error.nil?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def failed?
|
|
37
|
+
!successful?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def call_count
|
|
41
|
+
@results.size
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def total_cost
|
|
45
|
+
@results.sum { |r| r.total_cost || 0 }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def input_cost
|
|
49
|
+
@results.sum { |r| r.input_cost || 0 }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def output_cost
|
|
53
|
+
@results.sum { |r| r.output_cost || 0 }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def total_tokens
|
|
57
|
+
@results.sum { |r| r.total_tokens }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def input_tokens
|
|
61
|
+
@results.sum { |r| r.input_tokens || 0 }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def output_tokens
|
|
65
|
+
@results.sum { |r| r.output_tokens || 0 }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def duration_ms
|
|
69
|
+
return nil unless @started_at && @completed_at
|
|
70
|
+
((@completed_at - @started_at) * 1000).to_i
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def all_successful?
|
|
74
|
+
@results.all?(&:success?)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def any_errors?
|
|
78
|
+
@results.any?(&:error?)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def errors
|
|
82
|
+
@results.select(&:error?)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def successful
|
|
86
|
+
@results.select(&:success?)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def models_used
|
|
90
|
+
@results.filter_map(&:chosen_model_id).uniq
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def cost_breakdown
|
|
94
|
+
@results.map do |r|
|
|
95
|
+
{
|
|
96
|
+
agent: r.respond_to?(:agent_class_name) ? r.agent_class_name : nil,
|
|
97
|
+
model: r.chosen_model_id,
|
|
98
|
+
cost: r.total_cost || 0,
|
|
99
|
+
tokens: r.total_tokens,
|
|
100
|
+
duration_ms: r.duration_ms
|
|
101
|
+
}
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def to_h
|
|
106
|
+
{
|
|
107
|
+
successful: successful?,
|
|
108
|
+
value: value,
|
|
109
|
+
error: error&.message,
|
|
110
|
+
request_id: request_id,
|
|
111
|
+
call_count: call_count,
|
|
112
|
+
total_cost: total_cost,
|
|
113
|
+
input_cost: input_cost,
|
|
114
|
+
output_cost: output_cost,
|
|
115
|
+
total_tokens: total_tokens,
|
|
116
|
+
input_tokens: input_tokens,
|
|
117
|
+
output_tokens: output_tokens,
|
|
118
|
+
duration_ms: duration_ms,
|
|
119
|
+
started_at: started_at,
|
|
120
|
+
completed_at: completed_at,
|
|
121
|
+
models_used: models_used,
|
|
122
|
+
cost_breakdown: cost_breakdown
|
|
123
|
+
}
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Agents
|
|
5
|
+
# Internal collector used by RubyLLM::Agents.track to accumulate
|
|
6
|
+
# Result objects produced during a tracked block.
|
|
7
|
+
#
|
|
8
|
+
# Not part of the public API — users interact with TrackReport instead.
|
|
9
|
+
#
|
|
10
|
+
# @api private
|
|
11
|
+
class Tracker
|
|
12
|
+
attr_reader :results, :defaults, :request_id, :tags
|
|
13
|
+
|
|
14
|
+
def initialize(defaults: {}, request_id: nil, tags: {})
|
|
15
|
+
@results = []
|
|
16
|
+
@defaults = defaults
|
|
17
|
+
@request_id = request_id || generate_request_id
|
|
18
|
+
@tags = tags
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def <<(result)
|
|
22
|
+
@results << result
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def generate_request_id
|
|
28
|
+
"track_#{SecureRandom.hex(8)}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|