Class: Boxcars::EngineBoxcar

Inherits:
Boxcar
  • Object
show all
Defined in:
lib/boxcars/boxcar/engine_boxcar.rb

Overview

For Boxcars that use an engine to do their work.

Constant Summary

Constants inherited from Boxcar

Boxcar::SCHEMA_KEY_ALIASES, Boxcar::TYPE_ALIASES

Instance Attribute Summary collapse

Attributes inherited from Boxcar

#description, #name, #parameters, #return_direct

Instance Method Summary collapse

Methods inherited from Boxcar

assi, #conduct, #conduct_result, hist, #parameters_json_schema, #run, #run_result, #schema, syst, #tool_call_name, #tool_definition, #tool_spec, user, #validate_inputs, #validate_outputs

Constructor Details

#initialize(prompt:, engine: nil, **kwargs) ⇒ EngineBoxcar

Create an engine-backed boxcar.

Parameters:

  • prompt (Boxcars::Prompt)

    The prompt to use for this boxcar with sane defaults.

  • engine (Boxcars::Engine) (defaults to: nil)

    The engine to use for this boxcar. Can be inherited from a train if nil.

  • kwargs (Hash)

    Additional arguments including: name, description, top_k, return_direct, and stop.



13
14
15
16
17
18
19
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 13

def initialize(prompt:, engine: nil, **kwargs)
  @prompt = prompt
  @engine = engine || Boxcars.engine.new
  @top_k = kwargs.delete(:top_k) || 5
  @stop = kwargs.delete(:stop) || ["Answer:"]
  super(**kwargs)
end

Instance Attribute Details

#engineObject

Returns the value of attribute engine.



7
8
9
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 7

def engine
  @engine
end

#promptObject

Returns the value of attribute prompt.



7
8
9
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 7

def prompt
  @prompt
end

#stopObject

Returns the value of attribute stop.



7
8
9
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 7

def stop
  @stop
end

#top_kObject

Returns the value of attribute top_k.



7
8
9
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 7

def top_k
  @top_k
end

Instance Method Details

#apply(input_list:, current_conversation: nil) ⇒ Array<Hash>

Apply a response from the engine.

Parameters:

  • input_list (Array<Hash>)

    A list of hashes of input values to use for the prompt.

  • current_conversation (Boxcars::Conversation) (defaults to: nil)

    Optional ongoing conversation to use for the prompt.

Returns:

  • (Array<Hash>)

    One output hash per input hash.



57
58
59
60
61
62
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 57

def apply(input_list:, current_conversation: nil)
  return [] if input_list.empty?

  response = generate(input_list:, current_conversation:)
  response.generations.map { |generation| { output_key => generation[0]&.text.to_s } }
end

#call(inputs:) ⇒ Hash

Execute the boxcar.

Parameters:

  • inputs (Hash)

    The inputs to the boxcar.

Returns:

  • (Hash)

    The outputs from the boxcar.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 77

def call(inputs:)
  # if we get errors back, try predicting again giving the errors with the inputs
  conversation = nil
  answer = nil
  4.times do
    text = predict(current_conversation: conversation, **prediction_variables(inputs)).to_s.strip
    answer = if text.empty?
               Result.from_error("Empty response from engine")
             else
               get_answer(text)
             end
    if answer.status == :error
      Boxcars.debug "have error, trying again: #{answer.answer}", :red
      conversation ||= Conversation.new
      conversation.add_assistant(text)
      conversation.add_user(answer.answer)
    else
      Boxcars.debug answer.to_json, :magenta
      return { output_key => answer }
    end
  end
  Boxcars.error answer.to_json, :red
  { output_key => "Error: #{answer}" }
rescue Boxcars::ConfigurationError, Boxcars::SecurityError => e
  raise e
rescue Boxcars::Error => e
  Boxcars.error e.message, :red
  { output_key => "Error: #{e.message}" }
end

#extract_code(code) ⇒ String

Remove backticks or triple backticks from the code.

Parameters:

  • code (String)

    The code to remove backticks from.

Returns:

  • (String)

    The code without backticks.



121
122
123
124
125
126
127
128
129
130
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 121

def extract_code(code)
  case code
  when /^```\w*/
    code.split(/```\w*\n/).last.split('```').first.strip
  when /^`(.+)`/
    ::Regexp.last_match(1)
  else
    code.gsub("`", "")
  end
end

#generate(input_list:, current_conversation: nil) ⇒ Boxcars::EngineResult

Generate a response from the engine.

Parameters:

  • input_list (Array<Hash>)

    A list of hashes of input values to use for the prompt.

  • current_conversation (Boxcars::Conversation) (defaults to: nil)

    Optional ongoing conversation to use for the prompt.

Returns:

Raises:



40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 40

def generate(input_list:, current_conversation: nil)
  raise Boxcars::ArgumentError, "#{self.class}#generate requires at least one input hash" if input_list.empty?

  stop = input_value(input_list.first, :stop)
  the_prompt = current_conversation ? prompt.with_conversation(current_conversation) : prompt
  if input_list.length == 1 && engine.respond_to?(:generate_one)
    return engine.generate_one(prompt: the_prompt, inputs: input_list.first, stop:)
  end

  prompts = input_list.map { |inputs| [the_prompt, inputs] }
  engine.generate(prompts:, stop:)
end

#input_keysObject

Input keys for the prompt.



22
23
24
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 22

def input_keys
  prompt.input_variables
end

#output_keyObject

The first output key.



32
33
34
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 32

def output_key
  output_keys.first
end

#output_keysObject

Output keys for the prompt.



27
28
29
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 27

def output_keys
  prompt.output_variables
end

#predict(current_conversation: nil, **kwargs) ⇒ String

Predict a response from the engine.

Parameters:

  • current_conversation (Boxcars::Conversation) (defaults to: nil)

    Optional ongoing conversation to use for the prompt.

  • kwargs (Hash)

    A hash of input values to use for the prompt.

Returns:

  • (String)

    The output value.



68
69
70
71
72
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 68

def predict(current_conversation: nil, **kwargs)
  prediction = apply(current_conversation:, input_list: [kwargs]).first[output_key]
  Boxcars.debug(prediction, :white) if Boxcars.configuration.log_generated
  prediction
end

#prediction_additional(_inputs) ⇒ Hash

Returns The additional variables for this boxcar.

Returns:

  • (Hash)

    The additional variables for this boxcar.



108
109
110
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 108

def prediction_additional(_inputs)
  { stop:, top_k: }
end

#prediction_variables(inputs) ⇒ Hash

Returns The variables for this boxcar.

Parameters:

  • inputs (Hash)

    The inputs to the boxcar.

Returns:

  • (Hash)

    The variables for this boxcar.



114
115
116
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 114

def prediction_variables(inputs)
  prediction_additional(inputs).merge(inputs)
end