Skip to content

Commit 6018a4d

Browse files
committed
fix: preserve BYOK tool capabilities
1 parent c53c543 commit 6018a4d

1 file changed

Lines changed: 57 additions & 17 deletions

File tree

‎patches/copilot-background-byok.diff‎

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ server without a new user message and reconnect to the same progressed session.
4141
dispatch(channel: string, action: SessionAction | ChatAction | TerminalAction | ClientChangesetAction | ClientAnnotationsAction | ClientAutomationAction | ClientAutomationRunAction | IRootConfigChangedAction): void {
4242
const seq = this._subscriptionManager.dispatchOptimistic(channel, action);
4343
this.dispatchAction(channel, action, this._clientId, seq);
44+
4445
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/common/agentHostByokLm.ts
4546
+++ code-server/lib/vscode/src/vs/platform/agentHost/common/agentHostByokLm.ts
4647
@@ -135,6 +135,17 @@
@@ -61,7 +62,13 @@ server without a new user message and reconnect to the same progressed session.
6162
export interface IByokLmModelInfo {
6263
/** Provider/vendor name (the LM API vendor that registered the model). */
6364
readonly vendor: string;
64-
@@ -161,6 +172,11 @@
65+
@@ -157,10 +168,17 @@
66+
readonly maxOutputTokens?: number;
67+
/** Whether the model accepts image inputs, when known. */
68+
readonly supportsVision?: boolean;
69+
+ /** Whether the model supports canonical tool calling, when known. */
70+
+ readonly supportsToolCalling?: boolean;
71+
/** Reasoning effort values advertised by the renderer model, when known. */
6572
readonly supportedReasoningEfforts?: readonly string[];
6673
/** Default reasoning effort advertised by the renderer model, when known. */
6774
readonly defaultReasoningEffort?: string;
@@ -73,7 +80,7 @@ server without a new user message and reconnect to the same progressed session.
7380
}
7481

7582
/**
76-
@@ -177,7 +193,9 @@
83+
@@ -177,7 +195,9 @@
7784

7885
/** Returns the provider-qualified model id advertised by the agent host. */
7986
export function getByokLmAgentModelId(model: IByokLmModelInfo): string {
@@ -84,6 +91,7 @@ server without a new user message and reconnect to the same progressed session.
8491
}
8592

8693
/** Resolves BYOK enablement and trace context from synchronized root configuration. */
94+
8795
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/common/agentHostEnablementService.ts
8896
+++ code-server/lib/vscode/src/vs/platform/agentHost/common/agentHostEnablementService.ts
8997
@@ -51,9 +51,8 @@
@@ -108,6 +116,7 @@ server without a new user message and reconnect to the same progressed session.
108116
},
109117
'chat.editor.localAgent.enabled': {
110118
type: 'boolean',
119+
111120
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/common/agentHostStarter.config.contribution.ts
112121
+++ code-server/lib/vscode/src/vs/platform/agentHost/common/agentHostStarter.config.contribution.ts
113122
@@ -279,10 +279,9 @@
@@ -123,6 +132,7 @@ server without a new user message and reconnect to the same progressed session.
123132
},
124133
[AgentHostCodexAgentEnabledSettingId]: {
125134
type: 'boolean',
135+
126136
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/common/agentService.ts
127137
+++ code-server/lib/vscode/src/vs/platform/agentHost/common/agentService.ts
128138
@@ -13,6 +13,7 @@
@@ -155,7 +165,7 @@ server without a new user message and reconnect to the same progressed session.
155165
+
156166
/** Restart the agent host process, if this connection owns its lifecycle. */
157167
restartAgentHost(): Promise<void>;
158-
168+
159169
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/common/ahpJsonlLogger.ts
160170
+++ code-server/lib/vscode/src/vs/platform/agentHost/common/ahpJsonlLogger.ts
161171
@@ -99,7 +99,7 @@
@@ -206,6 +216,7 @@ server without a new user message and reconnect to the same progressed session.
206216
export function getAhpLogByteLength(text: string): number {
207217
return VSBuffer.fromString(text).byteLength;
208218
}
219+
209220
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/node/agentHostServerMain.ts
210221
+++ code-server/lib/vscode/src/vs/platform/agentHost/node/agentHostServerMain.ts
211222
@@ -32,6 +32,7 @@
@@ -233,6 +244,7 @@ server without a new user message and reconnect to the same progressed session.
233244
});
234245
disposables.add(runtime);
235246
const { agentService, instantiationService } = runtime;
247+
236248
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/node/agentService.ts
237249
+++ code-server/lib/vscode/src/vs/platform/agentHost/node/agentService.ts
238250
@@ -80,6 +80,8 @@
@@ -271,6 +283,7 @@ server without a new user message and reconnect to the same progressed session.
271283
dispatchAction(channel: string, action: SessionAction | ChatAction | TerminalAction | ClientChangesetAction | ClientAnnotationsAction | IRootConfigChangedAction | ClientAutomationAction | ClientAutomationRunAction, clientId: string, clientSeq: number, clientContextOrType: IAgentHostClientTelemetryContext | AgentHostClientType = AgentHostClientType.Unknown): void {
272284
const clientContext = typeof clientContextOrType === 'string'
273285
? createUnknownAgentHostClientTelemetryContext(clientContextOrType)
286+
274287
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/node/byokLmBridgeRegistry.ts
275288
+++ code-server/lib/vscode/src/vs/platform/agentHost/node/byokLmBridgeRegistry.ts
276289
@@ -38,6 +38,9 @@
@@ -315,15 +328,17 @@ server without a new user message and reconnect to the same progressed session.
315328
}
316329

317330
getServingConnection(): IByokLmBridgeConnection | undefined {
318-
@@ -171,6 +189,7 @@
331+
@@ -170,7 +188,9 @@
332+
&& m.maxPromptTokens === n.maxPromptTokens
319333
&& m.maxOutputTokens === n.maxOutputTokens
320334
&& m.supportsVision === n.supportsVision
335+
+ && m.supportsToolCalling === n.supportsToolCalling
321336
&& m.defaultReasoningEffort === n.defaultReasoningEffort
322337
+ && JSON.stringify(m.directProvider) === JSON.stringify(n.directProvider)
323338
&& arraysEqual(m.supportedReasoningEfforts, n.supportedReasoningEfforts);
324339
});
325340
}
326-
@@ -192,6 +211,8 @@
341+
@@ -192,6 +212,8 @@
327342
return Disposable.None;
328343
}
329344

@@ -332,6 +347,7 @@ server without a new user message and reconnect to the same progressed session.
332347
getModels(): readonly IByokLmModelInfo[] {
333348
return [];
334349
}
350+
335351
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/node/copilot/copilotSessionLauncher.ts
336352
+++ code-server/lib/vscode/src/vs/platform/agentHost/node/copilot/copilotSessionLauncher.ts
337353
@@ -13,7 +13,7 @@
@@ -343,7 +359,7 @@ server without a new user message and reconnect to the same progressed session.
343359
import { AgentHostByokModelsEnabledConfigKey, AgentHostMcpConnectorsEnabledConfigKey, AgentHostSessionSyncEnabledConfigKey, platformRootSchema, type AgentHostMcpServers } from '../../common/agentHostSchema.js';
344360
import { CopilotCliConfigKey, copilotCliConfigSchema, normalizeModelFamilyAlias, normalizeToolSearchDeferThreshold, resolveModelCapabilityOverrideField } from '../../common/copilotCliConfig.js';
345361
import { IAgentHostOTelService } from '../../common/otel/agentHostOTelService.js';
346-
@@ -543,66 +543,114 @@
362+
@@ -543,66 +543,117 @@
347363
* unit-testable without instantiating the launcher; the launcher passes a
348364
* `startProxy` thunk that memoizes the single shared proxy handle.
349365
*/
@@ -352,6 +368,9 @@ server without a new user message and reconnect to the same progressed session.
352368
+ if (model.supportsVision !== undefined) {
353369
+ supports.vision = model.supportsVision;
354370
+ }
371+
+ if (model.supportsToolCalling !== undefined) {
372+
+ supports.toolCalls = model.supportsToolCalling;
373+
+ }
355374
+ if (model.supportedReasoningEfforts?.length) {
356375
+ supports.reasoningEffort = true;
357376
+ }
@@ -495,6 +514,7 @@ server without a new user message and reconnect to the same progressed session.
495514
}
496515

497516
/** Applies sandbox configuration, returning false when the runtime retains its policy after a managed conflict. */
517+
498518
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/node/protocolServerHandler.ts
499519
+++ code-server/lib/vscode/src/vs/platform/agentHost/node/protocolServerHandler.ts
500520
@@ -18,6 +18,7 @@
@@ -505,7 +525,7 @@ server without a new user message and reconnect to the same progressed session.
505525
import { isManagedSettingsPermissions } from '../common/agentHostManagedSettings.js';
506526
import { isAnnotationsUri } from '../common/annotationsUri.js';
507527
import { parseChangesetUri } from '../common/changesetUri.js';
508-
@@ -145,6 +146,81 @@
528+
@@ -145,6 +146,82 @@
509529
return channel;
510530
}
511531

@@ -514,7 +534,7 @@ server without a new user message and reconnect to the same progressed session.
514534
+const MAX_EPHEMERAL_BYOK_REASONING_EFFORTS = 64;
515535
+const EPHEMERAL_BYOK_MODEL_KEYS = new Set([
516536
+ 'vendor', 'id', 'name', 'modelIdentifier', 'maxContextWindowTokens', 'maxPromptTokens', 'maxOutputTokens',
517-
+ 'supportsVision', 'supportedReasoningEfforts', 'defaultReasoningEffort', 'directProvider',
537+
+ 'supportsVision', 'supportsToolCalling', 'supportedReasoningEfforts', 'defaultReasoningEffort', 'directProvider',
518538
+]);
519539
+const EPHEMERAL_BYOK_PROVIDER_KEYS = new Set(['name', 'type', 'wireApi', 'baseUrl', 'apiKey', 'modelId']);
520540
+
@@ -559,6 +579,7 @@ server without a new user message and reconnect to the same progressed session.
559579
+ || !isOptionalTokenCount(candidate.maxPromptTokens)
560580
+ || !isOptionalTokenCount(candidate.maxOutputTokens)
561581
+ || !isOptionalBoolean(candidate.supportsVision)
582+
+ || !isOptionalBoolean(candidate.supportsToolCalling)
562583
+ || !isOptionalReasoningEfforts(candidate.supportedReasoningEfforts)
563584
+ || !isBoundedString(candidate.defaultReasoningEffort, true)) {
564585
+ return false;
@@ -587,7 +608,7 @@ server without a new user message and reconnect to the same progressed session.
587608
/**
588609
* Methods handled by the request dispatcher. Excludes `initialize`,
589610
* `reconnect`, and `ping`, which are handled directly during message
590-
@@ -523,6 +599,21 @@
611+
@@ -523,6 +600,21 @@
591612
}
592613
return;
593614
}
@@ -609,6 +630,7 @@ server without a new user message and reconnect to the same progressed session.
609630
// Notification — fire-and-forget
610631
switch (msg.method) {
611632
case 'unsubscribe':
633+
612634
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/test/common/ahpJsonlLogger.test.ts
613635
+++ code-server/lib/vscode/src/vs/platform/agentHost/test/common/ahpJsonlLogger.test.ts
614636
@@ -114,6 +114,58 @@
@@ -670,6 +692,7 @@ server without a new user message and reconnect to the same progressed session.
670692
test('rotates JSONL files and keeps bounded history', async () => {
671693
const fileService = store.add(new FileService(new NullLogService()));
672694
store.add(fileService.registerProvider('file', store.add(new InMemoryFileSystemProvider())));
695+
673696
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/test/node/byokLmBridgeRegistry.test.ts
674697
+++ code-server/lib/vscode/src/vs/platform/agentHost/test/node/byokLmBridgeRegistry.test.ts
675698
@@ -59,6 +59,64 @@
@@ -737,9 +760,10 @@ server without a new user message and reconnect to the same progressed session.
737760
test('a window that pushes an empty list is still a valid serving target', () => {
738761
const registry = new ByokLmBridgeRegistry();
739762
const only = pushable();
763+
740764
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/test/node/copilotSessionLauncher.test.ts
741765
+++ code-server/lib/vscode/src/vs/platform/agentHost/test/node/copilotSessionLauncher.test.ts
742-
@@ -417,10 +417,52 @@
766+
@@ -417,10 +417,53 @@
743767
assert.strictEqual(proxy.starts, 0);
744768
});
745769

@@ -752,6 +776,7 @@ server without a new user message and reconnect to the same progressed session.
752776
+ name: 'Fixture Model',
753777
+ maxContextWindowTokens: 128000,
754778
+ supportsVision: true,
779+
+ supportsToolCalling: true,
755780
+ supportedReasoningEfforts: ['low', 'high'],
756781
+ directProvider: {
757782
+ name: 'vscode-byok-customendpoint-abc',
@@ -780,7 +805,7 @@ server without a new user message and reconnect to the same progressed session.
780805
+ provider: 'vscode-byok-customendpoint-abc',
781806
+ name: 'Fixture Model',
782807
+ maxContextWindowTokens: 128000,
783-
+ capabilities: { supports: { vision: true, reasoningEffort: true } },
808+
+ capabilities: { supports: { vision: true, toolCalls: true, reasoningEffort: true } },
784809
+ }],
785810
+ });
786811
+ });
@@ -793,7 +818,7 @@ server without a new user message and reconnect to the same progressed session.
793818
{ vendor: 'acme', id: 'gpt', name: undefined, maxContextWindowTokens: undefined },
794819
{ vendor: 'globex', id: 'llama', name: 'Globex Llama' },
795820
]));
796-
@@ -436,7 +478,7 @@
821+
@@ -436,7 +479,7 @@
797822
{ name: 'globex', type: 'openai', wireApi: 'responses', baseUrl: 'http://127.0.0.1:1/v/globex', bearerToken: 'NONCE.sess-1' },
798823
],
799824
models: [
@@ -802,6 +827,7 @@ server without a new user message and reconnect to the same progressed session.
802827
{ id: 'gpt', provider: 'acme' },
803828
{ id: 'llama', provider: 'globex', name: 'Globex Llama' },
804829
],
830+
805831
--- code-server.orig/lib/vscode/src/vs/platform/agentHost/test/node/protocolServerHandler.test.ts
806832
+++ code-server/lib/vscode/src/vs/platform/agentHost/test/node/protocolServerHandler.test.ts
807833
@@ -22,6 +22,7 @@
@@ -897,6 +923,7 @@ server without a new user message and reconnect to the same progressed session.
897923
test('setClientManagedSettingsPermissions validates and attributes contributions to the connected client', async () => {
898924
const transport = connectClient('client-managed-settings-contribution');
899925
transport.sent.length = 0;
926+
900927
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHost.contribution.ts
901928
+++ code-server/lib/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHost.contribution.ts
902929
@@ -15,9 +15,11 @@
@@ -962,6 +989,7 @@ server without a new user message and reconnect to the same progressed session.
962989
registerWorkbenchContribution2(AgentHostExistingSessionHarnessPickerEnablement.ID, AgentHostExistingSessionHarnessPickerEnablement, WorkbenchPhase.BlockRestore);
963990
registerWorkbenchContribution2(AgentHostLegacyMigrationGateContribution.ID, AgentHostLegacyMigrationGateContribution, WorkbenchPhase.BlockStartup);
964991
registerWorkbenchContribution2(CopilotConfigSlashSubmitHandlerContribution.ID, CopilotConfigSlashSubmitHandlerContribution, WorkbenchPhase.AfterRestored);
992+
965993
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostByokLmHandler.ts
966994
+++ code-server/lib/vscode/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostByokLmHandler.ts
967995
@@ -6,7 +6,7 @@
@@ -981,7 +1009,7 @@ server without a new user message and reconnect to the same progressed session.
9811009
IByokLmModelInfo,
9821010
IByokLmOutputItem,
9831011
IByokLmReasoningItem,
984-
@@ -39,6 +40,115 @@
1012+
@@ -39,6 +40,118 @@
9851013
const VSCODE_REASONING_SUMMARY_PART_DONE = 'vscode_reasoning_summary_part_done';
9861014
const CLIENT_BYOK_CONTEXT_KEYS = new Set([ChatEntitlementContextKeys.clientByokEnabled.key]);
9871015

@@ -1029,10 +1057,13 @@ server without a new user message and reconnect to the same progressed session.
10291057
+ }
10301058
+ const modelOptions = asRecord(model.modelOptions);
10311059
+ const requestHeaders = asRecord(model.requestHeaders);
1060+
+ const editTools = Array.isArray(model.editTools) ? model.editTools : [];
10321061
+ return !!(modelOptions && Object.keys(modelOptions).length > 0)
10331062
+ || !!(requestHeaders && Object.keys(requestHeaders).length > 0)
10341063
+ || model.zeroDataRetentionEnabled === true
10351064
+ || model.adaptiveThinking === true
1065+
+ || model.thinking === true
1066+
+ || editTools.length > 0
10361067
+ || typeof model.minThinkingBudget === 'number'
10371068
+ || typeof model.maxThinkingBudget === 'number'
10381069
+ || model.streaming === false
@@ -1097,7 +1128,7 @@ server without a new user message and reconnect to the same progressed session.
10971128
/**
10981129
* Renderer-side {@link IAgentHostByokLmHandler}. Services BYOK chat requests
10991130
* forwarded by the node agent host's OpenAI proxy by calling the VS Code LM
1100-
@@ -169,6 +279,10 @@
1131+
@@ -169,6 +282,10 @@
11011132
// Only genuine renderer BYOK models — exclude agent-host copies, which
11021133
// carry a `targetChatSessionType` and would otherwise re-enter the bridge.
11031134
if (metadata?.isBYOK && !metadata.targetChatSessionType) {
@@ -1108,14 +1139,18 @@ server without a new user message and reconnect to the same progressed session.
11081139
const reasoningEffortSchema = metadata.configurationSchema?.properties?.reasoningEffort;
11091140
const supportedReasoningEfforts = reasoningEffortSchema?.enum?.filter((value): value is string => typeof value === 'string');
11101141
const defaultReasoningEffort = typeof reasoningEffortSchema?.default === 'string' ? reasoningEffortSchema.default : undefined;
1111-
@@ -183,6 +297,7 @@
1142+
@@ -181,8 +298,10 @@
1143+
maxPromptTokens: metadata.maxInputTokens,
1144+
maxOutputTokens: metadata.maxOutputTokens,
11121145
supportsVision: !!metadata.capabilities?.vision,
1146+
+ ...(metadata.capabilities?.toolCalling !== undefined ? { supportsToolCalling: metadata.capabilities.toolCalling } : {}),
11131147
...(supportedReasoningEfforts?.length ? { supportedReasoningEfforts } : {}),
11141148
...(defaultReasoningEffort !== undefined ? { defaultReasoningEffort } : {}),
11151149
+ ...(directProvider ? { directProvider } : {}),
11161150
};
11171151
const agentHostModelIdentifier = `${SessionType.AgentHostCopilot}:${getByokLmAgentModelId(model)}`;
11181152
if (!this._languageModelsService.isModelHidden(identifier) && !this._languageModelsService.isModelHidden(agentHostModelIdentifier)) {
1153+
11191154
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/chat/common/languageModels.ts
11201155
+++ code-server/lib/vscode/src/vs/workbench/contrib/chat/common/languageModels.ts
11211156
@@ -560,6 +560,12 @@
@@ -1161,6 +1196,7 @@ server without a new user message and reconnect to the same progressed session.
11611196
hasResolvedVendor(vendor: string): boolean {
11621197
return this._modelsGroups.has(vendor);
11631198
}
1199+
11641200
--- code-server.orig/lib/vscode/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostByokLmHandler.test.ts
11651201
+++ code-server/lib/vscode/src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostByokLmHandler.test.ts
11661202
@@ -18,7 +18,7 @@
@@ -1191,15 +1227,15 @@ server without a new user message and reconnect to the same progressed session.
11911227
override isModelHidden(identifier: string): boolean {
11921228
return this._isModelHidden(identifier);
11931229
}
1194-
@@ -197,6 +202,163 @@
1230+
@@ -197,6 +202,166 @@
11951231
]);
11961232
});
11971233

11981234
+
11991235
+ test('listModels attaches an ephemeral direct OpenAI-compatible provider config', async () => {
12001236
+ const identifier = 'customendpoint/Test Group/fixture-model';
12011237
+ const service = new TestLanguageModelsService(
1202-
+ new Map([[identifier, byokModel('customendpoint', 'fixture-model')]]),
1238+
+ new Map([[identifier, byokModel('customendpoint', 'fixture-model', { toolCalling: true })]]),
12031239
+ () => responseOf([]),
12041240
+ Event.None,
12051241
+ () => false,
@@ -1225,6 +1261,7 @@ server without a new user message and reconnect to the same progressed session.
12251261
+
12261262
+ assert.strictEqual(model.vendor, 'customendpoint');
12271263
+ assert.strictEqual(model.id, 'fixture-model');
1264+
+ assert.strictEqual(model.supportsToolCalling, true);
12281265
+ assert.ok(model.directProvider?.name.startsWith('vscode-byok-customendpoint-'));
12291266
+ assert.deepStrictEqual({ ...model.directProvider, name: '<stable-synthetic>' }, {
12301267
+ name: '<stable-synthetic>',
@@ -1336,6 +1373,8 @@ server without a new user message and reconnect to the same progressed session.
13361373
+ { name: 'modelOptions', extra: { modelOptions: { temperature: 0.4 } } },
13371374
+ { name: 'zero data retention', extra: { zeroDataRetentionEnabled: true } },
13381375
+ { name: 'adaptive thinking', extra: { adaptiveThinking: true } },
1376+
+ { name: 'thinking mode', extra: { thinking: true } },
1377+
+ { name: 'edit tools', extra: { editTools: ['apply-patch'] } },
13391378
+ { name: 'thinking budget', extra: { minThinkingBudget: 1024, maxThinkingBudget: 4096 } },
13401379
+ { name: 'non-streaming', extra: { streaming: false } },
13411380
+ { name: 'reasoning effort format', extra: { reasoningEffortFormat: 'responses' } },
@@ -1355,6 +1394,7 @@ server without a new user message and reconnect to the same progressed session.
13551394
test('listModels excludes hidden BYOK sources and Agent Host copies', async () => {
13561395
const sourceIdentifier = 'openrouter/OpenRouter 2/ai21/jamba-large-1.7';
13571396
const agentHostIdentifier = `${SessionType.AgentHostCopilot}:openrouter/OpenRouter 2/ai21/jamba-large-1.7`;
1397+
13581398
--- code-server.orig/lib/vscode/src/vs/workbench/services/agentHost/browser/editorRemoteAgentHostServiceClient.ts
13591399
+++ code-server/lib/vscode/src/vs/workbench/services/agentHost/browser/editorRemoteAgentHostServiceClient.ts
13601400
@@ -21,6 +21,7 @@

0 commit comments

Comments
 (0)