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.
## 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