Path: blob/main/extensions/copilot/src/extension/prompts/node/agent/test/agentTasksInstructions.spec.tsx
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 { BasePromptElementProps, PromptElement, UserMessage } from '@vscode/prompt-tsx';6import { expect, suite, test } from 'vitest';7import type * as vscode from 'vscode';8import { MockEndpoint } from '../../../../../platform/endpoint/test/node/mockEndpoint';9import { IIgnoreService, NullIgnoreService } from '../../../../../platform/ignore/common/ignoreService';10import { messageToMarkdown } from '../../../../../platform/log/common/messageStringify';11import { ITasksService } from '../../../../../platform/tasks/common/tasksService';12import { TestTasksService } from '../../../../../platform/tasks/common/testTasksService';13import { URI } from '../../../../../util/vs/base/common/uri';14import { SyncDescriptor } from '../../../../../util/vs/platform/instantiation/common/descriptors';15import { IInstantiationService } from '../../../../../util/vs/platform/instantiation/common/instantiation';16import { createExtensionUnitTestingServices } from '../../../../test/node/services';17import { ToolName } from '../../../../tools/common/toolNames';18import { renderPromptElement } from '../../base/promptRenderer';19import { AgentTasksInstructions } from '../agentPrompt';2021interface TaskPromptProps extends BasePromptElementProps {22readonly availableTools: readonly vscode.LanguageModelToolInformation[];23}2425class TaskPrompt extends PromptElement<TaskPromptProps> {26render() {27return (28<UserMessage>29<AgentTasksInstructions availableTools={this.props.availableTools} />30</UserMessage>31);32}33}3435class StaticTasksService extends TestTasksService {36constructor(private readonly taskGroups: [URI, vscode.TaskDefinition[]][]) {37super();38}3940override getTasks(...args: any[]): [] {41const workspaceFolder = args[0] as URI | undefined;4243if (workspaceFolder) {44const tasksForFolder = this.taskGroups.find(([folder]) => folder.toString() === workspaceFolder.toString())?.[1] ?? [];45return tasksForFolder as unknown as [];46}4748return this.taskGroups as unknown as [];49}50}5152class TestIgnoreService extends NullIgnoreService {53constructor(private readonly ignoredResources: Set<string>) {54super();55}5657override async isCopilotIgnored(file: URI): Promise<boolean> {58return this.ignoredResources.has(file.toString());59}60}6162suite('AgentTasksInstructions', () => {63const workspaceFolder = URI.file('/workspace');64const tasksFile = URI.joinPath(workspaceFolder, '.vscode', 'tasks.json');65const taskDefinition: vscode.TaskDefinition = {66type: 'shell',67label: 'Build',68command: 'npm',69args: ['run', 'build']70};7172const renderTaskPrompt = async (shouldIgnoreTasksFile: boolean) => {73const services = createExtensionUnitTestingServices();74services.define(ITasksService, new SyncDescriptor(StaticTasksService, [[[workspaceFolder, [taskDefinition]]]]));75services.define(IIgnoreService, new SyncDescriptor(TestIgnoreService, [new Set(shouldIgnoreTasksFile ? [tasksFile.toString()] : [])]));76const accessor = services.createTestingAccessor();77const instantiationService = accessor.get(IInstantiationService);78const endpoint = instantiationService.createInstance(MockEndpoint, undefined);79const taskTool: vscode.LanguageModelToolInformation = {80name: ToolName.CoreRunTask,81description: 'Run a workspace task',82source: undefined,83inputSchema: { type: 'object', properties: {} },84tags: []85};8687const { messages } = await renderPromptElement(instantiationService, endpoint, TaskPrompt, {88priority: 1,89availableTools: [taskTool]90});91const output = messages.map(m => messageToMarkdown(m)).join('\n\n');92accessor.dispose();93return { messages, output };94};9596test('renders task metadata when not ignored', async () => {97const { output } = await renderTaskPrompt(false);98expect(output).toContain('Build');99expect(output).toContain('"command": "npm"');100});101102test('skips task metadata when tasks.json is ignored', async () => {103const { output } = await renderTaskPrompt(true);104expect(output).not.toContain('Build');105expect(output).not.toContain('"command": "npm"');106});107});108109110