Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ import { IVSCodeExtensionContext } from '../../../platform/extContext/common/ext
import { IGitService } from '../../../platform/git/common/gitService';
import { toGitUri } from '../../../platform/git/common/utils';
import { ILogService } from '../../../platform/log/common/logService';
import { ParsedPromptFile, PromptFileParser } from '../../../platform/promptFiles/common/promptsService';
import { IPromptsService, ParsedPromptFile } from '../../../platform/promptFiles/common/promptsService';
import { ITelemetryService } from '../../../platform/telemetry/common/telemetry';
import { IWorkspaceService } from '../../../platform/workspace/common/workspaceService';
import { disposableTimeout } from '../../../util/vs/base/common/async';
import { isCancellationError } from '../../../util/vs/base/common/errors';
import { Emitter, Event } from '../../../util/vs/base/common/event';
Expand Down Expand Up @@ -414,7 +413,7 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
@IConfigurationService private readonly configurationService: IConfigurationService,
@ICopilotCLISDK private readonly copilotCLISDK: ICopilotCLISDK,
@ILogService private readonly logService: ILogService,
@IWorkspaceService private readonly workspaceService: IWorkspaceService,
@IPromptsService private readonly promptsService: IPromptsService,
) {
super();
}
Expand Down Expand Up @@ -458,8 +457,8 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
const additionalReferences = this.previousReferences.get(id) || [];
this.previousReferences.delete(id);
const [modelId, agent] = await Promise.all([
this.getModelId(id, request),
this.getAgent(id, request),
this.getModelId(id, request, token),
this.getAgent(id, request, token),
]);
const session = await this.getOrCreateSession(request, chatSessionContext, modelId, agent, stream, disposables, token);
if (!session || token.isCancellationRequested) {
Expand Down Expand Up @@ -511,8 +510,8 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
* If opening an existing session, then uses the agent associated with that session.
* If creating a new session with a prompt file that specifies an agent, then uses that agent.
*/
private async getAgent(sessionId: string | undefined, request: vscode.ChatRequest | undefined): Promise<SweCustomAgent | undefined> {
const promptFile = request ? await this.getPromptInfoFromRequest(request) : undefined;
private async getAgent(sessionId: string | undefined, request: vscode.ChatRequest | undefined, token: vscode.CancellationToken): Promise<SweCustomAgent | undefined> {
const promptFile = request ? await this.getPromptInfoFromRequest(request, token) : undefined;
if (promptFile?.header?.agent) {
const agent = await this.copilotCLIAgents.resolveAgent(promptFile.header.agent);
if (agent) {
Expand All @@ -527,14 +526,13 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
return this.copilotCLIAgents.resolveAgent(sessionAgent ?? defaultAgent);
}

private async getPromptInfoFromRequest(request: vscode.ChatRequest): Promise<ParsedPromptFile | undefined> {
private async getPromptInfoFromRequest(request: vscode.ChatRequest, token: vscode.CancellationToken): Promise<ParsedPromptFile | undefined> {
const promptFile = new ChatVariablesCollection(request.references).find(isPromptFile);
if (!promptFile || !URI.isUri(promptFile.reference.value)) {
return undefined;
}
try {
const doc = await this.workspaceService.openTextDocument(promptFile.reference.value);
return new PromptFileParser().parse(promptFile.reference.value, doc.getText());
return await this.promptsService.parseFile(promptFile.reference.value, token);
} catch (ex) {
this.logService.error(`Failed to parse the prompt file: ${promptFile.reference.value.toString()}`, ex);
return undefined;
Expand Down Expand Up @@ -571,8 +569,8 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
return session;
}

private async getModelId(sessionId: string | undefined, request: vscode.ChatRequest | undefined): Promise<string | undefined> {
const promptFile = request ? await this.getPromptInfoFromRequest(request) : undefined;
private async getModelId(sessionId: string | undefined, request: vscode.ChatRequest | undefined, token: vscode.CancellationToken): Promise<string | undefined> {
const promptFile = request ? await this.getPromptInfoFromRequest(request, token) : undefined;
if (promptFile?.header?.model) {
const model = await this.copilotCLIModels.resolveModel(promptFile.header.model);
if (model) {
Expand Down Expand Up @@ -812,8 +810,8 @@ export class CopilotCLIChatSessionParticipant extends Disposable {
}
const [{ prompt, attachments }, model, agent] = await Promise.all([
this.promptResolver.resolvePrompt(request, requestPrompt, (references || []).concat([]), isolationEnabled, token),
this.getModelId(undefined, undefined),
this.getAgent(undefined, undefined),
this.getModelId(undefined, undefined, token),
this.getAgent(undefined, undefined, token),
]);

const session = await this.sessionService.createSession({ workingDirectory, isolationEnabled, agent, model }, token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { IVSCodeExtensionContext } from '../../../../platform/extContext/common/
import { MockFileSystemService } from '../../../../platform/filesystem/node/test/mockFileSystemService';
import { IGitService } from '../../../../platform/git/common/gitService';
import { ILogService } from '../../../../platform/log/common/logService';
import { PromptsServiceImpl } from '../../../../platform/promptFiles/common/promptsServiceImpl';
import { NullTelemetryService } from '../../../../platform/telemetry/common/nullTelemetryService';
import type { ITelemetryService } from '../../../../platform/telemetry/common/telemetry';
import { IWorkspaceService, NullWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
Expand Down Expand Up @@ -190,7 +191,7 @@ describe('CopilotCLIChatSessionParticipant.handleRequest', () => {
configurationService,
copilotSDK,
logger,
new NullWorkspaceService()
new PromptsServiceImpl(new NullWorkspaceService())
);
});

Expand Down
7 changes: 2 additions & 5 deletions src/extension/prompts/node/panel/promptFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import { BasePromptElementProps, PromptElement, PromptReference, PromptSizing } from '@vscode/prompt-tsx';
import type { ChatLanguageModelToolReference } from 'vscode';
import { IFileSystemService } from '../../../../platform/filesystem/common/fileSystemService';
import { IIgnoreService } from '../../../../platform/ignore/common/ignoreService';
import { ILogService } from '../../../../platform/log/common/logService';
import { IPromptPathRepresentationService } from '../../../../platform/prompts/common/promptPathRepresentationService';
Expand All @@ -16,7 +15,6 @@ import { IPromptVariablesService } from '../../../prompt/node/promptVariablesSer
import { EmbeddedInsideUserMessage } from '../base/promptElement';
import { Tag } from '../base/tag';
import { FilePathMode } from './fileVariable';
import { isEqual } from '../../../../util/vs/base/common/resources';

export interface PromptFileProps extends BasePromptElementProps, EmbeddedInsideUserMessage {
readonly variable: PromptVariable;
Expand All @@ -28,7 +26,6 @@ export class PromptFile extends PromptElement<PromptFileProps, void> {

constructor(
props: PromptFileProps,
@IFileSystemService private readonly fileSystemService: IFileSystemService,
@IPromptVariablesService private readonly promptVariablesService: IPromptVariablesService,
@ILogService private readonly logService: ILogService,
@IPromptPathRepresentationService private readonly promptPathRepresentationService: IPromptPathRepresentationService,
Expand Down Expand Up @@ -65,8 +62,8 @@ export class PromptFile extends PromptElement<PromptFileProps, void> {

private async getBodyContent(fileUri: URI, toolReferences: readonly ChatLanguageModelToolReference[] | undefined): Promise<string | undefined> {
try {
const documentText = this.workspaceService.textDocuments.find(doc => isEqual(doc.uri, fileUri))?.getText();
let content = documentText ?? new TextDecoder().decode(await this.fileSystemService.readFile(fileUri));
const doc = await this.workspaceService.openTextDocument(fileUri);
let content = doc.getText();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aeschli /cc

if (toolReferences && toolReferences.length > 0) {
content = await this.promptVariablesService.resolveToolReferencesInPrompt(content, toolReferences);
}
Expand Down
1 change: 1 addition & 0 deletions src/platform/promptFiles/common/promptsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export namespace PromptFileLangageId {
* A service that provides prompt file related functionalities: agents, instructions and prompt files.
*/
export interface IPromptsService {
readonly _serviceBrand: undefined;
/**
* Reads and parses the provided URI
* @param uris
Expand Down
16 changes: 6 additions & 10 deletions src/platform/promptFiles/common/promptsServiceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,21 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { raceCancellationError } from '../../../util/vs/base/common/async';
import { CancellationToken } from '../../../util/vs/base/common/cancellation';
import { CancellationError } from '../../../util/vs/base/common/errors';
import { URI } from '../../../util/vs/base/common/uri';
import { PromptFileParser } from '../../../util/vs/workbench/contrib/chat/common/promptSyntax/promptFileParser';
import { IFileSystemService } from '../../filesystem/common/fileSystemService';
import { IWorkspaceService } from '../../workspace/common/workspaceService';
import { IPromptsService, ParsedPromptFile } from './promptsService';

export class PromptsServiceImpl implements IPromptsService {

declare _serviceBrand: undefined;
constructor(
@IFileSystemService private readonly fileService: IFileSystemService
@IWorkspaceService private readonly workspaceService: IWorkspaceService
) { }

public async parseFile(uri: URI, token: CancellationToken): Promise<ParsedPromptFile> {
const fileContent = await this.fileService.readFile(uri);
if (token.isCancellationRequested) {
throw new CancellationError();
}
const text = new TextDecoder().decode(fileContent);
return new PromptFileParser().parse(uri, text);
const doc = await raceCancellationError(this.workspaceService.openTextDocument(uri), token);
return new PromptFileParser().parse(uri, doc.getText());
}
}