dspy 0.22.0 → 0.23.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/lib/dspy/events/subscriber_mixin.rb +79 -0
- data/lib/dspy/memory/local_embedding_engine.rb +3 -16
- data/lib/dspy/mixins/type_coercion.rb +21 -1
- data/lib/dspy/prediction.rb +1 -1
- data/lib/dspy/teleprompt/gepa.rb +3380 -0
- data/lib/dspy/teleprompt/teleprompter.rb +1 -1
- data/lib/dspy/version.rb +1 -1
- data/lib/dspy.rb +2 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a74fa7e459b97d25d515492a9c8ef786981ca5212dcfe970b9f8311e5a2b7be4
|
4
|
+
data.tar.gz: 7cf45b5f12849e55b1a180f3b39e9054357a23477bbc8dacad4b85be35bc234a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7610ab7261fb039264acf5c2de69b70c7cc33932335faf70b97ba65e459a0d2048a428e8b1f49b6ccd73de3455ad4adc9351bb2e5dc58acfac47323086b7c3d
|
7
|
+
data.tar.gz: de8c212916e2135c27e881be529f12121439b12bbc8effca7dd98d6aa912f6057ae304e9d1aa5eee6c2dd2fafee904b3665cde4569f61d91360cacb6acbc2e43
|
@@ -0,0 +1,79 @@
|
|
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
|
@@ -53,22 +53,9 @@ module DSPy
|
|
53
53
|
def embed_batch(texts)
|
54
54
|
ensure_ready!
|
55
55
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
59
|
-
# Generate embeddings in batch
|
60
|
-
results = @model.call(cleaned_texts)
|
61
|
-
|
62
|
-
# Extract and normalize embeddings
|
63
|
-
results.map do |result|
|
64
|
-
# Handle both single embeddings and batch results
|
65
|
-
embedding = case result
|
66
|
-
when Array
|
67
|
-
result.flatten # Flatten in case of nested arrays
|
68
|
-
else
|
69
|
-
result.to_a.flatten
|
70
|
-
end
|
71
|
-
normalize_vector(embedding)
|
56
|
+
# Generate embeddings one by one (informers doesn't support true batch processing)
|
57
|
+
texts.map do |text|
|
58
|
+
embed(text)
|
72
59
|
end
|
73
60
|
end
|
74
61
|
|
@@ -140,8 +140,28 @@ module DSPy
|
|
140
140
|
# Convert string keys to symbols
|
141
141
|
symbolized_hash = value.transform_keys(&:to_sym)
|
142
142
|
|
143
|
+
# Get struct properties to understand what fields are expected
|
144
|
+
struct_props = struct_class.props
|
145
|
+
|
146
|
+
# Remove the _type field that DSPy adds for discriminating structs,
|
147
|
+
# but only if it's NOT a legitimate field in the struct definition
|
148
|
+
if !struct_props.key?(:_type) && symbolized_hash.key?(:_type)
|
149
|
+
symbolized_hash = symbolized_hash.except(:_type)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Recursively coerce nested struct fields
|
153
|
+
coerced_hash = symbolized_hash.map do |key, val|
|
154
|
+
prop_info = struct_props[key]
|
155
|
+
if prop_info && prop_info[:type]
|
156
|
+
coerced_value = coerce_value_to_type(val, prop_info[:type])
|
157
|
+
[key, coerced_value]
|
158
|
+
else
|
159
|
+
[key, val]
|
160
|
+
end
|
161
|
+
end.to_h
|
162
|
+
|
143
163
|
# Create the struct instance
|
144
|
-
struct_class.new(**
|
164
|
+
struct_class.new(**coerced_hash)
|
145
165
|
rescue ArgumentError => e
|
146
166
|
# If struct creation fails, return the original value
|
147
167
|
DSPy.logger.debug("Failed to coerce to struct #{struct_class}: #{e.message}")
|