diff --git a/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx b/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx index f24dc6015c3..35afdc6d9e7 100644 --- a/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx +++ b/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx @@ -7,6 +7,8 @@ import { BasePromptElementProps, Chunk, Image, PromptElement, PromptPiece, Promp import type { ChatRequestEditedFileEvent, LanguageModelToolInformation, NotebookEditor, TaskDefinition, TextEditor } from 'vscode'; import { ChatLocation } from '../../../../platform/chat/common/commonTypes'; import { ConfigKey, IConfigurationService } from '../../../../platform/configuration/common/configurationService'; +import { ICustomInstructionsService } from '../../../../platform/customInstructions/common/customInstructionsService'; +import { USE_SKILL_ADHERENCE_PROMPT_SETTING } from '../../../../platform/customInstructions/common/promptTypes'; import { CacheType } from '../../../../platform/endpoint/common/endpointTypes'; import { IEnvService, OperatingSystem } from '../../../../platform/env/common/envService'; import { ILogService } from '../../../../platform/log/common/logService'; @@ -17,11 +19,11 @@ import { ITabsAndEditorsService } from '../../../../platform/tabs/common/tabsAnd import { ITasksService } from '../../../../platform/tasks/common/tasksService'; import { IExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService'; import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService'; -import { isDefined } from '../../../../util/vs/base/common/types'; +import { isDefined, isString } from '../../../../util/vs/base/common/types'; import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation'; import { ChatRequestEditedFileEventKind, Position, Range } from '../../../../vscodeTypes'; import { GenericBasePromptElementProps } from '../../../context/node/resolvers/genericPanelIntentInvocation'; -import { ChatVariablesCollection } from '../../../prompt/common/chatVariablesCollection'; +import { ChatVariablesCollection, isPromptInstructionText } from '../../../prompt/common/chatVariablesCollection'; import { getGlobalContextCacheKey, GlobalContextMessageMetadata, RenderedUserMessageMetadata, Turn } from '../../../prompt/common/conversation'; import { InternalToolReference } from '../../../prompt/common/intents'; import { IPromptVariablesService } from '../../../prompt/node/promptVariablesService'; @@ -315,7 +317,8 @@ export class AgentUserMessage extends PromptElement { constructor( props: AgentUserMessageProps, @IPromptVariablesService private readonly promptVariablesService: IPromptVariablesService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(props); } @@ -376,6 +379,7 @@ export class AgentUserMessage extends PromptElement { {/* Critical reminders that are effective when repeated right next to the user message */} + {this.configurationService.getNonExtensionConfig(USE_SKILL_ADHERENCE_PROMPT_SETTING) && } {query && @@ -449,6 +453,41 @@ class CurrentDatePrompt extends PromptElement { } } +interface SkillAdherenceReminderProps extends BasePromptElementProps { + readonly chatVariables: ChatVariablesCollection; +} + +/** + * Skill adherence reminder that prompts the model to read SKILL.md files when skills are available + * in the instruction index. + * Shown whenever the instruction index variable contains at least one skill or skill folder entry. + */ +class SkillAdherenceReminder extends PromptElement { + constructor( + props: SkillAdherenceReminderProps, + @ICustomInstructionsService private readonly customInstructionsService: ICustomInstructionsService, + ) { + super(props); + } + + async render() { + // Check if any skills are available from the instruction index + const indexVariable = this.props.chatVariables.find(isPromptInstructionText); + if (!indexVariable || !isString(indexVariable.value)) { + return undefined; + } + + const indexFile = this.customInstructionsService.parseInstructionIndexFile(indexVariable.value); + if (indexFile.skills.size === 0) { + return undefined; + } + + return + Always check if any skills apply to the user's request. If so, use the {ToolName.ReadFile} tool to read the corresponding SKILL.md files. Multiple skill files may be needed for a single request. These files contain best practices built from testing that are needed for high-quality outputs.
+
; + } +} + interface CurrentEditorContextProps extends BasePromptElementProps { readonly endpoint: IChatEndpoint; } diff --git a/extensions/copilot/src/platform/customInstructions/common/promptTypes.ts b/extensions/copilot/src/platform/customInstructions/common/promptTypes.ts index ce1d856a814..aeb07244dc8 100644 --- a/extensions/copilot/src/platform/customInstructions/common/promptTypes.ts +++ b/extensions/copilot/src/platform/customInstructions/common/promptTypes.ts @@ -19,6 +19,7 @@ export const SKILLS_LOCATION_KEY = 'chat.agentSkillsLocations'; export const WORKSPACE_SKILL_FOLDERS = ['.github/skills', '.claude/skills']; export const PERSONAL_SKILL_FOLDERS = ['.copilot/skills', '.claude/skills']; export const USE_AGENT_SKILLS_SETTING = 'chat.useAgentSkills'; +export const USE_SKILL_ADHERENCE_PROMPT_SETTING = 'chat.experimental.useSkillAdherencePrompt'; export const COPILOT_INSTRUCTIONS_PATH = '.github/copilot-instructions.md';