From 2ac11b37d27ba16d75d6e64286a827f99d1369ce Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 14:47:14 -0700 Subject: [PATCH 1/6] Add 'default agent' concept (#195599) So that every request can be routed through an agent --- src/vs/workbench/api/common/extHostChatAgents2.ts | 9 +++++++++ .../chat/browser/contrib/chatInputEditorContrib.ts | 3 ++- src/vs/workbench/contrib/chat/common/chatAgents.ts | 8 +++++++- .../contrib/chat/common/chatServiceImpl.ts | 12 +++++++----- .../extensions/common/extensionsApiProposals.ts | 1 + .../vscode.proposed.defaultChatAgent.d.ts | 14 ++++++++++++++ 6 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index 13a6b7d6b85..f765884967e 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -185,6 +185,7 @@ class ExtHostChatAgent { private _description: string | undefined; private _fullName: string | undefined; private _iconPath: URI | undefined; + private _isDefault: boolean | undefined; private _onDidReceiveFeedback = new Emitter(); private _onDidPerformAction = new Emitter(); @@ -258,6 +259,7 @@ class ExtHostChatAgent { icon: this._iconPath, hasSlashCommands: this._slashCommandProvider !== undefined, hasFollowup: this._followupProvider !== undefined, + isDefault: this._isDefault }); updateScheduled = false; }); @@ -304,6 +306,13 @@ class ExtHostChatAgent { that._followupProvider = v; updateMetadataSoon(); }, + get isDefault() { + return that._isDefault; + }, + set isDefault(v) { + that._isDefault = v; + updateMetadataSoon(); + }, get onDidReceiveFeedback() { return that._onDidReceiveFeedback.event; }, diff --git a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts index 3c015b89c42..bb7a7b77e79 100644 --- a/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts +++ b/src/vs/workbench/contrib/chat/browser/contrib/chatInputEditorContrib.ts @@ -329,7 +329,8 @@ class AgentCompletions extends Disposable { return null; } - const agents = this.chatAgentService.getAgents(); + const agents = this.chatAgentService.getAgents() + .filter(a => !a.metadata.isDefault); return { suggestions: agents.map((c, i) => { const withAt = `@${c.id}`; diff --git a/src/vs/workbench/contrib/chat/common/chatAgents.ts b/src/vs/workbench/contrib/chat/common/chatAgents.ts index 525137f000e..886c5aa60a7 100644 --- a/src/vs/workbench/contrib/chat/common/chatAgents.ts +++ b/src/vs/workbench/contrib/chat/common/chatAgents.ts @@ -5,6 +5,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; +import { Iterable } from 'vs/base/common/iterator'; import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -36,7 +37,7 @@ export interface IChatAgentMetadata { description?: string; // subCommands: IChatAgentCommand[]; requireCommand?: boolean; // Do some agents not have a default action? - isImplicit?: boolean; // Only @workspace. slash commands get promoted to the top-level and this agent is invoked when those are used + isDefault?: boolean; // The agent invoked when no agent is specified fullName?: string; icon?: URI; } @@ -69,6 +70,7 @@ export interface IChatAgentService { getFollowups(id: string, sessionId: string, token: CancellationToken): Promise; getAgents(): Array; getAgent(id: string): IChatAgent | undefined; + getDefaultAgent(): IChatAgent | undefined; hasAgent(id: string): boolean; updateAgent(id: string, updateMetadata: IChatAgentMetadata): void; } @@ -112,6 +114,10 @@ export class ChatAgentService extends Disposable implements IChatAgentService { this._onDidChangeAgents.fire(); } + getDefaultAgent(): IChatAgent | undefined { + return Iterable.find(this._agents.values(), a => !!a.agent.metadata.isDefault)?.agent; + } + getAgents(): Array { return Array.from(this._agents.values(), v => v.agent); } diff --git a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts index eb3b8680044..92ae2ff6307 100644 --- a/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts +++ b/src/vs/workbench/contrib/chat/common/chatServiceImpl.ts @@ -507,7 +507,9 @@ export class ChatService extends Disposable implements IChatService { let rawResponse: IChatResponse | null | undefined; let agentOrCommandFollowups: Promise | undefined = undefined; - if (typeof message === 'string' && agentPart) { + const defaultAgent = this.chatAgentService.getDefaultAgent(); + if (typeof message === 'string' && (agentPart || defaultAgent)) { + const agent = (agentPart?.agent ?? defaultAgent)!; const history: IChatMessage[] = []; for (const request of model.getRequests()) { if (!request.response) { @@ -518,11 +520,11 @@ export class ChatService extends Disposable implements IChatService { history.push({ role: ChatMessageRole.Assistant, content: request.response.response.asString() }); } - request = model.addRequest(parsedRequest, agentPart.agent); + request = model.addRequest(parsedRequest, agent); const requestProps: IChatAgentRequest = { sessionId, requestId: generateUuid(), - message: message, + message, variables: {}, command: agentSlashCommandPart?.command.name ?? '', }; @@ -532,7 +534,7 @@ export class ChatService extends Disposable implements IChatService { requestProps.message = varResult.prompt; } - const agentResult = await this.chatAgentService.invokeAgent(agentPart.agent.id, requestProps, new Progress(p => { + const agentResult = await this.chatAgentService.invokeAgent(agent.id, requestProps, new Progress(p => { progressCallback(p); }), history, token); rawResponse = { @@ -541,7 +543,7 @@ export class ChatService extends Disposable implements IChatService { timings: agentResult.timings }; agentOrCommandFollowups = agentResult?.followUp ? Promise.resolve(agentResult.followUp) : - this.chatAgentService.getFollowups(agentPart.agent.id, sessionId, CancellationToken.None); + this.chatAgentService.getFollowups(agent.id, sessionId, CancellationToken.None); } else if (commandPart && typeof message === 'string' && this.chatSlashCommandService.hasCommand(commandPart.slashCommand.command)) { request = model.addRequest(parsedRequest); // contributed slash commands diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index 3ebf8b558b3..c5e30e4de43 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -38,6 +38,7 @@ export const allApiProposals = Object.freeze({ createFileSystemWatcher: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.createFileSystemWatcher.d.ts', customEditorMove: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.customEditorMove.d.ts', debugFocus: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.debugFocus.d.ts', + defaultChatAgent: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts', diffCommand: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.diffCommand.d.ts', diffContentOptions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.diffContentOptions.d.ts', documentFiltersExclusive: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.documentFiltersExclusive.d.ts', diff --git a/src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts b/src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts new file mode 100644 index 00000000000..573b0668744 --- /dev/null +++ b/src/vscode-dts/vscode.proposed.defaultChatAgent.d.ts @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * 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 interface ChatAgent2 { + /** + * When true, this agent is invoked by default when no other agent is being invoked + */ + isDefault?: boolean; + } +} From 7314532ae976809f0a3a72c93f25e9094ae3e28a Mon Sep 17 00:00:00 2001 From: Connor Peet Date: Fri, 13 Oct 2023 14:49:32 -0700 Subject: [PATCH 2/6] eng: fix extension test runner on windows (#195600) --- .vscode-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode-test.js b/.vscode-test.js index 9b9a35e5cbd..3741ea0eb44 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -57,7 +57,7 @@ module.exports = defineConfig(extensions.map(extension => { if (!config.platform || config.platform === 'desktop') { config.launchArgs = defaultLaunchArgs; config.useInstallation = { - fromPath: process.env.INTEGRATION_TEST_ELECTRON_PATH || `${__dirname}/scripts/code.${process.platform === 'win32' ? 'cmd' : 'sh'}`, + fromPath: process.env.INTEGRATION_TEST_ELECTRON_PATH || `${__dirname}/scripts/code.${process.platform === 'win32' ? 'bat' : 'sh'}`, }; config.env = { ...config.env, From 583d56685fe79d71c8eb83f9848259adeb2bbaf2 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 13 Oct 2023 14:50:34 -0700 Subject: [PATCH 3/6] use test extension to test extensions --- .vscode-test.js | 10 ++++++++++ scripts/test-integration.bat | 8 ++------ scripts/test-integration.sh | 4 ++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/.vscode-test.js b/.vscode-test.js index 3741ea0eb44..069cd0ac6c0 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -20,6 +20,16 @@ const extensions = [ workspaceFolder: `extensions/markdown-language-features/test-workspace`, mocha: { timeout: 60_000 } }, + { + label: 'ipynb', + workspaceFolder: '%TEMPDIR%/ipynb-%RANDOM%', + mocha: { timeout: 60_000 } + }, + { + label: 'notebook-renderers', + workspaceFolder: '%TEMPDIR%/nbout-%RANDOM%', + mocha: { timeout: 60_000 } + }, ]; diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 16efa750a49..1834f26162d 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -77,16 +77,12 @@ if %errorlevel% neq 0 exit /b %errorlevel% echo. echo ### Ipynb tests -set IPYNBWORKSPACE=%TEMPDIR%\ipynb-%RANDOM% -mkdir %IPYNBWORKSPACE% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %IPYNBWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\ipynb --extensionTestsPath=%~dp0\..\extensions\ipynb\out\test %API_TESTS_EXTRA_ARGS% +call yarn test-extension -l ipynb if %errorlevel% neq 0 exit /b %errorlevel% echo. echo ### Notebook Output tests -set NBOUTWORKSPACE=%TEMPDIR%\nbout-%RANDOM% -mkdir %NBOUTWORKSPACE% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %NBOUTWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\notebook-renderers --extensionTestsPath=%~dp0\..\extensions\notebook-renderers\out\test %API_TESTS_EXTRA_ARGS% +call yarn test-extension -l notebook-renderers if %errorlevel% neq 0 exit /b %errorlevel% echo. diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 35b97b58e59..6a7a1fe4a75 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -97,13 +97,13 @@ kill_app echo echo "### Ipynb tests" echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/ipynb --extensionTestsPath=$ROOT/extensions/ipynb/out/test $API_TESTS_EXTRA_ARGS +yarn test-extension -l ipynb kill_app echo echo "### Notebook Output tests" echo -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/notebook-renderers --extensionTestsPath=$ROOT/extensions/notebook-renderers/out/test $API_TESTS_EXTRA_ARGS +yarn test-extension -l notebook-renderers kill_app echo From e614d43eb4f00baa1ea50a9db7b6362e14819463 Mon Sep 17 00:00:00 2001 From: Aaron Munger Date: Fri, 13 Oct 2023 15:36:34 -0700 Subject: [PATCH 4/6] generate a valid temp directory --- .vscode-test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.vscode-test.js b/.vscode-test.js index 069cd0ac6c0..e09b8443b7f 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -7,6 +7,7 @@ const path = require('path'); const { defineConfig } = require('@vscode/test-cli'); +const os = require('os'); /** * A list of extension folders who have opted into tests, or configuration objects. @@ -22,12 +23,12 @@ const extensions = [ }, { label: 'ipynb', - workspaceFolder: '%TEMPDIR%/ipynb-%RANDOM%', + workspaceFolder: path.join(os.tmpdir(), `ipynb-${Math.floor(Math.random() * 100000)}`), mocha: { timeout: 60_000 } }, { label: 'notebook-renderers', - workspaceFolder: '%TEMPDIR%/nbout-%RANDOM%', + workspaceFolder: path.join(os.tmpdir(), `nbout-${Math.floor(Math.random() * 100000)}`), mocha: { timeout: 60_000 } }, ]; From 4efef1f42c3214705c39d6953f7d71c876538272 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 16:09:20 -0700 Subject: [PATCH 5/6] Add missing proposed API check (#195605) --- src/vs/workbench/api/common/extHostChatAgents2.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/api/common/extHostChatAgents2.ts b/src/vs/workbench/api/common/extHostChatAgents2.ts index f765884967e..c1dd23a6965 100644 --- a/src/vs/workbench/api/common/extHostChatAgents2.ts +++ b/src/vs/workbench/api/common/extHostChatAgents2.ts @@ -19,7 +19,7 @@ import { ChatAgentResultFeedbackKind } from 'vs/workbench/api/common/extHostType import { IChatAgentCommand, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents'; import { IChatMessage } from 'vs/workbench/contrib/chat/common/chatProvider'; import { IChatFollowup, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; -import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; +import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions'; import type * as vscode from 'vscode'; export class ExtHostChatAgents2 implements ExtHostChatAgentsShape2 { @@ -307,9 +307,11 @@ class ExtHostChatAgent { updateMetadataSoon(); }, get isDefault() { + checkProposedApiEnabled(that.extension, 'defaultChatAgent'); return that._isDefault; }, set isDefault(v) { + checkProposedApiEnabled(that.extension, 'defaultChatAgent'); that._isDefault = v; updateMetadataSoon(); }, From 54afbddf867c0c03baf67e5184dd0a07b7abf26a Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 13 Oct 2023 16:13:12 -0700 Subject: [PATCH 6/6] Update distro (#195604) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1401d9cb39c..860e50402fa 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.84.0", - "distro": "ca54f82b1adb64bbf5601501cc4edef8043f045c", + "distro": "f69d4735763562c6fd1d2a56596fe808865081ed", "author": { "name": "Microsoft Corporation" },