From d32199071db61e503c7e91f21653180a162172c0 Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 29 May 2026 21:30:23 +0200 Subject: [PATCH 1/2] feat: add getWorkingDirectory method to agent host session providers and related services for distiguishing local from user customizations + several bug fixes --- .../common/agentHostSessionsProvider.ts | 5 ++ .../browser/baseAgentHostSessionsProvider.ts | 5 ++ ...emoteAgentHostCustomizationHarness.test.ts | 3 + .../browser/agentHostCustomizationService.ts | 58 +++++++++++++------ .../agentCustomizationItemProvider.ts | 6 +- .../agentHostCustomizationService.ts | 10 ++++ .../agentHost/agentHostLocalCustomizations.ts | 3 +- 7 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/vs/sessions/common/agentHostSessionsProvider.ts b/src/vs/sessions/common/agentHostSessionsProvider.ts index e7bd5df693430..eca1153d9b83b 100644 --- a/src/vs/sessions/common/agentHostSessionsProvider.ts +++ b/src/vs/sessions/common/agentHostSessionsProvider.ts @@ -120,6 +120,11 @@ export interface IAgentHostSessionsProvider extends ISessionsProvider { */ getCustomizations(sessionId: string): readonly Customization[]; + /** + * Returns the working directory for the session, if provided by the host. + */ + getWorkingDirectory(sessionId: string): string | undefined; + /** * Set (or clear) the selected custom agent for a session. Optional so * providers that don't expose custom agents can omit it. diff --git a/src/vs/sessions/contrib/providers/agentHost/browser/baseAgentHostSessionsProvider.ts b/src/vs/sessions/contrib/providers/agentHost/browser/baseAgentHostSessionsProvider.ts index 9388880b2ccc5..0e7f5c82b2302 100644 --- a/src/vs/sessions/contrib/providers/agentHost/browser/baseAgentHostSessionsProvider.ts +++ b/src/vs/sessions/contrib/providers/agentHost/browser/baseAgentHostSessionsProvider.ts @@ -1687,6 +1687,11 @@ export abstract class BaseAgentHostSessionsProvider extends Disposable implement return sessionState?.customizations ?? []; } + getWorkingDirectory(sessionId: string): string | undefined { + const sessionState = this._lastSessionStates.get(sessionId); + return sessionState?.summary.workingDirectory; + } + // -- Session actions ------------------------------------------------------ async archiveSession(sessionId: string): Promise { diff --git a/src/vs/sessions/contrib/providers/remoteAgentHost/test/browser/remoteAgentHostCustomizationHarness.test.ts b/src/vs/sessions/contrib/providers/remoteAgentHost/test/browser/remoteAgentHostCustomizationHarness.test.ts index 5cbd89d9a46c3..2c01c653b3cb7 100644 --- a/src/vs/sessions/contrib/providers/remoteAgentHost/test/browser/remoteAgentHostCustomizationHarness.test.ts +++ b/src/vs/sessions/contrib/providers/remoteAgentHost/test/browser/remoteAgentHostCustomizationHarness.test.ts @@ -150,6 +150,9 @@ function createTestCustomAgentsService(connection: MockAgentConnection, rootCust } return [...rootCustomizations, ...(sessionState.customizations ?? [])]; }, + getWorkingDirectory(sessionResource: URI): string | undefined { + return undefined; + } }; } diff --git a/src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts b/src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts index 043befb62263b..f177041815c19 100644 --- a/src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts +++ b/src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts @@ -14,6 +14,7 @@ import { ISessionsProvidersService } from '../../sessions/browser/sessionsProvid import { ISessionsManagementService } from '../../sessions/common/sessionsManagement.js'; import { ISessionsProvider } from '../../sessions/common/sessionsProvider.js'; import { AgentCustomization, Customization, CustomizationType } from '../../../../platform/agentHost/common/state/sessionState.js'; +import { ISession } from '../../sessions/common/session.js'; export class AgentHostCustomizationService extends Disposable implements IAgentHostCustomizationService { declare readonly _serviceBrand: undefined; @@ -34,37 +35,56 @@ export class AgentHostCustomizationService extends Disposable implements IAgentH })); } - getCustomAgents(sessionResource: URI): readonly AgentCustomization[] { - const session = this._sessionsManagementService.activeSession.get(); - if (!session || session.resource.toString() !== sessionResource.toString()) { - return []; + private _getSession(sessionResource: URI): ISession | undefined { + const activeSession = this._sessionsManagementService.activeSession.get(); + if (activeSession && activeSession.resource.toString() === sessionResource.toString()) { + return activeSession; } + return this._sessionsManagementService.getSession(sessionResource); + } + private _getAHSProvider(session: ISession): IAgentHostSessionsProvider | undefined { const provider = this._sessionsProvidersService.getProvider(session.providerId); if (provider && isAgentHostProvider(provider)) { this._ensureProviderListener(provider); - const agents = provider.getCustomAgents(session.sessionId); - const activeMode = session.mode.get()?.id; - const result = agents.length === 0 && activeMode ? [this._agentFromMode(activeMode)] : agents; - return result; + return provider; } + return undefined; + } + getCustomAgents(sessionResource: URI): readonly AgentCustomization[] { + const session = this._getSession(sessionResource); + if (session) { + const provider = this._getAHSProvider(session); + if (provider) { + const agents = provider.getCustomAgents(session.sessionId); + const activeMode = session.mode.get()?.id; + return agents.length === 0 && activeMode ? [this._agentFromMode(activeMode)] : agents; + } + } return []; } getCustomizations(sessionResource: URI): readonly Customization[] { - const session = this._sessionsManagementService.getSession(sessionResource); - if (!session) { - return []; + const session = this._getSession(sessionResource); + if (session) { + const provider = this._getAHSProvider(session); + if (provider) { + return provider.getCustomizations(session.sessionId); + } } + return []; + } - const provider = this._sessionsProvidersService.getProvider(session.providerId); - if (provider && isAgentHostProvider(provider)) { - this._ensureProviderListener(provider); - return provider.getCustomizations(session.sessionId); + getWorkingDirectory(sessionResource: URI): string | undefined { + const session = this._getSession(sessionResource); + if (session) { + const provider = this._getAHSProvider(session); + if (provider) { + return provider.getWorkingDirectory(session.sessionId); + } } - - return []; + return undefined; } @@ -76,6 +96,10 @@ export class AgentHostCustomizationService extends Disposable implements IAgentH this._providerListeners.set(provider, provider.onDidChangeCustomAgents(() => { this._onDidChangeCustomAgents.fire(); })); + + this._providerListeners.set(provider, provider.onDidChangeCustomizations(() => { + this._onDidChangeCustomizations.fire(); + })); } private _agentFromMode(uri: string): AgentCustomization { diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentCustomizationItemProvider.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentCustomizationItemProvider.ts index 117d38c03ab17..eeab0f9015b2e 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentCustomizationItemProvider.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentCustomizationItemProvider.ts @@ -204,9 +204,11 @@ export class AgentCustomizationItemProvider extends Disposable implements ICusto } } + const workingDirectory = this._customAgentsService.getWorkingDirectory(sessionResource); + for (const sessionCustomization of directoryCustomizations) { - const source = AICustomizationSources.local; // TODO - const groupKey = undefined; //sessionCustomization.clientId ? REMOTE_CLIENT_GROUP : REMOTE_HOST_GROUP; + const source = workingDirectory && sessionCustomization.uri.startsWith(workingDirectory) ? AICustomizationSources.local : AICustomizationSources.user; + const groupKey = sessionCustomization.clientId ? REMOTE_CLIENT_GROUP : undefined; for (const child of this.toDirectoryItems(sessionCustomization, source, groupKey)) { items.set(child.itemKey ?? child.uri.toString(), { ...child, diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCustomizationService.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCustomizationService.ts index 049d05b732262..2314cfd4c7a85 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCustomizationService.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCustomizationService.ts @@ -30,6 +30,8 @@ export interface IAgentHostCustomizationService { getCustomAgents(sessionResource: URI): readonly AgentCustomization[]; getCustomizations(sessionResource: URI): readonly Customization[]; + + getWorkingDirectory(sessionResource: URI): string | undefined; } export class NullAgentHostCustomizationService implements IAgentHostCustomizationService { @@ -42,6 +44,9 @@ export class NullAgentHostCustomizationService implements IAgentHostCustomizatio getCustomizations(_sessionResource: URI): readonly Customization[] { return []; } + getWorkingDirectory(sessionResource: URI): string | undefined { + return undefined; + } } class WorkbenchAgentHostCustomizationService extends Disposable implements IAgentHostCustomizationService { @@ -101,6 +106,11 @@ class WorkbenchAgentHostCustomizationService extends Disposable implements IAgen return sessionState?.customizations ?? []; } + getWorkingDirectory(sessionResource: URI): string | undefined { + const sessionState = this._readSessionState(sessionResource); + return sessionState?.summary.workingDirectory; + } + private _readSessionState(sessionResource: URI): SessionState | undefined { const backendSession = this._resolveBackendSession(sessionResource); const value = backendSession ? this._ensureSessionStateSubscription(sessionResource, backendSession)?.sub.value : undefined; diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts index 13f9d55fc8283..5b7d936293daf 100644 --- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts +++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostLocalCustomizations.ts @@ -35,8 +35,7 @@ export const SYNCABLE_PROMPT_TYPES: readonly PromptsType[] = [ */ export const SYNCABLE_STORAGE_SOURCES: readonly PromptsStorage[] = [ PromptsStorage.plugin, - PromptsStorage.extension, - PromptsStorage.user, + PromptsStorage.extension ]; export interface ILocalCustomizationFile { From 24abb09e08798faa6a85c0c2bb39249ce3a9c0bb Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Fri, 29 May 2026 22:24:58 +0200 Subject: [PATCH 2/2] update --- .../browser/agentHostCustomizationService.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts b/src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts index f177041815c19..2919dae171c11 100644 --- a/src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts +++ b/src/vs/sessions/services/agentHost/browser/agentHostCustomizationService.ts @@ -5,7 +5,7 @@ import { URI } from '../../../../base/common/uri.js'; import { Emitter, Event } from '../../../../base/common/event.js'; -import { Disposable, DisposableMap } from '../../../../base/common/lifecycle.js'; +import { combinedDisposable, Disposable, DisposableMap } from '../../../../base/common/lifecycle.js'; import { basename } from '../../../../base/common/resources.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { IAgentHostCustomizationService } from '../../../../workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCustomizationService.js'; @@ -93,13 +93,15 @@ export class AgentHostCustomizationService extends Disposable implements IAgentH return; } - this._providerListeners.set(provider, provider.onDidChangeCustomAgents(() => { - this._onDidChangeCustomAgents.fire(); - })); - - this._providerListeners.set(provider, provider.onDidChangeCustomizations(() => { - this._onDidChangeCustomizations.fire(); - })); + // Keep both subscriptions alive under one map key so replacing the provider entry disposes both together. + this._providerListeners.set(provider, combinedDisposable( + provider.onDidChangeCustomAgents(() => { + this._onDidChangeCustomAgents.fire(); + }), + provider.onDidChangeCustomizations(() => { + this._onDidChangeCustomizations.fire(); + }) + )); } private _agentFromMode(uri: string): AgentCustomization {