# frozen_string_literal: true module Boxcars # used by Boxcars that have engine's to create a prompt. class Prompt attr_reader :template, :input_variables, :other_inputs, :output_variables # @param template [String] The template to use for the prompt. # @param input_variables [Array] The input vars to use for the prompt. Defaults to [:input] # @param other_inputs [Array] The other input vars to use for the prompt. Defaults to [] # @param output_variables [Array] The output vars to use for the prompt. Defaults to [:output] def initialize(template:, input_variables: nil, other_inputs: nil, output_variables: nil) @template = template @input_variables = input_variables || [:input] @other_inputs = other_inputs || [] @output_variables = output_variables || [:output] end # compute the prompt parameters with input substitutions (used for chatGPT) # @param inputs [Hash] The inputs to use for the prompt. # @return [Hash] The formatted prompt { messages: ...} # rubocop:disable Lint/UnusedMethodArgument def as_prompt(inputs: nil, prefixes: nil, show_roles: nil) { prompt: format(inputs) } end # rubocop:enable Lint/UnusedMethodArgument # compute the prompt parameters with input substitutions # @param inputs [Hash] The inputs to use for the prompt. # @return [Hash] The formatted prompt { prompt: "..."} def as_messages(inputs) { messages: [{ role: :assistant, content: format(inputs) }] } end # tack on the ongoing conversation if present to the prompt def with_conversation(conversation) return self unless conversation new_prompt = dup new_prompt.template += "\n\n#{conversation.message_text}" new_prompt end def default_prefixes end private # format the prompt with the input variables # @param inputs [Hash] The inputs to use for the prompt. # @return [String] The formatted prompt. # @raise [Boxcars::KeyError] if the template has extra keys. def format(inputs) @template % inputs rescue ::KeyError => e first_line = e.message.to_s.split("\n").first Boxcars.error "Missing prompt input key: #{first_line}" raise KeyError, "Prompt format error: #{first_line}" end end end