/** * Type definitions for @geepers/chat */ type Provider = 'xai' | 'anthropic' | 'openai' | 'cohere' | 'mistral' | 'perplexity' | 'huggingface' | 'gemini' | 'ollama'; interface ProviderConfig { /** Model identifier string sent to the API Gateway */ model: string; /** Human-readable display label */ label: string; } type MessageRole = 'user' | 'assistant' | 'system'; interface Message { /** Unique message identifier */ id: string; /** Sender role */ role: MessageRole; /** Message text content */ content: string; /** Unix timestamp (ms) when message was created */ timestamp: number; /** Provider that generated this message (assistant only) */ provider?: Provider; } interface ConversationRecord { /** Unique conversation identifier (UUID v4) */ id: string; /** Title derived from first user message */ title: string; /** Ordered message history (excludes system prompt) */ messages: Message[]; /** Active provider when conversation was saved */ provider: Provider; /** System prompt for this conversation (may be empty) */ systemPrompt: string; /** Unix timestamp (ms) when conversation was created */ createdAt: number; /** Unix timestamp (ms) when conversation was last modified */ updatedAt: number; } type ChatEventType = 'message' | 'stream-chunk' | 'stream-start' | 'stream-end' | 'error' | 'conversation-change'; interface MessageEvent { type: 'message'; message: Message; } interface StreamChunkEvent { type: 'stream-chunk'; chunk: string; accumulated: string; messageId: string; } interface StreamStartEvent { type: 'stream-start'; messageId: string; } interface StreamEndEvent { type: 'stream-end'; message: Message; } interface ErrorEvent { type: 'error'; error: Error; } interface ConversationChangeEvent { type: 'conversation-change'; conversationId: string | null; } type ChatEvent = MessageEvent | StreamChunkEvent | StreamStartEvent | StreamEndEvent | ErrorEvent | ConversationChangeEvent; type ChatEventHandler = (event: T) => void; interface WelcomeHint { /** Short label shown on the hint chip button */ label: string; /** Full text sent as the message when the hint is clicked */ prompt: string; } type ThemeMode = 'light' | 'dark' | 'auto'; interface ChatConfig { /** * API Gateway base URL. * Defaults to 'https://api.dr.eamer.dev/v1' if not provided. */ gateway?: string; /** API key sent as X-API-Key header. Falls back to localStorage 'api_key' if not set. */ apiKey?: string; /** Initial provider selection. Defaults to 'xai'. */ provider?: Provider; /** Initial model override. If omitted the default from MODELS[provider] is used. */ model?: string; /** System prompt prepended to every conversation. */ systemPrompt?: string; /** Initial conversation ID to restore. Loads from localStorage if found. */ conversationId?: string; /** Theme preference. Defaults to 'auto' (respects OS preference). */ theme?: ThemeMode; /** * Hint chips shown on the welcome screen. * Pass an empty array to disable the welcome screen entirely. */ welcomeHints?: WelcomeHint[]; /** * localStorage key prefix for conversation persistence. * Defaults to 'gchat_conversations'. Override to namespace multiple instances. */ storageKey?: string; /** Called when an assistant message finishes streaming. */ onMessage?: (message: Message) => void; /** Called when an error occurs (network, API, or parsing). */ onError?: (error: Error) => void; /** Called immediately when a stream begins. */ onStreamStart?: (messageId: string) => void; /** Called when a stream finishes (including aborted streams). */ onStreamEnd?: (message: Message) => void; } /** * ChatCore — Headless chat state controller for @geepers/chat * * Manages conversation state, localStorage persistence, and SSE streaming. * Emits typed events so any UI layer (or no UI at all) can consume state changes. * * Uses the package's internal SSE client for actual streaming; this class * handles state, persistence, and orchestration. */ declare class ChatCore { private config; private emitter; private sseClient; private storage; /** Current active provider */ private _provider; /** Current active model (can override per-provider default) */ private _model; /** System prompt for the current conversation */ private _systemPrompt; /** Ordered message history for the current conversation (excludes system) */ private _messages; /** ID of the current conversation (UUID) */ private _conversationId; /** Whether a stream is currently active */ private _isStreaming; /** AbortController for the current stream */ private _abortController; constructor(config?: ChatConfig); get provider(): Provider; get model(): string; get systemPrompt(): string; get messages(): Readonly; get conversationId(): string | null; get isStreaming(): boolean; on(type: ChatEventType, handler: ChatEventHandler): void; off(type: ChatEventType, handler: ChatEventHandler): void; setProvider(provider: string): void; setModel(model: string): void; setSystemPrompt(prompt: string): void; setApiKey(key: string): void; /** * Send a user message and stream the assistant response. * Rejects if a stream is already active. */ send(content: string): Promise; /** * Abort the current stream. The partial assistant response is kept. */ stop(): void; /** * Clear messages and start a fresh conversation with a new UUID. * Saves the current conversation before clearing if it has messages. */ clearHistory(): void; /** * Load a saved conversation by ID. * Saves the current conversation first. */ loadConversation(id: string): boolean; /** * Return all saved conversations, sorted newest first. */ getConversations(): ConversationRecord[]; /** * Delete a saved conversation by ID. * If deleting the active conversation, starts a fresh one. */ deleteConversation(id: string): void; private _resolveApiKey; private _addMessage; private _saveCurrentConversation; } /** * ChatUI — DOM renderer for @geepers/chat * * Mounts a full chat interface into any container element. * Drives ChatCore for all state; pure DOM updates on events. * * Usage: * const chat = new ChatUI('#chat-container', { provider: 'xai' }); * // or: new ChatUI(document.getElementById('chat'), config); */ declare class ChatUI { private core; private container; private config; private root; private sidebar; private historyEl; private messagesEl; private textarea; private sendBtn; private stopBtn; private providerSelect; private providerBadge; private syspromptPanel; private syspromptInput; private overlayEl; private toastEl; private welcomeEl; private toastTimer; constructor(target: string | HTMLElement, config?: ChatConfig); get chatCore(): ChatCore; send(text: string): Promise; stop(): void; focus(): void; setProvider(provider: Provider): void; setSystemPrompt(prompt: string): void; newConversation(): void; destroy(): void; private static stylesInjected; private static injectStyles; private buildDOM; private wireEvents; private appendMessage; private appendLoadingMessage; private updateStreamingMessage; private finalizeMessage; private showErrorMessage; private reRenderMessages; private showWelcome; private removeWelcome; private renderHistory; private addCodeCopyButtons; private submitMessage; private makeCopyBtn; private autoResize; private scrollToBottom; private toggleSidebar; private closeSidebar; private toast; private resolveTheme; } /** * Conversation persistence for @geepers/chat * localStorage-backed with max 20 conversations, sorted by updatedAt. */ declare class ConversationStorage { private readonly key; constructor(storageKey?: string); private read; private write; all(): ConversationRecord[]; get(id: string): ConversationRecord | undefined; save(record: ConversationRecord): void; delete(id: string): void; /** Create a new ConversationRecord from the given messages */ static build(id: string, messages: Message[], provider: Provider, systemPrompt: string): ConversationRecord; } /** * Provider configurations for @geepers/chat * * Model names match what the API Gateway (api-gateway/app.py) expects. * Sourced from Slate's MODELS constant and verified against the gateway. */ declare const MODELS: Record; /** Array of all valid provider keys, useful for validation and UI rendering */ declare const PROVIDER_KEYS: Provider[]; /** * Validate that a string is a known provider key. * Logs a console warning for unknown providers but does not throw. */ declare function isKnownProvider(value: string): value is Provider; /** * Get the model config for a provider, falling back to xai if unknown. */ declare function getProviderConfig(provider: string): ProviderConfig; export { type ChatConfig, ChatCore, type ChatEvent, type ChatEventHandler, type ChatEventType, ChatUI, type ConversationChangeEvent, type ConversationRecord, ConversationStorage, type ErrorEvent, MODELS, type Message, type MessageEvent, type MessageRole, PROVIDER_KEYS, type Provider, type ProviderConfig, type StreamChunkEvent, type StreamEndEvent, type StreamStartEvent, type ThemeMode, type WelcomeHint, ChatUI as default, getProviderConfig, isKnownProvider };