Skip to content

Commit b9c8f7b

Browse files
committed
Merge remote-tracking branch 'origin/main' into joao/copilot-builtin
2 parents 26f5685 + cc27248 commit b9c8f7b

101 files changed

Lines changed: 6564 additions & 4158 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---
2+
applyTo: 'src/extension/prompts/node/agent/**'
3+
description: Model-specific prompt authoring and registry guidelines
4+
---
5+
6+
Guidelines for creating, registering, and testing model-specific prompts via the `PromptRegistry` system.
7+
8+
## Prompt Registry
9+
10+
The `PromptRegistry` in `promptRegistry.ts` maps AI models to their optimal prompt structures. Each model provider has a **resolver** class implementing `IAgentPrompt` that returns prompt customizations for that provider's models.
11+
12+
### Resolution Order
13+
14+
When `PromptRegistry.resolveAllCustomizations()` is called:
15+
1. **Phase 1 — `matchesModel()`**: Iterates registered resolvers in order, calling `matchesModel()`. First `true` wins.
16+
2. **Phase 2 — `familyPrefixes`**: If no `matchesModel` matched, checks `endpoint.family.startsWith(prefix)`. First match wins.
17+
3. **Defaults**: If no resolver matches, defaults are used for all customizations.
18+
19+
Registration order matters — more specific resolvers (e.g., hash-based) should be registered before broader ones (e.g., prefix-based fallbacks).
20+
21+
### Resolver Interface
22+
23+
The `IAgentPrompt` interface provides these customization methods:
24+
25+
| Method | Returns | Purpose |
26+
|--------|---------|--------|
27+
| `resolveSystemPrompt(endpoint)` | `SystemPrompt` | Main system prompt class |
28+
| `resolveReminderInstructions?(endpoint)` | `ReminderInstructionsConstructor` | Reminder instructions appended to user messages |
29+
| `resolveToolReferencesHint?(endpoint)` | `ToolReferencesHintConstructor` | Tool usage hints |
30+
| `resolveCopilotIdentityRules?(endpoint)` | `CopilotIdentityRulesConstructor` | Identity/role rules |
31+
| `resolveSafetyRules?(endpoint)` | `SafetyRulesConstructor` | Safety rules |
32+
| `resolveUserQueryTagName?(endpoint)` | `string` | Tag name wrapping user queries |
33+
34+
All methods are optional except `resolveSystemPrompt`. Unimplemented methods fall back to defaults (`DefaultReminderInstructions`, `DefaultToolReferencesHint`, etc.).
35+
36+
### Dependency Injection in Resolvers
37+
38+
Resolvers are created via `instantiationService.createInstance()`, so they support full constructor DI. Inject `IConfigurationService`, `IExperimentationService`, etc. to read experiment flags or config values:
39+
40+
```typescript
41+
class MyProviderPromptResolver implements IAgentPrompt {
42+
static readonly familyPrefixes = ['my-model'];
43+
44+
constructor(
45+
@IConfigurationService private readonly configurationService: IConfigurationService,
46+
@IExperimentationService private readonly experimentationService: IExperimentationService,
47+
) { }
48+
49+
private getVariant(): string {
50+
return this.configurationService.getExperimentBasedConfig(
51+
ConfigKey.MyPromptVariant, this.experimentationService);
52+
}
53+
54+
resolveSystemPrompt(endpoint: IChatEndpoint): SystemPrompt | undefined {
55+
if (this.getVariant() === 'optimized') {
56+
return MyOptimizedPrompt;
57+
}
58+
if (endpoint.model?.includes('v4')) {
59+
return MyV4Prompt;
60+
}
61+
return MyDefaultPrompt;
62+
}
63+
64+
resolveReminderInstructions(endpoint: IChatEndpoint): ReminderInstructionsConstructor | undefined {
65+
if (this.getVariant() === 'optimized') {
66+
return MyOptimizedReminderInstructions;
67+
}
68+
return MyDefaultReminderInstructions;
69+
}
70+
71+
resolveCopilotIdentityRules(endpoint: IChatEndpoint): CopilotIdentityRulesConstructor | undefined {
72+
return MyCopilotIdentityRules;
73+
}
74+
75+
resolveSafetyRules(endpoint: IChatEndpoint): SafetyRulesConstructor | undefined {
76+
return MySafetyRules;
77+
}
78+
}
79+
```
80+
81+
See `AnthropicPromptResolver` in `anthropicPrompts.tsx` for a production example using config and experiment flags across multiple resolve methods.
82+
83+
## Creating a New Model Prompt
84+
85+
### 1. Create the prompt component
86+
87+
Copy `DefaultAgentPrompt` from `defaultAgentInstructions.tsx`:
88+
89+
```tsx
90+
export class MyProviderAgentPrompt extends PromptElement<DefaultAgentPromptProps> {
91+
async render(state: void, sizing: PromptSizing) {
92+
const tools = detectToolCapabilities(this.props.availableTools);
93+
return <InstructionMessage>
94+
{/* Your customizations here */}
95+
</InstructionMessage>;
96+
}
97+
}
98+
```
99+
100+
### 2. Create the resolver
101+
102+
A resolver can match models by hash (via `matchesModel`) and/or by family prefix:
103+
104+
```typescript
105+
class MyProviderPromptResolver implements IAgentPrompt {
106+
static readonly familyPrefixes = ['my-model', 'provider-name'];
107+
108+
// Optional: hash-based matching for models that can't be identified by prefix
109+
static async matchesModel(endpoint: IChatEndpoint): Promise<boolean> {
110+
return isMyModel(endpoint);
111+
}
112+
113+
resolveSystemPrompt(endpoint: IChatEndpoint): SystemPrompt | undefined {
114+
return MyProviderAgentPrompt;
115+
}
116+
117+
resolveReminderInstructions(endpoint: IChatEndpoint): ReminderInstructionsConstructor | undefined {
118+
return MyProviderReminderInstructions;
119+
}
120+
}
121+
```
122+
123+
A single resolver can return different prompts for different models within the same family using conditional logic inside `resolveSystemPrompt`.
124+
125+
### 3. Register and import
126+
127+
Register at the bottom of the file:
128+
129+
```typescript
130+
PromptRegistry.registerPrompt(MyProviderPromptResolver);
131+
```
132+
133+
Then add the import in `allAgentPrompts.ts`.
134+
135+
### 4. Test
136+
137+
Add your model family to the list at the top of `test/agentPrompt.spec.tsx`. This renders the prompt for your model with different input scenarios and validates against snapshots.
138+
139+
## Prompt Authoring Principles
140+
141+
- **Start with defaults** — most models infer correct behavior from tool definitions alone. Only customize if the model consistently fails.
142+
- **Make minimal adjustments** — add 1-2 sentences targeting specific issues rather than over-specifying.
143+
- **Use conditional sections** — wrap instructions in tool availability checks (`detectToolCapabilities`).
144+
- **Remove redundancy** — avoid repeating what tool definitions already convey.
145+
146+
### Behaviors to Validate
147+
148+
Run the model through test scenarios and check these categories before adding customizations:
149+
150+
**1. Tool Usage Patterns**
151+
- Uses edit tools (`replace_string_in_file`, `apply_patch`, `insert_edit_into_file`) instead of code blocks
152+
- Uses code search tools (`read_file`, `semantic_search`, `grep_search`, `file_search`) to gather context
153+
- Uses terminal tool (`run_in_terminal`) instead of bash commands
154+
- Does NOT use terminal tools to create, edit, or update files — always uses dedicated edit tools
155+
- Uses planning tools (`manage_todo_list`) for complex tasks
156+
157+
**2. Response Format**
158+
- File paths and symbols linkified
159+
- Structured markdown with headers and sections
160+
- Concise, well-timed progress updates between tool calls
161+
162+
**3. Workflow Execution**
163+
- Gathers context before acting
164+
- Completes tasks end-to-end without pausing to check with user
165+
- Handles errors and iterates appropriately
166+
167+
### Common Model Misbehaviors and Fixes
168+
169+
Only add these if the model **consistently** fails the behavior. Target the specific issue with 1-2 sentences:
170+
171+
```tsx
172+
// Fix: Model shows code blocks instead of using edit tools
173+
{tools[ToolName.ReplaceStringInFile] && <>
174+
NEVER print out a code block with file changes unless the user asked for it.
175+
Use the appropriate edit tool (replace_string_in_file, apply_patch, or insert_into_file).
176+
</>}
177+
178+
// Fix: Model calls terminal tool in parallel
179+
{tools[ToolName.CoreRunInTerminal] && <>
180+
Don't call the run_in_terminal tool multiple times in parallel.
181+
Instead, run one command and wait for the output before running the next command.
182+
</>}
183+
184+
// Fix: Model doesn't use TODO tool for planning
185+
{tools[ToolName.CoreManageTodoList] && <>
186+
For complex multi-step tasks, use the manage_todo_list tool to track your progress
187+
and provide visibility to the user.
188+
</>}
189+
190+
// Fix: Model front-loads thinking and only summarizes at the end
191+
Provide brief progress updates every 3-5 tool calls to keep the user informed of your progress.<br />
192+
After completing parallel tool calls, provide a brief status update before proceeding to the next step.<br />
193+
```

extensions/copilot/chat-lib/package-lock.json

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/copilot/chat-lib/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"dependencies": {
1717
"@microsoft/tiktokenizer": "^1.0.10",
1818
"@sinclair/typebox": "^0.34.41",
19-
"@vscode/copilot-api": "^0.2.18",
19+
"@vscode/copilot-api": "^0.2.19",
2020
"@vscode/l10n": "^0.0.18",
2121
"@vscode/prompt-tsx": "^0.4.0-alpha.8",
2222
"@vscode/tree-sitter-wasm": "0.0.5-php.2",
@@ -31,7 +31,7 @@
3131
"yaml": "^2.8.0"
3232
},
3333
"devDependencies": {
34-
"@anthropic-ai/sdk": "^0.80.0",
34+
"@anthropic-ai/sdk": "^0.81.0",
3535
"@octokit/types": "^14.1.0",
3636
"@types/node": "^22.16.3",
3737
"@types/vscode": "^1.109.0",

0 commit comments

Comments
 (0)