use IPromptsService to provide customizations (#309873)

* use IPromptsService to provide customizations

* update

* update

* update

* update

* Update extensions/copilot/src/platform/promptFiles/test/common/mockPromptsService.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* update

* dispose MockPromptsService

* update

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Martin Aeschlimann
2026-04-15 09:40:03 +02:00
committed by GitHub
parent 721ebb8ef6
commit bf8712457a
26 changed files with 559 additions and 825 deletions
@@ -8,7 +8,7 @@ import * as l10n from '@vscode/l10n';
import { createReadStream } from 'node:fs';
import { devNull } from 'node:os';
import { createInterface } from 'node:readline';
import type { ChatRequest, ChatSessionItem } from 'vscode';
import type { ChatCustomAgent, ChatRequest, ChatSessionItem } from 'vscode';
import { IChatDebugFileLoggerService } from '../../../../platform/chat/common/chatDebugFileLoggerService';
import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService';
import { INativeEnvService } from '../../../../platform/env/common/envService';
@@ -18,7 +18,7 @@ import { RelativePattern } from '../../../../platform/filesystem/common/fileType
import { ILogService } from '../../../../platform/log/common/logService';
import { deriveCopilotCliOTelEnv } from '../../../../platform/otel/common/agentOTelEnv';
import { IOTelService } from '../../../../platform/otel/common/otelService';
import { ParsedPromptFile } from '../../../../platform/promptFiles/common/promptsService';
import { IPromptsService } from '../../../../platform/promptFiles/common/promptsService';
import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
import { createServiceIdentifier } from '../../../../util/common/services';
import { coalesce } from '../../../../util/vs/base/common/arrays';
@@ -34,7 +34,6 @@ import { IInstantiationService } from '../../../../util/vs/platform/instantiatio
import { ChatRequestTurn2, ChatResponseTurn2, ChatSessionStatus, Uri } from '../../../../vscodeTypes';
import { IPromptVariablesService } from '../../../prompt/node/promptVariablesService';
import { IAgentSessionsWorkspace } from '../../common/agentSessionsWorkspace';
import { IChatPromptFileService } from '../../common/chatPromptFileService';
import { IChatSessionMetadataStore, RequestDetails, StoredModeInstructions } from '../../common/chatSessionMetadataStore';
import { IChatSessionWorkspaceFolderService } from '../../common/chatSessionWorkspaceFolderService';
import { IChatSessionWorktreeService } from '../../common/chatSessionWorktreeService';
@@ -165,7 +164,7 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
@IOTelService private readonly _otelService: IOTelService,
@IPromptVariablesService private readonly _promptVariablesService: IPromptVariablesService,
@IChatDebugFileLoggerService private readonly _debugFileLogger: IChatDebugFileLoggerService,
@IChatPromptFileService private readonly _chatPromptFileService: IChatPromptFileService,
@IPromptsService private readonly _promptsService: IPromptsService,
) {
super();
this.monitorSessionFiles();
@@ -647,7 +646,7 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
protected async createSessionsOptions(options: ICreateSessionOptions & { mcpServers?: SessionOptions['mcpServers'] }): Promise<Readonly<SessionOptions>> {
const [agentInfos, skillLocations] = await Promise.all([
this.agents.getAgents(),
this.copilotCLISkills.getSkillsLocations(),
this.copilotCLISkills.getSkillsLocations(CancellationToken.None),
]);
const customAgents = agentInfos.map(i => i.agent);
const variablesContext = this._promptVariablesService.buildTemplateVariablesContext(options.sessionId, options.debugTargetSessionIds);
@@ -791,14 +790,14 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
const [agentId, storedDetails] = await Promise.all([agentIdPromise, requestDetailsPromise]);
// Build lookup from copilotRequestId → RequestDetails for the callback
const customAgentLookup = this.createCustomAgentLookup();
const customAgentLookup = await this.createCustomAgentLookup();
const legacyMappings: RequestDetails[] = [];
const detailsByCopilotId = new Map<string, RequestIdDetails>();
const defaultModeInstructions = agentId ? this.resolveAgentModeInstructions(agentId, customAgentLookup) : undefined;
const defaultModeInstructions = agentId ? await this.resolveAgentModeInstructions(agentId, customAgentLookup) : undefined;
for (const d of storedDetails) {
if (d.copilotRequestId) {
const modeInstructions = d.modeInstructions ?? this.resolveAgentModeInstructions(d.agentId, customAgentLookup) ?? defaultModeInstructions;
const modeInstructions = d.modeInstructions ?? await this.resolveAgentModeInstructions(d.agentId, customAgentLookup) ?? defaultModeInstructions;
detailsByCopilotId.set(d.copilotRequestId, { requestId: d.vscodeRequestId, toolIdEditMap: d.toolIdEditMap, modeInstructions });
}
}
@@ -831,36 +830,38 @@ export class CopilotCLISessionService extends Disposable implements ICopilotCLIS
return { history, events };
}
private createCustomAgentLookup(): Map<string, ParsedPromptFile> {
const agents = this._chatPromptFileService.customAgentPromptFiles;
const lookup = new Map<string, ParsedPromptFile>();
private async createCustomAgentLookup(): Promise<Map<string, [ChatCustomAgent, Lazy<Promise<string>>]>> {
const agents = await this._promptsService.getCustomAgents(CancellationToken.None);
const lookup = new Map<string, [ChatCustomAgent, Lazy<Promise<string>>]>();
for (const agent of agents) {
const lazyContent = new Lazy(() => this._promptsService.parseFile(agent.uri, CancellationToken.None).then(parsed => parsed.body?.getContent() ?? ''));
const keys = [
agent.header?.name?.trim(),
agent.name?.trim(),
agent.uri.toString(),
getAgentFileNameFromFilePath(agent.uri),
];
for (const key of keys) {
if (key && !lookup.has(key)) {
lookup.set(key, agent);
lookup.set(key, [agent, lazyContent]);
}
}
}
return lookup;
}
private resolveAgentModeInstructions(agentId: string | undefined, customAgentLookup: Map<string, ParsedPromptFile>): StoredModeInstructions | undefined {
private async resolveAgentModeInstructions(agentId: string | undefined, customAgentLookup: Map<string, [ChatCustomAgent, Lazy<Promise<string>>]>): Promise<StoredModeInstructions | undefined> {
if (!agentId) {
return undefined;
}
const agent = customAgentLookup.get(agentId);
if (!agent) {
const agentEntry = customAgentLookup.get(agentId);
if (!agentEntry) {
return undefined;
}
const [agent, lazyContent] = agentEntry;
return {
uri: agent.uri.toString(),
name: agent.header?.name?.trim() || agentId,
content: agent.body?.getContent() ?? '',
name: agent.name?.trim() || agentId,
content: await lazyContent.value,
};
}