Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/agents/vscode-node/planAgentProvider.ts
13399 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as vscode from 'vscode';
7
import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';
8
import { AGENT_FILE_EXTENSION } from '../../../platform/customInstructions/common/promptTypes';
9
import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext';
10
import { IFileSystemService } from '../../../platform/filesystem/common/fileSystemService';
11
import { ILogService } from '../../../platform/log/common/logService';
12
import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService';
13
import { Disposable } from '../../../util/vs/base/common/lifecycle';
14
import { AgentConfig, AgentHandoff, buildAgentMarkdown, DEFAULT_READ_TOOLS } from './agentTypes';
15
16
/**
17
* Base Plan agent configuration - embedded from Plan.agent.md
18
* This avoids runtime file loading and YAML parsing dependencies.
19
*/
20
const BASE_PLAN_AGENT_CONFIG: AgentConfig = {
21
name: 'Plan',
22
description: 'Researches and outlines multi-step plans',
23
argumentHint: 'Outline the goal or problem to research',
24
target: 'vscode',
25
disableModelInvocation: true,
26
tools: [
27
...DEFAULT_READ_TOOLS,
28
],
29
handoffs: [], // Handoffs are generated dynamically in buildCustomizedConfig
30
body: '' // Body is generated dynamically in buildCustomizedConfig
31
};
32
33
/**
34
* Provides the Plan agent dynamically with settings-based customization.
35
*
36
* This provider uses an embedded configuration and generates .agent.md content
37
* with settings-based customization (additional tools and model override).
38
* No external file loading or YAML parsing dependencies required.
39
*/
40
export class PlanAgentProvider extends Disposable implements vscode.ChatCustomAgentProvider {
41
readonly label = vscode.l10n.t('Plan Agent');
42
43
private static readonly CACHE_DIR = 'plan-agent';
44
private static readonly AGENT_FILENAME = `Plan${AGENT_FILE_EXTENSION}`;
45
46
private readonly _onDidChangeCustomAgents = this._register(new vscode.EventEmitter<void>());
47
readonly onDidChangeCustomAgents = this._onDidChangeCustomAgents.event;
48
49
constructor(
50
@IConfigurationService private readonly configurationService: IConfigurationService,
51
@IVSCodeExtensionContext private readonly extensionContext: IVSCodeExtensionContext,
52
@IFileSystemService private readonly fileSystemService: IFileSystemService,
53
@ILogService private readonly logService: ILogService,
54
@IExperimentationService private readonly experimentationService: IExperimentationService,
55
) {
56
super();
57
58
// Listen for settings changes to refresh agents
59
// Note: When settings change, we fire onDidChangeCustomAgents which causes VS Code to re-fetch
60
// the agent definition. However, handoff buttons already rendered may not work as
61
// these capture the model at render time.
62
this._register(this.configurationService.onDidChangeConfiguration(e => {
63
if (e.affectsConfiguration(ConfigKey.PlanAgentAdditionalTools.fullyQualifiedId) ||
64
e.affectsConfiguration(ConfigKey.Deprecated.PlanAgentModel.fullyQualifiedId) ||
65
e.affectsConfiguration('chat.planAgent.defaultModel') ||
66
e.affectsConfiguration(ConfigKey.ImplementAgentModel.fullyQualifiedId) ||
67
e.affectsConfiguration(ConfigKey.ExploreAgentEnabled.fullyQualifiedId) ||
68
e.affectsConfiguration(ConfigKey.Advanced.SearchSubagentToolEnabled.fullyQualifiedId)) {
69
this._onDidChangeCustomAgents.fire();
70
}
71
}));
72
}
73
74
async provideCustomAgents(
75
_context: unknown,
76
_token: vscode.CancellationToken
77
): Promise<vscode.ChatResource[]> {
78
// Build config with settings-based customization
79
const config = this.buildCustomizedConfig();
80
81
// Generate .agent.md content
82
const content = buildAgentMarkdown(config);
83
84
// Write to cache file and return URI
85
const fileUri = await this.writeCacheFile(content);
86
return [{ uri: fileUri }];
87
}
88
89
private async writeCacheFile(content: string): Promise<vscode.Uri> {
90
const cacheDir = vscode.Uri.joinPath(
91
this.extensionContext.globalStorageUri,
92
PlanAgentProvider.CACHE_DIR
93
);
94
95
// Ensure cache directory exists
96
try {
97
await this.fileSystemService.stat(cacheDir);
98
} catch {
99
await this.fileSystemService.createDirectory(cacheDir);
100
}
101
102
const fileUri = vscode.Uri.joinPath(cacheDir, PlanAgentProvider.AGENT_FILENAME);
103
await this.fileSystemService.writeFile(fileUri, new TextEncoder().encode(content));
104
this.logService.trace(`[PlanAgentProvider] Wrote agent file: ${fileUri.toString()}`);
105
return fileUri;
106
}
107
108
static buildAgentBody(exploreEnabled: boolean, searchSubagentEnabled: boolean): string {
109
let discoverySection: string;
110
if (exploreEnabled) {
111
discoverySection = `## 1. Discovery
112
113
Run the *Explore* subagent to gather context, analogous existing features to use as implementation templates, and potential blockers or ambiguities. When the task spans multiple independent areas (e.g., frontend + backend, different features, separate repos), launch **2-3 *Explore* subagents in parallel** — one per area — to speed up discovery.
114
115
Update the plan with your findings.`;
116
} else if (searchSubagentEnabled) {
117
discoverySection = `## 1. Discovery
118
119
Use #tool:searchSubagent to gather context, analogous existing features to use as implementation templates, and potential blockers or ambiguities. When the task spans multiple independent areas (e.g., frontend + backend, different features, separate repos), launch **2-3 search subagents in parallel** — one per area — to speed up discovery.
120
121
Update the plan with your findings.`;
122
} else {
123
discoverySection = `## 1. Discovery
124
125
Search the codebase to gather context, analogous existing features to use as implementation templates, and potential blockers or ambiguities.
126
127
Update the plan with your findings.`;
128
}
129
130
return `You are a PLANNING AGENT, pairing with the user to create a detailed, actionable plan.
131
132
You research the codebase → clarify with the user → capture findings and decisions into a comprehensive plan. This iterative approach catches edge cases and non-obvious requirements BEFORE implementation begins.
133
134
Your SOLE responsibility is planning. NEVER start implementation.
135
136
**Current plan**: \`/memories/session/plan.md\` - update using #tool:vscode/memory .
137
138
<rules>
139
- STOP if you consider running file editing tools — plans are for others to execute. The only write tool you have is #tool:vscode/memory for persisting plans.
140
- Use #tool:vscode/askQuestions freely to clarify requirements — don't make large assumptions
141
- Present a well-researched plan with loose ends tied BEFORE implementation
142
</rules>
143
144
<workflow>
145
Cycle through these phases based on user input. This is iterative, not linear. If the user task is highly ambiguous, do only *Discovery* to outline a draft plan, then move on to alignment before fleshing out the full plan.
146
147
${discoverySection}
148
149
## 2. Alignment
150
151
If research reveals major ambiguities or if you need to validate assumptions:
152
- Use #tool:vscode/askQuestions to clarify intent with the user.
153
- Surface discovered technical constraints or alternative approaches
154
- If answers significantly change the scope, loop back to **Discovery**
155
156
## 3. Design
157
158
Once context is clear, draft a comprehensive implementation plan.
159
160
The plan should reflect:
161
- Structured concise enough to be scannable and detailed enough for effective execution
162
- Step-by-step implementation with explicit dependencies — mark which steps can run in parallel vs. which block on prior steps
163
- For plans with many steps, group into named phases that are each independently verifiable
164
- Verification steps for validating the implementation, both automated and manual
165
- Critical architecture to reuse or use as reference — reference specific functions, types, or patterns, not just file names
166
- Critical files to be modified (with full paths)
167
- Explicit scope boundaries — what's included and what's deliberately excluded
168
- Reference decisions from the discussion
169
- Leave no ambiguity
170
171
Save the comprehensive plan document to \`/memories/session/plan.md\` via #tool:vscode/memory, then show the scannable plan to the user for review. You MUST show plan to the user, as the plan file is for persistence only, not a substitute for showing it to the user.
172
173
## 4. Refinement
174
175
On user input after showing the plan:
176
- Changes requested → revise and present updated plan. Update \`/memories/session/plan.md\` to keep the documented plan in sync
177
- Questions asked → clarify, or use #tool:vscode/askQuestions for follow-ups
178
- Alternatives wanted → loop back to **Discovery** with new subagent
179
- Approval given → acknowledge, the user can now use handoff buttons
180
181
Keep iterating until explicit approval or handoff.
182
</workflow>
183
184
<plan_style_guide>
185
\`\`\`markdown
186
## Plan: {Title (2-10 words)}
187
188
{TL;DR - what, why, and how (your recommended approach).}
189
190
**Steps**
191
1. {Implementation step-by-step — note dependency ("*depends on N*") or parallelism ("*parallel with step N*") when applicable}
192
2. {For plans with 5+ steps, group steps into named phases with enough detail to be independently actionable}
193
194
**Relevant files**
195
- \`{full/path/to/file}\` — {what to modify or reuse, referencing specific functions/patterns}
196
197
**Verification**
198
1. {Verification steps for validating the implementation (**Specific** tasks, tests, commands, MCP tools, etc; not generic statements)}
199
200
**Decisions** (if applicable)
201
- {Decision, assumptions, and includes/excluded scope}
202
203
**Further Considerations** (if applicable, 1-3 items)
204
1. {Clarifying question with recommendation. Option A / Option B / Option C}
205
2. {…}
206
\`\`\`
207
208
Rules:
209
- NO code blocks — describe changes, link to files and specific symbols/functions
210
- NO blocking questions at the end — ask during workflow via #tool:vscode/askQuestions
211
- The plan MUST be presented to the user, don't just mention the plan file.
212
</plan_style_guide>`;
213
}
214
215
private buildCustomizedConfig(): AgentConfig {
216
const additionalTools = this.configurationService.getConfig(ConfigKey.PlanAgentAdditionalTools);
217
const isExploreEnabled = this.configurationService.getExperimentBasedConfig(ConfigKey.ExploreAgentEnabled, this.experimentationService);
218
const isSearchSubagentEnabled = this.configurationService.getExperimentBasedConfig(ConfigKey.Advanced.SearchSubagentToolEnabled, this.experimentationService);
219
const coreDefaultModel = this.configurationService.getNonExtensionConfig<string>('chat.planAgent.defaultModel');
220
const modelOverride = coreDefaultModel || this.configurationService.getConfig(ConfigKey.Deprecated.PlanAgentModel);
221
222
const implementAgentModelOverride = this.configurationService.getConfig(ConfigKey.ImplementAgentModel);
223
224
// Build handoffs dynamically with model override
225
const startImplementationHandoff: AgentHandoff = {
226
label: 'Start Implementation',
227
agent: 'agent',
228
prompt: 'Start implementation',
229
send: true,
230
...(implementAgentModelOverride ? { model: implementAgentModelOverride } : {})
231
};
232
233
const openInEditorHandoff: AgentHandoff = {
234
label: 'Open in Editor',
235
agent: 'agent',
236
prompt: '#createFile the plan as is into an untitled file (`untitled:plan-${camelCaseName}.prompt.md` without frontmatter) for further refinement.',
237
showContinueOn: false,
238
send: true
239
};
240
241
// Collect tools to add
242
const toolsToAdd: string[] = [...additionalTools];
243
244
// Always include askQuestions tool (now provided by core)
245
toolsToAdd.push('vscode/askQuestions');
246
247
// When explore agent is enabled, include the 'agent' tool to allow sub-agent calls
248
if (isExploreEnabled) {
249
toolsToAdd.push('agent');
250
}
251
252
// Merge additional tools (deduplicated)
253
const tools = toolsToAdd.length > 0
254
? [...new Set([...BASE_PLAN_AGENT_CONFIG.tools, ...toolsToAdd])]
255
: [...BASE_PLAN_AGENT_CONFIG.tools];
256
257
// Start with base config
258
return {
259
...BASE_PLAN_AGENT_CONFIG,
260
// When explore agent is enabled, allow the Explore subagent
261
...(isExploreEnabled ? { agents: ['Explore'] } : {}),
262
tools,
263
handoffs: [startImplementationHandoff, openInEditorHandoff, ...(BASE_PLAN_AGENT_CONFIG.handoffs ?? [])],
264
body: PlanAgentProvider.buildAgentBody(isExploreEnabled, isSearchSubagentEnabled),
265
...(modelOverride ? { model: modelOverride } : {}),
266
};
267
}
268
}
269
270