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.

Instance Attribute Summary collapse

Attributes inherited from Boxcar

#description, #name, #parameters, #return_direct

Instance Method Summary collapse

Methods inherited from Boxcar

assi, #conduct, hist, #load, #run, #save, #schema, syst, user, #validate_inputs, #validate_outputs

Constructor Details

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

A Boxcar is a container for a single tool to run.

Parameters:

  • prompt (Boxcars::Prompt)

    The prompt to use for this boxcar with sane defaults.

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

    The engine to user 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) ⇒ 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:

  • (Hash)

    A hash of the output key and the output value.



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

def apply(input_list:, current_conversation: nil)
  response = generate(input_list:, current_conversation:)
  response.generations.to_h do |generation|
    [output_key, generation[0]&.text.to_s]
  end
end

#call(inputs:) ⇒ Hash

call the boxcar

Parameters:

  • inputs (Hash)

    The inputs to the boxcar.

Returns:

  • (Hash)

    The outputs from the boxcar.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 84

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

#check_output_keysObject

check that there is exactly one output key

Raises:



75
76
77
78
79
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 75

def check_output_keys
  return unless output_keys.length != 1

  raise Boxcars::ArgumentError, "not supported when there is not exactly one output key. Got #{output_keys}."
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.



134
135
136
137
138
139
140
141
142
143
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 134

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:



45
46
47
48
49
50
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 45

def generate(input_list:, current_conversation: nil)
  stop = input_list[0][:stop]
  the_prompt = current_conversation ? prompt.with_conversation(current_conversation) : prompt
  prompts = input_list.map { |inputs| [the_prompt, inputs] }
  engine.generate(prompts:, stop:)
end

#input_keyObject

the first input key for the prompt



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

def input_key
  input_keys.first
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



37
38
39
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 37

def output_key
  output_keys.first
end

#output_keysObject

output keys



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

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.



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

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

#prediction_additional(_inputs) ⇒ Object

Returns Hash The additional variables for this boxcar.

Returns:

  • Hash The additional variables for this boxcar.



121
122
123
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 121

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

#prediction_input(inputs) ⇒ Object

Returns Hash The input variable for this boxcar.

Parameters:

  • inputs (Hash)

    The inputs to the boxcar.

Returns:

  • Hash The input variable for this boxcar.



116
117
118
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 116

def prediction_input(inputs)
  { input_key => inputs[input_key] }
end

#prediction_variables(inputs) ⇒ Object

Returns Hash The variables for this boxcar.

Parameters:

  • inputs (Hash)

    The inputs to the boxcar.

Returns:

  • Hash The variables for this boxcar.



127
128
129
# File 'lib/boxcars/boxcar/engine_boxcar.rb', line 127

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