Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/notebooks/endgame.github-issues
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$MILESTONE=milestone:\"1.134.0\"\n\n$TPI_CREATION=2026-03-23 // Used to find fixes that need to be verified"
"value": "$MILESTONE=milestone:\"1.135.0\"\n\n$TPI_CREATION=2026-03-23 // Used to find fixes that need to be verified"
},
{
"kind": 1,
Expand Down
2 changes: 1 addition & 1 deletion .vscode/notebooks/my-endgame.github-issues
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$MILESTONE=milestone:\"1.134.0\"\n\n$MINE=assignee:@me"
"value": "$MILESTONE=milestone:\"1.135.0\"\n\n$MINE=assignee:@me"
},
{
"kind": 2,
Expand Down
6 changes: 3 additions & 3 deletions extensions/copilot/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions extensions/copilot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "copilot-chat",
"displayName": "GitHub Copilot",
"description": "AI chat features powered by Copilot",
"version": "0.63.0",
"version": "0.64.0",
"build": "1",
"completionsCoreVersion": "1.378.1799",
"internalLargeStorageAriaKey": "ec712b3202c5462fb6877acae7f1f9d7-c19ad55e-3e3c-4f99-984b-827f6d95bd9e-6917",
Expand All @@ -22,7 +22,7 @@
"icon": "assets/copilot.png",
"pricing": "Trial",
"engines": {
"vscode": "^1.135.0",
"vscode": "^1.136.0",
"npm": ">=9.0.0",
"node": ">=22.14.0"
},
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "code-oss-dev",
"version": "1.135.0",
"version": "1.136.0",
"distro": "c842171bd42ca4aef20b0a186c94d99edd763842",
"author": {
"name": "Microsoft Corporation"
Expand Down
2 changes: 1 addition & 1 deletion src/vs/editor/contrib/snippet/browser/snippet.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ variable ::= '$' var | '${' var }'
| '${' var transform '}'
transform ::= '/' regex '/' (format | text)+ '/' options
format ::= '$' int | '${' int '}'
| '${' int ':' '/upcase' | '/downcase' | '/capitalize' | '/camelcase' | '/pascalcase' | '/kebabcase' | '/snakecase' '}'
| '${' int ':' ('/upcase' | '/downcase' | '/capitalize' | '/camelcase' | '/pascalcase' | '/kebabcase' | '/snakecase') '}'
| '${' int ':+' if '}'
| '${' int ':?' if ':' else '}'
| '${' int ':-' else '}' | '${' int ':' else '}'
Expand Down
14 changes: 12 additions & 2 deletions src/vs/platform/agentHost/common/copilotCliConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,16 @@ export const enum CopilotCliConfigKey {
ReasoningSummary = 'reasoningSummary',
/** Let the Auto router score prior turns instead of the latest message alone. Off by default. */
MultiTurnContextRouting = 'multiTurnContextRouting',
/** Tell the model to keep subagents on their default model unless the user asks otherwise. Off by default. */
SubagentModelGuidance = 'subagentModelGuidance',
/** Per-model capability overrides (family aliases) keyed by model id. */
ModelCapabilityOverrides = 'modelCapabilityOverrides',
}

export const CopilotCliVSCodeAssignmentContextKey = 'copilotCliVSCodeAssignmentContext';

// VS Code `chat.agentHost.*` setting IDs that feed the root-config keys above,
// kept beside the keys they forward to. Registered in `chat.shared.contribution.ts`
// VS Code `chat.agentHost.*` / `chat.copilot.*` setting IDs that feed the root-config
// keys above, kept beside the keys they forward to. Registered in `chat.shared.contribution.ts`
// and forwarded into the host's root config by `AgentHostCopilotCliSettingsContribution`
// (and, for the terminal-tool toggle, `AgentHostTerminalContribution`).

Expand All @@ -59,6 +61,8 @@ export const AgentHostReasoningSummaryEnabledSettingId = 'chat.agentHost.copilot

export const AgentHostMultiTurnContextRoutingEnabledSettingId = 'chat.agentHost.copilot.multiTurnContextRouting.enabled';

export const CopilotSubagentModelGuidanceEnabledSettingId = 'chat.copilot.subagentModelGuidance.enabled';

export const AgentHostModelCapabilityOverridesSettingId = 'chat.agentHost.modelCapabilityOverrides';
export const AgentHostCopilotModelCapabilityOverridesSettingId = 'chat.agentHost.copilot.modelCapabilityOverrides';

Expand Down Expand Up @@ -174,6 +178,12 @@ export const copilotCliConfigSchema = createSchema({
description: localize('agentHost.config.multiTurnContextRouting.description', "When enabled, Auto model selection sends prior user messages to the router so it scores the conversation so far instead of the latest message alone."),
default: false,
}),
[CopilotCliConfigKey.SubagentModelGuidance]: schemaProperty<boolean>({
type: 'boolean',
title: localize('agentHost.config.subagentModelGuidance.title', "Subagent Model Guidance"),
description: localize('agentHost.config.subagentModelGuidance.description', "When enabled, Copilot SDK sessions instruct the model to keep subagents on their default model unless the user explicitly names another one."),
default: false,
}),
[CopilotCliConfigKey.ModelCapabilityOverrides]: schemaProperty<CopilotCliModelCapabilityOverrides>({
type: 'object',
title: localize('agentHost.config.modelCapabilityOverrides.title', "Model Capability Overrides"),
Expand Down
5 changes: 3 additions & 2 deletions src/vs/platform/agentHost/node/agentHostChangesetService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -845,13 +845,14 @@ export class AgentHostChangesetService extends Disposable implements IAgentHostC
* diff, or an error), that repository falls back to its tracked edits so
* one repo's git failure never drops the folder — mirroring the
* single-folder path's edit-tracker fallback. `usedFallback` reports whether
* that fallback was taken. Every git failure is logged as an error.
* that fallback was taken. Missing checkpoints are expected for older turns;
* actual git failures are logged as errors.
*/
private async _computeRepoTurnDiffs(session: ProtocolURI, trackedSession: ProtocolURI, sessionUri: URI, db: ISessionDatabase, turnId: string, repoRoot: URI): Promise<{ readonly diffs: readonly ISessionFileDiff[]; readonly usedFallback: boolean }> {
try {
const pair = await this._checkpointService.getTurnCheckpointPair(sessionUri, turnId, repoRoot);
if (!pair) {
this._logService.error(`[AgentHostChangesetService] No checkpoint pair for multi-folder turn ${session}/${turnId} in repository ${repoRoot.toString()}; falling back to tracked edits for that repository.`);
this._logService.trace(`[AgentHostChangesetService] No checkpoint pair for multi-folder turn ${session}/${turnId} in repository ${repoRoot.toString()}; falling back to tracked edits for that repository.`);
return { diffs: await this._computeRepoTurnDiffsFromTrackedEdits(session, trackedSession, db, turnId, repoRoot), usedFallback: true };
}
if (pair.parent === pair.current) {
Expand Down
17 changes: 10 additions & 7 deletions src/vs/platform/agentHost/node/copilot/prompts/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ data the SDK accepts directly.
shared identity text, the `fullSystemPrompt` / `sectionOverrides` builders, and
`describeSystemMessageConfig` (the one-line log summary).
- `toolInstructions.ts` — the model-agnostic `tool_instructions` layer: gated
or unconditional one-line nudges (`TOOL_INSTRUCTION_LINES`) composed into the
SDK's `tool_instructions` section.
or unconditional nudges (`TOOL_INSTRUCTION_LINES`) composed into the SDK's
`tool_instructions` section, including the setting-gated default-model
guidance for subagents (`chat.copilot.subagentModelGuidance.enabled`).
- `anthropicPrompt.ts` — example per-model contributor (Claude Opus 4.8).
- `allPrompts.ts` — side-effect import hub; importing it registers every
contributor into the shared `agentHostPromptRegistry`.
Expand Down Expand Up @@ -53,16 +54,18 @@ There are two ways to customize, and a model can use both at once.
## Lever 1 — universal, all models (`toolInstructions.ts`)

Guidance that should apply to **every** model. A line can be unconditional for
host-wide behavior such as reading offloaded tool output, or gated on a client
tool as the browser line is.
host-wide behavior such as reading offloaded tool output, gated on a client
tool as the browser line is, or gated on a host setting as the subagent
model-guidance line is.

1. Write a `ToolInstructionLine` — a function `(hasTool) => string | undefined`
1. Write a `ToolInstructionLine` — a function `(context) => string | undefined`
that returns one sentence (no surrounding newlines), or `undefined` when its
gate does not apply.
gate does not apply. The `IToolInstructionContext` exposes `hasTool(name)`
and `getSetting(key)` (a `CopilotCliConfigKey`).
2. Add it to `TOOL_INSTRUCTION_LINES`.

```ts
const exampleToolInstructions: ToolInstructionLine = hasTool =>
const exampleToolInstructions: ToolInstructionLine = ({ hasTool }) =>
hasTool('someClientToolReferenceName')
? 'One sentence of guidance, shown only when that tool is present.'
: undefined;
Expand Down
10 changes: 7 additions & 3 deletions src/vs/platform/agentHost/node/copilot/prompts/promptRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { copilotCliConfigSchema } from '../../../common/copilotCliConfig.js';
import type { SchemaValue } from '../../../common/agentHostSchema.js';
import type { ModelSelection } from '../../../common/state/protocol/state.js';
import { appendSystemMessageContent, COPILOT_AGENT_HOST_FILE_LINK_INSTRUCTIONS, COPILOT_AGENT_HOST_WORKSPACELESS_INSTRUCTIONS, COPILOT_AGENT_HOST_SYSTEM_MESSAGE, fullSystemPrompt, sectionOverrides, withDefaultSections } from './systemMessage.js';
import { resolveToolInstructionsOverride, toolSearchInstructionLines, universalToolInstructions } from './toolInstructions.js';
import { resolveToolInstructionsOverride, toolSearchInstructionLines, universalToolInstructions, type IToolInstructionContext } from './toolInstructions.js';

type CopilotCliConfigDefinition = typeof copilotCliConfigSchema.definition;

Expand Down Expand Up @@ -196,14 +196,18 @@ export class AgentHostPromptRegistry {
* so they are appended after its content instead of being silently lost.
*/
private _withUniversalSections(config: SystemMessageConfig, context: IAgentHostPromptContext): SystemMessageConfig {
const lineContext: IToolInstructionContext = {
hasTool: name => context.hasClientTool(name),
getSetting: key => context.getSetting(key),
};
if (config.mode === 'replace') {
const lines = universalToolInstructions(name => context.hasClientTool(name), toolSearchInstructionLines(context.toolSearchActive));
const lines = universalToolInstructions(lineContext, toolSearchInstructionLines(context.toolSearchActive));
return lines ? appendSystemMessageContent(config, lines) : config;
}
if (config.mode !== 'customize') {
return config;
}
const toolInstructions = resolveToolInstructionsOverride(name => context.hasClientTool(name), config.sections?.tool_instructions, toolSearchInstructionLines(context.toolSearchActive));
const toolInstructions = resolveToolInstructionsOverride(lineContext, config.sections?.tool_instructions, toolSearchInstructionLines(context.toolSearchActive));
if (!toolInstructions) {
return config;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { SectionOverride, SystemMessageConfig, SystemMessageSection } from
* inherit it via {@link withDefaultSections}, so it is defined in one place and
* only a contributor that names `identity` replaces it.
*/
export const COPILOT_AGENT_HOST_IDENTITY = 'You are an AI assistant using Copilot CLI runtime in VS Code. You help users with software engineering tasks. When asked about your identity, you must state that you are an AI assistant using Copilot CLI runtime in VS Code.';
export const COPILOT_AGENT_HOST_IDENTITY = 'You are an AI assistant using Copilot SDK in VS Code. You help users with software engineering tasks. When asked about your identity, you must state that you are an AI assistant using Copilot SDK in VS Code.';

/** Response-formatting contract for workspace links emitted by Agent Host models. */
export const COPILOT_AGENT_HOST_FILE_LINK_INSTRUCTIONS = [
Expand Down
55 changes: 40 additions & 15 deletions src/vs/platform/agentHost/node/copilot/prompts/toolInstructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import type { SectionOverride } from '@github/copilot-sdk';
import { coalesce } from '../../../../../base/common/arrays.js';
import { BrowserChatToolReferenceName, browserChatToolReferenceNames } from '../../../../browserView/common/browserChatToolReferenceNames.js';
import type { SchemaValue } from '../../../common/agentHostSchema.js';
import { CopilotCliConfigKey, copilotCliConfigSchema } from '../../../common/copilotCliConfig.js';
import { CLIENT_TOOL_SEARCH_REFERENCE_NAME } from '../../../common/toolSearchConstants.js';

/**
Expand All @@ -14,25 +16,39 @@ import { CLIENT_TOOL_SEARCH_REFERENCE_NAME } from '../../../common/toolSearchCon
* This is the agent-host home for the Copilot extension's `toolUseInstructions`
* pattern (`defaultAgentInstructions.tsx` and the per-model agent prompts): a
* sequence of one-line nudges, either unconditional or gated on the relevant
* tool being present in the session, composed into the single SDK
* `tool_instructions` section. The agent host sees client tools under their
* camelCase `toolReferenceName`, so a line's gate and any tool name it mentions
* use that form (NOT the extension's snake_case ids).
* tool being present in the session (or on a host setting), composed into the
* single SDK `tool_instructions` section. The agent host sees client tools under
* their camelCase `toolReferenceName`, so a line's gate and any tool name it
* mentions use that form (NOT the extension's snake_case ids).
*
* To add guidance, write a {@link ToolInstructionLine} and add it to
* {@link TOOL_INSTRUCTION_LINES}. The browser guidance
* ({@link browserToolInstructions}) demonstrates a line gated on
* `openBrowserPage` plus an agentic browser tool.
* `openBrowserPage` plus an agentic browser tool; the subagent guidance
* ({@link subagentToolInstructions}) one gated on a setting.
*/

type CopilotCliConfigDefinition = typeof copilotCliConfigSchema.definition;

/**
* What a {@link ToolInstructionLine} may gate on: the session's client tools and
* the host-level Copilot CLI settings. The registry derives it from the wider
* `IAgentHostPromptContext`.
*/
export interface IToolInstructionContext {
/** Whether a client tool is available in the session, by camelCase `toolReferenceName`. */
hasTool(name: string): boolean;

/** The host-level value for a Copilot CLI setting, or `undefined` when unset. */
getSetting<K extends keyof CopilotCliConfigDefinition & string>(key: K): SchemaValue<CopilotCliConfigDefinition[K]> | undefined;
}

/**
* A single tool-instructions line. Returns its content (a single sentence, no
* surrounding newlines) when it applies, or `undefined` to contribute nothing.
* Mirrors one `<>…</>` fragment in the extension's `toolUseInstructions` block.
*
* @param hasTool predicate for whether a tool name is available in the session.
*/
type ToolInstructionLine = (hasTool: (name: string) => boolean) => string | undefined;
type ToolInstructionLine = (context: IToolInstructionContext) => string | undefined;

/**
* Browser tools other than `openBrowserPage` — the agent-host equivalent of the
Expand All @@ -45,13 +61,22 @@ const agenticBrowserToolNames = browserChatToolReferenceNames.filter(name => nam
export const COPILOT_AGENT_HOST_LARGE_OUTPUT_TOOL_INSTRUCTION = 'When a tool reports that its output was saved to a temporary file because it was too large, ONLY use the `view` tool with a narrow `view_range` to inspect that file. NEVER read it with shell commands such as `cat`, `head`, `tail`, or `sed`, because their output may be offloaded again.';
const largeOutputToolInstructions: ToolInstructionLine = () => COPILOT_AGENT_HOST_LARGE_OUTPUT_TOOL_INSTRUCTION;

/** Keeps subagents on their default model unless the user explicitly requests another model. */
export const COPILOT_AGENT_HOST_SUBAGENT_TOOL_INSTRUCTIONS = [
'When launching subagents with the task tool, leave the `model`, `reasoning_effort`, and `context_tier` parameters unset — each agent type already runs on a model suited to it, and overriding the model changes the session\'s cost and behavior profile.',
'Only set the task tool\'s `model` parameter when the user explicitly names the model the subagent should run on.',
].join('\n');
/** Opt-in via {@link CopilotCliConfigKey.SubagentModelGuidance}. */
const subagentToolInstructions: ToolInstructionLine = ({ getSetting }) =>
getSetting(CopilotCliConfigKey.SubagentModelGuidance) === true ? COPILOT_AGENT_HOST_SUBAGENT_TOOL_INSTRUCTIONS : undefined;

/**
* Front-end guidance for the integrated browser tools, ported from the Copilot
* extension's `defaultAgentInstructions`/per-model prompts. Emitted only when the
* page-opening tool AND at least one agentic browser tool are available, naming
* the first available agentic tool as the example (the rest are covered by "etc.").
*/
const browserToolInstructions: ToolInstructionLine = hasTool => {
const browserToolInstructions: ToolInstructionLine = ({ hasTool }) => {
if (!hasTool(BrowserChatToolReferenceName.OpenBrowserPage)) {
return undefined;
}
Expand All @@ -65,10 +90,10 @@ const browserToolInstructions: ToolInstructionLine = hasTool => {
/**
* The registered tool-instruction lines, in render order.
*/
const TOOL_INSTRUCTION_LINES: readonly ToolInstructionLine[] = [largeOutputToolInstructions, browserToolInstructions];
const TOOL_INSTRUCTION_LINES: readonly ToolInstructionLine[] = [largeOutputToolInstructions, subagentToolInstructions, browserToolInstructions];

/** Tool-search guidance mirrored from the Copilot extension prompt. */
const toolSearchToolInstructions: ToolInstructionLine = hasTool =>
const toolSearchToolInstructions: ToolInstructionLine = ({ hasTool }) =>
hasTool(CLIENT_TOOL_SEARCH_REFERENCE_NAME)
? `Most tools are deferred and hidden until you search for them. Before calling a tool that has not already been loaded, ALWAYS use tool search first with a short description of the capability you need, then call the specific tool it returns; tools it returns are immediately available and must not be searched for again.`
: undefined;
Expand All @@ -84,8 +109,8 @@ export function toolSearchInstructionLines(toolSearchActive: boolean): readonly
* @param lines defaults to the registered {@link TOOL_INSTRUCTION_LINES};
* overridable so the composition can be exercised in isolation.
*/
export function universalToolInstructions(hasTool: (name: string) => boolean, lines: readonly ToolInstructionLine[] = TOOL_INSTRUCTION_LINES): string | undefined {
const rendered = coalesce(lines.map(line => line(hasTool)));
export function universalToolInstructions(context: IToolInstructionContext, lines: readonly ToolInstructionLine[] = TOOL_INSTRUCTION_LINES): string | undefined {
const rendered = coalesce(lines.map(line => line(context)));
return rendered.length > 0 ? rendered.join('\n') : undefined;
}

Expand Down Expand Up @@ -132,7 +157,7 @@ function composeToolInstructions(existing: SectionOverride | undefined, content:
* @param existing the per-model contributor's `tool_instructions` override, if any.
* @param lines defaults to the registered {@link TOOL_INSTRUCTION_LINES}.
*/
export function resolveToolInstructionsOverride(hasTool: (name: string) => boolean, existing: SectionOverride | undefined, lines: readonly ToolInstructionLine[] = TOOL_INSTRUCTION_LINES): SectionOverride | undefined {
const content = universalToolInstructions(hasTool, lines);
export function resolveToolInstructionsOverride(context: IToolInstructionContext, existing: SectionOverride | undefined, lines: readonly ToolInstructionLine[] = TOOL_INSTRUCTION_LINES): SectionOverride | undefined {
const content = universalToolInstructions(context, lines);
return content === undefined ? undefined : composeToolInstructions(existing, content);
}
Loading
Loading