Conversation
Instead of hard-blocking subagent models that exceed the main model's cost tier, show a confirmation dialog with "Allow" / "Use Current Model" buttons. If the user approves, the expensive model is used; otherwise the subagent falls back to the parent model. - resolveSubagentModel returns exceedsCostTier info instead of throwing - prepareToolInvocation surfaces confirmationMessages with customButtons - invoke checks selectedCustomButton to apply or fall back - chatListRenderer skips subagent grouping while parent tool awaits confirmation
Screenshot ChangesBase: Changed (5) |
There was a problem hiding this comment.
Pull request overview
Enables subagent invocations to request a model that exceeds the current session model’s cost tier by returning a confirmation prompt (rather than hard-blocking), and updates rendering/tests to support the new confirmation flow.
Changes:
- Update
RunSubagentToolmodel resolution to return confirmation messages when the selected subagent model exceeds the current cost tier, and apply the user’s choice duringinvoke. - Adjust chat list rendering so parent subagent tool invocations that are waiting for confirmation render as a regular tool invocation (so confirmation buttons are visible).
- Update/add unit tests to cover the new prepare/invoke confirmation behavior.
Show a summary per file
| File | Description |
|---|---|
| src/vs/workbench/contrib/chat/test/common/tools/builtinTools/runSubagentTool.test.ts | Updates existing tests from “throws” to “confirmation returned” and adds invoke-path tests for Allow vs fallback behavior. |
| src/vs/workbench/contrib/chat/common/tools/builtinTools/runSubagentTool.ts | Implements expensive-model confirmation via confirmationMessages, caches resolution between prepare/invoke, and applies user choice during invoke. |
| src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.ts | Ensures parent subagent tool invocations waiting for confirmation are not grouped, allowing confirmation UI to display. |
Copilot's findings
Comments suppressed due to low confidence (1)
src/vs/workbench/contrib/chat/test/common/tools/builtinTools/runSubagentTool.test.ts:1146
- This test hardcodes the custom-button label ('Use Current Model') into
selectedCustomButton. Since the production label is localized and may change, consider sourcing it from the same localization key used byRunSubagentToolso the test stays aligned with the UI string.
modelId: 'main-model-id',
selectedCustomButton: 'Use Current Model',
} as IToolInvocation, async () => 0, { report() { } }, CancellationToken.None);
- Files reviewed: 3/3 changed files
- Comments generated: 3
| private applyResolvedModel(resolved: IResolvedSubagentModel, invocation: IToolInvocation, apply: (result: { modeModelId: string | undefined; resolvedModelName: string | undefined }) => void): void { | ||
| if (resolved.exceedsCostTier && invocation.selectedCustomButton !== localize('subagent.expensiveModel.allow', "Allow")) { | ||
| // User chose "Use Current Model" or didn't approve — fall back to the main model | ||
| const fallback = resolved.exceedsCostTier; | ||
| apply({ modeModelId: fallback.fallbackModelId, resolvedModelName: fallback.fallbackModelName }); |
There was a problem hiding this comment.
applyResolvedModel decides approval by comparing invocation.selectedCustomButton to a freshly-localized "Allow" string. This is tightly coupled to the button label and can silently break if the label/translation changes (comparison logic and customButtons would drift). Consider deriving the comparison value from the same source as the buttons (e.g. reuse a shared constant for the allow label, or persist the allow-button label/id in the cached resolved-model data) so prepare/invoke stay consistent.
| message: localize( | ||
| 'subagent.expensiveModel.message', | ||
| "The subagent requests '{0}' ({1}x premium) which exceeds the current model's cost tier ({2}x). Allow the expensive model, or continue with '{3}'?", | ||
| modelName, modelMultiplier, mainMultiplier, fallbackModelName ?? 'current model' |
There was a problem hiding this comment.
The confirmation message inserts the fallback label via fallbackModelName ?? 'current model'. Since this string can be shown to the user, it should be localized as well (or moved into the localized message template) to avoid leaking an English-only fragment in non-English locales.
| modelName, modelMultiplier, mainMultiplier, fallbackModelName ?? 'current model' | |
| modelName, | |
| modelMultiplier, | |
| mainMultiplier, | |
| fallbackModelName ?? localize('subagent.expensiveModel.currentModel', "current model") |
| modelId: 'main-model-id', | ||
| selectedCustomButton: 'Allow', | ||
| } as IToolInvocation, async () => 0, { report() { } }, CancellationToken.None); |
There was a problem hiding this comment.
This test hardcodes the custom-button label ('Allow') into selectedCustomButton. Since the production label is localized and may change, consider sourcing it from the same localization key used by RunSubagentTool so the test stays aligned with the UI string.
This issue also appears on line 1144 of the same file.
Implements #309540