diff --git a/enterprise/app/helpers/captain/chat_helper.rb b/enterprise/app/helpers/captain/chat_helper.rb index 2734e510e..d5ac6df33 100644 --- a/enterprise/app/helpers/captain/chat_helper.rb +++ b/enterprise/app/helpers/captain/chat_helper.rb @@ -53,15 +53,13 @@ module Captain::ChatHelper chat.on_end_message { |message| record_llm_generation(chat, message) } chat.on_tool_call { |tool_call| handle_tool_call(tool_call) } chat.on_tool_result { |result| handle_tool_result(result) } - chat end def handle_tool_call(tool_call) persist_thinking_message(tool_call) start_tool_span(tool_call) - @pending_tool_calls ||= [] - @pending_tool_calls.push(tool_call) + (@pending_tool_calls ||= []).push(tool_call) end def handle_tool_result(result) @@ -87,8 +85,9 @@ module Captain::ChatHelper messages: chat ? chat.messages.map { |m| { role: m.role.to_s, content: m.content.to_s } } : @messages, temperature: temperature, metadata: { - assistant_id: @assistant&.id - } + assistant_id: @assistant&.id, + channel_type: resolved_channel_type + }.compact } end @@ -104,6 +103,10 @@ module Captain::ChatHelper @account&.id || @assistant&.account_id end + def resolved_channel_type + Conversation.find_by(account_id: resolved_account_id, display_id: @conversation_id)&.inbox&.channel_type if @conversation_id + end + # Ensures all LLM calls and tool executions within an agentic loop # are grouped under a single trace/session in Langfuse. # @@ -127,10 +130,7 @@ module Captain::ChatHelper end def log_chat_completion_request - Rails.logger.info( - "#{self.class.name} Assistant: #{@assistant.id}, Requesting chat completion - for messages #{@messages} with #{@tools&.length || 0} tools - " - ) + Rails.logger.info("#{self.class.name} Assistant: #{@assistant.id}, Requesting chat completion " \ + "for messages #{@messages} with #{@tools&.length || 0} tools") end end diff --git a/enterprise/app/services/captain/assistant/agent_runner_service.rb b/enterprise/app/services/captain/assistant/agent_runner_service.rb index c832da93e..9aeee605f 100644 --- a/enterprise/app/services/captain/assistant/agent_runner_service.rb +++ b/enterprise/app/services/captain/assistant/agent_runner_service.rb @@ -114,6 +114,7 @@ class Captain::Assistant::AgentRunnerService if @conversation state[:conversation] = @conversation.attributes.symbolize_keys.slice(*CONVERSATION_STATE_ATTRIBUTES) + state[:channel_type] = @conversation.inbox&.channel_type state[:contact] = @conversation.contact.attributes.symbolize_keys.slice(*CONTACT_STATE_ATTRIBUTES) if @conversation.contact end @@ -151,7 +152,8 @@ class Captain::Assistant::AgentRunnerService ATTR_LANGFUSE_USER_ID => state[:account_id], format(ATTR_LANGFUSE_METADATA, 'assistant_id') => state[:assistant_id], format(ATTR_LANGFUSE_METADATA, 'conversation_id') => conversation[:id], - format(ATTR_LANGFUSE_METADATA, 'conversation_display_id') => conversation[:display_id] + format(ATTR_LANGFUSE_METADATA, 'conversation_display_id') => conversation[:display_id], + format(ATTR_LANGFUSE_METADATA, 'channel_type') => state[:channel_type] }.compact.transform_values(&:to_s) end diff --git a/spec/enterprise/services/captain/assistant/agent_runner_service_spec.rb b/spec/enterprise/services/captain/assistant/agent_runner_service_spec.rb index bbf712622..c3019b82c 100644 --- a/spec/enterprise/services/captain/assistant/agent_runner_service_spec.rb +++ b/spec/enterprise/services/captain/assistant/agent_runner_service_spec.rb @@ -278,6 +278,7 @@ RSpec.describe Captain::Assistant::AgentRunnerService do contact_id: contact.id, status: conversation.status ) + expect(state[:channel_type]).to eq(inbox.channel_type) end it 'includes contact attributes when contact is present' do diff --git a/spec/enterprise/services/captain/llm/assistant_chat_service_spec.rb b/spec/enterprise/services/captain/llm/assistant_chat_service_spec.rb index bc4ff0b63..4711e5f7e 100644 --- a/spec/enterprise/services/captain/llm/assistant_chat_service_spec.rb +++ b/spec/enterprise/services/captain/llm/assistant_chat_service_spec.rb @@ -28,6 +28,19 @@ RSpec.describe Captain::Llm::AssistantChatService do allow(mock_chat).to receive(:messages).and_return([]) end + describe 'instrumentation metadata' do + it 'passes channel_type to the agent session instrumentation' do + service = described_class.new(assistant: assistant, conversation_id: conversation.display_id) + + expect(service).to receive(:instrument_agent_session).with( + hash_including(metadata: hash_including(channel_type: conversation.inbox.channel_type)) + ).and_yield + + allow(mock_chat).to receive(:ask).and_return(mock_response) + service.generate_response(message_history: [{ role: 'user', content: 'Hello' }]) + end + end + describe 'image analysis' do context 'when user sends a message with an image attachment' do let(:message_history) do