Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
65054fc
Fix typo in README: remove extra 'and' in contributing section
Lefgk May 19, 2026
d67b2d8
remove copilot models from the list
vritant24 May 19, 2026
a35750c
Add model insertion ranges to language model config
vritant24 May 19, 2026
7da6310
Add provider group model management actions
vritant24 May 19, 2026
f1e5c76
Expose provider group actions in Manage Models
vritant24 May 19, 2026
7579173
Sanity test: tighten agent-mode prompt so the model can't skip the to…
bryanchen-d May 20, 2026
1e7597c
sessions: workspace picker emits folder URI, session type picker span…
sandy081 May 20, 2026
628f432
rename and reorder actions
vritant24 May 20, 2026
0d944f4
Address GHE onboarding issues (#317205)
cwebster-99 May 20, 2026
97a41a0
Fix model insertion for empty arrays and skip API key update when val…
vritant24 May 20, 2026
0741dcb
Merge branch 'main' into dev/vritant24/manageModelsContext
vritant24 May 20, 2026
3522b12
Merge branch 'main' into dev/vrbhardw/utility-no-copilot
vritant24 May 20, 2026
b36c628
Add agent (grok build, cursor) and agy (antigravity) CLIs to ignoredC…
Tyriar May 20, 2026
aead057
chat: persist installed plugin identity (#317585)
connor4312 May 20, 2026
f666f19
add ChatSessionCustomizationItem.source, clean up AICustomizationProm…
aeschli May 20, 2026
382e40a
fix: handle corrupted session files gracefully in getChatHistoryImpl …
vs-code-engineering[bot] May 20, 2026
9f1d336
use constant
vritant24 May 20, 2026
e359553
Merge branch 'main' into dev/vrbhardw/utility-no-copilot
vritant24 May 20, 2026
5af3ef5
add comment
vritant24 May 20, 2026
2e3819a
Fix sudo -S sensitive input detection (#317594)
meganrogge May 20, 2026
5e51382
don't show fun messages if we are replacing them for thinking phrases…
justschen May 20, 2026
83ab76d
Merge pull request #317595 from microsoft/dev/vrbhardw/utility-no-cop…
vritant24 May 20, 2026
57ff4a0
sessions: fix worktree-created task dispatch (#317598)
connor4312 May 20, 2026
bc7d325
"Open Browser Settings" simplified to just "Browser Settings" (#317217)
jruales May 20, 2026
2e8b995
agents: add smoke test for Agents Window with mocked LLM server (#317…
sandy081 May 20, 2026
80afb57
Add new VS Code theme for mermaid diagrams
mjbvz May 20, 2026
35e7549
Merge branch 'main' into dev/vritant24/manageModelsContext
vritant24 May 20, 2026
2b1baa0
Update notebook file too
mjbvz May 20, 2026
2207fb5
Merge pull request #317252 from Lefgk/fix/readme-typo-to-and
mjbvz May 20, 2026
4ec65be
test(mcp): avoid spurious sinon FakeTimers console warning
bryanchen-d May 20, 2026
8166ded
Fix fallback logic
mjbvz May 20, 2026
223302f
fixup: widen sinon fake-timer config type
bryanchen-d May 20, 2026
fe825e9
sessions: use per-agent icon for agent host sessions (#317620)
sandy081 May 20, 2026
59772e8
fix: enable logging condition in state model change logging (#317626)
DonJayamanne May 20, 2026
e993390
Merge pull request #317419 from microsoft/dev/vritant24/manageModelsC…
vritant24 May 20, 2026
5608b5f
Merge pull request #317426 from microsoft/brchen/sanity-agent-prompt-fix
bryanchen-d May 20, 2026
c0f1f05
Merge pull request #317631 from microsoft/brchen/mcp-sampling-log-fak…
bryanchen-d May 20, 2026
fb7459a
Merge pull request #317617 from microsoft/dev/mjbvz/remote-donkey
mjbvz May 20, 2026
1661173
sessions: don't reorder session list when find widget opens (#317615)
sandy081 May 20, 2026
66fa7c9
Make sure `npm run watch` also checks extension media builds
mjbvz May 20, 2026
86bd3e9
agent-host: stop redundant customization sync events (#317611)
connor4312 May 20, 2026
827fd6c
agent-host: route long question text through detailedMessage (#317650)
connor4312 May 20, 2026
2b473d6
Potential fix for pull request finding
mjbvz May 20, 2026
c7f7332
Potential fix for pull request finding
mjbvz May 20, 2026
f2fd637
Merge pull request #317653 from microsoft/dev/mjbvz/close-swordfish
mjbvz May 20, 2026
d61f56e
Enable BYOK in air-gapped scenarios/without GitHub auth (#317428)
dmitrivMS May 21, 2026
8f51c4a
fix null-safety in LocalNewSession._resolveGitState (#317645)
sandy081 May 21, 2026
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ There are many ways in which you can participate in this project, for example:

* [Submit bugs and feature requests](https://github.com/microsoft/vscode/issues), and help us verify as they are checked in
* Review [source code changes](https://github.com/microsoft/vscode/pulls)
* Review the [documentation](https://github.com/microsoft/vscode-docs) and make pull requests for anything from typos to and new content.
* Review the [documentation](https://github.com/microsoft/vscode-docs) and make pull requests for anything from typos to new content.

If you are interested in fixing issues and contributing directly to the code base,
please see the document [How to Contribute](https://github.com/microsoft/vscode/wiki/How-to-Contribute), which covers the following:
Expand Down
61 changes: 50 additions & 11 deletions build/lib/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { getProductionDependencies } from './dependencies.ts';
import { type IExtensionDefinition, getExtensionStream } from './builtInExtensions.ts';
import { fetchUrls, fetchGithub } from './fetch.ts';
import { createTsgoStream, spawnTsgo } from './tsgo.ts';
import watcher from './watch/index.ts';

import { createRequire } from 'module';
const require = createRequire(import.meta.url);
Expand Down Expand Up @@ -617,21 +618,59 @@ export async function esbuildExtensions(taskName: string, isWatch: boolean, scri


// Additional projects to run esbuild on. These typically build code for webviews
const esbuildMediaScripts = [
'ipynb/esbuild.notebook.mts',
'markdown-language-features/esbuild.notebook.mts',
'markdown-language-features/esbuild.webview.mts',
'markdown-math/esbuild.notebook.mts',
'mermaid-markdown-features/esbuild.webview.mts',
'notebook-renderers/esbuild.notebook.mts',
'simple-browser/esbuild.webview.mts',
const esbuildMediaScripts: { script: string; tsconfig: string }[] = [
{ script: 'ipynb/esbuild.notebook.mts', tsconfig: 'ipynb/notebook-src/tsconfig.json' },
{ script: 'markdown-language-features/esbuild.notebook.mts', tsconfig: 'markdown-language-features/notebook/tsconfig.json' },
{ script: 'markdown-language-features/esbuild.webview.mts', tsconfig: 'markdown-language-features/preview-src/tsconfig.json' },
{ script: 'markdown-math/esbuild.notebook.mts', tsconfig: 'markdown-math/notebook/tsconfig.json' },
{ script: 'mermaid-markdown-features/esbuild.webview.mts', tsconfig: 'mermaid-markdown-features/preview-src/tsconfig.json' },
{ script: 'notebook-renderers/esbuild.notebook.mts', tsconfig: 'notebook-renderers/tsconfig.json' },
{ script: 'simple-browser/esbuild.webview.mts', tsconfig: 'simple-browser/preview-src/tsconfig.json' },
];

export function buildExtensionMedia(isWatch: boolean, outputRoot?: string): Promise<void> {
return esbuildExtensions('esbuilding extension media', isWatch, esbuildMediaScripts.map(p => ({
script: path.join(extensionsPath, p),
outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(p)) : undefined
const esbuildTask = esbuildExtensions('esbuilding extension media', isWatch, esbuildMediaScripts.map(({ script }) => ({
script: path.join(extensionsPath, script),
outputRoot: outputRoot ? path.join(root, outputRoot, path.dirname(script)) : undefined
})));

const typeCheckTasks = esbuildMediaScripts.map(({ tsconfig }) => {
const tsconfigPath = path.join(extensionsPath, tsconfig);
const config = { taskName: 'typechecking extension media (tsgo)', noEmit: true };
if (!isWatch) {
return spawnTsgo(tsconfigPath, config);
} else {
return watchTypeCheckExtensionMedia(tsconfigPath, config);
}
});

return Promise.all([esbuildTask, ...typeCheckTasks]).then(() => undefined);
}

function watchTypeCheckExtensionMedia(tsconfigPath: string, config: { taskName: string; noEmit?: boolean }): Promise<void> {
const srcDir = path.dirname(tsconfigPath);
const watchInput = watcher([
path.join(srcDir, '**', '*.{ts,tsx,d.ts}'),
tsconfigPath,
'!' + path.join(srcDir, '**', 'node_modules', '**'),
'!' + path.join(srcDir, '**', 'out', '**'),
'!' + path.join(srcDir, '**', 'dist', '**'),
], { cwd: root, base: srcDir, dot: true, readDelay: 200 });
const stream = watchInput
.pipe(util2.debounce(() => {
const tsgoStream = createTsgoStream(tsconfigPath, config);
// Always emit 'end' (even on tsgo error) so the debounce resets to idle
// and can process future file changes. Errors are already logged by
// spawnTsgo's runReporter, so swallowing the stream error is safe.
const result = es.through();
tsgoStream.on('end', () => result.emit('end'));
tsgoStream.on('error', () => result.emit('end'));
return result;
}, 200));

return new Promise<void>((_resolve, reject) => {
stream.on('error', reject);
});
}

export function getBuildRootsForExtension(extensionPath: string): string[] {
Expand Down
16 changes: 8 additions & 8 deletions extensions/copilot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2263,49 +2263,49 @@
"icon": "$(chat-sparkle)",
"title": "%copilot.title%",
"content": "%github.copilot.viewsWelcome.individual.expired%",
"when": "github.copilot.interactiveSession.individual.expired"
"when": "github.copilot.interactiveSession.individual.expired && !github.copilot.hasByokModels"
},
{
"icon": "$(chat-sparkle)",
"title": "%copilot.title%",
"content": "%github.copilot.viewsWelcome.enterprise%",
"when": "github.copilot.interactiveSession.enterprise.disabled"
"when": "github.copilot.interactiveSession.enterprise.disabled && !github.copilot.hasByokModels"
},
{
"icon": "$(chat-sparkle)",
"title": "%copilot.title%",
"content": "%github.copilot.viewsWelcome.offline%",
"when": "github.copilot.offline"
"when": "github.copilot.offline && !github.copilot.hasByokModels"
},
{
"icon": "$(chat-sparkle)",
"title": "%copilot.title%",
"content": "%github.copilot.viewsWelcome.invalidToken%",
"when": "github.copilot.interactiveSession.invalidToken"
"when": "github.copilot.interactiveSession.invalidToken && !github.copilot.hasByokModels"
},
{
"icon": "$(chat-sparkle)",
"title": "%copilot.title%",
"content": "%github.copilot.viewsWelcome.rateLimited%",
"when": "github.copilot.interactiveSession.rateLimited"
"when": "github.copilot.interactiveSession.rateLimited && !github.copilot.hasByokModels"
},
{
"icon": "$(chat-sparkle)",
"title": "%copilot.title%",
"content": "%github.copilot.viewsWelcome.gitHubLoginFailed%",
"when": "github.copilot.interactiveSession.gitHubLoginFailed"
"when": "github.copilot.interactiveSession.gitHubLoginFailed && !github.copilot.hasByokModels"
},
{
"icon": "$(chat-sparkle)",
"title": "%copilot.title%",
"content": "%github.copilot.viewsWelcome.contactSupport%",
"when": "github.copilot.interactiveSession.contactSupport"
"when": "github.copilot.interactiveSession.contactSupport && !github.copilot.hasByokModels"
},
{
"icon": "$(chat-sparkle)",
"title": "%copilot.title%",
"content": "%github.copilot.viewsWelcome.chatDisabled%",
"when": "github.copilot.interactiveSession.chatDisabled"
"when": "github.copilot.interactiveSession.chatDisabled && !github.copilot.hasByokModels"
},
{
"icon": "$(chat-sparkle)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ class AuthUpgradeAsk extends Disposable {
}

private async waitForChatEnabled() {
if (!this._authenticationService.anyGitHubSession) {
// BYOK / air-gapped: do not wait for a Copilot token that may never arrive.
return;
}

try {
await this._authenticationService.getCopilotToken();
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';
import { IAuthenticationService } from '../../../platform/authentication/common/authentication';
import { IConfigurationService } from '../../../platform/configuration/common/configurationService';
import { ILogService } from '../../../platform/log/common/logService';
import { Disposable } from '../../../util/vs/base/common/lifecycle';

const NOTIFICATION_ID = 'copilot.byokUtilityModelHint';
const UTILITY_MODEL_SETTING = 'chat.utilityModel';
const UTILITY_SMALL_MODEL_SETTING = 'chat.utilitySmallModel';

/**
* Shows a chat input notification in air-gapped BYOK scenarios (no GitHub
* session) when at least one BYOK model is available but the utility model
* settings are still defaults. The default utility models require GitHub
* Copilot access, so without it the utility slots silently fall back and
* degrade the experience until the user points them at a BYOK model.
*
* The notification hides automatically once the user signs in, BYOK models
* disappear, or both utility settings are configured.
*/
export class ByokUtilityModelNotificationContribution extends Disposable {

private _notification: vscode.ChatInputNotification | undefined;
private _hasByokModels = false;
private _refreshing = false;

constructor(
@IAuthenticationService private readonly _authService: IAuthenticationService,
@IConfigurationService private readonly _configService: IConfigurationService,
@ILogService private readonly _logService: ILogService,
) {
super();

this._register(this._authService.onDidAuthenticationChange(() => this._update()));
this._register(vscode.lm.onDidChangeChatModels(() => this._update()));
this._register(this._configService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(UTILITY_MODEL_SETTING) || e.affectsConfiguration(UTILITY_SMALL_MODEL_SETTING)) {
this._update();
}
}));

this._update();
}

private async _refreshHasByokModels(): Promise<void> {
if (this._refreshing) {
return;
}
this._refreshing = true;
try {
const models = await vscode.lm.selectChatModels({});
this._hasByokModels = models.some(m => m.vendor !== 'copilot');
} catch (err) {
this._logService.warn(`[ByokUtilityModelNotification] Failed to query language models: ${err}`);
} finally {
this._refreshing = false;
}
}

private async _update(): Promise<void> {
await this._refreshHasByokModels();

const signedOut = !this._authService.anyGitHubSession;
const utilityUnset = !this._isUtilityOverrideSet(UTILITY_MODEL_SETTING);
const utilitySmallUnset = !this._isUtilityOverrideSet(UTILITY_SMALL_MODEL_SETTING);

if (!signedOut || !this._hasByokModels || (!utilityUnset && !utilitySmallUnset)) {
this._hideNotification();
return;
}

this._showNotification(utilityUnset, utilitySmallUnset);
}

private _isUtilityOverrideSet(configKey: string): boolean {
const raw = this._configService.getNonExtensionConfig<unknown>(configKey);
return typeof raw === 'string' && raw.length > 0;
}

private _showNotification(utilityUnset: boolean, utilitySmallUnset: boolean): void {
const notification = this._ensureNotification();
notification.severity = vscode.ChatInputNotificationSeverity.Info;
notification.dismissible = true;
notification.autoDismissOnMessage = false;

if (utilityUnset && utilitySmallUnset) {
notification.message = vscode.l10n.t('Set BYOK utility models');
notification.description = vscode.l10n.t('Unlocks full AI features.');
notification.actions = [
{ label: vscode.l10n.t('Configure'), commandId: 'workbench.action.openSettings', commandArgs: ['chat.utility'] },
];
} else if (utilityUnset) {
notification.message = vscode.l10n.t('Set BYOK utility model');
notification.description = vscode.l10n.t('Unlocks full AI features.');
notification.actions = [
{ label: vscode.l10n.t('Configure'), commandId: 'workbench.action.openSettings', commandArgs: [UTILITY_MODEL_SETTING] },
];
} else {
notification.message = vscode.l10n.t('Set BYOK small utility model');
notification.description = vscode.l10n.t('Unlocks full AI features.');
notification.actions = [
{ label: vscode.l10n.t('Configure'), commandId: 'workbench.action.openSettings', commandArgs: [UTILITY_SMALL_MODEL_SETTING] },
];
}

notification.show();
}

private _ensureNotification(): vscode.ChatInputNotification {
if (!this._notification) {
this._notification = vscode.chat.createInputNotification(NOTIFICATION_ID);
this._register({ dispose: () => this._notification?.dispose() });
}
return this._notification;
}

private _hideNotification(): void {
this._notification?.hide();
}
}
Loading
Loading