import type { EditorView } from "@tiptap/pm/view"; import React from "react"; import { type ComposerTerminalModeControl } from "./ComposerPlusMenu.js"; import { type AgentChatContextItem, type AgentComposerReference, type ComposerTranslate, type ReasoningEffort } from "./runtime-adapters.js"; import type { SkillResult, Reference, SlashCommand, AgentComposerLayoutVariant } from "./types.js"; export interface TiptapComposerHandle { focus(): void; /** Insert text through the editor's normal input path. */ insertText(text: string): void; setText(text: string): void; insertReference(ref: AgentComposerReference): void; } export type ComposerSubmitIntent = "immediate" | "queued"; export declare const DEFAULT_VOICE_DICTATION_ENABLED = false; export interface TiptapComposerSubmitOptions { intent?: ComposerSubmitIntent; } export declare function canSubmitComposerContent(options: { hasEditorContent: boolean; attachmentCount: number; disabled?: boolean; }): boolean; export declare function formatVoiceTranscriptForComposer(text: string): string; export declare function canRemoveVoicePreview(options: { documentSize: number; anchor: number; previewText: string; currentText: string; }): boolean; export declare function resolveComposerPrimaryAction(options: { canSubmit: boolean; hasStopButton: boolean; }): "send" | "stop"; export declare function getComposerSendTooltipKey(willQueue: boolean): "composer.queueMessage" | "composer.sendMessage"; export type ContextChipBackspaceAction = { type: "select"; key: string; } | { type: "remove"; key: string; } | null; export declare function resolveContextChipBackspaceAction(options: { contextItemKeys: string[]; selectedKey: string | null; cursorAtStart: boolean; }): ContextChipBackspaceAction; export declare function getOversizedDocumentAttachmentError(attachments: ReadonlyArray, options?: { maxBytes?: number; label?: string; translate?: ComposerTranslate; }): string | null; export declare function getComposerSubmitIntentForEnterKey(event: Pick, isMac: boolean): ComposerSubmitIntent | null; export declare function insertComposerHardBreakAndScrollIntoView(view: Pick): boolean; export declare function getComposerPopoverPosition(view: Pick, pos: number): { top: number; left: number; } | null; export declare function displayableComposerModeMessage(options: { messagePrefix: string; trimmedText: string; attachmentCount: number; attachedContextFallback?: string; }): string; export declare function handleComposerFileDrop(options: { event: Pick; addAttachment: (file: File) => Promise; onError?: (error: unknown) => void; }): boolean; type ExecMode = "build" | "plan"; export interface ComposerAgentOption { /** Stable host-defined identifier for the agent runtime. */ id: string; /** Human-readable runtime name shown in the picker. */ label: string; /** Optional icon shown beside the runtime name. */ icon?: React.ReactNode; /** Optional short detail shown below the runtime name. */ description?: string; /** Whether this runtime can be selected right now. */ configured?: boolean; /** Optional status text such as "Installed" or "Sign in". */ statusLabel?: string; } export interface TiptapComposerProps { placeholder?: string; disabled?: boolean; /** Override the generic document attachment cap for a multipart host. */ maxDocumentAttachmentBytes?: number; /** Label used in the visible document attachment limit error. */ documentAttachmentLimitLabel?: string; focusRef?: React.Ref; /** Programmatically seed the editor with plain text. */ initialText?: string; /** Stable key used to re-apply the seeded text. */ initialTextKey?: string | number; /** * When provided, called instead of composerRuntime.send(). Used for queue * mode and standalone prompt popovers. Receives the live composer * attachments so callers (e.g. PromptComposer) can surface uploaded files. */ onSubmit?: (text: string, references: Reference[], attachments?: ReadonlyArray, options?: TiptapComposerSubmitOptions) => void | Promise; /** Return false to stop a submit before it enters the chat runtime. */ onBeforeSubmit?: () => boolean | Promise; /** * Clear the editor after an onSubmit handler runs. Standalone workflows that * may fail outside the composer can keep the draft visible for quick edits. */ clearOnSubmit?: boolean; /** Called whenever the plain editor text changes. */ onTextChange?: (text: string) => void; /** Custom action button (e.g. stop button) to render instead of the default send button. */ actionButton?: React.ReactNode; /** Whether the default send action will wait behind existing work. */ willQueue?: boolean; /** Extra button to render alongside the primary action. */ extraActionButton?: React.ReactNode; /** * Stop control shown instead of the disabled send button while the composer * has no sendable content. Typing or attaching content restores send. */ stopButton?: React.ReactNode; /** Custom attachment button to render instead of ComposerPrimitive.AddAttachment. */ attachButton?: React.ReactNode; /** Custom host-owned control rendered next to the attachment affordance. */ modeControl?: React.ReactNode; /** Explicit host-owned toolbar slot rendered next to the attachment affordance. */ toolbarSlot?: React.ReactNode; /** Shared sizing/layout variant for host surfaces. Default keeps sidebar behavior. */ layoutVariant?: AgentComposerLayoutVariant; /** Additional slash commands surfaced in the shared / menu. */ slashCommands?: SlashCommand[]; /** Additional slash skills surfaced in the shared / menu. */ slashSkills?: SkillResult[]; /** Include built-in sidebar slash commands like /clear and /help. Default true. */ includeDefaultSlashCommands?: boolean; /** Include app-discovered skills from the default agent endpoint. Default true. */ includeDefaultSlashSkills?: boolean; /** Called when a slash command (e.g. /clear, /help) is executed */ onSlashCommand?: (command: string) => void; /** Current execution mode (build/plan) */ execMode?: ExecMode; /** Callback to change execution mode */ onExecModeChange?: (mode: ExecMode) => void; /** Disable Plan mode while leaving Act mode available. */ planModeDisabled?: boolean; /** Explanation shown next to the disabled Plan option. */ planModeDisabledReason?: string; /** Show the microphone button for voice dictation. Defaults to DEFAULT_VOICE_DICTATION_ENABLED. */ voiceEnabled?: boolean; /** Selected model override for this conversation */ selectedModel?: string; /** Selected effort override for this conversation */ selectedEffort?: ReasoningEffort; /** Show the legacy provider-level Auto model option (default: true). */ showAutoModelOption?: boolean; /** Controlled open state for hosts that resize around the model picker. */ modelSelectorOpen?: boolean; /** Available models grouped by provider */ availableModels?: Array<{ engine: string; label: string; models: string[]; configured: boolean; statusLabel?: string; isSubscription?: boolean; }>; /** Whether the model list is still being resolved. */ modelListLoading?: boolean; /** Callback when user picks a model */ onModelChange?: (model: string, engine: string) => void; /** Callback when user picks an effort */ onEffortChange?: (effort: ReasoningEffort) => void; /** Local or hosted agent runtimes shown above the model list. */ availableAgents?: ComposerAgentOption[]; /** Selected agent runtime identifier. Defaults to the built-in agent. */ selectedAgent?: string; /** Show only the selected agent in the model control. */ agentOnly?: boolean; /** Mark the selected runtime as the hosted tools-only harness mode. */ hostedHarness?: boolean; /** Callback when the user picks an agent runtime. */ onAgentChange?: (agent: string) => void; /** Called when the shared model picker opens or closes. */ onModelSelectorOpenChange?: (open: boolean) => void; /** * Disable Builder/provider status polling for hosts that supply provider * state through another channel, such as Electron IPC. */ providerConnectStatusEnabled?: boolean; /** * Override the Builder.io connect action in the model picker. When provided, * clicking "Connect Builder.io" calls this instead of opening a browser popup. * Used by the Electron desktop app to route through the native IPC handler. */ onConnectProvider?: () => void; /** Route local runtime setup through the host's native bridge. */ onConnectLocalRuntime?: (engine: string) => void; /** * Optional secondary model menu (e.g. an image-generation model) rendered as * an extra section inside the model picker. Opt-in; omit for chat-only apps. */ imageModelMenu?: ComposerImageModelMenu; /** Stable scope for persisted drafts, usually the active thread or tab id. */ draftScope?: string; /** Keyed context nuggets staged for the next submitted prompt. */ contextItems?: AgentChatContextItem[]; /** Remove a staged context nugget by key. */ onRemoveContextItem?: (key: string) => void; /** * Controls the "+" menu next to the composer. `"full"` (default) shows the * normal Upload / Skill / Job / Automation / MCP picker, plus Extension when * `extensionTools` is true. `"upload-only"` collapses it to a single button * that opens the file picker directly. `"hidden"` hides attachment controls * for text-only prompt surfaces. */ plusMenuMode?: "full" | "upload-only" | "terminal" | "hidden"; /** Controls the terminal-specific plus menu when `plusMenuMode` is terminal. */ terminalModeControl?: ComposerTerminalModeControl; /** * Include extension creation in the full "+" menu. Defaults to false so * apps opt into the extension capability deliberately. */ extensionTools?: boolean; /** * When true and the composer is running inside the Builder.io webview/iframe, * intercept "build me an app/agent" prompts and forward them to the parent * Builder chat via `builder.submitChat` instead of sending to the local * agent. Off by default — the chat sidebar opts in; standalone prompt * forms (NewWorkspaceAppFlow, etc.) handle delegation themselves with * extra context (vault keys, computed app ids) that the raw composer * text lacks. */ interceptBuildRequestsForBuilder?: boolean; /** * Called when a drag-drop or paste attachment fails (e.g. unsupported format, * size cap). Use this to surface a visible error in the parent chat surface * rather than silently swallowing the problem. */ onAttachmentError?: (message: string) => void; } /** Tiptap keeps the Editor object truthy after destroy but clears commandManager. */ export declare function isComposerEditorUsable(editor: T | null | undefined): editor is T; export declare function createTiptapComposerExtensions(getPlaceholder: () => string | undefined): (import("@tiptap/core").Extension | import("@tiptap/core").Extension | import("@tiptap/core").Node)[]; export declare function hasConfiguredCloudProvider(groups: ReadonlyArray<{ engine: string; configured: boolean; }>): boolean; export declare function isOpenAiModelProviderGroup(group: { engine: string; label: string; models: string[]; }): boolean; export declare const MODEL_SELECTOR_POPOVER_STYLE: { fontSize: number; maxHeight: string; }; export declare function shouldShowModelSelectorSkeleton(isLoading: boolean, engineCount: number): boolean; /** * With nothing connected, every family is a dead "needs API key" row, so the * picker shows only the connect CTAs. Never hide the list unless a CTA is * there to replace it — an empty popover reads as more broken, not less. */ export declare function shouldShowOnlyConnectPath(showBuilderCta: boolean, groups: ReadonlyArray<{ configured: boolean; }>): boolean; /** * When nothing is routable yet, the model hook resolves `selectedModel` to * `""` rather than pre-selecting something unusable — that reflects "nothing * chosen," not "nothing to show." The picker itself still has a job to do in * that state (its connect-provider CTAs), so gate on there being engines to * list and a way to change the selection, not on a model already being set. */ export declare function shouldRenderModelSelector(availableModels: ReadonlyArray | undefined, onModelChange: unknown): boolean; export declare function compactComposerModelName(model: string, t?: ComposerTranslate): string; export declare function compactComposerReasoningEffortLabel(effort: ReasoningEffort, t?: ComposerTranslate): string; export declare function composerModelCostTier(model: string): 1 | 2 | 3 | undefined; /** * Optional secondary model menu for apps that drive a separate generation model * alongside the chat LLM (e.g. the Assets app's image-generation model). When * provided, the model picker renders an extra collapsible section so the user * can see and pick both "what reasons about my request" (the chat model) and * "what produces the output" (this model). Opt-in — omit it and nothing changes. */ export interface ComposerImageModelMenu { /** Currently-selected model id for this secondary menu. */ value: string; /** Selectable options (stable id + human label). */ options: Array<{ value: string; label: string; }>; /** Invoked when the user picks a different option. */ onChange: (value: string) => void; /** Section header. Defaults to "Image model". */ label?: string; } export declare function getComposerReasoningEffortOptions(model: string): ReasoningEffort[]; export declare function TiptapComposer({ placeholder, disabled, maxDocumentAttachmentBytes, documentAttachmentLimitLabel, focusRef, initialText, initialTextKey, onSubmit, onBeforeSubmit, clearOnSubmit, onTextChange, actionButton, willQueue, extraActionButton, stopButton, attachButton, modeControl, toolbarSlot, layoutVariant, slashCommands, slashSkills, includeDefaultSlashCommands, includeDefaultSlashSkills, onSlashCommand, execMode, onExecModeChange, planModeDisabled, planModeDisabledReason, voiceEnabled, selectedModel, selectedEffort, showAutoModelOption, modelSelectorOpen, availableModels, modelListLoading, onModelChange, onEffortChange, availableAgents, selectedAgent, agentOnly, hostedHarness, onAgentChange, onModelSelectorOpenChange, providerConnectStatusEnabled, onConnectProvider, onConnectLocalRuntime, imageModelMenu, draftScope, contextItems, onRemoveContextItem, plusMenuMode, terminalModeControl, extensionTools, interceptBuildRequestsForBuilder, onAttachmentError, }: TiptapComposerProps): React.JSX.Element; export {}; //# sourceMappingURL=TiptapComposer.d.ts.map