import * as React$1 from 'react'; import { ReactNode, HTMLAttributes, ComponentProps } from 'react'; import { UIMessage, ChatTransport, ToolUIPart } from 'ai'; import * as react_jsx_runtime from 'react/jsx-runtime'; import * as class_variance_authority_types from 'class-variance-authority/types'; import { VariantProps } from 'class-variance-authority'; import * as DialogPrimitive from '@radix-ui/react-dialog'; import * as AvatarPrimitive from '@radix-ui/react-avatar'; import * as CollapsiblePrimitive from '@radix-ui/react-collapsible'; import { z } from 'zod'; /** * ChatWidget Configuration Types * * These types define all the configurable options for the ChatWidget component. * They match the structure used in the settings panel for easy integration with * a hosted service dashboard later. */ /** * Payload passed to `ChatWidgetProps.onFeedback` when a user rates an * assistant message via the thumbs control. */ interface FeedbackEvent { /** Id of the assistant message being rated. */ messageId: string; /** Active conversation id, if the conversation has one yet. */ conversationId?: string; /** Thumbs up or down. */ rating: 'up' | 'down'; /** Optional freeform reason (thumbs-down); omitted when the user gave none. */ reason?: string; } /** * Render function for a tool UI part. Receives the entire part so the * renderer can branch on `state` (input-streaming / output-available / * output-error) and on the input/output shapes. */ type ToolRenderer = (part: ToolPartLike) => ReactNode | null; /** Custom AI SDK data part. Payloads are untrusted until the host validates them. */ interface MessageDataPart { readonly type: `data-${string}`; readonly id?: string; readonly data: unknown; } /** Presentation context only; no identity, permissions, or tool execution authority. */ interface MessagePartRendererContext { readonly messageId: string; readonly role: 'system' | 'user' | 'assistant'; /** True only for the active assistant message while its stream is flowing. */ readonly isStreaming: boolean; } /** * Host-code-only render callback for custom data-* parts. Return null/undefined * to omit the part (the default); unknown data is never dumped into the UI. * Validate `part.data` before using it. Keep callbacks pure, synchronous and * SSR-safe; return a React component if you need hooks. Renderer errors follow * the host's React error boundary, just like toolRenderers. */ type MessagePartRenderer = (part: MessageDataPart, context: MessagePartRendererContext) => ReactNode | null; /** * Exact full part-type keys, e.g. 'data-account-lookup'. Built-in text, sources, * files, reasoning and tools cannot be overridden. data-follow-ups, * data-thread-title and data-chat-error are reserved widget metadata and are * not dispatched here. Transient events are not transcript parts. * Replace the map (rather than mutate it) when changing renderers. * Never put these functions in AgentConfig/published JSON/bootstrap payloads. */ type MessagePartRenderers = Readonly>>; /** * Outcome of an action, derived from the REAL tool output (never the model's * prose). Drives the card's icon + colour. 'partial' is the critical state for * false-completion prevention — the tool ran but didn't fully succeed. */ type ActionResultStatus = 'pending' | 'success' | 'partial' | 'error'; /** One key/value row shown on an action card (e.g. "Assignee" → "@alice"). */ interface ActionResultField { label: string; value: ReactNode; } /** * Structured description of what a tool actually did, rendered as an * `ActionResultCard`. Returned by an `ActionRenderer`. */ interface ActionResult { /** Real outcome — derive from the tool's output/state, not the model's claim. */ status: ActionResultStatus; /** Headline, e.g. "Ticket created" or "Couldn't update record". */ title: string; /** Key parameters / outcome rows (assignee, priority, id…). */ fields?: ActionResultField[]; /** Optional action link, e.g. `{ label: 'View in Linear', href }`. */ link?: { label: string; href: string; }; /** Optional freeform note or error detail under the fields. */ note?: ReactNode; } /** * Maps a tool part to a declarative `ActionResult` (or `null` to fall back to * the default tool row). Receives the same loose `ToolPartLike` as * `ToolRenderer`, so it can branch on `state`/`output` to report the true * outcome. */ type ActionRenderer = (part: ToolPartLike) => ActionResult | null; /** * Simplified message shape used by the server follow-up generator - no AI SDK * types to import. `content` is the concatenated text of the message's text * parts. */ interface FollowUpMessage { role: string; content: string; } /** * Loose shape of the tool parts the renderer will receive — covers * both static `ToolUIPart` and the dynamic-tool variant. Kept * loose so consumers don't have to import internal AI SDK types. */ interface ToolPartLike { /** Either `tool-` or `'dynamic-tool'`. */ type: string; /** Always present on dynamic-tool parts; sometimes absent on static. */ toolName?: string; toolCallId: string; /** * AI SDK v6 tool lifecycle. The `approval-*` and `output-denied` states cover * human-in-the-loop tools (`needsApproval`): the SDK pauses before `execute` * and emits `approval-requested`; the UI shows Approve/Deny, the response * moves it to `approval-responded`, then `output-available` (ran) or * `output-denied` (skipped). */ state: 'input-streaming' | 'input-available' | 'approval-requested' | 'approval-responded' | 'output-available' | 'output-error' | 'output-denied'; input?: unknown; output?: unknown; errorText?: string; /** * Present when `state === 'approval-requested'`: the approval to respond to. * `isAutomatic` true means a policy auto-approved it (no user prompt needed). */ approval?: { id: string; isAutomatic?: boolean; }; } /** * Item returned by an InputPlugin's fetch function. Renders as one row * in the popover. */ interface InputPluginItem { /** Stable id, used as the React key + passed back to onSelect. */ id: string; /** Primary line shown in the popover row. */ label: string; /** Optional muted second line (e.g. "8 holdings · USD"). */ sublabel?: string; } /** * Definition of a single trigger-driven autocomplete in the chat input. */ interface InputPlugin { /** * Unique id used for keying / debugging. Not user-visible. */ id: string; /** * Single character that opens the popover. Must be exactly one * character. Common picks: '@', '/', '#'. */ trigger: string; /** * Optional heading shown above results in the popover (e.g. "Mention", * "Commands"). When omitted, no heading. */ heading?: string; /** * Called with whatever the user has typed AFTER the trigger character * (empty string immediately after triggering). Should return the * matching items to render. The widget debounces calls; you don't * need to. */ fetch: (query: string) => Promise | InputPluginItem[]; /** * Called when the user picks an item. Returns the string to splice * into the input in place of the trigger + query span. Include any * trailing space the input should have after insertion. */ onSelect: (item: InputPluginItem) => string; /** * Optional empty-state copy when fetch returns zero results. * Defaults to "No results". */ emptyText?: string; } /** * Structured, per-turn context passed from the host app to the model (#162). * A plain JSON-serialisable object. Extend it with your own shape via the * `context` prop, e.g. `context={{ route: '/billing', plan: 'pro' } satisfies ChatContext}`. */ type ChatContext = Record; interface StarterPrompt { /** * The main text of the prompt (also used as the message when clicked) */ title: string; /** * Optional subtitle for additional context */ subtitle?: string; /** * Optional leading icon (e.g. a lucide icon element). Renders before the * title; most impactful in the `grid` starter-prompt layout where chips have * room for one. */ icon?: ReactNode; } /** * Theming is exactly three colors, all required. Every other color in the * widget is derived from these (see the ramp in ChatWidget). There is no * mode: light vs dark is simply which colors you pick. Omit `theme` entirely * to get the stock palette. If any value is not valid hex, the whole theme * is ignored — a theme is never half-applied. */ interface ThemeConfig { /** * Chat background color (hex, e.g. "#171717"). */ backgroundColor: string; /** * Body text color (hex). Must contrast with `backgroundColor` — the widget * renders what you declare and does not second-guess it. */ textColor: string; /** * Primary accent color (hex) — send button, links, focus states. */ primaryColor: string; } interface FeatureConfig { /** * Enable file uploads. When true, the input toolbar shows a paperclip * button and accepts files matching `fileUploadAccept`. */ fileUpload?: boolean; /** * Comma-separated `accept` filter passed to the file picker when * `fileUpload` is true. Mirrors the HTML input[type=file] `accept` * syntax (e.g. `"image/*,application/pdf,.csv"`). Defaults to * `"image/*"` for backwards compatibility — consumers serving more * file types should set this to whatever their server / model * actually accepts. */ fileUploadAccept?: string; /** * Per-file size cap in bytes. The file picker / drag-and-drop * surface rejects files above this size before any network call, * showing the consumer's onError hook. Should mirror whatever the * upload endpoint enforces server-side. When unset, no client-side * size check is applied. */ fileUploadMaxBytes?: number; /** * Enable web search */ webSearch?: boolean; /** * Voice dictation: a microphone button in the composer that turns speech * into text in the textbox (the user still edits and presses Send — * nothing is auto-sent). Uses the browser's built-in speech recognition, * so there is no server, key, or audio path through the host or mordn; * Chrome and Safari may send audio to Google/Apple speech services. The * button renders only where the browser supports the API (Chrome, Edge, * Safari; not Firefox by default). Defaults to `true`. */ voiceInput?: boolean; /** * BCP-47 language tag for dictation (e.g. `"en-GB"`, `"de"`). When * unset, the page's `` is used, then the browser language. */ voiceInputLanguage?: string; } /** * Size presets for the chat widget * Each preset uses clamp() for responsive sizing: * - compact: clamp(300px, 24vw, 400px) - sidebars, minimal footprint * - default: clamp(320px, 28vw, 500px) - balanced for most use cases * - large: clamp(400px, 35vw, 700px) - content-heavy conversations * - full: 100% - fills entire screen */ type ChatWidgetSize = 'compact' | 'default' | 'large' | 'full'; /** * Layout shape the widget renders in. * * - `popup` : floating side panel, opened by a toggle button (default). * Best for ambient assistance available across pages. * - `inline` : renders in place inside the parent element. No toggle button, * no fixed positioning, fills its container. Best for dashboard * cards or dedicated chat sections of a page. * - `page` : full-viewport layout with a conversation list sidebar on the * left and the active chat on the right. Best for a dedicated * chat route (e.g. `/chat`). * * The `popup` value is the historical default and remains backward compatible. */ type ChatWidgetLayout = 'popup' | 'inline' | 'page'; interface DisplayConfig { /** * How the widget renders. * Default: `'popup'` (backward compatible). */ layout?: ChatWidgetLayout; /** * Preset size for the widget (recommended) * Uses clamp() for responsive sizing with min/max bounds * Default: 'default' * * Note: `size` only applies in `popup` layout. `inline` and `page` layouts * fill their container regardless. */ size?: ChatWidgetSize; /** * Custom width override (any CSS value) * Examples: * - '400px' (fixed) * - '30vw' (viewport-relative) * - 'clamp(300px, 25vw, 500px)' (responsive with bounds) * Overrides the size preset if provided */ width?: string; /** * Enable drag-to-resize functionality * Default: true */ resizable?: boolean; /** * Initial state (open or closed) * Default: false */ defaultOpen?: boolean; /** * How starter prompts are laid out in the empty state. * - `'list'` (default): full-width rows, good for descriptive prompts with * subtitles. * - `'grid'`: a 2-column chip grid, good for short, scannable prompts * (optionally with an `icon`). */ starterPromptsLayout?: 'list' | 'grid'; /** * Show toggle button to open the chat * Default: true */ showToggleButton?: boolean; /** * Custom toggle button position */ toggleButtonPosition?: { bottom?: string; right?: string; }; /** * Open (toggle) the widget with a keyboard shortcut, so docs sites and * dashboards can wire an "Ask AI" affordance into their OWN chrome — nav * button, search bar, `/` command — without holding a `ChatWidgetHandle` * ref (#193). Also enables two other zero-JS/zero-ref open routes on the * same widget instance regardless of this setting: `data-mordn-chat-open` * / `-toggle` / `-close` attributes on any element (one delegated document * click listener, works from static/markdown-generated HTML), and a * `document` CustomEvent API (`mordn-chat:open` / `:close` / `:toggle`) — * the same thing a script-tag embed dispatches internally. See the README * section "Opening the widget from your site" for copy-pasteable examples * of all three. * * **Format**: a `+`-separated combo of modifier tokens and exactly one * key, matched against `KeyboardEvent.key` case-insensitively, e.g.: * - `"mod+k"` — the primary modifier + K * - `"mod+i"` — the primary modifier + I * - `"ctrl+shift+/"` — three tokens, last one is the key * - `"/"` — a single bare key, no modifier * * `"mod"` resolves at match time to `metaKey` on Mac (Cmd) and `ctrlKey` * everywhere else (Ctrl) — the conventional cross-platform "primary * modifier" token, same convention as most command-palette libraries. * Matching is an EXACT modifier-set match: `"mod+k"` does not also fire on * Cmd+Shift+K. * * **Recommended default for docs sites**: `"mod+i"`. `Cmd/Ctrl+K` has * become the de facto convention for "open search" (used by the doc site's * own search-bar shortcut in most themes); `Cmd/Ctrl+I` is the emerging * convention for "open AI chat" and won't fight the search shortcut for * the same key. * * **Typing and host shortcuts**: ALL combos, including modifier combos, * are ignored inside `input`, `textarea`, `select`, or `contenteditable` * surfaces (including descendants and `plaintext-only`). This intentionally * leaves editor shortcuts such as Cmd/Ctrl+I for italic alone. Previously, * only bare keys were suppressed while typing. Repeated/composing keydowns * and events already claimed with `preventDefault()` are also ignored. * A host can reserve a conflicting shortcut with `preventDefault()` before * it reaches the widget's window listener, or with `stopPropagation()`. * * **Explicit intent**: shortcuts and `data-mordn-chat-open` / `-toggle` * clicks can reopen a dismissed panel even when `allowAutoReopen` is false, * just like the launcher. Ref methods and `mordn-chat:*` CustomEvents remain * programmatic: opening still requires `allowAutoReopen`. All paths share * controlled-mode delegation and persistence; closing is always allowed. * * **Multi-instance**: if a page mounts more than one ``, a * matching shortcut/button/event fires ALL of them (no cross-instance * coordination) — fine for the common one-widget-per-page case; avoid * configuring the same shortcut on multiple simultaneously-mounted * instances if you don't want that. * * Default: `undefined` (off). There is no implicit shortcut — the widget * NEVER silently hijacks a host page's keybindings. Set `false` explicitly * to make "no shortcut" visible in code/diffs if you want that documented. */ keyboardShortcut?: string | false; } /** * Tiny declarative field schema + reader used by the canonical AgentConfig * contract (`src/config.ts`). * * WHY THIS EXISTS (and why it isn't zod): the config contract is consumed by * three repos and, more importantly, by MANY DEPLOYED VERSIONS of this package * at once. A field that the dashboard publishes today is read tomorrow by a * customer's server that was installed six weeks ago. The one property the * validator must therefore have is *forward tolerance*: a document that carries * a field this build has never heard of must still load. A hand-rolled engine * lets us make that guarantee structural — every validator in the package is * derived from ONE descriptor, and the read mode (strict vs tolerant) is a * parameter, so "strict here, tolerant there" can never drift. * * Two modes, one descriptor: * * • `strict` — the WRITER contract. Unknown keys and invalid values are * errors. Used where a document is authored or accepted for * storage (publish, preview trust boundary). Strictness at the * writer is what keeps typos and junk out of the store. * • `tolerant` — the READER contract. Unknown keys are DROPPED (recorded, not * fatal). An OPTIONAL known field whose value this build cannot * interpret (a new enum member, a changed shape) is DROPPED so * the schema default applies. Only a missing/invalid REQUIRED * field is fatal. Used by every runtime consumer: the customer's * handler, the hosted config fetcher, the browser bootstrap. * * The invariant this buys: within one `schemaVersion`, an OLDER reader can * always load a NEWER document (additive fields are ignored; new enum members * fall back to defaults). A change that would break that — removing a field, * changing a field's type or meaning, making an optional field required — is a * new `schemaVersion`. See docs/config-evolution.md. * * The reader always returns a NEW value containing only known, valid fields. * Callers never observe unknown keys, so downstream code cannot accidentally * depend on something the contract does not define. */ type Primitive = string | number | boolean; type ReadIssueCode = 'unknown_key' | 'invalid_value' | 'missing_required'; interface ReadIssue { /** Dotted path from the document root, e.g. `client.features.voiceInput`. */ path: string; code: ReadIssueCode; message: string; } type ReadResult = { ok: true; value: T; /** * Fields the reader ignored. Empty in strict mode (anything here would * have been an error). Non-empty in tolerant mode means "this document * was written by a newer schema than this build knows" — worth logging * once, never worth failing over. */ dropped: ReadIssue[]; } | { ok: false; issues: ReadIssue[]; }; interface FieldDescription { path: string; kind: string; required: boolean; since: string; description: string; default?: Primitive; enum?: Primitive[]; min?: number; max?: number; integer?: boolean; literal?: Primitive; } /** * THE schema descriptor for the canonical AgentConfig contract (schema v1). * * Everything that validates, describes, or defaults an agent configuration in * this package is derived from the field maps below — `isAgentConfig` (strict * writer), `readAgentConfig` / `readAgentBootstrap` (tolerant readers), * `resolveFeatures` (defaults), `describeAgentConfigSchema()` (the * machine-readable contract the compatibility gate snapshots). There is no * second list of keys anywhere. Adding a field is ONE entry here plus the * matching optional property on the TypeScript interface. * * GATES (they fail the build / the test suite, on purpose): * * 1. Every field map is declared `satisfies Record, Field>`. * Add a property to `FeatureConfig` without a descriptor entry → type * error. Add a descriptor entry without the property → type error. The * type and the contract cannot drift. * 2. `test/config-evolution.test.ts` snapshots `describeAgentConfigSchema()` * and diffs it against the baseline of the LAST RELEASE. Removing a field, * changing its kind, tightening a range, dropping an enum member, or * making an optional field required fails the suite — those are * schema-major changes and need a new `schemaVersion`, not a PR. * * RULES OF THE ROAD (full text in docs/config-evolution.md): * * • New fields are OPTIONAL and carry `since` + a `default` where one exists. * • A field's meaning never changes. Need different semantics? New field. * • Enum members may be ADDED (old readers drop the unknown value and apply * the default) but never removed or renamed. * • `required: true` is reserved for the envelope — fields no reader can * default. New required fields cannot be added to an existing object. */ /** Schema major. Bumps only for breaking changes (see module doc). */ declare const AGENT_CONFIG_SCHEMA_VERSION: 1; /** Independent of `schemaVersion`: transport shape and config schema evolve separately. */ declare const BOOTSTRAP_PROTOCOL_VERSION: 1; interface SerializableStarterPrompt { title: string; subtitle?: string; } interface SerializableFollowUpConfig { enabled?: boolean; max?: number; timeoutMs?: number; } interface SerializableTitleConfig { enabled?: boolean; timeoutMs?: number; } interface SerializableMemoryConfig { enabled: boolean; /** Inject recalled memories before generation. */ inject: boolean; /** Extract and store memories after a completed turn. */ extract: boolean; /** Maximum memories injected per turn. */ limit: number; } /** Managed workspace per verified user within an agent/tenant; absent means off. */ interface SerializableSandboxConfig { enabled: boolean; } interface AgentRuntimeConfig { model: string; systemPrompt?: string; temperature?: number; maxOutputTokens?: number; followUps?: boolean | SerializableFollowUpConfig; /** * Smart thread titles: a lightweight post-response model call names the * conversation after its first exchange. Default ON — pass `false` to keep * the first-message-prefix placeholder titles. */ titles?: boolean | SerializableTitleConfig; memory?: SerializableMemoryConfig; /** Enable sandboxes: Mordn-managed, shared across this user's conversations. */ sandbox?: SerializableSandboxConfig; } interface AgentClientConfig { greeting?: string; /** Faint line under the greeting headline (free display text). */ subGreeting?: string; /** The assistant's name (identity, not the greeting sub line). */ assistantName?: string; theme?: ThemeConfig; features?: FeatureConfig; display?: DisplayConfig; starterPrompts?: SerializableStarterPrompt[]; capabilitiesPrompt?: string; feedback?: boolean; streamingThrottleMs?: number; persistState?: boolean; allowAutoReopen?: boolean; } interface AgentConfig { schemaVersion: typeof AGENT_CONFIG_SCHEMA_VERSION; runtime: AgentRuntimeConfig; client: AgentClientConfig; } /** Hosted control-plane record consumed by the handler. */ interface PublishedAgentConfig { agent: string; revision: string; config: AgentConfig; } /** Browser-safe projection returned from GET /bootstrap. */ interface AgentBootstrap { protocolVersion: typeof BOOTSTRAP_PROTOCOL_VERSION; agent: string; revision: string; client: AgentClientConfig; storageScope: string; } /** * Read a complete schema-v1 config the way a RUNTIME must: fields this build * doesn't know are dropped and reported in `dropped`, never fatal. Fails only * on a wrong `schemaVersion` or a missing/invalid required field. Use in the * handler, the hosted config fetcher, and any other consumer of a published * document. The returned `value` contains only known, valid fields. */ declare function readAgentConfig(value: unknown): ReadResult; /** Tolerant reader for the browser-safe bootstrap envelope (see `readAgentConfig`). */ declare function readAgentBootstrap(value: unknown): ReadResult; /** * Validate the complete, strict schema-v1 config before it is authored, * stored, or trusted as a preview. Unknown keys are rejected — this is what * keeps typos and junk out of published revisions. Runtime consumers must use * `readAgentConfig` instead, or a newer dashboard will break older deployments. */ declare function isAgentConfig(value: unknown): value is AgentConfig; /** Strict validator for the bootstrap envelope. Browsers should prefer `readAgentBootstrap`. */ declare function isAgentBootstrap(value: unknown): value is AgentBootstrap; /** `FeatureConfig` with every defaulted flag resolved. */ interface ResolvedFeatureConfig { fileUpload: boolean; fileUploadAccept: string; fileUploadMaxBytes?: number; webSearch: boolean; voiceInput: boolean; voiceInputLanguage?: string; } /** Feature defaults, sourced from the descriptor — the single place they live. */ declare const DEFAULT_FEATURES: ResolvedFeatureConfig; /** * Apply schema defaults to a (possibly partial or absent) `features` object. * Consumers read flags from the result instead of sprinkling `=== true` / * `?? 'image/*'` fallbacks through UI code, so a default changes in one place. */ declare function resolveFeatures(features?: FeatureConfig | null): ResolvedFeatureConfig; /** * Machine-readable description of the whole contract: every path with its * kind, requiredness, `since`, default and constraints. The compatibility gate * (`test/config-evolution.test.ts`) snapshots this and diffs it against the * last release; dashboards and docs can render it directly. */ declare function describeAgentConfigSchema(): { schemaVersion: 1; bootstrapProtocolVersion: 1; config: FieldDescription[]; bootstrap: FieldDescription[]; }; /** One-line summary of read issues for error messages and logs. */ declare function formatConfigIssues(issues: readonly ReadIssue[]): string; interface ChatWidgetProps { /** Full canonical config for caller overrides or an authenticated preview. */ config?: AgentConfig; /** Handler mount. The widget calls `${apiBase}/bootstrap` on mount. */ apiBase?: string; /** Generic transport headers (for example a host's CSRF token). */ headers?: Record; requestCredentials?: RequestCredentials; /** * HOSTED RUNTIME MODE — for apps with no server route (Vite/Lovable/Bolt, * Supabase-backed SPAs). Pass the agent's publishable key (`pk_live_…`, from * the dashboard or the mordn MCP server) and the widget talks to * `api.mordn.com/v1/hosted/` directly instead of `apiBase`. The key is * public by design: it selects the agent and grants nothing on its own — the * hosted runtime enforces the agent's origin allowlist and verifies the end * user from `getUserToken`. Mutually exclusive with `apiBase`. */ publishableKey?: string; /** * Hosted mode only: returns the signed-in user's access token from the app's * identity provider (e.g. Supabase `session.access_token`, Clerk `getToken()`), * or `null` when nobody is signed in. Sent as `Authorization: Bearer …` and * verified server-side against the agent's configured JWKS — the browser * never asserts an id, it only presents a token somebody else signed. * Re-resolved every few minutes so expiring tokens stay fresh. Callback * identity is ignored; signal login/logout/account switches with * `authSessionKey` or the ref's `resetAuth()` after updating your session. */ getUserToken?: () => Promise | string | null | undefined; /** * Hosted mode only: local auth lifecycle marker (e.g. an incrementing counter). * Change on login, logout, or account switch to drop stale auth and mounted * chat state before resolving the new token. NOT identity: never sent to the * server or used as a storage scope. Stable across same-session token refreshes. */ authSessionKey?: string | number | null; /** * Hosted mode only: allow unauthenticated visitors. When no token is * available the widget sends a persisted random visitor id instead, and the * runtime scopes history to it as an explicitly anonymous (`anon:`) user. * Only takes effect when the agent's hosted settings also allow anonymous * visitors. Default false. */ anonymous?: boolean; /** Hosted mode only: API origin override for a self-hosted chat-api. Default `https://api.mordn.com`. */ hostedBaseUrl?: string; className?: string; conversationId?: string; initialMessages?: any[]; /** * Per-turn context (#162, #239): a static object, `'auto'` for the built-in * safe page capture, or a function resolved fresh at send time. See * `buildAutoPageContext` for opting into richer capture. Untrusted * server-side until the handler opts in via `getContext` / * `trustClientContext`. */ context?: ChatContext | 'auto' | (() => ChatContext | Promise); getStarterPrompts?: () => StarterPrompt[] | Promise; onClose?: () => void; open?: boolean; onOpenChange?: (open: boolean) => void; onStateChange?: (open: boolean) => void; headerActions?: ReactNode; inputPlugins?: InputPlugin[]; toolRenderers?: Record; actionRenderers?: Record; /** Host React code only: render custom data-* parts, never published JSON config. */ messagePartRenderers?: MessagePartRenderers; onFeedback?: (feedback: FeedbackEvent) => void; /** * Host-supplied colors, applied LIVE: change this prop (e.g. when the host * app flips light/dark, or a user picks a brand palette) and the open panel, * launcher and portalled menus repaint in place — no remount, no lost * conversation, no new bootstrap. Same three-hex contract as the published * `client.theme` (invalid or partial themes are ignored whole). * * Precedence: this prop > `config.client.theme` > the published theme from * `/bootstrap`. `undefined` defers to those sources; `null` forces the stock * palette even when a theme is published. * * Presentation only: it is never sent to the server and never enters * `AgentConfig`, so a host can theme the widget without authoring a full * config document. */ theme?: ThemeConfig | null; } /** * Imperative handle exposed via a ref on ``. Lets the host app * drive the popup panel programmatically. Opening is gated by * `config.client.allowAutoReopen` so a dismissed panel is never * re-surfaced without explicit opt-in; closing is always allowed. Only * meaningful in the `popup` layout (inline/page are always-open surfaces). * `resetAuth()` applies to hosted mode in every layout. */ interface ChatWidgetHandle { /** Open the panel. No-op unless `allowAutoReopen` is set. */ open: () => void; /** Close the panel. Always allowed. */ close: () => void; /** Toggle the panel. Opening obeys the same `allowAutoReopen` gate as `open()`. */ toggle: () => void; /** Whether the panel is currently open. */ readonly isOpen: boolean; /** * Hosted mode only: drop auth/bootstrap/mounted chat state and resolve the * latest getUserToken again. Call AFTER updating the host's session source. * Equivalent to changing authSessionKey; does not erase persisted chat data. */ resetAuth: () => void; } declare const ChatWidget: React$1.ForwardRefExoticComponent>; /** Browser-safe, versioned error contract. Never add provider payloads, messages, * codes, stacks or causes here. Metadata is a UI hint, NOT server authorization * or permission to replay a request (tools may already have had side effects). */ declare const CHAT_ERROR_VERSION: 1; declare const CHAT_ERROR_DATA_TYPE: "data-chat-error"; /** JSON metadata in a header preserves the existing HTTP status and body. */ declare const CHAT_ERROR_HEADER = "x-chat-error"; type ChatErrorKind = 'abort' | 'rate_limit' | 'auth' | 'transient' | 'content_policy' | 'prompt' | 'model' | 'tool' | 'unknown'; interface ChatErrorMetadata { version: typeof CHAT_ERROR_VERSION; kind: ChatErrorKind; retryable: boolean; retryAfterMs?: number; /** Opaque correlation reference, not user-facing copy or a URL. */ traceId?: string; } declare function messageForErrorKind(kind: ChatErrorKind): string; /** Fail closed on unknown versions/kinds and malformed core fields. Return a * fresh allowlisted projection, never spread untrusted data into an Error/DOM. * Optional invalid hints are dropped. Contradictory retry hints cannot enable * retries for auth/policy/tool/etc. No caller should use this as server policy. */ declare function parseChatErrorMetadata(value: unknown): ChatErrorMetadata | undefined; declare function parseChatErrorHeader(value: string | null): ChatErrorMetadata | undefined; interface ErrorRecovery { readonly metadata: Readonly; /** Absolute deadline captured on receipt, so re-renders/tab switches do not * restart a server-specified wait. Never schedules a network request. */ readonly retryAt?: number; } declare function getChatErrorRecovery(error: Error | null | undefined): ErrorRecovery | undefined; /** Use wrapTransport for a Chat: recovery must belong to each response stream, * not to a Chat-wide callback slot. A stopped response can still have queued * callbacks after the next request begins, and aborts skip the SDK onError hook. * The low-level onData/onError pair is only for a single, isolated stream. * Nothing is persisted in message parts or automatically retried. */ declare function createChatErrorRecovery(): { reset: () => void; /** Preserve the transport's method receiver and SDK request signatures. Each * send/reconnect has its own accumulator, including overlapping responses. */ wrapTransport(transport: ChatTransport): ChatTransport; onData(part: unknown): void; onError(error: Error): void; /** DefaultChatTransport fetch seam. Non-OK HTTP bodies remain untouched for * old servers. New-server metadata yields an Error with package-owned copy; * no arbitrary HTTP body/provider secret is promoted to a UI message. */ fetch: (input: RequestInfo | URL, init?: RequestInit) => Promise; }; interface ChatStorageContextValue { /** * Prefix for browser-stored chat keys, derived only from the opaque scope in * the authenticated bootstrap response. `null` disables persistence. */ storageKeyPrefix: string | null; } declare function ChatStorageProvider({ children, storageScope, }: { children: ReactNode; /** Opaque, server-issued scope from the authenticated bootstrap response. */ storageScope?: string | null; }): react_jsx_runtime.JSX.Element; declare function useChatStorageKey(): ChatStorageContextValue; /** * Remove chat data this widget persisted in the browser. Call this on sign-out * / user switch so a subsequent user on the same browser can never see the * previous user's conversation tabs, titles, prompts, or model. * * - No args → clears every `chat-*` key (safe blanket sign-out clear). * - `{ storageScope }` → clears only keys for that server-issued opaque scope. * * Sweeps BOTH localStorage (tabs, panel state) and sessionStorage (per-tab * composer drafts) — the same key scheme is used in both. */ declare function clearChatStorage(opts?: { storageScope?: string; }): void; declare const buttonVariants: (props?: ({ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined; size?: "default" | "sm" | "lg" | "icon" | null | undefined; } & class_variance_authority_types.ClassProp) | undefined) => string; declare function Button({ className, variant, size, asChild, ...props }: React$1.ComponentProps<"button"> & VariantProps & { asChild?: boolean; }): react_jsx_runtime.JSX.Element; interface InputProps extends React$1.InputHTMLAttributes { } declare const Input: React$1.ForwardRefExoticComponent>; declare function Dialog({ ...props }: React$1.ComponentProps): react_jsx_runtime.JSX.Element; declare function DialogContent({ className, children, showCloseButton, ...props }: React$1.ComponentProps & { showCloseButton?: boolean; }): react_jsx_runtime.JSX.Element; declare function DialogHeader({ className, ...props }: React$1.ComponentProps<"div">): react_jsx_runtime.JSX.Element; declare function DialogTitle({ className, ...props }: React$1.ComponentProps): react_jsx_runtime.JSX.Element; declare function DialogDescription({ className, ...props }: React$1.ComponentProps): react_jsx_runtime.JSX.Element; type StarterMessagesLayout = 'list' | 'grid'; type StarterMessagesProps = Omit, 'onSelect'> & { prompts: StarterPrompt[]; onPromptSelect: (prompt: StarterPrompt) => void; /** * How prompts are laid out. * - `'list'` (default): spaced, full-width bordered cards — good for * descriptive prompts, optionally with a subtitle. * - `'grid'`: a 2-column chip grid — good for short, scannable prompts, * optionally with an icon. */ layout?: StarterMessagesLayout; }; declare function StarterMessages({ className, prompts, onPromptSelect, layout, ...props }: StarterMessagesProps): react_jsx_runtime.JSX.Element | null; type StarterMessageItemProps = HTMLAttributes & { prompt: StarterPrompt; layout?: StarterMessagesLayout; }; declare function StarterMessageItem({ className, prompt, layout, ...props }: StarterMessageItemProps): react_jsx_runtime.JSX.Element; declare function Avatar({ className, ...props }: React$1.ComponentProps): react_jsx_runtime.JSX.Element; type MessageProps = HTMLAttributes & { from: UIMessage["role"]; }; declare const Message: ({ className, from, ...props }: MessageProps) => react_jsx_runtime.JSX.Element; declare const messageContentVariants: (props?: ({ variant?: "ghost" | "flat" | "contained" | "surface" | null | undefined; density?: "compact" | "balanced" | "spacious" | null | undefined; } & class_variance_authority_types.ClassProp) | undefined) => string; type MessageContentProps = HTMLAttributes & VariantProps; declare const MessageContent: ({ children, className, variant, density, ...props }: MessageContentProps) => react_jsx_runtime.JSX.Element; type MessageMetadataProps = HTMLAttributes & { items?: ReactNode[]; }; declare const MessageMetadata: ({ items, children, className, ...props }: MessageMetadataProps) => react_jsx_runtime.JSX.Element | null; type MessageAvatarProps = ComponentProps & { src: string; name?: string; }; declare const MessageAvatar: ({ src, name, className, ...props }: MessageAvatarProps) => react_jsx_runtime.JSX.Element; declare function Collapsible({ ...props }: React.ComponentProps): react_jsx_runtime.JSX.Element; declare function CollapsibleTrigger({ ...props }: React.ComponentProps): react_jsx_runtime.JSX.Element; declare function CollapsibleContent({ ...props }: React.ComponentProps): react_jsx_runtime.JSX.Element; type SourcesProps = ComponentProps<"div">; /** * Sources bibliography footer (#138). Lives BELOW the assistant answer, not * above it: the inline citation chips link the prose to these sources, so the * list is a reference footer, not a top-of-message callout. Collapsed by * default; the trigger is a quiet uppercase section label (see SourcesTrigger). * A hairline anchors it to the answer while each source remains an unboxed row. */ declare const Sources: ({ className, ...props }: SourcesProps) => react_jsx_runtime.JSX.Element; type SourcesTriggerProps = ComponentProps & { count: number; }; /** * The bibliography footer affordance: a quiet, left-aligned uppercase label, * not a bordered pill. The count remains visible as metadata and the chevron * rotates on open; expanded rows stay unnumbered because inline citation chips * already carry the numeric mapping. */ declare const SourcesTrigger: ({ className, count, children, ...props }: SourcesTriggerProps) => react_jsx_runtime.JSX.Element; type SourcesContentProps = ComponentProps; declare const SourcesContent: ({ className, ...props }: SourcesContentProps) => react_jsx_runtime.JSX.Element; type SourceProps = ComponentProps<"a"> & { index?: number; }; declare const Source: ({ href, title, children, index: _index, className, ...props }: SourceProps) => react_jsx_runtime.JSX.Element; /** A `source-url` part, as produced by the handler's `toSourceParts`. */ interface CitationSource { type: "source-url"; sourceId?: string; url: string; title?: string; /** Original 1-indexed DOC references represented by a deduplicated source. */ citationIds?: number[]; } declare const CitationSourcesProvider: React$1.Provider; /** * Props stamped onto each `citeRef` element by the remark plugin * (data-ref-n / data-ref-raw). react-markdown surfaces them as DOM attributes on * the element the component override receives; we read them off `node` (the * ExtraProps `node`) to stay source-of-truth rather than re-parsing the DOM. */ interface CiteRefElementProps { node?: { properties?: Record; } | undefined; "data-ref-n"?: string; "data-ref-raw"?: string; children?: ReactNode; } /** * The `citeRef` component override. Renders one superscript chip linking to the * source carrying that reference ID. Used as `components.citeRef` in response.tsx. * * Layout: a raised, pill-shaped superscript carrying the model's source number. * Links open in a new tab with safe rel * attrs. Out-of-range refs (N > source count, or no sources in context) render * muted and non-interactive so the prose still reads. */ declare function CitationRef({ children, ...props }: CiteRefElementProps): react_jsx_runtime.JSX.Element; /** * Inline citation-token parsing for the chat renderer (#138). * * The model emits citation markers inline in assistant prose as either: * - `[ref: N]` — explicit ref form (used by the docs/RAG system prompt * and the `searchKnowledge` tool's `ref` field). * - `[ref: N, ref: M]` — comma-separated list inside one bracket. * - `[r: N]` / `[r:N]` — abbreviated ref form (models shorten "ref" to "r" * unprompted; observed live on the demo agent). * - `[N]` — bare numeric form (the auto-retrieve context prompt * says "cite e.g. [1]"). * * Without this, those tokens render as the literal strings "[ref: 4, ref: 6]" / * "[1]" — which is the bug: the widget has `source-url` bibliography parts but * nothing links the inline text to them. This module turns tokens into `citeRef` * mdast element nodes so the component override in response.tsx can render chips. * * CONTRACT — [ref: N] retains the model's original reference ID. Knowledge * source parts carry their pre-dedup DOC indices in citationIds, so duplicate * URLs can collapse into one bibliography row without remapping attribution. * Unmatched refs render as muted, non-linking chips so the prose still reads and * we never ship a confidently wrong or broken href. * * DEPENDENCY-FREE by design. A naive hand-rolled mdast walker is used instead of * `unist-util-visit` to avoid adding a runtime dep and the strict-ESM dir-import * crash class that killed `react-syntax-highlighter` in #177. Only mdast `text` * nodes are split — code fences and inline code carry their text in `value`, not * as `text` children, so a `visit(tree, 'text')` walk never enters them and refs * inside code are correctly left as literal text. * * Pure (no React, no DOM) so it can run in the remark pipeline on the server or * client and is trivially unit-testable. */ interface MdNode { type: string; value?: string; children?: MdNode[]; properties?: Record; data?: { hName?: string; hProperties?: Record; [k: string]: unknown; }; } /** * One parsed citation ref. `raw` is the original token text (e.g. "ref: 4" or * "4") so a renderer can fall back to it if needed; `n` is the original * 1-indexed reference ID the chip resolves. */ interface ParsedRef { n: number; raw: string; } /** * Parse the inner content of a citation bracket into refs. Returns null if the * inner string is not a valid citation list (so the caller leaves it as text). */ declare function parseRefs(inner: string): ParsedRef[] | null; /** * Split a text string into an ordered list of segments: literal text and * citation refs. Citations keep their original bracket text in `raw` so a * renderer can show "ref: 4" if it ever needs to. Pure, no side effects. */ type CitationSegment = { kind: "text"; text: string; } | { kind: "refs"; refs: ParsedRef[]; raw: string; }; declare function splitCitations(text: string): CitationSegment[]; /** * The remark plugin. Walks the mdast tree, splits every `text` node on * citation tokens, and replaces each citation with one or more `citeRef` * element nodes (one per ref in a `[ref: N, ref: M]` list). Returns the * (mutated) tree. No-op when there are no citation tokens, so it's cheap on * non-cited answers. * * Usage: `remarkPlugins={[remarkCitations, ...streamdownDefaults]}` — prepend so * it runs before Streamdown's own transforms (it only touches `text` nodes, * which are stable across the earlier plugins, so order is not load-bearing, but * prepending keeps it out of the way of CJK/math plugins that may rewrite text). */ declare function remarkCitations(): (tree: MdNode) => MdNode; /** * Options for {@link buildAutoPageContext}. Both default to the safe capture; * set them only when the host has decided the extra data is safe to send to the * model provider under its `trustClientContext` / `getContext` policy. */ interface AutoPageContextOptions { /** * Append the query string (`?...`) to the captured `url` AND expose it as a * separate `query` field (the raw `location.search`, including the leading * `?`). Default `false` — the query string is stripped entirely because it * routinely carries reset tokens, OAuth `state`/`code`, signed-URL * signatures, and PII in search params. */ includeQuery?: boolean; /** * Bypass the conservative safe-anchor heuristic and capture the fragment * (`#...`) verbatim whenever one is present. Default `false` — by default a * fragment is captured ONLY when {@link isSafeAnchorHash} accepts it (a plain * docs anchor), so token-bearing / router-state fragments are dropped. */ includeHash?: boolean; } /** * True when `hash` (including its leading `#`) looks like a plain docs anchor * safe to include by default — NOT a token-bearing or router-state fragment. * * Rejects (→ dropped from the default capture): empty/`"#"`, anything * containing `=`, `&`, `?`, or `/` (query- or route-shaped), fragments longer * than 128 chars after the `#`, and anything using characters outside the * restricted anchor alphabet (e.g. `%`, spaces, `#access_token=…`). */ declare function isSafeAnchorHash(hash: string): boolean; /** * Snapshot the current page location as a {@link ChatContext}. * * Read from `window.location` / `document` at call time, so calling it AT SEND * TIME reflects SPA route changes between messages. Every browser global is * guarded, so this is safe to call during SSR / in a non-browser runtime — it * returns `{}` there rather than throwing (no `window`/`document` access * outside the guards). * * Captured fields — the SAFE DEFAULT deliberately excludes the query string and * non-anchor fragments (see the security note above): * - `url` — `origin + pathname` (NO query, NO fragment) * - `path` — `pathname` * - `title` — `document.title` (omitted when empty) * - `hash` — the fragment, included ONLY when {@link isSafeAnchorHash} accepts * it as a plain docs anchor; otherwise omitted entirely * * Opt in to more, explicitly, via {@link AutoPageContextOptions} — only through * the function form (`buildAutoPageContext({ … })`); the bare `'auto'` string * literal ALWAYS uses these safe defaults: * - `includeQuery: true` — append the query string to `url` AND add a `query` * field (raw `location.search`, including the leading `?`) * - `includeHash: true` — capture the fragment verbatim, bypassing the anchor * heuristic * * Never captures identity data (cookies, `document.referrer`, * `navigator.userAgent`). Any individual field whose global is unexpectedly * unavailable is simply omitted; the helper never throws. */ declare function buildAutoPageContext(options?: AutoPageContextOptions): ChatContext; interface ActionResultCardProps extends ActionResult { className?: string; } declare function ActionResultCard({ status, title, fields, link, note, className, }: ActionResultCardProps): react_jsx_runtime.JSX.Element; /** * Where a Mordn action is handled. Keep this small and explicit: browser-local * UI work, the host's createChatHandler server, or a hosted/server-side action * plane. Payloads are always untrusted until the chosen handler validates them. */ type MordnActionHandler = 'client' | 'server' | 'hosted'; /** How an action should mark the UI while it is in flight. */ type MordnActionLoadingBehavior = 'auto' | 'none' | 'self' | 'container'; /** How much confirmation a consequential action requires before execution. */ type MordnActionConfirmationPolicy = 'none' | 'recommended' | 'required'; /** Optional risk hint for dashboards, docs, and confirmation cards. */ type MordnActionRiskLevel = 'ui' | 'read' | 'capture' | 'mutation' | 'regulated'; /** JSON-schema-lite shape used by manifests and hosted config without pulling a validator into the client bundle. */ interface MordnActionSchema { type?: 'object'; required?: string[]; properties?: Record; additionalProperties?: boolean; } interface MordnActionSchemaProperty { type: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; title?: string; description?: string; enum?: Array; default?: unknown; format?: 'email' | 'uri' | 'date' | 'date-time' | 'time' | 'tel'; items?: MordnActionSchemaProperty; properties?: Record; /** Mark fields that should be redacted from audit/event display. */ redact?: boolean; } /** * Declarative action config that can be attached to cards, chips, forms, or * host-rendered widgets. It intentionally mirrors ChatKit-style action ideas * while staying framework-neutral for Mordn's hosted/self-hosted modes. */ interface MordnActionConfig { /** Namespaced action type, e.g. ecommerce.cart.add or restaurant.reservation.request. */ type: string; /** Data supplied by the rendered UI. Treat as untrusted on the server. */ payload?: TPayload; /** Defaults to server for mutations, client for purely local UI when explicitly set. */ handler?: MordnActionHandler; /** Defaults to auto. */ loadingBehavior?: MordnActionLoadingBehavior; /** Defaults to none for read/UI actions; required for consequential mutations. */ confirmation?: MordnActionConfirmationPolicy; /** Stable client-generated key for duplicate-click / retry safety. */ idempotencyKey?: string; /** Optional display label used by dashboards and generic confirmation UI. */ label?: string; /** Risk hint used by templates and hosted policy. */ risk?: MordnActionRiskLevel; /** Optional analytics name; defaults to type. */ analyticsName?: string; /** Optional schema for form/dashboard generation. Server must still validate authoritatively. */ schema?: MordnActionSchema; } type MordnActionStatus = 'idle' | 'pending' | 'requires_confirmation' | 'requires_input' | 'success' | 'error'; interface MordnActionEvent { action: MordnActionConfig; /** Component or message item that emitted the action, when known. */ source?: string; /** Current form values merged by ActionForm/ActionCard. */ values?: Record; } interface MordnActionResult { status: MordnActionStatus; title?: string; message?: string; data?: TData; /** Optional next UI part/template state for a later renderer. */ ui?: unknown; errorCode?: string; } type MordnActionDispatcher = (event: MordnActionEvent) => void | Promise; type MordnTemplateVertical = 'docs' | 'lead-capture' | 'services-booking' | 'restaurant' | 'ecommerce' | 'travel' | 'support' | 'internal-ops' | (string & {}); interface MordnTemplateActionDefinition { type: string; label: string; description: string; handler?: MordnActionHandler; risk?: MordnActionRiskLevel; confirmation?: MordnActionConfirmationPolicy; schema?: MordnActionSchema; } interface MordnTemplateCardDefinition { type: 'entity-card' | 'entity-carousel' | 'action-form' | 'selection-group' | 'summary-card' | 'status-tracker' | 'handoff-card' | (string & {}); label: string; description: string; } interface MordnTemplateStarterPrompt { title: string; subtitle?: string; message?: string; } interface MordnTemplateManifest { id: string; name: string; description: string; vertical: MordnTemplateVertical; version: string; minWidgetVersion?: string; starterPrompts: MordnTemplateStarterPrompt[]; promptFragment?: string; cards: MordnTemplateCardDefinition[]; actions: MordnTemplateActionDefinition[]; recommendedKnowledge?: string[]; demoData?: Record; notes?: string[]; } interface MordnActionPrimitiveProps { action?: MordnActionConfig; onAction?: MordnActionDispatcher; disabled?: boolean; loading?: boolean; } interface MordnEntityAttribute { label: string; value: ReactNode; } interface MordnEntityAction { label: string; action?: MordnActionConfig; href?: string; variant?: 'primary' | 'secondary' | 'ghost'; } interface MordnEntityItem { id: string; title: string; subtitle?: string; description?: ReactNode; imageUrl?: string; price?: string; badge?: string; attributes?: MordnEntityAttribute[]; actions?: MordnEntityAction[]; } interface MordnStatusStep { id: string; label: string; description?: string; status?: 'complete' | 'current' | 'pending' | 'error'; } interface ActionButtonProps extends Omit, 'onClick'>, MordnActionPrimitiveProps { label?: string; icon?: ReactNode; variant?: 'primary' | 'secondary' | 'ghost'; } declare function ActionButton({ action, onAction, disabled, loading, label, icon, variant, className, children, ...props }: ActionButtonProps): react_jsx_runtime.JSX.Element; interface ActionChipsProps extends ComponentProps<'div'> { actions: Array; onAction?: MordnActionDispatcher; disabled?: boolean; } declare function ActionChips({ actions, onAction, disabled, className, ...props }: ActionChipsProps): react_jsx_runtime.JSX.Element | null; interface EntityCardProps extends ComponentProps<'article'> { item: MordnEntityItem; onAction?: MordnActionDispatcher; } declare function EntityCard({ item, onAction, className, style, ...props }: EntityCardProps): react_jsx_runtime.JSX.Element; interface EntityCarouselProps extends ComponentProps<'div'> { items: MordnEntityItem[]; onAction?: MordnActionDispatcher; label?: string; } declare function EntityCarousel({ items, onAction, label, className, ...props }: EntityCarouselProps): react_jsx_runtime.JSX.Element | null; interface ActionFormField { name: string; label: string; type?: 'text' | 'email' | 'tel' | 'date' | 'time' | 'number' | 'textarea'; required?: boolean; placeholder?: string; defaultValue?: string; } interface ActionFormProps extends Omit, 'action' | 'onSubmit'> { title?: string; description?: string; fields: ActionFormField[]; submitLabel?: string; action: MordnActionConfig; onAction?: MordnActionDispatcher; } declare function ActionForm({ title, description, fields, submitLabel, action, onAction, className, ...props }: ActionFormProps): react_jsx_runtime.JSX.Element; interface SummaryCardProps extends ComponentProps<'section'> { title: string; description?: ReactNode; rows?: Array<{ label: string; value: ReactNode; }>; action?: MordnActionConfig; onAction?: MordnActionDispatcher; actionLabel?: string; } /** * Receipt-style summary. Rows render as a hairline-divided ledger; a row whose * label reads like a grand total ("Total", "Total due"…) is automatically * emphasised so the number that matters is the one you see first. */ declare function SummaryCard({ title, description, rows, action, onAction, actionLabel, className, ...props }: SummaryCardProps): react_jsx_runtime.JSX.Element; interface ConfirmationCardProps extends ComponentProps<'section'> { title: string; description?: ReactNode; action: MordnActionConfig; onAction?: MordnActionDispatcher; confirmLabel?: string; cancelLabel?: string; onCancel?: () => void; } declare function ConfirmationCard({ title, description, action, onAction, confirmLabel, cancelLabel, onCancel, className, ...props }: ConfirmationCardProps): react_jsx_runtime.JSX.Element; interface StatusTrackerProps extends ComponentProps<'ol'> { steps: MordnStatusStep[]; } /** * Vertical timeline: success-filled markers for completed steps, a compact * spinner on the current one, and a quiet connecting rail for at-a-glance progress. */ declare function StatusTracker({ steps, className, ...props }: StatusTrackerProps): react_jsx_runtime.JSX.Element; declare const docsAssistantTemplate: MordnTemplateManifest; declare const leadCaptureTemplate: MordnTemplateManifest; declare const servicesBookingTemplate: MordnTemplateManifest; declare const restaurantAssistantTemplate: MordnTemplateManifest; declare const ecommerceConciergeTemplate: MordnTemplateManifest; declare const travelPlannerTemplate: MordnTemplateManifest; declare const defaultMordnTemplates: MordnTemplateManifest[]; declare function getMordnTemplate(id: string): MordnTemplateManifest | undefined; type ToolProps = ComponentProps; declare const Tool: ({ className, ...props }: ToolProps) => react_jsx_runtime.JSX.Element; type ToolHeaderProps = { title?: string; type: ToolUIPart["type"] | "dynamic-tool"; /** * Set when the part is a `dynamic-tool` UIPart (MCP / `dynamicTool()`). * For these the `type` is always `"dynamic-tool"`, so the actual tool * identity lives in `toolName`. When provided, it wins over the parsed * type fragment so the header shows e.g. `get_financials` instead of * the generic `tool`. */ toolName?: string; state: ToolUIPart["state"]; className?: string; }; declare const ToolHeader: ({ className, title, type, toolName, state, ...props }: ToolHeaderProps) => react_jsx_runtime.JSX.Element; type ToolContentProps = ComponentProps; declare const ToolContent: ({ className, ...props }: ToolContentProps) => react_jsx_runtime.JSX.Element; type ToolInputProps = ComponentProps<"div"> & { input: ToolUIPart["input"]; }; declare const ToolInput: ({ className, input, ...props }: ToolInputProps) => react_jsx_runtime.JSX.Element; type ToolOutputProps = ComponentProps<"div"> & { output: ToolUIPart["output"]; errorText: ToolUIPart["errorText"]; }; declare const ToolOutput: ({ className, output, errorText, ...props }: ToolOutputProps) => react_jsx_runtime.JSX.Element | null; /** * ChartSpec — the declarative, JSON-serializable chart description the widget * renders inline in assistant transcripts. * * v2 widens v1 to a broad, high-quality chart vocabulary while preserving the * trust boundary (PRD §3): minimal enough for a model to emit reliably, strict * on honesty (finite numbers, required title, bounded points, closed type * enum), lenient on unknown fields (forward-compat). * * Multi-series: `series` accepts either a single ChartSeries (v1 shape, still * supported verbatim) or an array. The renderer normalizes to an array * internally; a single-series chart needs no array wrapping. Charts that are * inherently single-series (pie/donut/sparkline) accept a single `series`. * * Honesty overrides the model CANNOT set (enforced by the renderer, not the * schema, because they're rendering decisions): bar/area y-axis always starts * at 0; no dual y-axes (out of scope); pie/donut refused if parts don't sum to * ~100% of a stated whole; ordinal single-hue ramp for ranked data, distinct * categorical hues only when multiple named series exist. Deliberately absent * from the schema so a model can't sneak in a `yMin: 990`. * * No new runtime deps. zod is already a peer dependency of @mordn/chat-widget * (^3.25 || ^4). The schema is written against zod's stable API so both majors * accept it. */ /** Schema version. Bumped only on a breaking change to this shape. */ declare const CHART_SPEC_SCHEMA_VERSION: 2; declare const ChartSpecSchema: z.ZodObject<{ schemaVersion: z.ZodLiteral<2>; type: z.ZodEnum<{ area: "area"; line: "line"; bar: "bar"; "horizontal-bar": "horizontal-bar"; "multi-line": "multi-line"; "stacked-bar": "stacked-bar"; "grouped-bar": "grouped-bar"; pie: "pie"; donut: "donut"; scatter: "scatter"; sparkline: "sparkline"; }>; title: z.ZodString; subtitle: z.ZodOptional; xLabel: z.ZodOptional; yLabel: z.ZodOptional; source: z.ZodOptional; legend: z.ZodOptional; valueLabels: z.ZodOptional; series: z.ZodOptional; points: z.ZodArray; }, z.core.$strip>>; color: z.ZodOptional; }, z.core.$strip>, z.ZodArray; points: z.ZodArray; }, z.core.$strip>>; color: z.ZodOptional; }, z.core.$strip>>]>>; whole: z.ZodOptional; tolerance: z.ZodDefault; }, z.core.$strip>>; scatter: z.ZodOptional; color: z.ZodOptional; }, z.core.$strip>>>; }, z.core.$strip>; type ChartSpec = z.infer; /** The fence languages that trigger the chart renderer (Seam A). */ declare const CHART_FENCE_LANGUAGES: readonly ["mordn-chart", "chart"]; type ChartFenceLanguage = (typeof CHART_FENCE_LANGUAGES)[number]; /** True if a fenced-block language should render as a chart. */ declare function isChartFenceLanguage(language: string | undefined): boolean; type ChartSpecParseResult = { ok: true; spec: ChartSpec; } | { ok: false; error: string; issues: string[]; }; declare function parseChartSpec(text: string): ChartSpecParseResult; /** Validate an already-parsed object (for hosts building a spec programmatically). Throws on invalid. */ declare function validateChartSpec(input: unknown): ChartSpec; interface ChartBlockProps { spec: ChartSpec; className?: string; } declare function ChartBlock({ spec, className }: ChartBlockProps): react_jsx_runtime.JSX.Element; interface ChartErrorCardProps { error: string; rawText: string; className?: string; } declare function ChartErrorCard({ error, rawText, className }: ChartErrorCardProps): react_jsx_runtime.JSX.Element; /** Render a spec-or-error in one call (used by the fence hook + tool renderer). */ declare function ChartBlockOrError({ result, rawText, }: { result: { ok: true; spec: ChartSpec; } | { ok: false; error: string; }; rawText: string; }): ReactNode; declare function chartToolRenderer(toolName: string, map: (output: unknown) => ChartSpec): ToolRenderer; /** * ChartCode — Seam A fence renderer (PRD §2). Streamdown hands the `code` * component the COMPLETE fenced text once the closing backticks arrive, so we * only ever see a closed fence — no partial-chart risk. response.tsx routes * chart fence languages here; everything else stays CollapsibleCode. */ interface StreamdownCodeProps { inline?: boolean; className?: string; children?: React.ReactNode; node?: unknown; } declare function ChartCode({ inline, className, children, node: _node }: StreamdownCodeProps): react_jsx_runtime.JSX.Element; interface ThemePreset extends ThemeConfig { /** Display name shown in the playground preset picker. */ name: string; } /** * Canonical preset themes. The playground renders its preset picker from this * list so the widget package stays the single source of truth for what a * "good" three-color combination looks like. Every preset is just a valid * ThemeConfig — there is nothing a preset can do that a hand-picked trio * can't. */ declare const THEME_PRESETS: ThemePreset[]; export { AGENT_CONFIG_SCHEMA_VERSION, ActionButton, type ActionButtonProps, ActionChips, type ActionChipsProps, ActionForm, type ActionFormField, type ActionFormProps, type ActionRenderer, type ActionResult, ActionResultCard, type ActionResultCardProps, type ActionResultField, type ActionResultStatus, type AgentBootstrap, type AgentClientConfig, type AgentConfig, type AgentRuntimeConfig, type AutoPageContextOptions, BOOTSTRAP_PROTOCOL_VERSION, Button, CHART_FENCE_LANGUAGES, CHART_SPEC_SCHEMA_VERSION, CHAT_ERROR_DATA_TYPE, CHAT_ERROR_HEADER, CHAT_ERROR_VERSION, ChartBlock, ChartBlockOrError, type ChartBlockProps, ChartCode, ChartErrorCard, type ChartErrorCardProps, type ChartFenceLanguage, type ChartSpec, type ChartSpecParseResult, ChartSpecSchema, type ChatContext, type ChatErrorKind, type ChatErrorMetadata, ChatStorageProvider, ChatWidget, type ChatWidgetHandle, type ChatWidgetProps, type ChatWidgetSize, CitationRef, type CitationSegment, type CitationSource, CitationSourcesProvider, type FieldDescription as ConfigFieldDescription, type ReadIssue as ConfigReadIssue, type ReadResult as ConfigReadResult, ConfirmationCard, type ConfirmationCardProps, DEFAULT_FEATURES, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, type DisplayConfig, EntityCard, type EntityCardProps, EntityCarousel, type EntityCarouselProps, type FeatureConfig, type FeedbackEvent, type FollowUpMessage, Input, type InputPlugin, type InputPluginItem, Message, MessageAvatar, type MessageAvatarProps, MessageContent, type MessageContentProps, type MessageDataPart, MessageMetadata, type MessageMetadataProps, type MessagePartRenderer, type MessagePartRendererContext, type MessagePartRenderers, type MessageProps, type MordnActionConfig, type MordnActionConfirmationPolicy, type MordnActionDispatcher, type MordnActionEvent, type MordnActionHandler, type MordnActionLoadingBehavior, type MordnActionPrimitiveProps, type MordnActionResult, type MordnActionRiskLevel, type MordnActionSchema, type MordnActionSchemaProperty, type MordnActionStatus, type MordnEntityAction, type MordnEntityAttribute, type MordnEntityItem, type MordnStatusStep, type MordnTemplateActionDefinition, type MordnTemplateCardDefinition, type MordnTemplateManifest, type MordnTemplateStarterPrompt, type MordnTemplateVertical, type ParsedRef, type PublishedAgentConfig, type ResolvedFeatureConfig, type SerializableMemoryConfig, type SerializableStarterPrompt, Source, type SourceProps, Sources, SourcesContent, type SourcesContentProps, type SourcesProps, SourcesTrigger, type SourcesTriggerProps, StarterMessageItem, StarterMessages, type StarterPrompt, StatusTracker, type StatusTrackerProps, SummaryCard, type SummaryCardProps, THEME_PRESETS, type ThemeConfig, type ThemePreset, Tool, ToolContent, ToolHeader, ToolInput, ToolOutput, type ToolPartLike, type ToolRenderer, buildAutoPageContext, chartToolRenderer, clearChatStorage, createChatErrorRecovery, ChatWidget as default, defaultMordnTemplates, describeAgentConfigSchema, docsAssistantTemplate, ecommerceConciergeTemplate, formatConfigIssues, getChatErrorRecovery, getMordnTemplate, isAgentBootstrap, isAgentConfig, isChartFenceLanguage, isSafeAnchorHash, leadCaptureTemplate, messageForErrorKind, parseChartSpec, parseChatErrorHeader, parseChatErrorMetadata, parseRefs, readAgentBootstrap, readAgentConfig, remarkCitations, resolveFeatures, restaurantAssistantTemplate, servicesBookingTemplate, splitCitations, travelPlannerTemplate, useChatStorageKey, validateChartSpec };