From a29908d8b404b52b86fec913e29077ab3b86a730 Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Tue, 26 Nov 2024 15:20:23 +0100 Subject: [PATCH 01/14] Feedbacks backend --- .../assistant/conversation/AgentMessage.tsx | 9 +- .../conversation/ConversationLayout.tsx | 2 +- .../conversation/ConversationViewer.tsx | 17 +- .../assistant/conversation/MessageGroup.tsx | 13 +- .../assistant/conversation/MessageItem.tsx | 64 +++-- .../assistant/conversation/UserMessage.tsx | 8 +- .../AssistantBuilderPreviewDrawer.tsx | 1 - front/lib/api/assistant/feedback.ts | 244 ++++++++++++++++++ front/lib/models/assistant/conversation.ts | 15 +- .../agent_message_feedback_resource.ts | 23 +- front/lib/swr/conversations.ts | 25 ++ front/migrations/db/migration_122.sql | 4 + .../conversations/[cId]/feedbacks.ts | 68 +++++ .../[cId]/messages/[mId]/feedbacks/index.ts | 134 ++++++++++ 14 files changed, 555 insertions(+), 72 deletions(-) create mode 100644 front/lib/api/assistant/feedback.ts create mode 100644 front/migrations/db/migration_122.sql create mode 100644 front/pages/api/w/[wId]/assistant/conversations/[cId]/feedbacks.ts create mode 100644 front/pages/api/w/[wId]/assistant/conversations/[cId]/messages/[mId]/feedbacks/index.ts diff --git a/front/components/assistant/conversation/AgentMessage.tsx b/front/components/assistant/conversation/AgentMessage.tsx index c28bb5db614d..c0039666e23e 100644 --- a/front/components/assistant/conversation/AgentMessage.tsx +++ b/front/components/assistant/conversation/AgentMessage.tsx @@ -1,5 +1,5 @@ import type { - ConversationMessageEmojiSelectorProps, + ConversationMessageFeedbackSelectorProps, ConversationMessageSizeType, } from "@dust-tt/sparkle"; import { @@ -13,6 +13,7 @@ import { ConversationMessage, DocumentDuplicateIcon, EyeIcon, + FeedbackSelector, Markdown, Popover, } from "@dust-tt/sparkle"; @@ -83,7 +84,7 @@ interface AgentMessageProps { isInModal: boolean; isLastMessage: boolean; message: AgentMessageType; - messageEmoji?: ConversationMessageEmojiSelectorProps; + messageFeedback: ConversationMessageFeedbackSelectorProps; owner: WorkspaceType; user: UserType; size: ConversationMessageSizeType; @@ -100,7 +101,7 @@ export function AgentMessage({ isInModal, isLastMessage, message, - messageEmoji, + messageFeedback, owner, user, size, @@ -368,6 +369,7 @@ export function AgentMessage({ icon={ArrowPathIcon} disabled={isRetryHandlerProcessing || shouldStream} />, + , ]; // References logic. @@ -464,7 +466,6 @@ export function AgentMessage({ name={`@${agentConfiguration.name}`} buttons={buttons} avatarBusy={agentMessageToRender.status === "created"} - messageEmoji={messageEmoji} renderName={() => { return (
diff --git a/front/components/assistant/conversation/ConversationLayout.tsx b/front/components/assistant/conversation/ConversationLayout.tsx index 598a76795790..4a2e4b61dece 100644 --- a/front/components/assistant/conversation/ConversationLayout.tsx +++ b/front/components/assistant/conversation/ConversationLayout.tsx @@ -91,7 +91,7 @@ export default function ConversationLayout({ ]); const { conversation, conversationError } = useConversation({ - conversationId: activeConversationId, + conversationId: activeConversationId ?? "", workspaceId: owner.sId, }); diff --git a/front/components/assistant/conversation/ConversationViewer.tsx b/front/components/assistant/conversation/ConversationViewer.tsx index 43e70920f455..eef5c2ea09aa 100644 --- a/front/components/assistant/conversation/ConversationViewer.tsx +++ b/front/components/assistant/conversation/ConversationViewer.tsx @@ -28,9 +28,9 @@ import { } from "@app/lib/client/conversation/event_handlers"; import { useConversation, + useConversationFeedbacks, useConversationMessages, useConversationParticipants, - useConversationReactions, useConversations, } from "@app/lib/swr/conversations"; import { classNames } from "@app/lib/utils"; @@ -39,7 +39,6 @@ const DEFAULT_PAGE_LIMIT = 50; interface ConversationViewerProps { conversationId: string; - hideReactions?: boolean; isFading?: boolean; isInModal?: boolean; onStickyMentionsChange?: (mentions: AgentMention[]) => void; @@ -62,7 +61,6 @@ const ConversationViewer = React.forwardRef< conversationId, onStickyMentionsChange, isInModal = false, - hideReactions = false, isFading = false, }, ref @@ -95,11 +93,6 @@ const ConversationViewer = React.forwardRef< limit: DEFAULT_PAGE_LIMIT, }); - const { reactions } = useConversationReactions({ - workspaceId: owner.sId, - conversationId, - }); - const { mutateConversationParticipants } = useConversationParticipants({ conversationId, workspaceId: owner.sId, @@ -192,6 +185,11 @@ const ConversationViewer = React.forwardRef< const { ref: viewRef, inView: isTopOfListVisible } = useInView(); + const { feedbacks } = useConversationFeedbacks({ + conversationId: conversationId ?? "", + workspaceId: owner.sId, + }); + // On page load or when new data is loaded, check if the top of the list // is visible and there is more data to load. If so, set the current // highest message ID and increment the page number to load more data. @@ -346,10 +344,9 @@ const ConversationViewer = React.forwardRef< messages={typedGroup} isLastMessageGroup={isLastGroup} conversationId={conversationId} - hideReactions={hideReactions} + feedbacks={feedbacks} isInModal={isInModal} owner={owner} - reactions={reactions} prevFirstMessageId={prevFirstMessageId} prevFirstMessageRef={prevFirstMessageRef} user={user} diff --git a/front/components/assistant/conversation/MessageGroup.tsx b/front/components/assistant/conversation/MessageGroup.tsx index 9f8684948ce4..0c0eade31096 100644 --- a/front/components/assistant/conversation/MessageGroup.tsx +++ b/front/components/assistant/conversation/MessageGroup.tsx @@ -1,5 +1,4 @@ import type { - ConversationMessageReactions, FetchConversationMessagesResponse, MessageWithContentFragmentsType, UserType, @@ -8,15 +7,15 @@ import type { import React, { useEffect, useRef } from "react"; import MessageItem from "@app/components/assistant/conversation/MessageItem"; +import type { AgentMessageFeedbackType } from "@app/lib/api/assistant/feedback"; interface MessageGroupProps { messages: MessageWithContentFragmentsType[]; isLastMessageGroup: boolean; conversationId: string; - hideReactions: boolean; + feedbacks: AgentMessageFeedbackType[]; isInModal: boolean; owner: WorkspaceType; - reactions: ConversationMessageReactions; prevFirstMessageId: string | null; prevFirstMessageRef: React.RefObject; user: UserType; @@ -33,10 +32,9 @@ export default function MessageGroup({ messages, isLastMessageGroup, conversationId, - hideReactions, + feedbacks, isInModal, owner, - reactions, prevFirstMessageId, prevFirstMessageRef, user, @@ -66,11 +64,12 @@ export default function MessageGroup({ feedback.messageId === message.sId + )} isInModal={isInModal} message={message} owner={owner} - reactions={reactions} ref={ message.sId === prevFirstMessageId ? prevFirstMessageRef : undefined } diff --git a/front/components/assistant/conversation/MessageItem.tsx b/front/components/assistant/conversation/MessageItem.tsx index 40043a5bc7f6..181255a09fce 100644 --- a/front/components/assistant/conversation/MessageItem.tsx +++ b/front/components/assistant/conversation/MessageItem.tsx @@ -1,7 +1,10 @@ -import type { CitationType } from "@dust-tt/sparkle"; +import type { + CitationType, + ConversationMessageFeedbackSelectorProps, +} from "@dust-tt/sparkle"; import { Citation, ZoomableImageCitationWrapper } from "@dust-tt/sparkle"; +import { useSendNotification } from "@dust-tt/sparkle"; import type { - ConversationMessageReactions, MessageWithContentFragmentsType, UserType, WorkspaceType, @@ -12,16 +15,16 @@ import { useSWRConfig } from "swr"; import { AgentMessage } from "@app/components/assistant/conversation/AgentMessage"; import { UserMessage } from "@app/components/assistant/conversation/UserMessage"; +import type { AgentMessageFeedbackType } from "@app/lib/api/assistant/feedback"; import { useSubmitFunction } from "@app/lib/client/utils"; interface MessageItemProps { conversationId: string; - hideReactions: boolean; + messageFeedback: AgentMessageFeedbackType | undefined; isInModal: boolean; isLastMessage: boolean; message: MessageWithContentFragmentsType; owner: WorkspaceType; - reactions: ConversationMessageReactions; user: UserType; } @@ -29,45 +32,54 @@ const MessageItem = React.forwardRef( function MessageItem( { conversationId, - hideReactions, + messageFeedback, isInModal, isLastMessage, message, owner, - reactions, user, }: MessageItemProps, ref ) { const { sId, type } = message; + const sendNotification = useSendNotification(); - const convoReactions = reactions.find((r) => r.messageId === sId); - const messageReactions = convoReactions?.reactions || []; const { mutate } = useSWRConfig(); - const { submit: onSubmitEmoji, isSubmitting: isSubmittingEmoji } = + const { submit: onSubmitThumb, isSubmitting: isSubmittingThumb } = useSubmitFunction( async ({ - emoji, + thumb, isToRemove, + feedbackContent, }: { - emoji: string; + thumb: string; isToRemove: boolean; + feedbackContent?: string | null; }) => { const res = await fetch( - `/api/w/${owner.sId}/assistant/conversations/${conversationId}/messages/${message.sId}/reactions`, + `/api/w/${owner.sId}/assistant/conversations/${conversationId}/messages/${message.sId}/feedbacks`, { method: isToRemove ? "DELETE" : "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ - reaction: emoji, + thumbDirection: thumb, + feedbackContent, }), } ); if (res.ok) { + if (feedbackContent && !isToRemove) { + sendNotification({ + title: "Feedback submitted", + description: + "Your comment has been submitted successfully to the Builder of this assistant. Thank you!", + type: "success", + }); + } await mutate( - `/api/w/${owner.sId}/assistant/conversations/${conversationId}/reactions` + `/api/w/${owner.sId}/assistant/conversations/${conversationId}/feedbacks` ); } } @@ -77,17 +89,17 @@ const MessageItem = React.forwardRef( return null; } - const messageEmoji = hideReactions - ? undefined - : { - reactions: messageReactions.map((reaction) => ({ - emoji: reaction.emoji, - hasReacted: reaction.users.some((u) => u.userId === user.id), - count: reaction.users.length, - })), - onSubmitEmoji, - isSubmittingEmoji, - }; + const messageFeedbackWithSubmit: ConversationMessageFeedbackSelectorProps = + { + feedback: messageFeedback + ? { + thumb: messageFeedback.thumbDirection, + feedbackContent: messageFeedback.content, + } + : null, + onSubmitThumb, + isSubmittingThumb, + }; switch (type) { case "user_message": @@ -152,7 +164,7 @@ const MessageItem = React.forwardRef( isInModal={isInModal} isLastMessage={isLastMessage} message={message} - messageEmoji={messageEmoji} + messageFeedback={messageFeedbackWithSubmit} owner={owner} user={user} size={isInModal ? "compact" : "normal"} diff --git a/front/components/assistant/conversation/UserMessage.tsx b/front/components/assistant/conversation/UserMessage.tsx index 9498f2729c35..c435304e7168 100644 --- a/front/components/assistant/conversation/UserMessage.tsx +++ b/front/components/assistant/conversation/UserMessage.tsx @@ -1,7 +1,4 @@ -import type { - ConversationMessageEmojiSelectorProps, - ConversationMessageSizeType, -} from "@dust-tt/sparkle"; +import type { ConversationMessageSizeType } from "@dust-tt/sparkle"; import { ConversationMessage, Markdown } from "@dust-tt/sparkle"; import type { UserMessageType, WorkspaceType } from "@dust-tt/types"; import { useMemo } from "react"; @@ -23,7 +20,6 @@ interface UserMessageProps { conversationId: string; isLastMessage: boolean; message: UserMessageType; - messageEmoji?: ConversationMessageEmojiSelectorProps; owner: WorkspaceType; size: ConversationMessageSizeType; } @@ -33,7 +29,6 @@ export function UserMessage({ conversationId, isLastMessage, message, - messageEmoji, owner, size, }: UserMessageProps) { @@ -54,7 +49,6 @@ export function UserMessage({
{name}
} type="user" citations={citations} diff --git a/front/components/assistant_builder/AssistantBuilderPreviewDrawer.tsx b/front/components/assistant_builder/AssistantBuilderPreviewDrawer.tsx index a5fa8c623ceb..9bf4519e16de 100644 --- a/front/components/assistant_builder/AssistantBuilderPreviewDrawer.tsx +++ b/front/components/assistant_builder/AssistantBuilderPreviewDrawer.tsx @@ -152,7 +152,6 @@ export default function AssistantBuilderRightPanel({ conversationId={conversation.sId} onStickyMentionsChange={setStickyMentions} isInModal - hideReactions isFading={isFading} key={conversation.sId} /> diff --git a/front/lib/api/assistant/feedback.ts b/front/lib/api/assistant/feedback.ts new file mode 100644 index 000000000000..3fe587245e19 --- /dev/null +++ b/front/lib/api/assistant/feedback.ts @@ -0,0 +1,244 @@ +import type { + ConversationType, + ConversationWithoutContentType, + Result, +} from "@dust-tt/types"; +import type { UserType } from "@dust-tt/types"; +import { ConversationError, Err, GLOBAL_AGENTS_SID, Ok } from "@dust-tt/types"; +import { Op } from "sequelize"; + +import { canAccessConversation } from "@app/lib/api/assistant/conversation"; +import type { AgentMessageFeedbackDirection } from "@app/lib/api/assistant/conversation/feedbacks"; +import type { Authenticator } from "@app/lib/auth"; +import { AgentConfiguration } from "@app/lib/models/assistant/agent"; +import { + AgentMessage, + AgentMessageFeedback, +} from "@app/lib/models/assistant/conversation"; +import { Message } from "@app/lib/models/assistant/conversation"; +import { AgentMessageFeedbackResource } from "@app/lib/resources/agent_message_feedback_resource"; + +/** + * We retrieve the feedbacks for a whole conversation, not just a single message. + */ + +export type AgentMessageFeedbackType = { + id: number; + messageId: string; + agentMessageId: number; + userId: number; + thumbDirection: AgentMessageFeedbackDirection; + content: string | null; +}; + +export async function getConversationFeedbacksForUser( + auth: Authenticator, + conversation: ConversationType | ConversationWithoutContentType +): Promise> { + const owner = auth.workspace(); + if (!owner) { + throw new Error("Unexpected `auth` without `workspace`."); + } + const user = auth.user(); + if (!canAccessConversation(auth, conversation) || !user) { + return new Err(new ConversationError("conversation_access_restricted")); + } + + const messages = await Message.findAll({ + where: { + conversationId: conversation.id, + agentMessageId: { + [Op.ne]: null, + }, + }, + attributes: ["sId", "agentMessageId"], + }); + + const agentMessages = await AgentMessage.findAll({ + where: { + id: { + [Op.in]: messages + .map((m) => m.agentMessageId) + .filter((id): id is number => id !== null), + }, + }, + }); + + const feedbacks = await AgentMessageFeedback.findAll({ + where: { + userId: user.id, + agentMessageId: { + [Op.in]: agentMessages.map((m) => m.id), + }, + }, + }); + const feedbacksByMessageId = feedbacks.map( + (feedback) => + ({ + id: feedback.id, + messageId: messages.find( + (m) => m.agentMessageId === feedback.agentMessageId + )!.sId, + agentMessageId: feedback.agentMessageId, + userId: feedback.userId, + thumbDirection: feedback.thumbDirection, + content: feedback.content, + }) as AgentMessageFeedbackType + ); + + return new Ok(feedbacksByMessageId); +} + +/** + * We create a feedback for a single message. + * As user can be null (user from Slack), we also store the user context, as we do for messages. + */ +export async function createOrUpdateMessageFeedback( + auth: Authenticator, + { + messageId, + conversation, + user, + thumbDirection, + content, + }: { + messageId: string; + conversation: ConversationType | ConversationWithoutContentType; + user: UserType; + thumbDirection: AgentMessageFeedbackDirection; + content?: string; + } +): Promise { + const owner = auth.workspace(); + if (!owner) { + throw new Error("Unexpected `auth` without `workspace`."); + } + + const message = await Message.findOne({ + where: { + sId: messageId, + conversationId: conversation.id, + }, + }); + + if (!message || !message.agentMessageId) { + return null; + } + + const agentMessage = await AgentMessage.findOne({ + where: { + id: message.agentMessageId, + }, + }); + + if (!agentMessage) { + return null; + } + + let isGlobalAgent = false; + let agentConfigurationId = agentMessage.agentConfigurationId; + if ( + Object.values(GLOBAL_AGENTS_SID).includes( + agentMessage.agentConfigurationId as GLOBAL_AGENTS_SID + ) + ) { + isGlobalAgent = true; + } + + if (!isGlobalAgent) { + const agentConfiguration = await AgentConfiguration.findOne({ + where: { + sId: agentMessage.agentConfigurationId, + }, + }); + + if (!agentConfiguration) { + return null; + } + agentConfigurationId = agentConfiguration.sId; + } + + const feedback = + await AgentMessageFeedbackResource.fetchByUserAndAgentMessage({ + user, + agentMessage, + }); + + if (feedback) { + const updatedFeedback = await feedback.updateContentAndThumbDirection( + content ?? "", + thumbDirection + ); + + return updatedFeedback.isOk(); + } else { + const newFeedback = await AgentMessageFeedbackResource.makeNew({ + workspaceId: owner.id, + agentConfigurationId: agentConfigurationId, + agentConfigurationVersion: agentMessage.agentConfigurationVersion, + agentMessageId: agentMessage.id, + userId: user.id, + thumbDirection, + content, + }); + return newFeedback !== null; + } +} + +/** + * The id of a reaction is not exposed on the API so we need to find it from the message id and the user context. + * We destroy reactions, no point in soft-deleting them. + */ +export async function deleteMessageFeedback( + auth: Authenticator, + { + messageId, + conversation, + user, + }: { + messageId: string; + conversation: ConversationType | ConversationWithoutContentType; + user: UserType; + } +): Promise { + const owner = auth.workspace(); + if (!owner) { + throw new Error("Unexpected `auth` without `workspace`."); + } + + const message = await Message.findOne({ + where: { + sId: messageId, + conversationId: conversation.id, + }, + attributes: ["agentMessageId"], + }); + + if (!message || !message.agentMessageId) { + return null; + } + + const agentMessage = await AgentMessage.findOne({ + where: { + id: message.agentMessageId, + }, + }); + + if (!agentMessage) { + return null; + } + + const feedback = + await AgentMessageFeedbackResource.fetchByUserAndAgentMessage({ + user, + agentMessage, + }); + + if (!feedback) { + return null; + } + + const deletedFeedback = await feedback.delete(auth); + + return deletedFeedback.isOk(); +} diff --git a/front/lib/models/assistant/conversation.ts b/front/lib/models/assistant/conversation.ts index e247b2261275..cbaf73bf9c76 100644 --- a/front/lib/models/assistant/conversation.ts +++ b/front/lib/models/assistant/conversation.ts @@ -15,7 +15,6 @@ import type { import { DataTypes, Model } from "sequelize"; import type { AgentMessageFeedbackDirection } from "@app/lib/api/assistant/conversation/feedbacks"; -import { AgentConfiguration } from "@app/lib/models/assistant/agent"; import type { AgentMessageContent } from "@app/lib/models/assistant/agent_message_content"; import { User } from "@app/lib/models/user"; import { Workspace } from "@app/lib/models/workspace"; @@ -342,7 +341,8 @@ export class AgentMessageFeedback extends Model< declare updatedAt: CreationOptional; declare workspaceId: ForeignKey; - declare agentConfigurationId: ForeignKey; + declare agentConfigurationId: string; + declare agentConfigurationVersion: number; declare agentMessageId: ForeignKey; declare userId: ForeignKey; @@ -371,6 +371,14 @@ AgentMessageFeedback.init( type: DataTypes.INTEGER, allowNull: false, }, + agentConfigurationId: { + type: DataTypes.STRING, + allowNull: true, + }, + agentConfigurationVersion: { + type: DataTypes.INTEGER, + allowNull: true, + }, thumbDirection: { type: DataTypes.STRING, allowNull: true, @@ -401,9 +409,6 @@ AgentMessageFeedback.init( } ); -AgentConfiguration.hasMany(AgentMessageFeedback, { - onDelete: "RESTRICT", -}); AgentMessage.hasMany(AgentMessageFeedback, { onDelete: "RESTRICT", }); diff --git a/front/lib/resources/agent_message_feedback_resource.ts b/front/lib/resources/agent_message_feedback_resource.ts index ce1baeac3e74..e915d67795ca 100644 --- a/front/lib/resources/agent_message_feedback_resource.ts +++ b/front/lib/resources/agent_message_feedback_resource.ts @@ -1,17 +1,14 @@ -import type { - AgentConfigurationType, - AgentMessageType, - Result, -} from "@dust-tt/types"; +import type { AgentConfigurationType, Result, UserType } from "@dust-tt/types"; import { Err, Ok } from "@dust-tt/types"; import type { CreationAttributes, Transaction } from "sequelize"; import type { Attributes, ModelStatic } from "sequelize"; +import type { AgentMessageFeedbackDirection } from "@app/lib/api/assistant/conversation/feedbacks"; import type { Authenticator } from "@app/lib/auth"; +import type { AgentMessage } from "@app/lib/models/assistant/conversation"; import { AgentMessageFeedback } from "@app/lib/models/assistant/conversation"; import { BaseResource } from "@app/lib/resources/base_resource"; import type { ReadonlyAttributesType } from "@app/lib/resources/storage/types"; -import type { UserResource } from "@app/lib/resources/user_resource"; // Attributes are marked as read-only to reflect the stateless nature of our Resource. // This design will be moved up to BaseResource once we transition away from Sequelize. @@ -50,7 +47,7 @@ export class AgentMessageFeedbackResource extends BaseResource { const agentMessageFeedback = await AgentMessageFeedback.findAll({ where: { - agentConfigurationId: agentConfiguration.id, + agentConfigurationId: agentConfiguration.sId, }, order: [["id", "DESC"]], }); @@ -61,12 +58,12 @@ export class AgentMessageFeedbackResource extends BaseResource { const agentMessageFeedback = await AgentMessageFeedback.findOne({ where: { @@ -85,11 +82,15 @@ export class AgentMessageFeedbackResource extends BaseResource> { + async updateContentAndThumbDirection( + content: string, + thumbDirection: AgentMessageFeedbackDirection + ): Promise> { try { await this.model.update( { content, + thumbDirection, }, { where: { diff --git a/front/lib/swr/conversations.ts b/front/lib/swr/conversations.ts index 317db5e7749e..824efc0b759b 100644 --- a/front/lib/swr/conversations.ts +++ b/front/lib/swr/conversations.ts @@ -9,6 +9,7 @@ import { useCallback, useMemo } from "react"; import type { Fetcher } from "swr"; import { deleteConversation } from "@app/components/assistant/conversation/lib"; +import type { AgentMessageFeedbackType } from "@app/lib/api/assistant/feedback"; import type { FetchConversationMessagesResponse } from "@app/lib/api/assistant/messages"; import { getVisualizationRetryMessage } from "@app/lib/client/visualization"; import { @@ -92,6 +93,30 @@ export function useConversationReactions({ }; } +export function useConversationFeedbacks({ + conversationId, + workspaceId, +}: { + conversationId: string; + workspaceId: string; +}) { + const conversationFeedbacksFetcher: Fetcher<{ + feedbacks: AgentMessageFeedbackType[]; + }> = fetcher; + + const { data, error, mutate } = useSWRWithDefaults( + `/api/w/${workspaceId}/assistant/conversations/${conversationId}/feedbacks`, + conversationFeedbacksFetcher + ); + + return { + feedbacks: useMemo(() => (data ? data.feedbacks : []), [data]), + isFeedbacksLoading: !error && !data, + isFeedbacksError: error, + mutateReactions: mutate, + }; +} + export function useConversationMessages({ conversationId, workspaceId, diff --git a/front/migrations/db/migration_122.sql b/front/migrations/db/migration_122.sql new file mode 100644 index 000000000000..709a8d140637 --- /dev/null +++ b/front/migrations/db/migration_122.sql @@ -0,0 +1,4 @@ +-- First drop the column +ALTER TABLE "agent_message_feedbacks" DROP COLUMN "agentConfigurationId"; +ALTER TABLE "agent_message_feedbacks" ADD COLUMN "agentConfigurationId" VARCHAR(255); +ALTER TABLE "agent_message_feedbacks" ADD COLUMN "agentConfigurationVersion" INTEGER; diff --git a/front/pages/api/w/[wId]/assistant/conversations/[cId]/feedbacks.ts b/front/pages/api/w/[wId]/assistant/conversations/[cId]/feedbacks.ts new file mode 100644 index 000000000000..f0ecbabc35db --- /dev/null +++ b/front/pages/api/w/[wId]/assistant/conversations/[cId]/feedbacks.ts @@ -0,0 +1,68 @@ +import type { WithAPIErrorResponse } from "@dust-tt/types"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { getConversationWithoutContent } from "@app/lib/api/assistant/conversation"; +import { apiErrorForConversation } from "@app/lib/api/assistant/conversation/helper"; +import type { AgentMessageFeedbackType } from "@app/lib/api/assistant/feedback"; +import { getConversationFeedbacksForUser } from "@app/lib/api/assistant/feedback"; +import { withSessionAuthenticationForWorkspace } from "@app/lib/api/auth_wrappers"; +import type { Authenticator } from "@app/lib/auth"; +import { apiError } from "@app/logger/withlogging"; + +async function handler( + req: NextApiRequest, + res: NextApiResponse< + WithAPIErrorResponse<{ feedbacks: AgentMessageFeedbackType[] }> + >, + auth: Authenticator +): Promise { + if (!(typeof req.query.cId === "string")) { + return apiError(req, res, { + status_code: 400, + api_error: { + type: "invalid_request_error", + message: "Invalid query parameters, `cId` (string) is required.", + }, + }); + } + + const conversationId = req.query.cId; + const conversationRes = await getConversationWithoutContent( + auth, + conversationId + ); + + if (conversationRes.isErr()) { + return apiErrorForConversation(req, res, conversationRes.error); + } + + const conversation = conversationRes.value; + + switch (req.method) { + case "GET": + const feedbacksRes = await getConversationFeedbacksForUser( + auth, + conversation + ); + + if (feedbacksRes.isErr()) { + return apiErrorForConversation(req, res, feedbacksRes.error); + } + + const feedbacks = feedbacksRes.value; + + res.status(200).json({ feedbacks }); + return; + + default: + return apiError(req, res, { + status_code: 405, + api_error: { + type: "method_not_supported_error", + message: "The method passed is not supported, GET is expected.", + }, + }); + } +} + +export default withSessionAuthenticationForWorkspace(handler); diff --git a/front/pages/api/w/[wId]/assistant/conversations/[cId]/messages/[mId]/feedbacks/index.ts b/front/pages/api/w/[wId]/assistant/conversations/[cId]/messages/[mId]/feedbacks/index.ts new file mode 100644 index 000000000000..20dc7777342d --- /dev/null +++ b/front/pages/api/w/[wId]/assistant/conversations/[cId]/messages/[mId]/feedbacks/index.ts @@ -0,0 +1,134 @@ +import type { WithAPIErrorResponse } from "@dust-tt/types"; +import { isLeft } from "fp-ts/lib/Either"; +import * as t from "io-ts"; +import * as reporter from "io-ts-reporters"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { getConversationWithoutContent } from "@app/lib/api/assistant/conversation"; +import type { AgentMessageFeedbackDirection } from "@app/lib/api/assistant/conversation/feedbacks"; +import { apiErrorForConversation } from "@app/lib/api/assistant/conversation/helper"; +import { + createOrUpdateMessageFeedback, + deleteMessageFeedback, +} from "@app/lib/api/assistant/feedback"; +import { withSessionAuthenticationForWorkspace } from "@app/lib/api/auth_wrappers"; +import type { Authenticator } from "@app/lib/auth"; +import { apiError } from "@app/logger/withlogging"; + +export const MessageFeedbackRequestBodySchema = t.type({ + thumbDirection: t.string, + feedbackContent: t.union([t.string, t.undefined, t.null]), +}); + +async function handler( + req: NextApiRequest, + res: NextApiResponse< + WithAPIErrorResponse<{ + success: boolean; + }> + >, + auth: Authenticator +): Promise { + const user = auth.getNonNullableUser(); + + if (!(typeof req.query.cId === "string")) { + return apiError(req, res, { + status_code: 400, + api_error: { + type: "invalid_request_error", + message: "Invalid query parameters, `cId` (string) is required.", + }, + }); + } + + const conversationId = req.query.cId; + const conversationRes = await getConversationWithoutContent( + auth, + conversationId + ); + + if (conversationRes.isErr()) { + return apiErrorForConversation(req, res, conversationRes.error); + } + + const conversation = conversationRes.value; + + if (!(typeof req.query.mId === "string")) { + return apiError(req, res, { + status_code: 400, + api_error: { + type: "invalid_request_error", + message: "Invalid query parameters, `mId` (string) is required.", + }, + }); + } + + const messageId = req.query.mId; + const bodyValidation = MessageFeedbackRequestBodySchema.decode(req.body); + if (isLeft(bodyValidation)) { + const pathError = reporter.formatValidationErrors(bodyValidation.left); + return apiError(req, res, { + status_code: 400, + api_error: { + type: "invalid_request_error", + message: `Invalid request body: ${pathError}`, + }, + }); + } + + switch (req.method) { + case "POST": + const created = await createOrUpdateMessageFeedback(auth, { + messageId, + conversation, + user, + thumbDirection: bodyValidation.right + .thumbDirection as AgentMessageFeedbackDirection, + content: bodyValidation.right.feedbackContent || "", + }); + + if (created) { + res.status(200).json({ success: true }); + return; + } + return apiError(req, res, { + status_code: 400, + api_error: { + type: "invalid_request_error", + message: + "The message you're trying to give feedback to does not exist.", + }, + }); + + case "DELETE": + const deleted = await deleteMessageFeedback(auth, { + messageId, + conversation, + user, + }); + + if (deleted) { + res.status(200).json({ success: true }); + } + return apiError(req, res, { + status_code: 400, + api_error: { + type: "invalid_request_error", + message: + "The message you're trying to give feedback to does not exist.", + }, + }); + + default: + return apiError(req, res, { + status_code: 405, + api_error: { + type: "method_not_supported_error", + message: + "The method passed is not supported, POST or DELETE is expected.", + }, + }); + } +} + +export default withSessionAuthenticationForWorkspace(handler); From 3c617143adc60abf5b879210cbdc87058d8942a1 Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Tue, 26 Nov 2024 15:26:34 +0100 Subject: [PATCH 02/14] Update sparkle --- front/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/package.json b/front/package.json index 1908349907f0..01932cc1c6ea 100644 --- a/front/package.json +++ b/front/package.json @@ -20,7 +20,7 @@ "dependencies": { "@auth0/nextjs-auth0": "^3.5.0", "@dust-tt/client": "file:../sdks/js", - "@dust-tt/sparkle": "^0.2.324", + "@dust-tt/sparkle": "^0.2.325", "@dust-tt/types": "file:../types", "@headlessui/react": "^1.7.7", "@heroicons/react": "^2.0.11", From e50adf76cff001ee5fc7a7482d799cf82d3a025e Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Tue, 26 Nov 2024 15:41:34 +0100 Subject: [PATCH 03/14] Update package-lock.json --- front/package-lock.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/front/package-lock.json b/front/package-lock.json index e2b03265d0ec..c876e93bff8e 100644 --- a/front/package-lock.json +++ b/front/package-lock.json @@ -7,7 +7,7 @@ "dependencies": { "@auth0/nextjs-auth0": "^3.5.0", "@dust-tt/client": "file:../sdks/js", - "@dust-tt/sparkle": "^0.2.324", + "@dust-tt/sparkle": "^0.2.325", "@dust-tt/types": "file:../types", "@headlessui/react": "^1.7.7", "@heroicons/react": "^2.0.11", @@ -11487,9 +11487,10 @@ "link": true }, "node_modules/@dust-tt/sparkle": { - "version": "0.2.324", - "resolved": "https://registry.npmjs.org/@dust-tt/sparkle/-/sparkle-0.2.324.tgz", - "integrity": "sha512-lzUbYBgGDfcwcWUKLFKdKCoRvNP1xRpA70pzct4pOK7LSWKTbO8X6YbmPeTVXqdOe/pcXyu7dxqCCZ/GuK6yqw==", + "version": "0.2.325", + "resolved": "https://registry.npmjs.org/@dust-tt/sparkle/-/sparkle-0.2.325.tgz", + "integrity": "sha512-XVHdUxw74w7Mkv+P+ptlISD+huMTAqT3IpZ+xe1lK3ZgvqLKgpxH71xzdf75cCspgKh+Wswt5WTIAKgVj3Oirg==", + "license": "ISC", "dependencies": { "@emoji-mart/data": "^1.1.2", "@emoji-mart/react": "^1.1.1", From 1c1249c647439f528c8a4188b51410ec8b8a8f34 Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Tue, 26 Nov 2024 16:54:41 +0100 Subject: [PATCH 04/14] Use resource --- front/lib/api/assistant/feedback.ts | 14 +++++------- .../agent_message_feedback_resource.ts | 22 ++++++++++++++++++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/front/lib/api/assistant/feedback.ts b/front/lib/api/assistant/feedback.ts index 3fe587245e19..0ab0378ca265 100644 --- a/front/lib/api/assistant/feedback.ts +++ b/front/lib/api/assistant/feedback.ts @@ -64,14 +64,12 @@ export async function getConversationFeedbacksForUser( }, }); - const feedbacks = await AgentMessageFeedback.findAll({ - where: { - userId: user.id, - agentMessageId: { - [Op.in]: agentMessages.map((m) => m.id), - }, - }, - }); + const feedbacks = + await AgentMessageFeedbackResource.fetchByUserAndAgentMessages( + user, + agentMessages + ); + const feedbacksByMessageId = feedbacks.map( (feedback) => ({ diff --git a/front/lib/resources/agent_message_feedback_resource.ts b/front/lib/resources/agent_message_feedback_resource.ts index e915d67795ca..540d3b6efe3f 100644 --- a/front/lib/resources/agent_message_feedback_resource.ts +++ b/front/lib/resources/agent_message_feedback_resource.ts @@ -1,7 +1,8 @@ import type { AgentConfigurationType, Result, UserType } from "@dust-tt/types"; import { Err, Ok } from "@dust-tt/types"; -import type { CreationAttributes, Transaction } from "sequelize"; import type { Attributes, ModelStatic } from "sequelize"; +import type { CreationAttributes, Transaction } from "sequelize"; +import { Op } from "sequelize"; import type { AgentMessageFeedbackDirection } from "@app/lib/api/assistant/conversation/feedbacks"; import type { Authenticator } from "@app/lib/auth"; @@ -82,6 +83,25 @@ export class AgentMessageFeedbackResource extends BaseResource { + const agentMessageFeedback = await AgentMessageFeedback.findAll({ + where: { + userId: user.id, + agentMessageId: { + [Op.in]: agentMessages.map((m) => m.id), + }, + }, + }); + + return agentMessageFeedback.map( + (feedback) => + new AgentMessageFeedbackResource(AgentMessageFeedback, feedback.get()) + ); + } + async updateContentAndThumbDirection( content: string, thumbDirection: AgentMessageFeedbackDirection From fe7c0f5c60bc4e8ea2ebd026c7d94013f856b0cd Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Tue, 26 Nov 2024 16:56:03 +0100 Subject: [PATCH 05/14] Move bodyvalidation --- .../[cId]/messages/[mId]/feedbacks/index.ts | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/front/pages/api/w/[wId]/assistant/conversations/[cId]/messages/[mId]/feedbacks/index.ts b/front/pages/api/w/[wId]/assistant/conversations/[cId]/messages/[mId]/feedbacks/index.ts index 20dc7777342d..8c73c67ad54d 100644 --- a/front/pages/api/w/[wId]/assistant/conversations/[cId]/messages/[mId]/feedbacks/index.ts +++ b/front/pages/api/w/[wId]/assistant/conversations/[cId]/messages/[mId]/feedbacks/index.ts @@ -64,20 +64,21 @@ async function handler( } const messageId = req.query.mId; - const bodyValidation = MessageFeedbackRequestBodySchema.decode(req.body); - if (isLeft(bodyValidation)) { - const pathError = reporter.formatValidationErrors(bodyValidation.left); - return apiError(req, res, { - status_code: 400, - api_error: { - type: "invalid_request_error", - message: `Invalid request body: ${pathError}`, - }, - }); - } switch (req.method) { case "POST": + const bodyValidation = MessageFeedbackRequestBodySchema.decode(req.body); + if (isLeft(bodyValidation)) { + const pathError = reporter.formatValidationErrors(bodyValidation.left); + return apiError(req, res, { + status_code: 400, + api_error: { + type: "invalid_request_error", + message: `Invalid request body: ${pathError}`, + }, + }); + } + const created = await createOrUpdateMessageFeedback(auth, { messageId, conversation, From 1e02bb2e8d3b8adc103401d63c80c147bfb74ec4 Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Tue, 26 Nov 2024 16:57:53 +0100 Subject: [PATCH 06/14] Undo change --- front/components/assistant/conversation/ConversationLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/components/assistant/conversation/ConversationLayout.tsx b/front/components/assistant/conversation/ConversationLayout.tsx index 4a2e4b61dece..598a76795790 100644 --- a/front/components/assistant/conversation/ConversationLayout.tsx +++ b/front/components/assistant/conversation/ConversationLayout.tsx @@ -91,7 +91,7 @@ export default function ConversationLayout({ ]); const { conversation, conversationError } = useConversation({ - conversationId: activeConversationId ?? "", + conversationId: activeConversationId, workspaceId: owner.sId, }); From a8bae9d908c91ee8da989e6b10b97e41a029be52 Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Wed, 27 Nov 2024 09:33:08 +0100 Subject: [PATCH 07/14] Add cascade on workspace and message deletion --- front/lib/models/assistant/conversation.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/front/lib/models/assistant/conversation.ts b/front/lib/models/assistant/conversation.ts index cbaf73bf9c76..3bf74fff4ed2 100644 --- a/front/lib/models/assistant/conversation.ts +++ b/front/lib/models/assistant/conversation.ts @@ -367,10 +367,6 @@ AgentMessageFeedback.init( allowNull: false, defaultValue: DataTypes.NOW, }, - workspaceId: { - type: DataTypes.INTEGER, - allowNull: false, - }, agentConfigurationId: { type: DataTypes.STRING, allowNull: true, @@ -409,11 +405,15 @@ AgentMessageFeedback.init( } ); +Workspace.hasMany(AgentMessageFeedback, { + foreignKey: { name: "workspaceId", allowNull: false }, + onDelete: "CASCADE", +}); AgentMessage.hasMany(AgentMessageFeedback, { - onDelete: "RESTRICT", + onDelete: "CASCADE", }); User.hasMany(AgentMessageFeedback, { - onDelete: "RESTRICT", + onDelete: "SET NULL", }); export class Message extends Model< From e5290f144fd4966b9b9a3f22a06f7033cc45b761 Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Wed, 27 Nov 2024 10:08:21 +0100 Subject: [PATCH 08/14] Truncate index name --- front/lib/models/assistant/conversation.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/front/lib/models/assistant/conversation.ts b/front/lib/models/assistant/conversation.ts index 3bf74fff4ed2..a11f6b22730c 100644 --- a/front/lib/models/assistant/conversation.ts +++ b/front/lib/models/assistant/conversation.ts @@ -400,6 +400,7 @@ AgentMessageFeedback.init( { fields: ["agentConfigurationId", "agentMessageId", "userId"], unique: true, + name: "agent_message_feedbacks_agent_configuration_id_agent_message_id", }, ], } From 3b484aa3d2402212a4fd7234853d25ee850aa00e Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Wed, 27 Nov 2024 10:25:44 +0100 Subject: [PATCH 09/14] Add workspaceId FK --- front/migrations/db/migration_122.sql | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/front/migrations/db/migration_122.sql b/front/migrations/db/migration_122.sql index 709a8d140637..2198e8752465 100644 --- a/front/migrations/db/migration_122.sql +++ b/front/migrations/db/migration_122.sql @@ -1,4 +1,7 @@ --- First drop the column +-- First drop the column, ALTER TABLE "agent_message_feedbacks" DROP COLUMN "agentConfigurationId"; ALTER TABLE "agent_message_feedbacks" ADD COLUMN "agentConfigurationId" VARCHAR(255); ALTER TABLE "agent_message_feedbacks" ADD COLUMN "agentConfigurationVersion" INTEGER; + +ALTER TABLE "agent_message_feedbacks" ALTER COLUMN "workspaceId" SET NOT NULL; +ALTER TABLE "agent_message_feedbacks" ADD FOREIGN KEY ("workspaceId") REFERENCES "workspaces" ("id") ON DELETE RESTRICT ON UPDATE CASCADE; \ No newline at end of file From c28b97ec350ad74a6a1deef46ca789be6f1f99ac Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Wed, 27 Nov 2024 10:29:07 +0100 Subject: [PATCH 10/14] Add destroy feedbacks in workspace scrub --- front/lib/api/assistant/conversation/destroy.ts | 4 ++++ front/lib/models/assistant/conversation.ts | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/front/lib/api/assistant/conversation/destroy.ts b/front/lib/api/assistant/conversation/destroy.ts index fe04cd73329f..10b4bc618605 100644 --- a/front/lib/api/assistant/conversation/destroy.ts +++ b/front/lib/api/assistant/conversation/destroy.ts @@ -11,6 +11,7 @@ import { AgentWebsearchAction } from "@app/lib/models/assistant/actions/websearc import type { Conversation } from "@app/lib/models/assistant/conversation"; import { AgentMessage, + AgentMessageFeedback, ConversationParticipant, Mention, Message, @@ -154,6 +155,9 @@ export async function destroyConversation( await UserMessage.destroy({ where: { id: userMessageIds }, }); + await AgentMessageFeedback.destroy({ + where: { agentMessageId: agentMessageIds }, + }); await AgentMessage.destroy({ where: { id: agentMessageIds }, }); diff --git a/front/lib/models/assistant/conversation.ts b/front/lib/models/assistant/conversation.ts index a11f6b22730c..e93a305eff30 100644 --- a/front/lib/models/assistant/conversation.ts +++ b/front/lib/models/assistant/conversation.ts @@ -408,10 +408,10 @@ AgentMessageFeedback.init( Workspace.hasMany(AgentMessageFeedback, { foreignKey: { name: "workspaceId", allowNull: false }, - onDelete: "CASCADE", + onDelete: "RESTRICT", }); AgentMessage.hasMany(AgentMessageFeedback, { - onDelete: "CASCADE", + onDelete: "RESTRICT", }); User.hasMany(AgentMessageFeedback, { onDelete: "SET NULL", From f20896b33af89f3bbe86174ba3c1f01ac789d1e4 Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Wed, 27 Nov 2024 10:38:51 +0100 Subject: [PATCH 11/14] lint --- front/lib/api/assistant/feedback.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/front/lib/api/assistant/feedback.ts b/front/lib/api/assistant/feedback.ts index 0ab0378ca265..ebfb89af97e4 100644 --- a/front/lib/api/assistant/feedback.ts +++ b/front/lib/api/assistant/feedback.ts @@ -11,10 +11,7 @@ import { canAccessConversation } from "@app/lib/api/assistant/conversation"; import type { AgentMessageFeedbackDirection } from "@app/lib/api/assistant/conversation/feedbacks"; import type { Authenticator } from "@app/lib/auth"; import { AgentConfiguration } from "@app/lib/models/assistant/agent"; -import { - AgentMessage, - AgentMessageFeedback, -} from "@app/lib/models/assistant/conversation"; +import { AgentMessage } from "@app/lib/models/assistant/conversation"; import { Message } from "@app/lib/models/assistant/conversation"; import { AgentMessageFeedbackResource } from "@app/lib/resources/agent_message_feedback_resource"; From eab4ed64c06d11fe3a8145a72a2e9ef53064245a Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Wed, 27 Nov 2024 12:11:35 +0100 Subject: [PATCH 12/14] Destroy agentmessagefeedback --- front/poke/temporal/activities.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/front/poke/temporal/activities.ts b/front/poke/temporal/activities.ts index 2c1a451f0546..cdff5fb6051a 100644 --- a/front/poke/temporal/activities.ts +++ b/front/poke/temporal/activities.ts @@ -34,6 +34,7 @@ import { } from "@app/lib/models/assistant/agent"; import { AgentMessage, + AgentMessageFeedback, Conversation, ConversationParticipant, Mention, @@ -232,6 +233,11 @@ export async function deleteConversationsActivity({ }); } + await AgentMessageFeedback.destroy({ + where: { agentMessageId: msg.id }, + transaction: t, + }); + // Delete associated actions. await AgentBrowseAction.destroy({ From f0685e5f033bebca275f681878eb8e2040d8ec06 Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Wed, 27 Nov 2024 12:22:06 +0100 Subject: [PATCH 13/14] Add SET NULL on users FK --- front/migrations/db/migration_122.sql | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/front/migrations/db/migration_122.sql b/front/migrations/db/migration_122.sql index 2198e8752465..6d9884b4a080 100644 --- a/front/migrations/db/migration_122.sql +++ b/front/migrations/db/migration_122.sql @@ -4,4 +4,12 @@ ALTER TABLE "agent_message_feedbacks" ADD COLUMN "agentConfigurationId" VARCHAR( ALTER TABLE "agent_message_feedbacks" ADD COLUMN "agentConfigurationVersion" INTEGER; ALTER TABLE "agent_message_feedbacks" ALTER COLUMN "workspaceId" SET NOT NULL; -ALTER TABLE "agent_message_feedbacks" ADD FOREIGN KEY ("workspaceId") REFERENCES "workspaces" ("id") ON DELETE RESTRICT ON UPDATE CASCADE; \ No newline at end of file +ALTER TABLE "agent_message_feedbacks" ADD FOREIGN KEY ("workspaceId") REFERENCES "workspaces" ("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +ALTER TABLE "agent_message_feedbacks" +DROP CONSTRAINT "agent_message_feedbacks_userId_fkey", +ADD CONSTRAINT "agent_message_feedbacks_userId_fkey" + FOREIGN KEY ("userId") + REFERENCES "users"("id") + ON DELETE SET NULL + ON UPDATE CASCADE; From bc30d1cdf9917cc3e89de53dd6572f3ea5a4e74b Mon Sep 17 00:00:00 2001 From: Alban Dumouilla Date: Wed, 27 Nov 2024 12:27:46 +0100 Subject: [PATCH 14/14] Fix msg id --- front/poke/temporal/activities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/poke/temporal/activities.ts b/front/poke/temporal/activities.ts index cdff5fb6051a..09322f52727f 100644 --- a/front/poke/temporal/activities.ts +++ b/front/poke/temporal/activities.ts @@ -234,7 +234,7 @@ export async function deleteConversationsActivity({ } await AgentMessageFeedback.destroy({ - where: { agentMessageId: msg.id }, + where: { agentMessageId: agentMessage.id }, transaction: t, });