/** * Block state for one assistant message. * * Ported from TORUK Core's `blockStreamMutations.js` + `useMessageBlocks.js`, adapted to the * SDK's message shape (`message` string rather than Core's `content`). Kept framework-agnostic * and pure so the live-stream reducer and the history-replay path share one implementation and * cannot diverge — the same guarantee Core gets from running both through `resolveBlocks`. */ import type { Block, BlockWithId } from './split-blocks'; /** Inline placeholder held while a `ui` fence is still streaming. */ export type PendingUiBlock = { kind: 'pending-ui'; id: string; componentType: string; }; /** What a message renders: resolved content blocks plus in-flight placeholders. */ export type RenderBlock = Block | PendingUiBlock; export type ActivityStatus = 'active' | 'done' | 'error'; /** One step in the live "Working…" timeline (a flow node or a tool call). */ export type ActivityStep = { id: string; kind?: 'node' | 'tool'; label?: string; status?: ActivityStatus; response?: string; nodeId?: string; occurrence?: number; metric?: string; }; export type MessageActivity = { steps: ActivityStep[]; }; /** The subset of a widget message this module reads and writes. */ export type BlockCarrier = { message?: string; blocks?: RenderBlock[]; /** Persisted blocks replayed from Core's `dynamicUiBlocks` column. */ dynamicUiBlocks?: Block[]; activity?: MessageActivity; }; /** Seed the block array from whatever the message already has — live blocks, else its text. */ export declare function startBlocks(message: BlockCarrier): RenderBlock[]; /** Append a prose delta, merging into the trailing markdown block when there is one. */ export declare function appendTextBlock(blocks: RenderBlock[] | undefined, text: string): RenderBlock[]; export declare function pushPendingBlock(message: T, pending: { id: string; componentType: string; }): T; export declare function updatePendingBlockType(message: T, pending: { id: string; componentType: string; }): T; /** * Land a finalized block. When it carries the id of a pending placeholder it replaces that * placeholder in place, so a component never appears twice or jumps position on completion. */ export declare function replaceOrAppendContentBlock(message: T, block: BlockWithId): T; export declare function upsertActivityStep(message: T, step: ActivityStep): T; /** Flip a known step to a new status. Unknown ids are ignored so an END never invents a step. */ export declare function setActivityStepStatus(message: T, id: string, status: ActivityStatus): T; /** Settle every still-running step when the turn ends (or errors). */ export declare function finalizeActivitySteps(message: T, status: ActivityStatus): T; /** * The ordered blocks a message should render, and whether block rendering applies at all. * * Prefers live/persisted blocks; otherwise re-parses the message text, which also promotes * GFM pipe tables to `ui:table` exactly as Core's replay path does. * * Deviation from Core: Core sets `useBlocks` whenever live blocks exist at all. The SDK sets it * only when there is something the markdown renderer cannot draw (a component, a placeholder, or * an activity timeline), so a plain prose answer keeps flowing through the widget's existing * `BotBubble` markdown pipeline — same pixels, and no regression to file-annotation buttons, * TTS text extraction or copy-to-clipboard, which all read that element. */ export declare function resolveMessageBlocks(message: BlockCarrier | undefined | null): { renderBlocks: RenderBlock[]; useBlocks: boolean; };