import { Menu, PanelLeftOpen, X } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useStore } from "zustand"; import { OpenPiLogo } from "../components/OpenPiLogo.tsx"; import { InspectionPanel, type InspectionTarget, } from "../features/inspection/InspectionPanel.tsx"; import { Composer } from "../features/composer/Composer.tsx"; import { SessionSidebar } from "../features/sessions/SessionSidebar.tsx"; import { Trajectory } from "../features/trajectory/Trajectory.tsx"; import { Transcript } from "../features/transcript/Transcript.tsx"; import { webStore } from "../store/web-store.ts"; export function App() { const state = useStore(webStore); const { t } = useTranslation(); const { actions } = state; const [view, setView] = useState<"chat" | "trajectory">("chat"); const [inspection, setInspection] = useState(null); const currentModel = state.snapshot?.models.find((model) => model.current); const modelKey = JSON.stringify([currentModel?.provider, currentModel?.id]); const inspect = (terminalId?: string) => { const snapshot = state.snapshot; const session = snapshot?.selectedSession; if ( !snapshot || !session || state.sessionSwitching || session.id !== snapshot.currentSessionId ) return; setInspection({ sessionId: session.id, sessionPath: session.path, cwd: session.cwd, model: currentModel?.label ?? "", modelKey, terminalId, }); }; const inspectionVisible = inspection && !state.sessionSwitching && inspection.sessionId === state.snapshot?.currentSessionId && inspection.sessionPath === state.snapshot?.selectedSession?.path && inspection.modelKey === modelKey; useEffect(() => { if (inspection && !inspectionVisible) setInspection(null); }, [inspection, inspectionVisible]); useEffect(() => { actions.start(); return actions.stop; }, [actions]); const selected = state.snapshot?.selectedSession; const hasMessages = selected?.entries.some( (entry) => entry.type === "message" && entry.message, ) || state.liveMessages.length > 0; const landing = !selected || !hasMessages; const resend = useCallback( (content: string) => actions.sendPrompt(content), [actions], ); return (
{state.sidebarCollapsed && ( )}

OpenPI

{t(state.connection)}
{state.snapshot?.selectedSession && (
)} {state.sessionSwitching ? (
{t("switchingSession")}
) : view === "trajectory" && state.snapshot?.selectedSession ? ( ) : landing ? (
) : state.snapshot ? ( ) : null} {state.notice && (
{state.notice}
)}
{inspectionVisible && ( setInspection(null)} /> )}
); }