Add proposed API support for agent sessions workspace (#290385)

* Add proposed API support for agent sessions workspace

* add access to agentSessionsWorkspace proposed api
This commit is contained in:
Sandeep Somavarapu
2026-01-26 17:05:36 +01:00
committed by GitHub
parent 05c127e30e
commit d4d37b83e0
15 changed files with 63 additions and 24 deletions

View File

@@ -54,7 +54,8 @@
"workspaceTrust",
"inlineCompletionsAdditions",
"devDeviceId",
"languageModelProxy"
"languageModelProxy",
"agentSessionsWorkspace"
],
"private": true,
"activationEvents": [],

View File

@@ -9,6 +9,9 @@ const _allApiProposals = {
activeComment: {
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.activeComment.d.ts',
},
agentSessionsWorkspace: {
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.agentSessionsWorkspace.d.ts',
},
aiRelatedInformation: {
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.aiRelatedInformation.d.ts',
},

View File

@@ -281,6 +281,11 @@ export interface IWorkspace {
* the location of the workspace configuration
*/
readonly configuration?: URI | null;
/**
* Whether this workspace is an agent sessions workspace.
*/
readonly isAgentSessionsWorkspace?: boolean;
}
export function isWorkspace(thing: unknown): thing is IWorkspace {
@@ -344,6 +349,7 @@ export class Workspace implements IWorkspace {
private _transient: boolean,
private _configuration: URI | null,
private ignorePathCasing: (key: URI) => boolean,
private _isAgentSessionsWorkspace?: boolean,
) {
this.foldersMap = TernarySearchTree.forUris<WorkspaceFolder>(this.ignorePathCasing, () => true);
this.folders = folders;
@@ -354,6 +360,7 @@ export class Workspace implements IWorkspace {
this._configuration = workspace.configuration;
this._transient = workspace.transient;
this.ignorePathCasing = workspace.ignorePathCasing;
this._isAgentSessionsWorkspace = workspace.isAgentSessionsWorkspace;
this.folders = workspace.folders;
}
@@ -373,6 +380,10 @@ export class Workspace implements IWorkspace {
this._configuration = configuration;
}
get isAgentSessionsWorkspace(): boolean | undefined {
return this._isAgentSessionsWorkspace;
}
getFolder(resource: URI): IWorkspaceFolder | null {
if (!resource) {
return null;
@@ -389,7 +400,7 @@ export class Workspace implements IWorkspace {
}
toJSON(): IWorkspace {
return { id: this.id, folders: this.folders, transient: this.transient, configuration: this.configuration };
return { id: this.id, folders: this.folders, transient: this.transient, configuration: this.configuration, isAgentSessionsWorkspace: this.isAgentSessionsWorkspace };
}
}

View File

@@ -138,7 +138,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
folders: workspace.folders,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace),
transient: workspace.transient
transient: workspace.transient,
isAgentSessionsWorkspace: workspace.isAgentSessionsWorkspace
};
}

View File

@@ -1009,6 +1009,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
set workspaceFile(value) {
throw new errors.ReadonlyError('workspaceFile');
},
get isAgentSessionsWorkspace() {
checkProposedApiEnabled(extension, 'agentSessionsWorkspace');
return extHostWorkspace.isAgentSessionsWorkspace;
},
updateWorkspaceFolders: (index, deleteCount, ...workspaceFoldersToAdd) => {
return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd);
},

View File

@@ -95,7 +95,7 @@ class ExtHostWorkspaceImpl extends Workspace {
return { workspace: null, added: [], removed: [] };
}
const { id, name, folders, configuration, transient, isUntitled } = data;
const { id, name, folders, configuration, transient, isUntitled, isAgentSessionsWorkspace } = data;
const newWorkspaceFolders: vscode.WorkspaceFolder[] = [];
// If we have an existing workspace, we try to find the folders that match our
@@ -123,7 +123,7 @@ class ExtHostWorkspaceImpl extends Workspace {
// make sure to restore sort order based on index
newWorkspaceFolders.sort((f1, f2) => f1.index < f2.index ? -1 : 1);
const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders, !!transient, configuration ? URI.revive(configuration) : null, !!isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo));
const workspace = new ExtHostWorkspaceImpl(id, name, newWorkspaceFolders, !!transient, configuration ? URI.revive(configuration) : null, !!isUntitled, !!isAgentSessionsWorkspace, uri => ignorePathCasing(uri, extHostFileSystemInfo));
const { added, removed } = delta(oldWorkspace ? oldWorkspace.workspaceFolders : [], workspace.workspaceFolders, compareWorkspaceFolderByUri, extHostFileSystemInfo);
return { workspace, added, removed };
@@ -143,8 +143,8 @@ class ExtHostWorkspaceImpl extends Workspace {
private readonly _workspaceFolders: vscode.WorkspaceFolder[] = [];
private readonly _structure: TernarySearchTree<URI, vscode.WorkspaceFolder>;
constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[], transient: boolean, configuration: URI | null, private _isUntitled: boolean, ignorePathCasing: (key: URI) => boolean) {
super(id, folders.map(f => new WorkspaceFolder(f)), transient, configuration, ignorePathCasing);
constructor(id: string, private _name: string, folders: vscode.WorkspaceFolder[], transient: boolean, configuration: URI | null, private _isUntitled: boolean, isAgentSessionsWorkspace: boolean, ignorePathCasing: (key: URI) => boolean) {
super(id, folders.map(f => new WorkspaceFolder(f)), transient, configuration, ignorePathCasing, isAgentSessionsWorkspace);
this._structure = TernarySearchTree.forUris<vscode.WorkspaceFolder>(ignorePathCasing, () => true);
// setup the workspace folder data structure
@@ -223,7 +223,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
this._proxy = extHostRpc.getProxy(MainContext.MainThreadWorkspace);
this._messageService = extHostRpc.getProxy(MainContext.MainThreadMessageService);
const data = initData.workspace;
this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], !!data.transient, data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo)) : undefined;
this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], !!data.transient, data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled, !!data.isAgentSessionsWorkspace, uri => ignorePathCasing(uri, extHostFileSystemInfo)) : undefined;
}
$initializeWorkspace(data: IWorkspaceData | null, trusted: boolean): void {
@@ -246,6 +246,10 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
return this._actualWorkspace ? this._actualWorkspace.name : undefined;
}
get isAgentSessionsWorkspace(): boolean {
return this._actualWorkspace?.isAgentSessionsWorkspace ?? false;
}
get workspaceFile(): vscode.Uri | undefined {
if (this._actualWorkspace) {
if (this._actualWorkspace.configuration) {

View File

@@ -95,7 +95,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
this.virtualWorkspaceContext = VirtualWorkspaceContext.bindTo(this.contextKeyService);
this.temporaryWorkspaceContext = TemporaryWorkspaceContext.bindTo(this.contextKeyService);
this.isAgentSessionsWorkspaceContext = IsAgentSessionsWorkspaceContext.bindTo(this.contextKeyService);
this.isAgentSessionsWorkspaceContext.set(!!this.environmentService.agentSessionsWindow);
this.isAgentSessionsWorkspaceContext.set(!!this.contextService.getWorkspace().isAgentSessionsWorkspace);
this.updateWorkspaceContextKeys();
// Capabilities

View File

@@ -78,7 +78,7 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
this.hasProfilesContext.set(this.userDataProfilesService.profiles.length > 1);
this._register(this.userDataProfilesService.onDidChangeProfiles(e => this.hasProfilesContext.set(this.userDataProfilesService.profiles.length > 1)));
if (!this.environmentService.agentSessionsWindow) {
if (!this.workspaceContextService.getWorkspace().isAgentSessionsWorkspace) {
this.registerEditor();
this.registerActions();
@@ -91,8 +91,8 @@ export class UserDataProfilesWorkbenchContribution extends Disposable implements
this.reportWorkspaceProfileInfo();
if (environmentService.options?.profileToPreview) {
lifecycleService.when(LifecyclePhase.Restored).then(() => this.handleURL(URI.revive(environmentService.options!.profileToPreview!)));
if (this.environmentService.options?.profileToPreview) {
lifecycleService.when(LifecyclePhase.Restored).then(() => this.handleURL(URI.revive(this.environmentService.options!.profileToPreview!)));
}
this.registerDropHandler();

View File

@@ -109,7 +109,7 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
constructor(
{ remoteAuthority, configurationCache }: { remoteAuthority?: string; configurationCache: IConfigurationCache },
environmentService: IBrowserWorkbenchEnvironmentService,
private readonly environmentService: IBrowserWorkbenchEnvironmentService,
private readonly userDataProfileService: IUserDataProfileService,
private readonly userDataProfilesService: IUserDataProfilesService,
private readonly fileService: IFileService,
@@ -519,7 +519,8 @@ export class WorkspaceService extends Disposable implements IWorkbenchConfigurat
const workspaceConfigPath = workspaceIdentifier.configPath;
const workspaceFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), workspaceConfigPath, this.uriIdentityService.extUri);
const workspaceId = workspaceIdentifier.id;
const workspace = new Workspace(workspaceId, workspaceFolders, this.workspaceConfiguration.isTransient(), workspaceConfigPath, uri => this.uriIdentityService.extUri.ignorePathCasing(uri));
const isAgentSessionsWorkspace = this.uriIdentityService.extUri.isEqual(workspaceConfigPath, this.environmentService.agentSessionsWorkspace);
const workspace = new Workspace(workspaceId, workspaceFolders, this.workspaceConfiguration.isTransient(), workspaceConfigPath, uri => this.uriIdentityService.extUri.ignorePathCasing(uri), isAgentSessionsWorkspace);
workspace.initialized = this.workspaceConfiguration.initialized;
return workspace;
}

View File

@@ -36,7 +36,6 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService {
readonly skipWelcome: boolean;
readonly disableWorkspaceTrust: boolean;
readonly webviewExternalEndpoint: string;
readonly agentSessionsWindow?: boolean;
// --- Development
readonly debugRenderer: boolean;

View File

@@ -13,9 +13,8 @@ import { memoize } from '../../../../base/common/decorators.js';
import { URI } from '../../../../base/common/uri.js';
import { Schemas } from '../../../../base/common/network.js';
import { IProductService } from '../../../../platform/product/common/productService.js';
import { isEqual, joinPath } from '../../../../base/common/resources.js';
import { joinPath } from '../../../../base/common/resources.js';
import { VSBuffer } from '../../../../base/common/buffer.js';
import { isWorkspaceIdentifier } from '../../../../platform/workspace/common/workspace.js';
export const INativeWorkbenchEnvironmentService = refineServiceDecorator<IEnvironmentService, INativeWorkbenchEnvironmentService>(IEnvironmentService);
@@ -152,11 +151,6 @@ export class NativeWorkbenchEnvironmentService extends AbstractNativeEnvironment
@memoize
get filesToWait(): IPathsToWaitFor | undefined { return this.configuration.filesToWait; }
@memoize
get agentSessionsWindow(): boolean | undefined {
return isWorkspaceIdentifier(this.configuration.workspace) && isEqual(this.configuration.workspace.configPath, this.agentSessionsWorkspace);
}
constructor(
private readonly configuration: INativeWindowConfiguration,
productService: IProductService

View File

@@ -324,7 +324,8 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
configuration: workspace.configuration || undefined,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace),
transient: workspace.transient
transient: workspace.transient,
isAgentSessionsWorkspace: workspace.isAgentSessionsWorkspace
},
consoleForward: {
includeStack: false,

View File

@@ -83,6 +83,7 @@ export interface IStaticWorkspaceData {
transient?: boolean;
configuration?: UriComponents | null;
isUntitled?: boolean | null;
isAgentSessionsWorkspace?: boolean;
}
export interface MessagePortLike {

View File

@@ -495,7 +495,8 @@ export class NativeLocalProcessExtensionHost extends Disposable implements IExte
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace),
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false,
transient: workspace.transient
transient: workspace.transient,
isAgentSessionsWorkspace: workspace.isAgentSessionsWorkspace
},
remote: {
authority: this._environmentService.remoteAuthority,

View File

@@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'vscode' {
export namespace workspace {
/**
* Indicates whether the current workspace is an agent sessions workspace.
*
* Agent sessions workspace is a special workspace used for AI agent interactions
* where the window is dedicated to agent session management.
*/
export const isAgentSessionsWorkspace: boolean;
}
}