@djangocfg/ui-tools 2.1.385 → 2.1.389

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +25 -11
  2. package/dist/ChatRoot-EFNXQXXN.cjs +15 -0
  3. package/dist/{ChatRoot-JVR3M3H2.mjs.map → ChatRoot-EFNXQXXN.cjs.map} +1 -1
  4. package/dist/ChatRoot-FITF5RVP.mjs +6 -0
  5. package/dist/{ChatRoot-LXIUBOXF.cjs.map → ChatRoot-FITF5RVP.mjs.map} +1 -1
  6. package/dist/{DocsLayout-2P3ONDWJ.mjs → DocsLayout-EKASBSP7.mjs} +3 -3
  7. package/dist/{DocsLayout-2P3ONDWJ.mjs.map → DocsLayout-EKASBSP7.mjs.map} +1 -1
  8. package/dist/{DocsLayout-2YZNS5VK.cjs → DocsLayout-OURFYWQE.cjs} +8 -8
  9. package/dist/{DocsLayout-2YZNS5VK.cjs.map → DocsLayout-OURFYWQE.cjs.map} +1 -1
  10. package/dist/MapContainer-AKIPABJK.mjs +4 -0
  11. package/dist/MapContainer-AKIPABJK.mjs.map +1 -0
  12. package/dist/MapContainer-STVDMC36.cjs +17 -0
  13. package/dist/MapContainer-STVDMC36.cjs.map +1 -0
  14. package/dist/{chunk-HIK6BPL7.mjs → chunk-2NG4SXEP.mjs} +6 -5
  15. package/dist/chunk-2NG4SXEP.mjs.map +1 -0
  16. package/dist/chunk-4LFB7I5K.cjs +1387 -0
  17. package/dist/chunk-4LFB7I5K.cjs.map +1 -0
  18. package/dist/{MapContainer-76YL2JXL.cjs → chunk-5D2OCOPQ.cjs} +3 -2
  19. package/dist/chunk-5D2OCOPQ.cjs.map +1 -0
  20. package/dist/chunk-6ZX2G25W.mjs +1361 -0
  21. package/dist/chunk-6ZX2G25W.mjs.map +1 -0
  22. package/dist/{MapContainer-7HXBI3OH.mjs → chunk-7CWGZPO3.mjs} +3 -3
  23. package/dist/chunk-7CWGZPO3.mjs.map +1 -0
  24. package/dist/{chunk-FIRK5CEH.cjs → chunk-7IYXZUJO.cjs} +8 -4
  25. package/dist/chunk-7IYXZUJO.cjs.map +1 -0
  26. package/dist/{chunk-PEKBT75W.mjs → chunk-DMX7W4XZ.mjs} +53 -1387
  27. package/dist/chunk-DMX7W4XZ.mjs.map +1 -0
  28. package/dist/chunk-NTVBIIUD.mjs +1439 -0
  29. package/dist/chunk-NTVBIIUD.mjs.map +1 -0
  30. package/dist/{chunk-HPK3EWBF.cjs → chunk-TBSHZO5R.cjs} +50 -1409
  31. package/dist/chunk-TBSHZO5R.cjs.map +1 -0
  32. package/dist/chunk-W75B7Y6C.cjs +1478 -0
  33. package/dist/chunk-W75B7Y6C.cjs.map +1 -0
  34. package/dist/index.cjs +1269 -1790
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +660 -623
  37. package/dist/index.d.ts +660 -623
  38. package/dist/index.mjs +856 -1427
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/launcher-5Y42OBSN.mjs +6 -0
  41. package/dist/launcher-5Y42OBSN.mjs.map +1 -0
  42. package/dist/launcher-PMW2YB24.cjs +59 -0
  43. package/dist/launcher-PMW2YB24.cjs.map +1 -0
  44. package/package.json +23 -18
  45. package/src/components/index.ts +2 -2
  46. package/src/index.ts +20 -2
  47. package/src/tools/AudioPlayer/lazy.tsx +100 -0
  48. package/src/tools/Chat/README.md +85 -1
  49. package/src/tools/Chat/components/MessageBubble.tsx +1 -1
  50. package/src/tools/Chat/context/ChatProvider.tsx +42 -0
  51. package/src/tools/Chat/index.ts +1 -1
  52. package/src/tools/Chat/lazy.tsx +300 -1
  53. package/src/tools/CodeEditor/lazy.tsx +70 -0
  54. package/src/tools/Map/lazy.tsx +38 -1
  55. package/src/tools/MarkdownEditor/lazy.tsx +42 -0
  56. package/src/{components/markdown → tools}/MarkdownMessage/CodeBlock.tsx +1 -1
  57. package/src/{components/markdown → tools}/MarkdownMessage/CollapseToggle.tsx +1 -1
  58. package/src/{components/markdown → tools}/MarkdownMessage/MarkdownMessage.tsx +1 -1
  59. package/src/{components/markdown → tools}/MarkdownMessage/components.tsx +2 -2
  60. package/src/tools/OpenapiViewer/components/DocsLayout/ApiIntroSection.tsx +1 -1
  61. package/src/tools/OpenapiViewer/components/DocsLayout/EndpointDoc/Header/index.tsx +1 -1
  62. package/src/tools/SpeechRecognition/README.md +48 -0
  63. package/dist/ChatRoot-JVR3M3H2.mjs +0 -5
  64. package/dist/ChatRoot-LXIUBOXF.cjs +0 -14
  65. package/dist/MapContainer-76YL2JXL.cjs.map +0 -1
  66. package/dist/MapContainer-7HXBI3OH.mjs.map +0 -1
  67. package/dist/chunk-FIRK5CEH.cjs.map +0 -1
  68. package/dist/chunk-HIK6BPL7.mjs.map +0 -1
  69. package/dist/chunk-HPK3EWBF.cjs.map +0 -1
  70. package/dist/chunk-PEKBT75W.mjs.map +0 -1
  71. package/src/components/markdown/index.ts +0 -19
  72. /package/src/{components/markdown → hooks}/useCollapsibleContent.ts +0 -0
  73. /package/src/{components/markdown → tools}/MarkdownMessage/ActionRow.tsx +0 -0
  74. /package/src/{components/markdown → tools}/MarkdownMessage/ChatMessageRow.tsx +0 -0
  75. /package/src/{components/markdown → tools}/MarkdownMessage/README.md +0 -0
  76. /package/src/{components/markdown → tools}/MarkdownMessage/index.ts +0 -0
  77. /package/src/{components/markdown → tools}/MarkdownMessage/linkRules.ts +0 -0
  78. /package/src/{components/markdown → tools}/MarkdownMessage/plainText.ts +0 -0
  79. /package/src/{components/markdown → tools}/MarkdownMessage/sanitize.ts +0 -0
  80. /package/src/{components/markdown → tools}/MarkdownMessage/types.ts +0 -0
package/dist/index.d.cts CHANGED
@@ -1,7 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import react__default, { ReactNode, ComponentType, RefObject, ChangeEvent, KeyboardEvent, ClipboardEvent, CSSProperties, ButtonHTMLAttributes, MouseEvent } from 'react';
4
- import { Components } from 'react-markdown';
5
4
  import { ViewState } from 'react-map-gl/maplibre';
6
5
  import { Language } from 'prism-react-renderer';
7
6
  export { Language } from 'prism-react-renderer';
@@ -16,6 +15,7 @@ export { c as DEFAULT_TREE_APPEARANCE, D as DEFAULT_TREE_LABELS, F as FlatRow, R
16
15
  import * as zustand from 'zustand';
17
16
  import { AudioPrefsState } from '@djangocfg/ui-core/hooks';
18
17
  import { ConsolaInstance } from 'consola';
18
+ import { Components } from 'react-markdown';
19
19
  import { MediaPlayerInstance } from '@vidstack/react';
20
20
  import * as monaco from 'monaco-editor';
21
21
  import { Editor as Editor$1 } from '@tiptap/react';
@@ -117,220 +117,6 @@ declare function createLazyComponent<P extends object>(loader: () => Promise<{
117
117
  default: ComponentType<P>;
118
118
  }>, options?: CreateLazyComponentOptions<P>): ComponentType<P>;
119
119
 
120
- /**
121
- * Declarative rule for handling a custom URL scheme inside markdown.
122
- *
123
- * Each rule owns one href shape (e.g. `cmdop://machine/<uuid>`,
124
- * `obsidian://open?path=…`) and decides:
125
- *
126
- * 1. Whether the URL scheme survives sanitize (`protocols`).
127
- * 2. How to massage the source markdown before render
128
- * (`preprocess` — optional; useful for stripping decorative
129
- * prefixes like the `@` in `@[label](href)` so the chip alone
130
- * reads as the mention indicator).
131
- * 3. Which links it owns (`match`), and how to render them
132
- * (`render`, returning JSX).
133
- *
134
- * Rules compose: pass an array, and the renderer iterates top-to-bottom
135
- * picking the first `match` hit per `<a>`. Anything no rule claims
136
- * falls through to the built-in chat-link styling (or to a custom
137
- * `customComponents.a` if both are provided).
138
- *
139
- * Prefer `linkRules` over `customComponents` + `extraHrefProtocols` —
140
- * it's the same pieces with the boilerplate removed.
141
- */
142
- interface LinkRule {
143
- /** Pre-process the raw markdown source before any rendering happens.
144
- * Pure / synchronous; identity-return when no transform applies. */
145
- preprocess?: (source: string) => string;
146
- /** Predicate against the resolved href. */
147
- match: (href: string) => boolean;
148
- /** Render the link this rule owns. `children` is the link's label
149
- * (markdown-rendered React content). */
150
- render: (props: {
151
- href: string;
152
- children: react__default.ReactNode;
153
- isUser: boolean;
154
- }) => react__default.ReactNode;
155
- /** URL scheme(s) to whitelist on the sanitize side, e.g. `['cmdop']`.
156
- * Bare schemes only — no `://`. Optional; omit for `http(s)` rules. */
157
- protocols?: readonly string[];
158
- /** Diagnostic label, surfaced in dev warnings. Optional. */
159
- name?: string;
160
- }
161
- interface MarkdownMessageProps {
162
- /** Markdown content to render */
163
- content: string;
164
- /** Additional CSS classes */
165
- className?: string;
166
- /** Whether the message is from the user (affects styling) */
167
- isUser?: boolean;
168
- /** Use compact size (text-xs instead of text-sm) */
169
- isCompact?: boolean;
170
- /**
171
- * Force the plain-text rendering path (single `<div>` with
172
- * `white-space: pre-wrap`, no ReactMarkdown). Use this for
173
- * user-authored content where markdown shouldn't be parsed.
174
- *
175
- * When `undefined` (default) we run a small heuristic
176
- * (`looksLikePlainProse`): short single-paragraph text without
177
- * markdown markers → plain; everything else → ReactMarkdown.
178
- *
179
- * Pass an explicit `true` / `false` to opt out of the heuristic
180
- * entirely.
181
- */
182
- plainText?: boolean;
183
- /**
184
- * Per-tag overrides merged on top of the built-in renderers.
185
- *
186
- * Use this when you need custom rendering for a specific tag without
187
- * losing the chat-tuned defaults (links, code blocks with copy, etc).
188
- *
189
- * For custom URL-scheme link handling, prefer `linkRules` — it's the
190
- * same ergonomics with the per-consumer boilerplate removed.
191
- */
192
- customComponents?: Partial<Components>;
193
- /**
194
- * Extra URL protocols allowed in `<a href>` after sanitize.
195
- *
196
- * The default schema strips anything that isn't
197
- * `http(s)/mailto/xmpp/irc(s)` — your custom renderer would receive
198
- * `href={undefined}` for `cmdop://…` / `obsidian://…` etc. Listing
199
- * the bare scheme here (e.g. `'cmdop'`, NOT `'cmdop://'`) opts it in.
200
- *
201
- * Use carefully: every protocol you add increases what the rendered
202
- * HTML can do via clicks. Stick to schemes you control.
203
- */
204
- extraHrefProtocols?: readonly string[];
205
- /**
206
- * Declarative link rules — preferred over `customComponents` +
207
- * `extraHrefProtocols` for chat-style apps that want pluggable
208
- * URL-scheme handling without re-implementing the custom-`a`
209
- * boilerplate per consumer.
210
- *
211
- * If you provide both `linkRules` and `extraHrefProtocols`, the
212
- * effective protocol list is the union of the two.
213
- */
214
- linkRules?: readonly LinkRule[];
215
- /**
216
- * Enable collapsible "Read more..." functionality
217
- * @default false
218
- */
219
- collapsible?: boolean;
220
- /** Maximum character length before showing "Read more...". */
221
- maxLength?: number;
222
- /** Maximum number of lines before showing "Read more...". */
223
- maxLines?: number;
224
- /** Custom "Read more" button text. @default "Read more..." */
225
- readMoreLabel?: string;
226
- /** Custom "Show less" button text. @default "Show less" */
227
- showLessLabel?: string;
228
- /** Start expanded (only when `collapsible` is true). @default false */
229
- defaultExpanded?: boolean;
230
- /** Callback when collapsed state changes */
231
- onCollapseChange?: (isCollapsed: boolean) => void;
232
- }
233
-
234
- /**
235
- * MarkdownMessage — chat-tuned markdown renderer.
236
- *
237
- * Features:
238
- * - GitHub Flavored Markdown (GFM) via remark-gfm
239
- * - Syntax-highlighted code blocks with Copy button
240
- * - Mermaid diagram rendering (` ```mermaid ` fence)
241
- * - Tables, lists, blockquotes scaled for chat density
242
- * - User vs assistant styling modes (`isUser`)
243
- * - Plain-text fast path: skips ReactMarkdown when content has no
244
- * markdown syntax (cheaper render, preserves newlines via CSS)
245
- * - Optional collapsible "Read more..." for long messages
246
- *
247
- * Custom URL schemes (chat mentions, deep-links, custom file viewers)
248
- * are best handled with the declarative `linkRules` prop — see the
249
- * type definition in `./types.ts` and the storybook for examples.
250
- *
251
- * @example
252
- * ```tsx
253
- * <MarkdownMessage content="# Hello\n\nThis is **bold** text." />
254
- *
255
- * // User message styling
256
- * <MarkdownMessage content="Some content" isUser />
257
- *
258
- * // Custom URL scheme via linkRules
259
- * <MarkdownMessage
260
- * content="Talk to [Vps-audi](cmdop://machine/abc-123)"
261
- * linkRules={[machineMentionRule]}
262
- * />
263
- * ```
264
- *
265
- * Memoised: re-renders only when props change. `content` is the main
266
- * trigger — all other props (className, isUser, isCompact, etc.) are
267
- * compared by value/reference. `onCollapseChange` is compared by
268
- * reference — callers should stabilise it with useCallback.
269
- */
270
- declare function MarkdownMessageRaw({ content, className, isUser, isCompact, plainText, customComponents, extraHrefProtocols, linkRules, collapsible, maxLength, maxLines, readMoreLabel, showLessLabel, defaultExpanded, onCollapseChange, }: MarkdownMessageProps): react_jsx_runtime.JSX.Element;
271
- declare const MarkdownMessage: react__default.MemoExoticComponent<typeof MarkdownMessageRaw>;
272
-
273
- /** Recursively concatenate the text content of a React.ReactNode tree.
274
- * Used by the markdown renderers (e.g. `<pre>` extracting code) and
275
- * by consumers that need a plain-string label out of link children. */
276
- declare function extractTextFromChildren(children: react__default.ReactNode): string;
277
-
278
- interface UseCollapsibleContentOptions {
279
- /**
280
- * Maximum character length before collapsing
281
- * If both maxLength and maxLines are set, the stricter limit applies
282
- */
283
- maxLength?: number;
284
- /**
285
- * Maximum number of lines before collapsing
286
- * If both maxLength and maxLines are set, the stricter limit applies
287
- */
288
- maxLines?: number;
289
- /**
290
- * Start in expanded state (default: false - starts collapsed)
291
- */
292
- defaultExpanded?: boolean;
293
- }
294
- interface UseCollapsibleContentResult {
295
- /** Whether content is currently collapsed */
296
- isCollapsed: boolean;
297
- /** Toggle between collapsed/expanded state */
298
- toggleCollapsed: () => void;
299
- /** Set collapsed state directly */
300
- setCollapsed: (collapsed: boolean) => void;
301
- /** Content to display (truncated if collapsed, full if expanded) */
302
- displayContent: string;
303
- /** Whether the content exceeds limits and should be collapsible */
304
- shouldCollapse: boolean;
305
- /** Original content length */
306
- originalLength: number;
307
- /** Original line count */
308
- originalLineCount: number;
309
- }
310
- /**
311
- * Hook for managing collapsible content with "Read more..." functionality
312
- *
313
- * @example
314
- * ```tsx
315
- * const { isCollapsed, toggleCollapsed, displayContent, shouldCollapse } = useCollapsibleContent(
316
- * longText,
317
- * { maxLength: 300, maxLines: 5 }
318
- * );
319
- *
320
- * return (
321
- * <div>
322
- * <Markdown content={displayContent} />
323
- * {shouldCollapse && (
324
- * <button onClick={toggleCollapsed}>
325
- * {isCollapsed ? 'Read more...' : 'Show less'}
326
- * </button>
327
- * )}
328
- * </div>
329
- * );
330
- * ```
331
- */
332
- declare function useCollapsibleContent(content: string, options?: UseCollapsibleContentOptions): UseCollapsibleContentResult;
333
-
334
120
  interface MarkerData {
335
121
  id: string;
336
122
  longitude: number;
@@ -2249,267 +2035,6 @@ interface ChatRootProps {
2249
2035
  }
2250
2036
  declare function ChatRoot(props: ChatRootProps): react_jsx_runtime.JSX.Element;
2251
2037
 
2252
- declare const LazyChat: react.ComponentType<ChatRootProps>;
2253
-
2254
- /**
2255
- * Chat defaults and constants.
2256
- */
2257
- declare const STORAGE_KEYS: {
2258
- readonly mode: "djc-chat-mode";
2259
- readonly sidebarWidth: "djc-chat-sidebar-width";
2260
- readonly composerHistory: "djc-chat-composer-history";
2261
- };
2262
- declare const CSS_VARS: {
2263
- readonly reserve: "--djc-chat-reserve";
2264
- };
2265
- declare const DEFAULT_Z_INDEX = 9000;
2266
- declare const LIMITS: {
2267
- /** Max characters per single message. */
2268
- readonly messageMaxLength: 8000;
2269
- /** Max attachments per message. */
2270
- readonly attachmentsMax: 10;
2271
- /** Composer history slots. */
2272
- readonly composerHistorySize: 50;
2273
- /** Coalesce stream tokens within this window before dispatching. */
2274
- readonly streamCoalesceMs: 16;
2275
- /** Default history page size. */
2276
- readonly pageSize: 50;
2277
- /** Virtualize list when >= this many messages (host-controlled threshold). */
2278
- readonly virtualizeThreshold: 50;
2279
- /** SSE idle timeout. */
2280
- readonly sseIdleMs: 45000;
2281
- };
2282
- declare const DEFAULT_SIDEBAR: {
2283
- readonly width: 420;
2284
- readonly min: 320;
2285
- readonly max: 720;
2286
- };
2287
- declare const HOTKEYS: {
2288
- readonly send: "mod+enter";
2289
- readonly cancel: "esc";
2290
- readonly newChat: "mod+shift+n";
2291
- readonly toggleOpen: "mod+/";
2292
- readonly focusComposer: "mod+l";
2293
- };
2294
- declare const CHAT_EVENT_NAME = "djc:chat:send";
2295
- interface ChatEventDetail {
2296
- content: string;
2297
- sessionId?: string;
2298
- attachments?: unknown[];
2299
- metadata?: Record<string, unknown>;
2300
- }
2301
-
2302
- /**
2303
- * ID generation. Uses crypto.randomUUID when available with a fallback
2304
- * for older environments (and SSR bundles that may not have crypto).
2305
- */
2306
- declare function createId(prefix?: string): string;
2307
-
2308
- /**
2309
- * Token coalescer. Buffers stream tokens within a small time window before
2310
- * dispatching a single aggregated chunk. Prevents 60+ re-renders per second
2311
- * on fast streams.
2312
- */
2313
- interface TokenBuffer {
2314
- /** Append a delta. Returns immediately. */
2315
- push(delta: string): void;
2316
- /** Force flush and resolve any pending timer. */
2317
- flush(): void;
2318
- /** Stop accepting tokens; flush whatever is buffered. */
2319
- close(): void;
2320
- }
2321
- declare function createTokenBuffer(onFlush: (delta: string) => void, windowMs?: 16): TokenBuffer;
2322
-
2323
- declare function resolvePersona(message: Pick<ChatMessage, 'role' | 'sender'>, user?: ChatUserContext, assistant?: ChatAssistantContext): ChatPersona;
2324
- /** Compute initials for an avatar fallback. */
2325
- declare function deriveInitials(persona: ChatPersona, role?: string): string;
2326
-
2327
- /**
2328
- * HTTP + SSE transport. Default implementation for web hosts.
2329
- *
2330
- * Backend contract (see @dev/@refactoring7-chat/06-integration.md):
2331
- * POST /sessions → SessionInfo (JSON)
2332
- * GET /sessions/:id/history?cursor= → HistoryPage (JSON)
2333
- * POST /sessions/:id/messages → SSE stream of ChatStreamEvent
2334
- * POST /sessions/:id/messages/buffered → ChatMessage (JSON, fallback)
2335
- * DELETE /sessions/:id → 204
2336
- */
2337
-
2338
- interface HttpTransportConfig {
2339
- /** Base URL without trailing slash, e.g. '/api/chat' or 'https://api.example.com/v1/chat'. */
2340
- baseUrl: string;
2341
- /** Optional slug appended/forwarded as project identifier. */
2342
- slug?: string;
2343
- /** Returns headers applied to every request — e.g. Authorization. */
2344
- getAuthHeader?: () => Record<string, string> | Promise<Record<string, string>>;
2345
- /** Default fetch timeout (per non-streaming request). */
2346
- timeoutMs?: number;
2347
- /** Override fetch implementation (useful for tests or custom retry layers). */
2348
- fetchImpl?: typeof fetch;
2349
- }
2350
- declare function createHttpTransport(config: HttpTransportConfig): ChatTransport;
2351
-
2352
- /**
2353
- * In-memory chat transport for stories and tests. Replays scripted replies.
2354
- */
2355
-
2356
- interface MockTransportOptions {
2357
- /** Each entry is the assistant's reply for one user turn. Strings are split
2358
- * into chunks; arrays are taken as the exact event sequence (after a
2359
- * prepended `message_start` and before a synthetic `message_end`). */
2360
- replies?: Array<string | ChatStreamEvent[]>;
2361
- latencyMs?: number;
2362
- /** Initial history returned by `createSession`. */
2363
- initialMessages?: ChatMessage[];
2364
- shouldFail?: (attempt: number) => boolean;
2365
- }
2366
- declare function createMockTransport(opts?: MockTransportOptions): ChatTransport;
2367
-
2368
- /**
2369
- * Server-Sent Events parser as an AsyncGenerator.
2370
- *
2371
- * Yields parsed events from a `Response` body. Handles the split-read case
2372
- * where `event:` and `data:` arrive in separate TCP packets. Skips malformed
2373
- * JSON gracefully. Honors AbortSignal (caller passes one to fetch).
2374
- */
2375
-
2376
- interface RawEvent {
2377
- event?: string;
2378
- data?: string;
2379
- }
2380
- interface ParseSSEOptions {
2381
- signal?: AbortSignal;
2382
- /** Map a raw SSE event to zero, one, or many `ChatStreamEvent`s.
2383
- * Default: parse `data` as JSON and assume the JSON shape already
2384
- * matches `ChatStreamEvent`. */
2385
- map?: (raw: RawEvent) => ChatStreamEvent | ChatStreamEvent[] | null;
2386
- idleTimeoutMs?: number;
2387
- }
2388
- declare function parseSSE(response: Response, options?: ParseSSEOptions): AsyncGenerator<ChatStreamEvent, void, void>;
2389
-
2390
- /**
2391
- * Transport surface re-export. Lives in core so transport implementations
2392
- * never need to reach into the public types module.
2393
- */
2394
-
2395
- declare class TransportError extends Error {
2396
- code: string;
2397
- constructor(message: string, code?: string);
2398
- }
2399
-
2400
- /**
2401
- * Pydantic-AI SSE event mapper.
2402
- *
2403
- * Translates the event shape emitted by pydantic-AI–style Django backends
2404
- * (text_delta / tool_call / tool_result / done / error / approval_required)
2405
- * into the canonical `ChatStreamEvent` stream consumed by the Chat reducer.
2406
- *
2407
- * Backends that don't expose a stable `tool_call_id` are supported via a
2408
- * per-stream FIFO queue keyed by tool name. The earlier "Map<name, toolId>"
2409
- * approach lost the first toolId when a tool was invoked twice in one turn
2410
- * (e.g. `list_tasks` for search and again for confirmation) — using a queue
2411
- * keeps each call/result pair correctly matched.
2412
- */
2413
-
2414
- interface PydanticAIEvent {
2415
- type: 'text_delta' | 'tool_call' | 'tool_result' | 'done' | 'error' | 'approval_required';
2416
- delta?: string;
2417
- tool?: string;
2418
- args?: unknown;
2419
- result?: unknown;
2420
- /**
2421
- * Structured frontend payload — present on `tool_result` when the tool has
2422
- * a `result_schema`. The LLM sees only `result` (compact text); the
2423
- * frontend uses `data` to render rich UI (e.g. vehicle cards).
2424
- */
2425
- data?: unknown;
2426
- total_tokens?: number;
2427
- error?: string;
2428
- tool_call_id?: string;
2429
- session_id?: string;
2430
- }
2431
- /** Per-stream FIFO queue keyed by tool name. Created via `createToolIdQueue`. */
2432
- interface ToolIdQueue {
2433
- /** Allocate a new toolId for a `tool_call` event and enqueue it under `name`. */
2434
- push(name: string): string;
2435
- /** Pop the oldest toolId for `name` (or return an orphan marker if none). */
2436
- shift(name: string): string;
2437
- /** Reset all queues (e.g. on stream close). */
2438
- clear(): void;
2439
- }
2440
- declare function createToolIdQueue(): ToolIdQueue;
2441
- /**
2442
- * Translate a single pydantic-AI event into zero or more `ChatStreamEvent`s.
2443
- * Pass a `ToolIdQueue` shared across the lifetime of one stream so that
2444
- * `tool_call` / `tool_result` pairs match correctly.
2445
- */
2446
- declare function mapPydanticAIEvent(ev: PydanticAIEvent, toolIds: ToolIdQueue): Generator<ChatStreamEvent>;
2447
- /**
2448
- * Convenience factory: returns a `ParseSSEOptions['map']` callback that
2449
- * decodes raw SSE frames as `PydanticAIEvent` JSON and yields zero or
2450
- * more `ChatStreamEvent`s through `mapPydanticAIEvent`.
2451
- *
2452
- * Allocates an internal `ToolIdQueue` — call this once per stream.
2453
- */
2454
- declare function createPydanticAISSEMap(): NonNullable<ParseSSEOptions['map']>;
2455
-
2456
- /**
2457
- * High-level transport factory for pydantic-AI–style backends.
2458
- *
2459
- * Composes:
2460
- * - `parseSSE` for spec-compliant SSE framing (multi-line `data:`, comments, idle timeout).
2461
- * - `createPydanticAISSEMap` for normalizing pydantic-AI events into `ChatStreamEvent`.
2462
- *
2463
- * Use when your backend speaks the canonical pydantic-AI stream shape
2464
- * (`text_delta` / `tool_call` / `tool_result` / `done` / `error`).
2465
- * URL building, auth headers, history loading, and optional session
2466
- * bootstrapping are caller responsibilities — pass them in.
2467
- */
2468
-
2469
- interface PydanticAIChatTransportOpts {
2470
- /**
2471
- * Build the SSE stream URL for a user message turn.
2472
- * @example (sessionId, message) => `${base}/stream?session_id=${sessionId}&message=${encodeURIComponent(message)}`
2473
- */
2474
- buildStreamUrl: (sessionId: string, message: string) => string | URL;
2475
- /** Optional history loader. If omitted, `loadHistory` returns an empty page. */
2476
- loadHistory?: (sessionId: string, cursor?: string | null) => Promise<HistoryPage>;
2477
- /**
2478
- * Optional session bootstrap. Called from `createSession`. Useful for
2479
- * backends that need a `POST /sessions` round-trip or want to pre-seed
2480
- * history.
2481
- */
2482
- bootstrapSession?: (opts?: CreateSessionOptions) => Promise<SessionInfo>;
2483
- /** Optional session teardown. */
2484
- closeSession?: (sessionId: string) => Promise<void>;
2485
- /**
2486
- * Optional non-streaming send (for hosts that need a buffered fallback,
2487
- * e.g. when the user disables streaming). Defaults to throwing — most
2488
- * hosts only use streaming.
2489
- */
2490
- send?: (sessionId: string, content: string, options?: SendOptions) => Promise<ChatMessage>;
2491
- /** Request headers (Authorization, content-type, etc.). */
2492
- buildHeaders?: () => HeadersInit | Promise<HeadersInit>;
2493
- /** Override fetch (tests, retry layers). */
2494
- fetchImpl?: typeof fetch;
2495
- /**
2496
- * HTTP method for the stream request. Defaults to `'POST'` with
2497
- * `{ content, attachments, metadata }` JSON body. Set to `'GET'` if
2498
- * your backend embeds the message in the URL via `buildStreamUrl`.
2499
- */
2500
- streamMethod?: 'GET' | 'POST';
2501
- /** Idle timeout for the SSE connection, in ms. Forwarded to `parseSSE`. */
2502
- idleTimeoutMs?: number;
2503
- /**
2504
- * Side-channel for events that don't translate to `ChatStreamEvent`
2505
- * (e.g. `approval_required` — surfaces interactive prompts outside the
2506
- * normal message stream). Called synchronously while parsing the SSE
2507
- * frame; mutate caller-owned state, don't `await` long work here.
2508
- */
2509
- onPydanticEvent?: (event: PydanticAIEvent) => void;
2510
- }
2511
- declare function createPydanticAIChatTransport(opts: PydanticAIChatTransportOpts): ChatTransport;
2512
-
2513
2038
  type ChatFABPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
2514
2039
  type ChatFABVariant = 'simple' | 'animated' | 'glass';
2515
2040
  type ChatFABSize = 'sm' | 'md' | 'lg' | 'responsive';
@@ -3060,41 +2585,300 @@ type ChatPresencePhase = 'hidden' | 'entering' | 'visible' | 'leaving';
3060
2585
  declare function useChatPresence(open: boolean, exitDurationMs?: number): ChatPresencePhase;
3061
2586
 
3062
2587
  /**
3063
- * @deprecated Plan64. As of ui-tools 2.1.369, `<MessageList>` is
3064
- * virtualized via react-virtuoso and owns its own scroll viewport.
3065
- * Sticky-bottom + auto-follow on streaming live inside the component;
3066
- * use the new `MessageListProps.onAtBottomChange` prop and the
3067
- * `MessageListHandle.scrollToBottom()` imperative method instead.
3068
- *
3069
- * This hook is kept for hosts that render messages outside
3070
- * `<MessageList>` (e.g. headless story shells, custom non-virtualized
3071
- * scroll containers). It still works against any HTMLElement scroll
3072
- * container, but it does NOT integrate with Virtuoso — passing a
3073
- * Virtuoso-managed element here will read garbage scroll metrics.
2588
+ * Chat defaults and constants.
3074
2589
  */
3075
- interface UseChatScrollOptions {
3076
- containerRef: RefObject<HTMLElement | null>;
3077
- bottomRef: RefObject<HTMLElement | null>;
3078
- isStreaming?: boolean;
3079
- /** Distance from bottom (px) considered "at bottom". */
3080
- bottomThresholdPx?: number;
3081
- /** Bump key — increment when a new message arrives so the hook re-evaluates auto-scroll. */
3082
- messagesCount?: number;
3083
- }
3084
- interface UseChatScrollReturn {
3085
- isAtBottom: boolean;
3086
- unreadCount: number;
3087
- scrollToBottom: (smooth?: boolean) => void;
3088
- resetUnread: () => void;
3089
- }
3090
- declare function useChatScroll(options: UseChatScrollOptions): UseChatScrollReturn;
3091
-
3092
- interface UseChatHistoryOptions {
3093
- enabled?: boolean;
3094
- containerRef: RefObject<HTMLElement | null>;
3095
- topSentinelRef: RefObject<HTMLElement | null>;
3096
- hasMore: boolean;
3097
- isLoadingMore: boolean;
2590
+ declare const STORAGE_KEYS: {
2591
+ readonly mode: "djc-chat-mode";
2592
+ readonly sidebarWidth: "djc-chat-sidebar-width";
2593
+ readonly composerHistory: "djc-chat-composer-history";
2594
+ };
2595
+ declare const CSS_VARS: {
2596
+ readonly reserve: "--djc-chat-reserve";
2597
+ };
2598
+ declare const DEFAULT_Z_INDEX = 9000;
2599
+ declare const LIMITS: {
2600
+ /** Max characters per single message. */
2601
+ readonly messageMaxLength: 8000;
2602
+ /** Max attachments per message. */
2603
+ readonly attachmentsMax: 10;
2604
+ /** Composer history slots. */
2605
+ readonly composerHistorySize: 50;
2606
+ /** Coalesce stream tokens within this window before dispatching. */
2607
+ readonly streamCoalesceMs: 16;
2608
+ /** Default history page size. */
2609
+ readonly pageSize: 50;
2610
+ /** Virtualize list when >= this many messages (host-controlled threshold). */
2611
+ readonly virtualizeThreshold: 50;
2612
+ /** SSE idle timeout. */
2613
+ readonly sseIdleMs: 45000;
2614
+ };
2615
+ declare const DEFAULT_SIDEBAR: {
2616
+ readonly width: 420;
2617
+ readonly min: 320;
2618
+ readonly max: 720;
2619
+ };
2620
+ declare const HOTKEYS: {
2621
+ readonly send: "mod+enter";
2622
+ readonly cancel: "esc";
2623
+ readonly newChat: "mod+shift+n";
2624
+ readonly toggleOpen: "mod+/";
2625
+ readonly focusComposer: "mod+l";
2626
+ };
2627
+ declare const CHAT_EVENT_NAME = "djc:chat:send";
2628
+ interface ChatEventDetail {
2629
+ content: string;
2630
+ sessionId?: string;
2631
+ attachments?: unknown[];
2632
+ metadata?: Record<string, unknown>;
2633
+ }
2634
+
2635
+ /**
2636
+ * ID generation. Uses crypto.randomUUID when available with a fallback
2637
+ * for older environments (and SSR bundles that may not have crypto).
2638
+ */
2639
+ declare function createId(prefix?: string): string;
2640
+
2641
+ /**
2642
+ * Token coalescer. Buffers stream tokens within a small time window before
2643
+ * dispatching a single aggregated chunk. Prevents 60+ re-renders per second
2644
+ * on fast streams.
2645
+ */
2646
+ interface TokenBuffer {
2647
+ /** Append a delta. Returns immediately. */
2648
+ push(delta: string): void;
2649
+ /** Force flush and resolve any pending timer. */
2650
+ flush(): void;
2651
+ /** Stop accepting tokens; flush whatever is buffered. */
2652
+ close(): void;
2653
+ }
2654
+ declare function createTokenBuffer(onFlush: (delta: string) => void, windowMs?: 16): TokenBuffer;
2655
+
2656
+ declare function resolvePersona(message: Pick<ChatMessage, 'role' | 'sender'>, user?: ChatUserContext, assistant?: ChatAssistantContext): ChatPersona;
2657
+ /** Compute initials for an avatar fallback. */
2658
+ declare function deriveInitials(persona: ChatPersona, role?: string): string;
2659
+
2660
+ /**
2661
+ * HTTP + SSE transport. Default implementation for web hosts.
2662
+ *
2663
+ * Backend contract (see @dev/@refactoring7-chat/06-integration.md):
2664
+ * POST /sessions → SessionInfo (JSON)
2665
+ * GET /sessions/:id/history?cursor= → HistoryPage (JSON)
2666
+ * POST /sessions/:id/messages → SSE stream of ChatStreamEvent
2667
+ * POST /sessions/:id/messages/buffered → ChatMessage (JSON, fallback)
2668
+ * DELETE /sessions/:id → 204
2669
+ */
2670
+
2671
+ interface HttpTransportConfig {
2672
+ /** Base URL without trailing slash, e.g. '/api/chat' or 'https://api.example.com/v1/chat'. */
2673
+ baseUrl: string;
2674
+ /** Optional slug appended/forwarded as project identifier. */
2675
+ slug?: string;
2676
+ /** Returns headers applied to every request — e.g. Authorization. */
2677
+ getAuthHeader?: () => Record<string, string> | Promise<Record<string, string>>;
2678
+ /** Default fetch timeout (per non-streaming request). */
2679
+ timeoutMs?: number;
2680
+ /** Override fetch implementation (useful for tests or custom retry layers). */
2681
+ fetchImpl?: typeof fetch;
2682
+ }
2683
+ declare function createHttpTransport(config: HttpTransportConfig): ChatTransport;
2684
+
2685
+ /**
2686
+ * In-memory chat transport for stories and tests. Replays scripted replies.
2687
+ */
2688
+
2689
+ interface MockTransportOptions {
2690
+ /** Each entry is the assistant's reply for one user turn. Strings are split
2691
+ * into chunks; arrays are taken as the exact event sequence (after a
2692
+ * prepended `message_start` and before a synthetic `message_end`). */
2693
+ replies?: Array<string | ChatStreamEvent[]>;
2694
+ latencyMs?: number;
2695
+ /** Initial history returned by `createSession`. */
2696
+ initialMessages?: ChatMessage[];
2697
+ shouldFail?: (attempt: number) => boolean;
2698
+ }
2699
+ declare function createMockTransport(opts?: MockTransportOptions): ChatTransport;
2700
+
2701
+ /**
2702
+ * Server-Sent Events parser as an AsyncGenerator.
2703
+ *
2704
+ * Yields parsed events from a `Response` body. Handles the split-read case
2705
+ * where `event:` and `data:` arrive in separate TCP packets. Skips malformed
2706
+ * JSON gracefully. Honors AbortSignal (caller passes one to fetch).
2707
+ */
2708
+
2709
+ interface RawEvent {
2710
+ event?: string;
2711
+ data?: string;
2712
+ }
2713
+ interface ParseSSEOptions {
2714
+ signal?: AbortSignal;
2715
+ /** Map a raw SSE event to zero, one, or many `ChatStreamEvent`s.
2716
+ * Default: parse `data` as JSON and assume the JSON shape already
2717
+ * matches `ChatStreamEvent`. */
2718
+ map?: (raw: RawEvent) => ChatStreamEvent | ChatStreamEvent[] | null;
2719
+ idleTimeoutMs?: number;
2720
+ }
2721
+ declare function parseSSE(response: Response, options?: ParseSSEOptions): AsyncGenerator<ChatStreamEvent, void, void>;
2722
+
2723
+ /**
2724
+ * Transport surface re-export. Lives in core so transport implementations
2725
+ * never need to reach into the public types module.
2726
+ */
2727
+
2728
+ declare class TransportError extends Error {
2729
+ code: string;
2730
+ constructor(message: string, code?: string);
2731
+ }
2732
+
2733
+ /**
2734
+ * Pydantic-AI SSE event mapper.
2735
+ *
2736
+ * Translates the event shape emitted by pydantic-AI–style Django backends
2737
+ * (text_delta / tool_call / tool_result / done / error / approval_required)
2738
+ * into the canonical `ChatStreamEvent` stream consumed by the Chat reducer.
2739
+ *
2740
+ * Backends that don't expose a stable `tool_call_id` are supported via a
2741
+ * per-stream FIFO queue keyed by tool name. The earlier "Map<name, toolId>"
2742
+ * approach lost the first toolId when a tool was invoked twice in one turn
2743
+ * (e.g. `list_tasks` for search and again for confirmation) — using a queue
2744
+ * keeps each call/result pair correctly matched.
2745
+ */
2746
+
2747
+ interface PydanticAIEvent {
2748
+ type: 'text_delta' | 'tool_call' | 'tool_result' | 'done' | 'error' | 'approval_required';
2749
+ delta?: string;
2750
+ tool?: string;
2751
+ args?: unknown;
2752
+ result?: unknown;
2753
+ /**
2754
+ * Structured frontend payload — present on `tool_result` when the tool has
2755
+ * a `result_schema`. The LLM sees only `result` (compact text); the
2756
+ * frontend uses `data` to render rich UI (e.g. vehicle cards).
2757
+ */
2758
+ data?: unknown;
2759
+ total_tokens?: number;
2760
+ error?: string;
2761
+ tool_call_id?: string;
2762
+ session_id?: string;
2763
+ }
2764
+ /** Per-stream FIFO queue keyed by tool name. Created via `createToolIdQueue`. */
2765
+ interface ToolIdQueue {
2766
+ /** Allocate a new toolId for a `tool_call` event and enqueue it under `name`. */
2767
+ push(name: string): string;
2768
+ /** Pop the oldest toolId for `name` (or return an orphan marker if none). */
2769
+ shift(name: string): string;
2770
+ /** Reset all queues (e.g. on stream close). */
2771
+ clear(): void;
2772
+ }
2773
+ declare function createToolIdQueue(): ToolIdQueue;
2774
+ /**
2775
+ * Translate a single pydantic-AI event into zero or more `ChatStreamEvent`s.
2776
+ * Pass a `ToolIdQueue` shared across the lifetime of one stream so that
2777
+ * `tool_call` / `tool_result` pairs match correctly.
2778
+ */
2779
+ declare function mapPydanticAIEvent(ev: PydanticAIEvent, toolIds: ToolIdQueue): Generator<ChatStreamEvent>;
2780
+ /**
2781
+ * Convenience factory: returns a `ParseSSEOptions['map']` callback that
2782
+ * decodes raw SSE frames as `PydanticAIEvent` JSON and yields zero or
2783
+ * more `ChatStreamEvent`s through `mapPydanticAIEvent`.
2784
+ *
2785
+ * Allocates an internal `ToolIdQueue` — call this once per stream.
2786
+ */
2787
+ declare function createPydanticAISSEMap(): NonNullable<ParseSSEOptions['map']>;
2788
+
2789
+ /**
2790
+ * High-level transport factory for pydantic-AI–style backends.
2791
+ *
2792
+ * Composes:
2793
+ * - `parseSSE` for spec-compliant SSE framing (multi-line `data:`, comments, idle timeout).
2794
+ * - `createPydanticAISSEMap` for normalizing pydantic-AI events into `ChatStreamEvent`.
2795
+ *
2796
+ * Use when your backend speaks the canonical pydantic-AI stream shape
2797
+ * (`text_delta` / `tool_call` / `tool_result` / `done` / `error`).
2798
+ * URL building, auth headers, history loading, and optional session
2799
+ * bootstrapping are caller responsibilities — pass them in.
2800
+ */
2801
+
2802
+ interface PydanticAIChatTransportOpts {
2803
+ /**
2804
+ * Build the SSE stream URL for a user message turn.
2805
+ * @example (sessionId, message) => `${base}/stream?session_id=${sessionId}&message=${encodeURIComponent(message)}`
2806
+ */
2807
+ buildStreamUrl: (sessionId: string, message: string) => string | URL;
2808
+ /** Optional history loader. If omitted, `loadHistory` returns an empty page. */
2809
+ loadHistory?: (sessionId: string, cursor?: string | null) => Promise<HistoryPage>;
2810
+ /**
2811
+ * Optional session bootstrap. Called from `createSession`. Useful for
2812
+ * backends that need a `POST /sessions` round-trip or want to pre-seed
2813
+ * history.
2814
+ */
2815
+ bootstrapSession?: (opts?: CreateSessionOptions) => Promise<SessionInfo>;
2816
+ /** Optional session teardown. */
2817
+ closeSession?: (sessionId: string) => Promise<void>;
2818
+ /**
2819
+ * Optional non-streaming send (for hosts that need a buffered fallback,
2820
+ * e.g. when the user disables streaming). Defaults to throwing — most
2821
+ * hosts only use streaming.
2822
+ */
2823
+ send?: (sessionId: string, content: string, options?: SendOptions) => Promise<ChatMessage>;
2824
+ /** Request headers (Authorization, content-type, etc.). */
2825
+ buildHeaders?: () => HeadersInit | Promise<HeadersInit>;
2826
+ /** Override fetch (tests, retry layers). */
2827
+ fetchImpl?: typeof fetch;
2828
+ /**
2829
+ * HTTP method for the stream request. Defaults to `'POST'` with
2830
+ * `{ content, attachments, metadata }` JSON body. Set to `'GET'` if
2831
+ * your backend embeds the message in the URL via `buildStreamUrl`.
2832
+ */
2833
+ streamMethod?: 'GET' | 'POST';
2834
+ /** Idle timeout for the SSE connection, in ms. Forwarded to `parseSSE`. */
2835
+ idleTimeoutMs?: number;
2836
+ /**
2837
+ * Side-channel for events that don't translate to `ChatStreamEvent`
2838
+ * (e.g. `approval_required` — surfaces interactive prompts outside the
2839
+ * normal message stream). Called synchronously while parsing the SSE
2840
+ * frame; mutate caller-owned state, don't `await` long work here.
2841
+ */
2842
+ onPydanticEvent?: (event: PydanticAIEvent) => void;
2843
+ }
2844
+ declare function createPydanticAIChatTransport(opts: PydanticAIChatTransportOpts): ChatTransport;
2845
+
2846
+ /**
2847
+ * @deprecated Plan64. As of ui-tools 2.1.369, `<MessageList>` is
2848
+ * virtualized via react-virtuoso and owns its own scroll viewport.
2849
+ * Sticky-bottom + auto-follow on streaming live inside the component;
2850
+ * use the new `MessageListProps.onAtBottomChange` prop and the
2851
+ * `MessageListHandle.scrollToBottom()` imperative method instead.
2852
+ *
2853
+ * This hook is kept for hosts that render messages outside
2854
+ * `<MessageList>` (e.g. headless story shells, custom non-virtualized
2855
+ * scroll containers). It still works against any HTMLElement scroll
2856
+ * container, but it does NOT integrate with Virtuoso — passing a
2857
+ * Virtuoso-managed element here will read garbage scroll metrics.
2858
+ */
2859
+ interface UseChatScrollOptions {
2860
+ containerRef: RefObject<HTMLElement | null>;
2861
+ bottomRef: RefObject<HTMLElement | null>;
2862
+ isStreaming?: boolean;
2863
+ /** Distance from bottom (px) considered "at bottom". */
2864
+ bottomThresholdPx?: number;
2865
+ /** Bump key — increment when a new message arrives so the hook re-evaluates auto-scroll. */
2866
+ messagesCount?: number;
2867
+ }
2868
+ interface UseChatScrollReturn {
2869
+ isAtBottom: boolean;
2870
+ unreadCount: number;
2871
+ scrollToBottom: (smooth?: boolean) => void;
2872
+ resetUnread: () => void;
2873
+ }
2874
+ declare function useChatScroll(options: UseChatScrollOptions): UseChatScrollReturn;
2875
+
2876
+ interface UseChatHistoryOptions {
2877
+ enabled?: boolean;
2878
+ containerRef: RefObject<HTMLElement | null>;
2879
+ topSentinelRef: RefObject<HTMLElement | null>;
2880
+ hasMore: boolean;
2881
+ isLoadingMore: boolean;
3098
2882
  loadMore: () => Promise<void>;
3099
2883
  }
3100
2884
  /** Triggers `loadMore` when the top sentinel enters the container's viewport.
@@ -3419,6 +3203,101 @@ declare function isGeoJSONFeatureCollection(v: unknown): v is {
3419
3203
  };
3420
3204
  declare function isStringValue(v: unknown): v is string;
3421
3205
 
3206
+ /**
3207
+ * Chat dev logger.
3208
+ *
3209
+ * A thin namespaced wrapper over `consola` that no-ops in production unless
3210
+ * the host app explicitly opts in via `<ChatRoot debug />`. The default
3211
+ * detection uses `isDev` from `@djangocfg/ui-core/lib/env` (NODE_ENV).
3212
+ *
3213
+ * Why a dedicated module: chat is async and event-heavy (bootstrap, transport,
3214
+ * SSE chunks, tool calls, regenerate, …). Inline `console.log`s rot fast and
3215
+ * leak into prod. A single `getChatLogger()` call gives every layer the same
3216
+ * namespaced sub-logger and keeps zero-cost gating in one place.
3217
+ *
3218
+ * Sub-loggers:
3219
+ * bootstrap — initial session bootstrap (createSession / loadHistory)
3220
+ * transport — outbound transport calls + responses
3221
+ * stream — SSE chunk / tool / message_end events
3222
+ * lifecycle — sendMessage, regenerate, newSession, edits
3223
+ * tools — tool_call_start / _delta / _end specifics
3224
+ * error — caught errors (always emitted as `error` level)
3225
+ */
3226
+
3227
+ type ChatLogScope = 'bootstrap' | 'transport' | 'stream' | 'lifecycle' | 'tools' | 'error';
3228
+ interface ChatLogger {
3229
+ bootstrap: ConsolaInstance;
3230
+ transport: ConsolaInstance;
3231
+ stream: ConsolaInstance;
3232
+ lifecycle: ConsolaInstance;
3233
+ tools: ConsolaInstance;
3234
+ error: ConsolaInstance;
3235
+ /** True when this logger is actually emitting (host opted in or NODE_ENV=development). */
3236
+ enabled: boolean;
3237
+ }
3238
+ /**
3239
+ * Get the chat logger.
3240
+ * @param debug Explicit override from the host. `undefined` falls back to `isDev`.
3241
+ */
3242
+ declare function getChatLogger(debug?: boolean): ChatLogger;
3243
+
3244
+ /**
3245
+ * sanitizeDraft — minimal pre-submit cleanup for chat-composer drafts.
3246
+ *
3247
+ * Mirrors the conservative behaviour ChatGPT / Claude / Telegram
3248
+ * actually ship: clean the obvious junk the user didn't intend to
3249
+ * send, touch nothing that *could* be intentional.
3250
+ *
3251
+ * **What we DO touch:**
3252
+ *
3253
+ * 1. Trim leading/trailing whitespace (spaces, tabs, newlines,
3254
+ * NBSP). The user typing `\n\n hello \n` meant `hello`.
3255
+ * 2. Normalise line endings — `\r\n` / `\r` → `\n`. Pasted Windows
3256
+ * / old-mac text gets the same internal shape, so the LLM
3257
+ * tokeniser and markdown renderer see one canonical form.
3258
+ * 3. Strip zero-width / invisible characters that web-paste
3259
+ * smuggles in: ZWSP (U+200B), ZWNJ (U+200C), ZWJ (U+200D),
3260
+ * BOM / ZWNBSP (U+FEFF). They're invisible, break LLM
3261
+ * tokenisation, and the user never meant to type them.
3262
+ *
3263
+ * **What we DO NOT touch (and why):**
3264
+ *
3265
+ * - **Internal whitespace runs** (3+ spaces, tabs, blank lines).
3266
+ * Code indentation depends on these. ChatGPT preserves them as
3267
+ * typed — " if (x):\n return" stays four-space-indented.
3268
+ * Collapsing them is the path to subtly broken code snippets.
3269
+ *
3270
+ * - **Bidi override marks** (U+200E LRM, U+200F RLM, U+202A..U+202E).
3271
+ * Legitimately used in Arabic / Hebrew / mixed-direction text.
3272
+ * Stripping silently breaks RTL users. If a specific deployment
3273
+ * wants to block them as a security measure, do it at that layer
3274
+ * with explicit user-visible feedback.
3275
+ *
3276
+ * - **Tabs vs spaces** beyond rule 1. Could be either code or
3277
+ * prose; without parsing markdown we can't tell.
3278
+ *
3279
+ * - **Emoji, mentions, URLs, code spans** — passthrough text.
3280
+ *
3281
+ * The function is intentionally tiny — every rule earns its keep
3282
+ * with a concrete "user pasted X from Y, got nonsense" story.
3283
+ *
3284
+ * **Idempotent**: `sanitizeDraft(sanitizeDraft(x)) === sanitizeDraft(x)`.
3285
+ */
3286
+ declare function sanitizeDraft(input: string): string;
3287
+ /**
3288
+ * Convenience predicate: true when the draft is non-empty AFTER
3289
+ * sanitation. Use to gate Send buttons / Enter submits so an empty
3290
+ * or whitespace-only draft never produces a real message.
3291
+ *
3292
+ * Cheaper than sanitizeDraft(input).length > 0 only marginally —
3293
+ * we still allocate the cleaned string. Kept as a named helper for
3294
+ * call-site clarity.
3295
+ */
3296
+ declare function isSubmittableDraft(input: string): boolean;
3297
+
3298
+ /** Walk the conversation and collect image attachments in chronological order. */
3299
+ declare function collectImageAttachments(messages: ChatMessage[]): ChatAttachment[];
3300
+
3422
3301
  /**
3423
3302
  * Chat color tokens — single source of truth.
3424
3303
  *
@@ -3511,122 +3390,27 @@ interface ChatBubbleStyles {
3511
3390
  */
3512
3391
  declare function useChatBubbleStyles(role: 'user' | 'assistant' | 'system', isError: boolean): ChatBubbleStyles;
3513
3392
  interface ChatRoleStyles {
3514
- anchor: string;
3515
- toggle: string;
3516
- }
3517
- /**
3518
- * Lightweight variant when only role matters (no error state, no surface).
3519
- * Use in shared markdown renderers that don't know about bubble background.
3520
- */
3521
- declare function useChatRoleStyles(isUser: boolean): ChatRoleStyles;
3522
- interface ChatDestructiveStyles {
3523
- banner: string;
3524
- hover: string;
3525
- hoverStrong: string;
3526
- text: string;
3527
- menuItem: string;
3528
- toolErrorText: string;
3529
- }
3530
- /**
3531
- * Destructive (delete / error) class facade. Hook form keeps the API
3532
- * symmetric with the others; under the hood it returns a frozen object.
3533
- */
3534
- declare function useChatDestructiveStyles(): ChatDestructiveStyles;
3535
-
3536
- /** Walk the conversation and collect image attachments in chronological order. */
3537
- declare function collectImageAttachments(messages: ChatMessage[]): ChatAttachment[];
3538
-
3539
- /**
3540
- * sanitizeDraft — minimal pre-submit cleanup for chat-composer drafts.
3541
- *
3542
- * Mirrors the conservative behaviour ChatGPT / Claude / Telegram
3543
- * actually ship: clean the obvious junk the user didn't intend to
3544
- * send, touch nothing that *could* be intentional.
3545
- *
3546
- * **What we DO touch:**
3547
- *
3548
- * 1. Trim leading/trailing whitespace (spaces, tabs, newlines,
3549
- * NBSP). The user typing `\n\n hello \n` meant `hello`.
3550
- * 2. Normalise line endings — `\r\n` / `\r` → `\n`. Pasted Windows
3551
- * / old-mac text gets the same internal shape, so the LLM
3552
- * tokeniser and markdown renderer see one canonical form.
3553
- * 3. Strip zero-width / invisible characters that web-paste
3554
- * smuggles in: ZWSP (U+200B), ZWNJ (U+200C), ZWJ (U+200D),
3555
- * BOM / ZWNBSP (U+FEFF). They're invisible, break LLM
3556
- * tokenisation, and the user never meant to type them.
3557
- *
3558
- * **What we DO NOT touch (and why):**
3559
- *
3560
- * - **Internal whitespace runs** (3+ spaces, tabs, blank lines).
3561
- * Code indentation depends on these. ChatGPT preserves them as
3562
- * typed — " if (x):\n return" stays four-space-indented.
3563
- * Collapsing them is the path to subtly broken code snippets.
3564
- *
3565
- * - **Bidi override marks** (U+200E LRM, U+200F RLM, U+202A..U+202E).
3566
- * Legitimately used in Arabic / Hebrew / mixed-direction text.
3567
- * Stripping silently breaks RTL users. If a specific deployment
3568
- * wants to block them as a security measure, do it at that layer
3569
- * with explicit user-visible feedback.
3570
- *
3571
- * - **Tabs vs spaces** beyond rule 1. Could be either code or
3572
- * prose; without parsing markdown we can't tell.
3573
- *
3574
- * - **Emoji, mentions, URLs, code spans** — passthrough text.
3575
- *
3576
- * The function is intentionally tiny — every rule earns its keep
3577
- * with a concrete "user pasted X from Y, got nonsense" story.
3578
- *
3579
- * **Idempotent**: `sanitizeDraft(sanitizeDraft(x)) === sanitizeDraft(x)`.
3580
- */
3581
- declare function sanitizeDraft(input: string): string;
3582
- /**
3583
- * Convenience predicate: true when the draft is non-empty AFTER
3584
- * sanitation. Use to gate Send buttons / Enter submits so an empty
3585
- * or whitespace-only draft never produces a real message.
3586
- *
3587
- * Cheaper than sanitizeDraft(input).length > 0 only marginally —
3588
- * we still allocate the cleaned string. Kept as a named helper for
3589
- * call-site clarity.
3590
- */
3591
- declare function isSubmittableDraft(input: string): boolean;
3592
-
3593
- /**
3594
- * Chat dev logger.
3595
- *
3596
- * A thin namespaced wrapper over `consola` that no-ops in production unless
3597
- * the host app explicitly opts in via `<ChatRoot debug />`. The default
3598
- * detection uses `isDev` from `@djangocfg/ui-core/lib/env` (NODE_ENV).
3599
- *
3600
- * Why a dedicated module: chat is async and event-heavy (bootstrap, transport,
3601
- * SSE chunks, tool calls, regenerate, …). Inline `console.log`s rot fast and
3602
- * leak into prod. A single `getChatLogger()` call gives every layer the same
3603
- * namespaced sub-logger and keeps zero-cost gating in one place.
3604
- *
3605
- * Sub-loggers:
3606
- * bootstrap — initial session bootstrap (createSession / loadHistory)
3607
- * transport — outbound transport calls + responses
3608
- * stream — SSE chunk / tool / message_end events
3609
- * lifecycle — sendMessage, regenerate, newSession, edits
3610
- * tools — tool_call_start / _delta / _end specifics
3611
- * error — caught errors (always emitted as `error` level)
3393
+ anchor: string;
3394
+ toggle: string;
3395
+ }
3396
+ /**
3397
+ * Lightweight variant when only role matters (no error state, no surface).
3398
+ * Use in shared markdown renderers that don't know about bubble background.
3612
3399
  */
3613
-
3614
- type ChatLogScope = 'bootstrap' | 'transport' | 'stream' | 'lifecycle' | 'tools' | 'error';
3615
- interface ChatLogger {
3616
- bootstrap: ConsolaInstance;
3617
- transport: ConsolaInstance;
3618
- stream: ConsolaInstance;
3619
- lifecycle: ConsolaInstance;
3620
- tools: ConsolaInstance;
3621
- error: ConsolaInstance;
3622
- /** True when this logger is actually emitting (host opted in or NODE_ENV=development). */
3623
- enabled: boolean;
3400
+ declare function useChatRoleStyles(isUser: boolean): ChatRoleStyles;
3401
+ interface ChatDestructiveStyles {
3402
+ banner: string;
3403
+ hover: string;
3404
+ hoverStrong: string;
3405
+ text: string;
3406
+ menuItem: string;
3407
+ toolErrorText: string;
3624
3408
  }
3625
3409
  /**
3626
- * Get the chat logger.
3627
- * @param debug Explicit override from the host. `undefined` falls back to `isDev`.
3410
+ * Destructive (delete / error) class facade. Hook form keeps the API
3411
+ * symmetric with the others; under the hood it returns a frozen object.
3628
3412
  */
3629
- declare function getChatLogger(debug?: boolean): ChatLogger;
3413
+ declare function useChatDestructiveStyles(): ChatDestructiveStyles;
3630
3414
 
3631
3415
  interface MessageListProps {
3632
3416
  messages?: ChatMessage[];
@@ -3836,6 +3620,203 @@ interface AudioToggleProps {
3836
3620
  }
3837
3621
  declare function AudioToggle({ size, variant, alwaysShow, className, }: AudioToggleProps): react_jsx_runtime.JSX.Element;
3838
3622
 
3623
+ declare const LazyChat: react.ComponentType<ChatRootProps>;
3624
+
3625
+ /**
3626
+ * Declarative rule for handling a custom URL scheme inside markdown.
3627
+ *
3628
+ * Each rule owns one href shape (e.g. `cmdop://machine/<uuid>`,
3629
+ * `obsidian://open?path=…`) and decides:
3630
+ *
3631
+ * 1. Whether the URL scheme survives sanitize (`protocols`).
3632
+ * 2. How to massage the source markdown before render
3633
+ * (`preprocess` — optional; useful for stripping decorative
3634
+ * prefixes like the `@` in `@[label](href)` so the chip alone
3635
+ * reads as the mention indicator).
3636
+ * 3. Which links it owns (`match`), and how to render them
3637
+ * (`render`, returning JSX).
3638
+ *
3639
+ * Rules compose: pass an array, and the renderer iterates top-to-bottom
3640
+ * picking the first `match` hit per `<a>`. Anything no rule claims
3641
+ * falls through to the built-in chat-link styling (or to a custom
3642
+ * `customComponents.a` if both are provided).
3643
+ *
3644
+ * Prefer `linkRules` over `customComponents` + `extraHrefProtocols` —
3645
+ * it's the same pieces with the boilerplate removed.
3646
+ */
3647
+ interface LinkRule {
3648
+ /** Pre-process the raw markdown source before any rendering happens.
3649
+ * Pure / synchronous; identity-return when no transform applies. */
3650
+ preprocess?: (source: string) => string;
3651
+ /** Predicate against the resolved href. */
3652
+ match: (href: string) => boolean;
3653
+ /** Render the link this rule owns. `children` is the link's label
3654
+ * (markdown-rendered React content). */
3655
+ render: (props: {
3656
+ href: string;
3657
+ children: react__default.ReactNode;
3658
+ isUser: boolean;
3659
+ }) => react__default.ReactNode;
3660
+ /** URL scheme(s) to whitelist on the sanitize side, e.g. `['cmdop']`.
3661
+ * Bare schemes only — no `://`. Optional; omit for `http(s)` rules. */
3662
+ protocols?: readonly string[];
3663
+ /** Diagnostic label, surfaced in dev warnings. Optional. */
3664
+ name?: string;
3665
+ }
3666
+ interface MarkdownMessageProps {
3667
+ /** Markdown content to render */
3668
+ content: string;
3669
+ /** Additional CSS classes */
3670
+ className?: string;
3671
+ /** Whether the message is from the user (affects styling) */
3672
+ isUser?: boolean;
3673
+ /** Use compact size (text-xs instead of text-sm) */
3674
+ isCompact?: boolean;
3675
+ /**
3676
+ * Force the plain-text rendering path (single `<div>` with
3677
+ * `white-space: pre-wrap`, no ReactMarkdown). Use this for
3678
+ * user-authored content where markdown shouldn't be parsed.
3679
+ *
3680
+ * When `undefined` (default) we run a small heuristic
3681
+ * (`looksLikePlainProse`): short single-paragraph text without
3682
+ * markdown markers → plain; everything else → ReactMarkdown.
3683
+ *
3684
+ * Pass an explicit `true` / `false` to opt out of the heuristic
3685
+ * entirely.
3686
+ */
3687
+ plainText?: boolean;
3688
+ /**
3689
+ * Per-tag overrides merged on top of the built-in renderers.
3690
+ *
3691
+ * Use this when you need custom rendering for a specific tag without
3692
+ * losing the chat-tuned defaults (links, code blocks with copy, etc).
3693
+ *
3694
+ * For custom URL-scheme link handling, prefer `linkRules` — it's the
3695
+ * same ergonomics with the per-consumer boilerplate removed.
3696
+ */
3697
+ customComponents?: Partial<Components>;
3698
+ /**
3699
+ * Extra URL protocols allowed in `<a href>` after sanitize.
3700
+ *
3701
+ * The default schema strips anything that isn't
3702
+ * `http(s)/mailto/xmpp/irc(s)` — your custom renderer would receive
3703
+ * `href={undefined}` for `cmdop://…` / `obsidian://…` etc. Listing
3704
+ * the bare scheme here (e.g. `'cmdop'`, NOT `'cmdop://'`) opts it in.
3705
+ *
3706
+ * Use carefully: every protocol you add increases what the rendered
3707
+ * HTML can do via clicks. Stick to schemes you control.
3708
+ */
3709
+ extraHrefProtocols?: readonly string[];
3710
+ /**
3711
+ * Declarative link rules — preferred over `customComponents` +
3712
+ * `extraHrefProtocols` for chat-style apps that want pluggable
3713
+ * URL-scheme handling without re-implementing the custom-`a`
3714
+ * boilerplate per consumer.
3715
+ *
3716
+ * If you provide both `linkRules` and `extraHrefProtocols`, the
3717
+ * effective protocol list is the union of the two.
3718
+ */
3719
+ linkRules?: readonly LinkRule[];
3720
+ /**
3721
+ * Enable collapsible "Read more..." functionality
3722
+ * @default false
3723
+ */
3724
+ collapsible?: boolean;
3725
+ /** Maximum character length before showing "Read more...". */
3726
+ maxLength?: number;
3727
+ /** Maximum number of lines before showing "Read more...". */
3728
+ maxLines?: number;
3729
+ /** Custom "Read more" button text. @default "Read more..." */
3730
+ readMoreLabel?: string;
3731
+ /** Custom "Show less" button text. @default "Show less" */
3732
+ showLessLabel?: string;
3733
+ /** Start expanded (only when `collapsible` is true). @default false */
3734
+ defaultExpanded?: boolean;
3735
+ /** Callback when collapsed state changes */
3736
+ onCollapseChange?: (isCollapsed: boolean) => void;
3737
+ }
3738
+
3739
+ /**
3740
+ * MarkdownMessage — chat-tuned markdown renderer.
3741
+ *
3742
+ * Features:
3743
+ * - GitHub Flavored Markdown (GFM) via remark-gfm
3744
+ * - Syntax-highlighted code blocks with Copy button
3745
+ * - Mermaid diagram rendering (` ```mermaid ` fence)
3746
+ * - Tables, lists, blockquotes scaled for chat density
3747
+ * - User vs assistant styling modes (`isUser`)
3748
+ * - Plain-text fast path: skips ReactMarkdown when content has no
3749
+ * markdown syntax (cheaper render, preserves newlines via CSS)
3750
+ * - Optional collapsible "Read more..." for long messages
3751
+ *
3752
+ * Custom URL schemes (chat mentions, deep-links, custom file viewers)
3753
+ * are best handled with the declarative `linkRules` prop — see the
3754
+ * type definition in `./types.ts` and the storybook for examples.
3755
+ *
3756
+ * @example
3757
+ * ```tsx
3758
+ * <MarkdownMessage content="# Hello\n\nThis is **bold** text." />
3759
+ *
3760
+ * // User message styling
3761
+ * <MarkdownMessage content="Some content" isUser />
3762
+ *
3763
+ * // Custom URL scheme via linkRules
3764
+ * <MarkdownMessage
3765
+ * content="Talk to [Vps-audi](cmdop://machine/abc-123)"
3766
+ * linkRules={[machineMentionRule]}
3767
+ * />
3768
+ * ```
3769
+ *
3770
+ * Memoised: re-renders only when props change. `content` is the main
3771
+ * trigger — all other props (className, isUser, isCompact, etc.) are
3772
+ * compared by value/reference. `onCollapseChange` is compared by
3773
+ * reference — callers should stabilise it with useCallback.
3774
+ */
3775
+ declare function MarkdownMessageRaw({ content, className, isUser, isCompact, plainText, customComponents, extraHrefProtocols, linkRules, collapsible, maxLength, maxLines, readMoreLabel, showLessLabel, defaultExpanded, onCollapseChange, }: MarkdownMessageProps): react_jsx_runtime.JSX.Element;
3776
+ declare const MarkdownMessage: react__default.MemoExoticComponent<typeof MarkdownMessageRaw>;
3777
+
3778
+ /** Recursively concatenate the text content of a React.ReactNode tree.
3779
+ * Used by the markdown renderers (e.g. `<pre>` extracting code) and
3780
+ * by consumers that need a plain-string label out of link children. */
3781
+ declare function extractTextFromChildren(children: react__default.ReactNode): string;
3782
+
3783
+ interface ActionRowProps {
3784
+ /** Raw text to copy — pass the same source string used for render. */
3785
+ value: string;
3786
+ /** Bubble side. Just controls flex alignment; nothing is mirrored. */
3787
+ isUser: boolean;
3788
+ /**
3789
+ * Whether the row is currently shown. Owner-controlled (typically
3790
+ * `<ChatMessageRow>` toggles this on hover with a small close delay).
3791
+ * The component is intentionally dumb about visibility — owners
3792
+ * have full control over reveal logic (hover, focus, always-on,
3793
+ * touch behaviour, etc.).
3794
+ */
3795
+ visible: boolean;
3796
+ }
3797
+ declare function ActionRowRaw({ value, isUser, visible }: ActionRowProps): react_jsx_runtime.JSX.Element;
3798
+ declare const ActionRow: react__default.MemoExoticComponent<typeof ActionRowRaw>;
3799
+
3800
+ interface ChatMessageRowProps {
3801
+ /** Side of the conversation — drives flex alignment and `isUser`
3802
+ * passed to `actions`. */
3803
+ isUser: boolean;
3804
+ /** The bubble (your own JSX). Anything goes — `<MarkdownMessage>`,
3805
+ * custom card, multi-element composition. */
3806
+ children: react__default.ReactNode;
3807
+ /** Render-prop for the action row. Receives `visible` so the row
3808
+ * knows when to fade in/out. Render `null` to opt out. */
3809
+ actions?: (visible: boolean, isUser: boolean) => react__default.ReactNode;
3810
+ /** Close delay in ms after the cursor leaves the row. Long enough
3811
+ * to bridge cursor travel from bubble → action button without
3812
+ * flicker. Default 250ms (Radix Tooltip-ish). */
3813
+ closeDelayMs?: number;
3814
+ /** Optional class on the column container. */
3815
+ className?: string;
3816
+ }
3817
+ declare function ChatMessageRowRaw({ isUser, children, actions, closeDelayMs, className, }: ChatMessageRowProps): react_jsx_runtime.JSX.Element;
3818
+ declare const ChatMessageRow: react__default.MemoExoticComponent<typeof ChatMessageRowRaw>;
3819
+
3839
3820
  /**
3840
3821
  * PrettyCode Component - Dynamic Import Wrapper
3841
3822
  *
@@ -4889,4 +4870,60 @@ declare function useBlobUrlCleanup(key: string | null): void;
4889
4870
  */
4890
4871
  declare function generateContentKey(content: ArrayBuffer): string;
4891
4872
 
4892
- export { ANCHOR, type ApiKey, ArrayFieldItemTemplate, ArrayFieldTemplate, type AspectRatioValue, type AttachmentRenderer, type AttachmentRendererArgs, type AttachmentRendererMap, Attachments, AttachmentsGrid, type AttachmentsGridProps, AttachmentsList, type AttachmentsListProps, type AttachmentsProps, Player as AudioPlayer, type PlayerProps as AudioPlayerProps, AudioToggle, type AudioToggleProps, BUBBLE_SURFACE, BaseInputTemplate, type BlobSource, CHAT_EVENT_NAME, CSS_VARS, CardLoadingFallback, type ChatAction, type ChatAssistantContext, type ChatAttachment, type ChatAudioConfig, type ChatAudioEvent, type ChatAudioSounds, type ChatBubbleStyles, type ChatBubbleSurface, type ChatConfig, type ChatContextValue, type ChatDestructiveStyles, type ChatDisplayMode, ChatDock, type ChatDockMode, type ChatDockPrefs, type ChatDockProps, type ChatDockSide, type ChatEventDetail, ChatFAB, type ChatFABPosition, type ChatFABProps, type ChatFABSize, type ChatFABVariant, ChatGreeting, type ChatGreetingProps, ChatHeader, ChatHeaderActionButton, type ChatHeaderActionButtonProps, ChatHeaderAudioToggle, type ChatHeaderAudioToggleProps, ChatHeaderLanguageButton, type ChatHeaderLanguageButtonProps, ChatHeaderModeToggle, type ChatHeaderModeToggleProps, type ChatHeaderProps, ChatHeaderResetButton, type ChatHeaderResetButtonProps, type ChatLabels, ChatLauncher, type ChatLauncherGreeting, type ChatLauncherHotkey, type ChatLauncherProps, type ChatLightboxState, type ChatLogScope, type ChatLogger, type ChatMessage, type ChatPersona, type ChatPrefs, type ChatPresencePhase, ChatProvider, type ChatProviderProps, type ChatRole, type ChatRoleStyles, ChatRoot, type ChatRootProps, type ChatSource, type ChatState, type ChatStreamEvent, type ChatToolCall, type ChatTransport, ChatUnreadPreview, type ChatUnreadPreviewProps, type ChatUserContext, CheckboxWidget, ColorWidget, Composer, type ComposerProps, type CreateLazyComponentOptions, type CreateSessionOptions, type CreateVideoErrorFallbackOptions, CronScheduler, type CronSchedulerContextValue, type CronSchedulerProps, CronSchedulerProvider, type CronSchedulerState, CustomInput, type DASHSource, DEFAULT_CHAT_SOUNDS, DEFAULT_DOCK_PREFS, DEFAULT_LABELS, DEFAULT_SIDEBAR, DEFAULT_Z_INDEX, DESTRUCTIVE_SURFACE, type DataUrlSource, DayChips, DiffEditor, type DiffEditorProps, type DisabledWhenRule, Editor, type EditorContextValue, type EditorFile, type EditorOptions, type EditorProps, EditorProvider, type EditorRef, EmptyState, type EmptyStateProps, ErrorBanner, type ErrorBannerProps, type ErrorFallbackProps, ErrorListTemplate, FieldTemplate, type Focusable, type HLSSource, HOTKEYS, type HistoryPage, type HttpTransportConfig, type ImageFile, ImageViewer, type ImageViewerProps, type JsonFormContext, type JsonFormDensity, JsonSchemaForm, type JsonSchemaFormProps, JsonTreeComponent as JsonTree, type JsonTreeConfig, type JsonTreeProps, JumpToLatest, type JumpToLatestProps, LIMITS, LazyPlayer as LazyAudioPlayer, LazyChat, type ChatRootProps as LazyChatProps, LazyCronScheduler, LazyImageViewer, LazyJsonSchemaForm, LazyJsonTree, LazyLottiePlayer, LazyMapContainer, LazyMapView, LazyMermaid, LazyOpenapiViewer, LazyPrettyCode, LazyTree, TreeRootProps as LazyTreeProps, LazyVideoPlayer, LazyWrapper, type LazyWrapperProps, type LinkRule, LoadingFallback, type LoadingFallbackProps, type LottieDirection, LottiePlayer, type LottiePlayerProps, type LottieSize, type LottieSpeed, type MapContainerProps, MapLoadingFallback, type MapStyleKey, type MapViewport, MarkdownEditor, type MarkdownEditorProps, MarkdownMessage, type MarkdownMessageProps, type MarkerData, type MentionAttrs, type MentionConfig, type MentionItem, type MentionMarkdownRenderer, Mermaid, type MermaidProps, MessageActions, type MessageActionsProps, MessageBubble, type MessageBubbleProps, MessageList, type MessageListHandle, type MessageListProps, type MockTransportOptions, type MonthDay, MonthDayGrid, NativeProvider, NumberWidget, ObjectFieldTemplate, Playground as OpenapiViewer, type ParseSSEOptions, type PlayerMode, type PlaygroundConfig, type PlaygroundProps$1 as PlaygroundProps, PrettyCode, type PrettyCodeProps$1 as PrettyCodeProps, type PydanticAIChatTransportOpts, type PydanticAIEvent, type ResolveFileSourceOptions, STORAGE_KEYS, SchedulePreview, type ScheduleType, ScheduleTypeSelector, type SchemaSource, SelectWidget, type SendOptions, type SessionInfo, type SimpleStreamSource, SliderWidget, Sources, type SourcesProps, Spinner, type StreamOptions, StreamProvider, type StreamSource, StreamingIndicator, type StreamingIndicatorProps, SwitchWidget, TOGGLE, TOOL_CALL, TextWidget, TimeSelector, type TokenBuffer, ToolCalls, type ToolCallsProps, type ToolIdQueue, type ToolPayloadFallback, type ToolPayloadKind, type ToolPayloadMatcher, TransportError, TreeRootProps, type UiGroup, type UrlSource, type UseAutoFocusOnStreamEndOptions, type UseChatAudioReturn, type UseChatComposerOptions, type UseChatComposerReturn, type UseChatConfig, type UseChatDockPrefsOptions, type UseChatDockPrefsReturn, type UseChatHistoryOptions, type UseChatLayoutConfig, type UseChatLayoutReturn, type UseChatLightboxReturn, type UseChatResetOptions, type UseChatResetReturn, type UseChatReturn, type UseChatScrollOptions, type UseChatScrollReturn, type UseChatUnreadOptions, type UseChatUnreadReturn, type UseCollapsibleContentOptions, type UseCollapsibleContentResult, type UseEditorReturn, type UseFocusOnEmptyClickOptions, type UseLottieOptions, type UseLottieReturn, type UseMonacoReturn, type UseVisitorFingerprintOptions, VideoControls, VideoErrorFallback, type VideoErrorFallbackProps, VideoPlayer, type VideoPlayerContextValue, type VideoPlayerProps, VideoPlayerProvider, type VideoPlayerProviderProps, type VideoPlayerRef, type VideoSourceUnion, VidstackProvider, type VimeoSource, type WeekDay, type YouTubeSource, buildCron, collectImageAttachments, createHttpTransport, createId, createLazyComponent, createMockTransport, createPydanticAIChatTransport, createPydanticAISSEMap, createTokenBuffer, createToolIdQueue, createVideoErrorFallback, deriveInitials, dispatchToolPayload, evaluateDisabledWhen, extractTextFromChildren, generateContentKey, getChatLogger, getRequiredFields, hasRequiredFields, humanizeCron, initialState, isGeoJSONFeatureCollection, isLatLng, isPlainObject, isSimpleStreamSource, isStringValue, isSubmittableDraft, isValidCron, mapPydanticAIEvent, mentionPresets, mergeDefaults, normalizeFormData, parseCron, parseSSE, reducer, resolveFileSource, resolvePersona, resolvePlayerMode, resolveStreamSource, safeJsonParse, safeJsonStringify, sanitizeDraft, useAudioCache, useAutoFocusOnStreamEnd, useBlobUrlCleanup, useChat, useChatAudio, useChatAudioPrefs, useChatBubbleStyles, useChatComposer, useChatContext, useChatContextOptional, useChatDestructiveStyles, useChatDockPrefs, useChatHistory, useChatLayout, useChatLightbox, useChatPresence, useChatReset, useChatRoleStyles, useChatScroll, useChatUnread, useCollapsibleContent, useCronCustom, useCronMonthDays, useCronPreview, useCronScheduler, useCronSchedulerContext, useCronTime, useCronType, useCronWeekDays, useEditor, useEditorContext, useFocusOnEmptyClick, useImageCache, useLanguage, useLottie, useMediaCacheStore, useMonaco, useRegisterComposer, useVideoCache, useVideoPlayerContext, useVideoPlayerSettings, useVisitorFingerprint, validateRequiredFields, validateSchema };
4873
+ interface UseCollapsibleContentOptions {
4874
+ /**
4875
+ * Maximum character length before collapsing
4876
+ * If both maxLength and maxLines are set, the stricter limit applies
4877
+ */
4878
+ maxLength?: number;
4879
+ /**
4880
+ * Maximum number of lines before collapsing
4881
+ * If both maxLength and maxLines are set, the stricter limit applies
4882
+ */
4883
+ maxLines?: number;
4884
+ /**
4885
+ * Start in expanded state (default: false - starts collapsed)
4886
+ */
4887
+ defaultExpanded?: boolean;
4888
+ }
4889
+ interface UseCollapsibleContentResult {
4890
+ /** Whether content is currently collapsed */
4891
+ isCollapsed: boolean;
4892
+ /** Toggle between collapsed/expanded state */
4893
+ toggleCollapsed: () => void;
4894
+ /** Set collapsed state directly */
4895
+ setCollapsed: (collapsed: boolean) => void;
4896
+ /** Content to display (truncated if collapsed, full if expanded) */
4897
+ displayContent: string;
4898
+ /** Whether the content exceeds limits and should be collapsible */
4899
+ shouldCollapse: boolean;
4900
+ /** Original content length */
4901
+ originalLength: number;
4902
+ /** Original line count */
4903
+ originalLineCount: number;
4904
+ }
4905
+ /**
4906
+ * Hook for managing collapsible content with "Read more..." functionality
4907
+ *
4908
+ * @example
4909
+ * ```tsx
4910
+ * const { isCollapsed, toggleCollapsed, displayContent, shouldCollapse } = useCollapsibleContent(
4911
+ * longText,
4912
+ * { maxLength: 300, maxLines: 5 }
4913
+ * );
4914
+ *
4915
+ * return (
4916
+ * <div>
4917
+ * <Markdown content={displayContent} />
4918
+ * {shouldCollapse && (
4919
+ * <button onClick={toggleCollapsed}>
4920
+ * {isCollapsed ? 'Read more...' : 'Show less'}
4921
+ * </button>
4922
+ * )}
4923
+ * </div>
4924
+ * );
4925
+ * ```
4926
+ */
4927
+ declare function useCollapsibleContent(content: string, options?: UseCollapsibleContentOptions): UseCollapsibleContentResult;
4928
+
4929
+ export { ANCHOR, ActionRow, type ApiKey, ArrayFieldItemTemplate, ArrayFieldTemplate, type AspectRatioValue, type AttachmentRenderer, type AttachmentRendererArgs, type AttachmentRendererMap, Attachments, AttachmentsGrid, type AttachmentsGridProps, AttachmentsList, type AttachmentsListProps, type AttachmentsProps, Player as AudioPlayer, type PlayerProps as AudioPlayerProps, AudioToggle, type AudioToggleProps, BUBBLE_SURFACE, BaseInputTemplate, type BlobSource, CHAT_EVENT_NAME, CSS_VARS, CardLoadingFallback, type ChatAction, type ChatAssistantContext, type ChatAttachment, type ChatAudioConfig, type ChatAudioEvent, type ChatAudioSounds, type ChatBubbleStyles, type ChatBubbleSurface, type ChatConfig, type ChatContextValue, type ChatDestructiveStyles, type ChatDisplayMode, ChatDock, type ChatDockMode, type ChatDockPrefs, type ChatDockProps, type ChatDockSide, type ChatEventDetail, ChatFAB, type ChatFABPosition, type ChatFABProps, type ChatFABSize, type ChatFABVariant, ChatGreeting, type ChatGreetingProps, ChatHeader, ChatHeaderActionButton, type ChatHeaderActionButtonProps, ChatHeaderAudioToggle, type ChatHeaderAudioToggleProps, ChatHeaderLanguageButton, type ChatHeaderLanguageButtonProps, ChatHeaderModeToggle, type ChatHeaderModeToggleProps, type ChatHeaderProps, ChatHeaderResetButton, type ChatHeaderResetButtonProps, type ChatLabels, ChatLauncher, type ChatLauncherGreeting, type ChatLauncherHotkey, type ChatLauncherProps, type ChatLightboxState, type ChatLogScope, type ChatLogger, type ChatMessage, ChatMessageRow, type ChatPersona, type ChatPrefs, type ChatPresencePhase, ChatProvider, type ChatProviderProps, type ChatRole, type ChatRoleStyles, ChatRoot, type ChatRootProps, type ChatSource, type ChatState, type ChatStreamEvent, type ChatToolCall, type ChatTransport, ChatUnreadPreview, type ChatUnreadPreviewProps, type ChatUserContext, CheckboxWidget, ColorWidget, Composer, type ComposerProps, type CreateLazyComponentOptions, type CreateSessionOptions, type CreateVideoErrorFallbackOptions, CronScheduler, type CronSchedulerContextValue, type CronSchedulerProps, CronSchedulerProvider, type CronSchedulerState, CustomInput, type DASHSource, DEFAULT_CHAT_SOUNDS, DEFAULT_DOCK_PREFS, DEFAULT_LABELS, DEFAULT_SIDEBAR, DEFAULT_Z_INDEX, DESTRUCTIVE_SURFACE, type DataUrlSource, DayChips, DiffEditor, type DiffEditorProps, type DisabledWhenRule, Editor, type EditorContextValue, type EditorFile, type EditorOptions, type EditorProps, EditorProvider, type EditorRef, EmptyState, type EmptyStateProps, ErrorBanner, type ErrorBannerProps, type ErrorFallbackProps, ErrorListTemplate, FieldTemplate, type Focusable, type HLSSource, HOTKEYS, type HistoryPage, type HttpTransportConfig, type ImageFile, ImageViewer, type ImageViewerProps, type JsonFormContext, type JsonFormDensity, JsonSchemaForm, type JsonSchemaFormProps, JsonTreeComponent as JsonTree, type JsonTreeConfig, type JsonTreeProps, JumpToLatest, type JumpToLatestProps, LIMITS, LazyPlayer as LazyAudioPlayer, LazyChat, type ChatRootProps as LazyChatProps, LazyCronScheduler, LazyImageViewer, LazyJsonSchemaForm, LazyJsonTree, LazyLottiePlayer, LazyMapContainer, LazyMapView, LazyMermaid, LazyOpenapiViewer, LazyPrettyCode, LazyTree, TreeRootProps as LazyTreeProps, LazyVideoPlayer, LazyWrapper, type LazyWrapperProps, type LinkRule, LoadingFallback, type LoadingFallbackProps, type LottieDirection, LottiePlayer, type LottiePlayerProps, type LottieSize, type LottieSpeed, type MapContainerProps, MapLoadingFallback, type MapStyleKey, type MapViewport, MarkdownEditor, type MarkdownEditorProps, MarkdownMessage, MarkdownMessage as MarkdownMessageDefault, type MarkdownMessageProps, type MarkerData, type MentionAttrs, type MentionConfig, type MentionItem, type MentionMarkdownRenderer, Mermaid, type MermaidProps, MessageActions, type MessageActionsProps, MessageBubble, type MessageBubbleProps, MessageList, type MessageListHandle, type MessageListProps, type MockTransportOptions, type MonthDay, MonthDayGrid, NativeProvider, NumberWidget, ObjectFieldTemplate, Playground as OpenapiViewer, type ParseSSEOptions, type PlayerMode, type PlaygroundConfig, type PlaygroundProps$1 as PlaygroundProps, PrettyCode, type PrettyCodeProps$1 as PrettyCodeProps, type PydanticAIChatTransportOpts, type PydanticAIEvent, type ResolveFileSourceOptions, STORAGE_KEYS, SchedulePreview, type ScheduleType, ScheduleTypeSelector, type SchemaSource, SelectWidget, type SendOptions, type SessionInfo, type SimpleStreamSource, SliderWidget, Sources, type SourcesProps, Spinner, type StreamOptions, StreamProvider, type StreamSource, StreamingIndicator, type StreamingIndicatorProps, SwitchWidget, TOGGLE, TOOL_CALL, TextWidget, TimeSelector, type TokenBuffer, ToolCalls, type ToolCallsProps, type ToolIdQueue, type ToolPayloadFallback, type ToolPayloadKind, type ToolPayloadMatcher, TransportError, TreeRootProps, type UiGroup, type UrlSource, type UseAutoFocusOnStreamEndOptions, type UseChatAudioReturn, type UseChatComposerOptions, type UseChatComposerReturn, type UseChatConfig, type UseChatDockPrefsOptions, type UseChatDockPrefsReturn, type UseChatHistoryOptions, type UseChatLayoutConfig, type UseChatLayoutReturn, type UseChatLightboxReturn, type UseChatResetOptions, type UseChatResetReturn, type UseChatReturn, type UseChatScrollOptions, type UseChatScrollReturn, type UseChatUnreadOptions, type UseChatUnreadReturn, type UseCollapsibleContentOptions, type UseCollapsibleContentResult, type UseEditorReturn, type UseFocusOnEmptyClickOptions, type UseLottieOptions, type UseLottieReturn, type UseMonacoReturn, type UseVisitorFingerprintOptions, VideoControls, VideoErrorFallback, type VideoErrorFallbackProps, VideoPlayer, type VideoPlayerContextValue, type VideoPlayerProps, VideoPlayerProvider, type VideoPlayerProviderProps, type VideoPlayerRef, type VideoSourceUnion, VidstackProvider, type VimeoSource, type WeekDay, type YouTubeSource, buildCron, collectImageAttachments, createHttpTransport, createId, createLazyComponent, createMockTransport, createPydanticAIChatTransport, createPydanticAISSEMap, createTokenBuffer, createToolIdQueue, createVideoErrorFallback, deriveInitials, dispatchToolPayload, evaluateDisabledWhen, extractTextFromChildren, generateContentKey, getChatLogger, getRequiredFields, hasRequiredFields, humanizeCron, initialState, isGeoJSONFeatureCollection, isLatLng, isPlainObject, isSimpleStreamSource, isStringValue, isSubmittableDraft, isValidCron, mapPydanticAIEvent, mentionPresets, mergeDefaults, normalizeFormData, parseCron, parseSSE, reducer, resolveFileSource, resolvePersona, resolvePlayerMode, resolveStreamSource, safeJsonParse, safeJsonStringify, sanitizeDraft, useAudioCache, useAutoFocusOnStreamEnd, useBlobUrlCleanup, useChat, useChatAudio, useChatAudioPrefs, useChatBubbleStyles, useChatComposer, useChatContext, useChatContextOptional, useChatDestructiveStyles, useChatDockPrefs, useChatHistory, useChatLayout, useChatLightbox, useChatPresence, useChatReset, useChatRoleStyles, useChatScroll, useChatUnread, useCollapsibleContent, useCronCustom, useCronMonthDays, useCronPreview, useCronScheduler, useCronSchedulerContext, useCronTime, useCronType, useCronWeekDays, useEditor, useEditorContext, useFocusOnEmptyClick, useImageCache, useLanguage, useLottie, useMediaCacheStore, useMonaco, useRegisterComposer, useVideoCache, useVideoPlayerContext, useVideoPlayerSettings, useVisitorFingerprint, validateRequiredFields, validateSchema };