mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
refactor(vscode-ide-companion): introduce ApprovalMode enum and improve mode handling
- Create new approvalModeTypes.ts with ApprovalMode enum and helper functions - Replace hardcoded string literals with ApprovalModeValue type - Consolidate mode mapping logic using new helper functions
This commit is contained in:
@@ -10,6 +10,7 @@ import type {
|
|||||||
AcpPermissionRequest,
|
AcpPermissionRequest,
|
||||||
AcpResponse,
|
AcpResponse,
|
||||||
AcpSessionUpdate,
|
AcpSessionUpdate,
|
||||||
|
ApprovalModeValue,
|
||||||
} from '../types/acpTypes.js';
|
} from '../types/acpTypes.js';
|
||||||
import type { ChildProcess, SpawnOptions } from 'child_process';
|
import type { ChildProcess, SpawnOptions } from 'child_process';
|
||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
@@ -380,9 +381,7 @@ export class AcpConnection {
|
|||||||
/**
|
/**
|
||||||
* Set approval mode
|
* Set approval mode
|
||||||
*/
|
*/
|
||||||
async setMode(
|
async setMode(modeId: ApprovalModeValue): Promise<AcpResponse> {
|
||||||
modeId: 'plan' | 'default' | 'auto-edit' | 'yolo',
|
|
||||||
): Promise<AcpResponse> {
|
|
||||||
return this.sessionManager.setMode(
|
return this.sessionManager.setMode(
|
||||||
modeId,
|
modeId,
|
||||||
this.child,
|
this.child,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import type {
|
|||||||
AcpRequest,
|
AcpRequest,
|
||||||
AcpNotification,
|
AcpNotification,
|
||||||
AcpResponse,
|
AcpResponse,
|
||||||
|
ApprovalModeValue,
|
||||||
} from '../types/acpTypes.js';
|
} from '../types/acpTypes.js';
|
||||||
import { AGENT_METHODS } from '../constants/acpSchema.js';
|
import { AGENT_METHODS } from '../constants/acpSchema.js';
|
||||||
import type { PendingRequest } from '../types/connectionTypes.js';
|
import type { PendingRequest } from '../types/connectionTypes.js';
|
||||||
@@ -341,10 +342,10 @@ export class AcpSessionManager {
|
|||||||
/**
|
/**
|
||||||
* Set approval mode for current session (ACP session/set_mode)
|
* Set approval mode for current session (ACP session/set_mode)
|
||||||
*
|
*
|
||||||
* @param modeId - 'plan' | 'default' | 'auto-edit' | 'yolo'
|
* @param modeId - Approval mode value
|
||||||
*/
|
*/
|
||||||
async setMode(
|
async setMode(
|
||||||
modeId: 'plan' | 'default' | 'auto-edit' | 'yolo',
|
modeId: ApprovalModeValue,
|
||||||
child: ChildProcess | null,
|
child: ChildProcess | null,
|
||||||
pendingRequests: Map<number, PendingRequest<unknown>>,
|
pendingRequests: Map<number, PendingRequest<unknown>>,
|
||||||
nextRequestId: { value: number },
|
nextRequestId: { value: number },
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { AcpConnection } from './acpConnection.js';
|
|||||||
import type {
|
import type {
|
||||||
AcpSessionUpdate,
|
AcpSessionUpdate,
|
||||||
AcpPermissionRequest,
|
AcpPermissionRequest,
|
||||||
|
ApprovalModeValue,
|
||||||
} from '../types/acpTypes.js';
|
} from '../types/acpTypes.js';
|
||||||
import { QwenSessionReader, type QwenSession } from './qwenSessionReader.js';
|
import { QwenSessionReader, type QwenSession } from './qwenSessionReader.js';
|
||||||
import { QwenSessionManager } from './qwenSessionManager.js';
|
import { QwenSessionManager } from './qwenSessionManager.js';
|
||||||
@@ -138,21 +139,12 @@ export class QwenAgentManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set approval mode from UI (maps UI edit mode -> ACP mode id)
|
* Set approval mode from UI
|
||||||
*/
|
*/
|
||||||
async setApprovalModeFromUi(
|
async setApprovalModeFromUi(
|
||||||
uiMode: 'ask' | 'auto' | 'plan' | 'yolo',
|
mode: ApprovalModeValue,
|
||||||
): Promise<'plan' | 'default' | 'auto-edit' | 'yolo'> {
|
): Promise<ApprovalModeValue> {
|
||||||
const map: Record<
|
const modeId = mode;
|
||||||
'ask' | 'auto' | 'plan' | 'yolo',
|
|
||||||
'plan' | 'default' | 'auto-edit' | 'yolo'
|
|
||||||
> = {
|
|
||||||
plan: 'plan',
|
|
||||||
ask: 'default',
|
|
||||||
auto: 'auto-edit',
|
|
||||||
yolo: 'yolo',
|
|
||||||
} as const;
|
|
||||||
const modeId = map[uiMode];
|
|
||||||
try {
|
try {
|
||||||
const res = await this.connection.setMode(modeId);
|
const res = await this.connection.setMode(modeId);
|
||||||
// Optimistically notify UI using response
|
// Optimistically notify UI using response
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
export const JSONRPC_VERSION = '2.0' as const;
|
export const JSONRPC_VERSION = '2.0' as const;
|
||||||
export const authMethod = 'qwen-oauth';
|
export const authMethod = 'qwen-oauth';
|
||||||
|
|
||||||
export type AcpBackend = 'qwen';
|
|
||||||
|
|
||||||
export interface AcpRequest {
|
export interface AcpRequest {
|
||||||
jsonrpc: typeof JSONRPC_VERSION;
|
jsonrpc: typeof JSONRPC_VERSION;
|
||||||
id: number;
|
id: number;
|
||||||
@@ -36,7 +34,6 @@ export interface AcpNotification {
|
|||||||
params?: unknown;
|
params?: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Base interface for all session updates
|
|
||||||
export interface BaseSessionUpdate {
|
export interface BaseSessionUpdate {
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
}
|
}
|
||||||
@@ -50,7 +47,6 @@ export interface ContentBlock {
|
|||||||
uri?: string;
|
uri?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// User message chunk update
|
|
||||||
export interface UserMessageChunkUpdate extends BaseSessionUpdate {
|
export interface UserMessageChunkUpdate extends BaseSessionUpdate {
|
||||||
update: {
|
update: {
|
||||||
sessionUpdate: 'user_message_chunk';
|
sessionUpdate: 'user_message_chunk';
|
||||||
@@ -58,7 +54,6 @@ export interface UserMessageChunkUpdate extends BaseSessionUpdate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Agent message chunk update
|
|
||||||
export interface AgentMessageChunkUpdate extends BaseSessionUpdate {
|
export interface AgentMessageChunkUpdate extends BaseSessionUpdate {
|
||||||
update: {
|
update: {
|
||||||
sessionUpdate: 'agent_message_chunk';
|
sessionUpdate: 'agent_message_chunk';
|
||||||
@@ -66,7 +61,6 @@ export interface AgentMessageChunkUpdate extends BaseSessionUpdate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Agent thought chunk update
|
|
||||||
export interface AgentThoughtChunkUpdate extends BaseSessionUpdate {
|
export interface AgentThoughtChunkUpdate extends BaseSessionUpdate {
|
||||||
update: {
|
update: {
|
||||||
sessionUpdate: 'agent_thought_chunk';
|
sessionUpdate: 'agent_thought_chunk';
|
||||||
@@ -74,7 +68,6 @@ export interface AgentThoughtChunkUpdate extends BaseSessionUpdate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tool call update
|
|
||||||
export interface ToolCallUpdate extends BaseSessionUpdate {
|
export interface ToolCallUpdate extends BaseSessionUpdate {
|
||||||
update: {
|
update: {
|
||||||
sessionUpdate: 'tool_call';
|
sessionUpdate: 'tool_call';
|
||||||
@@ -109,7 +102,6 @@ export interface ToolCallUpdate extends BaseSessionUpdate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tool call status update
|
|
||||||
export interface ToolCallStatusUpdate extends BaseSessionUpdate {
|
export interface ToolCallStatusUpdate extends BaseSessionUpdate {
|
||||||
update: {
|
update: {
|
||||||
sessionUpdate: 'tool_call_update';
|
sessionUpdate: 'tool_call_update';
|
||||||
@@ -135,7 +127,6 @@ export interface ToolCallStatusUpdate extends BaseSessionUpdate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plan update
|
|
||||||
export interface PlanUpdate extends BaseSessionUpdate {
|
export interface PlanUpdate extends BaseSessionUpdate {
|
||||||
update: {
|
update: {
|
||||||
sessionUpdate: 'plan';
|
sessionUpdate: 'plan';
|
||||||
@@ -147,9 +138,15 @@ export interface PlanUpdate extends BaseSessionUpdate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Approval/Mode values as defined by ACP schema
|
|
||||||
export type ApprovalModeValue = 'plan' | 'default' | 'auto-edit' | 'yolo';
|
export type ApprovalModeValue = 'plan' | 'default' | 'auto-edit' | 'yolo';
|
||||||
|
|
||||||
|
export {
|
||||||
|
ApprovalMode,
|
||||||
|
APPROVAL_MODE_MAP,
|
||||||
|
APPROVAL_MODE_INFO,
|
||||||
|
getApprovalModeInfoFromString,
|
||||||
|
} from './approvalModeTypes.js';
|
||||||
|
|
||||||
// Current mode update (sent by agent when mode changes)
|
// Current mode update (sent by agent when mode changes)
|
||||||
export interface CurrentModeUpdate extends BaseSessionUpdate {
|
export interface CurrentModeUpdate extends BaseSessionUpdate {
|
||||||
update: {
|
update: {
|
||||||
@@ -158,7 +155,6 @@ export interface CurrentModeUpdate extends BaseSessionUpdate {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Union type for all session updates
|
|
||||||
export type AcpSessionUpdate =
|
export type AcpSessionUpdate =
|
||||||
| UserMessageChunkUpdate
|
| UserMessageChunkUpdate
|
||||||
| AgentMessageChunkUpdate
|
| AgentMessageChunkUpdate
|
||||||
|
|||||||
79
packages/vscode-ide-companion/src/types/approvalModeTypes.ts
Normal file
79
packages/vscode-ide-companion/src/types/approvalModeTypes.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2025 Qwen Team
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum for approval modes with UI-friendly labels
|
||||||
|
* Represents the different approval modes available in the ACP protocol
|
||||||
|
* with their corresponding user-facing display names
|
||||||
|
*/
|
||||||
|
export enum ApprovalMode {
|
||||||
|
PLAN = 'plan',
|
||||||
|
DEFAULT = 'default',
|
||||||
|
AUTO_EDIT = 'auto-edit',
|
||||||
|
YOLO = 'yolo',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping from string values to enum values for runtime conversion
|
||||||
|
*/
|
||||||
|
export const APPROVAL_MODE_MAP: Record<string, ApprovalMode> = {
|
||||||
|
plan: ApprovalMode.PLAN,
|
||||||
|
default: ApprovalMode.DEFAULT,
|
||||||
|
'auto-edit': ApprovalMode.AUTO_EDIT,
|
||||||
|
yolo: ApprovalMode.YOLO,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UI display information for each approval mode
|
||||||
|
*/
|
||||||
|
export const APPROVAL_MODE_INFO: Record<
|
||||||
|
ApprovalMode,
|
||||||
|
{
|
||||||
|
label: string;
|
||||||
|
title: string;
|
||||||
|
iconType?: 'edit' | 'auto' | 'plan' | 'yolo';
|
||||||
|
}
|
||||||
|
> = {
|
||||||
|
[ApprovalMode.PLAN]: {
|
||||||
|
label: 'Plan mode',
|
||||||
|
title: 'Qwen will plan before executing. Click to switch modes.',
|
||||||
|
iconType: 'plan',
|
||||||
|
},
|
||||||
|
[ApprovalMode.DEFAULT]: {
|
||||||
|
label: 'Ask before edits',
|
||||||
|
title: 'Qwen will ask before each edit. Click to switch modes.',
|
||||||
|
iconType: 'edit',
|
||||||
|
},
|
||||||
|
[ApprovalMode.AUTO_EDIT]: {
|
||||||
|
label: 'Edit automatically',
|
||||||
|
title: 'Qwen will edit files automatically. Click to switch modes.',
|
||||||
|
iconType: 'auto',
|
||||||
|
},
|
||||||
|
[ApprovalMode.YOLO]: {
|
||||||
|
label: 'YOLO',
|
||||||
|
title: 'Automatically approve all tools. Click to switch modes.',
|
||||||
|
iconType: 'yolo',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get UI display information for an approval mode from string value
|
||||||
|
*/
|
||||||
|
export function getApprovalModeInfoFromString(mode: string): {
|
||||||
|
label: string;
|
||||||
|
title: string;
|
||||||
|
iconType?: 'edit' | 'auto' | 'plan' | 'yolo';
|
||||||
|
} {
|
||||||
|
const enumValue = APPROVAL_MODE_MAP[mode];
|
||||||
|
if (enumValue !== undefined) {
|
||||||
|
return APPROVAL_MODE_INFO[enumValue];
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
label: 'Unknown mode',
|
||||||
|
title: 'Unknown edit mode',
|
||||||
|
iconType: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
* Copyright 2025 Qwen Team
|
* Copyright 2025 Qwen Team
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
import type { AcpPermissionRequest } from './acpTypes.js';
|
import type { AcpPermissionRequest, ApprovalModeValue } from './acpTypes.js';
|
||||||
|
|
||||||
export interface ChatMessage {
|
export interface ChatMessage {
|
||||||
role: 'user' | 'assistant';
|
role: 'user' | 'assistant';
|
||||||
@@ -66,15 +66,15 @@ export interface QwenAgentCallbacks {
|
|||||||
onEndTurn?: () => void;
|
onEndTurn?: () => void;
|
||||||
/** Callback for receiving mode information after ACP initialization */
|
/** Callback for receiving mode information after ACP initialization */
|
||||||
onModeInfo?: (info: {
|
onModeInfo?: (info: {
|
||||||
currentModeId?: 'plan' | 'default' | 'auto-edit' | 'yolo';
|
currentModeId?: ApprovalModeValue;
|
||||||
availableModes?: Array<{
|
availableModes?: Array<{
|
||||||
id: 'plan' | 'default' | 'auto-edit' | 'yolo';
|
id: ApprovalModeValue;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
}>;
|
}>;
|
||||||
}) => void;
|
}) => void;
|
||||||
/** Callback for receiving notifications when the mode changes */
|
/** Callback for receiving notifications when the mode changes */
|
||||||
onModeChanged?: (modeId: 'plan' | 'default' | 'auto-edit' | 'yolo') => void;
|
onModeChanged?: (modeId: ApprovalModeValue) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,8 +105,3 @@ export interface ToolCallUpdate {
|
|||||||
}>;
|
}>;
|
||||||
timestamp?: number; // Add timestamp field for message ordering
|
timestamp?: number; // Add timestamp field for message ordering
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Edit mode type
|
|
||||||
*/
|
|
||||||
export type EditMode = 'ask' | 'auto' | 'plan' | 'yolo';
|
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ import {
|
|||||||
import { InputForm } from './components/layout/InputForm.js';
|
import { InputForm } from './components/layout/InputForm.js';
|
||||||
import { SessionSelector } from './components/layout/SessionSelector.js';
|
import { SessionSelector } from './components/layout/SessionSelector.js';
|
||||||
import { FileIcon, UserIcon } from './components/icons/index.js';
|
import { FileIcon, UserIcon } from './components/icons/index.js';
|
||||||
import type { EditMode } from '../types/chatTypes.js';
|
import { ApprovalMode } from '../types/acpTypes.js';
|
||||||
|
import type { ApprovalModeValue } from '../types/acpTypes.js';
|
||||||
import type { PlanEntry } from '../types/chatTypes.js';
|
import type { PlanEntry } from '../types/chatTypes.js';
|
||||||
|
|
||||||
export const App: React.FC = () => {
|
export const App: React.FC = () => {
|
||||||
@@ -77,7 +78,9 @@ export const App: React.FC = () => {
|
|||||||
null,
|
null,
|
||||||
) as React.RefObject<HTMLDivElement>;
|
) as React.RefObject<HTMLDivElement>;
|
||||||
|
|
||||||
const [editMode, setEditMode] = useState<EditMode>('ask');
|
const [editMode, setEditMode] = useState<ApprovalModeValue>(
|
||||||
|
ApprovalMode.DEFAULT,
|
||||||
|
);
|
||||||
const [thinkingEnabled, setThinkingEnabled] = useState(false);
|
const [thinkingEnabled, setThinkingEnabled] = useState(false);
|
||||||
const [isComposing, setIsComposing] = useState(false);
|
const [isComposing, setIsComposing] = useState(false);
|
||||||
// When true, do NOT auto-attach the active editor file/selection to message context
|
// When true, do NOT auto-attach the active editor file/selection to message context
|
||||||
@@ -461,30 +464,22 @@ export const App: React.FC = () => {
|
|||||||
});
|
});
|
||||||
}, [vscode]);
|
}, [vscode]);
|
||||||
|
|
||||||
// Handle toggle edit mode (Ask -> Auto -> Plan -> YOLO -> Ask)
|
// Handle toggle edit mode (Default -> Auto-edit -> Plan -> YOLO -> Default)
|
||||||
const handleToggleEditMode = useCallback(() => {
|
const handleToggleEditMode = useCallback(() => {
|
||||||
setEditMode((prev) => {
|
setEditMode((prev) => {
|
||||||
const next: EditMode =
|
const next: ApprovalModeValue =
|
||||||
prev === 'ask'
|
prev === ApprovalMode.DEFAULT
|
||||||
? 'auto'
|
? ApprovalMode.AUTO_EDIT
|
||||||
: prev === 'auto'
|
: prev === ApprovalMode.AUTO_EDIT
|
||||||
? 'plan'
|
? ApprovalMode.PLAN
|
||||||
: prev === 'plan'
|
: prev === ApprovalMode.PLAN
|
||||||
? 'yolo'
|
? ApprovalMode.YOLO
|
||||||
: 'ask';
|
: ApprovalMode.DEFAULT;
|
||||||
// Notify extension to set approval mode via ACP
|
// Notify extension to set approval mode via ACP
|
||||||
try {
|
try {
|
||||||
const toAcp =
|
|
||||||
next === 'plan'
|
|
||||||
? 'plan'
|
|
||||||
: next === 'auto'
|
|
||||||
? 'auto-edit'
|
|
||||||
: next === 'yolo'
|
|
||||||
? 'yolo'
|
|
||||||
: 'default';
|
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
type: 'setApprovalMode',
|
type: 'setApprovalMode',
|
||||||
data: { modeId: toAcp },
|
data: { modeId: next },
|
||||||
});
|
});
|
||||||
} catch {
|
} catch {
|
||||||
/* no-op */
|
/* no-op */
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { MessageHandler } from '../webview/MessageHandler.js';
|
|||||||
import { WebViewContent } from '../webview/WebViewContent.js';
|
import { WebViewContent } from '../webview/WebViewContent.js';
|
||||||
import { CliInstaller } from '../cli/cliInstaller.js';
|
import { CliInstaller } from '../cli/cliInstaller.js';
|
||||||
import { getFileName } from './utils/webviewUtils.js';
|
import { getFileName } from './utils/webviewUtils.js';
|
||||||
import { authMethod } from '../types/acpTypes.js';
|
import { authMethod, type ApprovalModeValue } from '../types/acpTypes.js';
|
||||||
|
|
||||||
export class WebViewProvider {
|
export class WebViewProvider {
|
||||||
private panelManager: PanelManager;
|
private panelManager: PanelManager;
|
||||||
@@ -31,8 +31,7 @@ export class WebViewProvider {
|
|||||||
private pendingPermissionRequest: AcpPermissionRequest | null = null;
|
private pendingPermissionRequest: AcpPermissionRequest | null = null;
|
||||||
private pendingPermissionResolve: ((optionId: string) => void) | null = null;
|
private pendingPermissionResolve: ((optionId: string) => void) | null = null;
|
||||||
// Track current ACP mode id to influence permission/diff behavior
|
// Track current ACP mode id to influence permission/diff behavior
|
||||||
private currentModeId: 'plan' | 'default' | 'auto-edit' | 'yolo' | null =
|
private currentModeId: ApprovalModeValue | null = null;
|
||||||
null;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
context: vscode.ExtensionContext,
|
context: vscode.ExtensionContext,
|
||||||
@@ -885,7 +884,7 @@ export class WebViewProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Get current ACP mode id (if known). */
|
/** Get current ACP mode id (if known). */
|
||||||
getCurrentModeId(): 'plan' | 'default' | 'auto-edit' | 'yolo' | null {
|
getCurrentModeId(): ApprovalModeValue | null {
|
||||||
return this.currentModeId;
|
return this.currentModeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ import {
|
|||||||
} from '../icons/index.js';
|
} from '../icons/index.js';
|
||||||
import { CompletionMenu } from '../layout/CompletionMenu.js';
|
import { CompletionMenu } from '../layout/CompletionMenu.js';
|
||||||
import type { CompletionItem } from '../../../types/completionItemTypes.js';
|
import type { CompletionItem } from '../../../types/completionItemTypes.js';
|
||||||
import type { EditMode } from '../../../types/chatTypes.js';
|
import { getApprovalModeInfoFromString } from '../../../types/acpTypes.js';
|
||||||
|
import type { ApprovalModeValue } from '../../../types/acpTypes.js';
|
||||||
|
|
||||||
interface InputFormProps {
|
interface InputFormProps {
|
||||||
inputText: string;
|
inputText: string;
|
||||||
@@ -29,7 +30,7 @@ interface InputFormProps {
|
|||||||
isStreaming: boolean;
|
isStreaming: boolean;
|
||||||
isWaitingForResponse: boolean;
|
isWaitingForResponse: boolean;
|
||||||
isComposing: boolean;
|
isComposing: boolean;
|
||||||
editMode: EditMode;
|
editMode: ApprovalModeValue;
|
||||||
thinkingEnabled: boolean;
|
thinkingEnabled: boolean;
|
||||||
activeFileName: string | null;
|
activeFileName: string | null;
|
||||||
activeSelection: { startLine: number; endLine: number } | null;
|
activeSelection: { startLine: number; endLine: number } | null;
|
||||||
@@ -53,41 +54,35 @@ interface InputFormProps {
|
|||||||
onCompletionClose?: () => void;
|
onCompletionClose?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get edit mode display info
|
// Get edit mode display info using helper function
|
||||||
const getEditModeInfo = (editMode: EditMode) => {
|
const getEditModeInfo = (editMode: ApprovalModeValue) => {
|
||||||
switch (editMode) {
|
const info = getApprovalModeInfoFromString(editMode);
|
||||||
case 'ask':
|
|
||||||
return {
|
// Map icon types to actual icons
|
||||||
text: 'Ask before edits',
|
let icon = null;
|
||||||
title: 'Qwen will ask before each edit. Click to switch modes.',
|
switch (info.iconType) {
|
||||||
icon: <EditPencilIcon />,
|
case 'edit':
|
||||||
};
|
icon = <EditPencilIcon />;
|
||||||
|
break;
|
||||||
case 'auto':
|
case 'auto':
|
||||||
return {
|
icon = <AutoEditIcon />;
|
||||||
text: 'Edit automatically',
|
break;
|
||||||
title: 'Qwen will edit files automatically. Click to switch modes.',
|
|
||||||
icon: <AutoEditIcon />,
|
|
||||||
};
|
|
||||||
case 'plan':
|
case 'plan':
|
||||||
return {
|
icon = <PlanModeIcon />;
|
||||||
text: 'Plan mode',
|
break;
|
||||||
title: 'Qwen will plan before executing. Click to switch modes.',
|
|
||||||
icon: <PlanModeIcon />,
|
|
||||||
};
|
|
||||||
case 'yolo':
|
case 'yolo':
|
||||||
return {
|
icon = <AutoEditIcon />;
|
||||||
text: 'YOLO',
|
break;
|
||||||
title: 'Automatically approve all tools. Click to switch modes.',
|
|
||||||
// Reuse Auto icon for simplicity; can swap to a distinct icon later.
|
|
||||||
icon: <AutoEditIcon />,
|
|
||||||
};
|
|
||||||
default:
|
default:
|
||||||
return {
|
icon = null;
|
||||||
text: 'Unknown mode',
|
break;
|
||||||
title: 'Unknown edit mode',
|
|
||||||
icon: null,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
text: info.label,
|
||||||
|
title: info.title,
|
||||||
|
icon,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InputForm: React.FC<InputFormProps> = ({
|
export const InputForm: React.FC<InputFormProps> = ({
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
* @license
|
* @license
|
||||||
* Copyright 2025 Qwen Team
|
* Copyright 2025 Qwen Team
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
|
||||||
* MessageContent component - renders message with code highlighting and clickable file paths
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
@@ -14,9 +12,6 @@ interface MessageContentProps {
|
|||||||
onFileClick?: (filePath: string) => void;
|
onFileClick?: (filePath: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* MessageContent component - renders message content with markdown support
|
|
||||||
*/
|
|
||||||
export const MessageContent: React.FC<MessageContentProps> = ({
|
export const MessageContent: React.FC<MessageContentProps> = ({
|
||||||
content,
|
content,
|
||||||
onFileClick,
|
onFileClick,
|
||||||
|
|||||||
@@ -37,12 +37,5 @@ export const ThinkingMessage: React.FC<ThinkingMessageProps> = ({
|
|||||||
</span>
|
</span>
|
||||||
<MessageContent content={content} onFileClick={onFileClick} />
|
<MessageContent content={content} onFileClick={onFileClick} />
|
||||||
</div>
|
</div>
|
||||||
{/* Timestamp - temporarily hidden */}
|
|
||||||
{/* <div
|
|
||||||
className="text-xs opacity-60"
|
|
||||||
style={{ color: 'var(--app-secondary-foreground)' }}
|
|
||||||
>
|
|
||||||
{new Date(timestamp).toLocaleTimeString()}
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import type {
|
|||||||
PermissionOption,
|
PermissionOption,
|
||||||
ToolCall as PermissionToolCall,
|
ToolCall as PermissionToolCall,
|
||||||
} from '../components/PermissionDrawer/PermissionRequest.js';
|
} from '../components/PermissionDrawer/PermissionRequest.js';
|
||||||
import type { ToolCallUpdate, EditMode } from '../../types/chatTypes.js';
|
import type { ToolCallUpdate } from '../../types/chatTypes.js';
|
||||||
|
import type { ApprovalModeValue } from '../../types/acpTypes.js';
|
||||||
import type { PlanEntry } from '../../types/chatTypes.js';
|
import type { PlanEntry } from '../../types/chatTypes.js';
|
||||||
|
|
||||||
interface UseWebViewMessagesProps {
|
interface UseWebViewMessagesProps {
|
||||||
@@ -107,7 +108,7 @@ interface UseWebViewMessagesProps {
|
|||||||
inputFieldRef: React.RefObject<HTMLDivElement>;
|
inputFieldRef: React.RefObject<HTMLDivElement>;
|
||||||
setInputText: (text: string) => void;
|
setInputText: (text: string) => void;
|
||||||
// Edit mode setter (maps ACP modes to UI modes)
|
// Edit mode setter (maps ACP modes to UI modes)
|
||||||
setEditMode?: (mode: EditMode) => void;
|
setEditMode?: (mode: ApprovalModeValue) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -196,20 +197,9 @@ export const useWebViewMessages = ({
|
|||||||
case 'modeInfo': {
|
case 'modeInfo': {
|
||||||
// Initialize UI mode from ACP initialize
|
// Initialize UI mode from ACP initialize
|
||||||
try {
|
try {
|
||||||
const current = (message.data?.currentModeId || 'default') as
|
const current = (message.data?.currentModeId ||
|
||||||
| 'plan'
|
'default') as ApprovalModeValue;
|
||||||
| 'default'
|
setEditMode?.(current);
|
||||||
| 'auto-edit'
|
|
||||||
| 'yolo';
|
|
||||||
setEditMode?.(
|
|
||||||
(current === 'plan'
|
|
||||||
? 'plan'
|
|
||||||
: current === 'auto-edit'
|
|
||||||
? 'auto'
|
|
||||||
: current === 'yolo'
|
|
||||||
? 'yolo'
|
|
||||||
: 'ask') as EditMode,
|
|
||||||
);
|
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
// best effort
|
// best effort
|
||||||
}
|
}
|
||||||
@@ -218,20 +208,9 @@ export const useWebViewMessages = ({
|
|||||||
|
|
||||||
case 'modeChanged': {
|
case 'modeChanged': {
|
||||||
try {
|
try {
|
||||||
const modeId = (message.data?.modeId || 'default') as
|
const modeId = (message.data?.modeId ||
|
||||||
| 'plan'
|
'default') as ApprovalModeValue;
|
||||||
| 'default'
|
setEditMode?.(modeId);
|
||||||
| 'auto-edit'
|
|
||||||
| 'yolo';
|
|
||||||
setEditMode?.(
|
|
||||||
(modeId === 'plan'
|
|
||||||
? 'plan'
|
|
||||||
: modeId === 'auto-edit'
|
|
||||||
? 'auto'
|
|
||||||
: modeId === 'yolo'
|
|
||||||
? 'yolo'
|
|
||||||
: 'ask') as EditMode,
|
|
||||||
);
|
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
// Ignore error when setting mode
|
// Ignore error when setting mode
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user