@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.
Files changed (39) hide show
  1. package/README.md +0 -53
  2. package/dist/package.json +2 -2
  3. package/dist/qwen-code-qwen-code-0.0.12.tgz +0 -0
  4. package/dist/src/config/config.d.ts +0 -1
  5. package/dist/src/config/config.js +0 -8
  6. package/dist/src/config/config.js.map +1 -1
  7. package/dist/src/config/settings.js +0 -18
  8. package/dist/src/config/settings.js.map +1 -1
  9. package/dist/src/config/settingsSchema.d.ts +1 -10
  10. package/dist/src/config/settingsSchema.js +1 -10
  11. package/dist/src/config/settingsSchema.js.map +1 -1
  12. package/dist/src/generated/git-commit.d.ts +2 -2
  13. package/dist/src/generated/git-commit.js +2 -2
  14. package/dist/src/generated/git-commit.js.map +1 -1
  15. package/dist/src/ui/App.js +11 -22
  16. package/dist/src/ui/App.js.map +1 -1
  17. package/dist/src/ui/components/ModelSwitchDialog.d.ts +3 -3
  18. package/dist/src/ui/components/ModelSwitchDialog.js +6 -6
  19. package/dist/src/ui/components/ModelSwitchDialog.js.map +1 -1
  20. package/dist/src/ui/components/ModelSwitchDialog.test.js +13 -13
  21. package/dist/src/ui/components/ModelSwitchDialog.test.js.map +1 -1
  22. package/dist/src/ui/hooks/useGeminiStream.d.ts +1 -1
  23. package/dist/src/ui/hooks/useGeminiStream.js +4 -10
  24. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  25. package/dist/src/ui/hooks/useVisionAutoSwitch.d.ts +1 -1
  26. package/dist/src/ui/hooks/useVisionAutoSwitch.js +18 -77
  27. package/dist/src/ui/hooks/useVisionAutoSwitch.js.map +1 -1
  28. package/dist/src/ui/hooks/useVisionAutoSwitch.test.js +23 -268
  29. package/dist/src/ui/hooks/useVisionAutoSwitch.test.js.map +1 -1
  30. package/dist/src/ui/models/availableModels.d.ts +0 -2
  31. package/dist/src/ui/models/availableModels.js +3 -5
  32. package/dist/src/ui/models/availableModels.js.map +1 -1
  33. package/dist/src/ui/utils/MarkdownDisplay.js +2 -1
  34. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  35. package/dist/src/ui/utils/MarkdownDisplay.test.js +15 -24
  36. package/dist/src/ui/utils/MarkdownDisplay.test.js.map +1 -1
  37. package/dist/src/zed-integration/schema.d.ts +30 -30
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. 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, ApprovalMode } from '@qwen-code/qwen-code-core';
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 = true) {
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.ContinueWithCurrentModel:
118
- return {}; // Continue with current model, no changes needed
117
+ case VisionSwitchOutcome.DisallowWithGuidance:
118
+ return { showGuidance: true };
119
119
  default:
120
- return {}; // Default to continuing with current model
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 = true, onVisionSwitchRequired) {
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
- await config.setModel(visionSwitchResult.modelOverride, {
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
- await config.setModel(visionSwitchResult.persistSessionModel, {
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(async () => {
192
+ const restoreOriginalModel = useCallback(() => {
249
193
  if (originalModelRef.current) {
250
- await config.setModel(originalModelRef.current, {
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":"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"}
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, ApprovalMode } from '@qwen-code/qwen-code-core';
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, 'vision-model', true);
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 ContinueWithCurrentModel to empty result', () => {
101
- const result = processVisionSwitchOutcome(VisionSwitchOutcome.ContinueWithCurrentModel);
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, approvalMode = ApprovalMode.DEFAULT, vlmSwitchMode) => {
90
+ const createMockConfig = (authType, initialModel) => {
117
91
  let currentModel = initialModel;
118
92
  const mockConfig = {
119
93
  getModel: vi.fn(() => currentModel),
120
- setModel: vi.fn(async (m) => {
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('continues with current model when dialog returns empty result', async () => {
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.fn().mockResolvedValue({}); // Empty result for ContinueWithCurrentModel
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
- // Should not add any guidance message
191
- expect(addItem).not.toHaveBeenCalledWith({ type: MessageType.INFO, text: getVisionSwitchGuidanceMessage() }, userTs);
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: 'coder-model' });
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('coder-model', {
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
- await act(async () => {
216
- await result.current.restoreOriginalModel();
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: 'coder-model' });
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('coder-model', {
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
- await act(async () => {
243
- await result.current.restoreOriginalModel();
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('coder-model');
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