From 06e20ca01c0593415e7812b59f7c6c8eeb68d84b Mon Sep 17 00:00:00 2001 From: Akshita Goyal <36129505+gakshita@users.noreply.github.com> Date: Tue, 12 Aug 2025 13:13:10 +0530 Subject: [PATCH] [PAI-633] Chore workspace info added in apis (#3862) * chore: sending workspace info for all the pi apis * fix: message scrolling for chat * fix: border color for markdown table * fix: added workspace_id in queue-answer api * fix: workspaceId types * fix: refactor --- .../pi-chat/conversation/ai-message.tsx | 15 ++- .../pi-chat/conversation/messages.tsx | 2 + .../pi-chat/conversation/new-converstaion.tsx | 7 +- apps/web/ee/components/pi-chat/input/root.tsx | 15 ++- apps/web/ee/components/pi-chat/layout.tsx | 7 +- .../ee/components/pi-chat/list/list-item.tsx | 13 ++- .../components/pi-chat/modals/edit-form.tsx | 5 +- .../pi-chat/sidebar/right-side-panel.tsx | 2 +- .../pi-chat/sidebar/sidebar-item.tsx | 14 ++- .../ee/components/pi-chat/system-prompts.tsx | 4 +- apps/web/ee/services/pi-chat.service.ts | 66 ++++++++---- apps/web/ee/store/pi-chat/pi-chat.ts | 100 ++++++++++++------ apps/web/ee/types/pi-chat.d.ts | 7 +- 13 files changed, 176 insertions(+), 81 deletions(-) diff --git a/apps/web/ee/components/pi-chat/conversation/ai-message.tsx b/apps/web/ee/components/pi-chat/conversation/ai-message.tsx index af33403e13..1e0c4909f1 100644 --- a/apps/web/ee/components/pi-chat/conversation/ai-message.tsx +++ b/apps/web/ee/components/pi-chat/conversation/ai-message.tsx @@ -1,10 +1,12 @@ import { useState } from "react"; import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; import Markdown from "react-markdown"; import remarkGfm from "remark-gfm"; import { Copy, ThumbsDown, ThumbsUp } from "lucide-react"; import { Loader, PiIcon, setToast, TOAST_TYPE, Tooltip } from "@plane/ui"; import { cn, copyTextToClipboard } from "@plane/utils"; +import { useWorkspace } from "@/hooks/store/use-workspace"; import { usePiChat } from "@/plane-web/hooks/store/use-pi-chat"; import { EFeedback } from "@/plane-web/types"; import { FeedbackModal } from "../input/feedback-modal"; @@ -21,9 +23,12 @@ type TProps = { isLatest?: boolean; }; export const AiMessage = observer((props: TProps) => { - // store const { message = "", reasoning, isPiThinking = false, id, isLoading = false, feedback, isLatest } = props; + // store + const { workspaceSlug } = useParams(); const { sendFeedback, activeChatId } = usePiChat(); + const { getWorkspaceBySlug } = useWorkspace(); + const workspaceId = getWorkspaceBySlug(workspaceSlug as string)?.id; // state const [isFeedbackModalOpen, setIsFeedbackModalOpen] = useState(false); @@ -38,7 +43,7 @@ export const AiMessage = observer((props: TProps) => { }; const handleFeedback = async (feedback: EFeedback, feedbackMessage?: string) => { try { - await sendFeedback(activeChatId, parseInt(id), feedback, feedbackMessage); + await sendFeedback(activeChatId, parseInt(id), feedback, workspaceId, feedbackMessage); setToast({ type: TOAST_TYPE.SUCCESS, title: "Feedback sent!", @@ -74,12 +79,12 @@ export const AiMessage = observer((props: TProps) => { ), table: ({ children }) => ( -
+
{children}
), - th: ({ children }) => {children}, - td: ({ children }) => {children}, + th: ({ children }) => {children}, + td: ({ children }) => {children}, }} > {message} diff --git a/apps/web/ee/components/pi-chat/conversation/messages.tsx b/apps/web/ee/components/pi-chat/conversation/messages.tsx index 70aa12225d..d24dab880f 100644 --- a/apps/web/ee/components/pi-chat/conversation/messages.tsx +++ b/apps/web/ee/components/pi-chat/conversation/messages.tsx @@ -4,6 +4,7 @@ import { IUser } from "@plane/types"; import { cn } from "@plane/utils"; import { usePiChat } from "@/plane-web/hooks/store/use-pi-chat"; import { TDialogue } from "@/plane-web/types"; +import { scrollIntoViewHelper } from "../helper"; import { AiMessage } from "./ai-message"; import { MyMessage } from "./my-message"; import { NewConversation } from "./new-converstaion"; @@ -58,6 +59,7 @@ export const Messages = observer((props: TProps) => { //Always scroll to the latest message if (!activeChat?.dialogue) return; if (activeChat?.dialogue.length === 0) setHasMoreMessages(false); + scrollIntoViewHelper(`${activeChat?.dialogue?.length - 1}`); // eslint-disable-next-line react-hooks/exhaustive-deps }, [activeChat?.dialogue?.length]); diff --git a/apps/web/ee/components/pi-chat/conversation/new-converstaion.tsx b/apps/web/ee/components/pi-chat/conversation/new-converstaion.tsx index 0c1a021c69..997a43bdd2 100644 --- a/apps/web/ee/components/pi-chat/conversation/new-converstaion.tsx +++ b/apps/web/ee/components/pi-chat/conversation/new-converstaion.tsx @@ -1,9 +1,11 @@ import { useState } from "react"; import { observer } from "mobx-react"; +import { useParams } from "next/navigation"; import useSWR from "swr"; import { IUser } from "@plane/types"; import { Loader } from "@plane/ui"; import { cn } from "@plane/utils"; +import { useWorkspace } from "@/hooks/store/use-workspace"; import { usePiChat } from "@/plane-web/hooks/store/use-pi-chat"; import SystemPrompts from "../system-prompts"; @@ -16,8 +18,11 @@ type TProps = { export const NewConversation = observer((props: TProps) => { const { currentUser, isFullScreen, shouldRedirect = true, isProjectLevel = false } = props; // store hooks + const { workspaceSlug } = useParams(); const { getTemplates } = usePiChat(); - const { data: templates, isLoading } = useSWR("PI_TEMPLATES", () => getTemplates(), { + const { getWorkspaceBySlug } = useWorkspace(); + const workspaceId = getWorkspaceBySlug(workspaceSlug as string)?.id; + const { data: templates, isLoading } = useSWR("PI_TEMPLATES", () => getTemplates(workspaceId), { revalidateOnFocus: false, revalidateIfStale: false, errorRetryCount: 0, diff --git a/apps/web/ee/components/pi-chat/input/root.tsx b/apps/web/ee/components/pi-chat/input/root.tsx index 58fdfbf6c0..720bb03f4e 100644 --- a/apps/web/ee/components/pi-chat/input/root.tsx +++ b/apps/web/ee/components/pi-chat/input/root.tsx @@ -58,7 +58,7 @@ export const InputBox = observer((props: TProps) => { const focusRef = useRef(focus); const editorCommands = useRef(null); - useSWR(`PI_MODELS`, () => fetchModels(), { + useSWR(`PI_MODELS`, () => fetchModels(workspaceId), { revalidateOnFocus: true, revalidateIfStale: true, errorRetryCount: 0, @@ -72,17 +72,24 @@ export const InputBox = observer((props: TProps) => { async (e?: React.FormEvent) => { e?.preventDefault(); const query = editorCommands.current?.getHTML(); - if (isLoadingRef.current || !query || isCommentEmpty(query)) return; + if (isLoadingRef.current || !query || isCommentEmpty(query) || !workspaceId) return; if (!activeChatIdRef.current) { isLoadingRef.current = true; setIsInitializing(true); - const newChatId = await createNewChat(focusRef.current, isProjectLevel, workspaceId || ""); + const newChatId = await createNewChat(focusRef.current, isProjectLevel, workspaceId); activeChatIdRef.current = newChatId; setIsInitializing(false); // Don't redirect if we are in the floating chat window if (shouldRedirect) router.push(`/${workspaceSlug}/${isProjectLevel ? "projects/" : ""}pi-chat/${newChatId}`); } - getAnswer(activeChatIdRef.current, query, focusRef.current, isProjectLevel); + getAnswer( + activeChatIdRef.current, + query, + focusRef.current, + isProjectLevel, + workspaceSlug?.toString(), + workspaceId + ); editorCommands.current?.clear(); }, [editorCommands, getAnswer, activeChatId] diff --git a/apps/web/ee/components/pi-chat/layout.tsx b/apps/web/ee/components/pi-chat/layout.tsx index 6604013443..85af16a7dd 100644 --- a/apps/web/ee/components/pi-chat/layout.tsx +++ b/apps/web/ee/components/pi-chat/layout.tsx @@ -34,12 +34,11 @@ export const PiChatLayout = observer((props: TProps) => { const pathName = usePathname(); // derived states const isFullScreen = pathName.includes("pi-chat") || isFullScreenProp; + const workspaceId = getWorkspaceBySlug(workspaceSlug as string)?.id; useSWR( workspaceSlug ? `PI_USER_THREADS_${workspaceSlug}_${isProjectLevel}` : null, - workspaceSlug - ? () => fetchUserThreads(getWorkspaceBySlug(workspaceSlug as string)?.id || "", isProjectLevel) - : null, + workspaceSlug ? () => fetchUserThreads(workspaceId, isProjectLevel) : null, { revalidateOnFocus: false, revalidateIfStale: false, @@ -48,7 +47,7 @@ export const PiChatLayout = observer((props: TProps) => { ); useSWR( activeChatId ? `PI_ACTIVE_CHAT_${activeChatId}` : null, - activeChatId ? () => fetchChatById(activeChatId) : null, + activeChatId ? () => fetchChatById(activeChatId, workspaceId) : null, { revalidateOnFocus: false, revalidateIfStale: false, diff --git a/apps/web/ee/components/pi-chat/list/list-item.tsx b/apps/web/ee/components/pi-chat/list/list-item.tsx index 94a04cfcc6..e4227b10c5 100644 --- a/apps/web/ee/components/pi-chat/list/list-item.tsx +++ b/apps/web/ee/components/pi-chat/list/list-item.tsx @@ -6,10 +6,11 @@ import { Pencil, Star, Trash } from "lucide-react"; import { useTranslation } from "@plane/i18n"; import { CustomMenu, EModalPosition, EModalWidth, ModalCore, setToast, TContextMenuItem, TOAST_TYPE } from "@plane/ui"; import { calculateTimeAgo, cn } from "@plane/utils"; +import { useWorkspace } from "@/hooks/store/use-workspace"; +import { usePiChat } from "@/plane-web/hooks/store/use-pi-chat"; import { TUserThreads } from "@/plane-web/types"; import { ChatDeleteModal } from "../modals/delete-modal"; import { EditForm } from "../modals/edit-form"; -import { usePiChat } from "@/plane-web/hooks/store/use-pi-chat"; type TProps = { thread: TUserThreads; @@ -27,12 +28,15 @@ export const PiChatListItem = observer((props: TProps) => { const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); // hooks const { favoriteChat, unfavoriteChat } = usePiChat(); + const { getWorkspaceBySlug } = useWorkspace(); + // derived + const workspaceId = getWorkspaceBySlug(workspaceSlug as string)?.id; const handleFavorite = async () => { if (thread.is_favorite) { - await unfavoriteChat(thread.chat_id); + await unfavoriteChat(thread.chat_id, workspaceId); } else { - await favoriteChat(thread.chat_id); + await favoriteChat(thread.chat_id, workspaceId); } setToast({ title: thread.is_favorite ? t("favorite_removed_successfully") : t("favorite_created_successfully"), @@ -65,7 +69,7 @@ export const PiChatListItem = observer((props: TProps) => { <> setIsDeleteModalOpen(false)} @@ -80,6 +84,7 @@ export const PiChatListItem = observer((props: TProps) => { chatId={thread.chat_id} title={thread.title || ""} handleModalClose={() => setIsEditModalOpen(false)} + workspaceId={workspaceId} />
diff --git a/apps/web/ee/components/pi-chat/modals/edit-form.tsx b/apps/web/ee/components/pi-chat/modals/edit-form.tsx index 522bcaeed0..be60a278c0 100644 --- a/apps/web/ee/components/pi-chat/modals/edit-form.tsx +++ b/apps/web/ee/components/pi-chat/modals/edit-form.tsx @@ -13,11 +13,12 @@ import { usePiChat } from "@/plane-web/hooks/store/use-pi-chat"; type Props = { chatId: string; title: string; + workspaceId: string | undefined; handleModalClose: () => void; }; export const EditForm: React.FC = (props) => { - const { chatId, title, handleModalClose } = props; + const { chatId, title, handleModalClose, workspaceId } = props; // hooks const { isMobile } = usePlatformOS(); const { renameChat } = usePiChat(); @@ -31,7 +32,7 @@ export const EditForm: React.FC = (props) => { e.preventDefault(); try { setIsSubmitting(true); - await renameChat(chatId, newTitle); + await renameChat(chatId, newTitle, workspaceId); setIsSubmitting(false); setToast({ type: TOAST_TYPE.SUCCESS, diff --git a/apps/web/ee/components/pi-chat/sidebar/right-side-panel.tsx b/apps/web/ee/components/pi-chat/sidebar/right-side-panel.tsx index 7238494d85..c235595a97 100644 --- a/apps/web/ee/components/pi-chat/sidebar/right-side-panel.tsx +++ b/apps/web/ee/components/pi-chat/sidebar/right-side-panel.tsx @@ -26,7 +26,7 @@ export const RightSidePanel = observer((props: TProps) => { const { geUserThreadsByWorkspaceId, isLoadingThreads } = usePiChat(); const { getWorkspaceBySlug } = useWorkspace(); const workspaceId = workspaceSlug && getWorkspaceBySlug(workspaceSlug?.toString() || "")?.id; - const userThreads = geUserThreadsByWorkspaceId(workspaceId?.toString() || ""); + const userThreads = geUserThreadsByWorkspaceId(workspaceId?.toString()); // filter user threads const filteredUserThread = diff --git a/apps/web/ee/components/pi-chat/sidebar/sidebar-item.tsx b/apps/web/ee/components/pi-chat/sidebar/sidebar-item.tsx index ba6ddf5f43..c123a69442 100644 --- a/apps/web/ee/components/pi-chat/sidebar/sidebar-item.tsx +++ b/apps/web/ee/components/pi-chat/sidebar/sidebar-item.tsx @@ -6,6 +6,7 @@ import { useTranslation } from "@plane/i18n"; import { CustomMenu, EModalWidth, EModalPosition, ModalCore, setToast, TContextMenuItem, TOAST_TYPE } from "@plane/ui"; import { cn, joinUrlPath } from "@plane/utils"; import { SidebarNavItem } from "@/components/sidebar"; +import { useWorkspace } from "@/hooks/store/use-workspace"; import { usePiChat } from "@/plane-web/hooks/store/use-pi-chat"; import { ChatDeleteModal } from "../modals/delete-modal"; import { EditForm } from "../modals/edit-form"; @@ -30,12 +31,14 @@ export const SidebarItem = observer((props: TProps) => { const { t } = useTranslation(); // hooks const { favoriteChat, unfavoriteChat } = usePiChat(); + const { getWorkspaceBySlug } = useWorkspace(); + const workspaceId = getWorkspaceBySlug(workspaceSlug as string)?.id; const handleFavorite = async () => { if (isFavorite) { - await unfavoriteChat(chatId); + await unfavoriteChat(chatId, workspaceId); } else { - await favoriteChat(chatId); + await favoriteChat(chatId, workspaceId); } setToast({ title: isFavorite ? t("favorite_removed_successfully") : t("favorite_created_successfully"), @@ -81,7 +84,12 @@ export const SidebarItem = observer((props: TProps) => { position={EModalPosition.TOP} width={EModalWidth.SM} > - setIsEditModalOpen(false)} /> + setIsEditModalOpen(false)} + workspaceId={workspaceId} + /> {" "}
diff --git a/apps/web/ee/components/pi-chat/system-prompts.tsx b/apps/web/ee/components/pi-chat/system-prompts.tsx index 58538aa41c..f9a3a84025 100644 --- a/apps/web/ee/components/pi-chat/system-prompts.tsx +++ b/apps/web/ee/components/pi-chat/system-prompts.tsx @@ -50,11 +50,11 @@ const SystemPrompts = (props: TSystemPrompt) => { entityType: projectId ? "project_id" : "workspace_id", entityIdentifier: projectId?.toString() || workspaceId?.toString() || "", }; - const newChatId = await createNewChat(focus, isProjectLevel, workspaceId || ""); + const newChatId = await createNewChat(focus, isProjectLevel, workspaceId); setIsInitializing(""); // Don't redirect if we are in the floating chat window if (shouldRedirect) router.push(`/${workspaceSlug}/${isProjectLevel ? "projects/" : ""}pi-chat/${newChatId}`); - getAnswer(newChatId, prompt.text, focus, isProjectLevel); + getAnswer(newChatId, prompt.text, focus, isProjectLevel, workspaceSlug?.toString(), workspaceId?.toString()); }; const promptIcon = getIcon(prompt.type); diff --git a/apps/web/ee/services/pi-chat.service.ts b/apps/web/ee/services/pi-chat.service.ts index 48a05a904d..659a6863dc 100644 --- a/apps/web/ee/services/pi-chat.service.ts +++ b/apps/web/ee/services/pi-chat.service.ts @@ -70,8 +70,12 @@ export class PiChatService extends APIService { } // fetch templates - async listTemplates(): Promise { - return this.get(`/api/v1/chat/get-templates/`) + async listTemplates(workspaceId: string | undefined): Promise { + return this.get(`/api/v1/chat/get-templates/`, { + params: { + ...(workspaceId && { workspace_id: workspaceId }), + }, + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -79,8 +83,11 @@ export class PiChatService extends APIService { } // generate title - async retrieveTitle(chatId: string): Promise { - return this.post(`/api/v1/chat/generate-title/`, { chat_id: chatId }) + async retrieveTitle(chatId: string, workspaceId: string | undefined): Promise { + return this.post(`/api/v1/chat/generate-title/`, { + chat_id: chatId, + ...(workspaceId && { workspace_id: workspaceId }), + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -106,10 +113,11 @@ export class PiChatService extends APIService { } // get chat by id - async retrieveChat(chatId: string): Promise { + async retrieveChat(chatId: string, workspaceId: string | undefined): Promise { return this.get(`/api/v1/chat/get-chat-history-object/`, { params: { chat_id: chatId, + ...(workspaceId && { workspace_id: workspaceId }), }, }) .then((response) => response?.data) @@ -120,16 +128,16 @@ export class PiChatService extends APIService { // get user threads async listUserThreads( - workspaceId: string, + workspaceId: string | undefined, is_project_chat: boolean, cursor: string = "0" ): Promise { return this.get(`/api/v1/chat/get-user-threads/`, { params: { per_page: 100, - workspace_id: workspaceId, is_project_chat, cursor, + ...(workspaceId && { workspace_id: workspaceId }), }, }) .then((response) => response?.data) @@ -139,8 +147,12 @@ export class PiChatService extends APIService { } // get recent chats - async listRecentChats(): Promise { - return this.get(`/api/v1/chat/get-recent-user-threads/`) + async listRecentChats(workspaceId: string | undefined): Promise { + return this.get(`/api/v1/chat/get-recent-user-threads/`, { + params: { + ...(workspaceId && { workspace_id: workspaceId }), + }, + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -148,8 +160,12 @@ export class PiChatService extends APIService { } // get models - async listAiModels(): Promise { - return this.get(`/api/v1/chat/get-models/`) + async listAiModels(workspaceId?: string): Promise { + return this.get(`/api/v1/chat/get-models/`, { + params: { + ...(workspaceId && { workspace_id: workspaceId }), + }, + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -157,8 +173,11 @@ export class PiChatService extends APIService { } // favorite chat - async favoriteChat(chatId: string): Promise { - return this.post(`/api/v1/chat/favorite-chat/`, { chat_id: chatId }) + async favoriteChat(chatId: string, workspaceId: string | undefined): Promise { + return this.post(`/api/v1/chat/favorite-chat/`, { + chat_id: chatId, + ...(workspaceId && { workspace_id: workspaceId }), + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -166,8 +185,11 @@ export class PiChatService extends APIService { } // unfavorite chat - async unfavoriteChat(chatId: string): Promise { - return this.post(`/api/v1/chat/unfavorite-chat/`, { chat_id: chatId }) + async unfavoriteChat(chatId: string, workspaceId: string | undefined): Promise { + return this.post(`/api/v1/chat/unfavorite-chat/`, { + chat_id: chatId, + ...(workspaceId && { workspace_id: workspaceId }), + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -175,9 +197,11 @@ export class PiChatService extends APIService { } // get favorite chats - async listFavoriteChats(workspaceId: string): Promise { + async listFavoriteChats(workspaceId: string | undefined): Promise { return this.get(`/api/v1/chat/get-favorite-chats/`, { - params: { workspace_id: workspaceId }, + params: { + ...(workspaceId && { workspace_id: workspaceId }), + }, }) .then((response) => response?.data) .catch((error) => { @@ -186,8 +210,12 @@ export class PiChatService extends APIService { } // rename chat - async renameChat(chatId: string, title: string): Promise { - return this.post(`/api/v1/chat/rename-chat/`, { chat_id: chatId, title }) + async renameChat(chatId: string, title: string, workspaceId: string | undefined): Promise { + return this.post(`/api/v1/chat/rename-chat/`, { + chat_id: chatId, + title, + ...(workspaceId && { workspace_id: workspaceId }), + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; diff --git a/apps/web/ee/store/pi-chat/pi-chat.ts b/apps/web/ee/store/pi-chat/pi-chat.ts index e7aac4bcd6..f46cd7bed7 100644 --- a/apps/web/ee/store/pi-chat/pi-chat.ts +++ b/apps/web/ee/store/pi-chat/pi-chat.ts @@ -41,26 +41,39 @@ export interface IPiChatStore { isPiChatDrawerOpen: boolean; // computed fn geUserThreads: () => TUserThreads[]; - geUserThreadsByWorkspaceId: (workspaceId: string) => TUserThreads[]; + geUserThreadsByWorkspaceId: (workspaceId: string | undefined) => TUserThreads[]; geFavoriteChats: () => TUserThreads[]; getChatById: (chatId: string) => TChatHistory; // actions initPiChat: (chatId?: string) => void; - fetchChatById: (chatId: string) => void; - getAnswer: (chatId: string, query: string, focus: TFocus, isProjectChat: boolean) => Promise; - getTemplates: () => Promise; - fetchUserThreads: (workspaceId: string, isProjectChat: boolean) => void; + fetchChatById: (chatId: string, workspaceId: string | undefined) => void; + getAnswer: ( + chatId: string, + query: string, + focus: TFocus, + isProjectChat: boolean, + workspaceSlug: string, + workspaceId: string | undefined + ) => Promise; + getTemplates: (workspaceId: string | undefined) => Promise; + fetchUserThreads: (workspaceId: string | undefined, isProjectChat: boolean) => void; searchCallback: (workspace: string, query: string, focus: TFocus) => Promise; - sendFeedback: (chatId: string, message_index: number, feedback: EFeedback, feedbackMessage?: string) => Promise; - fetchModels: () => Promise; + sendFeedback: ( + chatId: string, + message_index: number, + feedback: EFeedback, + workspaceId?: string, + feedbackMessage?: string + ) => Promise; + fetchModels: (workspaceId?: string) => Promise; setActiveModel: (model: TAiModels) => void; - createNewChat: (focus: TFocus, isProjectChat: boolean, workspaceId: string) => Promise; - renameChat: (chatId: string, title: string) => Promise; + createNewChat: (focus: TFocus, isProjectChat: boolean, workspaceId: string | undefined) => Promise; + renameChat: (chatId: string, title: string, workspaceId: string | undefined) => Promise; deleteChat: (chatId: string, workspaceSlug: string) => Promise; - favoriteChat: (chatId: string) => Promise; - unfavoriteChat: (chatId: string) => Promise; - fetchRecentChats: (isProjectChat: boolean) => Promise; - fetchFavoriteChats: (workspaceId: string) => Promise; + favoriteChat: (chatId: string, workspaceId: string | undefined) => Promise; + unfavoriteChat: (chatId: string, workspaceId: string | undefined) => Promise; + fetchRecentChats: (workspaceId: string | undefined, isProjectChat: boolean) => Promise; + fetchFavoriteChats: (workspaceId: string | undefined) => Promise; togglePiChatDrawer: (value?: boolean) => void; } @@ -158,7 +171,7 @@ export class PiChatStore implements IPiChatStore { // computed geUserThreads = computedFn(() => this.piThreads.map((chatId) => this.chatMap[chatId]) || []); - geUserThreadsByWorkspaceId = computedFn((workspaceId: string) => { + geUserThreadsByWorkspaceId = computedFn((workspaceId: string | undefined) => { if (!workspaceId) return []; return ( this.projectThreads @@ -186,7 +199,7 @@ export class PiChatStore implements IPiChatStore { this.isAuthorized = true; }; - createNewChat = async (focus: TFocus, isProjectChat: boolean = false, workspaceId: string) => { + createNewChat = async (focus: TFocus, isProjectChat: boolean = false, workspaceId: string | undefined) => { this.isNewChat = true; let payload: TInitPayload = { workspace_in_context: focus.isInWorkspaceContext, @@ -216,8 +229,8 @@ export class PiChatStore implements IPiChatStore { return newChatId; }; - getTemplates = async () => { - const response = await this.piChatService.listTemplates(); + getTemplates = async (workspaceId: string | undefined) => { + const response = await this.piChatService.listTemplates(workspaceId); return response?.templates; }; @@ -225,6 +238,7 @@ export class PiChatStore implements IPiChatStore { isNewChat: boolean, chatId: string, payload: TQuery, + workspaceId: string | undefined, callback: (property: "answer" | "reasoning", value: string) => void ) => { const token = await this.piChatService.retrieveToken(payload); @@ -263,7 +277,7 @@ export class PiChatStore implements IPiChatStore { this.isPiTypingMap[chatId] = false; // Call the title api if its a new chat if (isNewChat) { - const title = await this.piChatService.retrieveTitle(chatId); + const title = await this.piChatService.retrieveTitle(chatId, workspaceId); runInAction(() => { this.isNewChat = false; update(this.chatMap, chatId, (chat) => ({ @@ -281,7 +295,14 @@ export class PiChatStore implements IPiChatStore { }; }; - getAnswer = async (chatId: string, query: string, focus: TFocus, isProjectChat: boolean = false) => { + getAnswer = async ( + chatId: string, + query: string, + focus: TFocus, + isProjectChat: boolean = false, + workspaceSlug: string, + workspaceId: string | undefined + ) => { if (!chatId) { throw new Error("Chat not initialized"); } @@ -333,13 +354,15 @@ export class PiChatStore implements IPiChatStore { } : {}, is_project_chat: isProjectChat, + workspace_slug: workspaceSlug, + workspace_id: workspaceId, }; if (focus.isInWorkspaceContext) { payload = { ...payload, [focus.entityType]: focus.entityIdentifier }; } // Api call here - this.getStreamingAnswer(isNewChat, chatId, payload, (property, value) => { + this.getStreamingAnswer(isNewChat, chatId, payload, workspaceId, (property, value) => { newDialogue[property] += value; runInAction(() => { update(this.chatMap, chatId, (chat) => ({ @@ -364,14 +387,14 @@ export class PiChatStore implements IPiChatStore { } }; - fetchChatById = async (chatId: string) => { + fetchChatById = async (chatId: string, workspaceId: string | undefined) => { if (this.isNewChat) return; try { // Call api here runInAction(() => { this.isLoadingMap[chatId] = true; }); - const response = await this.piChatService.retrieveChat(chatId); + const response = await this.piChatService.retrieveChat(chatId, workspaceId); runInAction(() => { update(this.chatMap, chatId, (chat) => ({ ...chat, @@ -391,7 +414,7 @@ export class PiChatStore implements IPiChatStore { } }; - fetchUserThreads = async (workspaceId: string, isProjectChat: boolean = false) => { + fetchUserThreads = async (workspaceId: string | undefined, isProjectChat: boolean = false) => { const threads = isProjectChat ? this.projectThreads : this.piThreads; try { runInAction(() => { @@ -419,13 +442,13 @@ export class PiChatStore implements IPiChatStore { } }; - fetchRecentChats = async (isProjectChat: boolean = false) => { + fetchRecentChats = async (workspaceId: string | undefined, isProjectChat: boolean = false) => { try { const threads = isProjectChat ? this.projectThreads : this.piThreads; runInAction(() => { this.isLoadingThreads = true; }); - const response = await this.piChatService.listRecentChats(); + const response = await this.piChatService.listRecentChats(workspaceId); runInAction(() => { response.results.forEach((chat) => { update(this.chatMap, chat.chat_id, (prev) => ({ @@ -446,9 +469,9 @@ export class PiChatStore implements IPiChatStore { } }; - fetchModels = async () => { + fetchModels = async (workspaceId: string | undefined) => { try { - const response = await this.piChatService.listAiModels(); + const response = await this.piChatService.listAiModels(workspaceId); runInAction(() => { this.models = response.models; response.models.forEach((model) => { @@ -476,7 +499,13 @@ export class PiChatStore implements IPiChatStore { return response.results; }; - sendFeedback = async (chatId: string, message_index: number, feedback: EFeedback, feedbackMessage?: string) => { + sendFeedback = async ( + chatId: string, + message_index: number, + feedback: EFeedback, + workspaceId?: string, + feedbackMessage?: string + ) => { const initialState = this.chatMap[chatId]?.dialogue?.[message_index]?.feedback; runInAction(() => { runInAction(() => { @@ -491,6 +520,7 @@ export class PiChatStore implements IPiChatStore { chat_id: chatId, feedback, feedback_message: feedbackMessage, + ...(workspaceId && { workspace_id: workspaceId }), }); return response; } catch (e) { @@ -503,7 +533,7 @@ export class PiChatStore implements IPiChatStore { } }; - fetchFavoriteChats = async (workspaceId: string) => { + fetchFavoriteChats = async (workspaceId: string | undefined) => { this.isLoadingFavoriteChats = true; const response = await this.piChatService.listFavoriteChats(workspaceId); runInAction(() => { @@ -520,7 +550,7 @@ export class PiChatStore implements IPiChatStore { }); }; - favoriteChat = async (chatId: string) => { + favoriteChat = async (chatId: string, workspaceId: string | undefined) => { const favoriteChats = this.favoriteChats; try { runInAction(() => { @@ -530,7 +560,7 @@ export class PiChatStore implements IPiChatStore { })); this.favoriteChats = [...this.favoriteChats, chatId]; }); - await this.piChatService.favoriteChat(chatId); + await this.piChatService.favoriteChat(chatId, workspaceId); } catch (e) { runInAction(() => { update(this.chatMap, chatId, (chat) => ({ @@ -542,7 +572,7 @@ export class PiChatStore implements IPiChatStore { } }; - unfavoriteChat = async (chatId: string) => { + unfavoriteChat = async (chatId: string, workspaceId: string | undefined) => { const favoriteChats = this.favoriteChats; try { runInAction(() => { @@ -552,7 +582,7 @@ export class PiChatStore implements IPiChatStore { })); this.favoriteChats = favoriteChats.filter((id) => id !== chatId); }); - await this.piChatService.unfavoriteChat(chatId); + await this.piChatService.unfavoriteChat(chatId, workspaceId); } catch (e) { runInAction(() => { update(this.chatMap, chatId, (chat) => ({ @@ -564,7 +594,7 @@ export class PiChatStore implements IPiChatStore { } }; - renameChat = async (chatId: string, title: string) => { + renameChat = async (chatId: string, title: string, workspaceId: string | undefined) => { const initialState = this.chatMap[chatId]?.title; try { runInAction(() => { @@ -573,7 +603,7 @@ export class PiChatStore implements IPiChatStore { title, })); }); - await this.piChatService.renameChat(chatId, title); + await this.piChatService.renameChat(chatId, title, workspaceId); } catch (e) { runInAction(() => { update(this.chatMap, chatId, (chat) => ({ diff --git a/apps/web/ee/types/pi-chat.d.ts b/apps/web/ee/types/pi-chat.d.ts index a97ed0cb91..7a3a63c3ee 100644 --- a/apps/web/ee/types/pi-chat.d.ts +++ b/apps/web/ee/types/pi-chat.d.ts @@ -25,8 +25,12 @@ export type TQuery = { [key: string]: string; }; is_project_chat?: boolean; + workspace_slug?: string; }; -export type TInitPayload = Pick; +export type TInitPayload = Pick< + TQuery, + "workspace_in_context" | "workspace_id" | "project_id" | "is_project_chat" | "workspace_slug" +>; export type TSearchQuery = { query: string; }; @@ -36,6 +40,7 @@ export type TFeedback = { message_index: number; feedback: EFeedback; feedback_message?: string; + workspace_id?: string; }; export type TFocus = {