Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/node/test/testHelpers.ts
13406 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type { SessionOptions, SweCustomAgent } from '@github/copilot/sdk';6import type { CancellationToken, Uri } from 'vscode';7import { Event } from '../../../../../util/vs/base/common/event';8import { Disposable, IDisposable } from '../../../../../util/vs/base/common/lifecycle';9import { URI } from '../../../../../util/vs/base/common/uri';10import { generateUuid } from '../../../../../util/vs/base/common/uuid';11import { CLIAgentInfo, CopilotCLIModelInfo, ICopilotCLIAgents, ICopilotCLIModels } from '../copilotCli';12import { ICopilotCLIImageSupport } from '../copilotCLIImageSupport';13import { ICopilotCLISkills } from '../copilotCLISkills';14import { ICopilotCLIMCPHandler } from '../mcpHandler';1516export class MockCliSdkSession {17public emittedEvents: { event: string; content: string | undefined }[] = [];18public aborted = false;19public messages: {}[] = [];20public events: {}[] = [];21public title: string | undefined;22public name: string | undefined;23public readonly renameSession = async (name: string): Promise<void> => {24this.title = name;25this.name = name;26this.summary = name;27};28public readonly updateSessionSummary = async (summary: string): Promise<void> => {29if (!this.name) {30this.title = summary;31}32this.summary = summary;33};34public summary?: string;35constructor(public readonly sessionId: string, public readonly startTime: Date) { }36getChatContextMessages(): Promise<{}[]> { return Promise.resolve(this.messages); }37getEvents(): {}[] { return this.events; }38getSelectedModel(): Promise<string | undefined> { return Promise.resolve(undefined); }39isAbortable(): boolean { return !this.aborted; }40abort(): Promise<void> {41this.aborted = true;42return Promise.resolve();43}44emit(event: string, args: { content: string | undefined }): void {45this.emittedEvents.push({ event, content: args.content });46}47clearCustomAgent() {48return;49}50setPermissionsRequired(_required: boolean): void {51// no-op in tests52}53}5455export class MockSkillLocations implements ICopilotCLISkills {56declare _serviceBrand: undefined;57private readonly locations: Uri[];58constructor(locations: Uri[] = []) {59this.locations = locations;60}61async getSkillsLocations(_token: CancellationToken): Promise<Uri[]> {62return this.locations;63}64}6566export class MockCliSdkSessionManager {67public sessions = new Map<string, MockCliSdkSession>();68constructor(public readonly opts: {}) { }69createSession(_options: SessionOptions & { sessionId?: string }) {70const id = _options.sessionId ?? `sess_${generateUuid()}`;71const s = new MockCliSdkSession(id, new Date());72this.sessions.set(id, s);73return Promise.resolve(s);74}75getSession(opts: SessionOptions & { sessionId: string }, _writable: boolean) {76if (opts && opts.sessionId && this.sessions.has(opts.sessionId)) {77return Promise.resolve(this.sessions.get(opts.sessionId));78}79return Promise.resolve(undefined);80}81listSessions() {82return Promise.resolve(Array.from(this.sessions.values()).map(s => ({ sessionId: s.sessionId, startTime: s.startTime, modifiedTime: s.startTime, summary: s.summary, name: s.name })));83}84getSessionMetadata({ sessionId }: { sessionId: string }) {85const session = this.sessions.get(sessionId);86return Promise.resolve(session ? { sessionId: session.sessionId, startTime: session.startTime, modifiedTime: session.startTime, summary: session.summary, name: session.name, isRemote: false } : undefined);87}88deleteSession(id: string) { this.sessions.delete(id); return Promise.resolve(); }89closeSession(_id: string) { return Promise.resolve(); }90forkSession(sourceId: string, _toEventId?: string): Promise<{ sessionId: string }> {91const newId = `${sourceId}-fork-${generateUuid()}`;92const source = this.sessions.get(sourceId);93const s = new MockCliSdkSession(newId, source?.startTime ?? new Date());94this.sessions.set(newId, s);95return Promise.resolve({ sessionId: newId });96}97async loadDeferredRepoHooks(session: unknown) {98//99}100}101102export class NullCopilotCLIAgents implements ICopilotCLIAgents {103_serviceBrand: undefined;104readonly onDidChangeAgents: Event<void> = Event.None;105async getAgents(): Promise<readonly CLIAgentInfo[]> {106return [];107}108async getSessionAgent(_sessionId: string): Promise<string | undefined> {109return undefined;110}111resolveAgent(_agentId: string): Promise<SweCustomAgent | undefined> {112return Promise.resolve(undefined);113}114}115116export class NullICopilotCLIImageSupport implements ICopilotCLIImageSupport {117_serviceBrand: undefined;118storeImage(_imageData: Uint8Array, _mimeType: string): Promise<URI> {119return Promise.resolve(URI.file('/dev/null'));120}121isTrustedImage(_imageUri: URI): boolean {122return false;123}124}125126export class NullCopilotCLIMCPHandler implements ICopilotCLIMCPHandler {127_serviceBrand: undefined;128async loadMcpConfig(_resource: URI): Promise<{ mcpConfig: Record<string, NonNullable<SessionOptions['mcpServers']>[string]> | undefined; disposable: IDisposable }> {129return { mcpConfig: undefined, disposable: Disposable.None };130}131}132133export class NullCopilotCLIModels implements ICopilotCLIModels {134_serviceBrand: undefined;135async resolveModel(_modelId: string): Promise<string | undefined> { return undefined; }136async getDefaultModel(): Promise<string | undefined> { return undefined; }137async setDefaultModel(_modelId: string | undefined): Promise<void> { return; }138async getModels(): Promise<CopilotCLIModelInfo[]> { return []; }139registerLanguageModelChatProvider(): void { return; }140}141142143