type RuntypeExecutionStreamEvent = ({ agentId?: string; agentName?: string; config?: Record; executionId: string; flowId?: string; flowName?: string; kind: "agent" | "flow"; maxTurns?: number; seq: number; source?: string; startedAt: string; totalSteps?: number; type: "execution_start"; }) | ({ completedAt?: string; durationMs?: number; executionId: string; failedSteps?: number; finalOutput?: string; iterations?: number; kind: "agent" | "flow"; seq: number; stopReason?: string; success: boolean; successfulSteps?: number; totalCost?: number; totalSteps?: number; totalTokens?: { input: number; output: number; }; type: "execution_complete"; }) | ({ code?: string; completedAt?: string; error: string | { code: string; details?: Record; message: string; }; executionId: string; kind: "agent" | "flow"; seq: number; type: "execution_error"; upgradeUrl?: string; }) | ({ executionId: string; id: string; iteration?: number; role: "user" | "assistant" | "system"; seq: number; turnIndex?: number; type: "turn_start"; }) | ({ completedAt?: string; content?: string; cost?: number; executionId: string; fallback?: { attempts: Array<{ attempt: number; error?: string; model?: string; success: boolean; type: "retry" | "model" | "message" | "flow"; }>; exhausted: boolean; model?: string; reason?: string | null; used: boolean; }; id: string; iteration?: number; role: "user" | "assistant" | "system"; seq: number; stopReason?: "end_turn" | "max_tool_calls" | "length" | "content_filter" | "error" | "unknown"; tokens?: { input: number; output: number; }; type: "turn_complete"; }) | { executionId: string; id: string; index?: number; name?: string; outputVariable?: string; seq: number; startedAt?: string; stepType?: string; totalSteps?: number; type: "step_start"; } | ({ completedAt?: string; durationMs?: number; error?: string; executionId: string; fallback?: { attempts: Array<{ attempt: number; error?: string; model?: string; success: boolean; type: "retry" | "model" | "message" | "flow"; }>; exhausted: boolean; model?: string; reason?: string | null; used: boolean; }; id: string; name?: string; result?: unknown; seq: number; stepType?: string; stopReason?: "end_turn" | "max_tool_calls" | "length" | "content_filter" | "error" | "unknown"; success?: boolean; tokensUsed?: number; type: "step_complete"; unresolvedVariables?: Array; }) | { executionId: string; id: string; index?: number; name?: string; seq: number; skippedAt?: string; stepType?: string; totalSteps?: number; type: "step_skip"; when?: string; } | ({ executionId: string; id: string; parentToolCallId?: string; role?: "user" | "assistant" | "system"; seq: number; stepId?: string; turnId?: string; type: "text_start"; }) | { delta: string; executionId: string; id: string; seq: number; type: "text_delta"; } | { executionId: string; id: string; seq: number; text?: string; type: "text_complete"; } | ({ executionId: string; id: string; parentToolCallId?: string; scope?: "turn" | "loop"; seq: number; type: "reasoning_start"; }) | { delta: string; executionId: string; id: string; seq: number; type: "reasoning_delta"; } | ({ executionId: string; id: string; scope?: "turn" | "loop"; seq: number; text?: string; type: "reasoning_complete"; }) | ({ executionId: string; id: string; mediaType: string; role?: "user" | "assistant" | "system"; seq: number; toolCallId?: string; type: "media_start"; }) | { delta: string; executionId: string; id: string; seq: number; type: "media_delta"; } | { data?: string; executionId: string; id: string; mediaType?: string; seq: number; toolCallId?: string; type: "media_complete"; url?: string; } | ({ artifactType: "markdown" | "component"; component?: string; executionId?: string; id: string; seq?: number; title?: string; type: "artifact_start"; }) | { delta: string; executionId?: string; id: string; seq?: number; type: "artifact_delta"; } | { component: string; executionId?: string; id: string; props: Record; seq?: number; type: "artifact_update"; } | { executionId?: string; id: string; seq?: number; type: "artifact_complete"; } | { executionId: string; id?: string; seq: number; sourceType?: string; title?: string; type: "source"; url?: string; [key: string]: unknown; } | ({ executionId: string; hiddenParameterNames?: Array; iteration?: number; origin?: "webmcp" | "sdk"; pageOrigin?: string; parameters?: Record; seq: number; startedAt?: string; stepId?: string; toolCallId: string; toolName: string; toolType: string; type: "tool_start"; }) | { delta: string; executionId: string; seq: number; toolCallId: string; type: "tool_input_delta"; } | { executionId: string; hiddenParameterNames?: Array; parameters: Record; seq: number; toolCallId: string; toolName?: string; type: "tool_input_complete"; } | { delta: string; executionId: string; seq: number; toolCallId: string; type: "tool_output_delta"; } | { error?: string; executionId: string; executionTime?: number; iteration?: number; result?: unknown; seq: number; stepId?: string; success: boolean; toolCallId: string; toolName?: string; type: "tool_complete"; } | { approvalId: string; description?: string; executionId: string; iteration?: number; parameters?: Record; reason?: string; seq: number; startedAt?: string; subagent?: { agentName?: string; toolName: string; }; timeout?: number; toolCallId?: string; toolName: string; toolType?: string; type: "approval_start"; } | ({ approvalId: string; completedAt?: string; decision: "approved" | "denied" | "timeout"; executionId: string; resolvedBy?: "user" | "system"; seq: number; type: "approval_complete"; }) | ({ awaitedAt?: string; executionId: string; origin?: "webmcp" | "sdk"; pageOrigin?: string; parameters?: Record; seq: number; toolCallId?: string; toolId?: string; toolName?: string; type: "await"; }) | ({ error: string | { code: string; details?: Record; message: string; }; executionId: string; recoverable?: boolean; seq: number; type: "error"; }) | { executionId: string; seq: number; timestamp: string; type: "ping"; } | { executionId?: string; name: string; seq?: number; type: "custom"; value?: unknown; }; type RuntypeFlowSSEEvent = { executionContext?: Record; executionId?: string; flowId: string; flowName?: string; input?: unknown; seq?: number; source?: string; startedAt: string; toolContext?: { executionId: string; stepId: string; toolId: string; }; totalSteps?: number; type: "flow_start"; } | { claudeManagedAgentId?: string; completedAt?: string; completedSteps?: number; duration?: number; executionContext?: Record; executionId?: string; executionTime?: number; failedSteps?: number; finalOutput?: string; flowId?: string; flowName?: string; output?: unknown; seq?: number; source?: string; success?: boolean; successfulSteps?: number; toolContext?: { executionId: string; stepId: string; toolId: string; }; totalSteps?: number; totalTokensUsed?: number; type: "flow_complete"; } | ({ code?: string; error: string | { code: string; message: string; stepId?: string; stepType?: string; }; executionId?: string; executionTime?: number; flowId?: string; seq?: number; timestamp?: string; toolContext?: { executionId: string; stepId: string; toolId: string; }; type: "flow_error"; upgradeUrl?: string; }) | ({ awaitedAt: string; executionId?: string; flowId: string; origin?: "webmcp" | "sdk"; pageOrigin?: string; parameters?: Record; seq?: number; toolCallId?: string; toolId?: string; toolName?: string; type: "flow_await"; }) | { estimatedTokens?: number; executionId?: string; id?: string; index?: number; name?: string; outputVariable?: string; seq?: number; startedAt: string; stepId?: string; stepName?: string; stepType?: string; toolContext?: { executionId: string; stepId: string; toolId: string; }; totalSteps?: number; type: "step_start"; } | { delta?: string; executionId?: string; id?: string; messageId?: string; partId?: string; seq?: number; text?: string; toolContext?: { executionId: string; stepId: string; toolId: string; }; toolId?: string; type: "step_delta"; } | ({ completedAt?: string; duration?: number; durationMs?: number; error?: string; executionId?: string; executionTime?: number; id?: string; index?: number; name?: string; output?: unknown; result?: unknown; seq?: number; stepId?: string; stepName?: string; stepType?: string; stopReason?: "end_turn" | "max_tool_calls" | "length" | "content_filter" | "error" | "unknown"; success?: boolean; tokensUsed?: number; toolContext?: { executionId: string; stepId: string; toolId: string; }; type: "step_complete"; unresolvedVariables?: Array; }) | { error: string; executionId?: string; executionTime?: number; id?: string; index?: number; name?: string; seq?: number; stepType?: string; type: "step_error"; } | { error?: string; executionId?: string; id: string; index?: number; name?: string; seq?: number; skippedAt: string; stepType: string; totalSteps: number; type: "step_skip"; when: string; } | { executionId?: string; reason?: string; seq?: number; type: "step_await"; [key: string]: unknown; } | ({ agentContext?: { executionId: string; iteration: number; seq: number; }; executionId?: string; hiddenParameterNames?: Array; name?: string; parameters?: Record; providerOptions?: Record; seq?: number; startedAt?: string; stepId?: string; toolCallId?: string; toolId?: string; toolName?: string; toolType: "flow" | "mcp" | "builtin" | "custom" | "external" | "advisor" | "subagent" | "local"; type: "tool_start"; [key: string]: unknown; }) | { delta?: string; executionId?: string; seq?: number; toolId?: string; type: "tool_delta"; [key: string]: unknown; } | { delta: string; executionId?: string; seq?: number; stepId?: string; toolCallId?: string; toolId?: string; type: "tool_input_delta"; } | { executionId?: string; hiddenParameterNames?: Array; parameters: Record; providerOptions?: Record; seq?: number; stepId?: string; toolCallId?: string; toolId?: string; toolName?: string; type: "tool_input_complete"; } | { agentContext?: { executionId: string; iteration: number; seq: number; }; completedAt?: string; error?: string; executionId?: string; executionTime?: number; name?: string; result?: unknown; seq?: number; stepId?: string; success: boolean; toolCallId?: string; toolCost?: number; toolId?: string; toolName?: string; type: "tool_complete"; } | { agentContext?: { executionId: string; iteration: number; seq: number; }; error: string; executionId?: string; executionTime?: number; failedAt?: string; name: string; seq?: number; toolId: string; type: "tool_error"; } | { executionId?: string; id: string; seq?: number; text: string; type: "chunk"; } | { executionId?: string; seq?: number; type: "text_start"; [key: string]: unknown; } | { executionId?: string; seq?: number; type: "text_end"; [key: string]: unknown; } | { executionId?: string; seq?: number; type: "reason_start"; [key: string]: unknown; } | { executionId?: string; seq?: number; type: "reason_delta"; [key: string]: unknown; } | { executionId?: string; seq?: number; type: "reason_complete"; [key: string]: unknown; } | { executionId?: string; seq?: number; type: "source"; [key: string]: unknown; } | { executionId?: string; seq?: number; type: "fallback_start"; [key: string]: unknown; } | { executionId?: string; seq?: number; type: "fallback_complete"; [key: string]: unknown; } | { executionId?: string; seq?: number; type: "fallback_exhausted"; [key: string]: unknown; }; type RuntypeStreamEventOf = Extract; type RuntypeTurnCompleteEvent = RuntypeStreamEventOf; type RuntypeStepCompleteEvent = RuntypeStreamEventOf; type RuntypeStopReasonKind = NonNullable; /** * Text content part for multi-modal messages */ type TextContentPart = { type: 'text'; text: string; }; /** * Image content part for multi-modal messages * Supports base64 data URIs or URLs */ type ImageContentPart = { type: 'image'; image: string; mimeType?: string; alt?: string; }; /** * File content part for multi-modal messages * Supports PDF, TXT, DOCX, and other document types */ type FileContentPart = { type: 'file'; data: string; mimeType: string; filename: string; }; /** * Audio content part for multi-modal messages * Supports base64 data URIs or URLs */ type AudioContentPart = { type: 'audio'; audio: string; mimeType?: string; }; /** * Video content part for multi-modal messages * Supports base64 data URIs or URLs */ type VideoContentPart = { type: 'video'; video: string; mimeType?: string; }; /** * Union type for all content part types */ type ContentPart = TextContentPart | ImageContentPart | FileContentPart | AudioContentPart | VideoContentPart; /** * Metadata attached to messages created during agent execution. */ type AgentMessageMetadata = { executionId?: string; iteration?: number; turnId?: string; agentName?: string; /** * When this message was produced by a step inside a nested flow executed * as a tool, identifies the parent tool call id. Enables renderers to * visually group or indent nested-flow output under its parent tool. */ parentToolId?: string; /** * Nested flow step id that produced this message (e.g. a `send-stream` * or `prompt` step inside the nested flow). Stable key for that step. */ parentStepId?: string; /** * Set to `true` on a tool-variant message produced from a `step_await` * event (`awaitReason: "local_tool_required"`). Signals to UI code that * the tool call is a LOCAL tool and the server is paused waiting for a * `POST /v1/dispatch/resume` with the user's answer keyed by tool name. */ awaitingLocalTool?: boolean; /** * The provider per-call id (`toolu_…`) carried on the `step_await` / * `flow_await` events for a LOCAL tool (core#3878). Present only when the * server emits it. Two PARALLEL calls to the same tool in one turn share a * `toolName` (and a collapsed `toolId`) but get DISTINCT `webMcpToolCallId`s, * so this is the key the widget batches a single `/resume` on: preferred * over tool name, which collides for same-tool parallel calls. Absent → * fall back to the legacy name-keyed resume contract. */ webMcpToolCallId?: string; /** * Set to `true` once the user has picked / typed / dismissed an answer for * an `ask_user_question` tool call, so renderers stop re-mounting the * answer-pill sheet for this tool call on subsequent render passes. */ askUserQuestionAnswered?: boolean; /** * In-progress answers for a multi-question `ask_user_question` payload, * keyed by question text. Persisted across refresh so the user lands back * where they were if the page reloads mid-flow. Cleared once * `askUserQuestionAnswered` flips to `true`. */ askUserQuestionAnswers?: Record; /** * Current page index for a multi-question `ask_user_question` payload's * paginated stepper. Persists alongside `askUserQuestionAnswers`. */ askUserQuestionIndex?: number; /** * Set to `true` once a `suggest_replies` tool call's fire-and-forget * `/resume` has been accepted by the server. Persisted belt-and-suspenders * mirror of the in-memory resolved-key dedupe, so hydration/re-emit paths * never re-resume the call. */ suggestRepliesResolved?: boolean; }; /** * Context passed to plugin lifecycle hooks. Carries the live DOM references * and resolved animation settings for the currently-streaming message. */ type StreamAnimationContext = { /** The `.persona-message-content` element owning the streamed text. */ container: HTMLElement; /** The outer message bubble element. */ bubble: HTMLElement; /** ID of the streaming message. */ messageId: string; /** Read-only reference to the message being streamed. */ message: AgentWidgetMessage; /** Effective `speed` from `streamAnimation.speed`. */ speed: number; /** Effective `duration` from `streamAnimation.duration`. */ duration: number; }; /** * Pluggable stream animation. Third-party packages and inline registrations * implement this interface to add custom reveal effects. * * Lifecycle: * - When the widget mounts and detects a plugin (either passed via config or * auto-registered in the IIFE bundle), it injects `styles` once into the * widget's style host. * - For each streaming assistant message whose `type` matches `name`, the * widget applies `containerClass` / `bubbleClass`, wraps text per `wrap`, * and, if `useCaret` is true, appends a blinking caret. * - Hooks fire after the live DOM is morphed; plugins use stable element IDs * and `data-preserve-animation` to safely mutate per-char or per-word spans * without idiomorph clobbering in-flight work. */ type StreamAnimationPlugin = { /** Plugin identifier. Matches the `type` field in `streamAnimation`. */ name: string; /** Class added to `.persona-message-content` while streaming. */ containerClass?: string; /** Class added to the bubble element (e.g. a one-shot scale animation). */ bubbleClass?: string; /** Wrap mode applied to text nodes during streaming. @default "none" */ wrap?: "none" | "char" | "word"; /** * HTML tags whose descendant text is skipped during wrapping. Defaults to * `["pre", "code", "a", "script", "style"]`: useful for keeping code * blocks legible and link click-targets intact. Plugins that want to * animate characters inside inline code (e.g. `glyph-cycle`) can narrow * the list. */ skipTags?: string[]; /** Append a blinking caret after the last rendered char/word. */ useCaret?: boolean; /** CSS string injected into the widget style host on first activation. */ styles?: string; /** * Optional custom buffering strategy. Returns the portion of `content` * that should be rendered during streaming. Use this for buffering * schemes beyond the built-in `word` / `line` strategies. */ bufferContent?: (content: string, message: AgentWidgetMessage) => string; /** * Fires once when the plugin is first activated inside a widget instance. * Use this to set up MutationObservers or other long-lived listeners. * Return an optional cleanup function that runs on widget destroy. */ onAttach?: (root: HTMLElement | ShadowRoot) => (() => void) | void; /** Fires after each render that reaches the live DOM. */ onAfterRender?: (ctx: StreamAnimationContext) => void; /** Fires when a streamed message's `streaming` flag flips to false. */ onStreamComplete?: (ctx: StreamAnimationContext) => void; /** * Report whether the plugin still has in-flight animation work for a * message. When `true`, the widget keeps rendering the message in its * "streaming-animated" mode even after `message.streaming` flips false: * preventing the final non-animated render from yanking the rug out from * under unfinished per-char cycles or reveals. */ isAnimating?: (message: AgentWidgetMessage) => boolean; }; type AgentWidgetMessageRole = "user" | "assistant" | "system"; type AgentWidgetReasoning = { id: string; status: "pending" | "streaming" | "complete"; chunks: string[]; /** * Reasoning channel scope (wire spec). `"turn"` is ordinary per-turn * thinking; `"loop"` is a cross-iteration agent reflection (the fold that * replaced the legacy `agent_reflection` event). Absent for legacy streams. */ scope?: "turn" | "loop"; startedAt?: number; completedAt?: number; durationMs?: number; }; type AgentWidgetToolCall = { id: string; name?: string; status: "pending" | "running" | "complete"; args?: unknown; chunks?: string[]; result?: unknown; duration?: number; startedAt?: number; completedAt?: number; durationMs?: number; }; /** * Represents a tool approval request in the chat conversation. * Created when the agent requires human approval before executing a tool. */ type AgentWidgetApproval = { id: string; status: "pending" | "approved" | "denied" | "timeout"; agentId: string; executionId: string; toolName: string; toolType?: string; description: string; /** * Agent-authored justification for this specific call (the agent's own * claim about its intent, extracted server-side from the reserved * `_approvalReason` parameter). Render it attributed to the agent and as * plain text: it is approver context, not a system statement. */ reason?: string; parameters?: unknown; resolvedAt?: number; }; type AgentWidgetMessageVariant = "assistant" | "reasoning" | "tool" | "approval"; /** * Per-turn / per-step stop reason emitted by the runtime on * `agent_turn_complete` and `step_complete` SSE events. The vocabulary is * owned by the upstream Runtype API: do not extend without coordination. * * - `end_turn`: natural completion (no affordance needed) * - `max_tool_calls`: agent loop tripped the configured tool-call ceiling * - `length`: provider hit max output tokens * - `content_filter`: provider content filter intervened * - `error`: provider/runtime error (prefer existing error rendering) * - `unknown`: explicitly reported but uninformative * * Absent (`undefined`) means "not reported": distinct from `'unknown'`. */ type StopReasonKind = RuntypeStopReasonKind; /** * Represents a message in the chat conversation. * * @property id - Unique message identifier * @property role - Message role: "user", "assistant", or "system" * @property content - Message text content (for display) * @property contentParts - Original multi-modal content parts (for API requests) * @property createdAt - ISO timestamp when message was created * @property streaming - Whether message is still streaming (for assistant messages) * @property variant - Message variant for assistant messages: "assistant", "reasoning", or "tool" * @property sequence - Message ordering number * @property reasoning - Reasoning data for assistant reasoning messages * @property toolCall - Tool call data for assistant tool messages * @property tools - Array of tool calls * @property viaVoice - Set to `true` when a user message is sent via voice recognition. * Useful for implementing voice-specific behaviors like auto-reactivation. */ type AgentWidgetMessage = { id: string; role: AgentWidgetMessageRole; content: string; createdAt: string; /** * Original multi-modal content parts for this message. * When present, this is sent to the API instead of `content`. * The `content` field contains the text-only representation for display. */ contentParts?: ContentPart[]; streaming?: boolean; variant?: AgentWidgetMessageVariant; sequence?: number; reasoning?: AgentWidgetReasoning; toolCall?: AgentWidgetToolCall; tools?: AgentWidgetToolCall[]; /** Approval data for messages with variant "approval" */ approval?: AgentWidgetApproval; viaVoice?: boolean; /** * Set to `true` on placeholder messages injected during Runtype voice processing. * Use this in `messageTransform` to detect and customize voice processing placeholders. * * @example * messageTransform: ({ text, message }) => { * if (message.voiceProcessing && message.role === 'user') { * return '
Transcribing...
'; * } * return text; * } */ voiceProcessing?: boolean; /** * Raw structured payload for this message (e.g., JSON action response). * Populated automatically when structured parsers run. */ rawContent?: string; /** * LLM-specific content for API requests. * When present, this is sent to the LLM instead of `content`. * * Priority for API payload: * 1. `contentParts` (if present, used as-is for multi-modal) * 2. `llmContent` (if present, sent as string) * 3. `rawContent` (backward compatibility with structured parsers) * 4. `content` (fallback - display content) * * The `content` field is always used for UI display. * * @example * // Show full details to user, send summary to LLM * { * content: "**Product:** iPhone 15 Pro\n**Price:** $1,199\n**SKU:** IP15P-256", * llmContent: "[Product search: iPhone 15 Pro, $1199]" * } */ llmContent?: string; /** * Text segment identity for chronological ordering. * When present, identifies which text segment this message represents * (e.g., "text_0", "text_1") for messages split at tool boundaries. */ partId?: string; /** * Metadata for messages created during agent loop execution. * Contains execution context like iteration number and turn ID. */ agentMetadata?: AgentMessageMetadata; /** * Per-turn stop reason reported by the runtime on `agent_turn_complete` * (agent-loop path) or the last `step_complete` for a prompt step * (dispatch / flow path). Absent when the API did not report a value. * * When set to a non-natural value (`max_tool_calls`, `length`, * `content_filter`, `error`), the widget renders an inline notice on * the assistant bubble. See `config.copy.stopReasonNotice` to override * the default copy. */ stopReason?: StopReasonKind; }; export type { StreamAnimationPlugin as S };