dspy 1.0.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85ae2299dbddc20bfd710c68e9e8dfbeeb201b742e3fd18b768669ddc4443261
4
- data.tar.gz: ba0ee2d5f637f499448e456fb58f0513aa58b5b258e754bf1b32839ea8c49b63
3
+ metadata.gz: b4a5f4d14d66f2be69cb22fb8a464de7272080fcd9d6978b9e53ead8ca71753e
4
+ data.tar.gz: c7ba793f96742801e903e08b8615145f99f5d38abea9411c49c8a04028759f41
5
5
  SHA512:
6
- metadata.gz: 310de5ce11b23d29bd168069eae4f5ce3ac154ba91974c96b9d70e5d02a0dcb45122dc4c83f80097a409ff448a0a30d45ebec3ff0883d80b2cdd8f1215d2dfff
7
- data.tar.gz: 1ce5ff1bfe900bcedabab28efba1e8352fed81c6cbf458d5b7c54e8f7eea29fa6b7ee33a62dcc73b456ede6181a85bbf055541e4fb70037ac4de05e3be2b8ce9
6
+ metadata.gz: 1c6aa6ae8e37e7c4538d05c6c881e78e9329ea40341aaf982c7dfc44cac60257b8e403850e59e495ba6b9633fd0268b796015371d93502ef54ae58b3d04f2804
7
+ data.tar.gz: d0b9fa562e22160fe1299cf8a7dbb56d973af727ccd4678bafe3b3a59e4c922776c492744eccd87d7b1eb8c181a7db69468e62e2c36e8d5f7e10d21e856a1ff4
@@ -299,9 +299,11 @@ module DSPy
299
299
  # Coerces an array value, converting each element as needed
300
300
  sig { params(value: T.untyped, prop_type: T.untyped).returns(T.untyped) }
301
301
  def coerce_array_value(value, prop_type)
302
- return value unless value.is_a?(Array)
303
302
  return value unless prop_type.is_a?(T::Types::TypedArray)
304
303
 
304
+ value = try_parse_string_to_array(value)
305
+ return value unless value.is_a?(Array)
306
+
305
307
  element_type = prop_type.type
306
308
  value.map { |element| coerce_value_to_type(element, element_type) }
307
309
  end
@@ -347,6 +349,18 @@ module DSPy
347
349
  value
348
350
  end
349
351
 
352
+ # Attempts to parse a JSON string into an Array.
353
+ # Returns the parsed Array on success, or the original value otherwise.
354
+ sig { params(value: T.untyped).returns(T.untyped) }
355
+ def try_parse_string_to_array(value)
356
+ return value unless value.is_a?(String)
357
+
358
+ parsed = JSON.parse(value)
359
+ parsed.is_a?(Array) ? parsed : value
360
+ rescue JSON::ParserError
361
+ value
362
+ end
363
+
350
364
  # Attempts to parse a JSON string into a Hash.
351
365
  # Returns the parsed Hash on success, or the original value otherwise.
352
366
  sig { params(value: T.untyped).returns(T.untyped) }
data/lib/dspy/re_act.rb CHANGED
@@ -110,6 +110,8 @@ module DSPy
110
110
  end
111
111
 
112
112
  FINISH_ACTION = "finish"
113
+ THOUGHT_LOOP_INSTRUCTION = "Generate a thought about what to do next to process the given inputs."
114
+ OBSERVATION_LOOP_INSTRUCTION = "Process the observation from a tool and decide what to do next."
113
115
  sig { returns(T.class_of(DSPy::Signature)) }
114
116
  attr_reader :original_signature_class
115
117
 
@@ -198,7 +200,9 @@ module DSPy
198
200
  def with_instruction(instruction)
199
201
  clone = self.class.new(@original_signature_class, tools: @tools.values, max_iterations: @max_iterations)
200
202
  thought_generator = clone.instance_variable_get(:@thought_generator)
203
+ observation_processor = clone.instance_variable_get(:@observation_processor)
201
204
  clone.instance_variable_set(:@thought_generator, thought_generator.with_instruction(instruction))
205
+ clone.instance_variable_set(:@observation_processor, observation_processor.with_instruction(instruction))
202
206
  clone
203
207
  end
204
208
 
@@ -224,6 +228,14 @@ module DSPy
224
228
 
225
229
  private
226
230
 
231
+ sig { params(signature_class: T.class_of(DSPy::Signature), loop_instruction: String).returns(String) }
232
+ def loop_description(signature_class, loop_instruction)
233
+ [
234
+ signature_class.description,
235
+ loop_instruction
236
+ ].compact.reject(&:empty?).join("\n\n")
237
+ end
238
+
227
239
  # Serialize value for LLM display
228
240
  sig { params(value: T.untyped).returns(T.untyped) }
229
241
  def serialize_for_llm(value)
@@ -302,6 +314,13 @@ module DSPy
302
314
  action_enum_class = @action_enum_class
303
315
  input_context_type = signature_class.input_struct_class || String
304
316
 
317
+ # Carry the user signature's instructions into the loop prompt, then append the
318
+ # loop mechanics — mirroring Python DSPy's ReAct, which prepends
319
+ # signature.instructions to the react predictor's instructions. Without this the
320
+ # user's task description never reaches the LM: it is only set on the enhanced
321
+ # signature used for typing, which issues no LM calls.
322
+ thought_description = loop_description(signature_class, THOUGHT_LOOP_INSTRUCTION)
323
+
305
324
  # Get the output field type for the final_answer field
306
325
  output_field_name = signature_class.output_struct_class.props.keys.first
307
326
  output_field_type = signature_class.output_struct_class.props[output_field_name][:type_object]
@@ -309,7 +328,7 @@ module DSPy
309
328
  # Create new class that inherits from DSPy::Signature
310
329
  Class.new(DSPy::Signature) do
311
330
  # Set description
312
- description "Generate a thought about what to do next to process the given inputs."
331
+ description thought_description
313
332
 
314
333
  # Define input fields
315
334
  input do
@@ -339,10 +358,12 @@ module DSPy
339
358
  sig { params(signature_class: T.class_of(DSPy::Signature), data_format: Symbol).returns(T.class_of(DSPy::Signature)) }
340
359
  def create_observation_signature(signature_class, data_format)
341
360
  input_context_type = signature_class.input_struct_class || String
361
+ observation_description = loop_description(signature_class, OBSERVATION_LOOP_INSTRUCTION)
362
+
342
363
  # Create new class that inherits from DSPy::Signature
343
364
  Class.new(DSPy::Signature) do
344
365
  # Set description
345
- description "Process the observation from a tool and decide what to do next."
366
+ description observation_description
346
367
 
347
368
  # Define input fields
348
369
  input do
data/lib/dspy/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DSPy
4
- VERSION = "1.0.0"
4
+ VERSION = "1.0.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dspy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vicente Reig Rincón de Arellano