Skip to content

chat: unify customization item paths via PromptsServiceCustomizationProvider#308618

Closed
joshspicer wants to merge 1 commit intomainfrom
copilot/unify-customization-provider
Closed

chat: unify customization item paths via PromptsServiceCustomizationProvider#308618
joshspicer wants to merge 1 commit intomainfrom
copilot/unify-customization-provider

Conversation

@joshspicer
Copy link
Copy Markdown
Member

Summary

Extracts the ~300-line fetchCoreItemsForSection from the AI Customizations list widget into a new PromptsServiceCustomizationProvider class that implements IExternalCustomizationItemProvider. The widget now uses a single provider-based code path for all harnesses — static (Local, CLI) and extension-contributed.

Follows #308590 which removed the kill-switch setting and Claude harness.

What changed (6 files, +406 / -509 lines)

File Change
promptsServiceCustomizationProvider.ts NEW — Provider class wrapping IPromptsService. Emits IExternalCustomizationItem[] with semantic groupKey (agent-instructions, context-instructions, on-demand-instructions, agents, BUILTIN_STORAGE), badge/badgeTooltip for applyTo patterns, enabled: false for disabled items
aiCustomizationListWidget.ts Deleted fetchCoreItemsForSection (~300 lines), filterItemsForCore (~40), applyBuiltinGroupKeys (~25), storageToIcon, isBuiltin/extensionLabel fields, if/else branching in filterItems(). Simplified hover tooltips and copy actions. Cleaned up unused imports
browser/customizationHarnessService.ts Core VS Code harness creates PromptsServiceCustomizationProvider and spreads itemProvider onto Local descriptor
sessions/.../customizationHarnessService.ts Sessions CLI harness does the same
common/customizationHarnessService.ts CustomizationHarnessServiceBase now extends Disposable for lifecycle management
customizationHarnessService.test.ts Wrapped base class in store.add()

Widget size reduction

~2250 lines → ~1770 lines (-480 lines). The deleted code was the complete "core discovery path" that only the Local harness used. It's now handled by the provider class (~340 lines) which emits items in the same format as extension-contributed providers.

Verification

  • TypeScript compilation clean
  • All 15 customizationHarnessService unit tests pass
  • Pre-commit hygiene hooks pass

Copilot AI review requested due to automatic review settings April 8, 2026 21:44
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 8, 2026

Screenshot Changes

Base: 9588b708 Current: d1d8c121

Changed (24)

chat/aiCustomizations/aiCustomizationListWidget/InstructionsTabWithItems/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationListWidget/InstructionsTabWithItems/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/LocalHarness/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/LocalHarness/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/CliHarness/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/CliHarness/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/Sessions/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/Sessions/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SessionsSkillsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SessionsSkillsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SkillsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/SkillsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/InstructionsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/InstructionsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/HooksTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/HooksTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTab/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTabScrolled/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/PromptsTabScrolled/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTabNarrow/Dark
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/AgentsTabNarrow/Light
Before After
before after

Copy link
Copy Markdown
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 refactors the Chat Customizations management UI to use a single provider-based item loading path by extracting the legacy “core discovery” logic into a new PromptsServiceCustomizationProvider that wraps IPromptsService. This reduces complexity in the list widget and aligns Local/CLI harnesses with extension-contributed harness behavior.

Changes:

  • Added PromptsServiceCustomizationProvider implementing IExternalCustomizationItemProvider to emit customization items from IPromptsService.
  • Updated core (workbench) and sessions harness services to attach the new provider to their static harness descriptors.
  • Simplified AICustomizationListWidget by removing the legacy core-fetch/filter pipeline and always using the provider-based path.
Show a summary per file
File Description
src/vs/workbench/contrib/chat/browser/aiCustomization/promptsServiceCustomizationProvider.ts New provider that produces IExternalCustomizationItem[] from IPromptsService and emits change events.
src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.ts Removes legacy core discovery path and routes everything through provider-based loading/grouping.
src/vs/workbench/contrib/chat/browser/aiCustomization/customizationHarnessService.ts Core harness now creates/registers the new provider and attaches it to the Local descriptor.
src/vs/sessions/contrib/chat/browser/customizationHarnessService.ts Sessions harness now creates/registers the new provider and attaches it to the CLI descriptor.
src/vs/workbench/contrib/chat/common/customizationHarnessService.ts CustomizationHarnessServiceBase now extends Disposable for lifecycle management.
src/vs/workbench/contrib/chat/test/common/customizationHarnessService.test.ts Test updated to dispose the base service via store.add().

Copilot's findings

  • Files reviewed: 6/6 changed files
  • Comments generated: 4

}

/**
/**
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

There’s an extra nested doc-comment opener (/**) here, which makes the comment block look malformed and is likely accidental. Please remove the redundant /** so the JSDoc is a single well-formed block.

Suggested change
/**

Copilot uses AI. Check for mistakes.
Comment on lines +276 to +279
// --- Post-processing: storage source filter ---
const filteredItems = this._applyFilters(items);

return filteredItems;
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

The comment says this is a “Post-processing: storage source filter”, but _applyFilters currently only applies workspaceSubpaths/instructionFileFilter and never applies the harness’s storage source filter (sources + includedUserFileRoots). This is important for restricted harnesses like CLI, which should not surface user items outside the allowed roots. Please apply descriptor.getStorageSourceFilter(...) filtering (potentially per-item-type) before returning the list.

Copilot uses AI. Check for mistakes.
Comment on lines +309 to +314
result = result.filter(item => {
if (item.uri.scheme !== Schemas.file || !projectRoot || !item.uri.path.startsWith(projectRoot.path)) {
return true;
}
if (matchesWorkspaceSubpath(item.uri.path, subpaths)) {
return true;
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

Workspace-subpath filtering is using item.uri.scheme === file plus item.uri.path.startsWith(projectRoot.path). This can fail for remote/workspace URIs (e.g. vscode-remote:) and can produce false positives on path prefixes (e.g. /proj/foo vs /proj/foobar). Consider using isEqualOrParent(item.uri, projectRoot) (or an equivalent URI-aware parent check) and avoid hard-coding the scheme to file so the filter works consistently in remote workspaces too.

Copilot uses AI. Check for mistakes.
Comment on lines 1196 to 1199
private async fetchItemsForSection(section: AICustomizationManagementSection): Promise<IAICustomizationListItem[]> {
const promptType = sectionToPromptType(section);
const activeDescriptor = this.harnessService.getActiveDescriptor();

if (activeDescriptor.itemProvider && promptType) {
return this.fetchProviderItemsForSection(activeDescriptor, promptType);
}

return this.fetchCoreItemsForSection(promptType);
return this.fetchProviderItemsForSection(this.harnessService.getActiveDescriptor(), promptType);
}
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

Now that all harnesses (including Local/CLI) go through the provider-based path, items coming from PromptsService will frequently have groupKey set (built-in, instruction categories, etc.). In fetchItemsFromProvider, the current mapping skips _inferStorageAndGroup when groupKey is present, leaving storage undefined, which can break context-key when-clauses that rely on AI_CUSTOMIZATION_ITEM_STORAGE_KEY (e.g. read-only/delete/enable-disable actions). Please ensure storage is still inferred/set even when a provider supplies a custom groupKey (grouping and storage shouldn’t be mutually exclusive).

Copilot uses AI. Check for mistakes.
@joshspicer joshspicer force-pushed the copilot/unify-customization-provider branch from 981665a to 1aa6371 Compare April 8, 2026 22:00
…rovider

Extract fetchCoreItemsForSection from the list widget into a new
PromptsServiceCustomizationProvider class that implements
IExternalCustomizationItemProvider. It emits IExternalCustomizationItem[]
with rich metadata (groupKey, badge, description, enabled) so the
widget's single provider-based code path handles all harnesses.

The Local (VSCode) and Sessions CLI harness services now create a
PromptsServiceCustomizationProvider and wire it as the itemProvider on
their static harness descriptors. This eliminates the if/else branching
in fetchItemsForSection and filterItems, and removes ~500 lines of
legacy core-path code from the widget:

- fetchCoreItemsForSection (~300 lines)
- filterItemsForCore (~40 lines)
- applyBuiltinGroupKeys (~25 lines)
- storageToIcon, findPluginUri, isBuiltin/extensionLabel fields
- Unused imports (dirname, ResourceSet, applyStorageSourceFilter, etc.)

CustomizationHarnessServiceBase now extends Disposable for lifecycle
management of the provider's event subscriptions.
@joshspicer joshspicer force-pushed the copilot/unify-customization-provider branch from 1aa6371 to 757195e Compare April 8, 2026 22:07
@joshspicer joshspicer closed this Apr 8, 2026
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