import { EmbeddableChat } from 'officerdev'; /** * A chat, sitting under the two lists. * * ── Why this exists instead of naming `officerdev/chat` in the layout ── * * It was tried, and it produced two Hosts panels. `PluginScreen` renders the workspace with * `appTypes={{ allowed, fallback: allowed[0] }}` where `allowed` is **this plugin's own panel keys**, so a * layout naming anything else silently falls back to the first one. That is deliberate and its comment * says why: a persisted layout must not be able to render another plugin's panel inside this screen. * * The registry being shared is a separate thing from the layout being allowed to name what is in it. Both * are true; only the second one decides this. * * So the panel is ours and the chat inside it is the platform's. `EmbeddableChat` is exported from * `officerdev` for precisely this — the whole composer, transcript, queue and model picker, with no second * implementation to fall behind the first. * * ── The prefix ── * * `promptPrefix` is described in `ChatPanelWrapper` as "a system prompt only this app understands". It is * per-panel rather than per-session-wide, so it costs nothing to anybody else's conversation. * * Kept to two sentences on purpose. The Proxy Manager SKILL carries the real knowledge and reaches every * conversation on the machine at a cost of two lines; this only says where the agent is standing, which is * the one thing the skill cannot know. Anything longer would be the skill written twice, and the copy here * would be the stale one. */ const PREFIX = [ 'This chat is a panel on the Proxy Manager screen, beside a list of this machine’s proxy hosts and a list', 'of its TLS certificates. Questions about domains, forwarding, whether a site is up, or when a certificate', 'expires are about THIS machine — read the Proxy Manager skill before answering one.', ].join(' '); /** * The wrapper is not decoration. `EmbeddableChat` is handed `flex-1 min-h-0`, which needs a flex COLUMN * with a real height above it — without one the composer floats mid-panel and the transcript overflows * below the fold, which is exactly what shipping it bare produced. `ChatPanelWrapper` has the same div for * the same reason. */ export const ChatPanel = ({ panelId }: { panelId: string }) => (