From 3cbeadf596c0fcdbe8a150f078b2765272ec9acb Mon Sep 17 00:00:00 2001 From: Matt Bierner <12821956+mjbvz@users.noreply.github.com> Date: Wed, 18 Mar 2026 15:21:13 -0700 Subject: [PATCH] Update more references --- .../contrib/chat/browser/newSession.ts | 33 +++++++------------ .../api/browser/mainThreadChatAgents2.ts | 5 +-- .../api/browser/mainThreadChatSessions.ts | 4 +-- .../workbench/api/common/extHost.protocol.ts | 6 ++-- .../api/common/extHostChatSessions.ts | 2 +- .../browser/mainThreadChatSessions.test.ts | 6 ++-- .../chatSessions/chatSessions.contribution.ts | 2 +- .../browser/widget/input/chatInputPart.ts | 12 ++----- .../chat/common/chatService/chatService.ts | 3 +- .../chat/common/chatSessionsService.ts | 10 +++--- .../test/common/mockChatSessionsService.ts | 6 ++-- 11 files changed, 36 insertions(+), 53 deletions(-) diff --git a/src/vs/sessions/contrib/chat/browser/newSession.ts b/src/vs/sessions/contrib/chat/browser/newSession.ts index 06ac91248a2..5d96087d85f 100644 --- a/src/vs/sessions/contrib/chat/browser/newSession.ts +++ b/src/vs/sessions/contrib/chat/browser/newSession.ts @@ -51,7 +51,7 @@ export interface INewSession extends IDisposable { setMode(mode: IChatMode | undefined): void; setQuery(query: string): void; setAttachedContext(context: IChatRequestVariableEntry[] | undefined): void; - setOption(optionId: string, value: IChatSessionProviderOptionItem | string): void; + setOption(optionId: string, value: IChatSessionProviderOptionItem): void; } const REPOSITORY_OPTION_ID = 'repository'; @@ -107,10 +107,10 @@ export class CopilotCLISession extends Disposable implements INewSession { super(); if (defaultRepoUri) { this._repoUri = defaultRepoUri; - this.setOption(REPOSITORY_OPTION_ID, defaultRepoUri.fsPath); + this.setOption(REPOSITORY_OPTION_ID, { id: defaultRepoUri.fsPath, name: defaultRepoUri.fsPath }); } this._isolationMode = 'worktree'; - this.setOption(ISOLATION_OPTION_ID, 'worktree'); + this.setOption(ISOLATION_OPTION_ID, { id: 'worktree', name: 'worktree' }); } setProject(project: SessionWorkspace): void { @@ -120,7 +120,7 @@ export class CopilotCLISession extends Disposable implements INewSession { this._branch = undefined; this._onDidChange.fire('repoUri'); this._onDidChange.fire('disabled'); - this.setOption(REPOSITORY_OPTION_ID, project.uri.fsPath); + this.setOption(REPOSITORY_OPTION_ID, { id: project.uri.fsPath, name: project.uri.fsPath }); } setIsolationMode(mode: IsolationMode): void { @@ -128,7 +128,7 @@ export class CopilotCLISession extends Disposable implements INewSession { this._isolationMode = mode; this._onDidChange.fire('isolationMode'); this._onDidChange.fire('disabled'); - this.setOption(ISOLATION_OPTION_ID, mode); + this.setOption(ISOLATION_OPTION_ID, { id: mode, name: mode }); } } @@ -137,7 +137,7 @@ export class CopilotCLISession extends Disposable implements INewSession { this._branch = branch; this._onDidChange.fire('branch'); this._onDidChange.fire('disabled'); - this.setOption(BRANCH_OPTION_ID, branch ?? ''); + this.setOption(BRANCH_OPTION_ID, { id: branch ?? '', name: branch ?? '' }); } } @@ -150,7 +150,7 @@ export class CopilotCLISession extends Disposable implements INewSession { this._mode = mode; this._onDidChange.fire('agent'); const modeName = mode?.isBuiltin ? undefined : mode?.name.get(); - this.setOption(AGENT_OPTION_ID, modeName ?? ''); + this.setOption(AGENT_OPTION_ID, { id: mode?.id ?? '', name: modeName ?? '' }); } } @@ -162,12 +162,8 @@ export class CopilotCLISession extends Disposable implements INewSession { this._attachedContext = context; } - setOption(optionId: string, value: IChatSessionProviderOptionItem | string): void { - if (typeof value === 'string') { - this.selectedOptions.set(optionId, { id: value, name: value }); - } else { - this.selectedOptions.set(optionId, value); - } + setOption(optionId: string, value: IChatSessionProviderOptionItem): void { + this.selectedOptions.set(optionId, value); this.chatSessionsService.notifySessionOptionsChange( this.resource, [{ optionId, value }] @@ -266,7 +262,7 @@ export class RemoteNewSession extends Disposable implements INewSession { this._attachedContext = context; } - setOption(optionId: string, value: IChatSessionProviderOptionItem | string): void { + setOption(optionId: string, value: IChatSessionProviderOptionItem): void { if (typeof value !== 'string') { this.selectedOptions.set(optionId, value); } @@ -349,15 +345,10 @@ export class RemoteNewSession extends Disposable implements INewSession { } // Check for extension-set session option const sessionOption = this.chatSessionsService.getSessionOption(this.resource, group.id); - if (sessionOption && typeof sessionOption !== 'string') { + if (sessionOption) { return sessionOption; } - if (typeof sessionOption === 'string') { - const item = group.items.find(i => i.id === sessionOption.trim()); - if (item) { - return item; - } - } + // Default to first item marked as default, or first item return group.items.find(i => i.default === true) ?? group.items[0]; } diff --git a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts index f40d952f332..4fcb6ee57db 100644 --- a/src/vs/workbench/api/browser/mainThreadChatAgents2.ts +++ b/src/vs/workbench/api/browser/mainThreadChatAgents2.ts @@ -253,10 +253,7 @@ export class MainThreadChatAgents2 extends Disposable implements MainThreadChatA chatSessionContext = { chatSessionResource, isUntitled, - initialSessionOptions: contributedSession.initialSessionOptions?.map(o => ({ - optionId: o.optionId, - value: typeof o.value === 'string' ? o.value : o.value.id, - })), + initialSessionOptions: contributedSession.initialSessionOptions, }; } return await this._proxy.$invokeAgent(handle, request, { diff --git a/src/vs/workbench/api/browser/mainThreadChatSessions.ts b/src/vs/workbench/api/browser/mainThreadChatSessions.ts index 8051f213589..021bf6fa172 100644 --- a/src/vs/workbench/api/browser/mainThreadChatSessions.ts +++ b/src/vs/workbench/api/browser/mainThreadChatSessions.ts @@ -546,7 +546,7 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat controller.addOrUpdateItem(resolvedItem); } - $onDidChangeChatSessionOptions(handle: number, sessionResourceComponents: UriComponents, updates: ReadonlyArray<{ optionId: string; value: string }>): void { + $onDidChangeChatSessionOptions(handle: number, sessionResourceComponents: UriComponents, updates: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem }>): void { const sessionResource = URI.revive(sessionResourceComponents); warnOnUntitledSessionResource(sessionResource, this._logService); this._chatSessionsService.notifySessionOptionsChange(sessionResource, updates); @@ -850,7 +850,7 @@ export class MainThreadChatSessions extends Disposable implements MainThreadChat /** * Notify the extension about option changes for a session */ - async notifyOptionsChange(handle: number, sessionResource: URI, updates: ReadonlyArray<{ optionId: string; value: string | IChatSessionProviderOptionItem | undefined }>): Promise { + async notifyOptionsChange(handle: number, sessionResource: URI, updates: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem | undefined }>): Promise { this._logService.trace(`[MainThreadChatSessions] notifyOptionsChange: starting proxy call for handle ${handle}, sessionResource ${sessionResource}`); try { await this._proxy.$provideHandleOptionsChange(handle, sessionResource, updates, CancellationToken.None); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 35249b9341d..a1a2daa57ea 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1639,7 +1639,7 @@ export type IChatAgentHistoryEntryDto = { export interface IChatSessionContextDto { readonly chatSessionResource: UriComponents; readonly isUntitled: boolean; - readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: string }>; + readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem }>; } export interface ExtHostChatAgentsShape2 { @@ -3594,12 +3594,12 @@ export type IChatSessionRequestHistoryItemDto = Extract, token: CancellationToken): Promise { + async $provideHandleOptionsChange(handle: number, sessionResourceComponents: UriComponents, updates: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem | undefined }>, token: CancellationToken): Promise { const sessionResource = URI.revive(sessionResourceComponents); const provider = this._chatSessionContentProviders.get(handle); if (!provider) { diff --git a/src/vs/workbench/api/test/browser/mainThreadChatSessions.test.ts b/src/vs/workbench/api/test/browser/mainThreadChatSessions.test.ts index 711a0be02aa..596b996c0b3 100644 --- a/src/vs/workbench/api/test/browser/mainThreadChatSessions.test.ts +++ b/src/vs/workbench/api/test/browser/mainThreadChatSessions.test.ts @@ -764,7 +764,7 @@ suite('MainThreadChatSessions', function () { // Simulate an option change await chatSessionsService.notifySessionOptionsChange(resource, [ - { optionId: 'models', value: 'gpt-4-turbo' } + { optionId: 'models', value: { name: 'gpt-4-turbo', id: 'gpt-4-turbo' } } ]); // Verify the extension was notified @@ -772,7 +772,7 @@ suite('MainThreadChatSessions', function () { const call = (proxy.$provideHandleOptionsChange as sinon.SinonStub).firstCall; assert.strictEqual(call.args[0], handle); assert.deepStrictEqual(call.args[1], resource); - assert.deepStrictEqual(call.args[2], [{ optionId: 'models', value: 'gpt-4-turbo' }]); + assert.deepStrictEqual(call.args[2], [{ optionId: 'models', value: { name: 'gpt-4-turbo', id: 'gpt-4-turbo' } }]); mainThread.$unregisterChatSessionContentProvider(handle); }); @@ -790,7 +790,7 @@ suite('MainThreadChatSessions', function () { // Attempt to notify option change for an unregistered scheme // This should not throw, but also should not call the proxy await chatSessionsService.notifySessionOptionsChange(resource, [ - { optionId: 'models', value: 'gpt-4-turbo' } + { optionId: 'models', value: { name: 'gpt-4-turbo', id: 'gpt-4-turbo' } } ]); // Verify the extension was NOT notified (no provider registered) diff --git a/src/vs/workbench/contrib/chat/browser/chatSessions/chatSessions.contribution.ts b/src/vs/workbench/contrib/chat/browser/chatSessions/chatSessions.contribution.ts index 14972c525f9..2e49abc6e60 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSessions/chatSessions.contribution.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSessions/chatSessions.contribution.ts @@ -1291,7 +1291,7 @@ export enum ChatSessionPosition { type NewChatSessionSendOptions = { readonly prompt: string; readonly attachedContext?: IChatRequestVariableEntry[]; - readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: string | { id: string; name: string } }>; + readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem }>; }; export type NewChatSessionOpenOptions = { diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts index d89e48b88ca..46eca39ff61 100644 --- a/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts @@ -704,9 +704,10 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge : mode.label.read(undefined) !== agentId; // Extensions use Label (name) as identifier for custom agents. } if (needsUpdate) { + const value = mode.isBuiltin ? '' : modeName; this.chatSessionsService.notifySessionOptionsChange( ctx.chatSessionResource, - [{ optionId: agentOptionId, value: mode.isBuiltin ? '' : modeName }] + [{ optionId: agentOptionId, value: { id: value, name: value } }] ).catch(err => this.logService.error('Failed to notify extension of agent change:', err)); } } @@ -1813,14 +1814,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge const defaultItem = optionGroup.items.find(item => item.default); return defaultItem; } - - if (typeof currentOptionValue === 'string') { - const normalizedOptionId = currentOptionValue.trim(); - return optionGroup.items.find(m => m.id === normalizedOptionId); - } else { - return currentOptionValue as IChatSessionProviderOptionItem; - } - + return currentOptionValue; } private getEffectiveSessionType(ctx: IChatSessionContext | undefined, delegate: ISessionTypePickerDelegate | undefined): string { diff --git a/src/vs/workbench/contrib/chat/common/chatService/chatService.ts b/src/vs/workbench/contrib/chat/common/chatService/chatService.ts index 61bd25515b6..cf5d3e2ca40 100644 --- a/src/vs/workbench/contrib/chat/common/chatService/chatService.ts +++ b/src/vs/workbench/contrib/chat/common/chatService/chatService.ts @@ -31,6 +31,7 @@ import { IChatRequestVariableEntry } from '../attachments/chatVariableEntries.js import { IChatRequestVariableValue } from '../attachments/chatVariables.js'; import { ChatAgentLocation } from '../constants.js'; import { IPreparedToolInvocation, IToolConfirmationMessages, IToolResult, IToolResultInputOutputDetails, ToolDataSource } from '../tools/languageModelToolsService.js'; +import { IChatSessionProviderOptionItem } from '../chatSessionsService.js'; export interface IChatRequest { message: string; @@ -1535,7 +1536,7 @@ export interface IChatService { export interface IChatSessionContext { readonly chatSessionResource: URI; - readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: string | { id: string; name: string } }>; + readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem }>; } export const KEYWORD_ACTIVIATION_SETTING_ID = 'accessibility.voice.keywordActivation'; diff --git a/src/vs/workbench/contrib/chat/common/chatSessionsService.ts b/src/vs/workbench/contrib/chat/common/chatSessionsService.ts index 6dac8ac49d8..0bcb4f9a033 100644 --- a/src/vs/workbench/contrib/chat/common/chatSessionsService.ts +++ b/src/vs/workbench/contrib/chat/common/chatSessionsService.ts @@ -216,7 +216,7 @@ export interface IChatNewSessionRequest { readonly prompt: string; readonly command?: string; - readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: string | IChatSessionProviderOptionItem }>; + readonly initialSessionOptions?: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem }>; } export interface IChatSessionItemsDelta { @@ -241,7 +241,7 @@ export interface IChatSessionItemController { */ export interface IChatSessionOptionsWillNotifyExtensionEvent extends IWaitUntil { readonly sessionResource: URI; - readonly updates: ReadonlyArray<{ optionId: string; value: string | IChatSessionProviderOptionItem }>; + readonly updates: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem }>; } export type ResolvedChatSessionsExtensionPoint = Omit & { @@ -352,15 +352,15 @@ export interface IChatSessionsService { getOptionGroupsForSessionType(chatSessionType: string): IChatSessionProviderOptionGroup[] | undefined; setOptionGroupsForSessionType(chatSessionType: string, handle: number, optionGroups?: IChatSessionProviderOptionGroup[]): void; - getNewSessionOptionsForSessionType(chatSessionType: string): Record | undefined; - setNewSessionOptionsForSessionType(chatSessionType: string, options: Record): void; + getNewSessionOptionsForSessionType(chatSessionType: string): Record | undefined; + setNewSessionOptionsForSessionType(chatSessionType: string, options: Record): void; /** * Event fired when session options change and need to be sent to the extension. * MainThreadChatSessions subscribes to this to forward changes to the extension host. * Uses IWaitUntil pattern to allow listeners to register async work. */ readonly onRequestNotifyExtension: Event; - notifySessionOptionsChange(sessionResource: URI, updates: ReadonlyArray<{ optionId: string; value: string | IChatSessionProviderOptionItem }>): Promise; + notifySessionOptionsChange(sessionResource: URI, updates: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem }>): Promise; getInProgressSessionDescription(chatModel: IChatModel): string | undefined; diff --git a/src/vs/workbench/contrib/chat/test/common/mockChatSessionsService.ts b/src/vs/workbench/contrib/chat/test/common/mockChatSessionsService.ts index cf710f6d9e8..6de6e2e7d88 100644 --- a/src/vs/workbench/contrib/chat/test/common/mockChatSessionsService.ts +++ b/src/vs/workbench/contrib/chat/test/common/mockChatSessionsService.ts @@ -173,15 +173,15 @@ export class MockChatSessionsService implements IChatSessionsService { } } - getNewSessionOptionsForSessionType(_chatSessionType: string): Record | undefined { + getNewSessionOptionsForSessionType(_chatSessionType: string): Record | undefined { return undefined; } - setNewSessionOptionsForSessionType(_chatSessionType: string, _options: Record): void { + setNewSessionOptionsForSessionType(_chatSessionType: string, _options: Record): void { // noop } - async notifySessionOptionsChange(sessionResource: URI, updates: ReadonlyArray<{ optionId: string; value: string | IChatSessionProviderOptionItem }>): Promise { + async notifySessionOptionsChange(sessionResource: URI, updates: ReadonlyArray<{ optionId: string; value: IChatSessionProviderOptionItem }>): Promise { await this._onRequestNotifyExtension.fireAsync({ sessionResource, updates }, CancellationToken.None); }