Repository: posit-dev/positron
Pull request #7338: Show active completion providers
Author: login: timtmok
Created: 2025-04-22T20:48:11Z | Merged: 2025-04-28T20:01:32Z

<!-- Thank you for submitting a pull request.
If this is your first pull request you can find information about
contributing here:
  * https://github.com/posit-dev/positron/blob/main/CONTRIBUTING.md

We recommend synchronizing your branch with the latest changes in the
main branch by either pulling or rebasing.
-->

<!--
  Describe briefly what problem this pull request resolves, or what
  new feature it introduces. Include screenshots of any new or altered
  UI. Link to any GitHub issues but avoid "magic" keywords that will
  automatically close the issue. If there are any details about your
  approach that are unintuitive or you want to draw attention to, please
  describe them here.
-->
Address #6818 

This activates the Chat status bar entry and updates the icon to Positron Assistant. It seems to be hidden by default and had some context keys to determine whether to show it. It's possibly due to the changes going on with Chat from upstream. See `chatStatus.ts L#130` where some parts will be removed in the future. It's likely that extensions will contribute to the tooltip and the Copilot specific code will be moved out to its extension.

This does use proposed API so it may break in a future upstream merge.

For us, we could contribute the information from the extension but it might be good to let this API stabilize. Then we can look into enhancements like changing the status icon when completion providers are running.

![image](https://github.com/user-attachments/assets/2c198e98-73cd-4d8e-b5ba-e37b8830b3b1)


### Release Notes

<!--
  Optionally, replace `N/A` with text to be included in the next release notes.
  The `N/A` bullets are ignored. If you refer to one or more Positron issues,
  these issues are used to collect information about the feature or bugfix, such
  as the relevant language pack as determined by Github labels of type `lang: `.
  The note will automatically be tagged with the language.

  These notes are typically filled by the Positron team. If you are an external
  contributor, you may ignore this section.
-->

#### New Features

- Show in Chat status bar tooltip the active completion providers #6818

#### Bug Fixes

- N/A


### QA Notes

<!--
  Add additional information for QA on how to validate the change,
  paying special attention to the level of risk, adjacent areas that
  could be affected by the change, and any important contextual
  information not present in the linked issues.
-->



Diff:
diff --git a/extensions/positron-assistant/src/extension.ts b/extensions/positron-assistant/src/extension.ts
index 0034481941c6..cce40a1ec56e 100644
--- a/extensions/positron-assistant/src/extension.ts
+++ b/extensions/positron-assistant/src/extension.ts
@@ -138,7 +138,8 @@ async function registerModelWithAPI(modelConfig: ModelConfig, context: vscode.Ex
 	// Register with VS Code completions API
 	else if (modelConfig.type === 'completion') {
 		const completionProvider = newCompletionProvider(modelConfig);
-		const complDisp = vscode.languages.registerInlineCompletionItemProvider(ALL_DOCUMENTS_SELECTOR, completionProvider);
+		// this uses the proposed inlineCompletionAdditions API
+		const complDisp = vscode.languages.registerInlineCompletionItemProvider(ALL_DOCUMENTS_SELECTOR, completionProvider, { displayName: modelConfig.name });
 		modelDisposables.push(complDisp);
 	}
 
diff --git a/src/vs/workbench/contrib/chat/browser/chatStatus.ts b/src/vs/workbench/contrib/chat/browser/chatStatus.ts
index d4d6718a816c..81231ec5b8a8 100644
--- a/src/vs/workbench/contrib/chat/browser/chatStatus.ts
+++ b/src/vs/workbench/contrib/chat/browser/chatStatus.ts
@@ -38,6 +38,9 @@ import { IChatStatusItemService, ChatStatusEntry } from './chatStatusItemService
 import { ITextResourceConfigurationService } from '../../../../editor/common/services/textResourceConfiguration.js';
 import { EditorResourceAccessor, SideBySideEditor } from '../../../common/editor.js';
 import { getCodeEditor } from '../../../../editor/browser/editorBrowser.js';
+// --- Start Positron ---
+import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';
+// --- End Positron ---
 
 const gaugeBackground = registerColor('gauge.background', {
 	dark: inputValidationInfoBorder,
@@ -120,6 +123,16 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
 	}
 
 	private async create(): Promise<void> {
+		// --- Start Positron ---
+		// We only need the part that displays the status. No need to hide it based on the chat entitlement setting the right context keys
+		this.entry ||= this.statusbarService.addEntry(this.getEntryProps(), 'chat.statusBarEntry', StatusbarAlignment.RIGHT, { location: { id: 'status.editor.mode', priority: 100.1 }, alignment: StatusbarAlignment.RIGHT });
+
+		// TODO@bpasero: remove this eventually
+		const completionsStatusId = `${defaultChat.extensionId}.status`;
+		this.statusbarService.updateEntryVisibility(completionsStatusId, false);
+		this.statusbarService.overrideEntry(completionsStatusId, { name: localize('codeCompletionsStatus', "Copilot Code Completions"), text: localize('codeCompletionsStatusText', "$(copilot) Completions") });
+
+		/*
 		const hidden = this.chatEntitlementService.sentiment === ChatSentiment.Disabled;
 
 		if (!hidden) {
@@ -133,6 +146,8 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
 			this.entry?.dispose();
 			this.entry = undefined;
 		}
+		*/
+		// --- End Positron ---
 	}
 
 	private registerListeners(): void {
@@ -164,8 +179,10 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
 	}
 
 	private getEntryProps(): IStatusbarEntry {
-		let text = '$(copilot)';
-		let ariaLabel = localize('chatStatus', "Copilot Status");
+		// --- Start Positron ---
+		let text = '$(positron-assistant)';
+		let ariaLabel = localize('chatStatus', "Assistant Status");
+		// --- End Positron ---
 		let kind: StatusbarEntryKind | undefined;
 
 		if (!isNewUser(this.chatEntitlementService)) {
@@ -261,6 +278,9 @@ class ChatStatusDashboard extends Disposable {
 	private readonly entryDisposables = this._register(new MutableDisposable());
 
 	constructor(
+		// --- Start Positron ---
+		@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,
+		// --- End Positron ---
 		@IChatEntitlementService private readonly chatEntitlementService: ChatEntitlementService,
 		@IChatStatusItemService private readonly chatStatusItemService: IChatStatusItemService,
 		@ICommandService private readonly commandService: ICommandService,
@@ -348,13 +368,42 @@ class ChatStatusDashboard extends Disposable {
 			}
 		}
 
-		// Settings
+		// --- Start Positron ---
+		// Completion Providers
 		{
-			addSeparator(localize('settingsTitle', "Settings"));
+			const entry = {
+				id: 'positron-assistant.completionProviders',
+				label: localize('completionProvidersLabel', "Completion Providers"),
+				description: '',
+				detail: '',
+			}
+			this.languageFeaturesService.inlineCompletionsProvider.allNoModel().forEach(provider => {
+				const name = provider.displayName;
+				if (name) {
+					// add an element to the container with the name
+					entry.description += `${name}\n`;
+				}
+			});
+
+			if (entry.description.length === 0) {
+				entry.description = localize('noCompletionProviders', "No completion providers available");
+			}
 
-			this.createSettings(this.element, disposables);
+			const rendered = this.renderContributedChatStatusItem(entry);
+			this.element.appendChild(rendered.element);
 		}
 
+		/*
+		// Settings
+		// {
+		// 	addSeparator(localize('settingsTitle', "Settings"));
+
+		// 	this.createSettings(this.element, disposables);
+		// }
+
+
+		// Remove Copilot
+
 		// New to Copilot / Signed out
 		{
 			const newUser = isNewUser(this.chatEntitlementService);
@@ -363,12 +412,13 @@ class ChatStatusDashboard extends Disposable {
 				addSeparator(undefined);
 
 				this.element.appendChild($('div.description', undefined, newUser ? localize('activateDescription', "Set up Copilot to use AI features.") : localize('signInDescription', "Sign in to use Copilot AI features.")));
-
 				const button = disposables.add(new Button(this.element, { ...defaultButtonStyles }));
 				button.label = newUser ? localize('activateCopilotButton', "Set up Copilot") : localize('signInToUseCopilotButton', "Sign in to use Copilot");
 				disposables.add(button.onDidClick(() => this.runCommandAndClose(newUser ? 'workbench.action.chat.triggerSetup' : () => this.chatEntitlementService.requests?.value.signIn())));
 			}
 		}
+		*/
+		// --- End Positron ---
 
 		return this.element;
 	}
@@ -455,6 +505,9 @@ class ChatStatusDashboard extends Disposable {
 		return update;
 	}
 
+	// --- Start Positron ---
+	// Removed Settings section since it doesn't change Positron Assistant
+	// @ts-ignore
 	private createSettings(container: HTMLElement, disposables: DisposableStore): HTMLElement {
 		const modeId = this.editorService.activeTextEditorLanguageId;
 		const settings = container.appendChild($('div.settings'));
@@ -478,6 +531,7 @@ class ChatStatusDashboard extends Disposable {
 
 		return settings;
 	}
+	// --- End Positron ---
 
 	private createSetting(container: HTMLElement, settingId: string, label: string, accessor: ISettingsAccessor, disposables: DisposableStore): Checkbox {
 		const checkbox = disposables.add(new Checkbox(label, Boolean(accessor.readSetting()), defaultCheckboxStyles));


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This pull request changes the Chat status bar entry to display active completion providers and updates the UI from Copilot to Positron Assistant. Key changes include:
- Updating the status bar entry creation and label to use Positron Assistant icons and messages.
- Injecting ILanguageFeaturesService to fetch and display available completion providers.
- Removing or commenting out Copilot-specific UI elements and related logic.

### Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

| File | Description |
| ---- | ----------- |
| src/vs/workbench/contrib/chat/browser/chatStatus.ts | Updates to the status bar entry and dashboard to reflect Positron Assistant branding and handle completion providers. |
| extensions/positron-assistant/src/extension.ts | Removal of Copilot-specific imports and parameters; update to inline completion provider registration with a display name. |


<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**src/vs/workbench/contrib/chat/browser/chatStatus.ts:369**
* Ensure there are tests covering the new logic for listing completion providers in the dashboard to verify its UI behavior.
```
const entry = { id: 'positron-assistant.completionProviders', label: localize('completionProvidersLabel', "Completion Providers"), description: '', detail: '' }
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T20:48:40Z
user: login: timtmok
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T18:42:24Z
user: login: seeM
body: Looks like a good improvement. I agree we can further refine later / once the API is more stable.
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T09:38:34Z
user: login: timtmok
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-25T22:14:41Z

Review comments:
diff_hunk: @@ -455,6 +502,9 @@ class ChatStatusDashboard extends Disposable {
 		return update;
 	}
 
+	// --- Start Positron ---
+	// Removed Settings section since it doesn't change Positron Assistant
+	// @ts-ignore
 	private createSettings(container: HTMLElement, disposables: DisposableStore): HTMLElement {
 		const modeId = this.editorService.activeTextEditorLanguageId;
 		const settings = container.appendChild($('div.settings'));
path: src/vs/workbench/contrib/chat/browser/chatStatus.ts
user: login: Copilot
body: Avoid using @ts-ignore; address the underlying TypeScript issue in the createSettings method for improved type safety.
```suggestion
	
	private createSettings(container: HTMLElement, disposables: DisposableStore): HTMLElement {
		const modeId: string | undefined = this.editorService.activeTextEditorLanguageId;
		const settings: HTMLElement = container.appendChild($('div.settings'));
```
created_at: 2025-04-22T20:48:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -455,6 +502,9 @@ class ChatStatusDashboard extends Disposable {
 		return update;
 	}
 
+	// --- Start Positron ---
+	// Removed Settings section since it doesn't change Positron Assistant
+	// @ts-ignore
 	private createSettings(container: HTMLElement, disposables: DisposableStore): HTMLElement {
 		const modeId = this.editorService.activeTextEditorLanguageId;
 		const settings = container.appendChild($('div.settings'));
path: src/vs/workbench/contrib/chat/browser/chatStatus.ts
user: login: timtmok
body: Ignored unused `createSettings` to make it easier to merge upstream changes.
created_at: 2025-04-23T18:42:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -164,8 +177,10 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
 	}
 
 	private getEntryProps(): IStatusbarEntry {
-		let text = '$(copilot)';
-		let ariaLabel = localize('chatStatus', "Copilot Status");
+		// --- Start Positron ---
+		let text = '$(positron-assistant)';
+		let ariaLabel = localize('chatStatus', "Positron Assistant Status");
path: src/vs/workbench/contrib/chat/browser/chatStatus.ts
user: login: seeM
body: What do you think about referring to it as just "Assistant" from within Positron?
```suggestion
		let ariaLabel = localize('chatStatus', "Assistant Status");
```
created_at: 2025-04-24T09:37:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -164,8 +177,10 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu
 	}
 
 	private getEntryProps(): IStatusbarEntry {
-		let text = '$(copilot)';
-		let ariaLabel = localize('chatStatus', "Copilot Status");
+		// --- Start Positron ---
+		let text = '$(positron-assistant)';
+		let ariaLabel = localize('chatStatus', "Positron Assistant Status");
path: src/vs/workbench/contrib/chat/browser/chatStatus.ts
user: login: timtmok
body: That makes sense. It's good to keep the wording consistent from the start!
created_at: 2025-04-25T22:14:41Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-22T20:48:36Z
body: <!-- PR Tags -->
<!-- 
🚨 RED ALERT! ✋ Rule breaker detected! Tags don’t go here, they belong above ^ in the PR description using this proper format: `@:tag`. Changing them here won't do anything (trust us, we’ve tried). Confused? Check out the README hyperlink.
-->

**E2E Tests** 🚀
This PR will run tests tagged with: `@:critical`

<sup>[readme](https://github.com/posit-dev/positron/blob/main/test/e2e/README.md#pull-requests-and-test-tags)</sup>&nbsp;&nbsp;<sup>[valid tags](https://github.com/posit-dev/positron/blob/main/test/e2e/infra/test-runner/test-tags.ts)</sup>
author_association: NONE
user: login: petetronic
created_at: 2025-04-27T15:18:28Z
body: If commenting out blocks from upstream, would `/* ... */` block comments be better to keep as many lines the same as upstream for future merge conflict resolution?
author_association: CONTRIBUTOR