From bf7e1655dbc42c8eb478e9106c3ea6f44ba6bbee Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Wed, 12 Nov 2025 17:22:05 -0800 Subject: [PATCH] Prompt updates (#1968) * Prompt tweak * Prompt updates --- .../prompts/node/agent/agentPrompt.tsx | 8 ++-- .../node/agent/defaultAgentInstructions.tsx | 6 +-- .../prompts/node/agent/openAIPrompts.tsx | 42 +++++++++++++++-- .../endpoint/common/chatModelCapabilities.ts | 46 +++++++++++++++++-- 4 files changed, 87 insertions(+), 15 deletions(-) diff --git a/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx b/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx index 6cad7377f7c..aa112437661 100644 --- a/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx +++ b/extensions/copilot/src/extension/prompts/node/agent/agentPrompt.tsx @@ -7,7 +7,7 @@ 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 { isHiddenModelB, isVSCModelA, modelNeedsStrongReplaceStringHint } from '../../../../platform/endpoint/common/chatModelCapabilities'; +import { isHiddenModelB, isHiddenModelC, isHiddenModelD, isVSCModelA, modelNeedsStrongReplaceStringHint } from '../../../../platform/endpoint/common/chatModelCapabilities'; import { CacheType } from '../../../../platform/endpoint/common/endpointTypes'; import { IEnvService, OperatingSystem } from '../../../../platform/env/common/envService'; import { getGitHubRepoInfoFromContext, IGitService } from '../../../../platform/git/common/gitService'; @@ -91,7 +91,7 @@ export class AgentPrompt extends PromptElement { const baseAgentInstructions = <> You are an expert AI programming assistant, working with a user in the VS Code editor.
- {this.props.endpoint.family.startsWith('gpt-5') || await isHiddenModelB(this.props.endpoint) ? ( + {this.props.endpoint.family.startsWith('gpt-5') || await isHiddenModelB(this.props.endpoint) || await isHiddenModelC(this.props.endpoint) || await isHiddenModelD(this.props.endpoint) ? ( <> @@ -408,7 +408,7 @@ class ToolReferencesHint extends PromptElement { The user attached the following tools to this message. The userRequest may refer to them using the tool name with "#". These tools are likely relevant to the user's query:
{this.props.toolReferences.map(tool => `- ${tool.name}`).join('\n')}
- {(this.props.modelFamily?.startsWith('gpt-5') || await isHiddenModelB(this.props.modelFamily)) && <> + {(this.props.modelFamily?.startsWith('gpt-5') || await isHiddenModelB(this.props.modelFamily) || await isHiddenModelC(this.props.modelFamily) || await isHiddenModelD(this.props.modelFamily)) && <> Start by using the most relevant tool attached to this message—the user expects you to act with it first.
}
@@ -701,7 +701,7 @@ export class KeepGoingReminder extends PromptElement { } async render(state: void, sizing: PromptSizing) { - if (this.props.modelFamily === 'gpt-4.1' || this.props.modelFamily?.startsWith('gpt-5') || await isHiddenModelB(this.props.modelFamily)) { + if (this.props.modelFamily === 'gpt-4.1' || this.props.modelFamily?.startsWith('gpt-5') || await isHiddenModelB(this.props.modelFamily) || await isHiddenModelC(this.props.modelFamily) || await isHiddenModelD(this.props.modelFamily)) { if (this.configurationService.getExperimentBasedConfig(ConfigKey.EnableAlternateGptPrompt, this.experimentationService)) { // Extended reminder return <> diff --git a/extensions/copilot/src/extension/prompts/node/agent/defaultAgentInstructions.tsx b/extensions/copilot/src/extension/prompts/node/agent/defaultAgentInstructions.tsx index 44d3e05f732..9da71ee6c42 100644 --- a/extensions/copilot/src/extension/prompts/node/agent/defaultAgentInstructions.tsx +++ b/extensions/copilot/src/extension/prompts/node/agent/defaultAgentInstructions.tsx @@ -16,7 +16,7 @@ import { Tag } from '../base/tag'; import { CodeBlockFormattingRules, EXISTING_CODE_MARKER } from '../panel/codeBlockFormattingRules'; import { MathIntegrationRules } from '../panel/editorIntegrationRules'; import { KeepGoingReminder } from './agentPrompt'; -import { isHiddenModelB } from '../../../../platform/endpoint/common/chatModelCapabilities'; +import { isHiddenModelB, isHiddenModelC, isHiddenModelD } from '../../../../platform/endpoint/common/chatModelCapabilities'; // Types and interfaces for reusable components interface ToolCapabilities extends Partial> { @@ -402,11 +402,11 @@ export class ApplyPatchInstructions extends PromptElement To edit files in the workspace, use the {ToolName.ApplyPatch} tool. If you have issues with it, you should first try to fix your patch and continue using {ToolName.ApplyPatch}. {this.props.tools[ToolName.EditFile] && <>If you are stuck, you can fall back on the {ToolName.EditFile} tool, but {ToolName.ApplyPatch} is much faster and is the preferred tool.}
- {(isGpt5 || await isHiddenModelB(this.props.modelFamily)) && <>Prefer the smallest set of changes needed to satisfy the task. Avoid reformatting unrelated code; preserve existing style and public APIs unless the task requires changes. When practical, complete all edits for a file within a single message.
} + {(isGpt5 || await isHiddenModelB(this.props.modelFamily) || await isHiddenModelC(this.props.modelFamily) || await isHiddenModelD(this.props.modelFamily)) && <>Prefer the smallest set of changes needed to satisfy the task. Avoid reformatting unrelated code; preserve existing style and public APIs unless the task requires changes. When practical, complete all edits for a file within a single message.
} {!useSimpleInstructions && <> The input for this tool is a string representing the patch to apply, following a special format. For each snippet of code that needs to be changed, repeat the following:

diff --git a/extensions/copilot/src/extension/prompts/node/agent/openAIPrompts.tsx b/extensions/copilot/src/extension/prompts/node/agent/openAIPrompts.tsx index eb80676839f..beaf65444b9 100644 --- a/extensions/copilot/src/extension/prompts/node/agent/openAIPrompts.tsx +++ b/extensions/copilot/src/extension/prompts/node/agent/openAIPrompts.tsx @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { PromptElement, PromptSizing } from '@vscode/prompt-tsx'; -import { isHiddenModelB } from '../../../../platform/endpoint/common/chatModelCapabilities'; +import { isHiddenModelB, isHiddenModelC, isHiddenModelD } from '../../../../platform/endpoint/common/chatModelCapabilities'; import { IChatEndpoint } from '../../../../platform/networking/common/networking'; import { ToolName } from '../../../tools/common/toolNames'; import { InstructionMessage } from '../base/instructionMessage'; @@ -489,11 +489,21 @@ class ModelBPrompt extends PromptElement { {this.props.availableTools && } {tools[ToolName.ApplyPatch] && } - Your final message should read naturally, like an update from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user's style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.
+ Your final message should read naturally, like a report from a concise teammate. For casual conversation, brainstorming tasks, or quick questions from the user, respond in a friendly, conversational tone. You should ask questions, suggest ideas, and adapt to the user's style. If you've finished a large amount of work, when describing what you've done to the user, you should follow the final answer formatting guidelines to communicate substantive changes. You don't need to add structured formatting for one-word answers, greetings, or purely conversational exchanges.
You can skip heavy formatting for single, simple actions or confirmations. In these cases, respond in plain sentences with any relevant next step or quick option. Reserve multi-section structured responses for results that need grouping or explanation.
- The user is working on the same computer as you, and has access to your work. As such there's no need to show the full contents of large files you have already written or verbatim code snippets unless the user explicitly asks for them. Similarly, if you've created or modified files using `apply_patch`, there's no need to tell users to "save the file" or "copy the code into a file"—just reference the file path.
+ The user is working on the same computer as you, and has access to your work. As such there's NEVER a need to show the full contents of large files you have already written or verbatim code snippets unless the user explicitly asks for them. Similarly, if you've created or modified files using `apply_patch`, there's no need to tell users to "save the file" or "copy the code into a file"—just reference the file path.
If there's something that you think you could help with as a logical next step, concisely ask the user if they want you to do so. Good examples of this are running tests, committing changes, or building out the next logical component. If there's something that you couldn't do (even with approval) but that the user might want to do (such as verifying changes by running the app), include those instructions succinctly.
- Brevity is very important as a default. You should be very concise (i.e. no more than 10 lines or around 500 words), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding. Don't simply repeat all the changes you made- that is too much detail.
+ Brevity is very important as a default. You should be very concise (i.e. no more than 10 lines), but can relax this requirement for tasks where additional detail and comprehensiveness is important for the user's understanding. Don't simply repeat all the changes you made- that is too much detail.
+
+ ### Final answer compactness rules (enforced)
+
+ Overall it should focus on the high level and the most important main points, not low-level details.
+
+ - Tiny/small single-file change (≤ ~10 lines): 2-5 sentences or ≤3 bullets. No headings. 0-1 short snippet (≤3 lines) only if essential.
+ - Medium change (single area or a few files): ≤6 bullets or 6-10 sentences. At most 1-2 short snippets total (≤8 lines each).
+ - Large change: Summarize per file with 1-2 bullets; do not inline code unless critical (still ≤2 short snippets total).
+ - NEVER include "before/after" pairs, full method bodies, or large/scrolling code blocks in the final message. Prefer referencing file/symbol names instead.
+ - Do not include process/tooling narration (e.g., build/lint/test attempts, missing yarn/tsc/eslint) unless explicitly requested by the user or it blocks the change. If checks succeed silently, don't mention them.

### Final answer structure and style guidelines

@@ -664,3 +674,27 @@ class ModelBPromptResolver implements IAgentPrompt { PromptRegistry.registerPrompt(OpenAIPromptResolver); PromptRegistry.registerPrompt(ModelBPromptResolver); + +PromptRegistry.registerPrompt(class implements IAgentPrompt { + static async matchesModel(endpoint: IChatEndpoint): Promise { + return isHiddenModelC(endpoint); + } + + static readonly familyPrefixes = []; + + resolvePrompt(endpoint: IChatEndpoint): PromptConstructor | undefined { + return CodexStyleGPT5CodexPrompt; + } +}); + +PromptRegistry.registerPrompt(class implements IAgentPrompt { + static async matchesModel(endpoint: IChatEndpoint): Promise { + return isHiddenModelD(endpoint); + } + + static readonly familyPrefixes = []; + + resolvePrompt(endpoint: IChatEndpoint): PromptConstructor | undefined { + return DefaultGpt5AgentPrompt; + } +}); diff --git a/extensions/copilot/src/platform/endpoint/common/chatModelCapabilities.ts b/extensions/copilot/src/platform/endpoint/common/chatModelCapabilities.ts index 3629dc25e1a..3042ec2511c 100644 --- a/extensions/copilot/src/platform/endpoint/common/chatModelCapabilities.ts +++ b/extensions/copilot/src/platform/endpoint/common/chatModelCapabilities.ts @@ -30,7 +30,18 @@ const VSC_MODEL_HASHES_B = [ const familyToHash = new Map(); const HIDDEN_MODEL_B_HASHES = [ '8f398886c326b5f8f07b20ac250c87de6723e062474465273fe1524f2b9092fa', - '40903c59d19feef1d67c455499304c194ebdec82df78790c3ceaac92bd1d84be']; + '40903c59d19feef1d67c455499304c194ebdec82df78790c3ceaac92bd1d84be', + 'e7ee8b015b531feb8b6b0409f21aca9d5f0fba84db806c9d3ef671e2b36c55bf']; + +const HIDDEN_MODEL_C_HASHES = [ + '57bc0aad677492da7a00731e3e411055b9828c6439f502fa5abd8fddb7a8a260', + 'c5f9e7e93624823213aa93017d0d970ce3203d99dfcd616a0446f7bae2d8caf4' +]; + +const HIDDEN_MODEL_D_HASHES = [ + '27d93f5008711fce9cf5425234e81432d8eec95284beff9d5edc8daecc81bf76', + '312f75b4c11f3fec13b8722cba17a3cb3e355144bce27ebb8afdd9abe2779685' +]; function getModelId(model: LanguageModelChat | IChatEndpoint): string { return 'id' in model ? model.id : model.model; @@ -55,6 +66,33 @@ export async function isHiddenModelB(model: LanguageModelChat | IChatEndpoint | return false; } +export async function isHiddenModelC(model: LanguageModelChat | IChatEndpoint | string | undefined): Promise { + if (!model) { + return false; + } + + const family = typeof model === 'string' ? model : model.family; + const h = familyToHash.get(family) ?? await getCachedSha256Hash(family); + if (HIDDEN_MODEL_C_HASHES.includes(h)) { + familyToHash.set(family, h); + return true; + } + return false; +} + +export async function isHiddenModelD(model: LanguageModelChat | IChatEndpoint | string | undefined): Promise { + if (!model) { + return false; + } + + const family = typeof model === 'string' ? model : model.family; + const h = familyToHash.get(family) ?? await getCachedSha256Hash(family); + if (HIDDEN_MODEL_D_HASHES.includes(h)) { + familyToHash.set(family, h); + return true; + } + return false; +} export async function isVSCModelA(model: LanguageModelChat | IChatEndpoint) { const h = await getCachedSha256Hash(getModelId(model)); @@ -86,7 +124,7 @@ export function modelPrefersInstructionsAfterHistory(modelFamily: string) { * Model supports apply_patch as an edit tool. */ export async function modelSupportsApplyPatch(model: LanguageModelChat | IChatEndpoint): Promise { - return (model.family.includes('gpt') && !model.family.includes('gpt-4o')) || model.family === 'o4-mini' || await isHiddenModelA(model) || await isHiddenModelB(model); + return (model.family.includes('gpt') && !model.family.includes('gpt-4o')) || model.family === 'o4-mini' || await isHiddenModelA(model) || await isHiddenModelB(model) || await isHiddenModelC(model) || await isHiddenModelD(model); } /** @@ -145,7 +183,7 @@ export function modelCanUseImageURL(model: LanguageModelChat | IChatEndpoint): b * without needing insert_edit_into_file. */ export async function modelCanUseApplyPatchExclusively(model: LanguageModelChat | IChatEndpoint): Promise { - return model.family.startsWith('gpt-5') || await isHiddenModelB(model); + return model.family.startsWith('gpt-5') || await isHiddenModelB(model) || await isHiddenModelC(model) || await isHiddenModelD(model); } /** @@ -161,7 +199,7 @@ export function modelNeedsStrongReplaceStringHint(model: LanguageModelChat | ICh * Model can take the simple, modern apply_patch instructions. */ export async function modelSupportsSimplifiedApplyPatchInstructions(model: LanguageModelChat | IChatEndpoint): Promise { - return model.family.startsWith('gpt-5') || await isHiddenModelB(model); + return model.family.startsWith('gpt-5') || await isHiddenModelB(model) || await isHiddenModelC(model) || await isHiddenModelD(model); } /**