Prototype: Auto Model Routing collapsible card in chat (dev command)#311442
Prototype: Auto Model Routing collapsible card in chat (dev command)#311442
Conversation
Agent-Logs-Url: https://github.com/microsoft/vscode/sessions/43632c6f-4ef0-4342-a39f-755e5c941185 Co-authored-by: eli-w-king <201316543+eli-w-king@users.noreply.github.com>
Agent-Logs-Url: https://github.com/microsoft/vscode/sessions/43632c6f-4ef0-4342-a39f-755e5c941185 Co-authored-by: eli-w-king <201316543+eli-w-king@users.noreply.github.com>
|
@copilot this doesn't look great but it works as expected. can we make it look a bit more like the origional desgin but more vscode. the image with the colors is the ogigional design. we can include grey bar graphs maybe? idk |
Agent-Logs-Url: https://github.com/microsoft/vscode/sessions/a24389ee-311f-450a-aa68-371b35c2e4d3 Co-authored-by: eli-w-king <201316543+eli-w-king@users.noreply.github.com>
Reworked the expanded view in 699a7be — header + intent chip, a one‑line reason, small chips for confidence/latency/cost, and a unified ranked list with grey horizontal bar graphs (selected model highlighted with a check + accent bar, other candidates in muted grey). All colors come from VS Code theme tokens ( Static preview of the new look (dark theme): |
|
@copilot also the two column reason styling could be better. |
Agent-Logs-Url: https://github.com/microsoft/vscode/sessions/ee62e087-8ae4-4a20-a525-626fe241160e Co-authored-by: eli-w-king <201316543+eli-w-king@users.noreply.github.com>
Restructured the candidate row in c501642 — the reason is no longer a second row spanning under the bar/score columns. It now sits as a muted subtitle directly under the model name in a single left-hand column, with the bar and score aligned vertically on the right. Italic styling dropped. |
There was a problem hiding this comment.
Pull request overview
Adds a prototype “Auto Model Routing” collapsible chat content part (behind a Developer command) to preview how an auto model selection decision could be surfaced in the VS Code chat UI.
Changes:
- Introduces new progress/content kind
autoModelRouting(IChatAutoModelRoutingPart) and threads it through chat model/history/serialization handling. - Adds a new
ChatAutoModelRoutingContentPartrenderer and wires it intochatListRenderer. - Adds a Developer command to inject a sample routing card into the focused chat session.
Show a summary per file
| File | Description |
|---|---|
| src/vs/workbench/contrib/chat/common/model/chatSessionOperationLog.ts | Treats autoModelRouting as a static response-part kind for mutation logging. |
| src/vs/workbench/contrib/chat/common/model/chatModel.ts | Adds IChatAutoModelRoutingPart to history content union and ignores it in partsToRepr. |
| src/vs/workbench/contrib/chat/common/chatService/chatService.ts | Defines IChatAutoModelRoutingPart + related types; adds to IChatProgress. |
| src/vs/workbench/contrib/chat/browser/widget/chatListRenderer.ts | Dispatches autoModelRouting to a new content-part renderer. |
| src/vs/workbench/contrib/chat/browser/widget/chatContentParts/media/chatAutoModelRoutingContentPart.css | Styles for the new routing collapsible card. |
| src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatAutoModelRoutingContentPart.ts | Implements the collapsible routing card renderer. |
| src/vs/workbench/contrib/chat/browser/actions/chatDeveloperActions.ts | Adds a Developer command that injects a sample autoModelRouting part into chat. |
Copilot's findings
Comments suppressed due to low confidence (2)
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatAutoModelRoutingContentPart.ts:94
hasSameContentonly compares candidatemodelNames and ignoresscore/reason. If the routing details update (e.g. scores change or reasons change), this method can incorrectly returntrueand prevent the UI from re-rendering. Include the relevant candidate fields in the equality check (or use a shallow/deep compare of the candidate objects).
const a = this.routingPart.candidates ?? [];
const b = other.candidates ?? [];
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (a[i].modelName !== b[i].modelName) {
return false;
}
}
src/vs/workbench/contrib/chat/browser/widget/chatContentParts/chatAutoModelRoutingContentPart.ts:56
- The
Learn morelink opens a new tab/window viatarget="_blank"but doesn’t setrel="noopener noreferrer". This allows the opened page to accesswindow.openerand can be a security issue. Add the appropriaterelattributes (or avoidtarget=_blankand route through the opener service).
const learnMore = $('a.chat-auto-model-routing-learn-more', { href: 'https://aka.ms/copilot-auto-model', target: '_blank' },
localize('autoModelRouting.learnMore', "Learn more"));
- Files reviewed: 7/7 changed files
- Comments generated: 4
| /** | ||
| * A progress part representing the execution result of a hook. | ||
| * Aligned with the hook output JSON structure: { stopReason, systemMessage, hookSpecificOutput }. | ||
| * If {@link stopReason} is set, the hook blocked/denied the operation. | ||
| */ | ||
| /** | ||
| * Prototype: a part describing how the "auto" model selector routed a request | ||
| * to a specific underlying language model. Rendered as a collapsible card, | ||
| * similar to thinking and tool-call parts. | ||
| */ |
There was a problem hiding this comment.
There are two consecutive JSDoc blocks here; the first one (“A progress part representing the execution result of a hook…”) is now detached from IChatHookPart and will no longer document the hook type. Merge/move that comment so it sits immediately above export interface IChatHookPart, and keep only one doc block at this location.
| protected override initContent(): HTMLElement { | ||
| const container = $('.chat-auto-model-routing-body'); | ||
|
|
||
| // Build capability sentence from top 2 capabilities by score | ||
| const caps = this.routingPart.capabilities; | ||
| let capSentence: string; | ||
| if (caps && caps.length >= 2) { | ||
| const top = [...caps].sort((a, b) => b.score - a.score).slice(0, 2).map(c => c.name.toLowerCase()); | ||
| capSentence = localize('autoModelRouting.capSentence', "{0} is selected for high {1} and {2} capability. ", | ||
| this.routingPart.selectedModel, top[0], top[1]); | ||
| } else if (caps && caps.length === 1) { | ||
| capSentence = localize('autoModelRouting.capSentenceSingle', "{0} is selected for high {1} capability. ", | ||
| this.routingPart.selectedModel, caps[0].name.toLowerCase()); | ||
| } else { | ||
| capSentence = ''; | ||
| } | ||
|
|
||
| const para = $('.chat-auto-model-routing-footer'); | ||
| para.appendChild($('span', undefined, capSentence)); | ||
| para.appendChild($('span', undefined, | ||
| localize('autoModelRouting.footer', "Auto routes based on your task and real-time system health and model performance. "))); | ||
| const learnMore = $('a.chat-auto-model-routing-learn-more', { href: 'https://aka.ms/copilot-auto-model', target: '_blank' }, | ||
| localize('autoModelRouting.learnMore', "Learn more")); | ||
| para.appendChild(learnMore); | ||
| container.appendChild(para); | ||
|
|
||
| // Capability score list | ||
| if (this.routingPart.capabilities && this.routingPart.capabilities.length > 0) { | ||
| container.appendChild($('span.chat-auto-model-routing-section-label', undefined, | ||
| localize('autoModelRouting.capabilities', "Task requirements"))); | ||
| const list = $('ul.chat-auto-model-routing-scores'); | ||
| for (const cap of this.routingPart.capabilities) { | ||
| const li = $('li.chat-auto-model-routing-score-row'); | ||
| li.appendChild($('span.chat-auto-model-routing-score-name', undefined, cap.name)); | ||
| li.appendChild($('span.chat-auto-model-routing-score-pct', undefined, `${Math.round(cap.score * 100)}%`)); | ||
| list.appendChild(li); | ||
| } | ||
| container.appendChild(list); | ||
| } |
There was a problem hiding this comment.
IChatAutoModelRoutingPart carries fields like selectionReason, intent, confidence, costTier, and candidates, but the renderer currently only shows a generic footer + capabilities list and never surfaces those fields. This doesn’t match the PR description/UI goals and makes the injected sample data mostly unused; either render the additional fields (reason/intent/metadata/candidate ranking) or trim the part shape/sample to what is actually displayed.
This issue also appears in the following locations of the same file:
- line 55
- line 85
| const message: IChatProgress[] = [ | ||
| { kind: 'markdownContent', content: new MarkdownString('Routing your request through Copilot Auto…') }, | ||
| routingPart, | ||
| { kind: 'markdownContent', content: new MarkdownString('Done — using **Claude Opus 4.6** for this turn.') }, | ||
| ]; |
There was a problem hiding this comment.
The injected chat markdown strings ("Routing your request through Copilot Auto…", "Done — using …") are user-visible but not localized. Please wrap these in localize(...) (or otherwise externalize them) even though the command is Developer-only, to keep the codebase’s localization guarantees consistent.
| color: var(--vscode-descriptionForeground); | ||
| } |
There was a problem hiding this comment.
CSS has a stray color: declaration and an extra closing } after .chat-auto-model-routing-score-row, which makes the stylesheet invalid and can cause the remaining rules to be ignored by the CSS parser. Remove the dangling property/brace so subsequent selectors (e.g. -score-name, -score-pct) apply reliably.
| color: var(--vscode-descriptionForeground); | |
| } |


Prototypes a "Copilot Auto Model Selection Routing" card that reuses the existing collapsible content-part styling (tool calls / thinking / file changes) to preview how an intelligently-selected model in
automode would surface in chat. Gated behind a Developer command — no real router is wired up.Description
autoModelRouting(IChatAutoModelRoutingPart) added toIChatProgressandIChatProgressHistoryResponseContent. Carries:selectedModel,selectionReason,intent,confidence,predictedLatencyMs,costTier,candidates[]. Switch arms added inpartsToRepr(ignore) andchatSessionOperationLog(static).ChatAutoModelRoutingContentPartextendsChatCollapsibleContentPart. Collapsed:Routed to <model>with a sparkle icon. Expanded view (revised after design feedback):descriptionForeground--vscode-badge-background)progressBar-backgroundbar, and a subtle hover-background row treatment. Other candidates use muted grey bars (scrollbarSlider-background)chatListRenderer.renderChatContentPart.Developer: Simulate Auto Model Selection Routing (Prototype)injects a sample part into the focused chat viaIChatService.addCompleteRequest, sandwiched between two markdown lines:Static preview of the collapsed and expanded states (dark theme):
How to test
Routed to GPT-5with a sparkle icon.Original prompt
Created from VS Code.