Class: DSPy::ReAct

Inherits:
Predict show all
Extended by:
T::Sig
Includes:
Mixins::StructBuilder
Defined in:
lib/dspy/re_act.rb

Overview

ReAct Agent using Sorbet signatures

Defined Under Namespace

Classes: AvailableTool, InvalidActionError, MaxIterationsError, TypeMismatchError

Constant Summary collapse

FINISH_ACTION =
"finish"
THOUGHT_LOOP_INSTRUCTION =
"Generate a thought about what to do next to process the given inputs."
OBSERVATION_LOOP_INSTRUCTION =
"Process the observation from a tool and decide what to do next."

Constants inherited from Module

Module::DEFAULT_MODULE_SUBSCRIPTION_SCOPE

Instance Attribute Summary collapse

Attributes inherited from Predict

#demos, #signature_class

Instance Method Summary collapse

Methods inherited from Predict

#add_examples, #configure, #forward_untyped, from_h, #system_signature, #user_signature, #with_prompt

Methods included from Mixins::TypeCoercion

deserialize_enum, enum_type?, extract_enum_class

Methods inherited from Module

#call, #call_untyped, #configure, #configure_predictor, #dup_for_thread, #forward_untyped, inherited, #lm, #module_scope_id, #module_scope_label, #module_scope_label=, module_subscription_specs, #registered_module_subscriptions, #save, subscribe, #to_h, #unsubscribe_module_events

Methods included from Callbacks

included

Constructor Details

#initialize(signature_class, tools: [], max_iterations: 5) ⇒ ReAct

Returns a new instance of ReAct.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/dspy/re_act.rb', line 129

def initialize(signature_class, tools: [], max_iterations: 5)
  @original_signature_class = signature_class
  @tools = T.let({}, T::Hash[String, T.untyped])
  tools.each { |tool| @tools[tool.name.downcase] = tool }
  @max_iterations = max_iterations
  @data_format = T.let(DSPy.config.lm&.data_format || :json, Symbol)

  # Create dynamic ActionEnum class with tool names + finish
  @action_enum_class = create_action_enum_class

  # Create dynamic signature classes that include the original input fields
  thought_signature = create_thought_signature(signature_class, @data_format)
  observation_signature = create_observation_signature(signature_class, @data_format)

  # Create thought generator using Predict to preserve field descriptions
  @thought_generator = T.let(DSPy::Predict.new(thought_signature), DSPy::Predict)

  # Create observation processor using Predict to preserve field descriptions
  @observation_processor = T.let(DSPy::Predict.new(observation_signature), DSPy::Predict)

  # Create enhanced output struct with ReAct fields
  @enhanced_output_struct = create_enhanced_output_struct(signature_class)
  enhanced_output_struct = @enhanced_output_struct

  # Create enhanced signature class
  enhanced_signature = Class.new(DSPy::Signature) do
    # Set the description
    description signature_class.description

    # Use the same input struct
    @input_struct_class = signature_class.input_struct_class

    # Use the enhanced output struct with ReAct fields
    @output_struct_class = enhanced_output_struct

    # Store original signature name
    @original_signature_name = signature_class.name

    class << self
      attr_reader :input_struct_class, :output_struct_class, :original_signature_name
      
      # Override name to return the original signature name
      def name
        @original_signature_name || super
      end
    end
  end

  # Call parent constructor with enhanced signature
  super(enhanced_signature)
end

Instance Attribute Details

#enhanced_output_structObject (readonly)

Returns the value of attribute enhanced_output_struct.



119
120
121
# File 'lib/dspy/re_act.rb', line 119

def enhanced_output_struct
  @enhanced_output_struct
end

#max_iterationsObject (readonly)

Returns the value of attribute max_iterations.



125
126
127
# File 'lib/dspy/re_act.rb', line 125

def max_iterations
  @max_iterations
end

#original_signature_classObject (readonly)

Returns the value of attribute original_signature_class.



116
117
118
# File 'lib/dspy/re_act.rb', line 116

def original_signature_class
  @original_signature_class
end

#toolsObject (readonly)

Returns the value of attribute tools.



122
123
124
# File 'lib/dspy/re_act.rb', line 122

def tools
  @tools
end

Instance Method Details

#forward(**kwargs) ⇒ Object



218
219
220
221
222
223
224
225
226
227
# File 'lib/dspy/re_act.rb', line 218

def forward(**kwargs)
  # Validate input
  input_struct = @original_signature_class.input_struct_class.new(**kwargs)

  # Execute ReAct reasoning loop
  reasoning_result = execute_react_reasoning_loop(input_struct)

  # Create enhanced output with all ReAct data
  create_enhanced_result(kwargs, reasoning_result)
end

#named_predictorsObject



182
183
184
185
186
187
# File 'lib/dspy/re_act.rb', line 182

def named_predictors
  pairs = T.let([], T::Array[[String, DSPy::Module]])
  pairs << ["thought_generator", @thought_generator]
  pairs << ["observation_processor", @observation_processor]
  pairs
end

#predictorsObject



190
191
192
# File 'lib/dspy/re_act.rb', line 190

def predictors
  named_predictors.map { |(_, predictor)| predictor }
end

#promptObject



195
196
197
# File 'lib/dspy/re_act.rb', line 195

def prompt
  @thought_generator.prompt
end

#with_examples(examples) ⇒ Object



210
211
212
213
214
215
# File 'lib/dspy/re_act.rb', line 210

def with_examples(examples)
  clone = self.class.new(@original_signature_class, tools: @tools.values, max_iterations: @max_iterations)
  thought_generator = clone.instance_variable_get(:@thought_generator)
  clone.instance_variable_set(:@thought_generator, thought_generator.with_examples(examples))
  clone
end

#with_instruction(instruction) ⇒ Object



200
201
202
203
204
205
206
207
# File 'lib/dspy/re_act.rb', line 200

def with_instruction(instruction)
  clone = self.class.new(@original_signature_class, tools: @tools.values, max_iterations: @max_iterations)
  thought_generator = clone.instance_variable_get(:@thought_generator)
  observation_processor = clone.instance_variable_get(:@observation_processor)
  clone.instance_variable_set(:@thought_generator, thought_generator.with_instruction(instruction))
  clone.instance_variable_set(:@observation_processor, observation_processor.with_instruction(instruction))
  clone
end