mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-21 09:17:53 +00:00
fix: use dedicated model names and settings
This commit is contained in:
@@ -69,7 +69,11 @@ const MOCK_WORKSPACE_SETTINGS_PATH = pathActual.join(
|
||||
);
|
||||
|
||||
// A more flexible type for test data that allows arbitrary properties.
|
||||
type TestSettings = Settings & { [key: string]: unknown };
|
||||
type TestSettings = Settings & {
|
||||
[key: string]: unknown;
|
||||
nested?: { [key: string]: unknown };
|
||||
nestedObj?: { [key: string]: unknown };
|
||||
};
|
||||
|
||||
vi.mock('fs', async (importOriginal) => {
|
||||
// Get all the functions from the real 'fs' module
|
||||
@@ -137,6 +141,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -197,6 +204,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -260,6 +270,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -320,6 +333,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -385,6 +401,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -477,6 +496,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -562,6 +584,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -691,6 +716,9 @@ describe('Settings Loading and Merging', () => {
|
||||
'/system/dir',
|
||||
],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -1431,6 +1459,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -1516,7 +1547,11 @@ describe('Settings Loading and Merging', () => {
|
||||
'workspace_endpoint_from_env/api',
|
||||
);
|
||||
expect(
|
||||
(settings.workspace.settings as TestSettings)['nested']['value'],
|
||||
(
|
||||
(settings.workspace.settings as TestSettings).nested as {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
)['value'],
|
||||
).toBe('workspace_endpoint_from_env');
|
||||
expect((settings.merged as TestSettings)['endpoint']).toBe(
|
||||
'workspace_endpoint_from_env/api',
|
||||
@@ -1766,19 +1801,39 @@ describe('Settings Loading and Merging', () => {
|
||||
).toBeUndefined();
|
||||
|
||||
expect(
|
||||
(settings.user.settings as TestSettings)['nestedObj']['nestedNull'],
|
||||
(
|
||||
(settings.user.settings as TestSettings).nestedObj as {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
)['nestedNull'],
|
||||
).toBeNull();
|
||||
expect(
|
||||
(settings.user.settings as TestSettings)['nestedObj']['nestedBool'],
|
||||
(
|
||||
(settings.user.settings as TestSettings).nestedObj as {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
)['nestedBool'],
|
||||
).toBe(true);
|
||||
expect(
|
||||
(settings.user.settings as TestSettings)['nestedObj']['nestedNum'],
|
||||
(
|
||||
(settings.user.settings as TestSettings).nestedObj as {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
)['nestedNum'],
|
||||
).toBe(0);
|
||||
expect(
|
||||
(settings.user.settings as TestSettings)['nestedObj']['nestedString'],
|
||||
(
|
||||
(settings.user.settings as TestSettings).nestedObj as {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
)['nestedString'],
|
||||
).toBe('literal');
|
||||
expect(
|
||||
(settings.user.settings as TestSettings)['nestedObj']['anotherEnv'],
|
||||
(
|
||||
(settings.user.settings as TestSettings).nestedObj as {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
)['anotherEnv'],
|
||||
).toBe('env_string_nested_value');
|
||||
|
||||
delete process.env['MY_ENV_STRING'];
|
||||
@@ -1864,6 +1919,9 @@ describe('Settings Loading and Merging', () => {
|
||||
advanced: {
|
||||
excludedEnvVars: [],
|
||||
},
|
||||
experimental: {},
|
||||
contentGenerator: {},
|
||||
systemPromptMappings: {},
|
||||
extensions: {
|
||||
disabled: [],
|
||||
workspacesWithMigrationNudge: [],
|
||||
@@ -2336,14 +2394,14 @@ describe('Settings Loading and Merging', () => {
|
||||
vimMode: false,
|
||||
},
|
||||
model: {
|
||||
maxSessionTurns: 0,
|
||||
maxSessionTurns: -1,
|
||||
},
|
||||
context: {
|
||||
includeDirectories: [],
|
||||
},
|
||||
security: {
|
||||
folderTrust: {
|
||||
enabled: null,
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -2352,9 +2410,9 @@ describe('Settings Loading and Merging', () => {
|
||||
|
||||
expect(v1Settings).toEqual({
|
||||
vimMode: false,
|
||||
maxSessionTurns: 0,
|
||||
maxSessionTurns: -1,
|
||||
includeDirectories: [],
|
||||
folderTrust: null,
|
||||
folderTrust: false,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -396,6 +396,24 @@ function mergeSettings(
|
||||
]),
|
||||
],
|
||||
},
|
||||
experimental: {
|
||||
...(systemDefaults.experimental || {}),
|
||||
...(user.experimental || {}),
|
||||
...(safeWorkspaceWithoutFolderTrust.experimental || {}),
|
||||
...(system.experimental || {}),
|
||||
},
|
||||
contentGenerator: {
|
||||
...(systemDefaults.contentGenerator || {}),
|
||||
...(user.contentGenerator || {}),
|
||||
...(safeWorkspaceWithoutFolderTrust.contentGenerator || {}),
|
||||
...(system.contentGenerator || {}),
|
||||
},
|
||||
systemPromptMappings: {
|
||||
...(systemDefaults.systemPromptMappings || {}),
|
||||
...(user.systemPromptMappings || {}),
|
||||
...(safeWorkspaceWithoutFolderTrust.systemPromptMappings || {}),
|
||||
...(system.systemPromptMappings || {}),
|
||||
},
|
||||
extensions: {
|
||||
...(systemDefaults.extensions || {}),
|
||||
...(user.extensions || {}),
|
||||
|
||||
@@ -746,7 +746,7 @@ export const SETTINGS_SCHEMA = {
|
||||
label: 'Vision Model Preview',
|
||||
category: 'Experimental',
|
||||
requiresRestart: false,
|
||||
default: false,
|
||||
default: true,
|
||||
description:
|
||||
'Enable vision model support and auto-switching functionality. When disabled, vision models like qwen-vl-max-latest will be hidden and auto-switching will not occur.',
|
||||
showInDialog: true,
|
||||
|
||||
@@ -670,7 +670,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
if (!contentGeneratorConfig) return [];
|
||||
|
||||
const visionModelPreviewEnabled =
|
||||
settings.merged.experimental?.visionModelPreview ?? false;
|
||||
settings.merged.experimental?.visionModelPreview ?? true;
|
||||
|
||||
switch (contentGeneratorConfig.authType) {
|
||||
case AuthType.QWEN_OAUTH:
|
||||
@@ -759,7 +759,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||
setModelSwitchedFromQuotaError,
|
||||
refreshStatic,
|
||||
() => cancelHandlerRef.current(),
|
||||
settings.merged.experimental?.visionModelPreview ?? false,
|
||||
settings.merged.experimental?.visionModelPreview ?? true,
|
||||
handleVisionSwitchRequired,
|
||||
);
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ export const useGeminiStream = (
|
||||
setModelSwitchedFromQuotaError: React.Dispatch<React.SetStateAction<boolean>>,
|
||||
onEditorClose: () => void,
|
||||
onCancelSubmit: () => void,
|
||||
visionModelPreviewEnabled: boolean = false,
|
||||
visionModelPreviewEnabled: boolean,
|
||||
onVisionSwitchRequired?: (query: PartListUnion) => Promise<{
|
||||
modelOverride?: string;
|
||||
persistSessionModel?: string;
|
||||
|
||||
@@ -41,7 +41,7 @@ describe('useVisionAutoSwitch helpers', () => {
|
||||
const result = shouldOfferVisionSwitch(
|
||||
parts,
|
||||
AuthType.QWEN_OAUTH,
|
||||
'qwen-vl-max-latest',
|
||||
'vision-model',
|
||||
true,
|
||||
);
|
||||
expect(result).toBe(false);
|
||||
@@ -140,7 +140,7 @@ describe('useVisionAutoSwitch helpers', () => {
|
||||
const result = shouldOfferVisionSwitch(
|
||||
parts,
|
||||
AuthType.QWEN_OAUTH,
|
||||
'qwen-vl-max-latest',
|
||||
'vision-model',
|
||||
true,
|
||||
);
|
||||
expect(result).toBe(false);
|
||||
@@ -314,7 +314,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
const config = createMockConfig(AuthType.QWEN_OAUTH, initialModel);
|
||||
const onVisionSwitchRequired = vi
|
||||
.fn()
|
||||
.mockResolvedValue({ modelOverride: 'qwen-vl-max-latest' });
|
||||
.mockResolvedValue({ modelOverride: 'coder-model' });
|
||||
const { result } = renderHook(() =>
|
||||
useVisionAutoSwitch(config, addItem as any, true, onVisionSwitchRequired),
|
||||
);
|
||||
@@ -329,7 +329,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
});
|
||||
|
||||
expect(res).toEqual({ shouldProceed: true, originalModel: initialModel });
|
||||
expect(config.setModel).toHaveBeenCalledWith('qwen-vl-max-latest', {
|
||||
expect(config.setModel).toHaveBeenCalledWith('coder-model', {
|
||||
reason: 'vision_auto_switch',
|
||||
context: 'User-prompted vision switch (one-time override)',
|
||||
});
|
||||
@@ -348,7 +348,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus');
|
||||
const onVisionSwitchRequired = vi
|
||||
.fn()
|
||||
.mockResolvedValue({ persistSessionModel: 'qwen-vl-max-latest' });
|
||||
.mockResolvedValue({ persistSessionModel: 'coder-model' });
|
||||
const { result } = renderHook(() =>
|
||||
useVisionAutoSwitch(config, addItem as any, true, onVisionSwitchRequired),
|
||||
);
|
||||
@@ -363,7 +363,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
});
|
||||
|
||||
expect(res).toEqual({ shouldProceed: true });
|
||||
expect(config.setModel).toHaveBeenCalledWith('qwen-vl-max-latest', {
|
||||
expect(config.setModel).toHaveBeenCalledWith('coder-model', {
|
||||
reason: 'vision_auto_switch',
|
||||
context: 'User-prompted vision switch (session persistent)',
|
||||
});
|
||||
@@ -373,9 +373,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
result.current.restoreOriginalModel();
|
||||
});
|
||||
// Last call should still be the persisted model set
|
||||
expect((config.setModel as any).mock.calls.pop()?.[0]).toBe(
|
||||
'qwen-vl-max-latest',
|
||||
);
|
||||
expect((config.setModel as any).mock.calls.pop()?.[0]).toBe('coder-model');
|
||||
});
|
||||
|
||||
it('returns shouldProceed=true when dialog returns no special flags', async () => {
|
||||
@@ -507,7 +505,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
it('does not switch in YOLO mode when already using vision model', async () => {
|
||||
const config = createMockConfig(
|
||||
AuthType.QWEN_OAUTH,
|
||||
'qwen-vl-max-latest',
|
||||
'vision-model',
|
||||
ApprovalMode.YOLO,
|
||||
);
|
||||
const onVisionSwitchRequired = vi.fn();
|
||||
@@ -709,7 +707,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
|
||||
expect(switchResult.shouldProceed).toBe(true);
|
||||
expect(switchResult.originalModel).toBe('qwen3-coder-plus');
|
||||
expect(config.setModel).toHaveBeenCalledWith('qwen-vl-max-latest', {
|
||||
expect(config.setModel).toHaveBeenCalledWith('vision-model', {
|
||||
reason: 'vision_auto_switch',
|
||||
context: 'Default VLM switch mode: once (one-time override)',
|
||||
});
|
||||
@@ -745,7 +743,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
|
||||
expect(switchResult.shouldProceed).toBe(true);
|
||||
expect(switchResult.originalModel).toBeUndefined(); // No original model for session switch
|
||||
expect(config.setModel).toHaveBeenCalledWith('qwen-vl-max-latest', {
|
||||
expect(config.setModel).toHaveBeenCalledWith('vision-model', {
|
||||
reason: 'vision_auto_switch',
|
||||
context: 'Default VLM switch mode: session (session persistent)',
|
||||
});
|
||||
@@ -794,7 +792,7 @@ describe('useVisionAutoSwitch hook', () => {
|
||||
);
|
||||
const onVisionSwitchRequired = vi
|
||||
.fn()
|
||||
.mockResolvedValue({ modelOverride: 'qwen-vl-max-latest' });
|
||||
.mockResolvedValue({ modelOverride: 'vision-model' });
|
||||
const { result } = renderHook(() =>
|
||||
useVisionAutoSwitch(
|
||||
config,
|
||||
|
||||
@@ -121,7 +121,7 @@ export function shouldOfferVisionSwitch(
|
||||
parts: PartListUnion,
|
||||
authType: AuthType,
|
||||
currentModel: string,
|
||||
visionModelPreviewEnabled: boolean = false,
|
||||
visionModelPreviewEnabled: boolean = true,
|
||||
): boolean {
|
||||
// Only trigger for qwen-oauth
|
||||
if (authType !== AuthType.QWEN_OAUTH) {
|
||||
@@ -198,7 +198,7 @@ export interface VisionSwitchHandlingResult {
|
||||
export function useVisionAutoSwitch(
|
||||
config: Config,
|
||||
addItem: UseHistoryManagerReturn['addItem'],
|
||||
visionModelPreviewEnabled: boolean = false,
|
||||
visionModelPreviewEnabled: boolean = true,
|
||||
onVisionSwitchRequired?: (query: PartListUnion) => Promise<{
|
||||
modelOverride?: string;
|
||||
persistSessionModel?: string;
|
||||
|
||||
@@ -10,8 +10,8 @@ export type AvailableModel = {
|
||||
isVision?: boolean;
|
||||
};
|
||||
|
||||
export const MAINLINE_VLM = 'qwen-vl-max-latest';
|
||||
export const MAINLINE_CODER = 'qwen3-coder-plus';
|
||||
export const MAINLINE_VLM = 'vision-model';
|
||||
export const MAINLINE_CODER = 'coder-model';
|
||||
|
||||
export const AVAILABLE_MODELS_QWEN: AvailableModel[] = [
|
||||
{ id: MAINLINE_CODER, label: MAINLINE_CODER },
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
export const DEFAULT_QWEN_MODEL = 'qwen3-coder-plus';
|
||||
// We do not have a fallback model for now, but note it here anyway.
|
||||
export const DEFAULT_QWEN_FLASH_MODEL = 'qwen3-coder-flash';
|
||||
export const DEFAULT_QWEN_MODEL = 'coder-model';
|
||||
export const DEFAULT_QWEN_FLASH_MODEL = 'coder-model';
|
||||
|
||||
export const DEFAULT_GEMINI_MODEL = 'qwen3-coder-plus';
|
||||
export const DEFAULT_GEMINI_MODEL = 'coder-model';
|
||||
export const DEFAULT_GEMINI_FLASH_MODEL = 'gemini-2.5-flash';
|
||||
export const DEFAULT_GEMINI_FLASH_LITE_MODEL = 'gemini-2.5-flash-lite';
|
||||
|
||||
|
||||
@@ -820,6 +820,14 @@ function getToolCallExamples(model?: string): string {
|
||||
if (/qwen[^-]*-vl/i.test(model)) {
|
||||
return qwenVlToolCallExamples;
|
||||
}
|
||||
// Match coder-model pattern (same as qwen3-coder)
|
||||
if (/coder-model/i.test(model)) {
|
||||
return qwenCoderToolCallExamples;
|
||||
}
|
||||
// Match vision-model pattern (same as qwen3-vl)
|
||||
if (/vision-model/i.test(model)) {
|
||||
return qwenVlToolCallExamples;
|
||||
}
|
||||
}
|
||||
|
||||
return generalToolCallExamples;
|
||||
|
||||
@@ -111,6 +111,9 @@ const PATTERNS: Array<[RegExp, TokenCount]> = [
|
||||
// Commercial Qwen3-Coder-Flash: 1M token context
|
||||
[/^qwen3-coder-flash(-.*)?$/, LIMITS['1m']], // catches "qwen3-coder-flash" and date variants
|
||||
|
||||
// Generic coder-model: same as qwen3-coder-plus (1M token context)
|
||||
[/^coder-model$/, LIMITS['1m']],
|
||||
|
||||
// Commercial Qwen3-Max-Preview: 256K token context
|
||||
[/^qwen3-max-preview(-.*)?$/, LIMITS['256k']], // catches "qwen3-max-preview" and date variants
|
||||
|
||||
@@ -134,6 +137,9 @@ const PATTERNS: Array<[RegExp, TokenCount]> = [
|
||||
// Qwen Vision Models
|
||||
[/^qwen-vl-max.*$/, LIMITS['128k']],
|
||||
|
||||
// Generic vision-model: same as qwen-vl-max (128K token context)
|
||||
[/^vision-model$/, LIMITS['128k']],
|
||||
|
||||
// -------------------
|
||||
// ByteDance Seed-OSS (512K)
|
||||
// -------------------
|
||||
@@ -169,12 +175,18 @@ const OUTPUT_PATTERNS: Array<[RegExp, TokenCount]> = [
|
||||
// Qwen3-Coder-Plus: 65,536 max output tokens
|
||||
[/^qwen3-coder-plus(-.*)?$/, LIMITS['64k']],
|
||||
|
||||
// Generic coder-model: same as qwen3-coder-plus (64K max output tokens)
|
||||
[/^coder-model$/, LIMITS['64k']],
|
||||
|
||||
// Qwen3-Max-Preview: 65,536 max output tokens
|
||||
[/^qwen3-max-preview(-.*)?$/, LIMITS['64k']],
|
||||
|
||||
// Qwen-VL-Max-Latest: 8,192 max output tokens
|
||||
[/^qwen-vl-max-latest$/, LIMITS['8k']],
|
||||
|
||||
// Generic vision-model: same as qwen-vl-max-latest (8K max output tokens)
|
||||
[/^vision-model$/, LIMITS['8k']],
|
||||
|
||||
// Qwen3-VL-Plus: 8,192 max output tokens
|
||||
[/^qwen3-vl-plus$/, LIMITS['8k']],
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user