Class: Boxcars::IntelligenceBase
- Includes:
- UnifiedObservability
- Defined in:
- lib/boxcars/engine/intelligence_base.rb
Overview
A Base class for all Intelligence Engines
Instance Attribute Summary collapse
-
#all_params ⇒ Object
readonly
Returns the value of attribute all_params.
-
#provider ⇒ Object
readonly
Returns the value of attribute provider.
Attributes inherited from Engine
#batch_size, #prompts, #user_id
Instance Method Summary collapse
- #adapter(params:, api_key:) ⇒ Object
-
#client(prompt:, inputs: {}, api_key: nil, **kwargs) ⇒ Object
Get an answer from the engine.
-
#default_model_params ⇒ Object
can be overridden by provider subclass.
-
#initialize(provider:, description:, name:, prompts: [], batch_size: 20, **kwargs) ⇒ IntelligenceBase
constructor
The base Intelligence Engine is used by other engines to generate output from prompts.
- #lookup_provider_api_key(params:) ⇒ Object
-
#process_content(content) ⇒ Object
Process different content types.
-
#run(question) ⇒ Object
Run the engine with a question.
-
#validate_content(content) ⇒ Object
Validate content structure.
Methods inherited from Engine
#extract_answer, #generate, #generation_info, #get_num_tokens
Constructor Details
#initialize(provider:, description:, name:, prompts: [], batch_size: 20, **kwargs) ⇒ IntelligenceBase
The base Intelligence Engine is used by other engines to generate output from prompts
20 21 22 23 24 25 26 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 20 def initialize(provider:, description:, name:, prompts: [], batch_size: 20, **kwargs) user_id = kwargs.delete(:user_id) @provider = provider # Start with defaults, merge other kwargs, then explicitly set model if provided in initialize @all_params = default_model_params.merge(kwargs) super(description:, name:, prompts:, batch_size:, user_id:) end |
Instance Attribute Details
#all_params ⇒ Object (readonly)
Returns the value of attribute all_params.
11 12 13 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 11 def all_params @all_params end |
#provider ⇒ Object (readonly)
Returns the value of attribute provider.
11 12 13 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 11 def provider @provider end |
Instance Method Details
#adapter(params:, api_key:) ⇒ Object
37 38 39 40 41 42 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 37 def adapter(params:, api_key:) Intelligence::Adapter.build! @provider do |config| config.key api_key config. params end end |
#client(prompt:, inputs: {}, api_key: nil, **kwargs) ⇒ Object
Get an answer from the engine
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 66 def client(prompt:, inputs: {}, api_key: nil, **kwargs) params = all_params.merge(kwargs) api_key ||= lookup_provider_api_key(params:) raise Error, "No API key found for #{provider}" unless api_key adapter = adapter(api_key:, params:) convo = prompt.as_intelligence_conversation(inputs:) request_context = { user_id:, prompt: prompt&.as_prompt(inputs:)&.[](:prompt), inputs:, conversation_for_api: convo.to_h } request = Intelligence::ChatRequest.new(adapter:) start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) response_obj = nil begin response_obj = request.chat(convo) duration_ms = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) * 1000 if response_obj.success? success = true parsed_json_response = JSON.parse(response_obj.body) response_data = { success:, parsed_json: parsed_json_response, response_obj:, status_code: response_obj.status } track_ai_generation(duration_ms:, current_params: params, request_context:, response_data:, provider:) parsed_json_response else success = false = response_obj&.reason_phrase || "No response from API #{provider}" response_data = { success:, error: StandardError.new(), response_obj:, status_code: response_obj.status } track_ai_generation(duration_ms:, current_params: params, request_context:, response_data:, provider:) raise Error, end rescue Error => e # Re-raise Error exceptions (like the one above) without additional tracking # since they were already tracked in the else branch Boxcars.error("#{provider} Error: #{e.message}", :red) raise rescue StandardError => e duration_ms = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) * 1000 success = false error_obj = e response_data = { success:, error: error_obj, response_obj:, status_code: response_obj&.status } track_ai_generation(duration_ms:, current_params: params, request_context:, response_data:, provider:) Boxcars.error("#{provider} Error: #{e.message}", :red) raise end end |
#default_model_params ⇒ Object
can be overridden by provider subclass
29 30 31 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 29 def default_model_params {} end |
#lookup_provider_api_key(params:) ⇒ Object
33 34 35 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 33 def lookup_provider_api_key(params:) raise NotImplementedError, "lookup_provider_api_key method must be implemented by subclass" end |
#process_content(content) ⇒ Object
Process different content types
45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 45 def process_content(content) case content when String { type: "text", text: content } when Hash validate_content(content) when Array content.map { |c| process_content(c) } else raise ArgumentError, "Unsupported content type: #{content.class}" end end |
#run(question) ⇒ Object
Run the engine with a question
115 116 117 118 119 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 115 def run(question, **) prompt = Prompt.new(template: question) response = client(prompt:, **) extract_answer(response) end |
#validate_content(content) ⇒ Object
Validate content structure
59 60 61 62 63 |
# File 'lib/boxcars/engine/intelligence_base.rb', line 59 def validate_content(content) raise ArgumentError, "Content must have type and text fields" unless content[:type] && content[:text] content end |