dspy 0.29.0 → 0.29.1
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 +1 -1
- data/lib/dspy/teleprompt/mipro_v2.rb +275 -26
- data/lib/dspy/version.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42a6bfa4a1e0fe7b7dd38e3a2fe017959365f566248319e1deec6cadcd06efc3
|
4
|
+
data.tar.gz: ffceb724c96e7803ec7531bf52c12f502266e21d4ab9bcf534a8005e59835883
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d81f0ab86954523f8b3511f3105f8005b9709f0a46fb08f0403dcac841c70efcfbff90dcdedccaf322554280f62bdbab6a36be34d0e787f01734d8ee2219bf6
|
7
|
+
data.tar.gz: 31d048ad3d7493be0c52a24729d033ce58a891039c180945aa80d54afb7a529b6e420ccfc49fdab32ef00803483ecbb63dd2c2bd9d15f569c44debfdfd6dea0c
|
data/README.md
CHANGED
@@ -111,7 +111,7 @@ end
|
|
111
111
|
- **Prompt Objects** - Manipulate prompts as first-class objects instead of strings
|
112
112
|
- **Typed Examples** - Type-safe training data with automatic validation
|
113
113
|
- **Evaluation Framework** - Advanced metrics beyond simple accuracy with error-resilient pipelines
|
114
|
-
- **MIPROv2 Optimization** - Advanced Bayesian optimization with Gaussian Processes, multiple optimization strategies, and storage persistence
|
114
|
+
- **MIPROv2 Optimization** - Advanced Bayesian optimization with Gaussian Processes, multiple optimization strategies, auto-config presets, and storage persistence
|
115
115
|
|
116
116
|
**Production Features:**
|
117
117
|
- **Reliable JSON Extraction** - Native structured outputs for OpenAI and Gemini, Anthropic tool-based extraction, and automatic strategy selection with fallback
|
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'digest'
|
4
4
|
require 'time'
|
5
|
+
require 'json'
|
5
6
|
require 'concurrent-ruby'
|
6
7
|
require 'sorbet-runtime'
|
7
8
|
require 'securerandom'
|
9
|
+
require 'set'
|
8
10
|
require_relative 'teleprompter'
|
9
11
|
require_relative 'utils'
|
10
12
|
require_relative '../propose/grounded_proposer'
|
@@ -30,6 +32,58 @@ module DSPy
|
|
30
32
|
Bayesian = new("bayesian")
|
31
33
|
end
|
32
34
|
end
|
35
|
+
|
36
|
+
class AutoPreset < T::Enum
|
37
|
+
enums do
|
38
|
+
None = new("none")
|
39
|
+
Light = new("light")
|
40
|
+
Medium = new("medium")
|
41
|
+
Heavy = new("heavy")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
AUTO_PRESET_SETTINGS = {
|
46
|
+
AutoPreset::None => {},
|
47
|
+
AutoPreset::Light => {
|
48
|
+
candidate_budget: 6,
|
49
|
+
instruction_candidates: 3,
|
50
|
+
instruction_candidates_when_fewshot: 3,
|
51
|
+
bootstrap_sets: 3,
|
52
|
+
max_bootstrapped_examples: 2,
|
53
|
+
max_labeled_examples: 8,
|
54
|
+
optimization_strategy: OptimizationStrategy::Greedy,
|
55
|
+
early_stopping_patience: 2,
|
56
|
+
valset_target_size: 100,
|
57
|
+
minibatch_size: nil
|
58
|
+
},
|
59
|
+
AutoPreset::Medium => {
|
60
|
+
candidate_budget: 12,
|
61
|
+
instruction_candidates: 5,
|
62
|
+
instruction_candidates_when_fewshot: 5,
|
63
|
+
bootstrap_sets: 5,
|
64
|
+
max_bootstrapped_examples: 4,
|
65
|
+
max_labeled_examples: 16,
|
66
|
+
optimization_strategy: OptimizationStrategy::Adaptive,
|
67
|
+
early_stopping_patience: 3,
|
68
|
+
valset_target_size: 300,
|
69
|
+
minibatch_size: nil
|
70
|
+
},
|
71
|
+
AutoPreset::Heavy => {
|
72
|
+
candidate_budget: 18,
|
73
|
+
instruction_candidates: 8,
|
74
|
+
instruction_candidates_when_fewshot: 8,
|
75
|
+
bootstrap_sets: 8,
|
76
|
+
max_bootstrapped_examples: 6,
|
77
|
+
max_labeled_examples: 24,
|
78
|
+
optimization_strategy: OptimizationStrategy::Bayesian,
|
79
|
+
early_stopping_patience: 5,
|
80
|
+
valset_target_size: 1000,
|
81
|
+
minibatch_size: nil
|
82
|
+
}
|
83
|
+
}.freeze
|
84
|
+
|
85
|
+
DEFAULT_AUTO_SEED = 42
|
86
|
+
|
33
87
|
# MIPROv2: Multi-prompt Instruction Proposal with Retrieval Optimization
|
34
88
|
# State-of-the-art prompt optimization combining bootstrap sampling,
|
35
89
|
# instruction generation, and Bayesian optimization
|
@@ -50,13 +104,7 @@ module DSPy
|
|
50
104
|
def self.light(metric: nil, **kwargs)
|
51
105
|
optimizer = MIPROv2.new(metric: metric, **kwargs)
|
52
106
|
optimizer.configure do |config|
|
53
|
-
config
|
54
|
-
config.num_instruction_candidates = 3
|
55
|
-
config.max_bootstrapped_examples = 2
|
56
|
-
config.max_labeled_examples = 8
|
57
|
-
config.bootstrap_sets = 3
|
58
|
-
config.optimization_strategy = :greedy
|
59
|
-
config.early_stopping_patience = 2
|
107
|
+
MIPROv2.apply_auto_defaults(config, AutoPreset::Light)
|
60
108
|
end
|
61
109
|
optimizer
|
62
110
|
end
|
@@ -70,13 +118,7 @@ module DSPy
|
|
70
118
|
def self.medium(metric: nil, **kwargs)
|
71
119
|
optimizer = MIPROv2.new(metric: metric, **kwargs)
|
72
120
|
optimizer.configure do |config|
|
73
|
-
config
|
74
|
-
config.num_instruction_candidates = 5
|
75
|
-
config.max_bootstrapped_examples = 4
|
76
|
-
config.max_labeled_examples = 16
|
77
|
-
config.bootstrap_sets = 5
|
78
|
-
config.optimization_strategy = :adaptive
|
79
|
-
config.early_stopping_patience = 3
|
121
|
+
MIPROv2.apply_auto_defaults(config, AutoPreset::Medium)
|
80
122
|
end
|
81
123
|
optimizer
|
82
124
|
end
|
@@ -90,19 +132,33 @@ module DSPy
|
|
90
132
|
def self.heavy(metric: nil, **kwargs)
|
91
133
|
optimizer = MIPROv2.new(metric: metric, **kwargs)
|
92
134
|
optimizer.configure do |config|
|
93
|
-
config
|
94
|
-
config.num_instruction_candidates = 8
|
95
|
-
config.max_bootstrapped_examples = 6
|
96
|
-
config.max_labeled_examples = 24
|
97
|
-
config.bootstrap_sets = 8
|
98
|
-
config.optimization_strategy = :bayesian
|
99
|
-
config.early_stopping_patience = 5
|
135
|
+
MIPROv2.apply_auto_defaults(config, AutoPreset::Heavy)
|
100
136
|
end
|
101
137
|
optimizer
|
102
138
|
end
|
103
139
|
end
|
104
140
|
|
105
141
|
# Dry-configurable settings for MIPROv2
|
142
|
+
setting :auto_preset, default: AutoPreset::None, constructor: ->(value) {
|
143
|
+
case value
|
144
|
+
when AutoPreset
|
145
|
+
value
|
146
|
+
when String, Symbol
|
147
|
+
begin
|
148
|
+
AutoPreset.deserialize(value.to_s.downcase)
|
149
|
+
rescue ArgumentError
|
150
|
+
raise ArgumentError, "Invalid auto preset: #{value}. Must be one of :none, :light, :medium, :heavy"
|
151
|
+
end
|
152
|
+
when nil
|
153
|
+
AutoPreset::None
|
154
|
+
else
|
155
|
+
raise ArgumentError, "Invalid auto preset: #{value.inspect}"
|
156
|
+
end
|
157
|
+
}
|
158
|
+
setting :auto_seed, default: DEFAULT_AUTO_SEED, constructor: ->(value) {
|
159
|
+
value.nil? ? DEFAULT_AUTO_SEED : Integer(value)
|
160
|
+
}
|
161
|
+
setting :valset_target_size, default: nil
|
106
162
|
setting :num_trials, default: 12
|
107
163
|
setting :num_instruction_candidates, default: 5
|
108
164
|
setting :bootstrap_sets, default: 5
|
@@ -142,6 +198,26 @@ module DSPy
|
|
142
198
|
@default_config_block
|
143
199
|
end
|
144
200
|
|
201
|
+
class << self
|
202
|
+
extend T::Sig
|
203
|
+
|
204
|
+
sig { params(config: T.untyped, preset: AutoPreset).void }
|
205
|
+
def apply_auto_defaults(config, preset)
|
206
|
+
settings = AUTO_PRESET_SETTINGS.fetch(preset) { {} }
|
207
|
+
|
208
|
+
config.auto_preset = preset
|
209
|
+
config.num_trials = settings[:candidate_budget] if settings[:candidate_budget]
|
210
|
+
config.num_instruction_candidates = settings[:instruction_candidates] if settings[:instruction_candidates]
|
211
|
+
config.bootstrap_sets = settings[:bootstrap_sets] if settings[:bootstrap_sets]
|
212
|
+
config.max_bootstrapped_examples = settings[:max_bootstrapped_examples] if settings.key?(:max_bootstrapped_examples)
|
213
|
+
config.max_labeled_examples = settings[:max_labeled_examples] if settings.key?(:max_labeled_examples)
|
214
|
+
config.optimization_strategy = settings[:optimization_strategy] if settings[:optimization_strategy]
|
215
|
+
config.early_stopping_patience = settings[:early_stopping_patience] if settings[:early_stopping_patience]
|
216
|
+
config.minibatch_size = settings[:minibatch_size] if settings.key?(:minibatch_size)
|
217
|
+
config.valset_target_size = settings[:valset_target_size] if settings[:valset_target_size]
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
145
221
|
|
146
222
|
# Simple data structure for evaluated candidate configurations (immutable)
|
147
223
|
EvaluatedCandidate = Data.define(
|
@@ -294,6 +370,13 @@ module DSPy
|
|
294
370
|
typed_trainset = ensure_typed_examples(trainset)
|
295
371
|
typed_valset = valset ? ensure_typed_examples(valset) : nil
|
296
372
|
|
373
|
+
if auto_preset_active?
|
374
|
+
typed_trainset, typed_valset = prepare_datasets_for_auto(typed_trainset, typed_valset)
|
375
|
+
typed_valset = apply_auto_preset!(program, typed_valset)
|
376
|
+
else
|
377
|
+
typed_valset = limit_validation_set(typed_valset, config.valset_target_size)
|
378
|
+
end
|
379
|
+
|
297
380
|
# Use validation set if available, otherwise use part of training set
|
298
381
|
evaluation_set = typed_valset || typed_trainset.take([typed_trainset.size / 3, 10].max)
|
299
382
|
|
@@ -345,6 +428,105 @@ module DSPy
|
|
345
428
|
|
346
429
|
private
|
347
430
|
|
431
|
+
sig { returns(T::Boolean) }
|
432
|
+
def auto_preset_active?
|
433
|
+
config.auto_preset != AutoPreset::None
|
434
|
+
end
|
435
|
+
|
436
|
+
sig { params(trainset: T::Array[DSPy::Example], valset: T.nilable(T::Array[DSPy::Example])).returns([T::Array[DSPy::Example], T::Array[DSPy::Example]]) }
|
437
|
+
def prepare_datasets_for_auto(trainset, valset)
|
438
|
+
settings = auto_settings_for(config.auto_preset)
|
439
|
+
target_size = settings[:valset_target_size]
|
440
|
+
config.valset_target_size = target_size
|
441
|
+
|
442
|
+
if valset && valset.any?
|
443
|
+
[trainset, limit_validation_set(valset, target_size)]
|
444
|
+
else
|
445
|
+
raise ArgumentError, "Training set must contain at least 2 examples when auto presets are enabled" if trainset.size < 2
|
446
|
+
|
447
|
+
shuffled = trainset.shuffle(random: Random.new(config.auto_seed))
|
448
|
+
default_val_size = [
|
449
|
+
[(trainset.size * 0.8).ceil, 1].max,
|
450
|
+
trainset.size - 1
|
451
|
+
].min
|
452
|
+
|
453
|
+
desired_val_size = target_size ? [default_val_size, target_size].min : default_val_size
|
454
|
+
desired_val_size = [[desired_val_size, 1].max, trainset.size - 1].min
|
455
|
+
|
456
|
+
validation_examples = shuffled.take(desired_val_size)
|
457
|
+
training_examples = shuffled.drop(desired_val_size)
|
458
|
+
|
459
|
+
[training_examples, limit_validation_set(validation_examples, target_size)]
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
sig { params(program: T.untyped, valset: T::Array[DSPy::Example]).returns(T::Array[DSPy::Example]) }
|
464
|
+
def apply_auto_preset!(program, valset)
|
465
|
+
settings = auto_settings_for(config.auto_preset)
|
466
|
+
zeroshot = zero_shot_for_settings?(settings)
|
467
|
+
candidate_budget = settings[:candidate_budget]
|
468
|
+
|
469
|
+
if candidate_budget && candidate_budget.positive?
|
470
|
+
config.num_trials = compute_trials_from_candidate_budget(program, candidate_budget, zeroshot)
|
471
|
+
instruction_candidates = if zeroshot
|
472
|
+
candidate_budget
|
473
|
+
else
|
474
|
+
settings[:instruction_candidates_when_fewshot] || (candidate_budget / 2.0).ceil
|
475
|
+
end
|
476
|
+
config.num_instruction_candidates = [instruction_candidates, 1].max
|
477
|
+
end
|
478
|
+
|
479
|
+
config.bootstrap_sets = settings[:bootstrap_sets] if settings[:bootstrap_sets]
|
480
|
+
config.max_bootstrapped_examples = settings[:max_bootstrapped_examples] if settings.key?(:max_bootstrapped_examples)
|
481
|
+
config.max_labeled_examples = settings[:max_labeled_examples] if settings.key?(:max_labeled_examples)
|
482
|
+
config.optimization_strategy = settings[:optimization_strategy] if settings[:optimization_strategy]
|
483
|
+
config.early_stopping_patience = settings[:early_stopping_patience] if settings[:early_stopping_patience]
|
484
|
+
config.minibatch_size = settings[:minibatch_size] if settings.key?(:minibatch_size)
|
485
|
+
|
486
|
+
config.valset_target_size = settings[:valset_target_size]
|
487
|
+
limit_validation_set(valset, config.valset_target_size)
|
488
|
+
end
|
489
|
+
|
490
|
+
sig { params(valset: T.nilable(T::Array[DSPy::Example]), target_size: T.nilable(Integer)).returns(T.nilable(T::Array[DSPy::Example])) }
|
491
|
+
def limit_validation_set(valset, target_size)
|
492
|
+
return valset unless valset && target_size && target_size.positive?
|
493
|
+
return valset if valset.size <= target_size
|
494
|
+
|
495
|
+
valset.shuffle(random: Random.new(config.auto_seed)).take(target_size)
|
496
|
+
end
|
497
|
+
|
498
|
+
sig { params(program: T.untyped, num_candidates: Integer, zeroshot: T::Boolean).returns(Integer) }
|
499
|
+
def compute_trials_from_candidate_budget(program, num_candidates, zeroshot)
|
500
|
+
predictor_count =
|
501
|
+
if program.respond_to?(:predictors)
|
502
|
+
Array(program.predictors).size
|
503
|
+
else
|
504
|
+
1
|
505
|
+
end
|
506
|
+
|
507
|
+
predictor_count = 1 if predictor_count.zero?
|
508
|
+
variable_count = zeroshot ? predictor_count : predictor_count * 2
|
509
|
+
log_term = Math.log2([num_candidates, 2].max)
|
510
|
+
|
511
|
+
[
|
512
|
+
(2 * variable_count * log_term).ceil,
|
513
|
+
(1.5 * num_candidates).ceil
|
514
|
+
].max
|
515
|
+
end
|
516
|
+
|
517
|
+
sig { params(settings: T::Hash[Symbol, T.untyped]).returns(T::Boolean) }
|
518
|
+
def zero_shot_for_settings?(settings)
|
519
|
+
settings.fetch(:max_bootstrapped_examples, 0).to_i.zero? &&
|
520
|
+
settings.fetch(:max_labeled_examples, 0).to_i.zero?
|
521
|
+
end
|
522
|
+
|
523
|
+
sig { params(preset: AutoPreset).returns(T::Hash[Symbol, T.untyped]) }
|
524
|
+
def auto_settings_for(preset)
|
525
|
+
AUTO_PRESET_SETTINGS.fetch(preset) do
|
526
|
+
raise ArgumentError, "Unknown auto preset: #{preset.inspect}"
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
348
530
|
# Phase 1: Bootstrap few-shot examples from training data
|
349
531
|
# Returns a hash mapping predictor indices to arrays of demo sets
|
350
532
|
sig { params(program: T.untyped, trainset: T::Array[DSPy::Example]).returns(T::Hash[Integer, T::Array[T::Array[DSPy::FewShotExample]]]) }
|
@@ -546,6 +728,21 @@ module DSPy
|
|
546
728
|
end
|
547
729
|
def generate_candidate_configurations(proposal_result, demo_candidates)
|
548
730
|
candidates = []
|
731
|
+
seen_signatures = Set.new
|
732
|
+
|
733
|
+
add_candidate = lambda do |instruction:, few_shot_examples:, type:, metadata:, config_id:|
|
734
|
+
signature = candidate_signature(type, instruction, metadata, few_shot_examples)
|
735
|
+
next if seen_signatures.include?(signature)
|
736
|
+
|
737
|
+
seen_signatures << signature
|
738
|
+
candidates << EvaluatedCandidate.new(
|
739
|
+
instruction: instruction,
|
740
|
+
few_shot_examples: few_shot_examples,
|
741
|
+
type: type,
|
742
|
+
metadata: metadata,
|
743
|
+
config_id: config_id
|
744
|
+
)
|
745
|
+
end
|
549
746
|
|
550
747
|
predictor_instruction_map = if proposal_result.respond_to?(:predictor_instructions) && proposal_result.predictor_instructions.any?
|
551
748
|
proposal_result.predictor_instructions
|
@@ -557,7 +754,7 @@ module DSPy
|
|
557
754
|
demo_maps = build_demo_maps(demo_candidates)
|
558
755
|
|
559
756
|
# Base configuration (no modifications)
|
560
|
-
|
757
|
+
add_candidate.call(
|
561
758
|
instruction: "",
|
562
759
|
few_shot_examples: [],
|
563
760
|
type: CandidateType::Baseline,
|
@@ -570,7 +767,7 @@ module DSPy
|
|
570
767
|
|
571
768
|
instruction_maps.each_with_index do |instruction_map, combo_idx|
|
572
769
|
primary_instruction = instruction_map[0] || instruction_map.values.first || ""
|
573
|
-
|
770
|
+
add_candidate.call(
|
574
771
|
instruction: primary_instruction,
|
575
772
|
few_shot_examples: [],
|
576
773
|
type: CandidateType::InstructionOnly,
|
@@ -587,7 +784,7 @@ module DSPy
|
|
587
784
|
next if demo_map.empty?
|
588
785
|
|
589
786
|
flattened_examples = demo_map.values.flatten
|
590
|
-
|
787
|
+
add_candidate.call(
|
591
788
|
instruction: "",
|
592
789
|
few_shot_examples: flattened_examples,
|
593
790
|
type: CandidateType::FewShotOnly,
|
@@ -607,7 +804,7 @@ module DSPy
|
|
607
804
|
next if demo_map.empty?
|
608
805
|
|
609
806
|
flattened_examples = demo_map.values.flatten
|
610
|
-
|
807
|
+
add_candidate.call(
|
611
808
|
instruction: primary_instruction,
|
612
809
|
few_shot_examples: flattened_examples,
|
613
810
|
type: CandidateType::Combined,
|
@@ -687,6 +884,55 @@ module DSPy
|
|
687
884
|
end
|
688
885
|
end
|
689
886
|
|
887
|
+
sig do
|
888
|
+
params(
|
889
|
+
type: CandidateType,
|
890
|
+
instruction: String,
|
891
|
+
metadata: T::Hash[Symbol, T.untyped],
|
892
|
+
few_shot_examples: T::Array[T.untyped]
|
893
|
+
).returns(String)
|
894
|
+
end
|
895
|
+
def candidate_signature(type, instruction, metadata, few_shot_examples)
|
896
|
+
JSON.generate(
|
897
|
+
type: type.serialize,
|
898
|
+
instruction: instruction,
|
899
|
+
instructions_map: normalize_instruction_map(metadata[:instructions_map] || {}),
|
900
|
+
demos_map: normalize_demo_map(metadata[:demos_map] || {}),
|
901
|
+
few_shot_examples: few_shot_examples.map { |example| serialize_few_shot_example(example) }
|
902
|
+
)
|
903
|
+
end
|
904
|
+
|
905
|
+
sig { params(map: T::Hash[Integer, T.untyped]).returns(T::Hash[Integer, String]) }
|
906
|
+
def normalize_instruction_map(map)
|
907
|
+
map.sort_by { |index, _| index }.each_with_object({}) do |(index, value), memo|
|
908
|
+
memo[index] = value.to_s
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
912
|
+
sig { params(map: T::Hash[Integer, T::Array[T.untyped]]).returns(T::Hash[Integer, T::Array[T.untyped]]) }
|
913
|
+
def normalize_demo_map(map)
|
914
|
+
map.sort_by { |index, _| index }.each_with_object({}) do |(index, demos), memo|
|
915
|
+
memo[index] = Array(demos).map { |demo| serialize_few_shot_example(demo) }
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
sig { params(example: T.untyped).returns(T.untyped) }
|
920
|
+
def serialize_few_shot_example(example)
|
921
|
+
case example
|
922
|
+
when DSPy::FewShotExample
|
923
|
+
deep_dup(example.to_h)
|
924
|
+
when DSPy::Example
|
925
|
+
{
|
926
|
+
input: deep_dup(example.input_values),
|
927
|
+
expected: deep_dup(example.expected_values)
|
928
|
+
}
|
929
|
+
when Hash
|
930
|
+
deep_dup(example)
|
931
|
+
else
|
932
|
+
example
|
933
|
+
end
|
934
|
+
end
|
935
|
+
|
690
936
|
sig { params(examples: T::Array[T.untyped]).returns(T::Array[DSPy::FewShotExample]) }
|
691
937
|
def normalize_few_shot_examples(examples)
|
692
938
|
examples.map do |example|
|
@@ -1412,10 +1658,13 @@ module DSPy
|
|
1412
1658
|
# Infer auto mode based on configuration
|
1413
1659
|
sig { returns(String) }
|
1414
1660
|
def infer_auto_mode
|
1661
|
+
return config.auto_preset.serialize unless config.auto_preset == AutoPreset::None
|
1662
|
+
|
1415
1663
|
case config.num_trials
|
1416
1664
|
when 0..6 then "light"
|
1417
1665
|
when 7..12 then "medium"
|
1418
|
-
|
1666
|
+
when 13..Float::INFINITY then "heavy"
|
1667
|
+
else "manual"
|
1419
1668
|
end
|
1420
1669
|
end
|
1421
1670
|
end
|
data/lib/dspy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dspy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.29.
|
4
|
+
version: 0.29.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vicente Reig Rincón de Arellano
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date: 2025-10-
|
10
|
+
date: 2025-10-20 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: dry-configurable
|
@@ -321,7 +320,6 @@ homepage: https://github.com/vicentereig/dspy.rb
|
|
321
320
|
licenses:
|
322
321
|
- MIT
|
323
322
|
metadata: {}
|
324
|
-
post_install_message:
|
325
323
|
rdoc_options: []
|
326
324
|
require_paths:
|
327
325
|
- lib
|
@@ -336,8 +334,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
336
334
|
- !ruby/object:Gem::Version
|
337
335
|
version: '0'
|
338
336
|
requirements: []
|
339
|
-
rubygems_version: 3.
|
340
|
-
signing_key:
|
337
|
+
rubygems_version: 3.6.5
|
341
338
|
specification_version: 4
|
342
339
|
summary: The Ruby framework for programming—rather than prompting—language models.
|
343
340
|
test_files: []
|