"use client"; import { memo } from "react"; import { SHORTCUTS } from "@/lib/keyboard/constants"; import { DesktopChatInputToolbar } from "./chat-input-toolbar-desktop"; import { MobileChatInputToolbar } from "./chat-input-toolbar-mobile"; import { SubmitButton } from "./chat-input-toolbar-primitives"; import { shouldUseCompactTaskChrome } from "@/hooks/use-compact-task-chrome"; import { useResponsiveBreakpoint } from "@/hooks/use-responsive-breakpoint"; import type { ContextFile } from "@/lib/state/context-files-store"; export type ChatInputToolbarProps = { planModeEnabled: boolean; planModeAvailable?: boolean; mcpServers?: string[]; onPlanModeChange: (enabled: boolean) => void; sessionId: string | null; taskId: string | null; taskTitle?: string; taskDescription: string; isAgentBusy: boolean; /** Whether the input has content to send (text, comments, or context) */ hasContent?: boolean; isDisabled: boolean; submitDisabledReason?: string; isSending: boolean; onCancel: () => void | Promise; onSubmit: () => void; submitKey?: "enter" | "cmd_enter"; contextCount?: number; contextPopoverOpen?: boolean; onContextPopoverOpenChange?: (open: boolean) => void; /** Whether plan is selected as context in the popover (independent of plan panel) */ planContextEnabled?: boolean; contextFiles?: ContextFile[]; onToggleFile?: (file: ContextFile) => void; onImplementPlan?: (fresh: boolean) => void; /** Callback to enhance the current prompt with AI */ onEnhancePrompt?: () => void; /** Whether prompt enhancement is in progress */ isEnhancingPrompt?: boolean; /** Whether utility agent is configured for AI enhancement */ isUtilityConfigured?: boolean; /** Callback to open file picker for attaching files */ onAttachFiles?: () => void; /** Callback to insert a transcribed voice utterance into the editor. When * omitted, the voice button is hidden — keeps quick-chat / read-only * variants free of a button they can't wire. */ onVoiceTranscript?: (text: string) => void; /** Optional auto-send hook fired after a voice transcript is inserted. */ onVoiceAutoSend?: () => void; /** Hide the sessions dropdown (for quick chat) */ hideSessionsDropdown?: boolean; /** When true, only render the submit/cancel button — no other controls */ minimalToolbar?: boolean; /** Hide ACP/session-specific controls while keeping Plan, attachment, and context controls */ hideAgentControls?: boolean; /** Hide the plan mode toggle button (for ephemeral/quick chat sessions) */ hidePlanMode?: boolean; }; function MinimalToolbar({ isAgentBusy, hasContent, isDisabled, submitDisabledReason, isSending, onCancel, onSubmit, submitKey = "cmd_enter", }: Pick< ChatInputToolbarProps, | "isAgentBusy" | "hasContent" | "isDisabled" | "submitDisabledReason" | "isSending" | "onCancel" | "onSubmit" | "submitKey" >) { const submitShortcut = submitKey === "enter" ? SHORTCUTS.SUBMIT_ENTER : SHORTCUTS.SUBMIT; return (
); } const toolbarDefaults = { planModeAvailable: true, mcpServers: [] as string[], submitKey: "cmd_enter" as const, contextCount: 0, contextPopoverOpen: false, planContextEnabled: false, contextFiles: [] as ContextFile[], isEnhancingPrompt: false, isUtilityConfigured: false, hideAgentControls: false, hidePlanMode: false, }; export const ChatInputToolbar = memo(function ChatInputToolbar(rawProps: ChatInputToolbarProps) { const props = { ...toolbarDefaults, ...rawProps }; const submitShortcut = props.submitKey === "enter" ? SHORTCUTS.SUBMIT_ENTER : SHORTCUTS.SUBMIT; const responsiveBreakpoint = useResponsiveBreakpoint(); const usesCompactTaskChrome = shouldUseCompactTaskChrome(responsiveBreakpoint); if (props.minimalToolbar) { return ( ); } if (usesCompactTaskChrome) { return ( {})} contextCount={props.contextCount} planContextEnabled={props.planContextEnabled} contextFiles={props.contextFiles} onToggleFile={props.onToggleFile ?? (() => {})} isAgentBusy={props.isAgentBusy} hasContent={props.hasContent ?? false} onImplementPlan={props.onImplementPlan} onEnhancePrompt={props.onEnhancePrompt} isEnhancingPrompt={props.isEnhancingPrompt} isUtilityConfigured={props.isUtilityConfigured} isDisabled={props.isDisabled} submitDisabledReason={props.submitDisabledReason} isSending={props.isSending} onCancel={props.onCancel} onSubmit={props.onSubmit} submitShortcut={submitShortcut} onVoiceTranscript={props.onVoiceTranscript} onVoiceAutoSend={props.onVoiceAutoSend} /> ); } const { submitKey: _submitKey, ...desktopProps } = props; return ; });