Class: Boxcars::Cohere

Inherits:
Engine
  • Object
show all
Includes:
UnifiedObservability
Defined in:
lib/boxcars/engine/cohere.rb

Overview

A engine that uses Cohere’s API.

Constant Summary collapse

DEFAULT_PARAMS =

The default parameters to use when asking the engine.

{
  model: "command-r-plus",
  max_tokens: 4000,
  max_input_tokens: 1000,
  temperature: 0.2
}.freeze
DEFAULT_NAME =

the default name of the engine

"Cohere engine"
DEFAULT_DESCRIPTION =

the default description of the engine

"useful for when you need to use Cohere AI to answer questions. " \
"You should ask targeted questions"

Instance Attribute Summary collapse

Attributes inherited from Engine

#user_id

Instance Method Summary collapse

Methods inherited from Engine

#extract_answer, #generate, #generation_info, #get_num_tokens

Constructor Details

#initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], **kwargs) ⇒ Cohere

A engine is the driver for a single tool to run.



30
31
32
33
34
35
36
# File 'lib/boxcars/engine/cohere.rb', line 30

def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], **kwargs)
  user_id = kwargs.delete(:user_id)
  @llm_params = DEFAULT_PARAMS.merge(kwargs)
  @prompts = prompts
  @batch_size = 20
  super(description:, name:, user_id:)
end

Instance Attribute Details

#batch_sizeObject (readonly)

Returns the value of attribute batch_size.



9
10
11
# File 'lib/boxcars/engine/cohere.rb', line 9

def batch_size
  @batch_size
end

#llm_paramsObject (readonly)

Returns the value of attribute llm_params.



9
10
11
# File 'lib/boxcars/engine/cohere.rb', line 9

def llm_params
  @llm_params
end

#model_kwargsObject (readonly)

Returns the value of attribute model_kwargs.



9
10
11
# File 'lib/boxcars/engine/cohere.rb', line 9

def model_kwargs
  @model_kwargs
end

#promptsObject (readonly)

Returns the value of attribute prompts.



9
10
11
# File 'lib/boxcars/engine/cohere.rb', line 9

def prompts
  @prompts
end

Instance Method Details

#chat(params, cohere_api_key) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/boxcars/engine/cohere.rb', line 42

def chat(params, cohere_api_key)
  raise Boxcars::ConfigurationError('Cohere API key not set') if cohere_api_key.blank?

  # Define the API endpoint and parameters
  api_endpoint = 'https://api.cohere.ai/v1/chat'

  connection = Faraday.new(api_endpoint) do |faraday|
    faraday.request :url_encoded
    faraday.headers['Authorization'] = "Bearer #{cohere_api_key}"
    faraday.headers['Content-Type'] = 'application/json'
  end

  # Make the API call
  response = connection.post { |req| req.body = params.to_json }
  JSON.parse(response.body, symbolize_names: true)
end

#client(prompt:, inputs: {}, **kwargs) ⇒ Object

Get an answer from the engine.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/boxcars/engine/cohere.rb', line 64

def client(prompt:, inputs: {}, **kwargs)
  start_time = Time.now
  response_data = { response_obj: nil, parsed_json: nil, success: false, error: nil, status_code: nil }
  current_params = llm_params.merge(kwargs)
  current_prompt_object = prompt.is_a?(Array) ? prompt.first : prompt
  api_request_params = nil

  begin
    api_key = Boxcars.configuration.cohere_api_key(**kwargs)
    api_request_params = current_prompt_object.as_prompt(inputs:, prefixes: default_prefixes,
                                                         show_roles: true).merge(current_params)
    api_request_params[:message] = api_request_params.delete(:prompt)
    api_request_params[:stop_sequences] = api_request_params.delete(:stop) if api_request_params.key?(:stop)

    Boxcars.debug("Prompt after formatting:#{api_request_params[:message]}", :cyan) if Boxcars.configuration.log_prompts

    raw_response = _cohere_api_call(api_request_params, api_key)
    _process_cohere_response(raw_response, response_data)
  rescue StandardError => e
    _handle_cohere_error(e, response_data)
  ensure
    call_context = {
      start_time:,
      prompt_object: current_prompt_object,
      inputs:,
      api_request_params:,
      current_params:
    }
    _track_cohere_observability(call_context, response_data)
  end

  _cohere_handle_call_outcome(response_data:)
end

#conversation_model?(_model) ⇒ Boolean



38
39
40
# File 'lib/boxcars/engine/cohere.rb', line 38

def conversation_model?(_model)
  true
end

#default_paramsObject

Get the default parameters for the engine.



114
115
116
# File 'lib/boxcars/engine/cohere.rb', line 114

def default_params
  llm_params
end

#default_prefixesObject



145
146
147
# File 'lib/boxcars/engine/cohere.rb', line 145

def default_prefixes
  { system: "SYSTEM: ", user: "USER: ", assistant: "CHATBOT: ", history: :history }
end

#engine_typeObject

the engine type



124
125
126
# File 'lib/boxcars/engine/cohere.rb', line 124

def engine_type
  "claude"
end

#max_tokens_for_prompt(prompt_text) ⇒ Integer

Calculate the maximum number of tokens possible to generate for a prompt.



137
138
139
140
141
142
143
# File 'lib/boxcars/engine/cohere.rb', line 137

def max_tokens_for_prompt(prompt_text)
  num_tokens = get_num_tokens(prompt_text)

  # get max context size for model by name
  max_size = modelname_to_contextsize(model_name)
  max_size - num_tokens
end

#modelname_to_contextsize(_modelname) ⇒ Object

lookup the context size for a model by name



130
131
132
# File 'lib/boxcars/engine/cohere.rb', line 130

def modelname_to_contextsize(_modelname)
  100000
end

#run(question) ⇒ Object

get an answer from the engine for a question.

Raises:



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/boxcars/engine/cohere.rb', line 101

def run(question, **)
  prompt = Prompt.new(template: question)
  response = client(prompt:, **)

  raise Error, "Cohere: No response from API" unless response
  raise Error, "Cohere: #{response[:error]}" if response[:error]

  answer = response[:text]
  Boxcars.debug("Answer: #{answer}", :cyan)
  answer
end

#validate_response!(response, must_haves: %w[completion])) ⇒ Object

validate_response! method uses the base implementation with Cohere-specific must_haves



119
120
121
# File 'lib/boxcars/engine/cohere.rb', line 119

def validate_response!(response, must_haves: %w[completion])
  super
end