\d+)/conversations/meta}.match(req.path)
+ next unless match_data.present? && req.get?
+
+ user_uid = req.get_header('HTTP_UID')
+ api_access_token = req.get_header('HTTP_API_ACCESS_TOKEN') || req.get_header('api_access_token')
+ user_identifier = user_uid.presence || api_access_token.presence
+
+ "#{user_identifier}:#{match_data[:account_id]}" if user_identifier.present?
+ end
+
## ----------------------------------------------- ##
end
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