Merge branch 'chore/improve-conversation-snooze' into chore/improve-custom-snooze

This commit is contained in:
Sivin Varghese
2026-02-20 13:41:09 +05:30
committed by GitHub
9 changed files with 47 additions and 18 deletions
+4 -4
View File
@@ -583,14 +583,14 @@ GEM
newrelic_rpm (9.6.0)
base64
nio4r (2.7.3)
nokogiri (1.18.9)
nokogiri (1.19.1)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.18.9-arm64-darwin)
nokogiri (1.19.1-arm64-darwin)
racc (~> 1.4)
nokogiri (1.18.9-x86_64-darwin)
nokogiri (1.19.1-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.18.9-x86_64-linux-gnu)
nokogiri (1.19.1-x86_64-linux-gnu)
racc (~> 1.4)
oauth (1.1.0)
oauth-tty (~> 1.0, >= 1.0.1)
@@ -47,7 +47,7 @@ defineProps({
<div
v-if="isComingSoon"
class="absolute inset-0 flex items-center justify-center backdrop-blur-[2px] rounded-2xl bg-gradient-to-br from-n-background/90 via-n-background/70 to-n-background/95 cursor-not-allowed"
class="absolute inset-0 flex items-center justify-center backdrop-blur-[2px] rounded-2xl bg-gradient-to-br from-n-surface-1/90 via-n-surface-1/70 to-n-surface-1/95 cursor-not-allowed"
>
<span class="text-n-slate-12 font-medium text-sm">
{{ $t('CHANNEL_SELECTOR.COMING_SOON') }} 🚀
@@ -33,7 +33,7 @@ const titleCase = computed(() => props.title.toLowerCase());
<section class="mx-0 mb-3">
<div
v-if="showTitle"
class="sticky top-0 pt-2 py-3 z-50 bg-gradient-to-b from-n-background from-80% to-transparent mb-3 -mx-1.5 px-1.5"
class="sticky top-0 pt-2 py-3 z-20 bg-gradient-to-b from-n-surface-1 from-80% to-transparent mb-3 -mx-1.5 px-1.5"
>
<h3 class="text-sm text-n-slate-11">{{ title }}</h3>
</div>
@@ -94,7 +94,7 @@ const handleAssignLabels = labels => {
<template>
<div
class="sticky top-0 z-10 bg-gradient-to-b from-n-background from-90% to-transparent px-6 pt-1 pb-2"
class="sticky top-0 z-10 bg-gradient-to-b from-n-surface-1 from-90% to-transparent pt-1 pb-2"
>
<BulkSelectBar
v-model="selectionModel"
+13
View File
@@ -221,6 +221,19 @@ class Rack::Attack
match_data[:account_id] if match_data.present?
end
## Prevent increased use of conversations meta API per user
throttle('/api/v1/accounts/:account_id/conversations/meta/user',
limit: ENV.fetch('RATE_LIMIT_CONVERSATIONS_META', '30').to_i, period: 1.minute) do |req|
match_data = %r{/api/v1/accounts/(?<account_id>\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
+10 -10
View File
@@ -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
@@ -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
@@ -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
@@ -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