From d13437dc88647f85d09c626e594508175abb4a76 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 4 Apr 2025 14:16:48 +0530 Subject: [PATCH] feat: add base llm service using rubyllm --- enterprise/app/services/llm/base_service.rb | 24 ++++++++ .../services/llm/base_service_spec.rb | 55 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 enterprise/app/services/llm/base_service.rb create mode 100644 spec/enterprise/services/llm/base_service_spec.rb diff --git a/enterprise/app/services/llm/base_service.rb b/enterprise/app/services/llm/base_service.rb new file mode 100644 index 000000000..1c252ef9d --- /dev/null +++ b/enterprise/app/services/llm/base_service.rb @@ -0,0 +1,24 @@ +class Llm::BaseService + DEFAULT_MODEL = 'gpt-4o-mini'.freeze + + def initialize + setup_ruby_llm + setup_model + rescue StandardError => e + raise "Failed to initialize LLM client: #{e.message}" + end + + private + + def setup_ruby_llm + api_key = InstallationConfig.find_by!(name: 'CAPTAIN_OPEN_AI_API_KEY').value + ::RubyLLM.configure do |config| + config.openai_api_key = api_key + end + end + + def setup_model + config_value = InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_MODEL')&.value + @model = (config_value.presence || DEFAULT_MODEL) + end +end diff --git a/spec/enterprise/services/llm/base_service_spec.rb b/spec/enterprise/services/llm/base_service_spec.rb new file mode 100644 index 000000000..211e9e7ea --- /dev/null +++ b/spec/enterprise/services/llm/base_service_spec.rb @@ -0,0 +1,55 @@ +require 'rails_helper' + +RSpec.describe Llm::BaseService do + describe '#initialize' do + let(:api_key) { 'test-key' } + let(:model) { 'custom-model' } + + before do + create(:installation_config, name: 'CAPTAIN_OPEN_AI_API_KEY', value: api_key) + end + + it 'configures RubyLLM with the API key' do + expect(RubyLLM).to receive(:configure) do |&block| + config = OpenStruct.new + block.call(config) + expect(config.openai_api_key).to eq(api_key) + end + + described_class.new + end + + context 'when API key is missing' do + before do + InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_API_KEY').destroy + end + + it 'raises an error' do + expect { described_class.new }.to raise_error( + RuntimeError, + /Failed to initialize LLM client: Couldn't find InstallationConfig/ + ) + end + end + + context 'when model config exists' do + before do + create(:installation_config, name: 'CAPTAIN_OPEN_AI_MODEL', value: model) + end + + it 'uses the configured model' do + allow(RubyLLM).to receive(:configure) + service = described_class.new + expect(service.instance_variable_get(:@model)).to eq(model) + end + end + + context 'when model config is missing' do + it 'uses the default model' do + allow(RubyLLM).to receive(:configure) + service = described_class.new + expect(service.instance_variable_get(:@model)).to eq(described_class::DEFAULT_MODEL) + end + end + end +end