mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 04:00:36 +00:00
- Add btwItem state management independent from pendingItem - Add cancelBtw functionality to abort in-flight BTW API calls - Allow /btw commands to execute concurrently with main responses - Add isBtwCommand utility function - Update BtwMessage UI with cleaner styling (remove spinner) - Add tests for concurrent /btw execution scenarios - Update layouts to render BTW messages in fixed bottom area Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
123 lines
3.7 KiB
TypeScript
123 lines
3.7 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { vi } from 'vitest';
|
|
import type { CommandContext } from '../ui/commands/types.js';
|
|
import type { LoadedSettings } from '../config/settings.js';
|
|
import type { GitService } from '@qwen-code/qwen-code-core';
|
|
import type { SessionStatsState } from '../ui/contexts/SessionContext.js';
|
|
import { ToolCallDecision } from '../ui/contexts/SessionContext.js';
|
|
|
|
// A utility type to make all properties of an object, and its nested objects, partial.
|
|
type DeepPartial<T> = T extends object
|
|
? {
|
|
[P in keyof T]?: DeepPartial<T[P]>;
|
|
}
|
|
: T;
|
|
|
|
/**
|
|
* Creates a deep, fully-typed mock of the CommandContext for use in tests.
|
|
* All functions are pre-mocked with `vi.fn()`.
|
|
*
|
|
* @param overrides - A deep partial object to override any default mock values.
|
|
* @returns A complete, mocked CommandContext object.
|
|
*/
|
|
export const createMockCommandContext = (
|
|
overrides: DeepPartial<CommandContext> = {},
|
|
): CommandContext => {
|
|
const defaultMocks: CommandContext = {
|
|
invocation: {
|
|
raw: '',
|
|
name: '',
|
|
args: '',
|
|
},
|
|
services: {
|
|
config: null,
|
|
settings: {
|
|
merged: {},
|
|
setValue: vi.fn(),
|
|
} as unknown as LoadedSettings,
|
|
git: undefined as GitService | undefined,
|
|
logger: {
|
|
log: vi.fn(),
|
|
logMessage: vi.fn(),
|
|
saveCheckpoint: vi.fn(),
|
|
loadCheckpoint: vi.fn().mockResolvedValue([]),
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
} as any, // Cast because Logger is a class.
|
|
},
|
|
ui: {
|
|
addItem: vi.fn(),
|
|
clear: vi.fn(),
|
|
setDebugMessage: vi.fn(),
|
|
pendingItem: null,
|
|
setPendingItem: vi.fn(),
|
|
btwItem: null,
|
|
setBtwItem: vi.fn(),
|
|
cancelBtw: vi.fn(),
|
|
btwAbortControllerRef: { current: null },
|
|
loadHistory: vi.fn(),
|
|
toggleVimEnabled: vi.fn(),
|
|
extensionsUpdateState: new Map(),
|
|
setExtensionsUpdateState: vi.fn(),
|
|
reloadCommands: vi.fn(),
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
} as any,
|
|
session: {
|
|
sessionShellAllowlist: new Set<string>(),
|
|
startNewSession: vi.fn(),
|
|
stats: {
|
|
sessionId: '',
|
|
sessionStartTime: new Date(),
|
|
lastPromptTokenCount: 0,
|
|
metrics: {
|
|
models: {},
|
|
tools: {
|
|
totalCalls: 0,
|
|
totalSuccess: 0,
|
|
totalFail: 0,
|
|
totalDurationMs: 0,
|
|
totalDecisions: {
|
|
[ToolCallDecision.ACCEPT]: 0,
|
|
[ToolCallDecision.REJECT]: 0,
|
|
[ToolCallDecision.MODIFY]: 0,
|
|
[ToolCallDecision.AUTO_ACCEPT]: 0,
|
|
},
|
|
byName: {},
|
|
},
|
|
files: { totalLinesAdded: 0, totalLinesRemoved: 0 },
|
|
},
|
|
promptCount: 0,
|
|
} as SessionStatsState,
|
|
},
|
|
};
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const merge = (target: any, source: any): any => {
|
|
const output = { ...target };
|
|
|
|
for (const key in source) {
|
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
const sourceValue = source[key];
|
|
const targetValue = output[key];
|
|
|
|
if (
|
|
// We only want to recursivlty merge plain objects
|
|
Object.prototype.toString.call(sourceValue) === '[object Object]' &&
|
|
Object.prototype.toString.call(targetValue) === '[object Object]'
|
|
) {
|
|
output[key] = merge(targetValue, sourceValue);
|
|
} else {
|
|
// If not, we do a direct assignment. This preserves Date objects and others.
|
|
output[key] = sourceValue;
|
|
}
|
|
}
|
|
}
|
|
return output;
|
|
};
|
|
|
|
return merge(defaultMocks, overrides);
|
|
};
|