dspy 0.31.0 → 0.31.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/lib/dspy/mixins/type_coercion.rb +2 -0
- data/lib/dspy/prompt.rb +117 -4
- data/lib/dspy/schema/sorbet_toon_adapter.rb +2 -1
- data/lib/dspy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 584b43a98aa27dcc4bcdb83c64f48b4c3d0f4b67453abfe9a0942cbc30b14e7d
|
|
4
|
+
data.tar.gz: ab2b58be33ef10e36d1825c371e29783a7a3cea72bfb34b765b9aeab5fb4644f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6671b0cca0709aa9dea2eaf46abbbc2366d0779a89139377b6840279afa767e659bf635e8314a0a3ca45bc3f476200b7d430f74e83b0af08a085ae221a97c7c5
|
|
7
|
+
data.tar.gz: 1f8aaba8e3e2f16e1bd0eb81f9694b677f20cbeb7d0dadbacc9571613076ab29bc44991c79f3c5908e821397b2e0616e04801704f4ced5e0e5a8e9eed4f84f4f
|
|
@@ -36,6 +36,8 @@ module DSPy
|
|
|
36
36
|
coerce_array_value(value, prop_type)
|
|
37
37
|
when ->(type) { hash_type?(type) }
|
|
38
38
|
coerce_hash_value(value, prop_type)
|
|
39
|
+
when ->(type) { type == String || simple_type_match?(type, String) }
|
|
40
|
+
value.to_s
|
|
39
41
|
when ->(type) { enum_type?(type) }
|
|
40
42
|
coerce_enum_value(value, prop_type)
|
|
41
43
|
when ->(type) { type == Float || simple_type_match?(type, Float) }
|
data/lib/dspy/prompt.rb
CHANGED
|
@@ -155,17 +155,38 @@ module DSPy
|
|
|
155
155
|
end
|
|
156
156
|
end
|
|
157
157
|
|
|
158
|
-
if
|
|
158
|
+
if toon_data_format_enabled?
|
|
159
|
+
sections << "## TOON data format instructions"
|
|
160
|
+
sections << "All input and output payloads must use Token-Oriented Object Notation (TOON). Do not return JSON, YAML, or prose."
|
|
161
|
+
sections << ""
|
|
159
162
|
sections << "## Input values"
|
|
163
|
+
sections << "Copy the TOON block below and replace the placeholder values with the correct inputs."
|
|
160
164
|
sections << "```toon"
|
|
161
165
|
sections << "{input_values}"
|
|
162
166
|
sections << "```"
|
|
167
|
+
|
|
168
|
+
if (example_input = example_toon_payload(:input))
|
|
169
|
+
sections << ""
|
|
170
|
+
sections << "### Example TOON input"
|
|
171
|
+
sections << "```toon"
|
|
172
|
+
sections << example_input
|
|
173
|
+
sections << "```"
|
|
174
|
+
end
|
|
175
|
+
|
|
163
176
|
sections << ""
|
|
164
177
|
sections << "## Output values"
|
|
165
|
-
sections << "Respond exclusively with a ```toon``` block
|
|
178
|
+
sections << "Respond exclusively with a ```toon``` block that lists the output fields in the exact order shown in the schema."
|
|
166
179
|
sections << "```toon"
|
|
167
180
|
sections << "{output_values}"
|
|
168
181
|
sections << "```"
|
|
182
|
+
|
|
183
|
+
if (example_output = example_toon_payload(:output))
|
|
184
|
+
sections << ""
|
|
185
|
+
sections << "### Example TOON output"
|
|
186
|
+
sections << "```toon"
|
|
187
|
+
sections << example_output
|
|
188
|
+
sections << "```"
|
|
189
|
+
end
|
|
169
190
|
else
|
|
170
191
|
sections << "## Input values"
|
|
171
192
|
sections << "```json"
|
|
@@ -189,15 +210,16 @@ module DSPy
|
|
|
189
210
|
def render_user_prompt(input_values)
|
|
190
211
|
sections = []
|
|
191
212
|
|
|
192
|
-
if
|
|
213
|
+
if toon_data_format_enabled?
|
|
193
214
|
toon_payload = DSPy::Schema::SorbetToonAdapter.render_input(@signature_class, input_values)
|
|
194
215
|
|
|
195
216
|
sections << "## Input Values"
|
|
217
|
+
sections << "Use the TOON block below as-is; do not convert it to JSON."
|
|
196
218
|
sections << "```toon"
|
|
197
219
|
sections << toon_payload
|
|
198
220
|
sections << "```"
|
|
199
221
|
sections << ""
|
|
200
|
-
sections << "Respond with the corresponding output schema fields encoded as TOON inside a ```toon``` block starting with the heading `## Output values`."
|
|
222
|
+
sections << "Respond with the corresponding output schema fields encoded as TOON inside a ```toon``` block starting with the heading `## Output values`. Do not include any JSON."
|
|
201
223
|
else
|
|
202
224
|
sections << "## Input Values"
|
|
203
225
|
sections << "```json"
|
|
@@ -393,5 +415,96 @@ module DSPy
|
|
|
393
415
|
|
|
394
416
|
result
|
|
395
417
|
end
|
|
418
|
+
|
|
419
|
+
def toon_data_format_enabled?
|
|
420
|
+
data_format == :toon && @signature_class
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
SAMPLE_DEPTH_LIMIT = 3
|
|
424
|
+
private_constant :SAMPLE_DEPTH_LIMIT
|
|
425
|
+
|
|
426
|
+
def example_toon_payload(role)
|
|
427
|
+
return nil unless toon_data_format_enabled?
|
|
428
|
+
|
|
429
|
+
sample_values = case role
|
|
430
|
+
when :input
|
|
431
|
+
sample_struct_values(@signature_class.input_struct_class)
|
|
432
|
+
when :output
|
|
433
|
+
sample_struct_values(@signature_class.output_struct_class)
|
|
434
|
+
else
|
|
435
|
+
{}
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
return nil if sample_values.empty?
|
|
439
|
+
|
|
440
|
+
case role
|
|
441
|
+
when :input
|
|
442
|
+
DSPy::Schema::SorbetToonAdapter.render_input(@signature_class, sample_values)
|
|
443
|
+
when :output
|
|
444
|
+
DSPy::Schema::SorbetToonAdapter.render_expected_output(@signature_class, sample_values)
|
|
445
|
+
end
|
|
446
|
+
rescue StandardError
|
|
447
|
+
nil
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
def sample_struct_values(struct_class, depth = 0)
|
|
451
|
+
return {} unless struct_class&.respond_to?(:props)
|
|
452
|
+
struct_class.props.each_with_object({}) do |(name, prop_info), memo|
|
|
453
|
+
memo[name] = sample_value_for_type(prop_info[:type], name, depth)
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def sample_value_for_type(prop_type, field_name, depth)
|
|
458
|
+
return sample_string(field_name) if prop_type.nil? || depth > SAMPLE_DEPTH_LIMIT
|
|
459
|
+
|
|
460
|
+
case prop_type
|
|
461
|
+
when T::Types::Simple
|
|
462
|
+
sample_value_for_type(prop_type.raw_type, field_name, depth + 1)
|
|
463
|
+
when T::Types::Union
|
|
464
|
+
preferred = prop_type.types.find { |type| !nil_type?(type) } || prop_type.types.first
|
|
465
|
+
sample_value_for_type(preferred, field_name, depth + 1)
|
|
466
|
+
when T::Types::TypedArray
|
|
467
|
+
[sample_value_for_type(prop_type.type, field_name, depth + 1)]
|
|
468
|
+
when T::Types::TypedHash
|
|
469
|
+
key_sample = sample_value_for_type(prop_type.keys, "#{field_name}_key", depth + 1)
|
|
470
|
+
value_sample = sample_value_for_type(prop_type.values, "#{field_name}_value", depth + 1)
|
|
471
|
+
{ key_sample.to_s => value_sample }
|
|
472
|
+
when Class
|
|
473
|
+
sample_for_class_type(prop_type, field_name, depth)
|
|
474
|
+
else
|
|
475
|
+
sample_string(field_name)
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def sample_for_class_type(prop_type, field_name, depth)
|
|
480
|
+
if prop_type <= String
|
|
481
|
+
sample_string(field_name)
|
|
482
|
+
elsif prop_type <= Integer
|
|
483
|
+
1
|
|
484
|
+
elsif prop_type <= Float
|
|
485
|
+
1.0
|
|
486
|
+
elsif prop_type <= Numeric
|
|
487
|
+
1
|
|
488
|
+
elsif prop_type <= TrueClass || prop_type <= FalseClass
|
|
489
|
+
true
|
|
490
|
+
elsif prop_type <= T::Enum
|
|
491
|
+
enum_value = prop_type.values.first
|
|
492
|
+
enum_value ? enum_value.serialize : sample_string(field_name)
|
|
493
|
+
elsif prop_type <= T::Struct
|
|
494
|
+
sample_struct_values(prop_type, depth + 1)
|
|
495
|
+
else
|
|
496
|
+
sample_string(field_name)
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def nil_type?(type)
|
|
501
|
+
(type.respond_to?(:raw_type) && type.raw_type == NilClass) || type == NilClass
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def sample_string(field_name)
|
|
505
|
+
base = field_name.to_s.gsub(/[^a-z0-9]+/i, '_').gsub(/_{2,}/, '_').sub(/^_+|_+$/, '')
|
|
506
|
+
base = 'value' if base.empty?
|
|
507
|
+
"example_#{base}"
|
|
508
|
+
end
|
|
396
509
|
end
|
|
397
510
|
end
|
data/lib/dspy/version.rb
CHANGED