/** * Playground Types * * TypeScript types for the Playground feature, enabling interactive * workflow testing with chat interface and session management. * * @module types/playground */ import type { ConfigProperty } from './index.js'; /** * Status of a playground session */ export type PlaygroundSessionStatus = 'idle' | 'running' | 'awaiting_input' | 'completed' | 'failed'; /** * Statuses that stop polling by default. * Only truly-dormant sessions stop polling — completed/failed/awaiting_input * sessions on async servers can still generate messages after the status change, * so polling continues until the session is explicitly idle. */ export declare const DEFAULT_STOP_POLLING_STATUSES: PlaygroundSessionStatus[]; /** * Statuses that are considered terminal by default (clears isExecuting) */ export declare const DEFAULT_TERMINAL_STATUSES: PlaygroundSessionStatus[]; /** * Default implementation for determining if polling should stop. * Consumers can override this via PlaygroundConfig.shouldStopPolling. * * @param status - The current session status * @returns True if polling should stop */ export declare function defaultShouldStopPolling(status: PlaygroundSessionStatus): boolean; /** * Default implementation for determining if a status is terminal (clears isExecuting). * Consumers can override this via PlaygroundConfig.isTerminalStatus. * * @param status - The current session status * @returns True if the status is terminal */ export declare function defaultIsTerminalStatus(status: PlaygroundSessionStatus): boolean; /** * Role of a message sender in the playground * * - `user`: Message from the user * - `assistant`: Response from the workflow/AI * - `system`: System notifications * - `log`: Execution log entries */ export type PlaygroundMessageRole = 'user' | 'assistant' | 'system' | 'log'; /** * Log level for log-type messages */ export type PlaygroundMessageLevel = 'info' | 'warning' | 'error' | 'debug'; /** * Status of a playground message */ export type PlaygroundMessageStatus = 'pending' | 'processing' | 'completed' | 'failed'; /** * A single pipeline execution associated with a playground session */ export interface PlaygroundExecution { id: string; startedAt: string; status: 'running' | 'completed' | 'failed'; /** * Client-derived flag: true when this run is a nested sub-flow rather than a * main pipeline run. Inferred from its messages' `parentPipelineId` (with a * `hierarchy` depth ≥ 2 fallback for legacy runs predating that field). Used * to keep the sidebar on the main pipeline and hide sub-flows from the * run-switcher. Not part of the wire contract — the server never sets this. */ isSubflow?: boolean; } /** * Playground session representing a test conversation * * Sessions maintain conversation history and allow interactive testing * of workflows in an isolated environment. * * @example * ```typescript * const session: PlaygroundSession = { * id: "sess-123", * workflowId: "wf-456", * name: "Test Session 1", * status: "idle", * createdAt: "2024-01-20T10:00:00Z", * updatedAt: "2024-01-20T10:30:00Z" * }; * ``` */ export interface PlaygroundSession { /** Session unique identifier */ id: string; /** Associated workflow ID */ workflowId: string; /** Session display name */ name: string; /** Current session status */ status: PlaygroundSessionStatus; /** Session creation timestamp (ISO 8601) */ createdAt: string; /** Last activity timestamp (ISO 8601) */ updatedAt: string; /** * Main pipeline runs triggered within this session, ordered oldest-first. * Sub-flow (nested) runs are excluded — they're surfaced only on individual * messages via `parentPipelineId`. The run-switcher relies on this being * main-runs-only; runs added from messages are classified client-side. */ executions?: PlaygroundExecution[]; /** Custom session metadata */ metadata?: Record; } /** * Message metadata containing additional context */ export interface PlaygroundMessageMetadata { /** Log level for log-type messages */ level?: PlaygroundMessageLevel; /** Execution duration in milliseconds */ duration?: number; /** Human-readable node label */ nodeLabel?: string; /** Node output data */ outputs?: Record; /** User's display name for user-role messages (from backend) */ userName?: string; /** Subsystem that produced this message (e.g. 'pipeline', 'job', 'queue', 'cron') */ source?: string; /** Allow additional properties */ [key: string]: unknown; } /** * A node on the contextual tree the server attaches to a message * (e.g. workflow > sub-workflow > iteration). Display-only — this is not a * navigation breadcrumb; `href` is intentionally not part of the schema. */ export interface MessageHierarchyItem { /** Stable identifier (for keying) */ id: string; /** Display label */ label: string; /** Optional iconify icon id (e.g. 'mdi:graph') */ icon?: string; } /** * Semantic color hooks for a tag. Map to design tokens in the theme. */ export type MessageTagColor = 'muted' | 'primary' | 'success' | 'warning' | 'error' | 'info'; /** * Visual emphasis for a tag. */ export type MessageTagVariant = 'solid' | 'outline' | 'subtle'; /** * A server-emitted classification chip rendered alongside a message. * Tags are unordered and replace any UI-side defaults. */ export interface MessageTag { /** Stable identifier (for keying) */ id: string; /** Display label */ label: string; /** Optional iconify icon id */ icon?: string; /** Semantic color hook; defaults to 'muted' if omitted */ color?: MessageTagColor; /** Visual style; defaults to 'subtle' if omitted */ variant?: MessageTagVariant; /** Free-form classifier the server may use for future grouping/filtering */ type?: string; } /** * Rendering hint the server may set to choose a layout regardless of role. * * - `bubble`: chat bubble shape (default for user/assistant) * - `log`: dense one-liner (default for log role) * - `notice`: compact centered notice (default for system role with * compactSystemMessages enabled) * - `card`: vertical layout — breadcrumb (top), body (middle), tags (bottom) * * When omitted, the client falls back to the role-based default above. */ export type PlaygroundMessageDisplay = 'bubble' | 'log' | 'notice' | 'card'; /** * Resolve the effective layout for a message. Server-supplied `display` wins; * otherwise we fall back to a role-based default. Pure function so the * dispatcher and tests can share it. */ export declare function resolveMessageDisplay(message: Pick, options?: { compactSystemMessages?: boolean; }): PlaygroundMessageDisplay; /** * Message in a playground session * * Messages can be user inputs, assistant responses, system notifications, * or execution logs. Each message is timestamped and can be associated * with a specific workflow node. * * @example * ```typescript * const message: PlaygroundMessage = { * id: "msg-123", * sessionId: "sess-456", * role: "assistant", * content: "I've analyzed your data and found 3 patterns.", * timestamp: "2024-01-20T10:30:00Z", * nodeId: "node-ai-analyzer", * metadata: { duration: 2500, nodeLabel: "AI Analyzer" } * }; * ``` */ export interface PlaygroundMessage { /** Message unique identifier */ id: string; /** Parent session ID */ sessionId: string; /** Role of the message sender */ role: PlaygroundMessageRole; /** Message content */ content: string; /** Message timestamp (ISO 8601) */ timestamp: string; /** Message status */ status?: PlaygroundMessageStatus; /** Incrementing sequence number for chronological ordering. All message roles receive unique incrementing numbers (1, 2, 3, ...). Primary sort key. */ sequenceNumber?: number; /** Parent message ID (for assistant responses linked to user messages) */ parentMessageId?: string; /** Pipeline/execution ID that generated this message */ executionId?: string | null; /** * Execution ID of the parent pipeline when this message came from a nested * sub-flow; `null`/absent for top-level (main pipeline) messages. Authoritative * nesting signal (unlike the display-only `hierarchy`) — used to keep the main * pipeline in focus and hide sub-flow runs from the run-switcher. */ parentPipelineId?: string | null; /** * Execution ID of the top-level pipeline this message ultimately belongs to. * Equals `executionId` for main-pipeline messages; for sub-flow messages it * points to the main run that triggered the sub-flow. */ rootPipelineId?: string | null; /** Associated node ID (for log/assistant messages) */ nodeId?: string | null; /** * Ordered hierarchy path (e.g. workflow > sub-workflow > iteration). * Rendered as a chevron-separated trail. Server-controlled — no * client-side derivation. */ hierarchy?: MessageHierarchyItem[]; /** * Server-emitted classification chips rendered with the message. * Replace any client-side defaults entirely (no merge). */ tags?: MessageTag[]; /** * Layout hint. When omitted, the client picks a default from the role: * - log → 'log', system (when compactSystemMessages) → 'notice', * user/assistant → 'bubble'. */ display?: PlaygroundMessageDisplay; /** Additional message metadata */ metadata?: PlaygroundMessageMetadata; } /** * Input field derived from workflow input nodes * * Used to auto-generate input forms in the playground based on * the workflow's input nodes' configSchema. * * @example * ```typescript * const inputField: PlaygroundInputField = { * nodeId: "node-text-input", * fieldId: "user_message", * label: "User Message", * type: "string", * defaultValue: "Hello!", * required: true, * schema: { type: "string", format: "multiline" } * }; * ``` */ export interface PlaygroundInputField { /** Source node ID */ nodeId: string; /** Field identifier */ fieldId: string; /** Display label */ label: string; /** Field data type */ type: string; /** Default value from node config */ defaultValue?: unknown; /** Whether the field is required */ required: boolean; /** JSON Schema for the field */ schema?: ConfigProperty; } /** * Request payload for sending a message to the playground */ export interface PlaygroundMessageRequest { /** Message content (typically user input) */ content: string; /** Additional input values for workflow nodes */ inputs?: Record; } /** * Response from the messages endpoint with polling support */ export interface PlaygroundMessagesResult { /** Array of messages */ messages: PlaygroundMessage[]; /** Whether there are more messages to fetch */ hasMore: boolean; /** Current session status (useful for polling) */ sessionStatus: PlaygroundSessionStatus; } /** * Configuration for the Playground component */ export interface PlaygroundConfig { /** Polling interval in milliseconds (default: 1500) */ pollingInterval?: number; /** Maximum number of messages to display (default: 500) */ maxMessages?: number; /** * Number of messages to fetch per page (default: 50). * The initial load fetches the most recent page; scrolling up loads * older pages of this size on demand. */ messagePageSize?: number; /** Auto-scroll to bottom on new messages (default: true) */ autoScroll?: boolean; /** Show timestamps on messages (default: true) */ showTimestamps?: boolean; /** Show log messages inline or in collapsible section (default: "collapsible") */ logDisplayMode?: 'inline' | 'collapsible'; /** Enable markdown rendering in messages (default: true) */ enableMarkdown?: boolean; /** * Whether to show the chat text input (default: true) * When false, only the "Run" button is displayed for workflow execution. */ showChatInput?: boolean; /** * Whether to show the "Run" button (default: true) * When false, the Run button is hidden. If both showChatInput and showRunButton * are false, a helpful message is displayed to the user. */ showRunButton?: boolean; /** * Predefined message to send when "Run" button is clicked (default: "Run workflow") * Used when showChatInput is false to provide a default message for workflow execution. */ predefinedMessage?: string; /** * Automatically run the workflow once when the playground loads (default: false) * When true, the workflow will execute immediately using the predefinedMessage. * This is useful for scenarios where the workflow should start without user interaction. * Note: Only runs once per session - subsequent runs require clicking the Run button. */ autoRun?: boolean; /** * Width of the sidebar in CSS units (default: "280px") * Accepts any valid CSS width value, e.g. "300px", "20rem". */ sidebarWidth?: string; /** * Whether to show the sidebar with session list (default: true) * When false, the sidebar is hidden, creating a minimal chat widget experience. * Use with initialSessionId to load a pre-created session directly. */ showSidebar?: boolean; /** * Whether to show the session header bar (default: true) * When false, the header with session name and close button is hidden. * Typically used together with showSidebar: false for minimal UI. */ showSessionHeader?: boolean; /** * Determines if polling should stop for a given session status. * Override to customize which statuses pause polling. * @default defaultShouldStopPolling (stops only on idle) */ shouldStopPolling?: (status: PlaygroundSessionStatus) => boolean; /** * Determines if a session status is terminal (clears isExecuting). * Override to customize which statuses end the executing state. * @default defaultIsTerminalStatus (terminal on idle, completed, failed, awaiting_input) */ isTerminalStatus?: (status: PlaygroundSessionStatus) => boolean; } /** * Metadata field to control Run button state from backend. * When a message contains this field set to true, the Run button becomes enabled. * * @example * ```typescript * // Backend sends a message with this metadata to re-enable Run button: * const message: PlaygroundMessage = { * id: "msg-123", * sessionId: "sess-456", * role: "system", * content: "Workflow completed. Ready for next run.", * timestamp: new Date().toISOString(), * metadata: { * enableRun: true * } * }; * ``` */ export declare const ENABLE_RUN_METADATA_KEY = "enableRun"; /** * Check if a message metadata contains the enableRun flag * * @param metadata - The message metadata to check * @returns True if the metadata signals to enable the Run button */ export declare function hasEnableRunFlag(metadata: PlaygroundMessageMetadata | undefined): boolean; /** * Display mode for the Playground component */ export type PlaygroundMode = 'embedded' | 'standalone' | 'modal'; /** * Chat input detection patterns for identifying chat nodes in workflows */ export declare const CHAT_INPUT_PATTERNS: readonly ["chat_input", "text_input", "user_input", "message_input", "prompt_input"]; /** * Check if a node type is a chat input node * * @param nodeTypeId - The node type identifier * @returns True if the node is a chat input type */ export declare function isChatInputNode(nodeTypeId: string): boolean; /** * API response wrapper for playground endpoints */ export interface PlaygroundApiResponse { /** Whether the request was successful */ success: boolean; /** Response data */ data?: T; /** Error message if unsuccessful */ error?: string; /** Human-readable message */ message?: string; } /** * Type alias for session list response */ export type PlaygroundSessionsResponse = PlaygroundApiResponse; /** * Type alias for single session response */ export type PlaygroundSessionResponse = PlaygroundApiResponse; /** * Type alias for message response */ export type PlaygroundMessageResponse = PlaygroundApiResponse; /** * Type alias for messages list response with polling metadata */ export interface PlaygroundMessagesApiResponse extends PlaygroundApiResponse { /** Whether more recent messages remain after this page (forward pagination via `since`) */ hasMore?: boolean; /** Whether older messages exist before the first message in this page (backward pagination via `latest`/`before`) */ hasOlder?: boolean; /** Current session status */ sessionStatus?: PlaygroundSessionStatus; }