From db7e02b93b7aacad0f699366e9363cacb2526cbf Mon Sep 17 00:00:00 2001 From: Aakash Bakhle <48802744+aakashb95@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:16:43 +0530 Subject: [PATCH] feat: captain channel type langfuse metadata (#13574) # Pull Request Template ## Description Adds channel type to Captain assistant traces in Langfuse ## Type of change - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. image image ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Claude Opus 4.6 --- enterprise/app/helpers/captain/chat_helper.rb | 20 +++++++++---------- .../captain/assistant/agent_runner_service.rb | 4 +++- .../assistant/agent_runner_service_spec.rb | 1 + .../llm/assistant_chat_service_spec.rb | 13 ++++++++++++ 4 files changed, 27 insertions(+), 11 deletions(-) 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