import { useContext, useEffect, useState } from "react"; import Row from "@moduletrace/twui/layout/Row"; import Stack from "@moduletrace/twui/layout/Stack"; import H1 from "@moduletrace/twui/layout/H1"; import Span from "@moduletrace/twui/layout/Span"; import Button from "@moduletrace/twui/layout/Button"; import Dropdown from "@moduletrace/twui/elements/Dropdown"; import useStatus from "@moduletrace/twui/hooks/useStatus"; import { CpuAi, EllipsisVertical, Monitor } from "lucide-react"; import type { BUN_SQLITE_COBBLE_WORKSPACES } from "@/db/types/db"; import type { BotTextModel, BotWithLastMessage } from "@/src/types"; import { AppContext } from "@/src/pages/__root"; import WorkspaceAvatar from "@/src/components/general/workspace-avatar"; import RailDrawerButton from "@/src/layouts/bots/(partials)/rail-drawer-button"; import { BotComputersContext } from "../(data)/bot-computers-context"; import BotProfileModal from "./bot-profile-modal"; import ConversationHeaderMenu from "./conversation-header-menu"; import HeaderMetaItem from "./header-meta-item"; import BackButton from "@/src/components/general/back-button"; import AdminShield from "@/src/components/general/admin-shield"; type Props = { bot: BotWithLastMessage; /** * The workspace the conversation is in: its name shows under the * bot's, and the models modal edits its models. */ workspace?: BUN_SQLITE_COBBLE_WORKSPACES | null; has_other_unread?: boolean; /** * The text model the bot runs on, kept by the conversation (which * shows a notice while there's none). */ model?: BotTextModel | null; onModelChange: (model: BotTextModel | null) => void; }; /** * 64px header. Under the name, what the bot runs on: its model and the * computer it's on. On the right, one menu holding everything the header * used to show as icons: sessions, a new session, the computer, the models * and the bot's settings. Kept here so a save or a switch shows under the * name at once. */ export default function ConversationHeader({ bot, workspace, has_other_unread, model, onModelChange, }: Props) { const { computers } = useContext(BotComputersContext); const { pageProps } = useContext(AppContext); /** * The menu's toggle shows its change at once; a push (here or from * another tab) brings the live bot's. */ const [is_admin, setIsAdmin] = useState(Boolean(bot.is_admin)); useEffect(() => { setIsAdmin(Boolean(bot.is_admin)); }, [bot.is_admin]); const { open: open_menu, setOpen: set_open_menu } = useStatus(); const computer = computers[0]; const computer_name = computer?.id ? computer.name || `Computer ${computer.id}` : null; const is_workspace = pageProps?.url?.pathname.includes(`/workspaces/`); return ( {is_workspace ? : null}

{bot.name}

{workspace?.id && is_admin ? ( ) : null}
{workspace?.id ? ( {workspace.name || "Workspace"} ) : null} {computer_name ? ( ) : null}
} > { const current = harnesses.find( (h) => h.harness == "text", )?.current; onModelChange( current ? { name: current.name, provider_name: current.provider_name, } : null, ); }} on_open={() => set_open_menu(false)} is_admin={is_admin} on_admin_changed={setIsAdmin} />
); }