mirror of
https://github.com/microsoft/vscode.git
synced 2026-06-01 04:26:50 -05:00
Don't emit empty <customizationsUpdate> on terminal steering turns (#318128)
Don't emit empty <customizationsUpdate> on steering turns Fixes #317763 Terminal steering requests sent from runInTerminalTool.ts don't forward an instructionContext, so chatServiceImpl short-circuits collectInstructions() to [] and the vscode.customizations.index variable is absent for those turns. The old freeze/drift consumer in agentPrompt.tsx treated that absence as 'all customizations removed' via 'effectiveCurrent = currentValue ?? ''', emitting an empty <customizationsUpdate> block whose own text says it 'supersedes the system prompt' — falsely telling the model that all skills/instructions/agents had been wiped mid-task and churning the cache tail. Gate drift emission on 'currentValue !== undefined' so an absent variable preserves the frozen system-prompt listing instead of falsely signalling removal. Also graduates the experimental 'github.copilot.chat.freezeCustomizationsIndex' setting (it was already default true on onExp).
This commit is contained in:
@@ -4294,16 +4294,6 @@
|
||||
"advanced"
|
||||
]
|
||||
},
|
||||
"github.copilot.chat.freezeCustomizationsIndex": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"tags": [
|
||||
"advanced",
|
||||
"experimental",
|
||||
"onExp"
|
||||
],
|
||||
"description": "%github.copilot.config.freezeCustomizationsIndex%"
|
||||
},
|
||||
"github.copilot.chat.installExtensionSkill.enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
@@ -340,7 +340,6 @@
|
||||
"github.copilot.config.anthropic.promptCaching.extendedTtl": "Use the extended (1 hour) prompt cache TTL on tools and system blocks for the Anthropic Messages API. Applied to Claude Opus 4.5/4.6/4.7 and Sonnet 4.5/4.6 variants; other models keep the default 5 minute TTL even when this setting is enabled.\n\n**Note**: This is an experimental feature. Only the main agent conversation is eligible — inline chat, terminal chat, notebook chat, and subagent requests are excluded.",
|
||||
"github.copilot.config.anthropic.promptCaching.extendedTtlMessages": "Also extend the 1 hour prompt cache TTL to message-level breakpoints. Requires `chat.anthropic.promptCaching.extendedTtl` to be enabled; has no effect on its own.\n\n**Note**: This is an experimental feature.",
|
||||
"github.copilot.config.modelCapabilityOverrides": "Per-model capability overrides keyed by model id, intended for evaluating preview and tenanted models against an existing model's capability profile. For each model id, declare an aliased `family`. Setting `family` to a known production family (e.g. `\"claude-opus-4.7\"`) makes the model receive that family's full capability profile — Anthropic family detection, latest Opus prompt, multi-replace tools, tool search, context editing, extended cache TTL — without a code change.\n\n**Note**: This is an advanced setting for evaluation use; it is not intended for regular end-user configuration.",
|
||||
"github.copilot.config.freezeCustomizationsIndex": "Freeze the bundled `<instructions>`, `<skills>`, and `<agents>` listing in the system prompt at the first turn of a conversation and reuse it on every subsequent turn. Prevents per-turn churn (e.g. the active mode swapping which subagent entry is listed, or async experimentation flipping a skill in or out) from invalidating the prompt cache. When the listing changes mid-conversation, the updated set is appended to the latest user message so the model still sees instructions, skills, or agents that became available or were removed.\n\n**Note**: This is an experimental feature.",
|
||||
"github.copilot.config.useResponsesApi": "Use the Responses API instead of the Chat Completions API when supported. Enables reasoning and reasoning summaries.\n\n**Note**: This is an experimental feature that is not yet activated for all users.\n\n**Important**: For Custom Endpoint models, the API type is independent of this setting and is determined per-model via the `apiType` property, or inferred from the `url` path when omitted.",
|
||||
"github.copilot.config.responsesApiReasoningSummary": "Sets the reasoning summary style used for the Responses API. Requires `#github.copilot.chat.useResponsesApi#`.",
|
||||
"github.copilot.config.responsesApiContextManagement.enabled": "Enables context management for the Responses API. Requires `#github.copilot.chat.useResponsesApi#`.",
|
||||
|
||||
@@ -230,8 +230,7 @@ export class AgentPrompt extends PromptElement<AgentPromptProps> {
|
||||
}
|
||||
|
||||
/**
|
||||
* When the experimental `FreezeCustomizationsIndex` setting is enabled,
|
||||
* snapshot the customizations-index variable on the first turn of the
|
||||
* Snapshot the customizations-index variable on the first turn of the
|
||||
* conversation and reuse it for every subsequent turn. Stops per-turn
|
||||
* churn in the bundled `<instructions>`/`<skills>`/`<agents>` text (e.g.
|
||||
* the active mode swapping which subagent entry is listed in `<agents>`)
|
||||
@@ -239,27 +238,23 @@ export class AgentPrompt extends PromptElement<AgentPromptProps> {
|
||||
*
|
||||
* Returns:
|
||||
* - `frozen`: the value (and matching tool-reference offsets) to substitute
|
||||
* in the system prompt. Always present when the setting is enabled and a
|
||||
* variable is available.
|
||||
* in the system prompt. Always present once a variable is available.
|
||||
* - `drift`: the live current-turn value (and offsets) when it differs from
|
||||
* `frozen`. Rendered in the latest user message so the model sees the
|
||||
* up-to-date listing without busting the system prompt cache. Also
|
||||
* emitted as an empty value when the live variable disappears, so the
|
||||
* model gets a signal that previously listed entries are no longer
|
||||
* available.
|
||||
* up-to-date listing without busting the system prompt cache. Only
|
||||
* surfaced when the variable was present this turn; an absent variable
|
||||
* (e.g. on a request path without `instructionContext` such as terminal
|
||||
* steering, or when collection ran but produced no listings) leaves the
|
||||
* frozen system-prompt listing standing rather than emitting an empty
|
||||
* update that would falsely signal removal.
|
||||
*
|
||||
* Returns `undefined` overall if no override should apply (setting off,
|
||||
* no first turn available, or no snapshot yet and the variable is absent
|
||||
* on this turn).
|
||||
* Returns `undefined` overall if no override should apply (no first turn
|
||||
* available, or no snapshot yet and the variable is absent on this turn).
|
||||
*/
|
||||
private getOrFreezeCustomizationsIndex(): {
|
||||
frozen: { value: string; toolReferences: readonly ChatLanguageModelToolReference[] | undefined };
|
||||
drift?: { value: string; toolReferences: readonly ChatLanguageModelToolReference[] | undefined };
|
||||
} | undefined {
|
||||
const enabled = this.configurationService.getExperimentBasedConfig(ConfigKey.Advanced.FreezeCustomizationsIndex, this.experimentationService);
|
||||
if (!enabled) {
|
||||
return undefined;
|
||||
}
|
||||
const firstTurn = this.props.promptContext.conversation?.turns.at(0);
|
||||
if (!firstTurn) {
|
||||
return undefined;
|
||||
@@ -272,14 +267,17 @@ export class AgentPrompt extends PromptElement<AgentPromptProps> {
|
||||
const existing = firstTurn.getMetadata(CustomizationsIndexMetadata);
|
||||
if (existing && existing.cacheKey === currentCacheKey) {
|
||||
const frozen = { value: existing.value, toolReferences: existing.toolReferences };
|
||||
// Surface drift in either direction: a different live value, or the
|
||||
// live variable disappearing entirely (treated as an empty listing).
|
||||
// Without the second case the model is left looking at the stale
|
||||
// frozen `<instructions>`/`<skills>`/`<agents>` block with no signal
|
||||
// that entries have been removed.
|
||||
const effectiveCurrent = currentValue ?? '';
|
||||
if (effectiveCurrent !== existing.value) {
|
||||
return { frozen, drift: { value: effectiveCurrent, toolReferences: currentToolReferences } };
|
||||
// Only surface drift when the variable was present this turn AND
|
||||
// differs from the snapshot. An absent variable can mean either
|
||||
// "collection didn't run" (e.g. terminal steering requests omit
|
||||
// `instructionContext`) or "collection ran but produced no listings".
|
||||
// In either case we keep the frozen system-prompt listing standing
|
||||
// rather than emit an empty `<customizationsUpdate>` block, which
|
||||
// would falsely tell the model that all customizations were removed
|
||||
// (its rendered text says it "supersedes" the system prompt) and
|
||||
// would needlessly churn the cache tail.
|
||||
if (currentValue !== undefined && currentValue !== existing.value) {
|
||||
return { frozen, drift: { value: currentValue, toolReferences: currentToolReferences } };
|
||||
}
|
||||
return { frozen };
|
||||
}
|
||||
@@ -404,8 +402,7 @@ export interface AgentUserMessageProps extends BasePromptElementProps, AgentUser
|
||||
* store just the drift block and historical replays on later turns would
|
||||
* lose the actual user query, busting cross-turn cache continuity.
|
||||
*
|
||||
* Only set when the experimental `FreezeCustomizationsIndex` setting is
|
||||
* enabled and the current value differs from the snapshot captured on
|
||||
* Only set when the current value differs from the snapshot captured on
|
||||
* the first turn.
|
||||
*/
|
||||
readonly customizationsIndexUpdate?: { value: string; toolReferences: readonly ChatLanguageModelToolReference[] | undefined };
|
||||
@@ -638,8 +635,8 @@ interface CustomizationsIndexUpdateProps extends BasePromptElementProps {
|
||||
* the drift block and historical replays on later turns would lose the
|
||||
* actual user query.
|
||||
*
|
||||
* Used only when `FreezeCustomizationsIndex` is on and the live index
|
||||
* differs from the snapshot captured on the first turn.
|
||||
* Used only when the live index differs from the snapshot captured on the
|
||||
* first turn.
|
||||
*/
|
||||
class CustomizationsIndexUpdate extends PromptElement<CustomizationsIndexUpdateProps> {
|
||||
constructor(
|
||||
|
||||
@@ -742,9 +742,6 @@ export namespace ConfigKey {
|
||||
/** Per-model capability overrides. Keys are model ids, values declare an aliased `family`. Lets evals route an unknown preview model id to a known production family (e.g. `"claude-opus-4.7"`) so the Anthropic prompt resolver, multi-replace tools, tool search, context editing, etc. all activate without a code change. */
|
||||
export const ModelCapabilityOverrides = defineSetting<Record<string, IModelCapabilityOverride>>('chat.modelCapabilityOverrides', ConfigType.Simple, {});
|
||||
|
||||
/** Freeze the customizations-index variable (the `<instructions>`/`<skills>`/`<agents>` block) at the first turn of a conversation and reuse it on subsequent turns. Prevents the system prompt cache from being invalidated by per-turn churn — e.g. the active mode swapping which subagent entry appears in `<agents>`, or async experimentation flipping a `when`-gated skill. */
|
||||
export const FreezeCustomizationsIndex = defineSetting<boolean>('chat.freezeCustomizationsIndex', ConfigType.ExperimentBased, true);
|
||||
|
||||
export const InlineEditsXtabProviderModelConfiguration = (() => {
|
||||
const oldKey = 'chat.advanced.inlineEdits.xtabProvider.modelConfiguration';
|
||||
const newKey = 'chat.inlineEdits.xtabProvider.modelConfiguration';
|
||||
|
||||
Reference in New Issue
Block a user