Rename executePrompt to runSubagent (#1420)

This commit is contained in:
Rob Lourens
2025-10-19 14:52:40 -07:00
committed by GitHub
parent 69afc14478
commit 0893eaecfd
9 changed files with 45 additions and 46 deletions

View File

@@ -1,6 +1,6 @@
---
description: Researches a task to create multi-step plans
tools: ['search', 'github/github-mcp-server/get_issue', 'github/github-mcp-server/get_issue_comments', 'executePrompt', 'usages', 'problems', 'changes', 'testFailure', 'fetch', 'githubRepo', 'github.vscode-pull-request-github/issue_fetch', 'github.vscode-pull-request-github/activePullRequest', 'todos']
tools: ['search', 'github/github-mcp-server/get_issue', 'github/github-mcp-server/get_issue_comments', 'runSubagent', 'usages', 'problems', 'changes', 'testFailure', 'fetch', 'githubRepo', 'github.vscode-pull-request-github/issue_fetch', 'github.vscode-pull-request-github/activePullRequest', 'todos']
handoffs:
- label: Start Implementation
agent: agent
@@ -17,11 +17,11 @@ Comprehensive context gathering for planning following <plan_research>:
## 1. Context gathering and research:
MANDATORY: Run #executePrompt tool, instructing the agent to work autonomously without pausing for user feedback, following <plan_research> to gather context to return to you.
MANDATORY: Run #runSubagent tool, instructing the agent to work autonomously without pausing for user feedback, following <plan_research> to gather context to return to you.
DO NOT do any other tool calls after #executePrompt returns!
DO NOT do any other tool calls after #runSubagent returns!
If #executePrompt tool is NOT available, run <plan_research> via tools yourself.
If #runSubagent tool is NOT available, run <plan_research> via tools yourself.
## 2. Present a concise plan to the user for iteration:

View File

@@ -15,7 +15,9 @@ First, consider whether a new built-in tool is needed. Tools should be built-in
### Static part
First, add an entry in vscode-copilot's package.json under `contributes.languageModelTools`:
- Give it a name that starts with `copilot_`- this pattern is protected for our use only
- ~~Give it a name that starts with `copilot_`- this pattern is protected for our use only~~
- This is obsolete- new tools can use any name, I think matching `toolReferenceName` might be a good idea.
- The existing `copilot_` tools will be renamed later.
- Give it a reasonable `toolReferenceName` and a localized `userDescription`.
- `toolReferenceName` is the name used in the tool picker, and to reference the tool with `#`, and to add the tool to a mode or toolset.
- Consider whether the tool should be available on its own or part of a toolset. Add it to a toolset in `contributes.languageModelToolSets` if needed.

View File

@@ -165,12 +165,12 @@
}
},
{
"name": "execute_prompt",
"toolReferenceName": "executePrompt",
"displayName": "Execute Prompt",
"when": "config.github.copilot.chat.executePrompt.enabled",
"name": "runSubagent",
"toolReferenceName": "runSubagent",
"displayName": "%copilot.tools.runSubagent.name%",
"canBeReferencedInPrompt": true,
"modelDescription": "Launch a new agent to handle complex, multi-step tasks autonomously. This tool is good at researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries, use this agent to perform the search for you.\n\n- When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.\n - Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.\n - The agent's outputs should generally be trusted\n - Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent",
"userDescription": "%copilot.tools.runSubagent.description%",
"modelDescription": "Launch a new agent to handle complex, multi-step tasks autonomously. This tool is good at researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries, use this agent to perform the search for you.\n\n- Agents do not run async or in the background, you will wait for the agent's result.\n- When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.\n - Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.\n - The agent's outputs should generally be trusted\n - Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent",
"tags": [],
"inputSchema": {
"type": "object",
@@ -3121,14 +3121,6 @@
"detailed"
]
},
"github.copilot.chat.executePrompt.enabled": {
"type": "boolean",
"default": true,
"markdownDescription": "%github.copilot.config.executePrompt.enabled%",
"tags": [
"experimental"
]
},
"github.copilot.chat.completionsFetcher": {
"type": [
"string",
@@ -4388,4 +4380,4 @@
"string_decoder": "npm:string_decoder@1.2.0",
"node-gyp": "npm:node-gyp@10.3.1"
}
}
}

View File

@@ -300,9 +300,10 @@
"github.copilot.config.useResponsesApi": "Use the Responses API instead of the Chat Completions API when supported. Enables reasoning and reasoning summaries.\n\n**Note**: This is an experimental feature that is not yet activated for all users.",
"github.copilot.config.responsesApiReasoningEffort": "Sets the reasoning effort used for the Responses API. Requires `#github.copilot.chat.useResponsesApi#`.",
"github.copilot.config.responsesApiReasoningSummary": "Sets the reasoning summary style used for the Responses API. Requires `#github.copilot.chat.useResponsesApi#`.",
"github.copilot.config.executePrompt.enabled": "The executePrompt tool enables the agent to execute tasks in a separate, isolated context.",
"github.copilot.config.completionsFetcher": "Sets the fetcher used for the inline completions.",
"github.copilot.config.nesFetcher": "Sets the fetcher used for the next edit suggestions.",
"github.copilot.command.refreshCopilotAgentSessions": "Refresh Copilot Agent Sessions",
"github.copilot.command.openCopilotAgentSessionsInBrowser": "Open in browser"
"github.copilot.command.openCopilotAgentSessionsInBrowser": "Open in browser",
"copilot.tools.runSubagent.name": "Run Subagent",
"copilot.tools.runSubagent.description": "Runs a task within an isolated subagent context. Enables efficient organization of tasks and context window management."
}

View File

@@ -18,23 +18,23 @@ import { IToolCallingLoopOptions, ToolCallingLoop, ToolCallingLoopFetchOptions }
import { AgentPrompt } from '../../prompts/node/agent/agentPrompt';
import { PromptRenderer } from '../../prompts/node/base/promptRenderer';
import { ToolName } from '../../tools/common/toolNames';
import { normalizeToolSchema } from '../../tools/common/toolSchemaNormalizer';
import { ChatVariablesCollection } from '../common/chatVariablesCollection';
import { IBuildPromptContext } from '../common/intents';
import { IBuildPromptResult } from './intents';
import { normalizeToolSchema } from '../../tools/common/toolSchemaNormalizer';
export interface IExecutePromptToolCallingLoopOptions extends IToolCallingLoopOptions {
export interface ISubagentToolCallingLoopOptions extends IToolCallingLoopOptions {
request: ChatRequest;
location: ChatLocation;
promptText: string;
}
export class ExecutePromptToolCallingLoop extends ToolCallingLoop<IExecutePromptToolCallingLoopOptions> {
export class SubagentToolCallingLoop extends ToolCallingLoop<ISubagentToolCallingLoopOptions> {
public static readonly ID = 'executePromptTool';
public static readonly ID = 'subagent';
constructor(
options: IExecutePromptToolCallingLoopOptions,
options: ISubagentToolCallingLoopOptions,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ILogService logService: ILogService,
@IRequestLogger requestLogger: IRequestLogger,
@@ -85,7 +85,7 @@ export class ExecutePromptToolCallingLoop extends ToolCallingLoop<IExecutePrompt
}
protected async getAvailableTools(): Promise<LanguageModelToolInformation[]> {
const excludedTools = new Set([ToolName.ExecutePrompt, ToolName.CoreManageTodoList]);
const excludedTools = new Set([ToolName.RunSubagent, ToolName.CoreManageTodoList]);
return (await getAgentTools(this.instantiationService, this.options.request))
.filter(tool => !excludedTools.has(tool.name as ToolName))
// TODO can't do virtual tools at this level
@@ -95,7 +95,7 @@ export class ExecutePromptToolCallingLoop extends ToolCallingLoop<IExecutePrompt
protected async fetch({ messages, finishedCb, requestOptions }: ToolCallingLoopFetchOptions, token: CancellationToken): Promise<ChatResponse> {
const endpoint = await this.getEndpoint(this.options.request);
return endpoint.makeChatRequest2({
debugName: ExecutePromptToolCallingLoop.ID,
debugName: SubagentToolCallingLoop.ID,
messages,
finishedCb,
location: this.options.location,
@@ -114,7 +114,7 @@ export class ExecutePromptToolCallingLoop extends ToolCallingLoop<IExecutePrompt
userInitiatedRequest: false,
telemetryProperties: {
messageId: randomUUID(),
messageSource: ExecutePromptToolCallingLoop.ID
messageSource: SubagentToolCallingLoop.ID
},
}, token);
}

View File

@@ -65,7 +65,7 @@ export enum ToolName {
CoreRunTest = 'runTests',
ToolReplay = 'tool_replay',
EditFilesPlaceholder = 'edit_files',
ExecutePrompt = 'execute_prompt',
RunSubagent = 'runSubagent',
CoreConfirmationTool = 'vscode_get_confirmation'
}
@@ -109,7 +109,6 @@ export enum ContributedToolName {
RunVscodeCmd = 'copilot_runVscodeCommand',
ToolReplay = 'copilot_toolReplay',
EditFilesPlaceholder = 'copilot_editFiles',
ExecutePrompt = 'execute_prompt',
}
export const byokEditToolNamesToToolNames = {
@@ -171,6 +170,7 @@ export const toolCategories: Record<ToolName, ToolCategory> = {
[ToolName.FindFiles]: ToolCategory.Core,
[ToolName.CreateDirectory]: ToolCategory.Core,
[ToolName.ReadProjectStructure]: ToolCategory.Core,
[ToolName.RunSubagent]: ToolCategory.Core,
// already enabled only when tasks are enabled
[ToolName.CoreRunTask]: ToolCategory.Core,
@@ -218,7 +218,6 @@ export const toolCategories: Record<ToolName, ToolCategory> = {
// Other tools - categorize appropriately
[ToolName.UpdateUserPreferences]: ToolCategory.VSCodeInteraction,
[ToolName.ToolReplay]: ToolCategory.RedundantButSpecific,
[ToolName.ExecutePrompt]: ToolCategory.RedundantButSpecific,
[ToolName.CoreConfirmationTool]: ToolCategory.VSCodeInteraction,
} as const;

View File

@@ -9,7 +9,7 @@ import './createDirectoryTool';
import './createFileTool';
import './docTool';
import './editNotebookTool';
import './executePromptTool';
import './runSubagentTool';
import './findFilesTool';
import './findTestsFilesTool';
import './findTextInFilesTool';

View File

@@ -9,26 +9,27 @@ import { IInstantiationService } from '../../../util/vs/platform/instantiation/c
import { ChatPrepareToolInvocationPart, ChatResponseNotebookEditPart, ChatResponseTextEditPart, ExtendedLanguageModelToolResult, LanguageModelTextPart } from '../../../vscodeTypes';
import { Conversation, Turn } from '../../prompt/common/conversation';
import { IBuildPromptContext } from '../../prompt/common/intents';
import { ExecutePromptToolCallingLoop } from '../../prompt/node/executePromptToolCalling';
import { SubagentToolCallingLoop } from '../../prompt/node/subagentLoop';
import { ToolName } from '../common/toolNames';
import { CopilotToolMode, ICopilotTool, ToolRegistry } from '../common/toolsRegistry';
import { ChatFetchResponseType } from '../../../platform/chat/common/commonTypes';
export interface IExecutePromptParams {
export interface IRunSubagentParams {
prompt: string;
description: string;
}
class ExecutePromptTool implements ICopilotTool<IExecutePromptParams> {
public static readonly toolName = ToolName.ExecutePrompt;
class RunSubagentTool implements ICopilotTool<IRunSubagentParams> {
public static readonly toolName = ToolName.RunSubagent;
private _inputContext: IBuildPromptContext | undefined;
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
) { }
async invoke(options: vscode.LanguageModelToolInvocationOptions<IExecutePromptParams>, token: vscode.CancellationToken) {
async invoke(options: vscode.LanguageModelToolInvocationOptions<IRunSubagentParams>, token: vscode.CancellationToken) {
const loop = this.instantiationService.createInstance(ExecutePromptToolCallingLoop, {
const loop = this.instantiationService.createInstance(SubagentToolCallingLoop, {
toolCallLimit: 25,
conversation: new Conversation('', [new Turn('', { type: 'user', message: options.input.prompt })]),
request: this._inputContext!.request!,
@@ -43,13 +44,18 @@ class ExecutePromptTool implements ICopilotTool<IExecutePromptParams> {
);
const loopResult = await loop.run(stream, token);
// Return the text of the last assistant response from the tool calling loop
const lastRoundResponse = loopResult.toolCallRounds.at(-1)?.response ?? loopResult.round.response ?? '';
const result = new ExtendedLanguageModelToolResult([new LanguageModelTextPart(lastRoundResponse)]);
// Return the text of the last assistant response from the tool calling loop, or request error
let subagentSummary = '';
if (loopResult.response.type === ChatFetchResponseType.Success) {
subagentSummary = loopResult.toolCallRounds.at(-1)?.response ?? loopResult.round.response ?? '';
} else {
subagentSummary = `The subagent request failed with this message:\n${loopResult.response.type}: ${loopResult.response.reason}`;
}
const result = new ExtendedLanguageModelToolResult([new LanguageModelTextPart(subagentSummary)]);
return result;
}
prepareInvocation(options: vscode.LanguageModelToolInvocationPrepareOptions<IExecutePromptParams>, token: vscode.CancellationToken): vscode.ProviderResult<vscode.PreparedToolInvocation> {
prepareInvocation(options: vscode.LanguageModelToolInvocationPrepareOptions<IRunSubagentParams>, token: vscode.CancellationToken): vscode.ProviderResult<vscode.PreparedToolInvocation> {
const { input } = options;
try {
return {
@@ -60,10 +66,10 @@ class ExecutePromptTool implements ICopilotTool<IExecutePromptParams> {
}
}
async resolveInput(input: IExecutePromptParams, promptContext: IBuildPromptContext, mode: CopilotToolMode): Promise<IExecutePromptParams> {
async resolveInput(input: IRunSubagentParams, promptContext: IBuildPromptContext, mode: CopilotToolMode): Promise<IRunSubagentParams> {
this._inputContext = promptContext;
return input;
}
}
ToolRegistry.registerTool(ExecutePromptTool);
ToolRegistry.registerTool(RunSubagentTool);

View File

@@ -811,7 +811,6 @@ export namespace ConfigKey {
export const Gpt5CodexAlternatePrompt = defineExpSetting<'default' | 'codex'>('chat.gpt5CodexAlternatePrompt', 'codex');
export const GrokCodeAlternatePrompt = defineExpSetting<string>('chat.grokCodeAlternatePrompt', 'default');
export const ClaudeSonnet45AlternatePrompt = defineExpSetting<string>('chat.claudeSonnet45AlternatePrompt', 'default');
export const ExecutePromptEnabled = defineSetting<boolean>('chat.executePrompt.enabled', true);
export const CompletionsFetcher = defineExpSetting<FetcherId | undefined>('chat.completionsFetcher', undefined);
export const NextEditSuggestionsFetcher = defineExpSetting<FetcherId | undefined>('chat.nesFetcher', undefined);