import { type JSX, type ReactNode } from "react"; import type { ChatMessageContextFile } from "../types/ui-schema.js"; export interface ComposerContextAttachment extends ChatMessageContextFile { preview?: string; } export interface SlashCommandHint { /** Command name, no leading slash. */ name: string; /** One-line description shown beside the name in the popover. */ description?: string; } export interface ComposerSkillOption { /** Short id used as the slash-token inserted into the textarea (`/`). */ id: string; /** Human-readable display name. */ name: string; /** Optional one-line description shown beside the name in the picker. */ description?: string; /** Source grouping used to split built-in skills from workspace skills. */ source?: "builtin" | "workspace"; } export interface ChatComposerProps { value: string; onChange: (value: string) => void; onSubmit: (value: string) => void; onAttach?: () => void; onPasteImages?: (files: File[]) => void; onCancel?: () => void; isStreaming?: boolean; /** Voice input. When `onMicStart` is provided the composer renders a * mic button next to the attach button. State is owned by the host: * the host flips `micState` as recording starts/stops/uploads and * the button shows the matching affordance. Click → start, click * again while recording → stop and upload. */ onMicStart?: () => void; onMicStop?: () => void; micState?: "idle" | "recording" | "uploading"; placeholder?: string; disabled?: boolean; contextFiles?: ComposerContextAttachment[]; onRemoveContextFile?: (path: string) => void; images?: string[]; onRemoveImage?: (index: number) => void; autoContextEnabled?: boolean; onToggleAutoContext?: () => void; /** Optional slash-command autocomplete. When provided and the user types `/`, * a filterable popover appears above the textarea. */ slashCommands?: SlashCommandHint[]; /** When provided, renders a Claude-Code-style `/` button that opens a * slash-command picker. For v1 the callback can be a no-op stub — this * prop exists so the button can be unconditionally mounted and hosts * can flesh out the picker later. If {@link onRequestSkills} is supplied * the built-in skill picker takes over and this callback is ignored. */ onOpenSlashPicker?: () => void; /** Optional async resolver that returns the list of skills available for * the current workspace. When supplied, clicking the `/` button opens a * filterable, keyboard-navigable popover that lets the user insert * `/` as a prefix in the textarea. */ onRequestSkills?: () => Promise | ComposerSkillOption[]; /** Controls the Ask/Auto edit-approval toggle. When set, the composer * renders a toggle near the submit arrow matching the Claude UX. */ editAutoApproveEnabled?: boolean; /** Handler invoked when the user toggles edit-auto-approve. When omitted * the toggle is hidden. */ onToggleEditAutoApprove?: () => void; /** Active permission mode ('plan' | 'ask' | 'auto' | 'dangerous'). When set * (with onCyclePermissionMode) the composer renders an always-visible mode * pill in the bottom row — the boundary the agent is operating under, on * screen where the user's attention is. */ permissionMode?: string; /** Click handler for the mode pill — cycles ask → auto → plan. When omitted * the pill is hidden. */ onCyclePermissionMode?: () => void; /** Extra controls rendered inside the `/` command menu under a * "Settings" section. Use this to hang host-specific settings * (e.g. model picker, provider switcher) off the same menu that * carries skills — keeps the composer row to `+ / send`. */ settingsSlot?: ReactNode; /** Compact label shown in the composer header when the chat is * focused on a specific model (e.g. "bandit-core:12b-it-qat"). The * full picker lives inside the `/` settings slot; this is read-only. */ modelLabel?: string; /** DEPRECATED: use {@link settingsSlot} instead. Kept for * back-compat; renders nothing in v1.5.53+ because the composer row * no longer has room for an inline footer chip. */ footerSlot?: ReactNode; /** * File / folder suggestions for `@` mention autocomplete. Host * populates this in response to {@link onFileMentionQuery}. Each * entry carries `isDir` so the composer can: * - render folders distinctly (trailing `/`, dim subpath) * - on folder select, DRILL IN (update the query to `folder/` and * keep the picker open) rather than committing the mention * - on file select, commit the mention and close the picker * * Accepts the legacy `string[]` shape for back-compat — each string * is treated as a file entry. */ fileMentionSuggestions?: Array<{ path: string; isDir: boolean; }> | string[]; /** * Fires whenever the user is actively typing a `@` token * (after whitespace or at line start, no closing space yet). Host * should debounce + search workspace files and feed results back * via {@link fileMentionSuggestions}. Called with an empty string * when the `@` is still bare — host can return the N most recently * touched files as a sensible default. */ onFileMentionQuery?: (query: string) => void; /** * When true, allow the user to submit a new message while a turn * is already streaming. The host receives `onSubmit` and is * expected to queue the message (not send it). Default `false` * preserves the original behavior (submit is blocked during * stream). When true, the stop-button stays visible and the host * shows its own "queued" affordance — the composer just stops * eating Enter / form-submit events. */ allowQueueWhileStreaming?: boolean; /** Number of messages the host is currently holding behind the * active turn. Renders as a small "N queued" pill inside the * composer footer when > 0. The composer is otherwise unaware * of the queue contents — host owns the array and dispatches * on stream completion. Ignored when `queuedItems` is provided. */ queuedCount?: number; /** Rich queue contents: when provided, the composer renders one * cancellable pill per item (preview text + ✕). Falls back to * `queuedCount` rendering when this is not provided so older * hosts keep working. */ queuedItems?: Array<{ id: string; preview: string; imageCount?: number; fileCount?: number; }>; /** Invoked when the user clicks the ✕ on a queued-message pill. */ onCancelQueued?: (id: string) => void; /** Invoked when the user clicks edit on a queued-message pill. The host * takes the message out of its queue and puts it back in the composer. * No edit button renders without it. */ onEditQueued?: (id: string) => void; } export declare const ChatComposer: ({ value, onChange, onSubmit, onAttach, onPasteImages, onCancel, isStreaming, onMicStart, onMicStop, micState, placeholder, disabled, contextFiles, onRemoveContextFile, images, onRemoveImage, autoContextEnabled, onToggleAutoContext, slashCommands, onOpenSlashPicker, onRequestSkills, editAutoApproveEnabled, onToggleEditAutoApprove, permissionMode, onCyclePermissionMode, settingsSlot, modelLabel, footerSlot, fileMentionSuggestions, onFileMentionQuery, allowQueueWhileStreaming, queuedCount, queuedItems, onCancelQueued, onEditQueued }: ChatComposerProps) => JSX.Element; //# sourceMappingURL=ChatComposer.d.ts.map