mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 15:31:27 +00:00
refactor: merge coder-model and qwen3.5-plus, remove vision model switching
- Merge coder-model and qwen3.5-plus into a single coder-model with vision capability - Remove vlmSwitchMode CLI argument and experimental.vlmSwitchMode setting - Remove useVisionAutoSwitch hook and inline image format checking into useGeminiStream - Remove ModelSwitchDialog and related vision switch UI components - Update all related tests to reflect the simplified model structure - Set DEFAULT_QWEN_MODEL to coder-model Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
a55e96a6a3
commit
ae6716c651
29 changed files with 149 additions and 1693 deletions
|
|
@ -74,14 +74,6 @@ const mockParseAndFormatApiError = vi.hoisted(() =>
|
|||
);
|
||||
const mockLogApiCancel = vi.hoisted(() => vi.fn());
|
||||
|
||||
// Vision auto-switch mocks (hoisted)
|
||||
const mockHandleVisionSwitch = vi.hoisted(() =>
|
||||
vi.fn().mockResolvedValue({ shouldProceed: true }),
|
||||
);
|
||||
const mockRestoreOriginalModel = vi.hoisted(() =>
|
||||
vi.fn().mockResolvedValue(undefined),
|
||||
);
|
||||
|
||||
vi.mock('@qwen-code/qwen-code-core', async (importOriginal) => {
|
||||
const actualCoreModule = (await importOriginal()) as any;
|
||||
return {
|
||||
|
|
@ -104,13 +96,6 @@ vi.mock('./useReactToolScheduler.js', async (importOriginal) => {
|
|||
};
|
||||
});
|
||||
|
||||
vi.mock('./useVisionAutoSwitch.js', () => ({
|
||||
useVisionAutoSwitch: vi.fn(() => ({
|
||||
handleVisionSwitch: mockHandleVisionSwitch,
|
||||
restoreOriginalModel: mockRestoreOriginalModel,
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock('./shellCommandProcessor.js', () => ({
|
||||
useShellCommandProcessor: vi.fn().mockReturnValue({
|
||||
handleShellCommand: vi.fn(),
|
||||
|
|
@ -306,7 +291,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -472,7 +456,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -557,7 +540,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -670,7 +652,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -784,7 +765,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -901,7 +881,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
cancelSubmitSpy,
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -945,7 +924,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
vi.fn(),
|
||||
false,
|
||||
setShellInputFocusedSpy, // Pass the spy here
|
||||
80,
|
||||
24,
|
||||
|
|
@ -1273,7 +1251,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -1331,7 +1308,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -1825,7 +1801,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -1881,7 +1856,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -1938,7 +1912,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -2035,7 +2008,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
vi.fn(),
|
||||
80,
|
||||
24,
|
||||
|
|
@ -2090,7 +2062,6 @@ describe('useGeminiStream', () => {
|
|||
vi.fn(), // setModelSwitched
|
||||
vi.fn(), // onEditorClose
|
||||
vi.fn(), // onCancelSubmit
|
||||
false, // visionModelPreviewEnabled
|
||||
vi.fn(), // setShellInputFocused
|
||||
80, // terminalWidth
|
||||
24, // terminalHeight
|
||||
|
|
@ -2164,7 +2135,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -2256,7 +2226,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -2317,7 +2286,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -2418,7 +2386,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
vi.fn(), // setShellInputFocused
|
||||
80,
|
||||
24,
|
||||
|
|
@ -2489,7 +2456,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -2548,7 +2514,6 @@ describe('useGeminiStream', () => {
|
|||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
() => {},
|
||||
80,
|
||||
24,
|
||||
|
|
@ -2736,187 +2701,6 @@ describe('useGeminiStream', () => {
|
|||
});
|
||||
|
||||
// --- New tests focused on recent modifications ---
|
||||
describe('Vision Auto Switch Integration', () => {
|
||||
it('should call handleVisionSwitch and proceed to send when allowed', async () => {
|
||||
mockHandleVisionSwitch.mockResolvedValueOnce({ shouldProceed: true });
|
||||
mockSendMessageStream.mockReturnValue(
|
||||
(async function* () {
|
||||
yield { type: ServerGeminiEventType.Content, value: 'ok' };
|
||||
yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
|
||||
})(),
|
||||
);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useGeminiStream(
|
||||
new MockedGeminiClientClass(mockConfig),
|
||||
[],
|
||||
mockAddItem,
|
||||
mockConfig,
|
||||
mockLoadedSettings,
|
||||
mockOnDebugMessage,
|
||||
mockHandleSlashCommand,
|
||||
false,
|
||||
() => 'vscode' as EditorType,
|
||||
() => {},
|
||||
() => Promise.resolve(),
|
||||
false,
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
vi.fn(), // setShellInputFocused
|
||||
80,
|
||||
24,
|
||||
),
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('image prompt');
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockHandleVisionSwitch).toHaveBeenCalled();
|
||||
expect(mockSendMessageStream).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should gate submission when handleVisionSwitch returns shouldProceed=false', async () => {
|
||||
mockHandleVisionSwitch.mockResolvedValueOnce({ shouldProceed: false });
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useGeminiStream(
|
||||
new MockedGeminiClientClass(mockConfig),
|
||||
[],
|
||||
mockAddItem,
|
||||
mockConfig,
|
||||
mockLoadedSettings,
|
||||
mockOnDebugMessage,
|
||||
mockHandleSlashCommand,
|
||||
false,
|
||||
() => 'vscode' as EditorType,
|
||||
() => {},
|
||||
() => Promise.resolve(),
|
||||
false,
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
vi.fn(), // setShellInputFocused
|
||||
80,
|
||||
24,
|
||||
),
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('vision-gated');
|
||||
});
|
||||
|
||||
// No call to API, no restoreOriginalModel needed since no override occurred
|
||||
expect(mockSendMessageStream).not.toHaveBeenCalled();
|
||||
expect(mockRestoreOriginalModel).not.toHaveBeenCalled();
|
||||
|
||||
// Next call allowed (flag reset path)
|
||||
mockHandleVisionSwitch.mockResolvedValueOnce({ shouldProceed: true });
|
||||
mockSendMessageStream.mockReturnValue(
|
||||
(async function* () {
|
||||
yield { type: ServerGeminiEventType.Content, value: 'ok' };
|
||||
yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
|
||||
})(),
|
||||
);
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('after-gate');
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(mockSendMessageStream).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Model restore on completion and errors', () => {
|
||||
it('should restore model after successful stream completion', async () => {
|
||||
mockSendMessageStream.mockReturnValue(
|
||||
(async function* () {
|
||||
yield { type: ServerGeminiEventType.Content, value: 'content' };
|
||||
yield { type: ServerGeminiEventType.Finished, value: 'STOP' };
|
||||
})(),
|
||||
);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useGeminiStream(
|
||||
new MockedGeminiClientClass(mockConfig),
|
||||
[],
|
||||
mockAddItem,
|
||||
mockConfig,
|
||||
mockLoadedSettings,
|
||||
mockOnDebugMessage,
|
||||
mockHandleSlashCommand,
|
||||
false,
|
||||
() => 'vscode' as EditorType,
|
||||
() => {},
|
||||
() => Promise.resolve(),
|
||||
false,
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
vi.fn(), // setShellInputFocused
|
||||
80,
|
||||
24,
|
||||
),
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('restore-success');
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockRestoreOriginalModel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should restore model when an error occurs during streaming', async () => {
|
||||
const testError = new Error('stream failure');
|
||||
mockSendMessageStream.mockReturnValue(
|
||||
(async function* () {
|
||||
yield { type: ServerGeminiEventType.Content, value: 'content' };
|
||||
throw testError;
|
||||
})(),
|
||||
);
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useGeminiStream(
|
||||
new MockedGeminiClientClass(mockConfig),
|
||||
[],
|
||||
mockAddItem,
|
||||
mockConfig,
|
||||
mockLoadedSettings,
|
||||
mockOnDebugMessage,
|
||||
mockHandleSlashCommand,
|
||||
false,
|
||||
() => 'vscode' as EditorType,
|
||||
() => {},
|
||||
() => Promise.resolve(),
|
||||
false,
|
||||
() => {},
|
||||
() => {},
|
||||
() => {},
|
||||
false, // visionModelPreviewEnabled
|
||||
vi.fn(), // setShellInputFocused
|
||||
80,
|
||||
24,
|
||||
),
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.submitQuery('restore-error');
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockRestoreOriginalModel).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Loop Detection Confirmation', () => {
|
||||
beforeEach(() => {
|
||||
// Add mock for getLoopDetectionService to the config
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue