2026-01-16 09:15:04 +08:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import { useParams, useRouter } from "next/navigation";
|
|
|
|
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
|
|
|
|
|
|
|
import { BreadcrumbItem } from "@/components/ui/breadcrumb";
|
|
|
|
|
import { InputBox } from "@/components/workspace/input-box";
|
|
|
|
|
import { MessageList } from "@/components/workspace/message-list/message-list";
|
|
|
|
|
import {
|
|
|
|
|
WorkspaceContainer,
|
|
|
|
|
WorkspaceBody,
|
|
|
|
|
WorkspaceHeader,
|
|
|
|
|
WorkspaceFooter,
|
|
|
|
|
} from "@/components/workspace/workspace-container";
|
2026-01-16 09:55:02 +08:00
|
|
|
import { useLocalSettings } from "@/core/settings";
|
2026-01-16 14:03:34 +08:00
|
|
|
import { type AgentThread } from "@/core/threads";
|
2026-01-16 19:51:39 +08:00
|
|
|
import { useSubmitThread, useThreadStream } from "@/core/threads/hooks";
|
|
|
|
|
import { pathOfThread, titleOfThread } from "@/core/threads/utils";
|
2026-01-16 09:15:04 +08:00
|
|
|
import { uuid } from "@/core/utils/uuid";
|
|
|
|
|
|
|
|
|
|
export default function ChatPage() {
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const { thread_id: threadIdFromPath } = useParams<{ thread_id: string }>();
|
|
|
|
|
const isNewThread = useMemo(
|
|
|
|
|
() => threadIdFromPath === "new",
|
|
|
|
|
[threadIdFromPath],
|
|
|
|
|
);
|
|
|
|
|
const [threadId, setThreadId] = useState<string | null>(null);
|
2026-01-16 09:55:02 +08:00
|
|
|
const { threadContext, setThreadContext } = useLocalSettings();
|
|
|
|
|
|
2026-01-16 09:15:04 +08:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (threadIdFromPath !== "new") {
|
|
|
|
|
setThreadId(threadIdFromPath);
|
|
|
|
|
} else {
|
|
|
|
|
setThreadId(uuid());
|
|
|
|
|
}
|
|
|
|
|
}, [threadIdFromPath]);
|
2026-01-16 14:03:34 +08:00
|
|
|
const thread = useThreadStream({
|
|
|
|
|
isNewThread,
|
|
|
|
|
threadId,
|
2026-01-16 09:15:04 +08:00
|
|
|
});
|
2026-01-16 19:51:39 +08:00
|
|
|
const handleSubmit = useSubmitThread({
|
|
|
|
|
isNewThread,
|
|
|
|
|
threadId,
|
|
|
|
|
thread,
|
|
|
|
|
threadContext,
|
|
|
|
|
afterSubmit() {
|
|
|
|
|
router.push(pathOfThread(threadId!));
|
2026-01-16 09:15:04 +08:00
|
|
|
},
|
2026-01-16 19:51:39 +08:00
|
|
|
});
|
2026-01-16 09:15:04 +08:00
|
|
|
const handleStop = useCallback(async () => {
|
|
|
|
|
await thread.stop();
|
|
|
|
|
}, [thread]);
|
|
|
|
|
return (
|
|
|
|
|
<WorkspaceContainer>
|
|
|
|
|
<WorkspaceHeader>
|
|
|
|
|
<BreadcrumbItem className="hidden md:block">
|
|
|
|
|
{isNewThread
|
|
|
|
|
? "New"
|
|
|
|
|
: titleOfThread(thread as unknown as AgentThread)}
|
|
|
|
|
</BreadcrumbItem>
|
|
|
|
|
</WorkspaceHeader>
|
|
|
|
|
<WorkspaceBody>
|
|
|
|
|
<div className="flex size-full justify-center">
|
|
|
|
|
<MessageList className="size-full" thread={thread} />
|
|
|
|
|
</div>
|
|
|
|
|
</WorkspaceBody>
|
|
|
|
|
<WorkspaceFooter>
|
|
|
|
|
<InputBox
|
|
|
|
|
className="max-w-(--container-width-md)"
|
|
|
|
|
autoFocus={isNewThread}
|
|
|
|
|
status={thread.isLoading ? "streaming" : "ready"}
|
2026-01-16 09:37:04 +08:00
|
|
|
context={threadContext}
|
|
|
|
|
onContextChange={setThreadContext}
|
2026-01-16 09:15:04 +08:00
|
|
|
onSubmit={handleSubmit}
|
|
|
|
|
onStop={handleStop}
|
|
|
|
|
/>
|
|
|
|
|
</WorkspaceFooter>
|
|
|
|
|
</WorkspaceContainer>
|
|
|
|
|
);
|
|
|
|
|
}
|