@qwen-code/qwen-code 0.0.13 → 0.1.0-preview
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -53
- package/dist/package.json +2 -2
- package/dist/qwen-code-qwen-code-0.0.12.tgz +0 -0
- package/dist/src/config/config.d.ts +0 -1
- package/dist/src/config/config.js +0 -8
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/settings.js +0 -18
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +1 -10
- package/dist/src/config/settingsSchema.js +1 -10
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/ui/App.js +11 -22
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/components/ModelSwitchDialog.d.ts +3 -3
- package/dist/src/ui/components/ModelSwitchDialog.js +6 -6
- package/dist/src/ui/components/ModelSwitchDialog.js.map +1 -1
- package/dist/src/ui/components/ModelSwitchDialog.test.js +13 -13
- package/dist/src/ui/components/ModelSwitchDialog.test.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +4 -10
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useVisionAutoSwitch.d.ts +1 -1
- package/dist/src/ui/hooks/useVisionAutoSwitch.js +18 -77
- package/dist/src/ui/hooks/useVisionAutoSwitch.js.map +1 -1
- package/dist/src/ui/hooks/useVisionAutoSwitch.test.js +23 -268
- package/dist/src/ui/hooks/useVisionAutoSwitch.test.js.map +1 -1
- package/dist/src/ui/models/availableModels.d.ts +0 -2
- package/dist/src/ui/models/availableModels.js +3 -5
- package/dist/src/ui/models/availableModels.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.js +2 -1
- package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.test.js +15 -24
- package/dist/src/ui/utils/MarkdownDisplay.test.js.map +1 -1
- package/dist/src/zed-integration/schema.d.ts +30 -30
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import {} from '@google/genai';
|
|
7
|
-
import { AuthType
|
|
7
|
+
import { AuthType } from '@qwen-code/qwen-code-core';
|
|
8
8
|
import { useCallback, useRef } from 'react';
|
|
9
9
|
import { VisionSwitchOutcome } from '../components/ModelSwitchDialog.js';
|
|
10
10
|
import { getDefaultVisionModel, isVisionModel, } from '../models/availableModels.js';
|
|
@@ -88,7 +88,7 @@ function checkImageFormatsSupport(parts) {
|
|
|
88
88
|
/**
|
|
89
89
|
* Determines if we should offer vision switch for the given parts, auth type, and current model
|
|
90
90
|
*/
|
|
91
|
-
export function shouldOfferVisionSwitch(parts, authType, currentModel, visionModelPreviewEnabled =
|
|
91
|
+
export function shouldOfferVisionSwitch(parts, authType, currentModel, visionModelPreviewEnabled = false) {
|
|
92
92
|
// Only trigger for qwen-oauth
|
|
93
93
|
if (authType !== AuthType.QWEN_OAUTH) {
|
|
94
94
|
return false;
|
|
@@ -114,10 +114,10 @@ export function processVisionSwitchOutcome(outcome) {
|
|
|
114
114
|
return { modelOverride: vlModelId };
|
|
115
115
|
case VisionSwitchOutcome.SwitchSessionToVL:
|
|
116
116
|
return { persistSessionModel: vlModelId };
|
|
117
|
-
case VisionSwitchOutcome.
|
|
118
|
-
return {
|
|
117
|
+
case VisionSwitchOutcome.DisallowWithGuidance:
|
|
118
|
+
return { showGuidance: true };
|
|
119
119
|
default:
|
|
120
|
-
return {
|
|
120
|
+
return { showGuidance: true };
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
/**
|
|
@@ -132,7 +132,7 @@ export function getVisionSwitchGuidanceMessage() {
|
|
|
132
132
|
/**
|
|
133
133
|
* Custom hook for handling vision model auto-switching
|
|
134
134
|
*/
|
|
135
|
-
export function useVisionAutoSwitch(config, addItem, visionModelPreviewEnabled =
|
|
135
|
+
export function useVisionAutoSwitch(config, addItem, visionModelPreviewEnabled = false, onVisionSwitchRequired) {
|
|
136
136
|
const originalModelRef = useRef(null);
|
|
137
137
|
const handleVisionSwitch = useCallback(async (query, userMessageTimestamp, isContinuation) => {
|
|
138
138
|
// Skip vision switch handling for continuations or if no handler provided
|
|
@@ -158,72 +158,20 @@ export function useVisionAutoSwitch(config, addItem, visionModelPreviewEnabled =
|
|
|
158
158
|
if (!shouldOfferVisionSwitch(query, contentGeneratorConfig.authType, config.getModel(), visionModelPreviewEnabled)) {
|
|
159
159
|
return { shouldProceed: true };
|
|
160
160
|
}
|
|
161
|
-
// In YOLO mode, automatically switch to vision model without user interaction
|
|
162
|
-
if (config.getApprovalMode() === ApprovalMode.YOLO) {
|
|
163
|
-
const vlModelId = getDefaultVisionModel();
|
|
164
|
-
originalModelRef.current = config.getModel();
|
|
165
|
-
await config.setModel(vlModelId, {
|
|
166
|
-
reason: 'vision_auto_switch',
|
|
167
|
-
context: 'YOLO mode auto-switch for image content',
|
|
168
|
-
});
|
|
169
|
-
return {
|
|
170
|
-
shouldProceed: true,
|
|
171
|
-
originalModel: originalModelRef.current,
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
// Check if there's a default VLM switch mode configured
|
|
175
|
-
const defaultVlmSwitchMode = config.getVlmSwitchMode();
|
|
176
|
-
if (defaultVlmSwitchMode) {
|
|
177
|
-
// Convert string value to VisionSwitchOutcome enum
|
|
178
|
-
let outcome;
|
|
179
|
-
switch (defaultVlmSwitchMode) {
|
|
180
|
-
case 'once':
|
|
181
|
-
outcome = VisionSwitchOutcome.SwitchOnce;
|
|
182
|
-
break;
|
|
183
|
-
case 'session':
|
|
184
|
-
outcome = VisionSwitchOutcome.SwitchSessionToVL;
|
|
185
|
-
break;
|
|
186
|
-
case 'persist':
|
|
187
|
-
outcome = VisionSwitchOutcome.ContinueWithCurrentModel;
|
|
188
|
-
break;
|
|
189
|
-
default:
|
|
190
|
-
// Invalid value, fall back to prompting user
|
|
191
|
-
outcome = VisionSwitchOutcome.ContinueWithCurrentModel;
|
|
192
|
-
}
|
|
193
|
-
// Process the default outcome
|
|
194
|
-
const visionSwitchResult = processVisionSwitchOutcome(outcome);
|
|
195
|
-
if (visionSwitchResult.modelOverride) {
|
|
196
|
-
// One-time model override
|
|
197
|
-
originalModelRef.current = config.getModel();
|
|
198
|
-
await config.setModel(visionSwitchResult.modelOverride, {
|
|
199
|
-
reason: 'vision_auto_switch',
|
|
200
|
-
context: `Default VLM switch mode: ${defaultVlmSwitchMode} (one-time override)`,
|
|
201
|
-
});
|
|
202
|
-
return {
|
|
203
|
-
shouldProceed: true,
|
|
204
|
-
originalModel: originalModelRef.current,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
else if (visionSwitchResult.persistSessionModel) {
|
|
208
|
-
// Persistent session model change
|
|
209
|
-
await config.setModel(visionSwitchResult.persistSessionModel, {
|
|
210
|
-
reason: 'vision_auto_switch',
|
|
211
|
-
context: `Default VLM switch mode: ${defaultVlmSwitchMode} (session persistent)`,
|
|
212
|
-
});
|
|
213
|
-
return { shouldProceed: true };
|
|
214
|
-
}
|
|
215
|
-
// For ContinueWithCurrentModel or any other case, proceed with current model
|
|
216
|
-
return { shouldProceed: true };
|
|
217
|
-
}
|
|
218
161
|
try {
|
|
219
162
|
const visionSwitchResult = await onVisionSwitchRequired(query);
|
|
163
|
+
if (visionSwitchResult.showGuidance) {
|
|
164
|
+
// Show guidance and don't proceed with the request
|
|
165
|
+
addItem({
|
|
166
|
+
type: MessageType.INFO,
|
|
167
|
+
text: getVisionSwitchGuidanceMessage(),
|
|
168
|
+
}, userMessageTimestamp);
|
|
169
|
+
return { shouldProceed: false };
|
|
170
|
+
}
|
|
220
171
|
if (visionSwitchResult.modelOverride) {
|
|
221
172
|
// One-time model override
|
|
222
173
|
originalModelRef.current = config.getModel();
|
|
223
|
-
|
|
224
|
-
reason: 'vision_auto_switch',
|
|
225
|
-
context: 'User-prompted vision switch (one-time override)',
|
|
226
|
-
});
|
|
174
|
+
config.setModel(visionSwitchResult.modelOverride);
|
|
227
175
|
return {
|
|
228
176
|
shouldProceed: true,
|
|
229
177
|
originalModel: originalModelRef.current,
|
|
@@ -231,13 +179,9 @@ export function useVisionAutoSwitch(config, addItem, visionModelPreviewEnabled =
|
|
|
231
179
|
}
|
|
232
180
|
else if (visionSwitchResult.persistSessionModel) {
|
|
233
181
|
// Persistent session model change
|
|
234
|
-
|
|
235
|
-
reason: 'vision_auto_switch',
|
|
236
|
-
context: 'User-prompted vision switch (session persistent)',
|
|
237
|
-
});
|
|
182
|
+
config.setModel(visionSwitchResult.persistSessionModel);
|
|
238
183
|
return { shouldProceed: true };
|
|
239
184
|
}
|
|
240
|
-
// For ContinueWithCurrentModel or any other case, proceed with current model
|
|
241
185
|
return { shouldProceed: true };
|
|
242
186
|
}
|
|
243
187
|
catch (_error) {
|
|
@@ -245,12 +189,9 @@ export function useVisionAutoSwitch(config, addItem, visionModelPreviewEnabled =
|
|
|
245
189
|
return { shouldProceed: false };
|
|
246
190
|
}
|
|
247
191
|
}, [config, addItem, visionModelPreviewEnabled, onVisionSwitchRequired]);
|
|
248
|
-
const restoreOriginalModel = useCallback(
|
|
192
|
+
const restoreOriginalModel = useCallback(() => {
|
|
249
193
|
if (originalModelRef.current) {
|
|
250
|
-
|
|
251
|
-
reason: 'vision_auto_switch',
|
|
252
|
-
context: 'Restoring original model after vision switch',
|
|
253
|
-
});
|
|
194
|
+
config.setModel(originalModelRef.current);
|
|
254
195
|
originalModelRef.current = null;
|
|
255
196
|
}
|
|
256
197
|
}, [config]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useVisionAutoSwitch.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useVisionAutoSwitch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAiC,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAe,
|
|
1
|
+
{"version":3,"file":"useVisionAutoSwitch.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useVisionAutoSwitch.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
7
7
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
8
8
|
import { renderHook, act } from '@testing-library/react';
|
|
9
|
-
import { AuthType
|
|
9
|
+
import { AuthType } from '@qwen-code/qwen-code-core';
|
|
10
10
|
import { shouldOfferVisionSwitch, processVisionSwitchOutcome, getVisionSwitchGuidanceMessage, useVisionAutoSwitch, } from './useVisionAutoSwitch.js';
|
|
11
11
|
import { VisionSwitchOutcome } from '../components/ModelSwitchDialog.js';
|
|
12
12
|
import { MessageType } from '../types.js';
|
|
@@ -24,7 +24,7 @@ describe('useVisionAutoSwitch helpers', () => {
|
|
|
24
24
|
const parts = [
|
|
25
25
|
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
26
26
|
];
|
|
27
|
-
const result = shouldOfferVisionSwitch(parts, AuthType.QWEN_OAUTH, '
|
|
27
|
+
const result = shouldOfferVisionSwitch(parts, AuthType.QWEN_OAUTH, 'qwen-vl-max-latest', true);
|
|
28
28
|
expect(result).toBe(false);
|
|
29
29
|
});
|
|
30
30
|
it('returns true when image parts exist, QWEN_OAUTH, and model is not vision', () => {
|
|
@@ -59,32 +59,6 @@ describe('useVisionAutoSwitch helpers', () => {
|
|
|
59
59
|
const result = shouldOfferVisionSwitch(parts, AuthType.QWEN_OAUTH, 'qwen3-coder-plus', false);
|
|
60
60
|
expect(result).toBe(false);
|
|
61
61
|
});
|
|
62
|
-
it('returns true when image parts exist in YOLO mode context', () => {
|
|
63
|
-
const parts = [
|
|
64
|
-
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
65
|
-
];
|
|
66
|
-
const result = shouldOfferVisionSwitch(parts, AuthType.QWEN_OAUTH, 'qwen3-coder-plus', true);
|
|
67
|
-
expect(result).toBe(true);
|
|
68
|
-
});
|
|
69
|
-
it('returns false when no image parts exist in YOLO mode context', () => {
|
|
70
|
-
const parts = [{ text: 'just text' }];
|
|
71
|
-
const result = shouldOfferVisionSwitch(parts, AuthType.QWEN_OAUTH, 'qwen3-coder-plus', true);
|
|
72
|
-
expect(result).toBe(false);
|
|
73
|
-
});
|
|
74
|
-
it('returns false when already using vision model in YOLO mode context', () => {
|
|
75
|
-
const parts = [
|
|
76
|
-
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
77
|
-
];
|
|
78
|
-
const result = shouldOfferVisionSwitch(parts, AuthType.QWEN_OAUTH, 'vision-model', true);
|
|
79
|
-
expect(result).toBe(false);
|
|
80
|
-
});
|
|
81
|
-
it('returns false when authType is not QWEN_OAUTH in YOLO mode context', () => {
|
|
82
|
-
const parts = [
|
|
83
|
-
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
84
|
-
];
|
|
85
|
-
const result = shouldOfferVisionSwitch(parts, AuthType.USE_GEMINI, 'qwen3-coder-plus', true);
|
|
86
|
-
expect(result).toBe(false);
|
|
87
|
-
});
|
|
88
62
|
});
|
|
89
63
|
describe('processVisionSwitchOutcome', () => {
|
|
90
64
|
it('maps SwitchOnce to a one-time model override', () => {
|
|
@@ -97,9 +71,9 @@ describe('useVisionAutoSwitch helpers', () => {
|
|
|
97
71
|
const result = processVisionSwitchOutcome(VisionSwitchOutcome.SwitchSessionToVL);
|
|
98
72
|
expect(result).toEqual({ persistSessionModel: vl });
|
|
99
73
|
});
|
|
100
|
-
it('maps
|
|
101
|
-
const result = processVisionSwitchOutcome(VisionSwitchOutcome.
|
|
102
|
-
expect(result).toEqual({});
|
|
74
|
+
it('maps DisallowWithGuidance to showGuidance', () => {
|
|
75
|
+
const result = processVisionSwitchOutcome(VisionSwitchOutcome.DisallowWithGuidance);
|
|
76
|
+
expect(result).toEqual({ showGuidance: true });
|
|
103
77
|
});
|
|
104
78
|
});
|
|
105
79
|
describe('getVisionSwitchGuidanceMessage', () => {
|
|
@@ -113,15 +87,13 @@ describe('useVisionAutoSwitch helpers', () => {
|
|
|
113
87
|
});
|
|
114
88
|
});
|
|
115
89
|
describe('useVisionAutoSwitch hook', () => {
|
|
116
|
-
const createMockConfig = (authType, initialModel
|
|
90
|
+
const createMockConfig = (authType, initialModel) => {
|
|
117
91
|
let currentModel = initialModel;
|
|
118
92
|
const mockConfig = {
|
|
119
93
|
getModel: vi.fn(() => currentModel),
|
|
120
|
-
setModel: vi.fn(
|
|
94
|
+
setModel: vi.fn((m) => {
|
|
121
95
|
currentModel = m;
|
|
122
96
|
}),
|
|
123
|
-
getApprovalMode: vi.fn(() => approvalMode),
|
|
124
|
-
getVlmSwitchMode: vi.fn(() => vlmSwitchMode),
|
|
125
97
|
getContentGeneratorConfig: vi.fn(() => ({
|
|
126
98
|
authType,
|
|
127
99
|
model: currentModel,
|
|
@@ -175,9 +147,11 @@ describe('useVisionAutoSwitch hook', () => {
|
|
|
175
147
|
expect(res).toEqual({ shouldProceed: true });
|
|
176
148
|
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
177
149
|
});
|
|
178
|
-
it('
|
|
150
|
+
it('shows guidance and blocks when dialog returns showGuidance', async () => {
|
|
179
151
|
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus');
|
|
180
|
-
const onVisionSwitchRequired = vi
|
|
152
|
+
const onVisionSwitchRequired = vi
|
|
153
|
+
.fn()
|
|
154
|
+
.mockResolvedValue({ showGuidance: true });
|
|
181
155
|
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
182
156
|
const parts = [
|
|
183
157
|
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
@@ -187,9 +161,8 @@ describe('useVisionAutoSwitch hook', () => {
|
|
|
187
161
|
await act(async () => {
|
|
188
162
|
res = await result.current.handleVisionSwitch(parts, userTs, false);
|
|
189
163
|
});
|
|
190
|
-
|
|
191
|
-
expect(
|
|
192
|
-
expect(res).toEqual({ shouldProceed: true });
|
|
164
|
+
expect(addItem).toHaveBeenCalledWith({ type: MessageType.INFO, text: getVisionSwitchGuidanceMessage() }, userTs);
|
|
165
|
+
expect(res).toEqual({ shouldProceed: false });
|
|
193
166
|
expect(config.setModel).not.toHaveBeenCalled();
|
|
194
167
|
});
|
|
195
168
|
it('applies a one-time override and returns originalModel, then restores', async () => {
|
|
@@ -197,7 +170,7 @@ describe('useVisionAutoSwitch hook', () => {
|
|
|
197
170
|
const config = createMockConfig(AuthType.QWEN_OAUTH, initialModel);
|
|
198
171
|
const onVisionSwitchRequired = vi
|
|
199
172
|
.fn()
|
|
200
|
-
.mockResolvedValue({ modelOverride: '
|
|
173
|
+
.mockResolvedValue({ modelOverride: 'qwen-vl-max-latest' });
|
|
201
174
|
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
202
175
|
const parts = [
|
|
203
176
|
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
@@ -207,24 +180,18 @@ describe('useVisionAutoSwitch hook', () => {
|
|
|
207
180
|
res = await result.current.handleVisionSwitch(parts, 2020, false);
|
|
208
181
|
});
|
|
209
182
|
expect(res).toEqual({ shouldProceed: true, originalModel: initialModel });
|
|
210
|
-
expect(config.setModel).toHaveBeenCalledWith('
|
|
211
|
-
reason: 'vision_auto_switch',
|
|
212
|
-
context: 'User-prompted vision switch (one-time override)',
|
|
213
|
-
});
|
|
183
|
+
expect(config.setModel).toHaveBeenCalledWith('qwen-vl-max-latest');
|
|
214
184
|
// Now restore
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
});
|
|
218
|
-
expect(config.setModel).toHaveBeenLastCalledWith(initialModel, {
|
|
219
|
-
reason: 'vision_auto_switch',
|
|
220
|
-
context: 'Restoring original model after vision switch',
|
|
185
|
+
act(() => {
|
|
186
|
+
result.current.restoreOriginalModel();
|
|
221
187
|
});
|
|
188
|
+
expect(config.setModel).toHaveBeenLastCalledWith(initialModel);
|
|
222
189
|
});
|
|
223
190
|
it('persists session model when dialog requests persistence', async () => {
|
|
224
191
|
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus');
|
|
225
192
|
const onVisionSwitchRequired = vi
|
|
226
193
|
.fn()
|
|
227
|
-
.mockResolvedValue({ persistSessionModel: '
|
|
194
|
+
.mockResolvedValue({ persistSessionModel: 'qwen-vl-max-latest' });
|
|
228
195
|
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
229
196
|
const parts = [
|
|
230
197
|
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
@@ -234,16 +201,13 @@ describe('useVisionAutoSwitch hook', () => {
|
|
|
234
201
|
res = await result.current.handleVisionSwitch(parts, 3030, false);
|
|
235
202
|
});
|
|
236
203
|
expect(res).toEqual({ shouldProceed: true });
|
|
237
|
-
expect(config.setModel).toHaveBeenCalledWith('
|
|
238
|
-
reason: 'vision_auto_switch',
|
|
239
|
-
context: 'User-prompted vision switch (session persistent)',
|
|
240
|
-
});
|
|
204
|
+
expect(config.setModel).toHaveBeenCalledWith('qwen-vl-max-latest');
|
|
241
205
|
// Restore should be a no-op since no one-time override was used
|
|
242
|
-
|
|
243
|
-
|
|
206
|
+
act(() => {
|
|
207
|
+
result.current.restoreOriginalModel();
|
|
244
208
|
});
|
|
245
209
|
// Last call should still be the persisted model set
|
|
246
|
-
expect(config.setModel.mock.calls.pop()?.[0]).toBe('
|
|
210
|
+
expect(config.setModel.mock.calls.pop()?.[0]).toBe('qwen-vl-max-latest');
|
|
247
211
|
});
|
|
248
212
|
it('returns shouldProceed=true when dialog returns no special flags', async () => {
|
|
249
213
|
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus');
|
|
@@ -287,214 +251,5 @@ describe('useVisionAutoSwitch hook', () => {
|
|
|
287
251
|
expect(res).toEqual({ shouldProceed: true });
|
|
288
252
|
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
289
253
|
});
|
|
290
|
-
describe('YOLO mode behavior', () => {
|
|
291
|
-
it('automatically switches to vision model in YOLO mode without showing dialog', async () => {
|
|
292
|
-
const initialModel = 'qwen3-coder-plus';
|
|
293
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, initialModel, ApprovalMode.YOLO);
|
|
294
|
-
const onVisionSwitchRequired = vi.fn(); // Should not be called in YOLO mode
|
|
295
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
296
|
-
const parts = [
|
|
297
|
-
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
298
|
-
];
|
|
299
|
-
let res;
|
|
300
|
-
await act(async () => {
|
|
301
|
-
res = await result.current.handleVisionSwitch(parts, 7070, false);
|
|
302
|
-
});
|
|
303
|
-
// Should automatically switch without calling the dialog
|
|
304
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
305
|
-
expect(res).toEqual({
|
|
306
|
-
shouldProceed: true,
|
|
307
|
-
originalModel: initialModel,
|
|
308
|
-
});
|
|
309
|
-
expect(config.setModel).toHaveBeenCalledWith(getDefaultVisionModel(), {
|
|
310
|
-
reason: 'vision_auto_switch',
|
|
311
|
-
context: 'YOLO mode auto-switch for image content',
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
it('does not switch in YOLO mode when no images are present', async () => {
|
|
315
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus', ApprovalMode.YOLO);
|
|
316
|
-
const onVisionSwitchRequired = vi.fn();
|
|
317
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
318
|
-
const parts = [{ text: 'no images here' }];
|
|
319
|
-
let res;
|
|
320
|
-
await act(async () => {
|
|
321
|
-
res = await result.current.handleVisionSwitch(parts, 8080, false);
|
|
322
|
-
});
|
|
323
|
-
expect(res).toEqual({ shouldProceed: true });
|
|
324
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
325
|
-
expect(config.setModel).not.toHaveBeenCalled();
|
|
326
|
-
});
|
|
327
|
-
it('does not switch in YOLO mode when already using vision model', async () => {
|
|
328
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, 'vision-model', ApprovalMode.YOLO);
|
|
329
|
-
const onVisionSwitchRequired = vi.fn();
|
|
330
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
331
|
-
const parts = [
|
|
332
|
-
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
333
|
-
];
|
|
334
|
-
let res;
|
|
335
|
-
await act(async () => {
|
|
336
|
-
res = await result.current.handleVisionSwitch(parts, 9090, false);
|
|
337
|
-
});
|
|
338
|
-
expect(res).toEqual({ shouldProceed: true });
|
|
339
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
340
|
-
expect(config.setModel).not.toHaveBeenCalled();
|
|
341
|
-
});
|
|
342
|
-
it('restores original model after YOLO mode auto-switch', async () => {
|
|
343
|
-
const initialModel = 'qwen3-coder-plus';
|
|
344
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, initialModel, ApprovalMode.YOLO);
|
|
345
|
-
const onVisionSwitchRequired = vi.fn();
|
|
346
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
347
|
-
const parts = [
|
|
348
|
-
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
349
|
-
];
|
|
350
|
-
// First, trigger the auto-switch
|
|
351
|
-
await act(async () => {
|
|
352
|
-
await result.current.handleVisionSwitch(parts, 10100, false);
|
|
353
|
-
});
|
|
354
|
-
// Verify model was switched
|
|
355
|
-
expect(config.setModel).toHaveBeenCalledWith(getDefaultVisionModel(), {
|
|
356
|
-
reason: 'vision_auto_switch',
|
|
357
|
-
context: 'YOLO mode auto-switch for image content',
|
|
358
|
-
});
|
|
359
|
-
// Now restore the original model
|
|
360
|
-
await act(async () => {
|
|
361
|
-
await result.current.restoreOriginalModel();
|
|
362
|
-
});
|
|
363
|
-
// Verify model was restored
|
|
364
|
-
expect(config.setModel).toHaveBeenLastCalledWith(initialModel, {
|
|
365
|
-
reason: 'vision_auto_switch',
|
|
366
|
-
context: 'Restoring original model after vision switch',
|
|
367
|
-
});
|
|
368
|
-
});
|
|
369
|
-
it('does not switch in YOLO mode when authType is not QWEN_OAUTH', async () => {
|
|
370
|
-
const config = createMockConfig(AuthType.USE_GEMINI, 'qwen3-coder-plus', ApprovalMode.YOLO);
|
|
371
|
-
const onVisionSwitchRequired = vi.fn();
|
|
372
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
373
|
-
const parts = [
|
|
374
|
-
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
375
|
-
];
|
|
376
|
-
let res;
|
|
377
|
-
await act(async () => {
|
|
378
|
-
res = await result.current.handleVisionSwitch(parts, 11110, false);
|
|
379
|
-
});
|
|
380
|
-
expect(res).toEqual({ shouldProceed: true });
|
|
381
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
382
|
-
expect(config.setModel).not.toHaveBeenCalled();
|
|
383
|
-
});
|
|
384
|
-
it('does not switch in YOLO mode when visionModelPreviewEnabled is false', async () => {
|
|
385
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus', ApprovalMode.YOLO);
|
|
386
|
-
const onVisionSwitchRequired = vi.fn();
|
|
387
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, false, onVisionSwitchRequired));
|
|
388
|
-
const parts = [
|
|
389
|
-
{ inlineData: { mimeType: 'image/png', data: '...' } },
|
|
390
|
-
];
|
|
391
|
-
let res;
|
|
392
|
-
await act(async () => {
|
|
393
|
-
res = await result.current.handleVisionSwitch(parts, 12120, false);
|
|
394
|
-
});
|
|
395
|
-
expect(res).toEqual({ shouldProceed: true });
|
|
396
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
397
|
-
expect(config.setModel).not.toHaveBeenCalled();
|
|
398
|
-
});
|
|
399
|
-
it('handles multiple image formats in YOLO mode', async () => {
|
|
400
|
-
const initialModel = 'qwen3-coder-plus';
|
|
401
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, initialModel, ApprovalMode.YOLO);
|
|
402
|
-
const onVisionSwitchRequired = vi.fn();
|
|
403
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
404
|
-
const parts = [
|
|
405
|
-
{ text: 'Here are some images:' },
|
|
406
|
-
{ inlineData: { mimeType: 'image/jpeg', data: '...' } },
|
|
407
|
-
{ fileData: { mimeType: 'image/png', fileUri: 'file://image.png' } },
|
|
408
|
-
{ text: 'Please analyze them.' },
|
|
409
|
-
];
|
|
410
|
-
let res;
|
|
411
|
-
await act(async () => {
|
|
412
|
-
res = await result.current.handleVisionSwitch(parts, 13130, false);
|
|
413
|
-
});
|
|
414
|
-
expect(res).toEqual({
|
|
415
|
-
shouldProceed: true,
|
|
416
|
-
originalModel: initialModel,
|
|
417
|
-
});
|
|
418
|
-
expect(config.setModel).toHaveBeenCalledWith(getDefaultVisionModel(), {
|
|
419
|
-
reason: 'vision_auto_switch',
|
|
420
|
-
context: 'YOLO mode auto-switch for image content',
|
|
421
|
-
});
|
|
422
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
423
|
-
});
|
|
424
|
-
});
|
|
425
|
-
describe('VLM switch mode default behavior', () => {
|
|
426
|
-
it('should automatically switch once when vlmSwitchMode is "once"', async () => {
|
|
427
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus', ApprovalMode.DEFAULT, 'once');
|
|
428
|
-
const onVisionSwitchRequired = vi.fn(); // Should not be called
|
|
429
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
430
|
-
const parts = [
|
|
431
|
-
{ inlineData: { mimeType: 'image/jpeg', data: 'base64data' } },
|
|
432
|
-
];
|
|
433
|
-
const switchResult = await result.current.handleVisionSwitch(parts, Date.now(), false);
|
|
434
|
-
expect(switchResult.shouldProceed).toBe(true);
|
|
435
|
-
expect(switchResult.originalModel).toBe('qwen3-coder-plus');
|
|
436
|
-
expect(config.setModel).toHaveBeenCalledWith('vision-model', {
|
|
437
|
-
reason: 'vision_auto_switch',
|
|
438
|
-
context: 'Default VLM switch mode: once (one-time override)',
|
|
439
|
-
});
|
|
440
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
441
|
-
});
|
|
442
|
-
it('should switch session when vlmSwitchMode is "session"', async () => {
|
|
443
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus', ApprovalMode.DEFAULT, 'session');
|
|
444
|
-
const onVisionSwitchRequired = vi.fn(); // Should not be called
|
|
445
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
446
|
-
const parts = [
|
|
447
|
-
{ inlineData: { mimeType: 'image/jpeg', data: 'base64data' } },
|
|
448
|
-
];
|
|
449
|
-
const switchResult = await result.current.handleVisionSwitch(parts, Date.now(), false);
|
|
450
|
-
expect(switchResult.shouldProceed).toBe(true);
|
|
451
|
-
expect(switchResult.originalModel).toBeUndefined(); // No original model for session switch
|
|
452
|
-
expect(config.setModel).toHaveBeenCalledWith('vision-model', {
|
|
453
|
-
reason: 'vision_auto_switch',
|
|
454
|
-
context: 'Default VLM switch mode: session (session persistent)',
|
|
455
|
-
});
|
|
456
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
457
|
-
});
|
|
458
|
-
it('should continue with current model when vlmSwitchMode is "persist"', async () => {
|
|
459
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus', ApprovalMode.DEFAULT, 'persist');
|
|
460
|
-
const onVisionSwitchRequired = vi.fn(); // Should not be called
|
|
461
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
462
|
-
const parts = [
|
|
463
|
-
{ inlineData: { mimeType: 'image/jpeg', data: 'base64data' } },
|
|
464
|
-
];
|
|
465
|
-
const switchResult = await result.current.handleVisionSwitch(parts, Date.now(), false);
|
|
466
|
-
expect(switchResult.shouldProceed).toBe(true);
|
|
467
|
-
expect(switchResult.originalModel).toBeUndefined();
|
|
468
|
-
expect(config.setModel).not.toHaveBeenCalled();
|
|
469
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
470
|
-
});
|
|
471
|
-
it('should fall back to user prompt when vlmSwitchMode is not set', async () => {
|
|
472
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus', ApprovalMode.DEFAULT, undefined);
|
|
473
|
-
const onVisionSwitchRequired = vi
|
|
474
|
-
.fn()
|
|
475
|
-
.mockResolvedValue({ modelOverride: 'vision-model' });
|
|
476
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
477
|
-
const parts = [
|
|
478
|
-
{ inlineData: { mimeType: 'image/jpeg', data: 'base64data' } },
|
|
479
|
-
];
|
|
480
|
-
const switchResult = await result.current.handleVisionSwitch(parts, Date.now(), false);
|
|
481
|
-
expect(switchResult.shouldProceed).toBe(true);
|
|
482
|
-
expect(onVisionSwitchRequired).toHaveBeenCalledWith(parts);
|
|
483
|
-
});
|
|
484
|
-
it('should fall back to persist behavior when vlmSwitchMode has invalid value', async () => {
|
|
485
|
-
const config = createMockConfig(AuthType.QWEN_OAUTH, 'qwen3-coder-plus', ApprovalMode.DEFAULT, 'invalid-value');
|
|
486
|
-
const onVisionSwitchRequired = vi.fn(); // Should not be called
|
|
487
|
-
const { result } = renderHook(() => useVisionAutoSwitch(config, addItem, true, onVisionSwitchRequired));
|
|
488
|
-
const parts = [
|
|
489
|
-
{ inlineData: { mimeType: 'image/jpeg', data: 'base64data' } },
|
|
490
|
-
];
|
|
491
|
-
const switchResult = await result.current.handleVisionSwitch(parts, Date.now(), false);
|
|
492
|
-
expect(switchResult.shouldProceed).toBe(true);
|
|
493
|
-
expect(switchResult.originalModel).toBeUndefined();
|
|
494
|
-
// For invalid values, it should continue with current model (persist behavior)
|
|
495
|
-
expect(config.setModel).not.toHaveBeenCalled();
|
|
496
|
-
expect(onVisionSwitchRequired).not.toHaveBeenCalled();
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
254
|
});
|
|
500
255
|
//# sourceMappingURL=useVisionAutoSwitch.test.js.map
|