diff --git a/web/src/app/(applayout)/playground/page.tsx b/web/src/app/(applayout)/playground/page.tsx
index 399886c..cdfe420 100644
--- a/web/src/app/(applayout)/playground/page.tsx
+++ b/web/src/app/(applayout)/playground/page.tsx
@@ -101,7 +101,7 @@ const ChatPlayground = () => {
transition="width 0.1s, visibility 0.1s"
>
-
+
diff --git a/web/src/components/Playground/ChatHistoryList.tsx b/web/src/components/Playground/ChatHistoryList.tsx
index 4066972..c2789d4 100644
--- a/web/src/components/Playground/ChatHistoryList.tsx
+++ b/web/src/components/Playground/ChatHistoryList.tsx
@@ -1,21 +1,8 @@
import {
Flex,
Spinner,
- Container,
useColorModeValue,
IconButton,
- Menu,
- MenuButton,
- MenuList,
- MenuItem,
- Modal,
- ModalOverlay,
- ModalContent,
- ModalHeader,
- ModalFooter,
- ModalBody,
- ModalCloseButton,
- useDisclosure,
Icon,
Box,
Text,
@@ -27,20 +14,15 @@ import useCustomToast from "../../hooks/useCustomToast";
import { useRouter } from "next/navigation";
import { useTranslation } from "react-i18next";
import React, { useEffect, useState } from "react";
-import {
- EllipsisVerticalIcon,
- StarIcon,
- Trash,
- Trash2Icon,
-} from "lucide-react";
+import { StarIcon, Trash2Icon } from "lucide-react";
import useChatMessageStore from "@/store/chatMessageStore";
-import { FaTrashCan } from "react-icons/fa6";
interface ChatHistoryProps {
teamId: string;
+ isPlayground?: boolean;
}
-const ChatHistoryList = ({ teamId }: ChatHistoryProps) => {
+const ChatHistoryList = ({ teamId, isPlayground }: ChatHistoryProps) => {
const queryClient = useQueryClient();
const navigate = useRouter();
@@ -86,31 +68,49 @@ const ChatHistoryList = ({ teamId }: ChatHistoryProps) => {
const deleteThreadMutation = useMutation(deleteThread, {
onError: (err: ApiError) => {
const errDetail = err.body?.detail;
- showToast("Unable to delete thread.", `${errDetail}`, "error");
+ // showToast("Unable to delete thread.", `${errDetail}`, "error");
+ console.log("error", errDetail);
},
onSettled: () => {
queryClient.invalidateQueries(["threads", teamId]);
- // queryClient.invalidateQueries(["threads", threadId]);
+ queryClient.invalidateQueries(["threads", selectedThreadId]);
},
});
const [selectedThreadId, setSelectedThreadId] = useState(null);
const onClickRowHandler = (threadId: string) => {
- navigate.push(`/playground?teamId=${teamId}&threadId=${threadId}`);
setSelectedThreadId(threadId);
+ if (isPlayground) {
+ navigate.push(`/playground?teamId=${teamId}&threadId=${threadId}`);
+ } else {
+ navigate.push(`/teams/${teamId}?threadId=${threadId}`);
+ }
};
const { setMessages } = useChatMessageStore();
+ const [shouldNavigate, setShouldNavigate] = useState(false);
+
const handleDeleteThread = () => {
if (selectedThreadId) {
deleteThreadMutation.mutate(selectedThreadId);
-
setMessages([]);
- navigate.push(`/playground?teamId=${teamId}`);
+ setShouldNavigate(true);
}
};
- if (isError) {
- const errDetail = (error as ApiError).body?.detail;
+ useEffect(() => {
+ if (shouldNavigate) {
+ if (isPlayground) {
+ navigate.push(`/playground?teamId=${teamId}`);
+ } else {
+ navigate.push(`/steamsS/${teamId}`);
+ }
+ setShouldNavigate(false);
+ }
+ }, [shouldNavigate, isPlayground, teamId, navigate]);
+
+ if (isError || membersIsError) {
+ const errors = error || membersError;
+ const errDetail = (errors as ApiError).body?.detail;
showToast("Something went wrong.", `${errDetail}`, "error");
}
@@ -118,7 +118,7 @@ const ChatHistoryList = ({ teamId }: ChatHistoryProps) => {
const { t } = useTranslation();
return (
<>
- {isLoading ? (
+ {isLoading && membersLoading ? (
@@ -175,7 +175,7 @@ const ChatHistoryList = ({ teamId }: ChatHistoryProps) => {
{thread.query}
-
+
{
- {/*
)}
diff --git a/web/src/components/Playground/ChatMain.tsx b/web/src/components/Playground/ChatMain.tsx
index 0fb97be..82d8cc1 100644
--- a/web/src/components/Playground/ChatMain.tsx
+++ b/web/src/components/Playground/ChatMain.tsx
@@ -18,7 +18,7 @@ import {
useQueryClient,
} from "react-query";
import useCustomToast from "../../hooks/useCustomToast";
-import { useRef, useState } from "react";
+import { useCallback, useRef, useState } from "react";
import {
getQueryString,
getRequestBody,
@@ -61,7 +61,9 @@ const ChatMain = ({ isPlayground }: { isPlayground?: boolean }) => {
const { t } = useTranslation();
const { teamId } = useChatTeamIdStore() as { teamId: string };
- const [currentThreadId, setCurrentThreadId] = useState(null);
+ const [currentThreadId, setCurrentThreadId] = useState(
+ searchParams.get("threadId")
+ );
const showToast = useCustomToast();
const [input, setInput] = useState("");
const { messages, setMessages } = useChatMessageStore();
@@ -139,9 +141,7 @@ const ChatMain = ({ isPlayground }: { isPlayground?: boolean }) => {
id: threadId,
requestBody: data,
});
-
cancelablePromise.then((thread) => resolve(thread.id)).catch(reject);
-
cancelUpdateRef.current = () => cancelablePromise.cancel();
});
};
@@ -162,26 +162,21 @@ const ChatMain = ({ isPlayground }: { isPlayground?: boolean }) => {
const processMessage = (response: ChatResponse) => {
setMessages((prevMessages: ChatResponse[]) => {
- const updatedMessages = [...prevMessages];
-
- const messageIndex = updatedMessages.findIndex(
+ const messageIndex = prevMessages.findIndex(
(msg) => msg.id === response.id
);
-
if (messageIndex !== -1) {
- const currentMessage = updatedMessages[messageIndex];
- updatedMessages[messageIndex] = {
- ...currentMessage,
- // only content is streamable in chunks
- content: currentMessage.content
- ? currentMessage.content + (response.content || "")
- : null,
- tool_output: response.tool_output,
- };
- } else {
- updatedMessages.push(response);
+ return prevMessages.map((msg, index) =>
+ index === messageIndex
+ ? {
+ ...msg,
+ content: (msg.content ?? "") + (response.content ?? ""),
+ tool_output: response.tool_output,
+ }
+ : msg
+ );
}
- return updatedMessages;
+ return [...prevMessages, response];
});
};
@@ -218,10 +213,9 @@ const ChatMain = ({ isPlayground }: { isPlayground?: boolean }) => {
},
});
- // 从 TeamChat 数据中提取适合 ThreadUpdate 的信息
+
const threadUpdateData: ThreadUpdate = {
- query: data.messages[0].content, // 假设第一条消息是查询
- // 如果需要,可以添加其他 ThreadUpdate 所需的字段
+ query: data.messages[0].content,
};
const updatePromise = updateThreadMutation.mutateAsync(threadUpdateData);
@@ -235,17 +229,12 @@ const ChatMain = ({ isPlayground }: { isPlayground?: boolean }) => {
}
};
- const interruptStreamAndUpdate = () => {
- if (abortControllerRef.current) {
- abortControllerRef.current.abort();
- }
- if (cancelUpdateRef.current) {
- cancelUpdateRef.current();
- }
+ const interruptStreamAndUpdate = useCallback(() => {
+ abortControllerRef.current?.abort();
+ cancelUpdateRef.current?.();
setIsInterruptible(false);
- // 添加中断消息
- setMessages((prev: ChatResponse[]) => [
+ setMessages((prev) => [
...prev,
{
type: "ai",
@@ -254,7 +243,7 @@ const ChatMain = ({ isPlayground }: { isPlayground?: boolean }) => {
name: "system",
},
]);
- };
+ }, [setMessages, t]);
const chatTeam = async (data: TeamChat) => {
// Create a new thread or update current thread with most recent user query
@@ -312,39 +301,40 @@ const ChatMain = ({ isPlayground }: { isPlayground?: boolean }) => {
},
});
- const onSubmit = async (e: React.FormEvent) => {
- e.preventDefault();
- mutation.mutate({ messages: [{ type: "human", content: input }] });
- setInput("");
- };
+ const onSubmit = useCallback(
+ async (e: React.FormEvent) => {
+ e.preventDefault();
+ mutation.mutate({ messages: [{ type: "human", content: input }] });
+ setInput("");
+ },
+ [input, mutation]
+ );
- const newChatHandler = () => {
- if (isPlayground) {
- navigate.push(`/playground?teamId=${teamId}`);
- setMessages([]);
- } else {
- navigate.push(`/teams/${teamId}`);
- setMessages([]);
- }
- };
+ const newChatHandler = useCallback(() => {
+ const path = isPlayground
+ ? `/playground?teamId=${teamId}`
+ : `/teams/${teamId}`;
+ navigate.push(path);
+ setMessages([]);
+ }, [isPlayground, teamId, navigate, setMessages]);
/**
* Submit the interrupt decision and optional tool message
*/
- const onResumeHandler = (
- decision: InterruptDecision,
- tool_message?: string | null
- ) => {
- mutation.mutate({
- messages: [
- {
- type: "human",
- content: tool_message || decision,
- },
- ],
- interrupt: { decision, tool_message },
- });
- };
+ const onResumeHandler = useCallback(
+ (decision: InterruptDecision, tool_message?: string | null) => {
+ mutation.mutate({
+ messages: [
+ {
+ type: "human",
+ content: tool_message || decision,
+ },
+ ],
+ interrupt: { decision, tool_message },
+ });
+ },
+ [mutation]
+ );
return (
{
borderRadius={"lg"}
size={"sm"}
>
- { t(`chat.chatMain.abort`)}
+ {t(`chat.chatMain.abort`)}
)}
diff --git a/web/src/components/Teams/DebugPreview/head.tsx b/web/src/components/Teams/DebugPreview/head.tsx
index 3976371..3e2ddef 100644
--- a/web/src/components/Teams/DebugPreview/head.tsx
+++ b/web/src/components/Teams/DebugPreview/head.tsx
@@ -66,7 +66,7 @@ function DebugPreviewHead({
-
+