Skip to content

chat: route AI customization list through item sources#309666

Draft
joshspicer wants to merge 2 commits intomainfrom
agents/delightful-asp
Draft

chat: route AI customization list through item sources#309666
joshspicer wants to merge 2 commits intomainfrom
agents/delightful-asp

Conversation

@joshspicer
Copy link
Copy Markdown
Member

Summary

Route the AI Customizations list widget through a small browser-internal item-source abstraction instead of branching directly between the promptsService path and extension-provider path.

This keeps Local/static harnesses on the existing rich promptsService loading pipeline (storage filtering, plugin metadata, hook parsing, built-in grouping, etc.) while adapting extension-contributed providers into the same list-item source shape.

Resolves #309627

Notes

  • No promptsService provider is attached to static harness descriptors.
  • No lazy provider/proxy is used.
  • The harness service remains descriptor/state-only and does not depend on IPromptsService.
  • promptsService change subscriptions are owned by the widget's Local item source.

Changes

Commit 1: Extract AI customization item sources

Introduces a pipeline architecture where both data sources converge on IExternalCustomizationItem early:

promptsService ──→ PromptsServiceCustomizationItemProvider ──→ IExternalCustomizationItem[]
                                                                        │
External Provider ────────────────────────────────────────→ IExternalCustomizationItem[]
                                                                        │
                                                                        ▼
                                                  ProviderCustomizationItemSource → AICustomizationItemNormalizer → Widget

New files: aiCustomizationListItem.ts, aiCustomizationItemSourceUtils.ts, aiCustomizationItemNormalizer.ts, promptsServiceCustomizationItemProvider.ts, providerCustomizationItemSource.ts

Commit 2: Clean up extraction

Council-review-driven cleanup:

  • Deduplicate isChatExtensionItem() and hook expansion logic into shared utils
  • Move storageToIcon() to icons file (pure function, retains PromptsStorage type safety)
  • Replace fragile backward-index splice loops with .filter() chains
  • Cache ProviderCustomizationItemSource per active harness descriptor
  • Use O(n) Map lookup for hook storage recovery instead of O(n²) .find()

Validation

  • VS Code - Build watch: clean
  • npm run precommit: passed
  • npm run compile-check-ts-native: clean (only pre-existing errors in copilotAgent.ts)

joshspicer and others added 2 commits April 13, 2026 16:20
Addresses code quality issues from council review:

- Extract shared isChatExtensionItem() to aiCustomizationItemSourceUtils
- Move storageToIcon() to aiCustomizationIcons (pure function, no class dep)
- Extract shared expandHookFileItems() utility, deduplicating hook file
  parsing from PromptsServiceCustomizationItemProvider and
  ProviderCustomizationItemSource
- Replace fragile backward-index splice loops in applyLocalFilters
  with idiomatic .filter() chains
- Cache ProviderCustomizationItemSource per active harness descriptor
  to avoid redundant event composition on every call

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 13, 2026 23:21
@github-actions
Copy link
Copy Markdown
Contributor

Screenshot Changes

Base: 11018d92 Current: b5d1b131

Changed (5)

chat/aiCustomizations/aiCustomizationManagementEditor/HooksTab/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/McpBrowseMode/Light
Before After
before after
chat/aiCustomizations/aiCustomizationManagementEditor/HooksTab/Dark
Before After
before after
editor/inlineCompletions/other/JumpToHint/Light
Before After
before after
editor/inlineCompletions/other/JumpToHint/Dark
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

Refactors the AI Customization management list to fetch items through a unified, browser-internal “item source” abstraction, converging both promptsService-backed discovery and extension-contributed providers onto the same normalized list-item model.

Changes:

  • Introduces IAICustomizationItemSource + supporting utilities/normalizer to unify discovery and normalization into IAICustomizationListItem.
  • Adds a promptsService adapter (PromptsServiceCustomizationItemProvider) so local/static harnesses keep the rich promptsService pipeline while still producing provider-shaped items.
  • Updates the list widget to select/cache an item source per active harness and remove direct branching between “core” vs “provider” paths.
Show a summary per file
File Description
src/vs/workbench/contrib/chat/browser/aiCustomization/providerCustomizationItemSource.ts New unified item source that merges provider items + optional local sync overlays and emits a composed onDidChange.
src/vs/workbench/contrib/chat/browser/aiCustomization/promptsServiceCustomizationItemProvider.ts Adapts IPromptsService to IExternalCustomizationItemProvider, including hook expansion and harness filtering.
src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.ts Switches the widget to consume an IAICustomizationItemSource and cache it per harness descriptor.
src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListItem.ts Extracts the widget list item model + item source contract into a shared browser file.
src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationItemSourceUtils.ts Shared utilities for friendly naming, hook expansion, and built-in chat extension detection.
src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationItemNormalizer.ts Normalizes provider-shaped items into rich UI list items, inferring source/grouping details.
src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationIcons.ts Moves storageToIcon into the icons module.
src/vs/sessions/AI_CUSTOMIZATIONS.md Updates sessions documentation to describe the new management editor item pipeline.

Copilot's findings

  • Files reviewed: 8/8 changed files
  • Comments generated: 2

Comment on lines +82 to +92
switch (item.groupKey) {
case PromptsStorage.local:
case PromptsStorage.user:
case PromptsStorage.extension:
case PromptsStorage.plugin:
return { ...inferred, storage: item.groupKey };
case BUILTIN_STORAGE:
return { ...inferred, storage: PromptsStorage.extension, groupKey: BUILTIN_STORAGE, isBuiltin: true };
default:
return { ...inferred, groupKey: item.groupKey };
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

In resolveSource, when a provider supplies groupKey equal to a PromptsStorage value (e.g. 'user'), the code returns { ...inferred, storage: item.groupKey }. If the URI is non-file: (so inferred.groupKey is BUILTIN_STORAGE and isBuiltin is true), the inferred built-in grouping leaks through and the item will still be grouped/shown as Built-in despite the provider explicitly setting the group. Consider treating PromptsStorage.* groupKeys as an explicit group override: clear/override groupKey and isBuiltin from the inferred value (and/or set groupKey to the provided storage) so the provider’s grouping is respected for non-file URIs too.

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +90
case 'local': return workspaceIcon;
case 'user': return userIcon;
case 'extension': return extensionIcon;
case 'plugin': return pluginIcon;
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

storageToIcon switches on PromptsStorage but uses raw string literals ('local', 'user', …). Since PromptsStorage is an enum, using PromptsStorage.local/user/... here avoids accidental typos and stays resilient if the enum members ever change.

Suggested change
case 'local': return workspaceIcon;
case 'user': return userIcon;
case 'extension': return extensionIcon;
case 'plugin': return pluginIcon;
case PromptsStorage.local: return workspaceIcon;
case PromptsStorage.user: return userIcon;
case PromptsStorage.extension: return extensionIcon;
case PromptsStorage.plugin: return pluginIcon;

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.

AI Customization: Unify item discovery through provider abstraction & cut over sessions

2 participants