Skip to content
Merged

h #6

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
12ac75e
mcp: label partially supported servers
vritant24 Sep 18, 2026
3063cdd
mcp: show diagnostics in server details
vritant24 Sep 18, 2026
82bef1c
mcp: link migratable servers to review
vritant24 Sep 18, 2026
934561a
Merge remote-tracking branch 'origin/main' into agents/mcp-partially-…
vritant24 Sep 18, 2026
b697019
mcp: align migration detail card
vritant24 Sep 21, 2026
ac663ce
Merge remote-tracking branch 'origin/main' into agents/mcp-partially-…
vritant24 Sep 21, 2026
cceb427
sessions: fix unified workspace picker edge cases (#337095)
meganrogge Sep 21, 2026
2c261bc
Update CodeNotify for automations (#337118)
benvillalobos Sep 21, 2026
03afce5
test: isolate CopilotAgent proxy environment (#337119)
jruales Sep 21, 2026
4a613ca
[cherry-pick] sessions: make harness bootstrap authentication provide…
vs-code-engineering[bot] Sep 21, 2026
e3ada48
chat: Configure keybindings for voice control actions (#337115)
meganrogge Sep 21, 2026
62a4595
Revert CSS changes from PR #336770 to fix hover regression (#337107)
lszomoru Sep 21, 2026
36351b5
network: align URL trust and IDN domain policies (#336960)
dmitrivMS Sep 21, 2026
20a1919
agentHost: stabilize concurrent subagent replay (#337102)
roblourens Sep 21, 2026
b112ecc
Make subagent model guidance the default (#337116)
bhavyaus Sep 21, 2026
5188ead
Fix migration activity persistence after reverting a customization (#…
hawkticehurst Sep 21, 2026
4a07c77
mcp: address server detail review feedback
vritant24 Sep 21, 2026
d046fe7
Agents - remember isolation per workspace (#337125)
lszomoru Sep 21, 2026
8f2902d
sessions: cap unified picker recent folders (#337132)
meganrogge Sep 21, 2026
bf715be
test: clean up Windows agent-host descendants after shutdown (#337080)
chrmarti Sep 21, 2026
e228693
Merge remote-tracking branch 'origin/main' into agents/mcp-partially-…
vritant24 Sep 21, 2026
baca19e
Update MCP screenshot baselines
vritant24 Sep 21, 2026
abfae63
Remove obsolete Copilot SDK postinstall patch (#337128)
dmitrivMS Sep 21, 2026
7e7370c
sessions: collapse Dev Container workspace recents (#337117)
meganrogge Sep 21, 2026
4ef9419
sessions: Keep single-mode peer chats independent (#337135)
sandy081 Sep 21, 2026
fba2a80
sessions: model per-chat folder ownership (#337035)
sandy081 Sep 21, 2026
95e1771
[cherry-pick] chat: refine Agents handoff experiments and entry point…
vs-code-engineering[bot] Sep 21, 2026
3c4f3f8
Merge pull request #337093 from vritant24/agents/mcp-partially-suppor…
vritant24 Sep 21, 2026
2cc2c0b
Fix Agent Host classifier telemetry classification (#336656)
amunger Sep 21, 2026
1aaf9d9
dialogs: Clean up Copilot unstable versions (#337137)
roblourens Sep 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
16 changes: 8 additions & 8 deletions .github/CODENOTIFY
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ src/vs/base/browser/ui/tree/** @benibenj

# Platform
src/vs/platform/agentHost/node/claude/** @TylerLeonhardt
src/vs/platform/agentHost/**/*Automation* @ulugbekna
src/vs/platform/agentHost/**/*automation* @ulugbekna
src/vs/platform/agentHost/common/state/protocol/channels-automation-run/** @ulugbekna
src/vs/platform/agentHost/common/state/protocol/channels-automation/** @ulugbekna
src/vs/platform/agentHost/**/*Automation* @ulugbekna @benvillalobos
src/vs/platform/agentHost/**/*automation* @ulugbekna @benvillalobos
src/vs/platform/agentHost/common/state/protocol/channels-automation-run/** @ulugbekna @benvillalobos
src/vs/platform/agentHost/common/state/protocol/channels-automation/** @ulugbekna @benvillalobos
src/vs/platform/browserView/** @kycutler @jruales
src/vs/platform/quickinput/** @TylerLeonhardt
src/vs/platform/secrets/** @TylerLeonhardt
Expand All @@ -42,12 +42,12 @@ src/vs/workbench/services/views/** @sandy081 @benibenj
# Workbench Contributions
src/vs/workbench/contrib/authentication/** @TylerLeonhardt
src/vs/workbench/contrib/browserView/** @kycutler @jruales
src/vs/workbench/contrib/chat/**/*Automation* @ulugbekna
src/vs/workbench/contrib/chat/**/*automation* @ulugbekna
src/vs/workbench/contrib/chat/**/*Automation* @ulugbekna @benvillalobos
src/vs/workbench/contrib/chat/**/*automation* @ulugbekna @benvillalobos
src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @roblourens
src/vs/workbench/contrib/chat/common/automations/** @ulugbekna
src/vs/workbench/contrib/chat/common/automations/** @ulugbekna @benvillalobos
src/vs/workbench/contrib/chat/electron-browser/builtInTools/fetchPageTool.ts @TylerLeonhardt
src/vs/workbench/contrib/chat/test/common/automations/** @ulugbekna
src/vs/workbench/contrib/chat/test/common/automations/** @ulugbekna @benvillalobos
src/vs/workbench/contrib/localization/** @TylerLeonhardt
src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts @TylerLeonhardt
src/vs/workbench/contrib/scm/** @lszomoru
Expand Down
15 changes: 0 additions & 15 deletions build/npm/postinstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,21 +338,6 @@ async function main() {
log('.', `Created ${claudeSkillsLinkType} .claude/skills -> .agents/skills`);
}

// Temporary: patch @github/copilot-sdk session.js to fix ESM import
// (missing .js extension on vscode-jsonrpc/node). Fixed upstream in v0.1.32.
// TODO: Remove once @github/copilot-sdk is updated to >=0.1.32
for (const dir of ['', 'remote']) {
const sessionFile = path.join(root, dir, 'node_modules', '@github', 'copilot-sdk', 'dist', 'session.js');
if (fs.existsSync(sessionFile)) {
const content = fs.readFileSync(sessionFile, 'utf8');
const patched = content.replace(/from "vscode-jsonrpc\/node"/g, 'from "vscode-jsonrpc/node.js"');
if (content !== patched) {
fs.writeFileSync(sessionFile, patched);
log(dir || '.', 'Patched @github/copilot-sdk session.js (vscode-jsonrpc ESM import fix)');
}
}
}

// foundry-local-sdk (on-device chat dictation) resolves its prebuilt N-API
// addon and native core libraries from fixed, package-relative paths. We do
// not ship that native payload (its addon requires a newer glibc than our
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -848,9 +848,9 @@ describe('ExP Service scoped treatment resolution', () => {
const delegate = service.delegates[0];

// The new assignments endpoint returns the key with a `/vscode/` scope prefix only.
delegate.setTreatment('/vscode/config.chat.copilot.subagentModelGuidance.enabled', true);
delegate.setTreatment('/vscode/config.test.scopedTreatment', true);

expect(service.getTreatmentVariable<boolean>('config.chat.copilot.subagentModelGuidance.enabled')).toBe(true);
expect(service.getTreatmentVariable<boolean>('config.test.scopedTreatment')).toBe(true);

service.dispose();
});
Expand Down
5 changes: 3 additions & 2 deletions extensions/git/src/cloneManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,10 @@ export class CloneManager {
}

private async tryOpenExistingRepository(cachedRepository: RepositoryCacheInfo[], url: string, postCloneAction?: ApiPostCloneAction, parentPath?: string, ref?: string, returnRepositoryPath?: boolean): Promise<string | undefined> {
// Gather existing folders/workspace files (ignore ones that no longer exist)
// Ignore cached entries whose requested path no longer exists.
const existingCachedRepositories: RepositoryCacheInfo[] = (await Promise.all<RepositoryCacheInfo | undefined>(cachedRepository.map(async folder => {
const stat = await fs.promises.stat(folder.workspacePath).catch(() => undefined);
const cachedPath = returnRepositoryPath ? folder.repositoryPath : folder.workspacePath;
const stat = await fs.promises.stat(cachedPath).catch(() => undefined);
if (stat) {
return folder;
}
Expand Down
49 changes: 49 additions & 0 deletions extensions/git/src/test/cloneManager.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import 'mocha';
import * as assert from 'assert';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { CloneManager } from '../cloneManager';
import type { RepositoryCacheInfo } from '../repositoryCache';

interface ICloneManagerHarness {
cloneRepository(url: string, parentPath?: string): Promise<string | undefined>;
}

const tryOpenExistingRepository = Reflect.get(CloneManager.prototype, 'tryOpenExistingRepository') as (
this: ICloneManagerHarness,
cachedRepository: RepositoryCacheInfo[],
url: string,
postCloneAction?: 'none',
parentPath?: string,
ref?: string,
returnRepositoryPath?: boolean,
) => Promise<string | undefined>;

suite('CloneManager', () => {
test('clones again when a cached repository path was deleted', async () => {
const workspacePath = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'vscode-git-clone-manager-'));
const repositoryPath = path.join(workspacePath, 'deleted-repository');
const calls: { url: string; parentPath: string | undefined }[] = [];
try {
const result = await tryOpenExistingRepository.call({
cloneRepository: async (url, parentPath) => {
calls.push({ url, parentPath });
return '/repos/recloned';
},
}, [{ workspacePath, repositoryPath }], 'https://github.com/microsoft/vscode.git', 'none', '/repos', undefined, true);

assert.deepStrictEqual({ result, calls }, {
result: '/repos/recloned',
calls: [{ url: 'https://github.com/microsoft/vscode.git', parentPath: '/repos' }],
});
} finally {
await fs.promises.rm(workspacePath, { recursive: true, force: true });
}
});
});
7 changes: 4 additions & 3 deletions src/vs/base/common/uri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -707,15 +707,16 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string {
}
}
if (path) {
// lower-case windows drive letters in /C:/fff or C:/fff
// HTTP paths are case-sensitive, even when their first segment resembles a drive letter.
const lowerScheme = scheme.toLowerCase();
if (path.length >= 3 && path.charCodeAt(0) === CharCode.Slash && path.charCodeAt(2) === CharCode.Colon) {
const code = path.charCodeAt(1);
if (code >= CharCode.A && code <= CharCode.Z) {
if (code >= CharCode.A && code <= CharCode.Z && lowerScheme !== 'http' && lowerScheme !== 'https') {
path = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // "/c:".length === 3
}
} else if (path.length >= 2 && path.charCodeAt(1) === CharCode.Colon) {
const code = path.charCodeAt(0);
if (code >= CharCode.A && code <= CharCode.Z) {
if (code >= CharCode.A && code <= CharCode.Z && lowerScheme !== 'http' && lowerScheme !== 'https') {
path = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // "/c:".length === 3
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/vs/base/test/common/uri.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,26 @@ suite('URI', () => {
assert.strictEqual(URI.parse('untitled:C:/Users/jrieken/Code/abc.txt').toString(), 'untitled:c%3A/Users/jrieken/Code/abc.txt');
});

test('URI#toString preserves drive-like HTTP path case', () => {
const schemes = ['http', 'https', 'HtTp', 'HTTPS'];
assert.deepStrictEqual(schemes.map(scheme => {
const uri = URI.parse(`${scheme}://example.test/C:/Secret`);
return [uri.toString(), uri.toString(true), URI.parse(uri.toString()).toString(true)];
}), schemes.map(scheme => [
`${scheme}://example.test/C%3A/Secret`,
`${scheme}://example.test/C:/Secret`,
`${scheme}://example.test/C:/Secret`,
]));
});

test('URI#toString retains non-HTTP drive-letter normalization', () => {
const schemes = ['file', 'untitled', 'vscode-remote', 'custom'];
assert.deepStrictEqual(
schemes.map(scheme => URI.parse(`${scheme}://server/C:/Secret`).toString(true)),
schemes.map(scheme => `${scheme}://server/c:/Secret`),
);
});

test('URI#toString, escape all the bits', () => {

const value = URI.file('/Users/jrieken/Code/_samples/18500/Mödel + Other Thîngß/model.js');
Expand Down
3 changes: 3 additions & 0 deletions src/vs/platform/agentHost/browser/agentHostProtocolClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,9 @@ export class AgentHostProtocolClient extends Disposable implements IAgentConnect
await this._sendRequest('createChat', {
channel: session.toString(),
chat: chat.toString(),
...(options?.workingDirectories !== undefined && !options.fork
? { workingDirectories: options.workingDirectories.map(directory => fromAgentHostUri(directory).toString()) }
: {}),
...(options?.fork ? {
source: { kind: ChatSourceKind.Fork, chat: options.fork.source.toString(), turnId: options.fork.turnId }
} : {}),
Expand Down
10 changes: 0 additions & 10 deletions src/vs/platform/agentHost/common/copilotCliConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ export const enum CopilotCliConfigKey {
SkillCharBudget = 'skillCharBudget',
/** Override Auto's "Optimize for" preference. */
AutoModeTierOverride = 'autoModeTierOverride',
/** 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',
}
Expand Down Expand Up @@ -71,8 +69,6 @@ export const CopilotSkillCharBudgetSettingId = 'chat.copilot.skillCharBudget';

export const CopilotAutoModeTierOverrideSettingId = 'github.copilot.chat.autoModeTierOverride';

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

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

Expand Down Expand Up @@ -216,12 +212,6 @@ export const copilotCliConfigSchema = createSchema({
description: localize('agentHost.config.autoModeTierOverride.description', "Overrides Auto's \"Optimize for\" preference. Accepts efficiency, balance, or intelligence. Applied when a session is created or resumed and when its model changes. Empty or unsupported values use the picker or service defaults."),
default: '',
}),
[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
11 changes: 6 additions & 5 deletions src/vs/platform/agentHost/node/agentHostCatalogProjection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,11 @@ const metadataValidator = plainObject(vObj({
[AH_META_DEV_CONTAINER_WORKTREE_DB_KEY]: vOptionalProp(devContainerWorktreeValidator),
}));

const workingDirectoriesValidator = new RefinedValidator(
boundedArray(uriString(), AGENT_HOST_CATALOG_CHILD_LIMIT),
value => hasUniqueValues(value, directory => directory) ? value : { message: 'Working directories must be unique.' },
);

const chatValidator = plainObject(vObj({
uri: uriString(),
order: safeInteger(),
Expand All @@ -307,6 +312,7 @@ const chatValidator = plainObject(vObj({
titleSource: vOptionalProp(vEnum('user', 'agent', 'auto')),
origin: vOptionalProp(jsonValue()),
inheritedTurnId: vOptionalProp(boundedString(AGENT_HOST_CATALOG_JSON_STRING_LENGTH_LIMIT)),
workingDirectories: vOptionalProp(workingDirectoriesValidator),
}));

const chatsValidator = new RefinedValidator(
Expand All @@ -323,11 +329,6 @@ const chatsValidator = new RefinedValidator(
},
);

const workingDirectoriesValidator = new RefinedValidator(
boundedArray(uriString(), AGENT_HOST_CATALOG_CHILD_LIMIT),
value => hasUniqueValues(value, directory => directory) ? value : { message: 'Working directories must be unique.' },
);

export const agentHostCatalogDataValidator = plainObject(vObj({
modifiedTime: safeInteger(),
summary: vOptionalProp(boundedString(AGENT_HOST_CATALOG_TITLE_LENGTH_LIMIT)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface ICatalogSourceState {
readonly title?: string;
readonly origin?: ChatOrigin;
readonly inheritedTurnId?: string;
readonly workingDirectories?: readonly string[];
}[];
}

Expand Down Expand Up @@ -225,6 +226,7 @@ export class AgentHostCatalogSourceResolver {
titleSource: normalizeCatalogTitleSource(titleSource),
origin: toCatalogChatOrigin(chat.origin),
...(chat.inheritedTurnId !== undefined ? { inheritedTurnId: chat.inheritedTurnId } : {}),
...(chat.workingDirectories !== undefined ? { workingDirectories: chat.workingDirectories } : {}),
};
}),
};
Expand Down
Loading