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
data/lib/dspy/prompt.rb
CHANGED
|
@@ -5,6 +5,7 @@ require 'sorbet-runtime'
|
|
|
5
5
|
require 'sorbet/toon'
|
|
6
6
|
|
|
7
7
|
require_relative 'few_shot_example'
|
|
8
|
+
require_relative 'utils/serialization'
|
|
8
9
|
require_relative 'schema/sorbet_toon_adapter'
|
|
9
10
|
|
|
10
11
|
module DSPy
|
|
@@ -26,24 +27,14 @@ module DSPy
|
|
|
26
27
|
sig { returns(T.nilable(String)) }
|
|
27
28
|
attr_reader :signature_class_name
|
|
28
29
|
|
|
29
|
-
# Returns the effective schema format
|
|
30
|
-
# Precedence: instance variable (if not :json default) > config.lm > :json
|
|
31
30
|
sig { returns(Symbol) }
|
|
32
31
|
def schema_format
|
|
33
|
-
|
|
34
|
-
return @schema_format if @schema_format && @schema_format != :json
|
|
35
|
-
|
|
36
|
-
# Otherwise, read from config if available
|
|
37
|
-
DSPy.config.lm&.schema_format || @schema_format || :json
|
|
32
|
+
@schema_format || :json
|
|
38
33
|
end
|
|
39
34
|
|
|
40
35
|
sig { returns(Symbol) }
|
|
41
36
|
def data_format
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
lm = DSPy.config.lm
|
|
45
|
-
lm_format = lm&.respond_to?(:data_format) ? lm.data_format : nil
|
|
46
|
-
lm_format || @data_format || :json
|
|
37
|
+
@data_format || :json
|
|
47
38
|
end
|
|
48
39
|
|
|
49
40
|
sig { returns(T.nilable(T.class_of(Signature))) }
|
|
@@ -56,20 +47,20 @@ module DSPy
|
|
|
56
47
|
output_schema: T::Hash[Symbol, T.untyped],
|
|
57
48
|
few_shot_examples: T::Array[FewShotExample],
|
|
58
49
|
signature_class_name: T.nilable(String),
|
|
59
|
-
schema_format: Symbol,
|
|
50
|
+
schema_format: T.nilable(Symbol),
|
|
60
51
|
signature_class: T.nilable(T.class_of(Signature)),
|
|
61
|
-
data_format: Symbol
|
|
52
|
+
data_format: T.nilable(Symbol)
|
|
62
53
|
).void
|
|
63
54
|
end
|
|
64
|
-
def initialize(instruction:, input_schema:, output_schema:, few_shot_examples: [], signature_class_name: nil, schema_format:
|
|
55
|
+
def initialize(instruction:, input_schema:, output_schema:, few_shot_examples: [], signature_class_name: nil, schema_format: nil, signature_class: nil, data_format: nil)
|
|
65
56
|
@instruction = instruction
|
|
66
57
|
@few_shot_examples = few_shot_examples.freeze
|
|
67
58
|
@input_schema = input_schema.freeze
|
|
68
59
|
@output_schema = output_schema.freeze
|
|
69
60
|
@signature_class_name = signature_class_name
|
|
70
|
-
@schema_format = schema_format
|
|
61
|
+
@schema_format = resolve_schema_format(schema_format)
|
|
71
62
|
@signature_class = signature_class
|
|
72
|
-
@data_format = data_format
|
|
63
|
+
@data_format = resolve_data_format(data_format)
|
|
73
64
|
end
|
|
74
65
|
|
|
75
66
|
# Immutable update methods for optimization
|
|
@@ -107,6 +98,34 @@ module DSPy
|
|
|
107
98
|
with_examples(combined_examples)
|
|
108
99
|
end
|
|
109
100
|
|
|
101
|
+
sig { params(new_schema_format: Symbol).returns(Prompt) }
|
|
102
|
+
def with_schema_format(new_schema_format)
|
|
103
|
+
self.class.new(
|
|
104
|
+
instruction: @instruction,
|
|
105
|
+
input_schema: @input_schema,
|
|
106
|
+
output_schema: @output_schema,
|
|
107
|
+
few_shot_examples: @few_shot_examples,
|
|
108
|
+
signature_class_name: @signature_class_name,
|
|
109
|
+
schema_format: new_schema_format,
|
|
110
|
+
signature_class: @signature_class,
|
|
111
|
+
data_format: @data_format
|
|
112
|
+
)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
sig { params(new_data_format: Symbol).returns(Prompt) }
|
|
116
|
+
def with_data_format(new_data_format)
|
|
117
|
+
self.class.new(
|
|
118
|
+
instruction: @instruction,
|
|
119
|
+
input_schema: @input_schema,
|
|
120
|
+
output_schema: @output_schema,
|
|
121
|
+
few_shot_examples: @few_shot_examples,
|
|
122
|
+
signature_class_name: @signature_class_name,
|
|
123
|
+
schema_format: @schema_format,
|
|
124
|
+
signature_class: @signature_class,
|
|
125
|
+
data_format: new_data_format
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
|
|
110
129
|
# Core prompt rendering methods
|
|
111
130
|
sig { returns(String) }
|
|
112
131
|
def render_system_prompt
|
|
@@ -223,7 +242,7 @@ module DSPy
|
|
|
223
242
|
else
|
|
224
243
|
sections << "## Input Values"
|
|
225
244
|
sections << "```json"
|
|
226
|
-
sections << JSON.pretty_generate(
|
|
245
|
+
sections << JSON.pretty_generate(DSPy::Utils::Serialization.deep_serialize(input_values))
|
|
227
246
|
sections << "```"
|
|
228
247
|
sections << ""
|
|
229
248
|
sections << "Respond with the corresponding output schema fields wrapped in a ```json ``` block,"
|
|
@@ -233,15 +252,6 @@ module DSPy
|
|
|
233
252
|
sections.join("\n")
|
|
234
253
|
end
|
|
235
254
|
|
|
236
|
-
# Generate messages for LM adapter
|
|
237
|
-
sig { params(input_values: T::Hash[Symbol, T.untyped]).returns(T::Array[T::Hash[Symbol, String]]) }
|
|
238
|
-
def to_messages(input_values)
|
|
239
|
-
[
|
|
240
|
-
{ role: 'system', content: render_system_prompt },
|
|
241
|
-
{ role: 'user', content: render_user_prompt(input_values) }
|
|
242
|
-
]
|
|
243
|
-
end
|
|
244
|
-
|
|
245
255
|
# Serialization for persistence and optimization
|
|
246
256
|
sig { returns(T::Hash[Symbol, T.untyped]) }
|
|
247
257
|
def to_h
|
|
@@ -280,10 +290,6 @@ module DSPy
|
|
|
280
290
|
).returns(Prompt)
|
|
281
291
|
end
|
|
282
292
|
def self.from_signature(signature_class, schema_format: nil, data_format: nil)
|
|
283
|
-
lm = DSPy.config.lm
|
|
284
|
-
schema_format ||= lm&.schema_format || :json
|
|
285
|
-
data_format ||= (lm&.respond_to?(:data_format) ? lm.data_format : nil) || :json
|
|
286
|
-
|
|
287
293
|
new(
|
|
288
294
|
instruction: signature_class.description || "Complete this task.",
|
|
289
295
|
input_schema: signature_class.input_json_schema,
|
|
@@ -371,51 +377,6 @@ module DSPy
|
|
|
371
377
|
"# Please install: gem install sorbet-baml"
|
|
372
378
|
end
|
|
373
379
|
|
|
374
|
-
# Recursively serialize complex objects for JSON representation
|
|
375
|
-
sig { params(obj: T.untyped).returns(T.untyped) }
|
|
376
|
-
def serialize_for_json(obj)
|
|
377
|
-
case obj
|
|
378
|
-
when T::Struct
|
|
379
|
-
# Convert T::Struct to hash using to_h method if available
|
|
380
|
-
if obj.respond_to?(:to_h)
|
|
381
|
-
serialize_for_json(obj.to_h)
|
|
382
|
-
else
|
|
383
|
-
# Fallback: serialize using struct properties
|
|
384
|
-
serialize_struct_to_hash(obj)
|
|
385
|
-
end
|
|
386
|
-
when Hash
|
|
387
|
-
# Recursively serialize hash values
|
|
388
|
-
obj.transform_values { |v| serialize_for_json(v) }
|
|
389
|
-
when Array
|
|
390
|
-
# Recursively serialize array elements
|
|
391
|
-
obj.map { |item| serialize_for_json(item) }
|
|
392
|
-
when T::Enum
|
|
393
|
-
# Serialize enums to their string representation
|
|
394
|
-
obj.serialize
|
|
395
|
-
else
|
|
396
|
-
# For basic types (String, Integer, Float, Boolean, etc.), return as-is
|
|
397
|
-
obj
|
|
398
|
-
end
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
# Fallback method to serialize T::Struct to hash when to_h is not available
|
|
402
|
-
sig { params(struct_obj: T::Struct).returns(T::Hash[Symbol, T.untyped]) }
|
|
403
|
-
def serialize_struct_to_hash(struct_obj)
|
|
404
|
-
result = {}
|
|
405
|
-
|
|
406
|
-
# Use struct's props method to get all properties
|
|
407
|
-
if struct_obj.class.respond_to?(:props)
|
|
408
|
-
struct_obj.class.props.each do |prop_name, _prop_info|
|
|
409
|
-
if struct_obj.respond_to?(prop_name)
|
|
410
|
-
value = struct_obj.public_send(prop_name)
|
|
411
|
-
result[prop_name] = serialize_for_json(value)
|
|
412
|
-
end
|
|
413
|
-
end
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
result
|
|
417
|
-
end
|
|
418
|
-
|
|
419
380
|
def toon_data_format_enabled?
|
|
420
381
|
data_format == :toon && @signature_class
|
|
421
382
|
end
|
|
@@ -506,5 +467,20 @@ module DSPy
|
|
|
506
467
|
base = 'value' if base.empty?
|
|
507
468
|
"example_#{base}"
|
|
508
469
|
end
|
|
470
|
+
|
|
471
|
+
def resolve_schema_format(schema_format)
|
|
472
|
+
return schema_format unless schema_format.nil?
|
|
473
|
+
|
|
474
|
+
lm = DSPy.respond_to?(:current_lm) ? DSPy.current_lm : DSPy.config.lm
|
|
475
|
+
lm&.schema_format || :json
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def resolve_data_format(data_format)
|
|
479
|
+
return data_format unless data_format.nil?
|
|
480
|
+
|
|
481
|
+
lm = DSPy.respond_to?(:current_lm) ? DSPy.current_lm : DSPy.config.lm
|
|
482
|
+
lm_format = lm&.respond_to?(:data_format) ? lm.data_format : nil
|
|
483
|
+
lm_format || :json
|
|
484
|
+
end
|
|
509
485
|
end
|
|
510
486
|
end
|
|
@@ -160,7 +160,7 @@ module DSPy
|
|
|
160
160
|
DSPy.current_lm,
|
|
161
161
|
verbose: @config.verbose
|
|
162
162
|
)
|
|
163
|
-
rescue => e
|
|
163
|
+
rescue StandardError => e
|
|
164
164
|
DSPy.logger.warn("Failed to generate dataset summary: #{e.message}")
|
|
165
165
|
@dataset_summary = nil
|
|
166
166
|
end
|
|
@@ -189,7 +189,7 @@ module DSPy
|
|
|
189
189
|
# This is a simplified version - could be enhanced with method_source gem
|
|
190
190
|
code = "Program: #{klass.name}\nSource: #{file}:#{line}"
|
|
191
191
|
code
|
|
192
|
-
rescue => e
|
|
192
|
+
rescue StandardError => e
|
|
193
193
|
DSPy.logger.warn("Could not extract program source: #{e.message}")
|
|
194
194
|
nil
|
|
195
195
|
end
|
|
@@ -506,7 +506,7 @@ module DSPy
|
|
|
506
506
|
instruction = result.instruction.strip
|
|
507
507
|
|
|
508
508
|
candidates << instruction if instruction.length > 0
|
|
509
|
-
rescue => error
|
|
509
|
+
rescue StandardError => error
|
|
510
510
|
DSPy.logger.warn("Failed to generate instruction candidate #{i + 1}: #{error.message}")
|
|
511
511
|
end
|
|
512
512
|
end
|