Skip to content
Snippets Groups Projects
Commit 9e9f63dd authored by Sincheol (David) Kim's avatar Sincheol (David) Kim
Browse files

Add missing thread to chat conversation

Missing thread was causing the Duo Code Review Chat to load the
messages from first thread all the time which is incorrect.
It should load messages from the current thread only.
parent 12fbfb21
No related branches found
No related tags found
3 merge requests!181325Fix ambiguous `created_at` in project.rb,!180187Draft: Update dashboard editing to save visualizations directly to the dashboard file,!180126Add missing thread to chat conversation
......@@ -14,7 +14,7 @@ class ReactExecutor
AgentEventError = Class.new(StandardError)
RetryableAgentEventError = Class.new(StandardError)
attr_reader :tools, :user_input, :context, :response_handler
attr_reader :tools, :user_input, :context, :response_handler, :thread
attr_accessor :iterations
MAX_ITERATIONS = 10
......@@ -30,8 +30,9 @@ class ReactExecutor
# @param [GitlabContext] context - Gitlab context containing useful context information
# @param [ResponseService] response_handler - Handles returning the response to the client
# @param [ResponseService] stream_response_handler - Handles streaming chunks to the client
def initialize(user_input:, tools:, context:, response_handler:, stream_response_handler: nil)
def initialize(user_input:, tools:, context:, response_handler:, stream_response_handler: nil, thread: nil)
@user_input = user_input
@thread = thread
@tools = tools
@context = context
@iterations = 0
......@@ -308,7 +309,7 @@ def model_metadata_params
end
def conversation
Gitlab::Llm::Chain::Utils::ChatConversation.new(context.current_user)
Gitlab::Llm::Chain::Utils::ChatConversation.new(context.current_user, thread)
.truncated_conversation_list
end
......
......@@ -7,8 +7,9 @@ module Utils
class ChatConversation
LAST_N_MESSAGES = 50
def initialize(user)
def initialize(user, thread)
@user = user
@thread = thread
end
# We save a maximum of 50 chat history messages
......@@ -36,13 +37,13 @@ def truncated_conversation_list(last_n: LAST_N_MESSAGES)
private
attr_reader :user
attr_reader :user, :thread
# agent_version is deprecated, Chat conversation doesn't have this param anymore
# returns successful interactions with chat where both question and answer are present
# messages are grouped into conversations based on request_id
def successful_conversations
ChatStorage.new(user, nil)
ChatStorage.new(user, nil, thread)
.last_conversation
.reject { |message| message.errors.present? || message.content.blank? }
.group_by(&:request_id)
......
......@@ -124,6 +124,7 @@ def agent_or_tool_response(response_handler)
Gitlab::Duo::Chat::ReactExecutor.new(
user_input: prompt_message.content,
thread: prompt_message.thread,
tools: tools,
context: context,
response_handler: response_handler,
......
......@@ -4,10 +4,11 @@
RSpec.describe Gitlab::Llm::Chain::Utils::ChatConversation, feature_category: :duo_chat do
describe "#truncated_conversation_list" do
subject(:conversation) { described_class.new(user).truncated_conversation_list }
subject(:conversation) { described_class.new(user, thread).truncated_conversation_list }
let_it_be(:organization) { create(:organization) }
let(:user) { create(:user, organizations: [organization]) }
let(:thread) { create(:ai_conversation_thread, user: user) }
before do
allow(::Gitlab::Llm::ChatStorage).to receive(:last_conversation).and_return(messages)
......@@ -33,7 +34,7 @@
end
context "with limit on messages" do
subject(:conversation) { described_class.new(user).truncated_conversation_list(last_n: 3) }
subject(:conversation) { described_class.new(user, thread).truncated_conversation_list(last_n: 3) }
it "returns exact number of messages" do
expect(history).to contain_exactly("answer 1", "question 2", "answer 2")
......
......@@ -72,8 +72,9 @@
let(:response_handler) { instance_double(Gitlab::Llm::ResponseService) }
let(:stream_response_handler) { nil }
let(:thread) { create(:ai_conversation_thread, user: user) }
let(:prompt_message) do
build(:ai_chat_message, user: user, resource: resource, request_id: 'uuid', content: content)
build(:ai_chat_message, user: user, resource: resource, request_id: 'uuid', content: content, thread: thread)
end
let(:tools) do
......@@ -92,6 +93,7 @@
it 'calls the SingleAction Agent with the right parameters', :snowplow do
expected_params = [
user_input: content,
thread: thread,
tools: match_array(tools),
context: context,
response_handler: response_handler,
......@@ -103,7 +105,8 @@
end
expect(response_handler).to receive(:execute)
expect(::Gitlab::Llm::ResponseService).to receive(:new).with(context, { request_id: 'uuid', ai_action: :chat })
expect(::Gitlab::Llm::ResponseService).to receive(:new)
.with(context, { request_id: 'uuid', ai_action: :chat, thread: thread })
.and_return(response_handler)
expect(::Gitlab::Llm::Chain::GitlabContext).to receive(:new)
.with(current_user: user, container: expected_container, resource: resource, ai_request: ai_request,
......@@ -131,7 +134,7 @@
context 'when client_subscription_id is set' do
let(:prompt_message) do
build(:ai_chat_message, user: user, resource: resource,
build(:ai_chat_message, user: user, resource: resource, thread: thread,
request_id: 'uuid', client_subscription_id: 'someid', content: content)
end
......@@ -140,6 +143,7 @@
it 'correctly initializes response handlers' do
expected_params = [
user_input: content,
thread: thread,
tools: an_instance_of(Array),
context: an_instance_of(Gitlab::Llm::Chain::GitlabContext),
response_handler: response_handler,
......@@ -152,12 +156,12 @@
expect(response_handler).to receive(:execute)
expect(::Gitlab::Llm::ResponseService).to receive(:new).with(
an_instance_of(Gitlab::Llm::Chain::GitlabContext), { request_id: 'uuid', ai_action: :chat }
an_instance_of(Gitlab::Llm::Chain::GitlabContext), { request_id: 'uuid', ai_action: :chat, thread: thread }
).and_return(response_handler)
expect(::Gitlab::Llm::ResponseService).to receive(:new).with(
an_instance_of(Gitlab::Llm::Chain::GitlabContext), { request_id: 'uuid', ai_action: :chat,
client_subscription_id: 'someid' }
an_instance_of(Gitlab::Llm::Chain::GitlabContext),
{ request_id: 'uuid', ai_action: :chat, client_subscription_id: 'someid', thread: thread }
).and_return(stream_response_handler).twice
expect(stream_response_handler).to receive(:execute).with(response: anything, save_message: false)
expect(categorize_service).to receive(:execute)
......@@ -243,6 +247,7 @@
it 'calls zero shot agent with selected tools' do
expected_params = [
user_input: content,
thread: thread,
tools: match_array(tools),
context: context,
response_handler: response_handler,
......@@ -253,7 +258,8 @@
expect(instance).to receive(:execute).and_return(answer)
end
expect(response_handler).to receive(:execute)
expect(::Gitlab::Llm::ResponseService).to receive(:new).with(context, { ai_action: :chat, request_id: 'uuid' })
expect(::Gitlab::Llm::ResponseService).to receive(:new)
.with(context, { ai_action: :chat, request_id: 'uuid', thread: thread })
.and_return(response_handler)
expect(::Gitlab::Llm::Chain::GitlabContext).to receive(:new)
.with(current_user: user, container: expected_container, resource: resource,
......@@ -428,6 +434,7 @@
it 'does not execute question categorization' do
expected_params = [
user_input: content,
thread: thread,
tools: match_array(tools),
context: context,
response_handler: response_handler,
......@@ -439,7 +446,8 @@
end
allow(response_handler).to receive(:execute)
allow(::Gitlab::Llm::ResponseService).to receive(:new).with(context, { request_id: 'uuid', ai_action: :chat })
allow(::Gitlab::Llm::ResponseService).to receive(:new)
.with(context, { request_id: 'uuid', ai_action: :chat, thread: thread })
.and_return(response_handler)
allow(::Gitlab::Llm::Chain::GitlabContext).to receive(:new)
.with(current_user: user, container: expected_container, resource: resource, ai_request: ai_request,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment