diff --git a/lib/captain/base_editor_service.rb b/lib/captain/base_editor_service.rb index bbb8cb2ad..dec8f741b 100644 --- a/lib/captain/base_editor_service.rb +++ b/lib/captain/base_editor_service.rb @@ -78,19 +78,15 @@ class Captain::BaseEditorService "#{endpoint}/v1" end - def make_api_call(payload) - payload = payload.deep_stringify_keys - instrumentation_params = build_instrumentation_params(payload) + def make_api_call(model:, messages:) + instrumentation_params = build_instrumentation_params(model, messages) instrument_llm_call(instrumentation_params) do - execute_ruby_llm_request(payload) + execute_ruby_llm_request(model: model, messages: messages) end end - def execute_ruby_llm_request(payload) - messages = payload['messages'] - model = payload['model'] - + def execute_ruby_llm_request(model:, messages:) Llm::Config.with_api_key(api_key, api_base: api_base) do |context| chat = context.chat(model: model) setup_chat_with_messages(chat, messages) @@ -109,24 +105,24 @@ class Captain::BaseEditorService end def apply_system_instructions(chat, messages) - system_msg = messages.find { |m| m['role'] == 'system' } - chat.with_instructions(system_msg['content']) if system_msg + system_msg = messages.find { |m| m[:role] == 'system' } + chat.with_instructions(system_msg[:content]) if system_msg end def send_conversation_messages(chat, messages) - conversation_messages = messages.reject { |m| m['role'] == 'system' } + conversation_messages = messages.reject { |m| m[:role] == 'system' } return nil if conversation_messages.empty? - return chat.ask(conversation_messages.first['content']) if conversation_messages.length == 1 + return chat.ask(conversation_messages.first[:content]) if conversation_messages.length == 1 add_conversation_history(chat, conversation_messages[0...-1]) - chat.ask(conversation_messages.last['content']) + chat.ask(conversation_messages.last[:content]) end def add_conversation_history(chat, messages) messages.each do |msg| - chat.add_message(role: msg['role'].to_sym, content: msg['content']) + chat.add_message(role: msg[:role].to_sym, content: msg[:content]) end end @@ -142,15 +138,15 @@ class Captain::BaseEditorService } end - def build_instrumentation_params(parsed_body) + def build_instrumentation_params(model, messages) { span_name: "llm.#{event_name}", account_id: account.id, conversation_id: conversation&.display_id, feature_name: event_name, - model: parsed_body['model'], - messages: parsed_body['messages'], - temperature: parsed_body['temperature'] + model: model, + messages: messages, + temperature: nil } end diff --git a/lib/captain/label_suggestion_service.rb b/lib/captain/label_suggestion_service.rb index 0eb717982..d959fdbab 100644 --- a/lib/captain/label_suggestion_service.rb +++ b/lib/captain/label_suggestion_service.rb @@ -2,10 +2,16 @@ class Captain::LabelSuggestionService < Captain::BaseEditorService CACHEABLE_EVENTS = %w[label_suggestion].freeze def label_suggestion_message - payload = label_suggestion_body - return nil if payload.blank? + content = labels_with_messages + return nil if content.blank? - response = make_api_call(payload) + response = make_api_call( + model: GPT_MODEL, # TODO: Use separate model for label suggestion + messages: [ + { role: 'system', content: prompt_from_file('label_suggestion') }, + { role: 'user', content: content } + ] + ) return response if response[:error].present? # LLMs are not deterministic - sometimes response includes "Labels:" prefix @@ -15,27 +21,6 @@ class Captain::LabelSuggestionService < Captain::BaseEditorService private - def label_suggestion_body - # TODO: Enable based on separate model and settings source - # Future: Different model for label suggestion - # Future: Settings-based feature gating - # For now: Enabled by default when API key available - - content = labels_with_messages - return value_from_cache if content.blank? - - { - model: GPT_MODEL, # TODO: Use separate model for label suggestion - messages: [ - { - role: 'system', - content: prompt_from_file('label_suggestion') - }, - { role: 'user', content: content } - ] - } - end - def labels_with_messages return nil unless valid_conversation?(conversation) diff --git a/lib/captain/reply_suggestion_service.rb b/lib/captain/reply_suggestion_service.rb index 753124b55..ceea19172 100644 --- a/lib/captain/reply_suggestion_service.rb +++ b/lib/captain/reply_suggestion_service.rb @@ -1,16 +1,10 @@ class Captain::ReplySuggestionService < Captain::BaseEditorService def reply_suggestion_message - make_api_call(reply_suggestion_body) - end - - private - - def reply_suggestion_body - { + make_api_call( model: GPT_MODEL, messages: [ { role: 'system', content: prompt_from_file('reply') } ].concat(conversation_messages) - } + ) end end diff --git a/lib/captain/rewrite_service.rb b/lib/captain/rewrite_service.rb index a9964232b..8ed2a8257 100644 --- a/lib/captain/rewrite_service.rb +++ b/lib/captain/rewrite_service.rb @@ -37,14 +37,13 @@ class Captain::RewriteService < Captain::BaseEditorService private def call_llm_with_prompt(system_content, user_content = event['data']['content']) - payload = { + make_api_call( model: GPT_MODEL, messages: [ { role: 'system', content: system_content }, { role: 'user', content: user_content } ] - } - make_api_call(payload) + ) end def render_liquid_template(template_content, variables = {}) diff --git a/lib/captain/summary_service.rb b/lib/captain/summary_service.rb index 59f8f7ea7..1c2f94aac 100644 --- a/lib/captain/summary_service.rb +++ b/lib/captain/summary_service.rb @@ -1,17 +1,11 @@ class Captain::SummaryService < Captain::BaseEditorService def summarize_message - make_api_call(summarize_body) - end - - private - - def summarize_body - { + make_api_call( model: GPT_MODEL, messages: [ { role: 'system', content: prompt_from_file('summary') }, { role: 'user', content: conversation.to_llm_text(include_contact_details: false) } ] - } + ) end end