Skip to content

Commit 74d615d

Browse files
authored
Enable auto V2 in SDK (#331702)
1 parent 88d8741 commit 74d615d

9 files changed

Lines changed: 90 additions & 8 deletions

File tree

src/vs/platform/agentHost/common/copilotCliConfig.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export const enum CopilotCliConfigKey {
3030
ReasoningEffortOverride = 'reasoningEffortOverride',
3131
/** Enable concise reasoning summaries for supported models. Off by default. */
3232
ReasoningSummary = 'reasoningSummary',
33+
/** Let the Auto router score prior turns instead of the latest message alone. Off by default. */
34+
MultiTurnContextRouting = 'multiTurnContextRouting',
3335
/** Per-model capability overrides (family aliases) keyed by model id. */
3436
ModelCapabilityOverrides = 'modelCapabilityOverrides',
3537
}
@@ -55,6 +57,8 @@ export const AgentHostReasoningEffortOverrideSettingId = 'chat.agentHost.copilot
5557

5658
export const AgentHostReasoningSummaryEnabledSettingId = 'chat.agentHost.copilot.reasoningSummary.enabled';
5759

60+
export const AgentHostMultiTurnContextRoutingEnabledSettingId = 'chat.agentHost.copilot.multiTurnContextRouting.enabled';
61+
5862
export const AgentHostModelCapabilityOverridesSettingId = 'chat.agentHost.modelCapabilityOverrides';
5963
export const AgentHostCopilotModelCapabilityOverridesSettingId = 'chat.agentHost.copilot.modelCapabilityOverrides';
6064

@@ -164,6 +168,12 @@ export const copilotCliConfigSchema = createSchema({
164168
description: localize('agentHost.config.reasoningSummary.description', "When enabled, requests concise reasoning summaries for supported Copilot SDK sessions."),
165169
default: false,
166170
}),
171+
[CopilotCliConfigKey.MultiTurnContextRouting]: schemaProperty<boolean>({
172+
type: 'boolean',
173+
title: localize('agentHost.config.multiTurnContextRouting.title', "Auto Multi-Turn Context Routing"),
174+
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."),
175+
default: false,
176+
}),
167177
[CopilotCliConfigKey.ModelCapabilityOverrides]: schemaProperty<CopilotCliModelCapabilityOverrides>({
168178
type: 'object',
169179
title: localize('agentHost.config.modelCapabilityOverrides.title', "Model Capability Overrides"),

src/vs/platform/agentHost/node/copilot/copilotAgent.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,10 @@ export class CopilotAgent extends Disposable implements IAgent {
973973
return this._configurationService.getRootValue(copilotCliConfigSchema, CopilotCliConfigKey.RubberDuck) ?? DEFAULT_COPILOT_RUBBER_DUCK_ENABLED;
974974
}
975975

976+
private _isMultiTurnContextRoutingEnabled(): boolean {
977+
return this._configurationService.getRootValue(copilotCliConfigSchema, CopilotCliConfigKey.MultiTurnContextRouting) === true;
978+
}
979+
976980
private _getCopilotSdkLogLevelSetting(): CopilotSdkLogLevelSetting {
977981
return this._configurationService.getRootValue(copilotCliConfigSchema, CopilotCliConfigKey.CopilotSdkLogLevel) ?? 'info';
978982
}
@@ -1001,6 +1005,7 @@ export class CopilotAgent extends Disposable implements IAgent {
10011005
return new CopilotAgentStartupConfig(
10021006
this._isSessionSyncEnabled(),
10031007
this._isRubberDuckEnabled(),
1008+
this._isMultiTurnContextRoutingEnabled(),
10041009
this._getCopilotSdkLogLevelSetting(),
10051010
this._getEnterpriseHost(),
10061011
this._isSystemProxyEnabled(),
@@ -1935,6 +1940,17 @@ export class CopilotAgent extends Disposable implements IAgent {
19351940
delete env['RUBBER_DUCK_AGENT'];
19361941
}
19371942

1943+
// Let the Auto router score prior user messages instead of the latest
1944+
// message alone. `MULTI_TURN_CONTEXT_ROUTING` is the runtime's local
1945+
// override for the matching ExP flag, and only takes effect on top of
1946+
// the single-call Auto endpoint that `createCopilotCliEnvironment`
1947+
// already opts into.
1948+
if (startupConfig.multiTurnContextRouting) {
1949+
env['MULTI_TURN_CONTEXT_ROUTING'] = 'true';
1950+
} else {
1951+
delete env['MULTI_TURN_CONTEXT_ROUTING'];
1952+
}
1953+
19381954
// Resolve the CLI entry point and native SDK binaries from node_modules.
19391955
// In the desktop app these live next to the ASAR archive in
19401956
// `node_modules.asar.unpacked` (the `@github/copilot-<platform>` CLI and

src/vs/platform/agentHost/node/copilot/copilotAgentStartupConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export class CopilotAgentStartupConfig {
1111
constructor(
1212
readonly sessionSync: boolean,
1313
readonly rubberDuck: boolean,
14+
readonly multiTurnContextRouting: boolean,
1415
readonly copilotSdkLogLevel: CopilotSdkLogLevelSetting,
1516
readonly enterpriseHost: string | undefined,
1617
readonly systemProxy: boolean,

src/vs/platform/agentHost/node/copilot/copilotCliEnvironment.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,9 @@ export function createCopilotCliEnvironment(environment: NodeJS.ProcessEnv = pro
2424
env['COPILOT_MCP_APPS'] = 'true';
2525
env[AiAgentEnvVar] = AiAgentEnvValue;
2626
env['AUTO_APPROVAL'] = 'true';
27+
// Resolve Auto mode through the CLI's single-call `POST /auto` endpoint. The
28+
// runtime gates this on an ExP flag whose local override is the flag name
29+
// itself, so VS Code opts its whole population in rather than splitting it.
30+
env['AUTO_V2_ENDPOINT'] = 'true';
2731
return env;
2832
}

src/vs/platform/agentHost/test/node/copilotAgent.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3719,6 +3719,41 @@ suite('CopilotAgent', () => {
37193719
}
37203720
});
37213721

3722+
test('enables the auto v2 endpoint always and multi-turn context routing only when configured', async () => {
3723+
const defaultClient = new TestCopilotClient([]);
3724+
const { agent: defaultAgent } = createTestAgentContext(disposables, { copilotClient: defaultClient });
3725+
try {
3726+
await defaultAgent.listChatsToMigrate();
3727+
3728+
const routingClient = new TestCopilotClient([]);
3729+
const { agent: routingAgent } = createTestAgentContext(disposables, {
3730+
copilotClient: routingClient,
3731+
rootConfig: { [CopilotCliConfigKey.MultiTurnContextRouting]: true },
3732+
});
3733+
try {
3734+
await routingAgent.listChatsToMigrate();
3735+
3736+
const defaultEnv = getCreatedClientOptions(defaultAgent).at(-1)?.env;
3737+
const routingEnv = getCreatedClientOptions(routingAgent).at(-1)?.env;
3738+
assert.deepStrictEqual({
3739+
defaultAutoV2: defaultEnv?.['AUTO_V2_ENDPOINT'],
3740+
defaultMultiTurn: defaultEnv?.['MULTI_TURN_CONTEXT_ROUTING'],
3741+
routingAutoV2: routingEnv?.['AUTO_V2_ENDPOINT'],
3742+
routingMultiTurn: routingEnv?.['MULTI_TURN_CONTEXT_ROUTING'],
3743+
}, {
3744+
defaultAutoV2: 'true',
3745+
defaultMultiTurn: undefined,
3746+
routingAutoV2: 'true',
3747+
routingMultiTurn: 'true',
3748+
});
3749+
} finally {
3750+
await disposeAgent(routingAgent);
3751+
}
3752+
} finally {
3753+
await disposeAgent(defaultAgent);
3754+
}
3755+
});
3756+
37223757
test('enables the built-in GitHub MCP server by default and removes its environment variable when disabled', async () => {
37233758
const enabledClient = new TestCopilotClient([]);
37243759
const { agent: enabledAgent } = createTestAgentContext(disposables, { copilotClient: enabledClient });

src/vs/platform/agentHost/test/node/copilotAgentStartupConfig.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ suite('CopilotAgentStartupConfig', () => {
1111
ensureNoDisposablesAreLeakedInTestSuite();
1212

1313
test('compares and describes startup configuration changes', () => {
14-
const previous = new CopilotAgentStartupConfig(false, true, 'info', undefined, true, true, {});
15-
const same = new CopilotAgentStartupConfig(false, true, 'info', undefined, true, true, {});
16-
const changed = new CopilotAgentStartupConfig(true, true, 'trace', 'github.example.com', false, false, { deny: ['shell(*)'] });
14+
const previous = new CopilotAgentStartupConfig(false, true, false, 'info', undefined, true, true, {});
15+
const same = new CopilotAgentStartupConfig(false, true, false, 'info', undefined, true, true, {});
16+
const changed = new CopilotAgentStartupConfig(true, true, true, 'trace', 'github.example.com', false, false, { deny: ['shell(*)'] });
1717

1818
assert.deepStrictEqual({
1919
same: same.equals(previous),
@@ -24,7 +24,7 @@ suite('CopilotAgentStartupConfig', () => {
2424
same: true,
2525
changed: false,
2626
proxyTargetChanged: true,
27-
description: 'sessionSync=true, copilotSdkLogLevel=trace, enterpriseHost=github.example.com, systemProxy=false, githubMcpServer=false, managedSettingsPermissions',
27+
description: 'sessionSync=true, multiTurnContextRouting=true, copilotSdkLogLevel=trace, enterpriseHost=github.example.com, systemProxy=false, githubMcpServer=false, managedSettingsPermissions',
2828
});
2929
});
3030
});

src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCopilotCliSettingsContribution.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { autorun } from '../../../../../../base/common/observable.js';
88
import { isObject } from '../../../../../../base/common/types.js';
99
import { IAgentHostEnablementService } from '../../../../../../platform/agentHost/common/agentHostEnablementService.js';
1010
import { IAgentHostService } from '../../../../../../platform/agentHost/common/agentService.js';
11-
import { AgentHostCopilotModelCapabilityOverridesSettingId, AgentHostCopilotSdkLogLevelSettingId, AgentHostOpus48PromptEnabledSettingId, AgentHostReasoningSummaryEnabledSettingId, AgentHostToolSearchDeferThresholdSettingId, AgentHostToolSearchEnabledSettingId, CopilotCliConfigKey, normalizeToolSearchDeferThreshold, type CopilotCliModelCapabilityOverrides, type CopilotSdkLogLevelSetting } from '../../../../../../platform/agentHost/common/copilotCliConfig.js';
11+
import { AgentHostCopilotModelCapabilityOverridesSettingId, AgentHostCopilotSdkLogLevelSettingId, AgentHostMultiTurnContextRoutingEnabledSettingId, AgentHostOpus48PromptEnabledSettingId, AgentHostReasoningSummaryEnabledSettingId, AgentHostToolSearchDeferThresholdSettingId, AgentHostToolSearchEnabledSettingId, CopilotCliConfigKey, normalizeToolSearchDeferThreshold, type CopilotCliModelCapabilityOverrides, type CopilotSdkLogLevelSetting } from '../../../../../../platform/agentHost/common/copilotCliConfig.js';
1212
import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js';
1313
import { IWorkbenchContribution } from '../../../../../../workbench/common/contributions.js';
1414
import { AgentHostRootConfigForwarder, type IForwardedRootConfigKey } from './agentHostRootConfigForwarder.js';
@@ -58,6 +58,11 @@ export class AgentHostCopilotCliSettingsContribution extends Disposable implemen
5858
computeValue: () => this._configurationService.getValue<boolean>(AgentHostReasoningSummaryEnabledSettingId),
5959
registerTriggers: (store, push) => this._pushOnSettingChange(store, push, AgentHostReasoningSummaryEnabledSettingId),
6060
},
61+
{
62+
key: CopilotCliConfigKey.MultiTurnContextRouting,
63+
computeValue: () => this._configurationService.getValue<boolean>(AgentHostMultiTurnContextRoutingEnabledSettingId) === true,
64+
registerTriggers: (store, push) => this._pushOnSettingChange(store, push, AgentHostMultiTurnContextRoutingEnabledSettingId),
65+
},
6166
{
6267
key: CopilotCliConfigKey.ModelCapabilityOverrides,
6368
computeValue: () => {

src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { AgentHostAutoReplyEnabledConfigKey, AgentHostEditAutoApprovePatternsCon
2020
import '../../../../platform/agentHost/common/agentHostStarter.config.contribution.js';
2121
import { AgentMergeSettingId } from '../../../../platform/agentHost/common/agentMerge.js';
2222
import { AgentHostAhpJsonlLoggingSettingId, AgentHostAllowSignedOutWhenUsableSettingId, AgentHostSdkSandboxEnabledSettingId, AgentHostSdkSandboxWindowsEnabledSettingId, CodexPreferAgentHostEditorSettingId } from '../../../../platform/agentHost/common/agentService.js';
23-
import { AgentHostCopilotModelCapabilityOverridesSettingId, AgentHostCopilotSdkLogLevelSettingId, AgentHostCustomTerminalToolEnabledSettingId, AgentHostOpus48PromptEnabledSettingId, AgentHostReasoningEffortOverrideSettingId, AgentHostReasoningSummaryEnabledSettingId, AgentHostToolSearchDeferThresholdSettingId, AgentHostToolSearchEnabledSettingId, copilotSdkLogLevelSettingValues } from '../../../../platform/agentHost/common/copilotCliConfig.js';
23+
import { AgentHostCopilotModelCapabilityOverridesSettingId, AgentHostCopilotSdkLogLevelSettingId, AgentHostCustomTerminalToolEnabledSettingId, AgentHostMultiTurnContextRoutingEnabledSettingId, AgentHostOpus48PromptEnabledSettingId, AgentHostReasoningEffortOverrideSettingId, AgentHostReasoningSummaryEnabledSettingId, AgentHostToolSearchDeferThresholdSettingId, AgentHostToolSearchEnabledSettingId, copilotSdkLogLevelSettingValues } from '../../../../platform/agentHost/common/copilotCliConfig.js';
2424
import { DEFAULT_EDIT_AUTO_APPROVE_PATTERNS, mergeChatEditAutoApprovePatterns } from '../../../../platform/chat/common/chatSettings.js';
2525
import { reasoningEffortLevels } from '../../../../platform/agentHost/common/reasoningEffort.js';
2626
import { ChatSessionArchiveActionWordingSettingId } from '../../../../platform/chat/common/sessionArchiveActions.js';
@@ -1597,6 +1597,13 @@ configurationRegistry.registerConfiguration({
15971597
experiment: { mode: 'startup' },
15981598
tags: ['experimental', 'advanced'],
15991599
},
1600+
[AgentHostMultiTurnContextRoutingEnabledSettingId]: {
1601+
type: 'boolean',
1602+
markdownDescription: nls.localize('chat.agentHost.copilot.multiTurnContextRouting', "When enabled, Auto model selection in Copilot SDK agent sessions routes on the conversation so far, sending prior user messages to the router instead of scoring the latest message alone."),
1603+
default: false,
1604+
experiment: { mode: 'startup' },
1605+
tags: ['experimental', 'advanced'],
1606+
},
16001607
[AgentHostCopilotModelCapabilityOverridesSettingId]: {
16011608
type: 'object',
16021609
markdownDescription: nls.localize('chat.agentHost.copilot.modelCapabilityOverrides', "Per-model capability overrides for Copilot SDK agent sessions, keyed by model id (`*` matches every model; a specific entry wins field-by-field), intended for evaluating models against an existing model's profile. Declare an aliased `family` (for example `claude-opus-4.8`) to route the model to that family's tuned system prompt and tool profile without changing the model id sent to the runtime — so a preview model can be evaluated against a known prompt while still running on its own endpoint — a `reasoningEffort` to pin its effort level, `availableTools`/`excludedTools` to filter its tool set, or `modelCapabilities` to override individual capability limits (e.g. vision support, context window size) passed through to the SDK. All overrides apply when a session launches or resumes. On a mid-session model change, only the new model's `reasoningEffort` is applied; the session keeps its launch-time family, tool filters, and model capabilities. Only affects Copilot agent sessions.\n\n**Note**: This is an advanced setting for experimentation."),

src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostCopilotCliSettingsContribution.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { mock } from '../../../../../../base/test/common/mock.js';
1111
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../../base/test/common/utils.js';
1212
import { IAgentHostEnablementService } from '../../../../../../platform/agentHost/common/agentHostEnablementService.js';
1313
import { IAgentHostService } from '../../../../../../platform/agentHost/common/agentService.js';
14-
import { AgentHostCopilotModelCapabilityOverridesSettingId, AgentHostCopilotSdkLogLevelSettingId, AgentHostOpus48PromptEnabledSettingId, AgentHostReasoningSummaryEnabledSettingId, AgentHostToolSearchDeferThresholdSettingId, AgentHostToolSearchEnabledSettingId, CopilotCliConfigKey } from '../../../../../../platform/agentHost/common/copilotCliConfig.js';
14+
import { AgentHostCopilotModelCapabilityOverridesSettingId, AgentHostCopilotSdkLogLevelSettingId, AgentHostMultiTurnContextRoutingEnabledSettingId, AgentHostOpus48PromptEnabledSettingId, AgentHostReasoningSummaryEnabledSettingId, AgentHostToolSearchDeferThresholdSettingId, AgentHostToolSearchEnabledSettingId, CopilotCliConfigKey } from '../../../../../../platform/agentHost/common/copilotCliConfig.js';
1515
import { IAgentSubscription } from '../../../../../../platform/agentHost/common/state/agentSubscription.js';
1616
import type { ClientAnnotationsAction, INotification, IRootConfigChangedAction, SessionAction, TerminalAction } from '../../../../../../platform/agentHost/common/state/sessionActions.js';
1717
import type { ConfigPropertySchema, RootState } from '../../../../../../platform/agentHost/common/state/sessionState.js';
@@ -76,6 +76,7 @@ const fullSchema: Record<string, ConfigPropertySchema> = {
7676
[CopilotCliConfigKey.ToolSearchEnabled]: { type: 'boolean', title: 'Agent Host Tool Search' },
7777
[CopilotCliConfigKey.ToolSearchDeferThreshold]: { type: 'number', title: 'Tool Search Defer Threshold' },
7878
[CopilotCliConfigKey.ReasoningSummary]: { type: 'boolean', title: 'Reasoning Summary' },
79+
[CopilotCliConfigKey.MultiTurnContextRouting]: { type: 'boolean', title: 'Auto Multi-Turn Context Routing' },
7980
[CopilotCliConfigKey.ModelCapabilityOverrides]: { type: 'object', title: 'Model Capability Overrides' },
8081
};
8182

@@ -119,20 +120,22 @@ suite('AgentHostCopilotCliSettingsContribution', () => {
119120
[AgentHostToolSearchDeferThresholdSettingId]: 5.9,
120121
[AgentHostCopilotModelCapabilityOverridesSettingId]: capabilityOverrides,
121122
[AgentHostReasoningSummaryEnabledSettingId]: true,
123+
[AgentHostMultiTurnContextRoutingEnabledSettingId]: true,
122124
});
123125
agentHostService.setRootState(makeRootStateWithSchema(fullSchema));
124126
await flush();
125127

126128
// The shared forwarder dispatches one RootConfigChanged per key; merge them
127129
// and assert the full forwarded set (order-independent).
128-
assert.strictEqual(agentHostService.dispatchedActions.length, 6);
130+
assert.strictEqual(agentHostService.dispatchedActions.length, 7);
129131
const merged = Object.assign({}, ...agentHostService.dispatchedActions.map(a => (a.action as IRootConfigChangedAction).config));
130132
assert.deepStrictEqual(merged, {
131133
[CopilotCliConfigKey.CopilotSdkLogLevel]: 'trace',
132134
[CopilotCliConfigKey.Opus48Prompt]: true,
133135
[CopilotCliConfigKey.ToolSearchEnabled]: true,
134136
[CopilotCliConfigKey.ToolSearchDeferThreshold]: 5,
135137
[CopilotCliConfigKey.ReasoningSummary]: true,
138+
[CopilotCliConfigKey.MultiTurnContextRouting]: true,
136139
[CopilotCliConfigKey.ModelCapabilityOverrides]: capabilityOverrides,
137140
});
138141
});
@@ -187,6 +190,7 @@ suite('AgentHostCopilotCliSettingsContribution', () => {
187190
[CopilotCliConfigKey.ToolSearchEnabled]: false,
188191
[CopilotCliConfigKey.ToolSearchDeferThreshold]: 1,
189192
[CopilotCliConfigKey.ReasoningSummary]: false,
193+
[CopilotCliConfigKey.MultiTurnContextRouting]: false,
190194
[CopilotCliConfigKey.ModelCapabilityOverrides]: { 'preview-model-x': { family: 'claude-opus-4-8' } },
191195
}));
192196
await flush();

0 commit comments

Comments
 (0)