import type { FetchChunksFunction, HistoricalMessage, MessageProcessingOptions, MessageSegment, NatsMessageType } from '../types'; import type { DialogTokenUsage, UnifiedChatState, UnifiedChatMessage } from '../types/unified-chat-state.types'; import type { DialogItem } from '../types/component.types'; export { appendToTrailingAssistant, applyToolExecutionToMessages, upsertTrailingCompaction, } from '../stream/message-mutations'; /** Page-fetch parameters passed to `fetchDialogs`. The adapter owns the * cursor — the host only resolves it against the backend. */ export interface FetchDialogsParams { cursor?: string; limit?: number; search?: string; } /** Successful `fetchDialogs` response. `nextCursor: null` means "no more * pages" — used to terminate the infinite-scroll observer in the * sidebar. */ export interface FetchDialogsResult { dialogs: DialogItem[]; nextCursor: string | null; } /** Page-fetch parameters passed to `fetchDialogMessages`. */ export interface FetchDialogMessagesParams { dialogId: string; cursor?: string; limit?: number; } /** Successful `fetchDialogMessages` response. `tokenUsage` is optional — * some backends only attach it to the dialog header query, in which case * hosts can either include it on the first page only (will populate the * ModelDisplay readout) or fold it in via a separate update path. */ export interface FetchDialogMessagesResult { messages: HistoricalMessage[]; nextCursor: string | null; tokenUsage?: DialogTokenUsage | null; } /** * Consumer-supplied configuration for the NATS chat adapter. * * Every field except `getNatsWsUrl` + `publishUserMessage` is optional — * the lib does not assume a particular backend protocol or auth scheme. * Hosts wire these up against their own OpenFrame deployment. */ export interface UseNatsChatAdapterConfig { /** * Active conversation/dialog id. When omitted (`undefined`) the * adapter manages its own active dialog id internally — the host * drives selection through `selectDialog` / `startNewDialog`. When * explicitly set (including `null`) the adapter treats this as * controlled mode and uses the value verbatim. v0 consumers (the * Tauri Fae Chat client) pass an explicit id here and own the * lifecycle externally; v1+ consumers (the openframe-frontend * EmbeddableChat) leave it undefined and rely on `fetchDialogs` * for sidebar-driven selection. */ dialogId?: string | null; /** * Build the NATS WebSocket URL. Returning `null` short-circuits the * subscription — same contract as `useNatsDialogSubscription`. */ getNatsWsUrl: () => string | null; /** * Optional NATS client auth. */ clientConfig?: { name?: string; user?: string; pass?: string; }; /** * Send a user message upstream. Consumer-owned: typically an * authenticated HTTP POST to the OpenFrame chat endpoint, or a * direct NATS publish to a dedicated subject. * * The adapter does NOT couple to the wire format — it only: * 1. appends the user message to local state for immediate render * 2. flips streamingPhase to 'thinking' so the input UI shows status * 3. calls this callback * * Reply arrives asynchronously as NATS chunks via the live tail and * is accumulated into the trailing assistant message. */ publishUserMessage: (text: string, options: { hidden?: boolean; dialogId: string | null; }) => Promise | void; /** * Historical-chunk fetcher used by `useChunkCatchup` to back-fill * events that happened while the user was in another mode or before * the websocket came online. Consumer-owned: typically a REST GET * against the OpenFrame chat-history endpoint. * * When omitted, `useChunkCatchup` falls back to its own default * fetch implementation — see hook docs for the contract. */ fetchChunks?: FetchChunksFunction; /** * NATS topics to live-tail for the active dialog. Each maps to the * subject suffix `chat.{dialogId}.{topic}` (see * `useNatsDialogSubscription`). Defaults to `['message']` — the * client-chat subject the Tauri Fae Chat consumer relies on. Admin / * Mingo chat publishes its agent replies on `'admin-message'`, so the * openframe EmbeddableChat host MUST set `topics: ['admin-message']` * here — otherwise the subscription tails the wrong subject, no reply * chunks ever arrive, and the assistant placeholder hangs forever in * the `thinking` phase. */ topics?: NatsMessageType[]; /** * Mirrors the reducer's `batchApprovalsEnabled`. Default `true` — * single batch card per APPROVAL_REQUEST with `toolCalls[]`. Set * `false` to fall back to legacy per-tool cards. */ batchApprovalsEnabled?: boolean; /** * Approval types rendered as actionable cards inline. Mirrors the * reducer's `displayApprovalTypes` (default `['CLIENT']`) and is * forwarded to the history processor so both paths agree. Hosts whose * backend emits other types (e.g. `USER`) MUST set this — otherwise * those approvals are escalated to a callback this adapter doesn't * surface and the card never renders. */ displayApprovalTypes?: string[]; /** * Fetch a paginated page of dialogs for the sidebar. When provided, * the adapter switches to managed-dialog mode: it owns the active * dialog id, the dialog list, and pagination state. When omitted, * the adapter operates in bare-transport mode (current Tauri Fae * Chat usage) and the sidebar fields on the return value stay empty. */ fetchDialogs?: (params: FetchDialogsParams) => Promise; /** * Fetch a page of historical messages for a dialog. Required for * sidebar-driven dialog switching — when omitted, selecting a * dialog brings up an empty thread until streaming starts. * * Messages must arrive in the same wire shape the openframe backend * emits (HistoricalMessage with messageData[]); the adapter feeds * them through `processHistoricalMessagesWithErrors` to produce * reducer-compatible messages. */ fetchDialogMessages?: (params: FetchDialogMessagesParams) => Promise; /** * Allocate a fresh dialog on the backend. Returns the new dialog id * which the adapter sets as the active dialog. When omitted, the * "Start new chat" affordance on the sidebar is hidden (or the host * can implement its own). */ createDialog?: () => Promise<{ dialogId: string; }>; /** Delete a dialog from history. When omitted, the sidebar item's * delete affordance is hidden. */ deleteDialog?: (dialogId: string) => Promise; /** Rename a dialog on the backend. When omitted, the "Rename" affordance * in the chat-history row menu is hidden. */ renameDialog?: (dialogId: string, title: string) => Promise; /** Archive a dialog on the backend (removes it from the active list). * When omitted, the "Archive" affordance in the row menu is hidden. */ archiveDialog?: (dialogId: string) => Promise; /** Fetch a paginated page of ARCHIVED dialogs for the Chat Archive page. * When omitted, the archive (clock-history) button in the header is * hidden. Same page/cursor contract as `fetchDialogs`. */ fetchArchivedDialogs?: (params: FetchDialogsParams) => Promise; /** Restore an archived dialog back to the active list. When omitted, the * restore (refresh) button in an archived chat's header is hidden. */ unarchiveDialog?: (dialogId: string) => Promise; /** * Approve a pending tool-call request. Wired into the reducer's * approval-card callbacks so card buttons fire this directly. When * omitted, approval cards render disabled buttons. */ approveRequest?: (requestId: string) => Promise; /** Reject counterpart of `approveRequest`. */ rejectRequest?: (requestId: string, reason?: string) => Promise; /** * Cancel in-flight assistant generation. Without this, `stopMessage` * only flips the UI status — the backend continues until the agent * finishes naturally. With this, the backend stops emitting chunks. */ stopGeneration?: (dialogId: string) => Promise; /** Display name for the assistant in historical messages — defaults * to `'Mingo'`. */ assistantName?: string; /** * GraphQL `chatType` discriminator to filter historical messages by. * When set, `processHistoricalMessagesWithErrors` skips messages * whose `chatType` doesn't match. Openframe-frontend uses * `'ADMIN_AI_CHAT'` here. */ chatTypeFilter?: string; /** Default page size for dialog list pagination. Defaults to 20. */ dialogsPageSize?: number; /** Default page size for message history pagination. Defaults to 50. */ messagesPageSize?: number; /** * Baseline model display for the composer's `` — used as the * empty-state fallback before any streaming `metadata` frame arrives (e.g. * a brand-new chat). The host typically sources these from its AI-config * endpoint. Live `metadata` frames refine them per-turn. NATS-only; SSE * (guide) derives its own model from the stream. */ modelProvider?: string | null; modelLabel?: string | null; } /** * Per-call options for `useNatsChatAdapter`. Carries only the * activation gate — config travels through the config object so it * survives mode swaps without re-mounting. */ export interface UseNatsChatAdapterOptions { /** * When `false` the adapter goes idle: no NATS subscription, no * catchup fetch, no publish. Local message state is preserved so * the user sees their history when the mode flips back to active. * Default `true`. */ active?: boolean; } /** * Map `ProcessedMessage` (lib's historical-message format) into * `UnifiedChatMessage` (the unified-chat-state contract). Only `user` * and `assistant` roles round-trip; `error` is dropped on the floor * here because the unified contract surfaces errors as banners, not * inline messages. (Hosts that need inline error bubbles can extend * the contract later.) * * Exported for host reuse (e.g. scripted marketing demos that rehydrate a * stored `HistoricalMessage[]` via `processHistoricalMessagesWithErrors` and * feed a `previewMode` EmbeddableChat). This mapper carries the segment/content * shape only; author identity (name/avatar/authorType/timestamp) that a host * needs for the demo is re-attached by the host from the same processed rows. */ export declare function mapProcessedToUnified(processed: Array<{ id: string; role: 'user' | 'assistant' | 'error'; content: string | MessageSegment[]; name?: string; }>): UnifiedChatMessage[]; /** * ONE-CALL `HistoricalMessage[]` -> `UnifiedChatMessage[]` for hosts replaying a * stored conversation outside the live adapter (scripted marketing demos, a * `previewMode` EmbeddableChat). Does the full pipeline the adapter does inline: * `processHistoricalMessagesWithErrors` -> `mapProcessedToUnified` -> re-attach * the author identity (name / avatar / authorType / timestamp) the segment * mapper drops. Hosts no longer hand-roll the two-step + re-attach. */ export declare function historicalToUnified(messages: HistoricalMessage[], options?: MessageProcessingOptions): UnifiedChatMessage[]; export declare function useNatsChatAdapter(config: UseNatsChatAdapterConfig, options?: UseNatsChatAdapterOptions): UnifiedChatState; //# sourceMappingURL=use-nats-chat-adapter.d.ts.map