feat: BYOK users consume a single credit only
This commit is contained in:
@@ -28,7 +28,7 @@ module Enterprise::Captain::BaseTaskService
|
||||
end
|
||||
|
||||
def increment_usage
|
||||
credits = Llm::Models.credit_multiplier_for(configured_model)
|
||||
credits = using_hook_key? ? 1 : Llm::Models.credit_multiplier_for(configured_model)
|
||||
Rails.logger.info("[CAPTAIN][#{self.class.name}] Incrementing response usage for account #{account.id} by #{credits} credits")
|
||||
account.increment_response_usage(credits: credits)
|
||||
end
|
||||
|
||||
@@ -72,6 +72,11 @@ class Captain::BaseTaskService
|
||||
build_ruby_llm_response(response, messages)
|
||||
end
|
||||
rescue StandardError => e
|
||||
# TODO: RubyLLM throws the RubyLLM::Error when any API based error occurs
|
||||
# Just like inboxes have a reauthroizable error handling mechanism,
|
||||
# we should handle the errors if the account is using their own key.
|
||||
# If more than 5 errors occur, we disable the hook and notify the admins
|
||||
# see: https://rubyllm.com/error-handling/#rubyllm-error-hierarchy
|
||||
ChatwootExceptionTracker.new(e, account: account).capture_exception
|
||||
{ error: e.message, request_messages: messages }
|
||||
end
|
||||
@@ -128,6 +133,8 @@ class Captain::BaseTaskService
|
||||
end
|
||||
|
||||
def api_key
|
||||
# TODO: Once we support multiple LLM providers, ensure provider key is correctly looked up
|
||||
# Currently works because the only model/provider is OpenAI
|
||||
@api_key ||= openai_hook&.settings&.dig('api_key') || system_api_key
|
||||
end
|
||||
|
||||
@@ -135,6 +142,12 @@ class Captain::BaseTaskService
|
||||
@openai_hook ||= account.hooks.find_by(app_id: 'openai', status: 'enabled')
|
||||
end
|
||||
|
||||
def using_hook_key?
|
||||
# TODO: Once we support multiple LLM providers, ensure provider key is correctly looked up
|
||||
# Currently works because the only model/provider is OpenAI
|
||||
openai_hook&.settings&.dig('api_key').present?
|
||||
end
|
||||
|
||||
def system_api_key
|
||||
@system_api_key ||= InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_API_KEY')&.value
|
||||
end
|
||||
|
||||
@@ -69,6 +69,22 @@ RSpec.describe Captain::BaseTaskService, type: :model do
|
||||
service.perform
|
||||
end
|
||||
|
||||
context 'when account uses their own OpenAI key via hook' do
|
||||
let!(:openai_hook) { create(:integrations_hook, :openai, account: account, settings: { 'api_key' => 'user-own-key' }) }
|
||||
|
||||
it 'uses 1 credit regardless of model cost' do
|
||||
allow(account).to receive(:captain_editor_model).and_return('gpt-5.1')
|
||||
expect(account).to receive(:increment_response_usage).with(credits: 1)
|
||||
service.perform
|
||||
end
|
||||
|
||||
it 'uses 1 credit even for expensive models' do
|
||||
allow(account).to receive(:captain_editor_model).and_return('gpt-4.1')
|
||||
expect(account).to receive(:increment_response_usage).with(credits: 1)
|
||||
service.perform
|
||||
end
|
||||
end
|
||||
|
||||
context 'when result has an error' do
|
||||
let(:perform_result) { { error: 'API Error' } }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user