|
| 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 | +``` |
0 commit comments