Skip to content

Commit b31c8ea

Browse files
authored
Migrate LLM tools and remove Positron Assistant (#14718)
Fixes #14638 ### Summary As part of reverting to Copilot Chat, the Positron Assistant extension is no longer needed. This PR removes the `positron-assistant` extension and migrates the pieces Copilot Chat still relies on into Positron core, so core can supply Positron-specific context (runtime sessions, variables, code execution) to Copilot Chat through the Positron API. - **Removes** the `positron-assistant` extension -- participants, tools, prompt rendering, provider configuration/migration, and its tests -- along with its entries in `product.json` and the build config (`gulpfile.extensions.ts`, `dirs.ts`, `.vscode-test.js`). - **Migrates to core** under `src/vs/workbench/contrib/positronAssistant/`: the prompt template engine and renderer, the chat prompt templates, the Positron assistant tools, and the execute-code observer. - **Extends the Positron API** with the assistant's LLM tools and a tool filter (`positronToolFilter.ts`), wired through `mainThreadAiFeatures` / `extHostAiFeatures`, so Copilot Chat consumes Positron context via the public API rather than a bundled extension. - **Updates Copilot Chat** (`extensions/copilot/`) to render the Positron assistant prompt and register the migrated tools through the Positron API. ### Release Notes #### New Features - Positron assistant context (runtime sessions, variables, and code execution) is now provided to Copilot Chat through Positron core instead of a separate extension (#14638) #### Bug Fixes - N/A ### Validation Steps @:assistant @:posit-assistant 1. Open Copilot Chat and start a Python or R session. 2. Ask a question that requires Positron context (e.g. "what variables are in my session?" or "run this code and explain the output"). 3. Verify the assistant sees the active session, can list variables, and can execute code in the console. 4. Confirm the `positron-assistant` extension no longer appears in the Extensions view.
1 parent ced407e commit b31c8ea

91 files changed

Lines changed: 2283 additions & 7986 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test-tag-paths-map.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@
3333
"src/vs/workbench/contrib/runtimeSession/": ["@:sessions"],
3434
"src/vs/workbench/contrib/runtimeNotebookKernel/": ["@:positron-notebooks"],
3535

36-
"extensions/positron-assistant/": ["@:assistant"],
36+
"extensions/authentication/": ["@:assistant"],
37+
"extensions/copilot/": ["@:assistant"],
38+
"extensions/copilot/src/extension/prompts/node/base/positronAssistant.tsx/": ["@:assistant"],
3739
"extensions/positron-connections/": ["@:connections"],
3840
"extensions/positron-notebooks/": ["@:positron-notebooks"],
3941
"extensions/positron-reticulate/": ["@:reticulate"],

.vscode-test.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,6 @@ const extensions = [
6868
workspaceFolder: path.join(os.tmpdir(), `authentication-${Math.floor(Math.random() * 100000)}`),
6969
mocha: { timeout: 60_000 }
7070
},
71-
{
72-
label: 'positron-assistant',
73-
workspaceFolder: 'extensions/positron-assistant/test-workspace',
74-
mocha: { timeout: 60_000 }
75-
},
7671
{
7772
label: 'next-edit-suggestions',
7873
workspaceFolder: path.join(os.tmpdir(), `next-edit-suggestions-${Math.floor(Math.random() * 100000)}`),

build/gulpfile.extensions.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ const compilations = [
5858
'extensions/authentication/tsconfig.json',
5959
'extensions/open-remote-ssh/tsconfig.json',
6060
'extensions/next-edit-suggestions/tsconfig.json',
61-
'extensions/positron-assistant/tsconfig.json',
6261
'extensions/positron-catalog-explorer/tsconfig.json',
6362
'extensions/positron-code-cells/tsconfig.json',
6463
'extensions/positron-connections/tsconfig.json',

build/gulpfile.vscode.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ const vscodeResourceIncludes = [
129129
// Positron Help
130130
'out-build/vs/workbench/contrib/positronHelp/browser/resources/*.html',
131131
'out-build/vs/workbench/browser/media/*.svg',
132+
// Positron Assistant chat prompt templates
133+
'out-build/vs/workbench/contrib/positronAssistant/browser/media/prompts/chat/*.md',
132134
// --- End Positron ---
133135

134136
// Tree Sitter highlights

build/gulpfile.vscode.web.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ export const vscodeWebResourceIncludes = [
7777
// Positron Help
7878
'out-build/vs/workbench/contrib/positronHelp/browser/resources/*.html',
7979
'out-build/vs/workbench/browser/media/*.svg',
80+
// Positron Assistant chat prompt templates
81+
'out-build/vs/workbench/contrib/positronAssistant/browser/media/prompts/chat/*.md',
8082
'out-build/esm-package-dependencies/**',
8183
// --- End Positron ---
8284

build/next/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ const desktopResourcePatterns = [
261261
// --- Start Positron ---
262262
// Positron Help welcome/help HTML loaded by positronHelpService at runtime.
263263
'vs/workbench/contrib/positronHelp/browser/resources/*.html',
264+
// Positron Assistant chat prompt templates, loaded by PromptRenderer at runtime.
265+
'vs/workbench/contrib/positronAssistant/browser/media/prompts/chat/*.md',
264266
// --- End Positron ---
265267

266268
// HTML
@@ -342,6 +344,8 @@ const serverWebResourcePatterns = [
342344
// --- Start Positron ---
343345
// Positron Help welcome/help HTML loaded by positronHelpService at runtime.
344346
'vs/workbench/contrib/positronHelp/browser/resources/*.html',
347+
// Positron Assistant chat prompt templates, loaded by PromptRenderer at runtime.
348+
'vs/workbench/contrib/positronAssistant/browser/media/prompts/chat/*.md',
345349
// --- End Positron ---
346350

347351
// Web HTML
@@ -374,6 +378,8 @@ const webResourcePatterns = [
374378
// --- Start Positron ---
375379
// Positron Help welcome/help HTML loaded by positronHelpService at runtime.
376380
'vs/workbench/contrib/positronHelp/browser/resources/*.html',
381+
// Positron Assistant chat prompt templates, loaded by PromptRenderer at runtime.
382+
'vs/workbench/contrib/positronAssistant/browser/media/prompts/chat/*.md',
377383
// --- End Positron ---
378384

379385
// Web HTML

build/npm/dirs.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export let dirs = [
2222
'extensions/authentication',
2323
'extensions/next-edit-suggestions',
2424
'extensions/open-remote-ssh',
25-
'extensions/positron-assistant',
2625
'extensions/positron-catalog-explorer',
2726
'extensions/positron-code-cells',
2827
'extensions/positron-connections',
@@ -142,7 +141,6 @@ if (existsSync(`${import.meta.dirname}/../../.build/distro/npm`)) {
142141
// THIS IS THE SINGLE SOURCE OF TRUTH for volatile extension list
143142
export const volatileExtensions = [
144143
'extensions/positron-python',
145-
'extensions/positron-assistant',
146144
'extensions/positron-r'
147145
];
148146

extensions/authentication/src/test/providerSources.test.ts

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,23 @@ import { PROVIDER_METADATA } from '../providerSources';
1212
* Guards against drift between PROVIDER_METADATA in providerSources.ts and the
1313
* package.json contributions that own the same data. The metadata hardcodes
1414
* provider ids, display names, setting names, and maturity status that really
15-
* live in the manifests; nothing but this test keeps them in sync.
15+
* live in this extension's manifest; nothing but this test keeps them in sync.
1616
*
17-
* Two manifests are involved:
18-
* - this extension's package.json: `contributes.authentication` (id + label)
19-
* and the `assistant.provider.<settingName>.enabled` settings for providers
20-
* that don't ship via positron-assistant (googleVertex, deepseek).
21-
* - positron-assistant's package.json: the `positron.assistant.provider.
22-
* <settingName>.enable` settings (and their tags, which `status` mirrors).
17+
* Two sets of contributions in this extension's package.json are involved:
18+
* - `contributes.authentication` (id + label).
19+
* - the provider enablement settings (and their tags, which `status`
20+
* mirrors). posit-dev/positron#13811 already moved every enablement
21+
* setting into this manifest (the old positron-assistant home is gone) and
22+
* is still renaming the legacy `positron.assistant.provider.<name>.enable`
23+
* keys to the new `assistant.provider.<name>.enabled` format (note the
24+
* trailing `d`). Until every key is renamed, both formats coexist here.
2325
*
24-
* NOTE: posit-dev/positron#13811 migrates the old `positron.assistant.provider.
25-
* <name>.enable` keys to the new `assistant.provider.<name>.enabled` format
26-
* (note the trailing `d`) and moves every enablement setting into a single home.
27-
* Once that lands, this test simplifies:
28-
* - If the settings move here, drop `assistantPkg` and its `collect()` call;
29-
* the cross-extension read into positron-assistant goes away (it's being
30-
* deprecated anyway). If they move elsewhere, point the single read there.
31-
* - Tighten the `provider\.(?<name>[^.]+)\.enabled?$` regex to `\.enabled$`;
32-
* the optional `d` only exists to match both the old and new key formats.
33-
* - If the migration keeps the old keys around as deprecated aliases instead
34-
* of removing them, both keys will exist for the same provider. They map to
35-
* the same capture group, so skip anything carrying a `deprecationMessage`/
36-
* `markdownDeprecationMessage` to avoid the deprecated entry's tags winning.
26+
* The `provider\.(?<name>[^.]+)\.enabled?$` regex matches both formats; the
27+
* optional `d` only exists to bridge them. Tighten it to `\.enabled$` once the
28+
* rename is complete. If any legacy key is kept around as a deprecated alias
29+
* (so both keys exist for one provider, mapping to the same capture group),
30+
* skip entries carrying a `deprecationMessage`/`markdownDeprecationMessage` so
31+
* the deprecated entry's tags don't win.
3732
*/
3833
suite('PROVIDER_METADATA package.json consistency', () => {
3934

@@ -43,7 +38,6 @@ suite('PROVIDER_METADATA package.json consistency', () => {
4338
}
4439

4540
const authPkg = readPackageJson('package.json');
46-
const assistantPkg = readPackageJson('..', 'positron-assistant', 'package.json');
4741

4842
test('every authentication contribution has a PROVIDER_METADATA entry', () => {
4943
// `label` (Accounts menu) and `displayName` (model picker) are deliberately
@@ -60,8 +54,8 @@ suite('PROVIDER_METADATA package.json consistency', () => {
6054
});
6155

6256
test('settingName and status match the provider enable settings', () => {
63-
// Collect every `provider.<name>.enable`/`.enabled` setting across both
64-
// manifests, mapping the name to its maturity status (derived from tags).
57+
// Collect every `provider.<name>.enable`/`.enabled` setting in the
58+
// manifest, mapping the name to its maturity status (derived from tags).
6559
// `status` in PROVIDER_METADATA must mirror that exactly.
6660
const enableSettings: Record<string, 'preview' | 'experimental' | undefined> = {};
6761
const collect = (pkg: any) => {
@@ -80,7 +74,6 @@ suite('PROVIDER_METADATA package.json consistency', () => {
8074
}
8175
};
8276
collect(authPkg);
83-
collect(assistantPkg);
8477

8578
const fromMetadata: Record<string, 'preview' | 'experimental' | undefined> = {};
8679
for (const entry of Object.values(PROVIDER_METADATA)) {

extensions/copilot/.esbuild.mts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ const baseNodeBuildOptions = {
3232
external: [
3333
'./package.json',
3434
'./.vscode-test.mjs',
35+
// Positron: the `positron` module is provided by the Positron extension
36+
// host at runtime, so leave it external rather than bundling it.
37+
'positron',
3538
'playwright',
3639
'keytar',
3740
'@azure/functions-core',
@@ -206,6 +209,7 @@ const webExtHostBuildOptions = {
206209
format: 'cjs', // Necessary to export activate function from bundle for extension
207210
external: [
208211
'vscode',
212+
'positron', // Positron: provided by the Positron extension host at runtime
209213
'http',
210214
]
211215
} satisfies esbuild.BuildOptions;

extensions/copilot/src/extension/prompts/node/base/positronAssistant.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { PromptElement, PromptSizing, SystemMessage, TextChunk } from '@vscode/prompt-tsx';
77
import type { ChatResponsePart } from '@vscode/prompt-tsx/dist/base/vscodeTypes.js';
8-
import * as vscode from 'vscode';
8+
import type * as vscode from 'vscode';
99
import type { GenericBasePromptElementProps } from '../../../context/node/resolvers/genericPanelIntentInvocation';
1010
import type { IBuildPromptContext } from '../../../prompt/common/intents.js';
1111

@@ -25,22 +25,22 @@ export class PositronAssistant extends PromptElement<GenericBasePromptElementPro
2525
progress?: vscode.Progress<ChatResponsePart>,
2626
token?: vscode.CancellationToken): Promise<any> {
2727

28-
// The Positron Assistant extension supplies the Positron-specific context
29-
// for this prompt. When Copilot Chat is used on its own, that extension may
30-
// be disabled or not installed; skip this element in that case rather than
31-
// failing the whole chat request.
32-
const extension = vscode.extensions.getExtension('positron.positron-assistant');
33-
if (!extension) {
28+
const request = this.context.request;
29+
if (!request) {
3430
return undefined;
3531
}
3632

37-
// Activate the extension if needed so its API is available, then generate
38-
// the content element.
39-
const api = await extension.activate();
40-
if (typeof api?.generateAssistantPrompt !== 'function') {
33+
// Positron supplies the Positron-specific context for this prompt via the
34+
// `positron` API, provided by the Positron extension host at runtime. It
35+
// is absent when Copilot Chat runs outside Positron (or in simulation
36+
// tests), so guard the lookup and skip this element rather than failing
37+
// the whole chat request.
38+
try {
39+
const positron = require('positron') as typeof import('positron');
40+
return await positron.ai.generateAssistantPrompt(request);
41+
} catch {
4142
return undefined;
4243
}
43-
return await api.generateAssistantPrompt(this.context.request);
4444
}
4545

4646
/**

0 commit comments

Comments
 (0)