dspy 0.17.0 → 0.18.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 +3 -3
- data/lib/dspy/chain_of_thought.rb +13 -16
- data/lib/dspy/code_act.rb +31 -37
- data/lib/dspy/context.rb +67 -0
- data/lib/dspy/evaluate.rb +20 -17
- data/lib/dspy/lm.rb +72 -37
- data/lib/dspy/memory/memory_compactor.rb +5 -6
- data/lib/dspy/memory/memory_manager.rb +5 -4
- data/lib/dspy/observability.rb +109 -0
- data/lib/dspy/predict.rb +18 -6
- data/lib/dspy/propose/grounded_proposer.rb +13 -12
- data/lib/dspy/re_act.rb +34 -41
- data/lib/dspy/registry/registry_manager.rb +8 -10
- data/lib/dspy/registry/signature_registry.rb +40 -52
- data/lib/dspy/storage/program_storage.rb +28 -37
- data/lib/dspy/storage/storage_manager.rb +3 -4
- data/lib/dspy/teleprompt/teleprompter.rb +11 -12
- data/lib/dspy/teleprompt/utils.rb +24 -22
- data/lib/dspy/version.rb +1 -1
- data/lib/dspy.rb +42 -82
- metadata +31 -24
- data/lib/dspy/instrumentation/event_payload_factory.rb +0 -282
- data/lib/dspy/instrumentation/event_payloads.rb +0 -476
- data/lib/dspy/instrumentation/token_tracker.rb +0 -70
- data/lib/dspy/instrumentation.rb +0 -341
- data/lib/dspy/mixins/instrumentation_helpers.rb +0 -120
- data/lib/dspy/subscribers/langfuse_subscriber.rb +0 -669
- data/lib/dspy/subscribers/logger_subscriber.rb +0 -480
- data/lib/dspy/subscribers/newrelic_subscriber.rb +0 -686
- data/lib/dspy/subscribers/otel_subscriber.rb +0 -537
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'sorbet-runtime'
|
4
|
-
require_relative '../instrumentation'
|
5
4
|
require_relative '../evaluate'
|
6
5
|
require_relative '../example'
|
7
6
|
|
@@ -313,22 +312,22 @@ module DSPy
|
|
313
312
|
# Instrument optimization steps
|
314
313
|
sig { params(step_name: String, payload: T::Hash[Symbol, T.untyped], block: T.proc.returns(T.untyped)).returns(T.untyped) }
|
315
314
|
def instrument_step(step_name, payload = {}, &block)
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
config
|
321
|
-
|
315
|
+
DSPy::Context.with_span(
|
316
|
+
operation: "optimization.#{step_name}",
|
317
|
+
'dspy.module' => 'Teleprompter',
|
318
|
+
'teleprompter.class' => self.class.name,
|
319
|
+
'teleprompter.config' => @config.to_h,
|
320
|
+
**payload
|
321
|
+
) do
|
322
|
+
yield
|
323
|
+
end
|
322
324
|
end
|
323
325
|
|
324
326
|
# Emit optimization events
|
325
327
|
sig { params(event_name: String, payload: T::Hash[Symbol, T.untyped]).void }
|
326
328
|
def emit_event(event_name, payload = {})
|
327
|
-
|
328
|
-
|
329
|
-
Instrumentation.emit(full_event_name, payload.merge({
|
330
|
-
teleprompter_class: self.class.name,
|
331
|
-
timestamp: Time.now.iso8601
|
329
|
+
DSPy.log("optimization.#{event_name}", **payload.merge({
|
330
|
+
'teleprompter.class': self.class.name
|
332
331
|
}))
|
333
332
|
end
|
334
333
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'sorbet-runtime'
|
4
|
-
require_relative '../instrumentation'
|
5
4
|
require_relative '../evaluate'
|
6
5
|
require_relative '../example'
|
7
6
|
require_relative 'data_handler'
|
@@ -104,11 +103,13 @@ module DSPy
|
|
104
103
|
).returns(BootstrapResult)
|
105
104
|
end
|
106
105
|
def self.create_n_fewshot_demo_sets(program, trainset, config: BootstrapConfig.new, metric: nil)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
106
|
+
DSPy::Context.with_span(
|
107
|
+
operation: 'optimization.bootstrap_start',
|
108
|
+
'dspy.module' => 'Bootstrap',
|
109
|
+
'bootstrap.trainset_size' => trainset.size,
|
110
|
+
'bootstrap.max_examples' => config.max_bootstrapped_examples,
|
111
|
+
'bootstrap.num_candidate_sets' => config.num_candidate_sets
|
112
|
+
) do
|
112
113
|
# Convert to typed examples if needed
|
113
114
|
typed_examples = ensure_typed_examples(trainset)
|
114
115
|
|
@@ -172,11 +173,13 @@ module DSPy
|
|
172
173
|
).returns(DSPy::Evaluate::BatchEvaluationResult)
|
173
174
|
end
|
174
175
|
def self.eval_candidate_program_minibatch(program, examples, config, metric)
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
176
|
+
DSPy::Context.with_span(
|
177
|
+
operation: 'optimization.minibatch_evaluation',
|
178
|
+
'dspy.module' => 'Bootstrap',
|
179
|
+
'minibatch.total_examples' => examples.size,
|
180
|
+
'minibatch.size' => config.minibatch_size,
|
181
|
+
'minibatch.num_batches' => (examples.size.to_f / config.minibatch_size).ceil
|
182
|
+
) do
|
180
183
|
# Randomly sample a minibatch for evaluation
|
181
184
|
sample_size = [config.minibatch_size, examples.size].min
|
182
185
|
sampled_examples = examples.sample(sample_size)
|
@@ -340,23 +343,22 @@ module DSPy
|
|
340
343
|
# Emit bootstrap completion event
|
341
344
|
sig { params(statistics: T::Hash[Symbol, T.untyped]).void }
|
342
345
|
def self.emit_bootstrap_complete_event(statistics)
|
343
|
-
|
344
|
-
successful_count
|
345
|
-
failed_count
|
346
|
-
success_rate
|
347
|
-
candidate_sets_created
|
348
|
-
average_set_size
|
346
|
+
DSPy.log('optimization.bootstrap_complete', **{
|
347
|
+
'bootstrap.successful_count' => statistics[:successful_count],
|
348
|
+
'bootstrap.failed_count' => statistics[:failed_count],
|
349
|
+
'bootstrap.success_rate' => statistics[:success_rate],
|
350
|
+
'bootstrap.candidate_sets_created' => statistics[:candidate_sets_created],
|
351
|
+
'bootstrap.average_set_size' => statistics[:average_set_size]
|
349
352
|
})
|
350
353
|
end
|
351
354
|
|
352
355
|
# Emit individual bootstrap example event
|
353
356
|
sig { params(index: Integer, success: T::Boolean, error: T.nilable(String)).void }
|
354
357
|
def self.emit_bootstrap_example_event(index, success, error)
|
355
|
-
|
356
|
-
example_index
|
357
|
-
success
|
358
|
-
error
|
359
|
-
timestamp: Time.now.iso8601
|
358
|
+
DSPy.log('optimization.bootstrap_example', **{
|
359
|
+
'bootstrap.example_index' => index,
|
360
|
+
'bootstrap.success' => success,
|
361
|
+
'bootstrap.error' => error
|
360
362
|
})
|
361
363
|
end
|
362
364
|
|
data/lib/dspy/version.rb
CHANGED
data/lib/dspy.rb
CHANGED
@@ -7,18 +7,11 @@ require 'securerandom'
|
|
7
7
|
require_relative 'dspy/version'
|
8
8
|
require_relative 'dspy/errors'
|
9
9
|
require_relative 'dspy/type_serializer'
|
10
|
+
require_relative 'dspy/observability'
|
11
|
+
require_relative 'dspy/context'
|
10
12
|
|
11
13
|
module DSPy
|
12
14
|
extend Dry::Configurable
|
13
|
-
|
14
|
-
# Timestamp format options for instrumentation events
|
15
|
-
class TimestampFormat < T::Enum
|
16
|
-
enums do
|
17
|
-
ISO8601 = new('iso8601')
|
18
|
-
RFC3339_NANO = new('rfc3339_nano')
|
19
|
-
UNIX_NANO = new('unix_nano')
|
20
|
-
end
|
21
|
-
end
|
22
15
|
|
23
16
|
setting :lm
|
24
17
|
setting :logger, default: Dry.Logger(:dspy, formatter: :string)
|
@@ -35,86 +28,52 @@ module DSPy
|
|
35
28
|
|
36
29
|
# Test mode disables sleeps in retry logic
|
37
30
|
setting :test_mode, default: false
|
38
|
-
|
39
|
-
# Nested instrumentation configuration using proper dry-configurable syntax
|
40
|
-
setting :instrumentation do
|
41
|
-
# Core settings
|
42
|
-
setting :enabled, default: false
|
43
|
-
setting :subscribers, default: []
|
44
|
-
setting :sampling_rate, default: 1.0
|
45
|
-
setting :async_processing, default: false
|
46
|
-
setting :buffer_size, default: 1000
|
47
|
-
setting :flush_interval, default: 30
|
48
|
-
setting :error_reporting, default: false
|
49
|
-
setting :error_service, default: nil
|
50
|
-
setting :sampling_rules, default: {}
|
51
|
-
setting :timestamp_format, default: TimestampFormat::ISO8601
|
52
|
-
|
53
|
-
# Nested correlation ID configuration
|
54
|
-
setting :correlation_id do
|
55
|
-
setting :enabled, default: false
|
56
|
-
setting :header, default: 'X-Correlation-ID'
|
57
|
-
setting :generator, default: -> { SecureRandom.uuid }
|
58
|
-
end
|
59
|
-
|
60
|
-
# Nested logger configuration
|
61
|
-
setting :logger do
|
62
|
-
setting :level, default: :info
|
63
|
-
setting :include_payloads, default: true
|
64
|
-
setting :correlation_id, default: true
|
65
|
-
setting :sampling, default: {}
|
66
|
-
setting :sampling_conditions, default: {}
|
67
|
-
end
|
68
|
-
|
69
|
-
# Nested OpenTelemetry configuration
|
70
|
-
setting :otel do
|
71
|
-
setting :tracer_name, default: 'dspy-ruby'
|
72
|
-
setting :service_name, default: 'dspy-application'
|
73
|
-
setting :service_version, default: DSPy::VERSION
|
74
|
-
setting :endpoint, default: -> { ENV['OTEL_EXPORTER_OTLP_ENDPOINT'] }
|
75
|
-
end
|
76
|
-
|
77
|
-
# Nested New Relic configuration
|
78
|
-
setting :newrelic do
|
79
|
-
setting :app_name, default: 'DSPy Application'
|
80
|
-
setting :license_key, default: -> { ENV['NEW_RELIC_LICENSE_KEY'] }
|
81
|
-
setting :custom_attributes, default: {}
|
82
|
-
end
|
83
|
-
|
84
|
-
# Nested Langfuse configuration
|
85
|
-
setting :langfuse do
|
86
|
-
setting :public_key, default: -> { ENV['LANGFUSE_PUBLIC_KEY'] }
|
87
|
-
setting :secret_key, default: -> { ENV['LANGFUSE_SECRET_KEY'] }
|
88
|
-
setting :host, default: -> { ENV['LANGFUSE_HOST'] }
|
89
|
-
setting :track_tokens, default: true
|
90
|
-
setting :track_costs, default: true
|
91
|
-
setting :track_prompts, default: true
|
92
|
-
end
|
93
|
-
end
|
94
31
|
|
95
32
|
def self.logger
|
96
|
-
|
33
|
+
@logger ||= create_logger
|
97
34
|
end
|
98
35
|
|
99
|
-
|
100
|
-
|
101
|
-
config = self.config.instrumentation
|
36
|
+
def self.log(event, **attributes)
|
37
|
+
return unless logger
|
102
38
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
39
|
+
# Merge context automatically (but don't include span_stack)
|
40
|
+
context = Context.current.dup
|
41
|
+
context.delete(:span_stack)
|
42
|
+
attributes = context.merge(attributes)
|
43
|
+
attributes[:event] = event
|
107
44
|
|
108
|
-
|
109
|
-
|
110
|
-
|
45
|
+
# Use Dry::Logger's structured logging
|
46
|
+
logger.info(attributes)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.create_logger
|
50
|
+
env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
51
|
+
log_output = ENV['DSPY_LOG'] # Allow override
|
111
52
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
53
|
+
case env
|
54
|
+
when 'test'
|
55
|
+
# Test: key=value format to log/test.log (or override)
|
56
|
+
Dry.Logger(:dspy, formatter: :string) do |config|
|
57
|
+
config.add_backend(stream: log_output || "log/test.log")
|
58
|
+
end
|
59
|
+
when 'development'
|
60
|
+
# Development: key=value format to log/development.log (or override)
|
61
|
+
Dry.Logger(:dspy, formatter: :string) do |config|
|
62
|
+
config.add_backend(stream: log_output || "log/development.log")
|
63
|
+
end
|
64
|
+
when 'production', 'staging'
|
65
|
+
# Production: JSON to STDOUT (or override)
|
66
|
+
Dry.Logger(:dspy, formatter: :json) do |config|
|
67
|
+
config.add_backend(stream: log_output || $stdout)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
# Fallback: key=value to STDOUT
|
71
|
+
Dry.Logger(:dspy, formatter: :string) do |config|
|
72
|
+
config.add_backend(stream: log_output || $stdout)
|
73
|
+
end
|
116
74
|
end
|
117
75
|
end
|
76
|
+
|
118
77
|
end
|
119
78
|
|
120
79
|
require_relative 'dspy/module'
|
@@ -138,15 +97,16 @@ require_relative 'dspy/teleprompt/data_handler'
|
|
138
97
|
require_relative 'dspy/propose/grounded_proposer'
|
139
98
|
require_relative 'dspy/teleprompt/simple_optimizer'
|
140
99
|
require_relative 'dspy/teleprompt/mipro_v2'
|
141
|
-
require_relative 'dspy/subscribers/logger_subscriber'
|
142
100
|
require_relative 'dspy/tools'
|
143
101
|
require_relative 'dspy/memory'
|
144
|
-
require_relative 'dspy/instrumentation'
|
145
102
|
require_relative 'dspy/storage/program_storage'
|
146
103
|
require_relative 'dspy/storage/storage_manager'
|
147
104
|
require_relative 'dspy/registry/signature_registry'
|
148
105
|
require_relative 'dspy/registry/registry_manager'
|
149
106
|
|
107
|
+
# Auto-configure observability if Langfuse env vars are present
|
108
|
+
DSPy::Observability.configure!
|
109
|
+
|
150
110
|
# LoggerSubscriber will be lazy-initialized when first accessed
|
151
111
|
|
152
112
|
# Detect potential gem conflicts and warn users
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dspy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vicente Reig Rincón de Arellano
|
@@ -37,20 +37,6 @@ dependencies:
|
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '1.0'
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: dry-monitor
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '1.0'
|
47
|
-
type: :runtime
|
48
|
-
prerelease: false
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '1.0'
|
54
40
|
- !ruby/object:Gem::Dependency
|
55
41
|
name: async
|
56
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -149,6 +135,34 @@ dependencies:
|
|
149
135
|
- - "~>"
|
150
136
|
- !ruby/object:Gem::Version
|
151
137
|
version: '1.2'
|
138
|
+
- !ruby/object:Gem::Dependency
|
139
|
+
name: opentelemetry-sdk
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '1.8'
|
145
|
+
type: :runtime
|
146
|
+
prerelease: false
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '1.8'
|
152
|
+
- !ruby/object:Gem::Dependency
|
153
|
+
name: opentelemetry-exporter-otlp
|
154
|
+
requirement: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0.30'
|
159
|
+
type: :runtime
|
160
|
+
prerelease: false
|
161
|
+
version_requirements: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0.30'
|
152
166
|
description: The Ruby framework for programming with large language models.
|
153
167
|
email:
|
154
168
|
- hey@vicente.services
|
@@ -160,16 +174,13 @@ files:
|
|
160
174
|
- lib/dspy.rb
|
161
175
|
- lib/dspy/chain_of_thought.rb
|
162
176
|
- lib/dspy/code_act.rb
|
177
|
+
- lib/dspy/context.rb
|
163
178
|
- lib/dspy/errors.rb
|
164
179
|
- lib/dspy/evaluate.rb
|
165
180
|
- lib/dspy/example.rb
|
166
181
|
- lib/dspy/few_shot_example.rb
|
167
182
|
- lib/dspy/field.rb
|
168
183
|
- lib/dspy/image.rb
|
169
|
-
- lib/dspy/instrumentation.rb
|
170
|
-
- lib/dspy/instrumentation/event_payload_factory.rb
|
171
|
-
- lib/dspy/instrumentation/event_payloads.rb
|
172
|
-
- lib/dspy/instrumentation/token_tracker.rb
|
173
184
|
- lib/dspy/lm.rb
|
174
185
|
- lib/dspy/lm/adapter.rb
|
175
186
|
- lib/dspy/lm/adapter_factory.rb
|
@@ -200,10 +211,10 @@ files:
|
|
200
211
|
- lib/dspy/memory/memory_manager.rb
|
201
212
|
- lib/dspy/memory/memory_record.rb
|
202
213
|
- lib/dspy/memory/memory_store.rb
|
203
|
-
- lib/dspy/mixins/instrumentation_helpers.rb
|
204
214
|
- lib/dspy/mixins/struct_builder.rb
|
205
215
|
- lib/dspy/mixins/type_coercion.rb
|
206
216
|
- lib/dspy/module.rb
|
217
|
+
- lib/dspy/observability.rb
|
207
218
|
- lib/dspy/predict.rb
|
208
219
|
- lib/dspy/prediction.rb
|
209
220
|
- lib/dspy/prompt.rb
|
@@ -216,10 +227,6 @@ files:
|
|
216
227
|
- lib/dspy/storage/program_storage.rb
|
217
228
|
- lib/dspy/storage/storage_manager.rb
|
218
229
|
- lib/dspy/strategy.rb
|
219
|
-
- lib/dspy/subscribers/langfuse_subscriber.rb
|
220
|
-
- lib/dspy/subscribers/logger_subscriber.rb
|
221
|
-
- lib/dspy/subscribers/newrelic_subscriber.rb
|
222
|
-
- lib/dspy/subscribers/otel_subscriber.rb
|
223
230
|
- lib/dspy/teleprompt/data_handler.rb
|
224
231
|
- lib/dspy/teleprompt/mipro_v2.rb
|
225
232
|
- lib/dspy/teleprompt/simple_optimizer.rb
|
@@ -1,282 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'sorbet-runtime'
|
4
|
-
require_relative 'event_payloads'
|
5
|
-
|
6
|
-
module DSPy
|
7
|
-
module Instrumentation
|
8
|
-
# Factory for creating typed event payloads from hash data
|
9
|
-
module EventPayloadFactory
|
10
|
-
extend T::Sig
|
11
|
-
extend self
|
12
|
-
|
13
|
-
# Create appropriate event struct based on event name
|
14
|
-
sig { params(event_name: String, payload: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
|
15
|
-
def create_event(event_name, payload)
|
16
|
-
case event_name
|
17
|
-
when 'dspy.lm.request'
|
18
|
-
create_lm_request_event(payload)
|
19
|
-
when 'dspy.lm.tokens'
|
20
|
-
create_lm_tokens_event(payload)
|
21
|
-
when 'dspy.lm.response.parsed'
|
22
|
-
create_lm_response_parsed_event(payload)
|
23
|
-
when 'dspy.predict'
|
24
|
-
create_predict_event(payload)
|
25
|
-
when 'dspy.predict.validation_error'
|
26
|
-
create_predict_validation_error_event(payload)
|
27
|
-
when 'dspy.chain_of_thought'
|
28
|
-
create_chain_of_thought_event(payload)
|
29
|
-
when 'dspy.chain_of_thought.reasoning_complete'
|
30
|
-
create_chain_of_thought_reasoning_complete_event(payload)
|
31
|
-
when 'dspy.react.iteration'
|
32
|
-
create_react_iteration_event(payload)
|
33
|
-
when 'dspy.react.tool_call'
|
34
|
-
create_react_tool_call_event(payload)
|
35
|
-
when 'dspy.react.iteration_complete'
|
36
|
-
create_react_iteration_complete_event(payload)
|
37
|
-
when 'dspy.react.max_iterations'
|
38
|
-
create_react_max_iterations_event(payload)
|
39
|
-
when 'dspy.codeact.iteration'
|
40
|
-
create_codeact_iteration_event(payload)
|
41
|
-
when 'dspy.codeact.code_execution'
|
42
|
-
create_codeact_code_execution_event(payload)
|
43
|
-
else
|
44
|
-
# Return original payload for unhandled events
|
45
|
-
payload
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
# LM Request Event
|
52
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(LMRequestEvent) }
|
53
|
-
def create_lm_request_event(payload)
|
54
|
-
# Extract timestamp, handling both timestamp and timestamp_ns keys
|
55
|
-
timestamp = extract_timestamp(payload)
|
56
|
-
|
57
|
-
LMRequestEvent.new(
|
58
|
-
timestamp: timestamp,
|
59
|
-
duration_ms: payload[:duration_ms] || 0.0,
|
60
|
-
cpu_time_ms: payload[:cpu_time_ms] || 0.0,
|
61
|
-
status: payload[:status] || 'success',
|
62
|
-
gen_ai_operation_name: payload[:gen_ai_operation_name] || 'unknown',
|
63
|
-
gen_ai_system: payload[:gen_ai_system] || 'unknown',
|
64
|
-
gen_ai_request_model: payload[:gen_ai_request_model] || 'unknown',
|
65
|
-
signature_class: payload[:signature_class],
|
66
|
-
provider: payload[:provider] || 'unknown',
|
67
|
-
adapter_class: payload[:adapter_class] || 'unknown',
|
68
|
-
input_size: payload[:input_size] || 0,
|
69
|
-
error_type: payload[:error_type],
|
70
|
-
error_message: payload[:error_message]
|
71
|
-
)
|
72
|
-
end
|
73
|
-
|
74
|
-
# Helper to extract timestamp from various formats
|
75
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(String) }
|
76
|
-
def extract_timestamp(payload)
|
77
|
-
if payload[:timestamp]
|
78
|
-
payload[:timestamp]
|
79
|
-
elsif payload[:timestamp_ns]
|
80
|
-
# Convert nanoseconds to ISO8601 for storage in struct
|
81
|
-
Time.at(payload[:timestamp_ns] / 1_000_000_000.0).iso8601
|
82
|
-
else
|
83
|
-
Time.now.iso8601
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# LM Tokens Event
|
88
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(LMTokensEvent) }
|
89
|
-
def create_lm_tokens_event(payload)
|
90
|
-
LMTokensEvent.new(
|
91
|
-
timestamp: extract_timestamp(payload),
|
92
|
-
status: payload[:status] || 'success',
|
93
|
-
input_tokens: payload[:input_tokens] || 0,
|
94
|
-
output_tokens: payload[:output_tokens] || 0,
|
95
|
-
total_tokens: payload[:total_tokens] || 0,
|
96
|
-
gen_ai_system: payload[:gen_ai_system] || 'unknown',
|
97
|
-
gen_ai_request_model: payload[:gen_ai_request_model] || 'unknown',
|
98
|
-
signature_class: payload[:signature_class]
|
99
|
-
)
|
100
|
-
end
|
101
|
-
|
102
|
-
# LM Response Parsed Event
|
103
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(LMResponseParsedEvent) }
|
104
|
-
def create_lm_response_parsed_event(payload)
|
105
|
-
LMResponseParsedEvent.new(
|
106
|
-
timestamp: extract_timestamp(payload),
|
107
|
-
duration_ms: payload[:duration_ms] || 0.0,
|
108
|
-
cpu_time_ms: payload[:cpu_time_ms] || 0.0,
|
109
|
-
status: payload[:status] || 'success',
|
110
|
-
signature_class: payload[:signature_class] || 'unknown',
|
111
|
-
provider: payload[:provider] || 'unknown',
|
112
|
-
success: payload[:success] || false,
|
113
|
-
response_length: payload[:response_length] || 0,
|
114
|
-
parse_type: payload[:parse_type],
|
115
|
-
error_type: payload[:error_type],
|
116
|
-
error_message: payload[:error_message]
|
117
|
-
)
|
118
|
-
end
|
119
|
-
|
120
|
-
# Predict Event
|
121
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(PredictEvent) }
|
122
|
-
def create_predict_event(payload)
|
123
|
-
PredictEvent.new(
|
124
|
-
timestamp: extract_timestamp(payload),
|
125
|
-
duration_ms: payload[:duration_ms] || 0.0,
|
126
|
-
cpu_time_ms: payload[:cpu_time_ms] || 0.0,
|
127
|
-
status: payload[:status] || 'success',
|
128
|
-
signature_class: payload[:signature_class] || 'unknown',
|
129
|
-
module_name: payload[:module_name] || 'unknown',
|
130
|
-
model: payload[:model] || 'unknown',
|
131
|
-
provider: payload[:provider] || 'unknown',
|
132
|
-
input_fields: payload[:input_fields] || [],
|
133
|
-
input_size: payload[:input_size],
|
134
|
-
output_size: payload[:output_size],
|
135
|
-
error_type: payload[:error_type],
|
136
|
-
error_message: payload[:error_message]
|
137
|
-
)
|
138
|
-
end
|
139
|
-
|
140
|
-
# Predict Validation Error Event
|
141
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(PredictValidationErrorEvent) }
|
142
|
-
def create_predict_validation_error_event(payload)
|
143
|
-
PredictValidationErrorEvent.new(
|
144
|
-
timestamp: payload[:timestamp] || Time.now.iso8601,
|
145
|
-
status: payload[:status] || 'error',
|
146
|
-
signature_class: payload[:signature_class] || 'unknown',
|
147
|
-
module_name: payload[:module_name] || 'unknown',
|
148
|
-
field_name: payload[:field_name] || 'unknown',
|
149
|
-
error_message: payload[:error_message] || 'unknown error',
|
150
|
-
retry_count: payload[:retry_count] || 0
|
151
|
-
)
|
152
|
-
end
|
153
|
-
|
154
|
-
# Chain of Thought Event
|
155
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(ChainOfThoughtEvent) }
|
156
|
-
def create_chain_of_thought_event(payload)
|
157
|
-
ChainOfThoughtEvent.new(
|
158
|
-
timestamp: extract_timestamp(payload),
|
159
|
-
duration_ms: payload[:duration_ms] || 0.0,
|
160
|
-
cpu_time_ms: payload[:cpu_time_ms] || 0.0,
|
161
|
-
status: payload[:status] || 'success',
|
162
|
-
signature_class: payload[:signature_class] || 'unknown',
|
163
|
-
module_name: payload[:module_name] || 'unknown',
|
164
|
-
model: payload[:model] || 'unknown',
|
165
|
-
provider: payload[:provider] || 'unknown',
|
166
|
-
reasoning_length: payload[:reasoning_length],
|
167
|
-
answer_length: payload[:answer_length],
|
168
|
-
error_type: payload[:error_type],
|
169
|
-
error_message: payload[:error_message]
|
170
|
-
)
|
171
|
-
end
|
172
|
-
|
173
|
-
# Chain of Thought Reasoning Complete Event
|
174
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(ChainOfThoughtReasoningCompleteEvent) }
|
175
|
-
def create_chain_of_thought_reasoning_complete_event(payload)
|
176
|
-
ChainOfThoughtReasoningCompleteEvent.new(
|
177
|
-
timestamp: payload[:timestamp] || Time.now.iso8601,
|
178
|
-
status: payload[:status] || 'success',
|
179
|
-
signature_class: payload[:signature_class] || 'unknown',
|
180
|
-
module_name: payload[:module_name] || 'unknown',
|
181
|
-
reasoning_length: payload[:reasoning_length] || 0,
|
182
|
-
answer_present: payload[:answer_present] || false
|
183
|
-
)
|
184
|
-
end
|
185
|
-
|
186
|
-
# ReAct Iteration Event
|
187
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(ReactIterationEvent) }
|
188
|
-
def create_react_iteration_event(payload)
|
189
|
-
ReactIterationEvent.new(
|
190
|
-
timestamp: payload[:timestamp] || Time.now.iso8601,
|
191
|
-
duration_ms: payload[:duration_ms] || 0.0,
|
192
|
-
cpu_time_ms: payload[:cpu_time_ms] || 0.0,
|
193
|
-
status: payload[:status] || 'success',
|
194
|
-
iteration: payload[:iteration] || 0,
|
195
|
-
max_iterations: payload[:max_iterations] || 5,
|
196
|
-
history_length: payload[:history_length] || 0,
|
197
|
-
tools_used_so_far: payload[:tools_used_so_far] || [],
|
198
|
-
error_type: payload[:error_type],
|
199
|
-
error_message: payload[:error_message]
|
200
|
-
)
|
201
|
-
end
|
202
|
-
|
203
|
-
# ReAct Tool Call Event
|
204
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(ReactToolCallEvent) }
|
205
|
-
def create_react_tool_call_event(payload)
|
206
|
-
ReactToolCallEvent.new(
|
207
|
-
timestamp: payload[:timestamp] || Time.now.iso8601,
|
208
|
-
duration_ms: payload[:duration_ms] || 0.0,
|
209
|
-
cpu_time_ms: payload[:cpu_time_ms] || 0.0,
|
210
|
-
status: payload[:status] || 'success',
|
211
|
-
iteration: payload[:iteration] || 0,
|
212
|
-
tool_name: payload[:tool_name] || 'unknown',
|
213
|
-
tool_input: payload[:tool_input],
|
214
|
-
error_type: payload[:error_type],
|
215
|
-
error_message: payload[:error_message]
|
216
|
-
)
|
217
|
-
end
|
218
|
-
|
219
|
-
# ReAct Iteration Complete Event
|
220
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(ReactIterationCompleteEvent) }
|
221
|
-
def create_react_iteration_complete_event(payload)
|
222
|
-
ReactIterationCompleteEvent.new(
|
223
|
-
timestamp: payload[:timestamp] || Time.now.iso8601,
|
224
|
-
status: payload[:status] || 'success',
|
225
|
-
iteration: payload[:iteration] || 0,
|
226
|
-
thought: payload[:thought] || '',
|
227
|
-
action: payload[:action] || '',
|
228
|
-
action_input: payload[:action_input],
|
229
|
-
observation: payload[:observation] || '',
|
230
|
-
tools_used: payload[:tools_used] || []
|
231
|
-
)
|
232
|
-
end
|
233
|
-
|
234
|
-
# ReAct Max Iterations Event
|
235
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(ReactMaxIterationsEvent) }
|
236
|
-
def create_react_max_iterations_event(payload)
|
237
|
-
ReactMaxIterationsEvent.new(
|
238
|
-
timestamp: payload[:timestamp] || Time.now.iso8601,
|
239
|
-
status: payload[:status] || 'warning',
|
240
|
-
iteration_count: payload[:iteration_count] || 0,
|
241
|
-
max_iterations: payload[:max_iterations] || 5,
|
242
|
-
tools_used: payload[:tools_used] || [],
|
243
|
-
final_history_length: payload[:final_history_length] || 0
|
244
|
-
)
|
245
|
-
end
|
246
|
-
|
247
|
-
# CodeAct Iteration Event
|
248
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(CodeActIterationEvent) }
|
249
|
-
def create_codeact_iteration_event(payload)
|
250
|
-
CodeActIterationEvent.new(
|
251
|
-
timestamp: payload[:timestamp] || Time.now.iso8601,
|
252
|
-
duration_ms: payload[:duration_ms] || 0.0,
|
253
|
-
cpu_time_ms: payload[:cpu_time_ms] || 0.0,
|
254
|
-
status: payload[:status] || 'success',
|
255
|
-
iteration: payload[:iteration] || 0,
|
256
|
-
max_iterations: payload[:max_iterations] || 5,
|
257
|
-
history_length: payload[:history_length] || 0,
|
258
|
-
code_blocks_executed: payload[:code_blocks_executed] || 0,
|
259
|
-
error_type: payload[:error_type],
|
260
|
-
error_message: payload[:error_message]
|
261
|
-
)
|
262
|
-
end
|
263
|
-
|
264
|
-
# CodeAct Code Execution Event
|
265
|
-
sig { params(payload: T::Hash[Symbol, T.untyped]).returns(CodeActCodeExecutionEvent) }
|
266
|
-
def create_codeact_code_execution_event(payload)
|
267
|
-
CodeActCodeExecutionEvent.new(
|
268
|
-
timestamp: payload[:timestamp] || Time.now.iso8601,
|
269
|
-
duration_ms: payload[:duration_ms] || 0.0,
|
270
|
-
cpu_time_ms: payload[:cpu_time_ms] || 0.0,
|
271
|
-
status: payload[:status] || 'success',
|
272
|
-
iteration: payload[:iteration] || 0,
|
273
|
-
code_type: payload[:code_type] || 'unknown',
|
274
|
-
code_length: payload[:code_length] || 0,
|
275
|
-
execution_success: payload[:execution_success] || false,
|
276
|
-
error_type: payload[:error_type],
|
277
|
-
error_message: payload[:error_message]
|
278
|
-
)
|
279
|
-
end
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|