import { AssistantRuntimeProvider } from "@assistant-ui/react"; import { useEffect, useState, useSyncExternalStore } from "react"; import { useHarnessRuntime, type HarnessRuntimeStore } from "./assistant/use-harness-runtime.js"; import { Thread } from "./components/chat/Thread.js"; import { AppShell } from "./components/layout/AppShell.js"; import { SkillsPanel } from "./components/skills/SkillsPanel.js"; import { EventTimeline } from "./components/timeline/EventTimeline.js"; import { HarnessClientStore } from "./store/harness-client-store.js"; type AppStore = HarnessRuntimeStore & { start(): Promise; getModelConfig(): Promise<{ modelConfig: { configured: boolean; modelId?: string; supportsImages?: boolean } }>; }; export type AppProps = { store?: AppStore; autoStart?: boolean; modelConfigured?: boolean; }; export function App({ store: suppliedStore, autoStart = true, modelConfigured: suppliedModelConfigured }: AppProps) { const [ownedStore] = useState(() => new HarnessClientStore()); const store = suppliedStore ?? ownedStore; const snapshot = useSyncExternalStore( (subscriber) => store.subscribe(subscriber), () => store.getSnapshot(), () => store.getSnapshot(), ); const [model, setModel] = useState({ configured: suppliedModelConfigured ?? false, modelId: suppliedModelConfigured === true ? "Configured model" : "No model", supportsImages: false, }); const runtime = useHarnessRuntime(store, { isSendDisabled: !model.configured }); const busy = Object.values(snapshot.runs).some((run) => run.status === "running"); const approvalPending = Object.values(snapshot.approvals).some((approval) => approval.status === "pending"); useEffect(() => { if (!autoStart) return undefined; let active = true; void store.start().then(async () => { const response = await store.getModelConfig(); if (active) setModel({ configured: response.modelConfig.configured, modelId: response.modelConfig.modelId ?? "No model", supportsImages: response.modelConfig.supportsImages ?? false, }); }).catch(() => undefined); return () => { active = false; }; }, [autoStart, store]); return ( { window.dispatchEvent(new CustomEvent("agent-studio:open-settings")); }, onReset: () => window.location.reload(), }} skills={} chat={} timeline={} /> ); }