/** * Browser client for smrt-chat's streaming chat route — the consume side of * the SSE contract `createChatStreamHandler` serves (see `chat-stream.ts`, * which owns the wire contract and exports the encode side). * * This module is BROWSER-SAFE and dependency-free: it must not import the * server runtime (models, services, tool loop) or any workspace package, so * a static site can ship it without dragging server code into the bundle. It * is exported under the dedicated `@happyvertical/smrt-chat/client` subpath. * * POST {endpoint} * Authorization: Bearer (SMRT bearer = session id) * Content-Type: application/json * Body: { "messages": ChatClientMessage[], "session": SmrtChatSession? } * * Response: text/event-stream, events as `data: ` lines: * { "type": "token", "text": "..." } * { "type": "emotion", "name": "heart" } (reserved; v1 engine forwards * the model's inline cue as tokens) * { "type": "control", "command": {...} } (#1921 host-page control lane; * parsed, no client hook yet) * { "type": "done", "message": ChatStreamMessage } * { "type": "error", "error": "..." } * plus `: heartbeat` comment lines every ~15s, which clients must ignore. * * The server always terminates a turn with a `done` or `error` frame; a clean * close without one means an intermediary cut the stream (proxy idle timeout) * and is surfaced as an error rather than an empty success. * * The widget-facing types below are STRUCTURALLY identical to * `@happyvertical/animation`'s chat contract (`ChatBackend`, `ChatMessage`, * `ChatStreamHandlers`, `ChatSendHandle`), so an instance drops straight into * `createHappyChat({ backend })` without this package depending on the widget * library. `client.contract.ts` pins the other seam under `pnpm typecheck`: * every `ChatStreamEvent` the server can emit is assignable to * `ChatClientStreamFrame`. */ /** A rendered conversation message (the widget-side shape; all fields set). */ export interface ChatClientMessage { id: string; role: 'user' | 'assistant' | 'system'; content: string; createdAt: string; } /** Streaming callbacks for one assistant reply. */ export interface ChatClientStreamHandlers { /** A chunk of assistant text (may be words or partial words). */ onToken(text: string): void; /** An expression cue for the character (e.g. 'heart', 'wink'). */ onEmotion?(name: string): void; /** The reply is complete; `message` is the final assembled message. */ onDone(message: ChatClientMessage): void; onError(error: unknown): void; } export interface ChatClientSendHandle { cancel(): void; } /** * A conversation backend. `send` receives the FULL message history (latest * user message last) and streams the assistant reply through `handlers`. */ export interface ChatClientBackend { send(messages: ChatClientMessage[], handlers: ChatClientStreamHandlers): ChatClientSendHandle; } /** * Conversation identity, mirroring `ChatStreamSession` * (`VoiceGatewayTurnMetadata`) so a server route can bind the turn to an * AgentSession/persona. Mirrored rather than imported to keep this module * free of server imports; `client.test.ts` asserts the shapes stay aligned. */ export interface SmrtChatSession { tenantId?: string; actorProfileId?: string; chatRoomId?: string; threadId?: string; agentSessionId?: string; personaId?: string; voiceSessionId?: string; } export interface SmrtChatBackendOptions { /** Full URL of the streaming chat route. */ endpoint: string; /** SMRT bearer token (the session id). Omit for cookie/same-origin auth. */ token?: string; /** * fetch credentials mode (the `RequestCredentials` union, spelled out so * this module typechecks without the DOM lib). Cookie auth from a * cross-origin embed needs 'include' (pairs with the server's allow-listed * credentialed CORS, smrt #1861); the default is fetch's own 'same-origin'. */ credentials?: 'omit' | 'same-origin' | 'include'; /** Conversation identity (persona/agent-session binding). */ session?: SmrtChatSession; fetchImpl?: typeof fetch; } /** * One parsed wire frame. Deliberately lenient where the client can degrade * (optional `message`/`error`) — and provably a superset of the server's * `ChatStreamEvent` union (compile-time lock in `client.test.ts`). */ export type ChatClientStreamFrame = { type: 'token'; text: string; } | { type: 'emotion'; name: string; } | { type: 'control'; command: unknown; } | { type: 'done'; message?: { id?: string; role: ChatClientMessage['role']; content: string; createdAt?: string; }; } | { type: 'error'; error?: string; }; /** * SSE client for the streaming chat route (smrt-chat #1936). Structurally * implements `@happyvertical/animation`'s `ChatBackend`, so it plugs straight * into the floating chat widget. */ export declare class SmrtChatBackend implements ChatClientBackend { private options; constructor(options: SmrtChatBackendOptions); send(messages: ChatClientMessage[], handlers: ChatClientStreamHandlers): ChatClientSendHandle; } //# sourceMappingURL=client.d.ts.map