Skip to content

chatCustomizations: support grouping and badges for external provider items#305813

Merged
joshspicer merged 5 commits intomicrosoft:mainfrom
joshspicer:copilot/existing-bovid
Mar 27, 2026
Merged

chatCustomizations: support grouping and badges for external provider items#305813
joshspicer merged 5 commits intomicrosoft:mainfrom
joshspicer:copilot/existing-bovid

Conversation

@joshspicer
Copy link
Copy Markdown
Member

Summary

When the Chat Customizations editor displays items from an external provider (e.g., Copilot CLI), they were previously rendered as a flat, ungrouped list with no badge support. This PR adds:

  1. Auto-detected storage-based grouping — Provider items are now automatically grouped into Workspace/User/Plugin categories by inferring storage from the item URI (checking workspace folders, user data prompts home, and plugin locations). No provider changes needed.

  2. Explicit groupKey support — Providers can optionally set groupKey on items to create custom group headers (e.g., "Agent Instructions", "Included Based On Context", "Loaded On Demand" for instructions).

  3. Badge support — Providers can set badge and badgeTooltip on items to display inline badges like applyTo glob patterns (e.g., src/vs/sessions/**).

Changes

customizationHarnessService.ts

  • Extended IExternalCustomizationItem with optional groupKey, badge, badgeTooltip fields

aiCustomizationListWidget.ts

  • Added inferStorageFromUri() — infers PromptsStorage from URI by checking workspace folders, user data home, and plugin locations
  • Added sectionToIcon() — maps management sections to their corresponding icons for group headers
  • Updated fetchItemsFromProvider() to pass through groupKey/badge/badgeTooltip and auto-set storage
  • Updated filterItems() grouping logic:
    • Items with explicit groupKey → grouped by key with auto-built headers
    • Items without groupKey → fall through to standard storage-based grouping (Workspace/User/Plugin/Extension/Built-in)"

Copilot AI review requested due to automatic review settings March 27, 2026 20:31
@vs-code-engineering vs-code-engineering bot added this to the Backlog milestone Mar 27, 2026
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 enhances the Chat Customizations management UI to better support items coming from external customization providers (e.g., provider-backed harnesses) by enabling provider-defined grouping and inline badges, while also auto-inferring an item’s storage origin from its URI.

Changes:

  • Extend IExternalCustomizationItem with optional groupKey, badge, and badgeTooltip.
  • Add URI-based storage inference for provider items and pass through grouping/badge fields into list items.
  • Update list filtering/grouping to support provider-defined groupKey headers (falling back to storage-based grouping when no explicit groups are provided).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
src/vs/workbench/contrib/chat/common/customizationHarnessService.ts Extends the external provider item contract with grouping/badge metadata.
src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationListWidget.ts Implements storage inference for provider items and updates grouping logic to render provider-defined groups and badges.

joshspicer and others added 2 commits March 27, 2026 13:41
- Remove duplicate sectionToIcon, reuse getSectionIcon instance method
- Use Map for O(1) groupKey lookups instead of O(n²) includes/find
- Check active project root in inferStorageFromUri for Sessions window
- Set pluginUri on provider items and use it for storage inference
- Remove redundant plugin check from inferStorageFromUri (handled by caller)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@joshspicer joshspicer marked this pull request as ready for review March 27, 2026 21:30
@joshspicer joshspicer enabled auto-merge (squash) March 27, 2026 21:33
joshspicer added a commit that referenced this pull request Mar 27, 2026
Move instruction enrichment from inline in fetchItemsFromProvider to a
post-processing step (enrichProviderInstructionItems) called from
fetchItemsForSection. This avoids touching fetchItemsFromProvider's
mapping logic which #305813 also modifies.

Restore the flat-list early return in filterItems (305813 replaces it
with groupKey-based grouping). Drop our inferStorageFromUri in favor
of the one 305813 adds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@joshspicer joshspicer merged commit 7efa1c5 into microsoft:main Mar 27, 2026
19 checks passed
joaomoreno pushed a commit that referenced this pull request Apr 7, 2026
…opilot CLI (#4772)

* Add customization providers for Claude and Copilot CLI chat sessions

* Add unit tests for chat session customization providers

Add tests for ClaudeCustomizationProvider and CopilotCLICustomizationProvider
covering metadata, item discovery, and change event forwarding. Refactor
metadata from static readonly to static getter for testability (avoids
class initializer accessing vscode.ChatSessionCustomizationType before
shim setup).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix customization provider accuracy: add hook discovery, mark unsupported types

- Claude provider now discovers hooks from .claude/settings.json and
  .claude/settings.local.json (workspace + user home), reporting them
  as ChatSessionCustomizationType.Hook items with event/matcher names
- Copilot CLI provider marks both Hook and Prompt as unsupported since
  it doesn't support hooks and prompt files aren't enumerable via the API
- Claude provider now takes IWorkspaceService, IFileSystemService, and
  INativeEnvService to read settings files for hook discovery
- Added 6 new hook discovery tests covering workspace/user settings,
  multiple matchers, invalid JSON, and missing files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Mark Agent as unsupported for Claude customization provider

Claude doesn't use .agent.md files — it has its own agent system via
CLAUDE.md memory files and the Claude Agent SDK. Remove Agent items
from Claude's provideChatSessionCustomizations output and add Agent
to its unsupportedTypes metadata.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove workspaceSubpaths from API, add internal path filtering

Remove the workspaceSubpaths property from ChatSessionCustomizationProviderMetadata
since the extension should filter internally. Each provider now only returns items
under its relevant paths:

- Claude: instructions/skills under .claude/ (workspace folders + user home)
- Copilot CLI: instructions/skills under .github/ or .copilot/ (agents are always
  included since they're Copilot-specific)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add TODO comments for work in progress on chatSessionCustomizationProvider API

* Sync chatSessionCustomizationProvider d.ts with VS Code origin/main

Add groupKey, badge, and badgeTooltip fields to ChatSessionCustomizationItem
to match upstream changes from #305810 and #305813.

The providers don't set these fields explicitly — the VS Code UI
auto-enriches instruction items by parsing frontmatter when groupKey
is not provided.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* sessions: Claude customization provider uses SDK runtime data

- Add IClaudeRuntimeDataService to cache agents from Query.supportedAgents()
- ClaudeCodeSession calls runtimeDataService.update() after query creation
- Rewrite ClaudeCustomizationProvider:
  - Agents: reported from SDK via IClaudeRuntimeDataService (built-in groupKey)
  - Instructions: hard-coded CLAUDE.md paths with existence checks
  - Skills: filtered from IChatPromptFileService under .claude/
  - Hooks: unchanged (from .claude/settings.json)
- unsupportedTypes changed from [Agent, Prompt] to [Prompt] only
- 28 tests (22 provider + 6 service)

* sessions: Copilot CLI customization provider uses runtime agent data

- Inject ICopilotCLIAgents to enrich agents with displayName/description
- Expand path filter: add .agents/ to CLI_SUBPATHS
- Add home directory support: ~/.copilot/, ~/.agents/
- Listen to ICopilotCLIAgents.onDidChangeAgents for change events
- 21 tests covering new paths, agent enrichment, and events

* fix: register IClaudeRuntimeDataService in test services

The existing claudeCodeAgent tests were failing because ClaudeCodeSession
now depends on IClaudeRuntimeDataService, but it was not registered in
createExtensionUnitTestingServices().

* sessions: implement correct chatSessionCustomizationProvider for Claude and Copilot CLI

Claude provider:
- New IClaudeRuntimeDataService to cache SDK Query agents
- Hybrid agent approach: file-based .claude/ agents pre-session, SDK agents post-session
- Instructions from hard-coded CLAUDE.md paths (stat-checked)
- Skills from .claude/skills/ via IChatPromptFileService
- Hooks from .claude/settings.json (unchanged)
- Per-category debug logging with names

Copilot CLI provider:
- ICopilotCLIAgents as primary agent source (SDK + prompt files)
- Path filter expanded to .github/, .copilot/, .agents/
- Home directory support (~/.copilot/, ~/.agents/)
- Agent enrichment with displayName/description from SDK

Menu contributions:
- chat/customizations/create for Claude agents, hooks, instructions sections

Code review fixes:
- Use stat() instead of readFile() for existence checks
- Fire-and-forget runtimeDataService.update() to avoid blocking session startup
- Restore vscode.ChatSessionCustomizationType in test afterEach
- Type-safe makeSweAgent helper (no as any)

* claude: mark plugins as unsupported type

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

3 participants