Support top-level model in managed settings while retaining permissions.model - #330574
Draft
joshspicer wants to merge 1 commit into
Draft
Support top-level model in managed settings while retaining permissions.model#330574joshspicer wants to merge 1 commit into
model in managed settings while retaining permissions.model#330574joshspicer wants to merge 1 commit into
Conversation
…ns.model VS Code drove the default chat model (ChatDefaultModel policy) only from the legacy nested `permissions.model` managed-settings key. Also consume the new top-level `model` key, retaining `permissions.model` for original-schema deployments; when both are present the top-level `model` wins. Because the server and file channels funnel through `normalizeManagedSettings` (which flattens scalar leaves) and native MDM watches only declared keys, the fix is: declare `model` on the policy so it is watched + projected on every channel, and resolve the top-level-over-legacy precedence in the policy value callback (`managedModelValue`). Precedence is key-level, so a non-empty top-level `model` wins even over a `permissions.model` from a higher-precedence channel; a blank top-level value falls back to the legacy key. Fixes #330364 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds support for top-level managed model settings while preserving legacy permissions.model.
Changes:
- Adds normalized top-level model precedence and policy wiring.
- Extends server response typing and documentation.
- Adds normalization and precedence tests.
Show a summary per file
| File | Description |
|---|---|
src/vs/workbench/services/accounts/browser/managedSettings.ts |
Types both model locations. |
src/vs/workbench/contrib/chat/browser/chat.shared.contribution.ts |
Declares both managed keys. |
src/vs/platform/policy/common/copilotManagedSettings.ts |
Implements model precedence and normalization. |
src/vs/platform/policy/test/common/copilotManagedSettings.test.ts |
Tests resolution behavior. |
src/vs/platform/policy/test/common/fileManagedSettingsService.test.ts |
Tests flattened model keys. |
.github/skills/policy-and-managed-settings/github-managed-settings.md |
Documents schema and precedence. |
Review details
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Suppressed comments (2)
src/vs/platform/policy/common/copilotManagedSettings.ts:178
- This JSDoc exceeds the repository's 1–2 sentence hard limit and enumerates implementation branches and architecture already expressed by the code and tests. Condense it to the callback contract.
* `value` callback for the default-chat-model managed setting. Resolves the top-level
* {@link COPILOT_TOP_LEVEL_MODEL_KEY} first and falls back to the legacy nested
* {@link COPILOT_MODEL_KEY} — so a deployment on either schema shape works, and when both are
* present the top-level value wins. Like {@link managedSettingValue} it locks the setting to the
* managed value and otherwise falls through to the user's own value, but it additionally trims each
src/vs/platform/policy/test/common/fileManagedSettingsService.test.ts:148
- This inline comment only restates the test name and assertions and spans multiple lines, contrary to the repository's one-line hard limit for inline method comments. Remove it.
// A payload authored against both schema shapes flattens to two distinct bag keys; the
// policy value callback resolves the top-level one.
- Files reviewed: 6/6 changed files
- Comments generated: 4
- Review effort level: Balanced
Comment on lines
+192
to
+193
| const topLevel = normalizeModelValue(policyData.managedSettings?.[COPILOT_TOP_LEVEL_MODEL_KEY]); | ||
| return topLevel ?? normalizeModelValue(policyData.managedSettings?.[COPILOT_MODEL_KEY]); |
Comment on lines
+79
to
+81
| * `permissions.model` in the normalized bag. Retained for deployments authored against the original | ||
| * schema; new deployments use the top-level {@link COPILOT_TOP_LEVEL_MODEL_KEY}, which wins when | ||
| * both are present. See {@link managedModelValue} for the precedence. |
Comment on lines
+133
to
+135
| // The current managed-settings schema carries `model` at the top level; as a scalar leaf it | ||
| // flattens to the bag key `model`, which the ChatDefaultModel policy value callback reads | ||
| // with precedence over the legacy nested key. |
Comment on lines
+85
to
+86
| | `model` | string (`auto`, a model family name, or a full model id) | top-level wins over the legacy nested `permissions.model` | | ||
| | `permissions.model` | string (legacy location for `model`) | superseded by top-level `model` when both are present; retained for original-schema deployments | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #330364
Summary
VS Code drove the default chat model (the
ChatDefaultModelpolicy →chat.defaultModelsetting) only from the legacy nestedpermissions.modelmanaged-settings key. This PR also consumes the new top-levelmodelkey while retainingpermissions.modelfor deployments authored against the original schema. When both are present, top-levelmodelwins. The behavior is consistent across all three delivery channels: server API, file on disk, and native MDM.Why the change lands where it does
adaptManagedSettings) and file (FileManagedSettingsService) both funnel through the single normalizernormalizeManagedSettings, which flattens nested objects to dot-paths.{ model }is a scalar leaf, so it flattens to the bag keymodelfor free — no structured-settings row needed.managedSettings, andprojectManagedSettingsdrops any bag key that isn't declared. So the top-levelmodelkey is now declared on theChatDefaultModelpolicy — that is what makes native MDM deliver it and projection keep it on every channel.value()callbackmanagedModelValue(), since the two are distinct bag keys. The channel-precedence logic inpickManagedSettingsonly merges the same key across channels, so it can't express "top-level supersedes legacy" — that lives in the callback.Changes
copilotManagedSettings.ts— addCOPILOT_TOP_LEVEL_MODEL_KEY = 'model'; updatemanagedModelValue()to resolve the top-level key first and fall back topermissions.model(extracting a smallnormalizeModelValuetrim helper; blank/whitespace treated as unset). Preserves the memoized single-reference contract.chat.shared.contribution.ts— declare both keys in theChatDefaultModelpolicy'smanagedSettingsso native MDM watchesmodeland projection keeps it.managedSettings.ts(server response type) — typemodelat the top level and underpermissionsonIManagedSettingsResponse(documentation/typing; runtime already accepted them via the forward-compatible index signature).github-managed-settings.md: add the top-levelmodelrows to the schema + constants tables and a note explaining the key-level precedence.copilotManagedSettings.test.tsandfileManagedSettingsService.test.ts.Behavior details
modelwins even whenpermissions.modelwas supplied by a higher-precedence channel (e.g. native MDM). This matches the issue ("if both are present, top-levelmodelshould win").modelis treated as unset and falls back to the legacy key (mirroring the existing blank→unset rule for a cleared field).managedSettingsmappings aren't part of the exportedPolicyDto(policyData.jsoncis unchanged).Validation
tscharness — all pass.build/lib/policies/policyData.jsoncis unchanged.