Problem
Whether a chat customization is "disabled" is tracked in two independent, unsynchronised stores:
| # |
Store |
Storage key |
Scope / target |
Serialization |
Written by |
| 1 |
IPromptsService.get/setDisabledPromptFiles(type) (promptsServiceImpl.ts) |
chat.disabledPromptFiles.<PromptsType> |
PROFILE / USER |
uri.toJSON() + URI.revive() |
the Disable/Enable actions in aiCustomizationManagement.contribution.ts |
| 2 |
AgentCustomizationSyncProvider (ICustomizationSyncProvider) |
customizationSync.disabled.<harnessId> |
PROFILE / MACHINE |
uri.toString() |
only pluginListWidget.ts (plugins) |
Nothing keeps them in agreement, and they differ in storage target (USER vs MACHINE, so one syncs across machines and the other does not) and in URI serialization.
Consumers pick one essentially at random:
enumerateLocalCustomizationsForHarness read store 2 only.
PureItemProviderItemSource read neither.
ItemProviderItemSource reads store 1.
- The older sessions tree view (
aiCustomizationTreeViewViews.ts) reads store 1.
This is the direct cause of #329751, where the Agents window wrote to store 1 and every relevant consumer read store 2. It produced a particularly confusing symptom: the older sessions tree view did reflect the disabled state, so the same skill appeared disabled in one surface and enabled in another, while the agent host kept receiving it either way.
Why this is worth fixing structurally
The immediate fix for #329751 makes the agent-host wire consult both stores (syncProvider.isDisabled(uri) || userDisabled.has(uri)). That resolves the user-visible bug but entrenches the split: every future consumer now has to remember to OR the two together, and every future writer has to pick the right one. The bug is likely to recur in the next surface that ships.
Suggested direction
Consolidate on a single source of truth for "is this customization disabled", most naturally on IPromptsService, with the sync provider's per-harness store either folded into it or kept strictly as a harness-scoped overlay with an explicit, documented precedence rule. Whichever way it goes, there should be exactly one function that answers the question, and the storage target and URI serialization should be consistent.
The two stores and the requirement to consult both are documented for now in src/vs/sessions/AI_CUSTOMIZATIONS.md under Built-in Skills → Enabling and Disabling Built-in Skills.
Found while investigating #329751.
Problem
Whether a chat customization is "disabled" is tracked in two independent, unsynchronised stores:
IPromptsService.get/setDisabledPromptFiles(type)(promptsServiceImpl.ts)chat.disabledPromptFiles.<PromptsType>PROFILE/USERuri.toJSON()+URI.revive()aiCustomizationManagement.contribution.tsAgentCustomizationSyncProvider(ICustomizationSyncProvider)customizationSync.disabled.<harnessId>PROFILE/MACHINEuri.toString()pluginListWidget.ts(plugins)Nothing keeps them in agreement, and they differ in storage target (
USERvsMACHINE, so one syncs across machines and the other does not) and in URI serialization.Consumers pick one essentially at random:
enumerateLocalCustomizationsForHarnessread store 2 only.PureItemProviderItemSourceread neither.ItemProviderItemSourcereads store 1.aiCustomizationTreeViewViews.ts) reads store 1.This is the direct cause of #329751, where the Agents window wrote to store 1 and every relevant consumer read store 2. It produced a particularly confusing symptom: the older sessions tree view did reflect the disabled state, so the same skill appeared disabled in one surface and enabled in another, while the agent host kept receiving it either way.
Why this is worth fixing structurally
The immediate fix for #329751 makes the agent-host wire consult both stores (
syncProvider.isDisabled(uri) || userDisabled.has(uri)). That resolves the user-visible bug but entrenches the split: every future consumer now has to remember to OR the two together, and every future writer has to pick the right one. The bug is likely to recur in the next surface that ships.Suggested direction
Consolidate on a single source of truth for "is this customization disabled", most naturally on
IPromptsService, with the sync provider's per-harness store either folded into it or kept strictly as a harness-scoped overlay with an explicit, documented precedence rule. Whichever way it goes, there should be exactly one function that answers the question, and the storage target and URI serialization should be consistent.The two stores and the requirement to consult both are documented for now in
src/vs/sessions/AI_CUSTOMIZATIONS.mdunder Built-in Skills → Enabling and Disabling Built-in Skills.Found while investigating #329751.