@@ -466,18 +395,7 @@ function ChangesPanelBody(props: ChangesPanelBodyProps) {
totalFileCount={props.totalFileCount}
onOpenReview={props.onOpenReview}
/>
-
+
);
}
@@ -508,13 +426,13 @@ const ChangesPanel = memo(function ChangesPanel({
onOpenReview,
}: ChangesPanelProps) {
const isArchived = useIsTaskArchived();
- const { activeTaskId, activeSessionId, taskTitle, baseBranch, existingPrUrl } =
- useChangesPanelStoreData();
+ const { activeTaskId, activeSessionId, baseBranch, existingPrUrl } = useChangesPanelStoreData();
const git = useSessionGit(activeSessionId);
const { toast } = useToast();
const { reviews } = useSessionFileReviews(activeSessionId);
const { prDiffFiles, prCommitsList, hasPRFiles, hasPRCommits, prFiles } = useChangesPanelPRData();
+ const vcsDialogs = useVcsDialogs();
// Periodically check for a PR when the session has a branch but no PR yet
useTaskPRDetection(
@@ -534,14 +452,8 @@ const ChangesPanel = memo(function ChangesPanel({
const staged = useMemo(() => computeStagedStats(git.stagedFiles), [git.stagedFiles]);
const gitHandlers = useChangesGitHandlers(git, toast, baseBranch);
- const firstCommitMessage = git.commits?.[0]?.commit_message;
- const dialogs = useChangesDialogHandlers(git, toast, gitHandlers.handleGitOperation, {
- taskTitle,
- baseBranch,
- firstCommitMessage,
- });
- const isUtilityConfigured = useIsUtilityConfigured();
- const utilityGen = useUtilityAgentGenerator({ sessionId: activeSessionId ?? null, taskTitle });
+ const localDialogs = useChangesDialogHandlers(git, toast, gitHandlers.handleGitOperation);
+ const dialogs = { ...localDialogs, ...vcsDialogs };
if (isArchived) return
;
@@ -597,10 +509,6 @@ const ChangesPanel = memo(function ChangesPanel({
stagedFileCount={staged.stagedFileCount}
stagedAdditions={staged.stagedAdditions}
stagedDeletions={staged.stagedDeletions}
- displayBranch={git.branch}
- baseBranch={baseBranch}
- utilityGen={utilityGen}
- isUtilityConfigured={isUtilityConfigured}
/>
);
diff --git a/apps/web/components/task/chat/chat-input-body.tsx b/apps/web/components/task/chat/chat-input-body.tsx
index 67fcd481f1..24731eebfd 100644
--- a/apps/web/components/task/chat/chat-input-body.tsx
+++ b/apps/web/components/task/chat/chat-input-body.tsx
@@ -47,6 +47,7 @@ export type ChatInputEditorAreaProps = {
onImplementPlan?: () => void;
onEnhancePrompt?: () => void;
isEnhancingPrompt?: boolean;
+ isUtilityConfigured?: boolean;
};
function EditorWithTooltip({
@@ -143,15 +144,12 @@ export function ChatInputEditorArea({
onImplementPlan,
onEnhancePrompt,
isEnhancingPrompt,
+ isUtilityConfigured,
hideSessionsDropdown,
}: ChatInputEditorAreaProps) {
// Block submit while enhancing prompt, but keep editor editable for programmatic updates
const wrappedSubmit = isEnhancingPrompt ? () => {} : handleSubmitWithReset;
-
- const handleAttachFiles = useCallback(() => {
- fileInputRef.current?.click();
- }, [fileInputRef]);
-
+ const handleAttachFiles = useCallback(() => fileInputRef.current?.click(), [fileInputRef]);
return (
diff --git a/apps/web/components/task/chat/chat-input-container.tsx b/apps/web/components/task/chat/chat-input-container.tsx
index e1771adfa7..7b8c3ca2c8 100644
--- a/apps/web/components/task/chat/chat-input-container.tsx
+++ b/apps/web/components/task/chat/chat-input-container.tsx
@@ -139,6 +139,7 @@ function buildContextAreaProps(
type EnhancePromptExtras = {
onEnhancePrompt?: () => void;
isEnhancingPrompt?: boolean;
+ isUtilityConfigured?: boolean;
};
function buildEditorAreaProps(
@@ -181,6 +182,7 @@ function buildEditorAreaProps(
onImplementPlan: p.onImplementPlan,
onEnhancePrompt: extras.onEnhancePrompt,
isEnhancingPrompt: extras.isEnhancingPrompt,
+ isUtilityConfigured: extras.isUtilityConfigured,
hideSessionsDropdown: p.hideSessionsDropdown,
};
}
@@ -273,11 +275,11 @@ export const ChatInputContainer = forwardRef
);
},
diff --git a/apps/web/components/task/chat/chat-input-toolbar.tsx b/apps/web/components/task/chat/chat-input-toolbar.tsx
index 04fc57a3d5..3190d12a0e 100644
--- a/apps/web/components/task/chat/chat-input-toolbar.tsx
+++ b/apps/web/components/task/chat/chat-input-toolbar.tsx
@@ -65,6 +65,8 @@ export type ChatInputToolbarProps = {
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;
/** Hide the sessions dropdown (for quick chat) */
@@ -181,24 +183,40 @@ function ImplementPlanButton({ onClick }: { onClick: () => void }) {
);
}
-function EnhancePromptButton({ onClick, isLoading }: { onClick: () => void; isLoading: boolean }) {
+function EnhancePromptButton({
+ onClick,
+ isLoading,
+ isConfigured = true,
+}: {
+ onClick: () => void;
+ isLoading: boolean;
+ isConfigured?: boolean;
+}) {
+ const isDisabled = !isConfigured || isLoading;
+ const tooltipText = isConfigured
+ ? "Enhance prompt with AI"
+ : "Configure a utility agent in settings to enable AI enhancement";
+
return (
-
+ {/* Wrap in span so tooltip works even when button is disabled */}
+
+
+
- Enhance prompt with AI
+ {tooltipText}
);
}
@@ -308,6 +326,7 @@ type ToolbarRightSectionProps = {
submitShortcut: (typeof SHORTCUTS)[keyof typeof SHORTCUTS];
onEnhancePrompt?: () => void;
isEnhancingPrompt?: boolean;
+ isUtilityConfigured?: boolean;
onImplementPlan?: () => void;
hideSessionsDropdown?: boolean;
};
@@ -326,10 +345,11 @@ function ToolbarRightSection({
submitShortcut,
onEnhancePrompt,
isEnhancingPrompt,
+ isUtilityConfigured,
onImplementPlan,
hideSessionsDropdown,
}: ToolbarRightSectionProps) {
- const showEnhance = onEnhancePrompt && !isAgentBusy;
+ const showEnhance = !isAgentBusy;
const showImplement = planModeEnabled && !isAgentBusy && onImplementPlan;
const showResetContext = !!sessionId && !isAgentBusy;
return (
@@ -349,7 +369,11 @@ function ToolbarRightSection({
{/* AuthMethodsIndicator hidden — UX needs rethinking */}
{showEnhance && (
-
+
{})}
+ isLoading={isEnhancingPrompt ?? false}
+ isConfigured={isUtilityConfigured}
+ />
)}
{showImplement && }
@@ -391,6 +415,7 @@ export const ChatInputToolbar = memo(function ChatInputToolbar({
onImplementPlan,
onEnhancePrompt,
isEnhancingPrompt = false,
+ isUtilityConfigured = false,
onAttachFiles,
hideSessionsDropdown,
}: ChatInputToolbarProps) {
@@ -465,6 +490,7 @@ export const ChatInputToolbar = memo(function ChatInputToolbar({
submitShortcut={submitShortcut}
onEnhancePrompt={onEnhancePrompt}
isEnhancingPrompt={isEnhancingPrompt}
+ isUtilityConfigured={isUtilityConfigured}
onImplementPlan={onImplementPlan}
hideSessionsDropdown={hideSessionsDropdown}
/>
diff --git a/apps/web/components/vcs/vcs-dialogs.tsx b/apps/web/components/vcs/vcs-dialogs.tsx
index 32760232da..f7358b2677 100644
--- a/apps/web/components/vcs/vcs-dialogs.tsx
+++ b/apps/web/components/vcs/vcs-dialogs.tsx
@@ -88,6 +88,8 @@ type GenerateButtonProps = {
isGenerating: boolean;
disabled?: boolean;
tooltip: string;
+ notConfiguredTooltip?: string;
+ isConfigured?: boolean;
size?: "icon" | "sm";
showLabel?: boolean;
};
@@ -97,31 +99,39 @@ function GenerateButton({
isGenerating,
disabled,
tooltip,
+ notConfiguredTooltip = "Configure a utility agent in settings to enable AI generation",
+ isConfigured = true,
size = "icon",
showLabel,
}: GenerateButtonProps) {
+ const isDisabled = !isConfigured || disabled || isGenerating;
+ const tooltipText = isConfigured ? tooltip : notConfiguredTooltip;
+
return (
-
+ {/* Wrap in span so tooltip works even when button is disabled */}
+
+
+
- {tooltip}
+ {tooltipText}
);
}
@@ -136,8 +146,9 @@ type CommitDialogProps = {
onStageAllChange: (v: boolean) => void;
isGitLoading: boolean;
onCommit: () => void;
- onGenerateMessage?: () => void;
- isGenerating?: boolean;
+ onGenerateMessage: () => void;
+ isGenerating: boolean;
+ isUtilityConfigured: boolean;
};
function CommitDialog({
@@ -152,6 +163,7 @@ function CommitDialog({
onCommit,
onGenerateMessage,
isGenerating,
+ isUtilityConfigured,
}: CommitDialogProps) {
return (
-
@@ -234,8 +245,9 @@ type PRDialogProps = {
onPrDraftChange: (v: boolean) => void;
isGitLoading: boolean;
onCreatePR: () => void;
- onGenerateDescription?: () => void;
- isGenerating?: boolean;
+ onGenerateDescription: () => void;
+ isGenerating: boolean;
+ isUtilityConfigured: boolean;
};
function PRBranchSummary({
@@ -278,6 +290,7 @@ function PRDialog({
onCreatePR,
onGenerateDescription,
isGenerating,
+ isUtilityConfigured,
}: PRDialogProps) {
return (