diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx
index ba8f6f63999..982bccb896a 100644
--- a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx
+++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/SidebarChat.tsx
@@ -7,15 +7,13 @@ import React, { KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState
import { useAccessor, useChatThreadsState, useChatThreadsStreamState, useSettingsState } from '../util/services.js';
-import { TextAreaFns, VoidInputBox2 } from '../util/inputs.js';
+import { TextAreaFns } from '../util/inputs.js';
import { PastThreadsList } from './SidebarThreadSelector.js';
import { VoidChatArea, ButtonSubmit, ButtonStop } from './composer/VoidChatArea.js';
import { SelectedFiles } from './composer/SelectedFiles.js';
import { scrollToBottom } from './composer/ScrollToBottomContainer.js';
-import { ContextUsageBar } from './composer/ContextUsageBar.js';
-import { CommandBarInChat } from './composer/CommandBarInChat.js';
import { ChatMessageList } from './composer/ChatMessageList.js';
-import { StagingContextChips } from './composer/StagingContextChips.js';
+import { ComposerInputSection } from './composer/ComposerInputSection.js';
import { useContextUsage } from './composer/useContextUsage.js';
import { resolveAtReferencesInMessage } from '../../../../common/resolveAtReferences.js';
import { handleSlashCommand } from './composer/handleSlashCommand.js';
@@ -31,8 +29,6 @@ import ErrorBoundary from './ErrorBoundary.js';
import { useImageAttachments } from '../util/useImageAttachments.js';
import { usePDFAttachments } from '../util/usePDFAttachments.js';
import { useTranslation } from '../util/useTranslation.js';
-import { PDFAttachmentList } from '../util/PDFAttachmentList.js';
-import { ImageAttachmentList } from '../util/ImageAttachmentList.js';
import { IconX, IconWarning, IconLoading, TypingCursor } from './shared/icons.js';
import { getBasename, getFolderName, getRelative, voidOpenFileFn } from './shared/pathUtils.js';
import { ToolChildrenWrapper, CodeChildren, ListableToolItem } from './tools/ToolPrimitives.js';
@@ -260,117 +256,55 @@ export const SidebarChat = () => {
scrollToBottomCallback={scrollToBottomCallback}
/>
- const inputChatArea = onSubmit()}
- onAbort={onAbort}
- isStreaming={isActivelyStreaming}
- isDisabled={isDisabled}
- showSelections={true}
- // showProspectiveSelections={previousMessagesHTML.length === 0}
- selections={selections}
- setSelections={setSelections}
- onClickAnywhere={() => { textAreaRef.current?.focus() }}
- imageAttachments={
- imageAttachments.length > 0 ? (
- <>
-
- {imageValidationError && (
-
- {imageValidationError.message}
-
- )}
- >
- ) : null
- }
- onImagePaste={addImages}
- onImageDrop={addImages}
- onPDFDrop={addPDFs}
- pdfAttachments={
- pdfAttachments.length > 0 ? (
- <>
-
- {pdfValidationError && (
-
- {pdfValidationError}
-
- )}
- >
- ) : null
- }
- >
- { chatThreadsService.setCurrentlyFocusedMessageIdx(undefined) }}
- ref={textAreaRef}
- fnsRef={textAreaFnsRef}
- multiline={true}
- />
-
- {/* Context chips for current selections */}
- { chatThreadsService.popStagingSelections(1) }}
+ const composerInputProps = {
+ onSubmit: () => onSubmit(),
+ onAbort,
+ isStreaming: isActivelyStreaming,
+ isDisabled,
+ selections,
+ setSelections,
+ textAreaRef,
+ textAreaFnsRef,
+ onChangeText,
+ onKeyDown,
+ onInputFocus: () => { chatThreadsService.setCurrentlyFocusedMessageIdx(undefined) },
+ onRemoveStagingLast: () => { chatThreadsService.popStagingSelections(1) },
+ imageAttachments,
+ removeImage,
+ retryImage,
+ cancelImage,
+ focusedImageIndex,
+ setFocusedImageIndex,
+ imageValidationError,
+ addImages,
+ pdfAttachments,
+ removePDF,
+ retryPDF,
+ cancelPDF,
+ focusedPDFIndex,
+ setFocusedPDFIndex,
+ pdfValidationError,
+ addPDFs,
+ modelSel,
+ contextTotal,
+ contextBudget,
+ contextPct,
+ };
+
+ const landingPageInput = (
+
+ );
+
+ const threadPageInput = (
+
-
-
-
+ );
const isLandingPage = previousMessages.length === 0
-
- const threadPageInput =
-
-
-
-
- {inputChatArea}
-
- {/* Context usage indicator */}
- {modelSel ? (
-
- ) : null}
-
-
-
- const landingPageInput =
-
- {inputChatArea}
- {modelSel ? (
-
- ) : null}
-
-
-
const landingPageContent = (
+
+ {message}
+
+);
+
+export type ComposerInputAreaProps = {
+ onSubmit: () => void;
+ onAbort: () => void;
+ isStreaming: boolean;
+ isDisabled: boolean;
+ selections: StagingSelectionItem[];
+ setSelections: (selections: StagingSelectionItem[]) => void;
+ textAreaRef: RefObject;
+ textAreaFnsRef: RefObject;
+ onChangeText: (value: string) => void;
+ onKeyDown: (e: KeyboardEvent) => void;
+ onInputFocus: () => void;
+ onRemoveStagingLast: () => void;
+ imageAttachments: ChatImageAttachment[];
+ removeImage: (id: string) => void;
+ retryImage: (id: string) => Promise;
+ cancelImage: (id: string) => void;
+ focusedImageIndex: number | null;
+ setFocusedImageIndex: (index: number | null) => void;
+ imageValidationError: ImageValidationError | null;
+ addImages: (files: File[]) => Promise;
+ pdfAttachments: ChatPDFAttachment[];
+ removePDF: (id: string) => void;
+ retryPDF: (id: string) => Promise;
+ cancelPDF: (id: string) => void;
+ focusedPDFIndex: number | null;
+ setFocusedPDFIndex: (index: number | null) => void;
+ pdfValidationError: string | null;
+ addPDFs: (files: File[]) => Promise;
+};
+
+export const ComposerInputArea = ({
+ onSubmit,
+ onAbort,
+ isStreaming,
+ isDisabled,
+ selections,
+ setSelections,
+ textAreaRef,
+ textAreaFnsRef,
+ onChangeText,
+ onKeyDown,
+ onInputFocus,
+ onRemoveStagingLast,
+ imageAttachments,
+ removeImage,
+ retryImage,
+ cancelImage,
+ focusedImageIndex,
+ setFocusedImageIndex,
+ imageValidationError,
+ addImages,
+ pdfAttachments,
+ removePDF,
+ retryPDF,
+ cancelPDF,
+ focusedPDFIndex,
+ setFocusedPDFIndex,
+ pdfValidationError,
+ addPDFs,
+}: ComposerInputAreaProps) => (
+ { textAreaRef.current?.focus() }}
+ imageAttachments={
+ imageAttachments.length > 0 ? (
+ <>
+
+ {imageValidationError ? (
+
+ ) : null}
+ >
+ ) : null
+ }
+ onImagePaste={addImages}
+ onImageDrop={addImages}
+ onPDFDrop={addPDFs}
+ pdfAttachments={
+ pdfAttachments.length > 0 ? (
+ <>
+
+ {pdfValidationError ? (
+
+ ) : null}
+ >
+ ) : null
+ }
+ >
+
+
+
+);
diff --git a/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ComposerInputSection.tsx b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ComposerInputSection.tsx
new file mode 100644
index 00000000000..2b71ec26bcb
--- /dev/null
+++ b/src/vs/workbench/contrib/cortexide/browser/react/src/sidebar-tsx/composer/ComposerInputSection.tsx
@@ -0,0 +1,62 @@
+/*--------------------------------------------------------------------------------------
+ * Copyright 2025 Glass Devtools, Inc. All rights reserved.
+ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
+ *--------------------------------------------------------------------------------------*/
+
+import React from 'react';
+import { CommandBarInChat } from './CommandBarInChat.js';
+import { ContextUsageBar } from './ContextUsageBar.js';
+import { ComposerInputArea, ComposerInputAreaProps } from './ComposerInputArea.js';
+import { ModelSelection } from '../../../../common/cortexideSettingsTypes.js';
+
+type ComposerInputSectionProps = ComposerInputAreaProps & {
+ variant: 'landing' | 'thread';
+ threadKey?: string;
+ modelSel: ModelSelection | null | undefined;
+ contextTotal: number;
+ contextBudget: number;
+ contextPct: number;
+};
+
+export const ComposerInputSection = ({
+ variant,
+ threadKey,
+ modelSel,
+ contextTotal,
+ contextBudget,
+ contextPct,
+ ...inputProps
+}: ComposerInputSectionProps) => {
+ const inputArea = ;
+ const contextBar = modelSel ? (
+
+ ) : null;
+
+ if (variant === 'thread') {
+ return (
+
+
+
+
+
+ {inputArea}
+ {contextBar}
+
+
+ );
+ }
+
+ return (
+
+
+ {inputArea}
+ {contextBar}
+
+
+ );
+};