diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts index ce1e544e505..6518dd519a5 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts @@ -120,7 +120,7 @@ suite('chat', () => { assert.deepStrictEqual(result.metadata, { key: 'value' }); }); - test('isolated participant history', async () => { + test('participant history not isolated within extension', async () => { const onRequest = setupParticipant(); const onRequest2 = setupParticipant(true); @@ -132,13 +132,13 @@ suite('chat', () => { commands.executeCommand('workbench.action.chat.open', { query: '@participant2 hi' }); }, 0); const request2 = await asPromise(onRequest2); - assert.strictEqual(request2.context.history.length, 0); + assert.strictEqual(request2.context.history.length, 10); setTimeout(() => { commands.executeCommand('workbench.action.chat.open', { query: '@participant2 hi' }); }, 0); const request3 = await asPromise(onRequest2); - assert.strictEqual(request3.context.history.length, 2); // request + response = 2 + assert.strictEqual(request3.context.history.length, 12); // request + response = 2 }); test('title provider is called for first request', async () => { diff --git a/src/vs/workbench/contrib/chat/browser/media/chatEditorController.css b/src/vs/workbench/contrib/chat/browser/media/chatEditorController.css index 513be97904c..03d8b6e6171 100644 --- a/src/vs/workbench/contrib/chat/browser/media/chatEditorController.css +++ b/src/vs/workbench/contrib/chat/browser/media/chatEditorController.css @@ -28,8 +28,7 @@ .chat-diff-change-content-widget .monaco-action-bar .action-item .action-label.codicon { width: unset; - padding: 0 2px; - z-index: 9; + padding: 2px; font-size: 12px; line-height: 14px; color: var(--vscode-button-foreground); diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index f1d62f78d85..26f5332430b 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -16,14 +16,13 @@ import { StopWatch } from '../../../../base/common/stopwatch.js'; import { URI, UriComponents } from '../../../../base/common/uri.js'; import { localize } from '../../../../nls.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; -import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { Progress } from '../../../../platform/progress/common/progress.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js'; import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js'; -import { IWorkbenchAssignmentService } from '../../../services/assignment/common/assignmentService.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; import { ChatAgentLocation, IChatAgent, IChatAgentCommand, IChatAgentData, IChatAgentHistoryEntry, IChatAgentRequest, IChatAgentResult, IChatAgentService } from './chatAgents.js'; import { ChatModel, ChatRequestModel, ChatRequestRemovalReason, IChatModel, IChatRequestModel, IChatRequestVariableData, IChatResponseModel, IExportableChatData, ISerializableChatData, ISerializableChatDataIn, ISerializableChatsData, normalizeSerializableChatData, toChatHistoryContent, updateRanges } from './chatModel.js'; @@ -131,8 +130,6 @@ export class ChatService extends Disposable implements IChatService { @IChatSlashCommandService private readonly chatSlashCommandService: IChatSlashCommandService, @IChatVariablesService private readonly chatVariablesService: IChatVariablesService, @IChatAgentService private readonly chatAgentService: IChatAgentService, - @IWorkbenchAssignmentService workbenchAssignmentService: IWorkbenchAssignmentService, - @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService private readonly configurationService: IConfigurationService ) { super(); @@ -788,13 +785,23 @@ export class ChatService extends Disposable implements IChatService { private getHistoryEntriesFromModel(requests: IChatRequestModel[], sessionId: string, location: ChatAgentLocation, forAgentId: string): IChatAgentHistoryEntry[] { const history: IChatAgentHistoryEntry[] = []; + + + const defaultAgentId = this.chatAgentService.getDefaultAgent(location)?.id; + + const forAgentExtension = this.chatAgentService.getAgent(forAgentId); + for (const request of requests) { if (!request.response) { continue; } - const defaultAgentId = this.chatAgentService.getDefaultAgent(location)?.id; - if (forAgentId !== request.response.agent?.id && forAgentId !== defaultAgentId) { + const responseAgentExtension = request.response.agent ? this.chatAgentService.getAgent(request.response.agent.id) : undefined; + + if (forAgentId !== defaultAgentId + && forAgentId !== request.response.agent?.id + && !ExtensionIdentifier.equals(forAgentExtension?.extensionId, responseAgentExtension?.extensionId) + ) { // An agent only gets to see requests that were sent to this agent. // The default agent (the undefined case) gets to see all of them. continue; diff --git a/src/vs/workbench/contrib/chat/test/common/chatService.test.ts b/src/vs/workbench/contrib/chat/test/common/chatService.test.ts index 393c3813b83..c96a79b08c6 100644 --- a/src/vs/workbench/contrib/chat/test/common/chatService.test.ts +++ b/src/vs/workbench/contrib/chat/test/common/chatService.test.ts @@ -34,6 +34,7 @@ import { IExtensionService, nullExtensionDescription } from '../../../../service import { IViewsService } from '../../../../services/views/common/viewsService.js'; import { TestContextService, TestExtensionService, TestStorageService } from '../../../../test/common/workbenchTestServices.js'; import { MarkdownString } from '../../../../../base/common/htmlContent.js'; +import { ExtensionIdentifier } from '../../../../../platform/extensions/common/extensions.js'; const chatAgentWithUsedContextId = 'ChatProviderWithUsedContext'; const chatAgentWithUsedContext: IChatAgent = { @@ -196,9 +197,11 @@ suite('ChatService', () => { }; testDisposables.add(chatAgentService.registerAgent('defaultAgent', { ...getAgentData('defaultAgent'), isDefault: true })); - testDisposables.add(chatAgentService.registerAgent('agent2', getAgentData('agent2'))); + testDisposables.add(chatAgentService.registerAgent('agent2', { ...getAgentData('agent2'), extensionId: new ExtensionIdentifier('foo.bar') })); + testDisposables.add(chatAgentService.registerAgent('agent3', getAgentData('agent3'))); testDisposables.add(chatAgentService.registerAgentImplementation('defaultAgent', historyLengthAgent)); testDisposables.add(chatAgentService.registerAgentImplementation('agent2', historyLengthAgent)); + testDisposables.add(chatAgentService.registerAgentImplementation('agent3', historyLengthAgent)); const testService = testDisposables.add(instantiationService.createInstance(ChatService)); const model = testDisposables.add(testService.startSession(ChatAgentLocation.Panel, CancellationToken.None)); @@ -217,12 +220,19 @@ suite('ChatService', () => { assert.strictEqual(model.getRequests().length, 2); assert.strictEqual(model.getRequests()[1].response?.result?.metadata?.historyLength, 0); - // Send a request to defaultAgent - the default agent can see agent2's message - const response3 = await testService.sendRequest(model.sessionId, `test request`, { agentId: 'defaultAgent' }); + // Send a request to agent3- it can see the default agent's message because they are from the same extension + const response3 = await testService.sendRequest(model.sessionId, `test request`, { agentId: 'agent3' }); assert(response3); await response3.responseCompletePromise; assert.strictEqual(model.getRequests().length, 3); - assert.strictEqual(model.getRequests()[2].response?.result?.metadata?.historyLength, 2); + assert.strictEqual(model.getRequests()[2].response?.result?.metadata?.historyLength, 1); + + // Send a request to defaultAgent - the default agent can see agent2's message + const response4 = await testService.sendRequest(model.sessionId, `test request`, { agentId: 'defaultAgent' }); + assert(response4); + await response4.responseCompletePromise; + assert.strictEqual(model.getRequests().length, 4); + assert.strictEqual(model.getRequests()[3].response?.result?.metadata?.historyLength, 3); }); test('can serialize', async () => {