import type { HTMLAttributes } from 'svelte/elements'; import type { ChatReasoningPart } from '../chat.types.js'; import type { MarkdownUrlPolicy } from '../markdown/types.js'; import type { ReasoningDisclosureSlots } from './reasoning-disclosure.variants.js'; /** * @summary The model's thinking, folded away until someone wants to look. * @description Default renderer for `reasoning` parts in ChatMessage. Wraps a * model's thinking trace in a collapsed, muted disclosure: the header shows a * state label ("Thinking" while streaming, "Thought for Xs" once settled with a * duration, otherwise "Reasoning"), the body renders the reasoning text through * StreamingMarkdown in a damped tertiary tone, indented rather than boxed. Stays * collapsed by default — including while streaming — so a growing reasoning * trace never steals the answer's space; the caller drives the `streaming` flag * (the part carries no status). Renders in the same register as ToolCallCard's * default header: both report how an answer came about, and a reader should be * able to tell at a glance that they are the same kind of thing. * @tag ai * @related ChatMessage * @related ToolCallCard * @related StreamingMarkdown * @stability experimental * * @example * ```svelte * * ``` */ export interface ReasoningDisclosureProps extends Omit, 'class' | 'children'> { /** The reasoning part to render (`{ type: 'reasoning'; text; durationMs? }`). Required. */ reasoning: ChatReasoningPart; /** * The reasoning trace is currently growing. Drives the "Thinking" label and * its pulse; supplied by the caller (the part itself carries no status). * @default false * @summary Whether the trace is still growing, which drives the Thinking label and its pulse. */ streaming?: boolean; /** * Whether the disclosure is expanded. Supports `bind:open`. Passing `open` * without `bind:` requires mirroring every `onOpenChange` back into your state. */ open?: boolean; /** * Initial expanded state for uncontrolled usage. Reasoning stays collapsed by * default, even while streaming. * @default false */ defaultOpen?: boolean; /** Fires once per trigger-driven open transition, after the state is applied. */ onOpenChange?: (open: boolean) => void; /** * URL policy passed through to the inner StreamingMarkdown for any links in * the reasoning text (same strict default — untrusted model output). */ urlPolicy?: MarkdownUrlPolicy; /** * Header label while `streaming`. * @default 'Thinking' */ thinkingLabel?: string; /** * Header label once settled without a `durationMs`. * @default 'Reasoning' */ reasoningLabel?: string; /** * Header label once settled with a `durationMs`, receiving whole seconds * (`Math.round(durationMs / 1000)`). * @default (s) => `Thought for ${s}s` */ formatDuration?: (seconds: number) => string; /** Extra classes merged onto the root (the underlying Collapsible base). */ class?: string; /** Strip ReasoningDisclosure's own tv() classes (trigger/label/chevron/content); the collapse mechanics stay. */ unstyled?: boolean; /** Per-slot class overrides. Slots: `trigger` (header button), `label` (state label), `chevron`, `content` (markdown wrapper). */ slotClasses?: Partial>; /** * Apply a named preset registered via ``. * Prefer this over `class` overrides when the requested look falls outside the * semantic intent palette. */ preset?: string; } export { default as ReasoningDisclosure } from './ReasoningDisclosure.svelte'; export { type ReasoningDisclosureSlots, type ReasoningDisclosureVariants, reasoningDisclosureVariants } from './reasoning-disclosure.variants.js';