"use client"; import { useEffect, useState } from "react"; import { Thread } from "../components/assistant-ui/thread"; import { ThreadList } from "@/components/assistant-ui/thread-list"; import { usePiThreadState } from "@assistant-ui/react-pi"; import type { PiRuntimeReadiness } from "@assistant-ui/react-pi"; // Type-only import — erased at build time, so no server code reaches the client. import type { PiHandshake } from "@/lib/pi-server"; import { PiHandshakeProvider } from "../components/pi-handshake"; import { PiRuntimeProvider } from "./PiRuntimeProvider"; import { WorkspaceBrowser } from "../components/workspace-browser"; export default function Home() { const [handshake, setHandshake] = useState(null); const [workspacePath, setWorkspacePath] = useState(""); useEffect(() => { let active = true; fetch("/api/pi/handshake") .then((response) => response.json()) .then((data: PiHandshake) => { if (!active) return; setHandshake(data); setWorkspacePath(data.workspacePath ?? ""); }) .catch(() => { /* handshake is best-effort; the runtime still works on env defaults. */ }); return () => { active = false; }; }, []); return (
); } function Header({ workspacePath, onCommitWorkspace, }: { workspacePath: string; onCommitWorkspace: (value: string) => void; }) { return (
assistant-ui × Pi
); } function ReadinessBanner({ fallback, }: { fallback?: PiRuntimeReadiness | undefined; }) { const live = usePiThreadState((state) => state.readiness); const readiness = live ?? fallback; if (!readiness || readiness.state === "ready") return null; return (
{readiness.message ?? "The Pi runtime has no usable model selected."}
); }