2026-01-17 11:02:33 +08:00
|
|
|
"use client";
|
|
|
|
|
|
2026-03-11 13:51:51 +08:00
|
|
|
import { useParams } from "next/navigation";
|
|
|
|
|
import { useEffect, useRef, useState } from "react";
|
|
|
|
|
|
2026-02-02 10:18:02 +08:00
|
|
|
import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
|
2026-01-17 11:02:33 +08:00
|
|
|
import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
2026-02-07 16:14:48 +08:00
|
|
|
import { SubtasksProvider } from "@/core/tasks/context";
|
2026-01-17 11:02:33 +08:00
|
|
|
|
|
|
|
|
export default function ChatLayout({
|
|
|
|
|
children,
|
|
|
|
|
}: {
|
|
|
|
|
children: React.ReactNode;
|
|
|
|
|
}) {
|
2026-03-11 13:51:51 +08:00
|
|
|
const { thread_id } = useParams<{ thread_id: string }>();
|
|
|
|
|
const prevThreadId = useRef(thread_id);
|
|
|
|
|
|
|
|
|
|
// Increment only when navigating TO "new" from a non-"new" route.
|
|
|
|
|
// This forces a full remount of the subtree for a fresh new-chat state,
|
|
|
|
|
// without remounting when the URL transitions from "new" → actual-id
|
|
|
|
|
// (which would interrupt streaming).
|
|
|
|
|
const [generation, setGeneration] = useState(0);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (thread_id === "new" && prevThreadId.current !== "new") {
|
|
|
|
|
setGeneration((g) => g + 1);
|
|
|
|
|
}
|
|
|
|
|
prevThreadId.current = thread_id;
|
|
|
|
|
}, [thread_id]);
|
|
|
|
|
|
2026-02-02 10:18:02 +08:00
|
|
|
return (
|
2026-03-11 13:51:51 +08:00
|
|
|
<SubtasksProvider key={generation}>
|
2026-02-07 16:14:48 +08:00
|
|
|
<ArtifactsProvider>
|
|
|
|
|
<PromptInputProvider>{children}</PromptInputProvider>
|
|
|
|
|
</ArtifactsProvider>
|
|
|
|
|
</SubtasksProvider>
|
2026-02-02 10:18:02 +08:00
|
|
|
);
|
2026-01-17 11:02:33 +08:00
|
|
|
}
|