import { default as React } from 'react'; export type ChatRole = "user" | "assistant"; export interface ChatSourceData { id: string; label: string; href: string; } export interface ChatMessageData { id: string; role: ChatRole; /** Rendered as-is: plain text while streaming, rich markup when done. */ content: React.ReactNode; /** Plain-text mirror of `content`, used to build the history for onSend. */ text?: string; sources?: ChatSourceData[]; } export interface ChatHistoryEntry { role: ChatRole; content: string; } export interface ChatSendContext { /** Aborted by reset() and on unmount; pass it to fetch. */ signal: AbortSignal; /** The conversation before this question, oldest first. */ history: ChatHistoryEntry[]; /** * Creates the assistant reply on the first call and patches the same * message on every later call, so streaming updates one bubble and the * typing indicator stays put until real content arrives. */ setAssistant: (content: React.ReactNode, options?: { text?: string; sources?: ChatSourceData[]; }) => void; } /** * The transport, supplied by the app: take the question, talk to a server * however you like, and stream the reply through `setAssistant`. A thrown * error lands in `error`; an abort is swallowed. */ export type ChatSendHandler = (question: string, context: ChatSendContext) => void | Promise; interface ChatContextValue { isOpen: boolean; open: (returnFocusTo?: HTMLElement | null) => void; close: (restoreFocus?: boolean) => HTMLElement | null; toggle: () => void; messages: ChatMessageData[]; input: string; setInput: (value: string) => void; loading: boolean; error: string | null; /** Sends `text`, or the current input when omitted. No-op while loading. */ send: (text?: string) => void; /** * Opens the panel and hands `question` to the assistant. While a reply is * still streaming the question is pre-filled instead, ready to send. */ ask: (question: string, returnFocusTo?: HTMLElement | null) => void; /** Aborts any in-flight reply and restores the initial greeting. */ reset: () => void; inputRef: React.RefObject; } declare const ChatContext: React.Context; declare function useChat(): ChatContextValue; export interface ChatProviderProps { children: React.ReactNode; /** * The transport. Optional when $showcase is on, where the commands can * carry a demo by themselves; required for real answers. */ onSend?: ChatSendHandler; /** Assistant message seeded on first open and after reset. Pass null for none. */ greeting?: React.ReactNode; /** How many prior messages the history handed to onSend may contain. */ historyLimit?: number; /** Cmd/Ctrl + this key toggles the panel. Pass null to disable. */ shortcut?: string | null; /** * Demo mode: chat input matching a showcase command ("help", "list", * "callout", …) is answered locally with a live rendering of that element * instead of going to onSend. Anything else still goes to the transport. */ $showcase?: boolean; } declare function ChatProvider({ children, onSend, greeting, historyLimit, shortcut, $showcase, }: ChatProviderProps): React.JSX.Element; export { ChatContext, ChatProvider, useChat };