Repository navigation
fix(ui): distinguish auto approval mode indicators #4600
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,12 +20,12 @@ import { useReverseSearchCompletion } from '../hooks/useReverseSearchCompletion. | |||||||||
| import { useCommandCompletion } from '../hooks/useCommandCompletion.js'; | ||||||||||
| import { useExportCompletion } from '../hooks/useExportCompletion.js'; | ||||||||||
| import { useFollowupSuggestionsCLI } from '../hooks/useFollowupSuggestions.js'; | ||||||||||
| import type { Config } from '@qwen-code/qwen-code-core'; | ||||||||||
| import type { Key } from '../hooks/useKeypress.js'; | ||||||||||
| import { keyMatchers, Command } from '../keyMatchers.js'; | ||||||||||
| import type { CommandContext, SlashCommand } from '../commands/types.js'; | ||||||||||
| import { | ||||||||||
| ApprovalMode, | ||||||||||
| type Config, | ||||||||||
| Storage, | ||||||||||
| createDebugLogger, | ||||||||||
| } from '@qwen-code/qwen-code-core'; | ||||||||||
|
|
@@ -56,6 +56,7 @@ import { | |||||||||
| import { FEEDBACK_DIALOG_KEYS } from '../FeedbackDialog.js'; | ||||||||||
| import { BaseTextInput } from './BaseTextInput.js'; | ||||||||||
| import type { RenderLineOptions } from './BaseTextInput.js'; | ||||||||||
| import { getApprovalModePromptStyle } from './approvalModeVisuals.js'; | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Represents an attachment (e.g., pasted image) displayed above the input prompt | ||||||||||
|
|
@@ -1529,22 +1530,24 @@ export const InputPrompt: React.FC<InputPromptProps> = ({ | |||||||||
| // eslint-disable-next-line react-hooks/exhaustive-deps -- only trigger on prop change | ||||||||||
| }, [promptSuggestion]); | ||||||||||
|
|
||||||||||
| const showAutoAcceptStyling = | ||||||||||
| !shellModeActive && approvalMode === ApprovalMode.AUTO_EDIT; | ||||||||||
| const showYoloStyling = | ||||||||||
| !shellModeActive && approvalMode === ApprovalMode.YOLO; | ||||||||||
| const approvalModePromptStyle = !shellModeActive | ||||||||||
| ? getApprovalModePromptStyle(approvalMode) | ||||||||||
| : undefined; | ||||||||||
|
|
||||||||||
| let statusColor: string | undefined; | ||||||||||
| let statusText = ''; | ||||||||||
| if (shellModeActive) { | ||||||||||
| statusColor = theme.ui.symbol; | ||||||||||
| statusText = t('Shell mode'); | ||||||||||
| } else if (showYoloStyling) { | ||||||||||
| statusColor = theme.status.errorDim; | ||||||||||
| statusText = t('YOLO mode'); | ||||||||||
| } else if (showAutoAcceptStyling) { | ||||||||||
| statusColor = theme.status.warningDim; | ||||||||||
| statusText = t('Accepting edits'); | ||||||||||
| } else if (approvalModePromptStyle?.color) { | ||||||||||
| statusColor = approvalModePromptStyle.color; | ||||||||||
| if (approvalMode === ApprovalMode.YOLO) { | ||||||||||
| statusText = t('YOLO mode'); | ||||||||||
| } else if (approvalMode === ApprovalMode.AUTO_EDIT) { | ||||||||||
| statusText = t('Accepting edits'); | ||||||||||
| } else if (approvalMode === ApprovalMode.AUTO) { | ||||||||||
| statusText = t('Auto mode'); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| const borderColor = | ||||||||||
|
|
@@ -1567,8 +1570,8 @@ export const InputPrompt: React.FC<InputPromptProps> = ({ | |||||||||
| ) | ||||||||||
| ) : commandSearchActive ? ( | ||||||||||
| <Text color={theme.text.accent}>(r:) </Text> | ||||||||||
| ) : showYoloStyling ? ( | ||||||||||
| '*' | ||||||||||
| ) : approvalModePromptStyle ? ( | ||||||||||
| approvalModePromptStyle.prefix | ||||||||||
| ) : ( | ||||||||||
| '>' | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The
Suggested change
— qwen3.7-max via Qwen Code /review |
||||||||||
| )}{' '} | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -45,6 +45,7 @@ import { keyMatchers, Command } from '../../keyMatchers.js'; | |||||||||
| import { theme } from '../../semantic-colors.js'; | ||||||||||
| import { usePreferredEditor } from '../../hooks/usePreferredEditor.js'; | ||||||||||
| import { t } from '../../../i18n/index.js'; | ||||||||||
| import { getApprovalModePromptStyle } from '../approvalModeVisuals.js'; | ||||||||||
|
|
||||||||||
| // ─── Types ────────────────────────────────────────────────── | ||||||||||
|
|
||||||||||
|
|
@@ -243,22 +244,18 @@ export const AgentComposer: React.FC<AgentComposerProps> = ({ agentId }) => { | |||||||||
|
|
||||||||||
| // ── Approval-mode styling (mirrors main InputPrompt) ── | ||||||||||
|
|
||||||||||
| const isYolo = agentApprovalMode === ApprovalMode.YOLO; | ||||||||||
| const isAutoAccept = agentApprovalMode !== ApprovalMode.DEFAULT; | ||||||||||
|
|
||||||||||
| const statusColor = isYolo | ||||||||||
| ? theme.status.errorDim | ||||||||||
| : isAutoAccept | ||||||||||
| ? theme.status.warningDim | ||||||||||
| : undefined; | ||||||||||
| const approvalModePromptStyle = getApprovalModePromptStyle(agentApprovalMode); | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] PLAN mode silently loses visual styling in sub-agent views — behavioral regression. The old code used If this is intentional (PLAN shouldn't have warning-style coloring), consider adding a test that asserts
Suggested change
— qwen3.7-max via Qwen Code /review |
||||||||||
| const statusColor = approvalModePromptStyle.color; | ||||||||||
|
|
||||||||||
| const inputBorderColor = | ||||||||||
| !isInputActive || agentTabBarFocused | ||||||||||
| ? theme.border.default | ||||||||||
| : (statusColor ?? theme.border.focused); | ||||||||||
|
|
||||||||||
| const prefixNode = ( | ||||||||||
| <Text color={statusColor ?? theme.text.accent}>{isYolo ? '*' : '>'} </Text> | ||||||||||
| <Text color={statusColor ?? theme.text.accent}> | ||||||||||
| {approvalModePromptStyle.prefix}{' '} | ||||||||||
| </Text> | ||||||||||
| ); | ||||||||||
|
|
||||||||||
| return ( | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| /** | ||
| * @license | ||
| * Copyright 2025 Qwen Team | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| import { describe, expect, it } from 'vitest'; | ||
| import { ApprovalMode } from '@qwen-code/qwen-code-core'; | ||
| import { theme } from '../semantic-colors.js'; | ||
| import { | ||
| getApprovalModeIndicatorColor, | ||
| getApprovalModePromptStyle, | ||
| } from './approvalModeVisuals.js'; | ||
|
|
||
| describe('approval mode visuals', () => { | ||
| it('uses distinct colors for auto-edit and classifier auto mode', () => { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] Several
Adding these would guard against accidental styling regressions, especially for the PLAN/DEFAULT path which is the exact code path that changes behavior in — qwen3.7-max via Qwen Code /review |
||
| expect(getApprovalModeIndicatorColor(ApprovalMode.AUTO_EDIT)).toBe( | ||
| theme.status.warning, | ||
| ); | ||
| expect(getApprovalModeIndicatorColor(ApprovalMode.AUTO)).toBe( | ||
| theme.text.link, | ||
| ); | ||
| }); | ||
|
|
||
| it('gives classifier auto mode its own input styling', () => { | ||
| expect(getApprovalModePromptStyle(ApprovalMode.AUTO_EDIT)).toEqual({ | ||
| color: theme.status.warningDim, | ||
| prefix: '>', | ||
| }); | ||
| expect(getApprovalModePromptStyle(ApprovalMode.AUTO)).toEqual({ | ||
| color: theme.text.link, | ||
| prefix: '>', | ||
| }); | ||
| }); | ||
|
|
||
| it('keeps yolo visually separate from both auto modes', () => { | ||
| expect(getApprovalModePromptStyle(ApprovalMode.YOLO)).toEqual({ | ||
| color: theme.status.errorDim, | ||
| prefix: '*', | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /** | ||
| * @license | ||
| * Copyright 2025 Qwen Team | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| import { ApprovalMode } from '@qwen-code/qwen-code-core'; | ||
| import { theme } from '../semantic-colors.js'; | ||
|
|
||
| export function getApprovalModeIndicatorColor( | ||
| approvalMode: ApprovalMode, | ||
| ): string | undefined { | ||
| switch (approvalMode) { | ||
| case ApprovalMode.PLAN: | ||
| return theme.status.success; | ||
| case ApprovalMode.AUTO_EDIT: | ||
| return theme.status.warning; | ||
| case ApprovalMode.AUTO: | ||
| return theme.text.link; | ||
| case ApprovalMode.YOLO: | ||
| return theme.status.error; | ||
| case ApprovalMode.DEFAULT: | ||
| default: | ||
| return undefined; | ||
| } | ||
| } | ||
|
|
||
| export function getApprovalModePromptStyle(approvalMode: ApprovalMode): { | ||
| color?: string; | ||
| prefix: '>' | '*'; | ||
| } { | ||
| switch (approvalMode) { | ||
| case ApprovalMode.AUTO_EDIT: | ||
| return { color: theme.status.warningDim, prefix: '>' }; | ||
| case ApprovalMode.AUTO: | ||
| return { color: theme.text.link, prefix: '>' }; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] AUTO uses full-brightness Every other mode uses dim tokens for prompts: AUTO_EDIT → Consider adding an case ApprovalMode.AUTO:
return { color: theme.status.infoDim /* new AccentBlueDim token */, prefix: '>' };— qwen3.7-max via Qwen Code /review |
||
| case ApprovalMode.YOLO: | ||
| return { color: theme.status.errorDim, prefix: '*' }; | ||
| case ApprovalMode.PLAN: | ||
| case ApprovalMode.DEFAULT: | ||
| default: | ||
| return { prefix: '>' }; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] The
'Auto mode'key is missing from all locale files underpackages/cli/src/i18n/locales/(zh, fr, ca, ja, etc.) and frommustTranslateKeys.ts. All peer status-text keys ('Shell mode','YOLO mode','Accepting edits') are properly translated. Non-English users will see the raw English string"Auto mode"in the prompt status area.— qwen3.7-max via Qwen Code /review