dspy 0.30.1 → 0.31.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/README.md +51 -64
- data/lib/dspy/evals.rb +21 -2
- data/lib/dspy/lm/adapter_factory.rb +40 -17
- data/lib/dspy/lm/errors.rb +3 -0
- data/lib/dspy/lm/json_strategy.rb +24 -8
- data/lib/dspy/lm.rb +62 -19
- data/lib/dspy/module.rb +6 -6
- data/lib/dspy/prompt.rb +94 -36
- data/lib/dspy/re_act.rb +50 -17
- data/lib/dspy/schema/sorbet_json_schema.rb +5 -2
- data/lib/dspy/schema/sorbet_toon_adapter.rb +80 -0
- data/lib/dspy/structured_outputs_prompt.rb +5 -3
- data/lib/dspy/type_serializer.rb +2 -1
- data/lib/dspy/version.rb +1 -1
- metadata +14 -51
- data/lib/dspy/lm/adapters/anthropic_adapter.rb +0 -291
- data/lib/dspy/lm/adapters/gemini/schema_converter.rb +0 -186
- data/lib/dspy/lm/adapters/gemini_adapter.rb +0 -220
- data/lib/dspy/lm/adapters/ollama_adapter.rb +0 -73
- data/lib/dspy/lm/adapters/openai/schema_converter.rb +0 -359
- data/lib/dspy/lm/adapters/openai_adapter.rb +0 -188
- data/lib/dspy/lm/adapters/openrouter_adapter.rb +0 -68
data/lib/dspy/prompt.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'json'
|
|
3
4
|
require 'sorbet-runtime'
|
|
5
|
+
require 'sorbet/toon'
|
|
6
|
+
|
|
4
7
|
require_relative 'few_shot_example'
|
|
8
|
+
require_relative 'schema/sorbet_toon_adapter'
|
|
5
9
|
|
|
6
10
|
module DSPy
|
|
7
11
|
class Prompt
|
|
@@ -33,6 +37,15 @@ module DSPy
|
|
|
33
37
|
DSPy.config.lm&.schema_format || @schema_format || :json
|
|
34
38
|
end
|
|
35
39
|
|
|
40
|
+
sig { returns(Symbol) }
|
|
41
|
+
def data_format
|
|
42
|
+
return @data_format if @data_format && @data_format != :json
|
|
43
|
+
|
|
44
|
+
lm = DSPy.config.lm
|
|
45
|
+
lm_format = lm&.respond_to?(:data_format) ? lm.data_format : nil
|
|
46
|
+
lm_format || @data_format || :json
|
|
47
|
+
end
|
|
48
|
+
|
|
36
49
|
sig { returns(T.nilable(T.class_of(Signature))) }
|
|
37
50
|
attr_reader :signature_class
|
|
38
51
|
|
|
@@ -44,10 +57,11 @@ module DSPy
|
|
|
44
57
|
few_shot_examples: T::Array[FewShotExample],
|
|
45
58
|
signature_class_name: T.nilable(String),
|
|
46
59
|
schema_format: Symbol,
|
|
47
|
-
signature_class: T.nilable(T.class_of(Signature))
|
|
60
|
+
signature_class: T.nilable(T.class_of(Signature)),
|
|
61
|
+
data_format: Symbol
|
|
48
62
|
).void
|
|
49
63
|
end
|
|
50
|
-
def initialize(instruction:, input_schema:, output_schema:, few_shot_examples: [], signature_class_name: nil, schema_format: :json, signature_class: nil)
|
|
64
|
+
def initialize(instruction:, input_schema:, output_schema:, few_shot_examples: [], signature_class_name: nil, schema_format: :json, signature_class: nil, data_format: :json)
|
|
51
65
|
@instruction = instruction
|
|
52
66
|
@few_shot_examples = few_shot_examples.freeze
|
|
53
67
|
@input_schema = input_schema.freeze
|
|
@@ -55,6 +69,7 @@ module DSPy
|
|
|
55
69
|
@signature_class_name = signature_class_name
|
|
56
70
|
@schema_format = schema_format
|
|
57
71
|
@signature_class = signature_class
|
|
72
|
+
@data_format = data_format
|
|
58
73
|
end
|
|
59
74
|
|
|
60
75
|
# Immutable update methods for optimization
|
|
@@ -67,7 +82,8 @@ module DSPy
|
|
|
67
82
|
few_shot_examples: @few_shot_examples,
|
|
68
83
|
signature_class_name: @signature_class_name,
|
|
69
84
|
schema_format: @schema_format,
|
|
70
|
-
signature_class: @signature_class
|
|
85
|
+
signature_class: @signature_class,
|
|
86
|
+
data_format: @data_format
|
|
71
87
|
)
|
|
72
88
|
end
|
|
73
89
|
|
|
@@ -80,7 +96,8 @@ module DSPy
|
|
|
80
96
|
few_shot_examples: new_examples,
|
|
81
97
|
signature_class_name: @signature_class_name,
|
|
82
98
|
schema_format: @schema_format,
|
|
83
|
-
signature_class: @signature_class
|
|
99
|
+
signature_class: @signature_class,
|
|
100
|
+
data_format: @data_format
|
|
84
101
|
)
|
|
85
102
|
end
|
|
86
103
|
|
|
@@ -106,7 +123,13 @@ module DSPy
|
|
|
106
123
|
sections << "```baml"
|
|
107
124
|
sections << render_baml_schema(@output_schema, :output)
|
|
108
125
|
sections << "```"
|
|
109
|
-
|
|
126
|
+
when :toon
|
|
127
|
+
sections << "Your input schema fields (TOON order) are:"
|
|
128
|
+
sections << Sorbet::Toon::SignatureFormatter.describe_signature(@signature_class, :input)
|
|
129
|
+
sections << ""
|
|
130
|
+
sections << "Your output schema fields (TOON order) are:"
|
|
131
|
+
sections << Sorbet::Toon::SignatureFormatter.describe_signature(@signature_class, :output)
|
|
132
|
+
else
|
|
110
133
|
sections << "Your input schema fields are:"
|
|
111
134
|
sections << "```json"
|
|
112
135
|
sections << JSON.pretty_generate(@input_schema)
|
|
@@ -117,11 +140,10 @@ module DSPy
|
|
|
117
140
|
sections << JSON.pretty_generate(@output_schema)
|
|
118
141
|
sections << "```"
|
|
119
142
|
end
|
|
120
|
-
|
|
143
|
+
|
|
121
144
|
sections << ""
|
|
122
145
|
sections << "All interactions will be structured in the following way, with the appropriate values filled in."
|
|
123
|
-
|
|
124
|
-
# Add few-shot examples if present
|
|
146
|
+
|
|
125
147
|
if @few_shot_examples.any?
|
|
126
148
|
sections << ""
|
|
127
149
|
sections << "Here are some examples:"
|
|
@@ -133,36 +155,59 @@ module DSPy
|
|
|
133
155
|
end
|
|
134
156
|
end
|
|
135
157
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
if data_format == :toon && @signature_class
|
|
159
|
+
sections << "## Input values"
|
|
160
|
+
sections << "```toon"
|
|
161
|
+
sections << "{input_values}"
|
|
162
|
+
sections << "```"
|
|
163
|
+
sections << ""
|
|
164
|
+
sections << "## Output values"
|
|
165
|
+
sections << "Respond exclusively with a ```toon``` block containing only the output fields defined above, in the same order."
|
|
166
|
+
sections << "```toon"
|
|
167
|
+
sections << "{output_values}"
|
|
168
|
+
sections << "```"
|
|
169
|
+
else
|
|
170
|
+
sections << "## Input values"
|
|
171
|
+
sections << "```json"
|
|
172
|
+
sections << "{input_values}"
|
|
173
|
+
sections << "```"
|
|
174
|
+
|
|
175
|
+
sections << "## Output values"
|
|
176
|
+
sections << "Respond exclusively with the output schema fields in the json block below."
|
|
177
|
+
sections << "```json"
|
|
178
|
+
sections << "{output_values}"
|
|
179
|
+
sections << "```"
|
|
180
|
+
end
|
|
181
|
+
|
|
147
182
|
sections << ""
|
|
148
183
|
sections << "In adhering to this structure, your objective is: #{@instruction}"
|
|
149
|
-
|
|
184
|
+
|
|
150
185
|
sections.join("\n")
|
|
151
186
|
end
|
|
152
187
|
|
|
153
188
|
sig { params(input_values: T::Hash[Symbol, T.untyped]).returns(String) }
|
|
154
189
|
def render_user_prompt(input_values)
|
|
155
190
|
sections = []
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
191
|
+
|
|
192
|
+
if data_format == :toon && @signature_class
|
|
193
|
+
toon_payload = DSPy::Schema::SorbetToonAdapter.render_input(@signature_class, input_values)
|
|
194
|
+
|
|
195
|
+
sections << "## Input Values"
|
|
196
|
+
sections << "```toon"
|
|
197
|
+
sections << toon_payload
|
|
198
|
+
sections << "```"
|
|
199
|
+
sections << ""
|
|
200
|
+
sections << "Respond with the corresponding output schema fields encoded as TOON inside a ```toon``` block starting with the heading `## Output values`."
|
|
201
|
+
else
|
|
202
|
+
sections << "## Input Values"
|
|
203
|
+
sections << "```json"
|
|
204
|
+
sections << JSON.pretty_generate(serialize_for_json(input_values))
|
|
205
|
+
sections << "```"
|
|
206
|
+
sections << ""
|
|
207
|
+
sections << "Respond with the corresponding output schema fields wrapped in a ```json ``` block,"
|
|
208
|
+
sections << "starting with the heading `## Output values`."
|
|
209
|
+
end
|
|
210
|
+
|
|
166
211
|
sections.join("\n")
|
|
167
212
|
end
|
|
168
213
|
|
|
@@ -184,7 +229,8 @@ module DSPy
|
|
|
184
229
|
input_schema: @input_schema,
|
|
185
230
|
output_schema: @output_schema,
|
|
186
231
|
signature_class_name: @signature_class_name,
|
|
187
|
-
schema_format: @schema_format
|
|
232
|
+
schema_format: @schema_format,
|
|
233
|
+
data_format: @data_format
|
|
188
234
|
}
|
|
189
235
|
end
|
|
190
236
|
|
|
@@ -198,13 +244,24 @@ module DSPy
|
|
|
198
244
|
output_schema: hash[:output_schema] || {},
|
|
199
245
|
few_shot_examples: examples,
|
|
200
246
|
signature_class_name: hash[:signature_class_name],
|
|
201
|
-
schema_format: hash[:schema_format] || :json
|
|
247
|
+
schema_format: hash[:schema_format] || :json,
|
|
248
|
+
data_format: hash[:data_format] || :json
|
|
202
249
|
)
|
|
203
250
|
end
|
|
204
251
|
|
|
205
252
|
# Create prompt from signature class
|
|
206
|
-
sig
|
|
207
|
-
|
|
253
|
+
sig do
|
|
254
|
+
params(
|
|
255
|
+
signature_class: T.class_of(Signature),
|
|
256
|
+
schema_format: T.nilable(Symbol),
|
|
257
|
+
data_format: T.nilable(Symbol)
|
|
258
|
+
).returns(Prompt)
|
|
259
|
+
end
|
|
260
|
+
def self.from_signature(signature_class, schema_format: nil, data_format: nil)
|
|
261
|
+
lm = DSPy.config.lm
|
|
262
|
+
schema_format ||= lm&.schema_format || :json
|
|
263
|
+
data_format ||= (lm&.respond_to?(:data_format) ? lm.data_format : nil) || :json
|
|
264
|
+
|
|
208
265
|
new(
|
|
209
266
|
instruction: signature_class.description || "Complete this task.",
|
|
210
267
|
input_schema: signature_class.input_json_schema,
|
|
@@ -212,7 +269,8 @@ module DSPy
|
|
|
212
269
|
few_shot_examples: [],
|
|
213
270
|
signature_class_name: signature_class.name,
|
|
214
271
|
schema_format: schema_format,
|
|
215
|
-
signature_class: signature_class
|
|
272
|
+
signature_class: signature_class,
|
|
273
|
+
data_format: data_format
|
|
216
274
|
)
|
|
217
275
|
end
|
|
218
276
|
|
|
@@ -336,4 +394,4 @@ module DSPy
|
|
|
336
394
|
result
|
|
337
395
|
end
|
|
338
396
|
end
|
|
339
|
-
end
|
|
397
|
+
end
|
data/lib/dspy/re_act.rb
CHANGED
|
@@ -98,13 +98,14 @@ module DSPy
|
|
|
98
98
|
@tools = T.let({}, T::Hash[String, T.untyped])
|
|
99
99
|
tools.each { |tool| @tools[tool.name.downcase] = tool }
|
|
100
100
|
@max_iterations = max_iterations
|
|
101
|
+
@data_format = T.let(DSPy.config.lm&.data_format || :json, Symbol)
|
|
101
102
|
|
|
102
103
|
# Create dynamic ActionEnum class with tool names + finish
|
|
103
104
|
@action_enum_class = create_action_enum_class
|
|
104
105
|
|
|
105
106
|
# Create dynamic signature classes that include the original input fields
|
|
106
|
-
thought_signature = create_thought_signature(signature_class)
|
|
107
|
-
observation_signature = create_observation_signature(signature_class)
|
|
107
|
+
thought_signature = create_thought_signature(signature_class, @data_format)
|
|
108
|
+
observation_signature = create_observation_signature(signature_class, @data_format)
|
|
108
109
|
|
|
109
110
|
# Create thought generator using Predict to preserve field descriptions
|
|
110
111
|
@thought_generator = T.let(DSPy::Predict.new(thought_signature), DSPy::Predict)
|
|
@@ -216,6 +217,28 @@ module DSPy
|
|
|
216
217
|
end
|
|
217
218
|
end
|
|
218
219
|
|
|
220
|
+
sig { params(input_struct: T.untyped).returns(T.untyped) }
|
|
221
|
+
def format_input_context(input_struct)
|
|
222
|
+
return input_struct if toon_data_format?
|
|
223
|
+
|
|
224
|
+
DSPy::TypeSerializer.serialize(input_struct).to_json
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
sig { params(history: T::Array[HistoryEntry]).returns(T.untyped) }
|
|
228
|
+
def format_history(history)
|
|
229
|
+
toon_data_format? ? history : serialize_history_for_llm(history)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
sig { params(observation: T.untyped).returns(T.untyped) }
|
|
233
|
+
def format_observation(observation)
|
|
234
|
+
toon_data_format? ? observation : serialize_for_llm(observation)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
sig { returns(T::Boolean) }
|
|
238
|
+
def toon_data_format?
|
|
239
|
+
@data_format == :toon
|
|
240
|
+
end
|
|
241
|
+
|
|
219
242
|
# Creates a dynamic ActionEnum class with tool names and "finish"
|
|
220
243
|
sig { returns(T.class_of(T::Enum)) }
|
|
221
244
|
def create_action_enum_class
|
|
@@ -241,9 +264,14 @@ module DSPy
|
|
|
241
264
|
end
|
|
242
265
|
|
|
243
266
|
# Creates a dynamic Thought signature that includes the original input fields
|
|
244
|
-
sig { params(signature_class: T.class_of(DSPy::Signature)).returns(T.class_of(DSPy::Signature)) }
|
|
245
|
-
def create_thought_signature(signature_class)
|
|
267
|
+
sig { params(signature_class: T.class_of(DSPy::Signature), data_format: Symbol).returns(T.class_of(DSPy::Signature)) }
|
|
268
|
+
def create_thought_signature(signature_class, data_format)
|
|
246
269
|
action_enum_class = @action_enum_class
|
|
270
|
+
input_context_type = if data_format == :toon
|
|
271
|
+
signature_class.input_struct_class || String
|
|
272
|
+
else
|
|
273
|
+
String
|
|
274
|
+
end
|
|
247
275
|
# Create new class that inherits from DSPy::Signature
|
|
248
276
|
Class.new(DSPy::Signature) do
|
|
249
277
|
# Set description
|
|
@@ -251,8 +279,8 @@ module DSPy
|
|
|
251
279
|
|
|
252
280
|
# Define input fields
|
|
253
281
|
input do
|
|
254
|
-
const :input_context,
|
|
255
|
-
description: "Serialized representation of all input fields"
|
|
282
|
+
const :input_context, input_context_type,
|
|
283
|
+
description: data_format == :toon ? "All original input fields with their typed values" : "Serialized representation of all input fields"
|
|
256
284
|
const :history, T::Array[HistoryEntry],
|
|
257
285
|
description: "Previous thoughts and actions, including observations from tools."
|
|
258
286
|
const :available_tools, T::Array[AvailableTool],
|
|
@@ -272,8 +300,13 @@ module DSPy
|
|
|
272
300
|
end
|
|
273
301
|
|
|
274
302
|
# Creates a dynamic observation signature that includes the original input fields
|
|
275
|
-
sig { params(signature_class: T.class_of(DSPy::Signature)).returns(T.class_of(DSPy::Signature)) }
|
|
276
|
-
def create_observation_signature(signature_class)
|
|
303
|
+
sig { params(signature_class: T.class_of(DSPy::Signature), data_format: Symbol).returns(T.class_of(DSPy::Signature)) }
|
|
304
|
+
def create_observation_signature(signature_class, data_format)
|
|
305
|
+
input_context_type = if data_format == :toon
|
|
306
|
+
signature_class.input_struct_class || String
|
|
307
|
+
else
|
|
308
|
+
String
|
|
309
|
+
end
|
|
277
310
|
# Create new class that inherits from DSPy::Signature
|
|
278
311
|
Class.new(DSPy::Signature) do
|
|
279
312
|
# Set description
|
|
@@ -281,8 +314,8 @@ module DSPy
|
|
|
281
314
|
|
|
282
315
|
# Define input fields
|
|
283
316
|
input do
|
|
284
|
-
const :input_context,
|
|
285
|
-
description: "Serialized representation of all input fields"
|
|
317
|
+
const :input_context, input_context_type,
|
|
318
|
+
description: data_format == :toon ? "All original input fields with their typed values" : "Serialized representation of all input fields"
|
|
286
319
|
const :history, T::Array[HistoryEntry],
|
|
287
320
|
description: "Previous thoughts, actions, and observations."
|
|
288
321
|
const :observation, T.untyped,
|
|
@@ -358,8 +391,8 @@ module DSPy
|
|
|
358
391
|
) do
|
|
359
392
|
# Generate thought and action
|
|
360
393
|
thought_obj = @thought_generator.forward(
|
|
361
|
-
input_context:
|
|
362
|
-
history:
|
|
394
|
+
input_context: format_input_context(input_struct),
|
|
395
|
+
history: format_history(history),
|
|
363
396
|
available_tools: available_tools_desc
|
|
364
397
|
)
|
|
365
398
|
|
|
@@ -617,9 +650,9 @@ module DSPy
|
|
|
617
650
|
sig { params(input_struct: T.untyped, history: T::Array[HistoryEntry], observation: T.untyped, available_tools_desc: T::Array[AvailableTool], iteration: Integer).returns(T::Hash[Symbol, T.untyped]) }
|
|
618
651
|
def process_observation_and_decide_next_step(input_struct, history, observation, available_tools_desc, iteration)
|
|
619
652
|
observation_result = @observation_processor.forward(
|
|
620
|
-
input_context:
|
|
621
|
-
history:
|
|
622
|
-
observation:
|
|
653
|
+
input_context: format_input_context(input_struct),
|
|
654
|
+
history: format_history(history),
|
|
655
|
+
observation: format_observation(observation)
|
|
623
656
|
)
|
|
624
657
|
|
|
625
658
|
return { should_finish: false } unless observation_result.next_step == NextStep::Finish
|
|
@@ -634,8 +667,8 @@ module DSPy
|
|
|
634
667
|
sig { params(input_struct: T.untyped, history: T::Array[HistoryEntry], available_tools_desc: T::Array[AvailableTool], observation_result: T.untyped, iteration: Integer).returns(T.untyped) }
|
|
635
668
|
def generate_forced_final_answer(input_struct, history, available_tools_desc, observation_result, iteration)
|
|
636
669
|
final_thought = @thought_generator.forward(
|
|
637
|
-
input_context:
|
|
638
|
-
history:
|
|
670
|
+
input_context: format_input_context(input_struct),
|
|
671
|
+
history: format_history(history),
|
|
639
672
|
available_tools: available_tools_desc
|
|
640
673
|
)
|
|
641
674
|
|
|
@@ -254,10 +254,13 @@ module DSPy
|
|
|
254
254
|
"DSPy uses _type for automatic type detection in union types."
|
|
255
255
|
end
|
|
256
256
|
|
|
257
|
+
struct_name = struct_class.name || "Struct#{format('%x', struct_class.object_id)}"
|
|
258
|
+
simple_name = struct_name.split('::').last || struct_name
|
|
259
|
+
|
|
257
260
|
# Add automatic _type field for type detection
|
|
258
261
|
properties[:_type] = {
|
|
259
262
|
type: "string",
|
|
260
|
-
const:
|
|
263
|
+
const: simple_name # Use the simple class name
|
|
261
264
|
}
|
|
262
265
|
required << "_type"
|
|
263
266
|
|
|
@@ -280,7 +283,7 @@ module DSPy
|
|
|
280
283
|
type: "object",
|
|
281
284
|
properties: properties,
|
|
282
285
|
required: required,
|
|
283
|
-
description: "#{
|
|
286
|
+
description: "#{struct_name} struct"
|
|
284
287
|
}
|
|
285
288
|
end
|
|
286
289
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'sorbet-runtime'
|
|
4
|
+
require 'sorbet/toon'
|
|
5
|
+
|
|
6
|
+
require_relative '../lm/errors'
|
|
7
|
+
|
|
8
|
+
module DSPy
|
|
9
|
+
module Schema
|
|
10
|
+
module SorbetToonAdapter
|
|
11
|
+
extend T::Sig
|
|
12
|
+
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
sig { params(signature_class: T.nilable(T.class_of(DSPy::Signature)), values: T::Hash[Symbol, T.untyped]).returns(String) }
|
|
16
|
+
def render_input(signature_class, values)
|
|
17
|
+
Sorbet::Toon.encode(
|
|
18
|
+
values,
|
|
19
|
+
signature: signature_class,
|
|
20
|
+
role: :input
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
sig { params(signature_class: T.nilable(T.class_of(DSPy::Signature)), values: T::Hash[Symbol, T.untyped]).returns(String) }
|
|
25
|
+
def render_expected_output(signature_class, values)
|
|
26
|
+
Sorbet::Toon.encode(
|
|
27
|
+
values,
|
|
28
|
+
signature: signature_class,
|
|
29
|
+
role: :output
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
sig { params(signature_class: T.nilable(T.class_of(DSPy::Signature)), toon_string: String).returns(T.untyped) }
|
|
34
|
+
def parse_output(signature_class, toon_string)
|
|
35
|
+
payload = strip_code_fences(toon_string)
|
|
36
|
+
|
|
37
|
+
Sorbet::Toon.decode(
|
|
38
|
+
payload,
|
|
39
|
+
signature: signature_class,
|
|
40
|
+
role: :output
|
|
41
|
+
)
|
|
42
|
+
rescue Sorbet::Toon::DecodeError => e
|
|
43
|
+
log_decode_error(payload, e)
|
|
44
|
+
raise DSPy::LM::AdapterError,
|
|
45
|
+
"Failed to parse TOON response: #{e.message}. Ensure the model replies with a ```toon``` block using the schema described in the system prompt."
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
sig { params(text: T.nilable(String)).returns(String) }
|
|
49
|
+
def strip_code_fences(text)
|
|
50
|
+
return '' if text.nil?
|
|
51
|
+
|
|
52
|
+
match = text.match(/```(?:toon)?\s*(.*?)```/m)
|
|
53
|
+
return match[1].strip if match
|
|
54
|
+
|
|
55
|
+
text.strip
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
sig { params(payload: String, error: StandardError).void }
|
|
59
|
+
def log_decode_error(payload, error)
|
|
60
|
+
logger = DSPy.logger if DSPy.respond_to?(:logger)
|
|
61
|
+
return unless logger.respond_to?(:warn)
|
|
62
|
+
|
|
63
|
+
preview = payload.to_s.lines.first(5).join
|
|
64
|
+
logger.warn(
|
|
65
|
+
event: 'toon.decode_error',
|
|
66
|
+
error: error.message,
|
|
67
|
+
preview: preview,
|
|
68
|
+
length: payload.to_s.length
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
sig { params(signature_class: T.nilable(T.class_of(DSPy::Signature)), role: Symbol).returns(String) }
|
|
73
|
+
def field_guidance(signature_class, role)
|
|
74
|
+
return '' unless signature_class
|
|
75
|
+
|
|
76
|
+
Sorbet::Toon::SignatureFormatter.describe_signature(signature_class, role)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -17,10 +17,11 @@ module DSPy
|
|
|
17
17
|
few_shot_examples: T::Array[T.untyped],
|
|
18
18
|
signature_class_name: T.nilable(String),
|
|
19
19
|
schema_format: Symbol,
|
|
20
|
-
signature_class: T.nilable(T.class_of(Signature))
|
|
20
|
+
signature_class: T.nilable(T.class_of(Signature)),
|
|
21
|
+
data_format: Symbol
|
|
21
22
|
).void
|
|
22
23
|
end
|
|
23
|
-
def initialize(instruction:, input_schema:, output_schema:, few_shot_examples: [], signature_class_name: nil, schema_format: :json, signature_class: nil)
|
|
24
|
+
def initialize(instruction:, input_schema:, output_schema:, few_shot_examples: [], signature_class_name: nil, schema_format: :json, signature_class: nil, data_format: :json)
|
|
24
25
|
normalized_examples = few_shot_examples.map do |example|
|
|
25
26
|
case example
|
|
26
27
|
when FewShotExample
|
|
@@ -39,7 +40,8 @@ module DSPy
|
|
|
39
40
|
few_shot_examples: normalized_examples,
|
|
40
41
|
signature_class_name: signature_class_name,
|
|
41
42
|
schema_format: schema_format,
|
|
42
|
-
signature_class: signature_class
|
|
43
|
+
signature_class: signature_class,
|
|
44
|
+
data_format: data_format
|
|
43
45
|
)
|
|
44
46
|
end
|
|
45
47
|
|
data/lib/dspy/type_serializer.rb
CHANGED
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.
|
|
4
|
+
version: 0.31.0
|
|
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:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: dry-configurable
|
|
@@ -67,77 +66,49 @@ dependencies:
|
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: '1.3'
|
|
69
68
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - "~>"
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: 0.22.0
|
|
76
|
-
type: :runtime
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - "~>"
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: 0.22.0
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: anthropic
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: 1.5.0
|
|
90
|
-
type: :runtime
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - "~>"
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: 1.5.0
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: gemini-ai
|
|
69
|
+
name: sorbet-runtime
|
|
99
70
|
requirement: !ruby/object:Gem::Requirement
|
|
100
71
|
requirements:
|
|
101
72
|
- - "~>"
|
|
102
73
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
74
|
+
version: '0.5'
|
|
104
75
|
type: :runtime
|
|
105
76
|
prerelease: false
|
|
106
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
78
|
requirements:
|
|
108
79
|
- - "~>"
|
|
109
80
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
81
|
+
version: '0.5'
|
|
111
82
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: sorbet-
|
|
83
|
+
name: sorbet-schema
|
|
113
84
|
requirement: !ruby/object:Gem::Requirement
|
|
114
85
|
requirements:
|
|
115
86
|
- - "~>"
|
|
116
87
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: '0.
|
|
88
|
+
version: '0.3'
|
|
118
89
|
type: :runtime
|
|
119
90
|
prerelease: false
|
|
120
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
92
|
requirements:
|
|
122
93
|
- - "~>"
|
|
123
94
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: '0.
|
|
95
|
+
version: '0.3'
|
|
125
96
|
- !ruby/object:Gem::Dependency
|
|
126
|
-
name: sorbet-
|
|
97
|
+
name: sorbet-baml
|
|
127
98
|
requirement: !ruby/object:Gem::Requirement
|
|
128
99
|
requirements:
|
|
129
100
|
- - "~>"
|
|
130
101
|
- !ruby/object:Gem::Version
|
|
131
|
-
version: '0.
|
|
102
|
+
version: '0.1'
|
|
132
103
|
type: :runtime
|
|
133
104
|
prerelease: false
|
|
134
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
135
106
|
requirements:
|
|
136
107
|
- - "~>"
|
|
137
108
|
- !ruby/object:Gem::Version
|
|
138
|
-
version: '0.
|
|
109
|
+
version: '0.1'
|
|
139
110
|
- !ruby/object:Gem::Dependency
|
|
140
|
-
name: sorbet-
|
|
111
|
+
name: sorbet-toon
|
|
141
112
|
requirement: !ruby/object:Gem::Requirement
|
|
142
113
|
requirements:
|
|
143
114
|
- - "~>"
|
|
@@ -209,13 +180,6 @@ files:
|
|
|
209
180
|
- lib/dspy/lm.rb
|
|
210
181
|
- lib/dspy/lm/adapter.rb
|
|
211
182
|
- lib/dspy/lm/adapter_factory.rb
|
|
212
|
-
- lib/dspy/lm/adapters/anthropic_adapter.rb
|
|
213
|
-
- lib/dspy/lm/adapters/gemini/schema_converter.rb
|
|
214
|
-
- lib/dspy/lm/adapters/gemini_adapter.rb
|
|
215
|
-
- lib/dspy/lm/adapters/ollama_adapter.rb
|
|
216
|
-
- lib/dspy/lm/adapters/openai/schema_converter.rb
|
|
217
|
-
- lib/dspy/lm/adapters/openai_adapter.rb
|
|
218
|
-
- lib/dspy/lm/adapters/openrouter_adapter.rb
|
|
219
183
|
- lib/dspy/lm/chat_strategy.rb
|
|
220
184
|
- lib/dspy/lm/errors.rb
|
|
221
185
|
- lib/dspy/lm/json_strategy.rb
|
|
@@ -248,6 +212,7 @@ files:
|
|
|
248
212
|
- lib/dspy/registry/signature_registry.rb
|
|
249
213
|
- lib/dspy/schema.rb
|
|
250
214
|
- lib/dspy/schema/sorbet_json_schema.rb
|
|
215
|
+
- lib/dspy/schema/sorbet_toon_adapter.rb
|
|
251
216
|
- lib/dspy/schema/version.rb
|
|
252
217
|
- lib/dspy/schema_adapters.rb
|
|
253
218
|
- lib/dspy/signature.rb
|
|
@@ -275,7 +240,6 @@ homepage: https://github.com/vicentereig/dspy.rb
|
|
|
275
240
|
licenses:
|
|
276
241
|
- MIT
|
|
277
242
|
metadata: {}
|
|
278
|
-
post_install_message:
|
|
279
243
|
rdoc_options: []
|
|
280
244
|
require_paths:
|
|
281
245
|
- lib
|
|
@@ -290,8 +254,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
290
254
|
- !ruby/object:Gem::Version
|
|
291
255
|
version: '0'
|
|
292
256
|
requirements: []
|
|
293
|
-
rubygems_version: 3.
|
|
294
|
-
signing_key:
|
|
257
|
+
rubygems_version: 3.6.9
|
|
295
258
|
specification_version: 4
|
|
296
259
|
summary: The Ruby framework for programming—rather than prompting—language models.
|
|
297
260
|
test_files: []
|