dspy 0.34.2 → 0.34.4
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 +8 -16
- data/lib/dspy/chain_of_thought.rb +3 -2
- data/lib/dspy/context.rb +70 -21
- data/lib/dspy/evals/version.rb +1 -1
- data/lib/dspy/evals.rb +42 -31
- data/lib/dspy/events.rb +2 -3
- data/lib/dspy/example.rb +1 -1
- data/lib/dspy/lm/adapter.rb +39 -0
- data/lib/dspy/lm/json_strategy.rb +28 -67
- data/lib/dspy/lm/message.rb +1 -1
- data/lib/dspy/lm/response.rb +2 -2
- data/lib/dspy/lm/usage.rb +35 -10
- data/lib/dspy/lm.rb +22 -51
- data/lib/dspy/mixins/type_coercion.rb +256 -35
- data/lib/dspy/module.rb +203 -31
- data/lib/dspy/predict.rb +33 -6
- data/lib/dspy/prediction.rb +25 -58
- data/lib/dspy/prompt.rb +52 -76
- data/lib/dspy/propose/dataset_summary_generator.rb +1 -1
- data/lib/dspy/propose/grounded_proposer.rb +3 -3
- data/lib/dspy/re_act.rb +159 -196
- data/lib/dspy/registry/signature_registry.rb +3 -3
- data/lib/dspy/ruby_llm/lm/adapters/ruby_llm_adapter.rb +1 -27
- data/lib/dspy/schema/sorbet_json_schema.rb +7 -6
- data/lib/dspy/schema/version.rb +1 -1
- data/lib/dspy/schema_adapters.rb +1 -1
- data/lib/dspy/signature.rb +4 -5
- data/lib/dspy/storage/program_storage.rb +2 -2
- data/lib/dspy/structured_outputs_prompt.rb +4 -4
- data/lib/dspy/teleprompt/utils.rb +2 -2
- data/lib/dspy/tools/github_cli_toolset.rb +7 -7
- data/lib/dspy/tools/text_processing_toolset.rb +2 -2
- data/lib/dspy/tools/toolset.rb +1 -1
- data/lib/dspy/utils/serialization.rb +2 -6
- data/lib/dspy/version.rb +1 -1
- data/lib/dspy.rb +50 -5
- metadata +7 -26
- data/lib/dspy/events/subscriber_mixin.rb +0 -79
- data/lib/dspy/events/subscribers.rb +0 -43
- data/lib/dspy/memory/embedding_engine.rb +0 -68
- data/lib/dspy/memory/in_memory_store.rb +0 -216
- data/lib/dspy/memory/local_embedding_engine.rb +0 -244
- data/lib/dspy/memory/memory_compactor.rb +0 -298
- data/lib/dspy/memory/memory_manager.rb +0 -266
- data/lib/dspy/memory/memory_record.rb +0 -163
- data/lib/dspy/memory/memory_store.rb +0 -90
- data/lib/dspy/memory.rb +0 -30
- data/lib/dspy/tools/memory_toolset.rb +0 -117
|
@@ -198,7 +198,7 @@ module DSPy
|
|
|
198
198
|
emit_save_complete_event(saved_program)
|
|
199
199
|
saved_program
|
|
200
200
|
|
|
201
|
-
rescue => error
|
|
201
|
+
rescue StandardError => error
|
|
202
202
|
emit_save_error_event(program_id, error)
|
|
203
203
|
raise
|
|
204
204
|
end
|
|
@@ -223,7 +223,7 @@ module DSPy
|
|
|
223
223
|
emit_load_complete_event(saved_program)
|
|
224
224
|
saved_program
|
|
225
225
|
|
|
226
|
-
rescue => error
|
|
226
|
+
rescue StandardError => error
|
|
227
227
|
emit_load_error_event(program_id, error)
|
|
228
228
|
nil
|
|
229
229
|
end
|
|
@@ -16,12 +16,12 @@ module DSPy
|
|
|
16
16
|
output_schema: T::Hash[Symbol, T.untyped],
|
|
17
17
|
few_shot_examples: T::Array[T.untyped],
|
|
18
18
|
signature_class_name: T.nilable(String),
|
|
19
|
-
schema_format: Symbol,
|
|
19
|
+
schema_format: T.nilable(Symbol),
|
|
20
20
|
signature_class: T.nilable(T.class_of(Signature)),
|
|
21
|
-
data_format: Symbol
|
|
21
|
+
data_format: T.nilable(Symbol)
|
|
22
22
|
).void
|
|
23
23
|
end
|
|
24
|
-
def initialize(instruction:, input_schema:, output_schema:, few_shot_examples: [], signature_class_name: nil, schema_format:
|
|
24
|
+
def initialize(instruction:, input_schema:, output_schema:, few_shot_examples: [], signature_class_name: nil, schema_format: nil, signature_class: nil, data_format: nil)
|
|
25
25
|
normalized_examples = few_shot_examples.map do |example|
|
|
26
26
|
case example
|
|
27
27
|
when FewShotExample
|
|
@@ -80,7 +80,7 @@ module DSPy
|
|
|
80
80
|
|
|
81
81
|
sections << "## Input Values"
|
|
82
82
|
sections << "```json"
|
|
83
|
-
sections << JSON.pretty_generate(
|
|
83
|
+
sections << JSON.pretty_generate(DSPy::Utils::Serialization.deep_serialize(input_values))
|
|
84
84
|
sections << "```"
|
|
85
85
|
|
|
86
86
|
sections.join("\n")
|
|
@@ -360,7 +360,7 @@ module DSPy
|
|
|
360
360
|
)
|
|
361
361
|
successful_demos << demo
|
|
362
362
|
end
|
|
363
|
-
rescue => e
|
|
363
|
+
rescue StandardError => e
|
|
364
364
|
# Continue on errors
|
|
365
365
|
DSPy.logger.warn("Bootstrap error: #{e.message}") if DSPy.logger
|
|
366
366
|
end
|
|
@@ -513,7 +513,7 @@ module DSPy
|
|
|
513
513
|
emit_bootstrap_example_event(index, false, "Prediction did not match expected output")
|
|
514
514
|
end
|
|
515
515
|
|
|
516
|
-
rescue => error
|
|
516
|
+
rescue StandardError => error
|
|
517
517
|
error_count += 1
|
|
518
518
|
failed << example
|
|
519
519
|
emit_bootstrap_example_event(index, false, error.message)
|
|
@@ -105,7 +105,7 @@ module DSPy
|
|
|
105
105
|
else
|
|
106
106
|
"Failed to list issues: #{result[:error]}"
|
|
107
107
|
end
|
|
108
|
-
rescue => e
|
|
108
|
+
rescue StandardError => e
|
|
109
109
|
"Error listing issues: #{e.message}"
|
|
110
110
|
end
|
|
111
111
|
|
|
@@ -140,7 +140,7 @@ module DSPy
|
|
|
140
140
|
else
|
|
141
141
|
"Failed to list pull requests: #{result[:error]}"
|
|
142
142
|
end
|
|
143
|
-
rescue => e
|
|
143
|
+
rescue StandardError => e
|
|
144
144
|
"Error listing pull requests: #{e.message}"
|
|
145
145
|
end
|
|
146
146
|
|
|
@@ -159,7 +159,7 @@ module DSPy
|
|
|
159
159
|
else
|
|
160
160
|
"Failed to get issue: #{result[:error]}"
|
|
161
161
|
end
|
|
162
|
-
rescue => e
|
|
162
|
+
rescue StandardError => e
|
|
163
163
|
"Error getting issue: #{e.message}"
|
|
164
164
|
end
|
|
165
165
|
|
|
@@ -178,7 +178,7 @@ module DSPy
|
|
|
178
178
|
else
|
|
179
179
|
"Failed to get pull request: #{result[:error]}"
|
|
180
180
|
end
|
|
181
|
-
rescue => e
|
|
181
|
+
rescue StandardError => e
|
|
182
182
|
"Error getting pull request: #{e.message}"
|
|
183
183
|
end
|
|
184
184
|
|
|
@@ -214,7 +214,7 @@ module DSPy
|
|
|
214
214
|
else
|
|
215
215
|
"API request failed: #{result[:error]}"
|
|
216
216
|
end
|
|
217
|
-
rescue => e
|
|
217
|
+
rescue StandardError => e
|
|
218
218
|
"Error making API request: #{e.message}"
|
|
219
219
|
end
|
|
220
220
|
|
|
@@ -231,7 +231,7 @@ module DSPy
|
|
|
231
231
|
else
|
|
232
232
|
"Failed to fetch traffic views: #{result[:error]}"
|
|
233
233
|
end
|
|
234
|
-
rescue => e
|
|
234
|
+
rescue StandardError => e
|
|
235
235
|
"Error fetching traffic views: #{e.message}"
|
|
236
236
|
end
|
|
237
237
|
|
|
@@ -248,7 +248,7 @@ module DSPy
|
|
|
248
248
|
else
|
|
249
249
|
"Failed to fetch traffic clones: #{result[:error]}"
|
|
250
250
|
end
|
|
251
|
-
rescue => e
|
|
251
|
+
rescue StandardError => e
|
|
252
252
|
"Error fetching traffic clones: #{e.message}"
|
|
253
253
|
end
|
|
254
254
|
|
|
@@ -52,7 +52,7 @@ module DSPy
|
|
|
52
52
|
else
|
|
53
53
|
result
|
|
54
54
|
end
|
|
55
|
-
rescue => e
|
|
55
|
+
rescue StandardError => e
|
|
56
56
|
"Error running grep: #{e.message}"
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -92,7 +92,7 @@ module DSPy
|
|
|
92
92
|
else
|
|
93
93
|
result
|
|
94
94
|
end
|
|
95
|
-
rescue => e
|
|
95
|
+
rescue StandardError => e
|
|
96
96
|
"Error running ripgrep: #{e.message}"
|
|
97
97
|
end
|
|
98
98
|
|
data/lib/dspy/tools/toolset.rb
CHANGED
|
@@ -13,6 +13,8 @@ module DSPy
|
|
|
13
13
|
when T::Struct
|
|
14
14
|
# Use the serialize method to convert to a plain hash
|
|
15
15
|
deep_serialize(obj.serialize)
|
|
16
|
+
when T::Enum
|
|
17
|
+
obj.serialize
|
|
16
18
|
when Hash
|
|
17
19
|
# Recursively serialize hash values
|
|
18
20
|
obj.transform_values { |v| deep_serialize(v) }
|
|
@@ -24,12 +26,6 @@ module DSPy
|
|
|
24
26
|
obj
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
|
-
|
|
28
|
-
# Serializes an object to JSON with proper T::Struct handling
|
|
29
|
-
sig { params(obj: T.untyped).returns(String) }
|
|
30
|
-
def self.to_json(obj)
|
|
31
|
-
deep_serialize(obj).to_json
|
|
32
|
-
end
|
|
33
29
|
end
|
|
34
30
|
end
|
|
35
31
|
end
|
data/lib/dspy/version.rb
CHANGED
data/lib/dspy.rb
CHANGED
|
@@ -141,7 +141,7 @@ module DSPy
|
|
|
141
141
|
# Events are instant moments in time, not ongoing operations
|
|
142
142
|
span = DSPy::Observability.start_span(event_name, flattened_attributes)
|
|
143
143
|
DSPy::Observability.finish_span(span) if span
|
|
144
|
-
rescue => e
|
|
144
|
+
rescue StandardError => e
|
|
145
145
|
# Log error but don't let it break the event system
|
|
146
146
|
# Use emit_log directly to avoid infinite recursion
|
|
147
147
|
emit_log('event.span_creation_error', {
|
|
@@ -159,13 +159,61 @@ module DSPy
|
|
|
159
159
|
if value.is_a?(Hash)
|
|
160
160
|
flatten_attributes(value, new_key, result)
|
|
161
161
|
else
|
|
162
|
-
result[new_key] = value
|
|
162
|
+
result[new_key] = sanitize_event_attribute_value(value)
|
|
163
163
|
end
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
result
|
|
167
167
|
end
|
|
168
168
|
|
|
169
|
+
def self.sanitize_event_attribute_value(value)
|
|
170
|
+
return value if primitive_event_attribute_value?(value)
|
|
171
|
+
|
|
172
|
+
if value.is_a?(Array)
|
|
173
|
+
return value if homogeneous_primitive_array?(value)
|
|
174
|
+
return JSON.generate(value.map { |item| normalize_event_json_value(item) })
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
if value.is_a?(Hash)
|
|
178
|
+
return JSON.generate(normalize_event_json_value(value))
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
if value.respond_to?(:to_h)
|
|
182
|
+
return JSON.generate(normalize_event_json_value(value.to_h))
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
value.respond_to?(:to_json) ? value.to_json : value.to_s
|
|
186
|
+
rescue StandardError
|
|
187
|
+
value.to_s
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def self.primitive_event_attribute_value?(value)
|
|
191
|
+
value.nil? || value.is_a?(String) || value.is_a?(Integer) || value.is_a?(Float) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def self.homogeneous_primitive_array?(value)
|
|
195
|
+
return true if value.empty?
|
|
196
|
+
return false unless value.all? { |item| primitive_event_attribute_value?(item) }
|
|
197
|
+
|
|
198
|
+
value.map(&:class).uniq.size == 1
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def self.normalize_event_json_value(value)
|
|
202
|
+
if primitive_event_attribute_value?(value)
|
|
203
|
+
value
|
|
204
|
+
elsif value.is_a?(Array)
|
|
205
|
+
value.map { |item| normalize_event_json_value(item) }
|
|
206
|
+
elsif value.is_a?(Hash)
|
|
207
|
+
value.each_with_object({}) do |(k, v), acc|
|
|
208
|
+
acc[k.to_s] = normalize_event_json_value(v)
|
|
209
|
+
end
|
|
210
|
+
elsif value.respond_to?(:to_h)
|
|
211
|
+
normalize_event_json_value(value.to_h)
|
|
212
|
+
else
|
|
213
|
+
value.to_s
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
169
217
|
def self.create_logger
|
|
170
218
|
env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
|
171
219
|
log_output = ENV['DSPY_LOG'] # Allow override
|
|
@@ -221,8 +269,6 @@ require_relative 'dspy/lm'
|
|
|
221
269
|
require_relative 'dspy/image'
|
|
222
270
|
require_relative 'dspy/prediction'
|
|
223
271
|
require_relative 'dspy/predict'
|
|
224
|
-
require_relative 'dspy/events/subscribers'
|
|
225
|
-
require_relative 'dspy/events/subscriber_mixin'
|
|
226
272
|
require_relative 'dspy/chain_of_thought'
|
|
227
273
|
require_relative 'dspy/re_act'
|
|
228
274
|
require_relative 'dspy/evals'
|
|
@@ -248,7 +294,6 @@ begin
|
|
|
248
294
|
rescue LoadError
|
|
249
295
|
end
|
|
250
296
|
require_relative 'dspy/tools'
|
|
251
|
-
require_relative 'dspy/memory'
|
|
252
297
|
|
|
253
298
|
begin
|
|
254
299
|
require 'dspy/datasets'
|
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.34.
|
|
4
|
+
version: 0.34.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vicente Reig Rincón de Arellano
|
|
@@ -100,6 +100,9 @@ dependencies:
|
|
|
100
100
|
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
102
|
version: '0.5'
|
|
103
|
+
- - ">="
|
|
104
|
+
- !ruby/object:Gem::Version
|
|
105
|
+
version: 0.5.1
|
|
103
106
|
type: :runtime
|
|
104
107
|
prerelease: false
|
|
105
108
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -107,6 +110,9 @@ dependencies:
|
|
|
107
110
|
- - "~>"
|
|
108
111
|
- !ruby/object:Gem::Version
|
|
109
112
|
version: '0.5'
|
|
113
|
+
- - ">="
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: 0.5.1
|
|
110
116
|
- !ruby/object:Gem::Dependency
|
|
111
117
|
name: sorbet-toon
|
|
112
118
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -135,20 +141,6 @@ dependencies:
|
|
|
135
141
|
- - "~>"
|
|
136
142
|
- !ruby/object:Gem::Version
|
|
137
143
|
version: 1.0.0
|
|
138
|
-
- !ruby/object:Gem::Dependency
|
|
139
|
-
name: informers
|
|
140
|
-
requirement: !ruby/object:Gem::Requirement
|
|
141
|
-
requirements:
|
|
142
|
-
- - "~>"
|
|
143
|
-
- !ruby/object:Gem::Version
|
|
144
|
-
version: '1.2'
|
|
145
|
-
type: :runtime
|
|
146
|
-
prerelease: false
|
|
147
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
-
requirements:
|
|
149
|
-
- - "~>"
|
|
150
|
-
- !ruby/object:Gem::Version
|
|
151
|
-
version: '1.2'
|
|
152
144
|
description: The Ruby framework for programming with large language models. DSPy.rb
|
|
153
145
|
brings structured LLM programming to Ruby developers. Instead of wrestling with
|
|
154
146
|
prompt strings and parsing responses, you define typed signatures using idiomatic
|
|
@@ -170,8 +162,6 @@ files:
|
|
|
170
162
|
- lib/dspy/evals.rb
|
|
171
163
|
- lib/dspy/evals/version.rb
|
|
172
164
|
- lib/dspy/events.rb
|
|
173
|
-
- lib/dspy/events/subscriber_mixin.rb
|
|
174
|
-
- lib/dspy/events/subscribers.rb
|
|
175
165
|
- lib/dspy/events/types.rb
|
|
176
166
|
- lib/dspy/example.rb
|
|
177
167
|
- lib/dspy/ext/struct_descriptions.rb
|
|
@@ -189,14 +179,6 @@ files:
|
|
|
189
179
|
- lib/dspy/lm/response.rb
|
|
190
180
|
- lib/dspy/lm/usage.rb
|
|
191
181
|
- lib/dspy/lm/vision_models.rb
|
|
192
|
-
- lib/dspy/memory.rb
|
|
193
|
-
- lib/dspy/memory/embedding_engine.rb
|
|
194
|
-
- lib/dspy/memory/in_memory_store.rb
|
|
195
|
-
- lib/dspy/memory/local_embedding_engine.rb
|
|
196
|
-
- lib/dspy/memory/memory_compactor.rb
|
|
197
|
-
- lib/dspy/memory/memory_manager.rb
|
|
198
|
-
- lib/dspy/memory/memory_record.rb
|
|
199
|
-
- lib/dspy/memory/memory_store.rb
|
|
200
182
|
- lib/dspy/mixins/instruction_updatable.rb
|
|
201
183
|
- lib/dspy/mixins/struct_builder.rb
|
|
202
184
|
- lib/dspy/mixins/type_coercion.rb
|
|
@@ -238,7 +220,6 @@ files:
|
|
|
238
220
|
- lib/dspy/tools.rb
|
|
239
221
|
- lib/dspy/tools/base.rb
|
|
240
222
|
- lib/dspy/tools/github_cli_toolset.rb
|
|
241
|
-
- lib/dspy/tools/memory_toolset.rb
|
|
242
223
|
- lib/dspy/tools/schema.rb
|
|
243
224
|
- lib/dspy/tools/text_processing_toolset.rb
|
|
244
225
|
- lib/dspy/tools/toolset.rb
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'sorbet-runtime'
|
|
4
|
-
|
|
5
|
-
module DSPy
|
|
6
|
-
module Events
|
|
7
|
-
# Mixin for adding class-level event subscriptions
|
|
8
|
-
# Provides a clean way to subscribe to events at the class level
|
|
9
|
-
# instead of requiring instance-based subscriptions
|
|
10
|
-
#
|
|
11
|
-
# Usage:
|
|
12
|
-
# class MyTracker
|
|
13
|
-
# include DSPy::Events::SubscriberMixin
|
|
14
|
-
#
|
|
15
|
-
# add_subscription('llm.*') do |name, attrs|
|
|
16
|
-
# # Handle LLM events globally for this class
|
|
17
|
-
# end
|
|
18
|
-
# end
|
|
19
|
-
module SubscriberMixin
|
|
20
|
-
extend T::Sig
|
|
21
|
-
|
|
22
|
-
def self.included(base)
|
|
23
|
-
base.extend(ClassMethods)
|
|
24
|
-
base.class_eval do
|
|
25
|
-
@event_subscriptions = []
|
|
26
|
-
@subscription_mutex = Mutex.new
|
|
27
|
-
|
|
28
|
-
# Initialize subscriptions when the class is first loaded
|
|
29
|
-
@subscriptions_initialized = false
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
module ClassMethods
|
|
34
|
-
extend T::Sig
|
|
35
|
-
|
|
36
|
-
# Add a class-level event subscription
|
|
37
|
-
sig { params(pattern: String, block: T.proc.params(arg0: String, arg1: T::Hash[T.any(String, Symbol), T.untyped]).void).returns(String) }
|
|
38
|
-
def add_subscription(pattern, &block)
|
|
39
|
-
subscription_mutex.synchronize do
|
|
40
|
-
subscription_id = DSPy.events.subscribe(pattern, &block)
|
|
41
|
-
event_subscriptions << subscription_id
|
|
42
|
-
subscription_id
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Remove all subscriptions for this class
|
|
47
|
-
sig { void }
|
|
48
|
-
def unsubscribe_all
|
|
49
|
-
subscription_mutex.synchronize do
|
|
50
|
-
event_subscriptions.each { |id| DSPy.events.unsubscribe(id) }
|
|
51
|
-
event_subscriptions.clear
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Get list of active subscription IDs
|
|
56
|
-
sig { returns(T::Array[String]) }
|
|
57
|
-
def subscriptions
|
|
58
|
-
subscription_mutex.synchronize do
|
|
59
|
-
event_subscriptions.dup
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
# Thread-safe access to subscriptions array
|
|
66
|
-
sig { returns(T::Array[String]) }
|
|
67
|
-
def event_subscriptions
|
|
68
|
-
@event_subscriptions ||= []
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Thread-safe access to mutex
|
|
72
|
-
sig { returns(Mutex) }
|
|
73
|
-
def subscription_mutex
|
|
74
|
-
@subscription_mutex ||= Mutex.new
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module DSPy
|
|
4
|
-
module Events
|
|
5
|
-
# Base subscriber class for event-driven patterns
|
|
6
|
-
# This provides the foundation for creating custom event subscribers
|
|
7
|
-
#
|
|
8
|
-
# Example usage:
|
|
9
|
-
# class MySubscriber < DSPy::Events::BaseSubscriber
|
|
10
|
-
# def subscribe
|
|
11
|
-
# add_subscription('llm.*') do |event_name, attributes|
|
|
12
|
-
# # Handle LLM events
|
|
13
|
-
# end
|
|
14
|
-
# end
|
|
15
|
-
# end
|
|
16
|
-
#
|
|
17
|
-
# subscriber = MySubscriber.new
|
|
18
|
-
# # subscriber will start receiving events
|
|
19
|
-
# subscriber.unsubscribe # Clean up when done
|
|
20
|
-
class BaseSubscriber
|
|
21
|
-
def initialize
|
|
22
|
-
@subscriptions = []
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def subscribe
|
|
26
|
-
raise NotImplementedError, "Subclasses must implement #subscribe"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def unsubscribe
|
|
30
|
-
@subscriptions.each { |id| DSPy.events.unsubscribe(id) }
|
|
31
|
-
@subscriptions.clear
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
protected
|
|
35
|
-
|
|
36
|
-
def add_subscription(pattern, &block)
|
|
37
|
-
subscription_id = DSPy.events.subscribe(pattern, &block)
|
|
38
|
-
@subscriptions << subscription_id
|
|
39
|
-
subscription_id
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'sorbet-runtime'
|
|
4
|
-
|
|
5
|
-
module DSPy
|
|
6
|
-
module Memory
|
|
7
|
-
# Abstract base class for embedding engines
|
|
8
|
-
class EmbeddingEngine
|
|
9
|
-
extend T::Sig
|
|
10
|
-
extend T::Helpers
|
|
11
|
-
abstract!
|
|
12
|
-
|
|
13
|
-
# Generate embeddings for a single text
|
|
14
|
-
sig { abstract.params(text: String).returns(T::Array[Float]) }
|
|
15
|
-
def embed(text); end
|
|
16
|
-
|
|
17
|
-
# Generate embeddings for multiple texts (batch processing)
|
|
18
|
-
sig { abstract.params(texts: T::Array[String]).returns(T::Array[T::Array[Float]]) }
|
|
19
|
-
def embed_batch(texts); end
|
|
20
|
-
|
|
21
|
-
# Get the dimension of embeddings produced by this engine
|
|
22
|
-
sig { abstract.returns(Integer) }
|
|
23
|
-
def embedding_dimension; end
|
|
24
|
-
|
|
25
|
-
# Get the model name/identifier
|
|
26
|
-
sig { abstract.returns(String) }
|
|
27
|
-
def model_name; end
|
|
28
|
-
|
|
29
|
-
# Check if the engine is ready to use
|
|
30
|
-
sig { returns(T::Boolean) }
|
|
31
|
-
def ready?
|
|
32
|
-
true
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Get engine statistics
|
|
36
|
-
sig { returns(T::Hash[Symbol, T.untyped]) }
|
|
37
|
-
def stats
|
|
38
|
-
{
|
|
39
|
-
model_name: model_name,
|
|
40
|
-
embedding_dimension: embedding_dimension,
|
|
41
|
-
ready: ready?
|
|
42
|
-
}
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Normalize a vector to unit length
|
|
46
|
-
sig { params(vector: T::Array[Float]).returns(T::Array[Float]) }
|
|
47
|
-
def normalize_vector(vector)
|
|
48
|
-
magnitude = Math.sqrt(vector.sum { |x| x * x })
|
|
49
|
-
return vector if magnitude == 0.0
|
|
50
|
-
vector.map { |x| x / magnitude }
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Calculate cosine similarity between two vectors
|
|
54
|
-
sig { params(a: T::Array[Float], b: T::Array[Float]).returns(Float) }
|
|
55
|
-
def cosine_similarity(a, b)
|
|
56
|
-
return 0.0 if a.empty? || b.empty? || a.size != b.size
|
|
57
|
-
|
|
58
|
-
dot_product = a.zip(b).sum { |x, y| x * y }
|
|
59
|
-
magnitude_a = Math.sqrt(a.sum { |x| x * x })
|
|
60
|
-
magnitude_b = Math.sqrt(b.sum { |x| x * x })
|
|
61
|
-
|
|
62
|
-
return 0.0 if magnitude_a == 0.0 || magnitude_b == 0.0
|
|
63
|
-
|
|
64
|
-
dot_product / (magnitude_a * magnitude_b)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|