Skip to content

Conversation

@osortega
Copy link
Contributor

No description provided.

Copilot AI review requested due to automatic review settings January 10, 2026 00:35
@osortega osortega self-assigned this Jan 10, 2026
@osortega osortega marked this pull request as draft January 10, 2026 00:35
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces two main experimental features: a searchable picker UI component for chat session option groups with many items (e.g., repository selection), and an agent sessions start page that provides a welcome/landing page for agent sessions.

Key changes:

  • Adds a searchable property to option groups in the Chat Sessions Provider API to enable QuickPick-based selection for large item lists
  • Implements SearchableOptionPickerActionItem as an alternative to the dropdown-based ChatSessionPickerActionItem
  • Creates a new "Agent Sessions Start Page" editor pane with session history, search, and an embedded chat input widget
  • Modifies the logic for showing session option pickers to display them when items are available, not just when a value is already set

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/vscode-dts/vscode.proposed.chatSessionsProvider.d.ts Adds searchable property to ChatSessionProviderOptionGroup interface for QuickPick UI
src/vs/workbench/contrib/chat/common/chatSessionsService.ts Adds searchable property to internal option group interface
src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts Updates picker creation logic to support searchable option groups and show pickers when items are available
src/vs/workbench/contrib/chat/browser/chatSessions/searchableOptionPickerActionItem.ts New action item component implementing QuickPick-based option selection for searchable groups
src/vs/workbench/contrib/chat/browser/chatSessions/chatSessionPickerActionItem.ts Adds hardcoded default icon and label for repository use case
src/vs/workbench/contrib/chat/browser/chatSessions/media/chatSessionPickerActionItem.css Adds styling for searchable picker with commented-out experimental rules
src/vs/workbench/contrib/chat/browser/chat.contribution.ts Registers the new agent sessions start page contribution
src/vs/workbench/contrib/chat/browser/agentSessionsStartPage/*.ts New editor pane, input, and contribution files for the agent sessions start page
src/vs/workbench/contrib/chat/browser/agentSessionsStartPage/media/agentSessionsStartPage.css Complete styling for the start page UI with collapsible sections and session cards
src/vs/platform/actionWidget/browser/actionWidget.css Increases global min-width for all action widgets from 100px to 160px
src/vs/base/common/network.ts Adds new URI scheme for the agent sessions start page
Comments suppressed due to low confidence (1)

src/vs/workbench/contrib/chat/browser/agentSessionsStartPage/agentSessionsStartPage.ts:116

  • The renderPage() method references this.tabsContainer which is never initialized (it's declared at line 42 but never assigned a value). This will cause the code to attempt operations on undefined. Either the tabs functionality should be fully implemented, or this dead code should be removed.
	private renderPage(): void {
		// Update dynamic parts only (tabs and sessions)
		if (this.tabsContainer) {
			dom.clearNode(this.tabsContainer);
			this.renderTabs(this.tabsContainer);
		}
		this.renderSessions();
	}

Comment on lines +51 to +53
/* .chat-searchable-option-picker-item .chat-session-option-picker > .codicon:first-child {
margin-right: 0px;
} */
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented-out CSS rules should either be removed or have a clear explanation for why they're being kept. The commented rules on lines 51-53 appear to be styling experiments that should either be implemented or deleted.

Suggested change
/* .chat-searchable-option-picker-item .chat-session-option-picker > .codicon:first-child {
margin-right: 0px;
} */

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +137
// const tabsConfig: Array<{ id: 'agents' | 'code' | 'learn'; label: string }> = [
// { id: 'agents', label: 'AGENTS' },
// { id: 'code', label: 'CODE' },
// { id: 'learn', label: 'LEARN' },
// ];

// for (const tab of tabsConfig) {
// const tabButton = dom.append(container, dom.$('button.tab'));
// tabButton.textContent = tab.label;
// if (tab.id === this.selectedTab) {
// tabButton.classList.add('active');
// }
// tabButton.onclick = () => {
// this.selectedTab = tab.id;
// // Re-render tabs to update active state
// dom.clearNode(container);
// this.renderTabs(container);
// };
// }
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extensive commented-out code (lines 119-137 and related fields) should be removed unless there's a specific reason to keep it. If this represents future work for implementing tabs functionality, it should be tracked in an issue rather than left in the codebase. The commented field at line 48 and related code in setInput (lines 432-434) should also be removed.

This issue also appears in the following locations of the same file:

  • line 109
Suggested change
// const tabsConfig: Array<{ id: 'agents' | 'code' | 'learn'; label: string }> = [
// { id: 'agents', label: 'AGENTS' },
// { id: 'code', label: 'CODE' },
// { id: 'learn', label: 'LEARN' },
// ];
// for (const tab of tabsConfig) {
// const tabButton = dom.append(container, dom.$('button.tab'));
// tabButton.textContent = tab.label;
// if (tab.id === this.selectedTab) {
// tabButton.classList.add('active');
// }
// tabButton.onclick = () => {
// this.selectedTab = tab.id;
// // Re-render tabs to update active state
// dom.clearNode(container);
// this.renderTabs(container);
// };
// }

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +17
export interface AgentSessionsStartEditorOptions extends IEditorOptions {
selectedTab?: 'agents' | 'code' | 'learn';
}
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The selectedTab property is defined in the input but never actually used in any meaningful way. The commented code at line 48 and lines 432-434 suggests this was intended to be implemented but wasn't. Either fully implement tab functionality or remove the unused selectedTab property from AgentSessionsStartEditorOptions and AgentSessionsStartInput to avoid confusion.

Copilot uses AI. Check for mistakes.
Comment on lines +737 to +789
const searchableDelegate: ISearchableOptionPickerDelegate = {
getCurrentOption: () => this.getCurrentOptionForGroup(optionGroup.id),
onDidChangeOption: this.getOrCreateOptionEmitter(optionGroup.id).event,
setOption: (option: IChatSessionProviderOptionItem) => {
const ctx = resolveChatSessionContext();
if (!ctx) {
return;
}
this.getOrCreateOptionEmitter(optionGroup.id).fire(option);
this.chatSessionsService.notifySessionOptionsChange(
ctx.chatSessionResource,
[{ optionId: optionGroup.id, value: option }]
).catch(err => this.logService.error(`Failed to notify extension of ${optionGroup.id} change:`, err));
},
getOptionGroup: () => {
const ctx = resolveChatSessionContext();
if (!ctx) {
return undefined;
}
const groups = this.chatSessionsService.getOptionGroupsForSessionType(ctx.chatSessionType);
return groups?.find(g => g.id === optionGroup.id);
}
this.getOrCreateOptionEmitter(optionGroup.id).fire(option);
this.chatSessionsService.notifySessionOptionsChange(
ctx.chatSessionResource,
[{ optionId: optionGroup.id, value: option }]
).catch(err => this.logService.error(`Failed to notify extension of ${optionGroup.id} change:`, err));
},
getAllOptions: () => {
const ctx = resolveChatSessionContext();
if (!ctx) {
return [];
};

const widget = this.instantiationService.createInstance(SearchableOptionPickerActionItem, action, initialState, searchableDelegate, {});
this.chatSessionPickerWidgets.set(optionGroup.id, widget);
widgets.push(widget);
} else {
// Create delegate for standard dropdown picker
const itemDelegate: IChatSessionPickerDelegate = {
getCurrentOption: () => this.getCurrentOptionForGroup(optionGroup.id),
onDidChangeOption: this.getOrCreateOptionEmitter(optionGroup.id).event,
setOption: (option: IChatSessionProviderOptionItem) => {
const ctx = resolveChatSessionContext();
if (!ctx) {
return;
}
this.getOrCreateOptionEmitter(optionGroup.id).fire(option);
this.chatSessionsService.notifySessionOptionsChange(
ctx.chatSessionResource,
[{ optionId: optionGroup.id, value: option }]
).catch(err => this.logService.error(`Failed to notify extension of ${optionGroup.id} change:`, err));
},
getAllOptions: () => {
const ctx = resolveChatSessionContext();
if (!ctx) {
return [];
}
const groups = this.chatSessionsService.getOptionGroupsForSessionType(ctx.chatSessionType);
const group = groups?.find(g => g.id === optionGroup.id);
return group?.items ?? [];
}
const groups = this.chatSessionsService.getOptionGroupsForSessionType(ctx.chatSessionType);
const group = groups?.find(g => g.id === optionGroup.id);
return group?.items ?? [];
}
};
};
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Significant code duplication between the searchableDelegate (lines 737-759) and itemDelegate (lines 766-789) objects. The getCurrentOption, onDidChangeOption, and setOption implementations are identical. Consider extracting these common properties into a shared factory function or base delegate object to improve maintainability and reduce the risk of inconsistencies.

Copilot uses AI. Check for mistakes.
this.labelElement.tabIndex = 0;
this.labelElement.role = 'button';
this.labelElement.setAttribute('aria-haspopup', 'true');
this.labelElement.setAttribute('aria-expanded', 'false');
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The aria-expanded attribute is set to 'false' at line 74 but is never updated to 'true' when the QuickPick is shown. For proper accessibility, this attribute should be updated in the showQuickPick method to indicate when the picker is open, though the QuickPick itself handles its own accessibility, so this may be acceptable as-is given the QuickPick is a separate UI element.

Suggested change
this.labelElement.setAttribute('aria-expanded', 'false');

Copilot uses AI. Check for mistakes.
case 'subagents':
return Codicon.copilot;
default:
return Codicon.sourceControl;
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default case in the switch statement (line 155) returns Codicon.sourceControl, which means any unrecognized option group will get a source control icon. This hardcoded fallback is inappropriate - if the option group ID doesn't match known cases, it should return undefined instead of defaulting to a potentially misleading icon.

Suggested change
return Codicon.sourceControl;
return undefined;

Copilot uses AI. Check for mistakes.
font-size: 13px;
border-radius: 0;
min-width: 100px;
min-width: 160px;
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The min-width change from 100px to 160px affects all action widgets globally, not just the chat session pickers. This could have unintended layout effects on other parts of the application that use the action widget. Consider whether this change should be scoped specifically to chat session pickers using a more specific CSS selector, or if there's a documented reason why all action widgets need to be wider.

Suggested change
min-width: 160px;
min-width: 100px;

Copilot uses AI. Check for mistakes.
Comment on lines +111 to +114
} else {
domChildren.push(...renderLabelWithIcons(`$(source-control)`));
}
domChildren.push(dom.$('span.chat-session-option-label', undefined, this.currentOption?.name ?? localize('chat.sessionPicker.label', "Pick Option")));
domChildren.push(dom.$('span.chat-session-option-label', undefined, this.currentOption?.name ?? localize('chat.sessionPicker.label', "Repository")));
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded default icon and label ("Repository") suggest this code is tied to a specific use case rather than being generic. Since this is supposed to be a generic picker for any option group, these defaults should be removed or made more generic. The icon should only be shown when explicitly provided by the option, and the label should fall back to a generic message like "Pick Option" (which already exists in the code) or the option group name.

See below for a potential fix:

		}
		domChildren.push(dom.$('span.chat-session-option-label', undefined, this.currentOption?.name ?? localize('chat.sessionPicker.label', "Pick Option")));

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants