Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8bdc1ff
Fix agent host SDK download progress notification (#324455, #324461)
Giuspepe Jul 6, 2026
3b37c12
Codex: create a managed temp folder when no working directory is supp…
Giuspepe Jul 6, 2026
6e1a936
[cherry-pick] [release/1.128] Hide Tools Marketplace in sessions window
vs-code-engineering[bot] Jul 6, 2026
1e486d1
Claude: defer restore-reachable SDK reads until SDK is local
Giuspepe Jul 7, 2026
87d66b3
Agent sessions: commit each concurrent new-session send to its own se…
Giuspepe Jul 7, 2026
1418c6b
support top provider context length in open router
vritant24 Jul 7, 2026
dc051d1
contextWindow for BYOK models
vritant24 Jul 7, 2026
ed41d15
Merge remote-tracking branch 'origin/main' into agents/debug-fix-test…
Giuspepe Jul 7, 2026
0e64743
change the default to open editors to inside editor instead of modal …
sandy081 Jul 7, 2026
6ed31a3
Add validation for deprecated design tokens (#324782)
mrleemurray Jul 7, 2026
0542f07
Merge pull request #324792 from microsoft/agents/debug-fix-test-plan-…
Giuspepe Jul 7, 2026
833244d
Custom editors opt out of diff/merge by default via `never` priority
hediet Jul 7, 2026
5880e4c
fix: handle failed terminal quick fix model request to avoid unhandle…
vs-code-engineering[bot] Jul 7, 2026
5fbe3eb
Address PR review: clamp token limits and require input/context window
vritant24 Jul 7, 2026
4ea4650
Fall back to a custom diff editor for binary content
hediet Jul 7, 2026
275befb
fix: guard notebook sticky-scroll against evicted cell (fixes #324790…
vs-code-engineering[bot] Jul 7, 2026
ac42efa
Merge pull request #324796 from microsoft/agents/issue-fix-plan-and-t…
vritant24 Jul 7, 2026
afcc43c
feat: update Kimi family model capabilities to match BYOK models
vritant24 Jul 7, 2026
278ac59
[Cherry-Pick] Remove IStorageSourceFilter (#323480) (#324810)
benvillalobos Jul 7, 2026
bf3018c
chat: preserve shell intention command height (#324800)
roblourens Jul 7, 2026
bffa61d
Merge pull request #324643 from microsoft/cherry-pick/324636
connor4312 Jul 7, 2026
9b2dd75
chat: keep shell intention chevron adjacent (#324812)
roblourens Jul 7, 2026
debbc28
chat: fix scroll-follow and spacing for queued/steering messages (#32…
connor4312 Jul 7, 2026
4f9cbeb
Merge pull request #324814 from microsoft/dev/vritant24/kimiByokPrompt
vritant24 Jul 7, 2026
5c8dc63
[cherry-pick] [release/1.128] Update GPT-5.6 model family detection (…
vs-code-engineering[bot] Jul 7, 2026
a012939
Preserve browser view attachments in agent sessions (#324630)
dileepyavan Jul 7, 2026
04c9ab5
Prompt timeline rail for the Agents window (#324131)
osortega Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/.cachesalt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2026-06-22T15:10:10.546Z
2026-07-07T20:00:56.412Z
4 changes: 4 additions & 0 deletions build/lib/i18n.resources.json
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,10 @@
"name": "vs/sessions/contrib/chat",
"project": "vscode-sessions"
},
{
"name": "vs/sessions/contrib/promptTimeline",
"project": "vscode-sessions"
},
{
"name": "vs/sessions/contrib/providers/copilotChatSessions",
"project": "vscode-sessions"
Expand Down
72 changes: 62 additions & 10 deletions build/lib/stylelint/validateDesignTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ export function validateCodiconFontSizes(text: string): IDesignTokenViolation[]

/** Exact px value -> suggested token var(s). Ambiguous values list alternatives. */
const FONT_SIZE_RAMP: ReadonlyMap<number, string> = new Map([
[26, 'var(--vscode-agents-fontSize-heading1)'],
[18, 'var(--vscode-agents-fontSize-heading2)'],
[13, 'var(--vscode-bodyFontSize) or var(--vscode-agents-fontSize-heading3) or var(--vscode-agents-fontSize-body1)'],
[12, 'var(--vscode-bodyFontSize-small) or var(--vscode-agents-fontSize-label1)'],
[11, 'var(--vscode-bodyFontSize-xSmall) or var(--vscode-agents-fontSize-body2) or var(--vscode-agents-fontSize-label2)'],
[10, 'var(--vscode-agents-fontSize-label3)'],
[26, 'var(--vscode-fontSize-heading1)'],
[18, 'var(--vscode-fontSize-heading2)'],
[13, 'var(--vscode-fontSize-body1) or var(--vscode-fontSize-heading3)'],
[12, 'var(--vscode-fontSize-label1)'],
[11, 'var(--vscode-fontSize-body2) or var(--vscode-fontSize-label2)'],
[10, 'var(--vscode-fontSize-label3)'],
]);

/**
Expand Down Expand Up @@ -255,7 +255,7 @@ export function validateCornerRadiusTokens(text: string): IDesignTokenViolation[
// Font-weight token suggestions (sessions design-system area only)
// ---------------------------------------------------------------------------
//
// The agents font ramp defines exactly two weights: regular (400) and
// The font ramp defines exactly two weights: regular (400) and
// semiBold (600). Any other numeric weight (e.g. 500, 700) is off the ramp and
// snaps to the nearer of the two. The CSS keywords `normal` (400) and `bold`
// (700) are normalised before snapping. `inherit`, `lighter`, `bolder` and
Expand All @@ -268,7 +268,7 @@ interface IFontWeightToken {
readonly name: string;
}

/** The only two weights in the agents ramp. */
/** The only two weights in the font ramp. */
const FONT_WEIGHT_TOKENS: readonly IFontWeightToken[] = [
{ weight: 400, name: 'regular' },
{ weight: 600, name: 'semiBold' },
Expand Down Expand Up @@ -303,7 +303,7 @@ function snapFontWeight(weight: number): IFontWeightToken {
}

/**
* Finds hardcoded `font-weight` values and suggests the agents weight-ramp var.
* Finds hardcoded `font-weight` values and suggests the weight-ramp var.
* Exact ramp values (400 / 600, plus `normal` = 400) are flagged as drop-in
* replacements; off-ramp values (e.g. 500, 700, `bold`) snap to the nearer
* token and call out that the value is off the two-weight ramp. `inherit`,
Expand Down Expand Up @@ -332,7 +332,7 @@ export function validateFontWeightTokens(text: string): IDesignTokenViolation[]
const note = exact ? '' : ' (off-ramp, 400/600 only)';
violations.push({
line,
message: `${shown} -> var(--vscode-agents-fontWeight-${token.name})${note}`
message: `${shown} -> var(--vscode-fontWeight-${token.name})${note}`
});
});

Expand Down Expand Up @@ -475,3 +475,55 @@ export function validateStrokeTokens(text: string): IDesignTokenViolation[] {

return violations;
}

// ---------------------------------------------------------------------------
// Deprecated token usage
// ---------------------------------------------------------------------------
//
// Some `--vscode-*` size tokens have been superseded by more generic ones and
// are marked `@deprecated` in the size registry. Any remaining usage of a
// deprecated token var is reported with its drop-in replacement, regardless of
// which property it appears in.

interface IDeprecatedToken {
readonly deprecated: string;
readonly replacement: string;
}

/** Deprecated token var -> its replacement. */
const DEPRECATED_TOKENS: readonly IDeprecatedToken[] = [
{ deprecated: '--vscode-bodyFontSize', replacement: '--vscode-fontSize-body1' },
{ deprecated: '--vscode-bodyFontSize-small', replacement: '--vscode-fontSize-label1' },
{ deprecated: '--vscode-bodyFontSize-xSmall', replacement: '--vscode-fontSize-body2' },
];

// Longest-first so a suffixed token (e.g. `-small`) matches before the base
// token that is its prefix (`--vscode-bodyFontSize`).
const DEPRECATED_TOKENS_SORTED = [...DEPRECATED_TOKENS].sort((a, b) => b.deprecated.length - a.deprecated.length);

/**
* Finds usages of deprecated token vars and suggests the replacement token.
* A match is only reported when the token is not the prefix of a longer token
* (the next character does not continue the identifier). Returns one finding
* per occurrence so the terminal can linkify each `file(line,col)`.
*/
export function validateDeprecatedTokens(text: string): IDesignTokenViolation[] {
const violations: IDesignTokenViolation[] = [];

forEachDeclaration(text, (line, _selector, declaration) => {
for (const { deprecated, replacement } of DEPRECATED_TOKENS_SORTED) {
for (let idx = declaration.indexOf(deprecated); idx !== -1; idx = declaration.indexOf(deprecated, idx + deprecated.length)) {
const nextChar = declaration[idx + deprecated.length] ?? '';
if (/[\w-]/.test(nextChar)) {
continue; // prefix of a longer token
}
violations.push({
line,
message: `${deprecated} -> ${replacement} (deprecated)`
});
}
}
});

return violations;
}
1 change: 1 addition & 0 deletions build/lib/stylelint/vscode-known-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,7 @@
"--session-view-background",
"--session-view-foreground",
"--session-view-centered-content-max-width",
"--prompt-timeline-bottom",
"--chat-editing-last-edit-shift",
"--chat-voice-icon-glow-color",
"--chat-current-response-min-height",
Expand Down
10 changes: 6 additions & 4 deletions build/stylelint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import es from 'event-stream';
import vfs from 'vinyl-fs';
import { stylelintFilter } from './filters.ts';
import { getVariableNameValidator } from './lib/stylelint/validateVariableNames.ts';
import { validateCodiconFontSizes, validateFontSizeTokens, validateFontWeightTokens, validateCornerRadiusTokens, validateSpacingTokens, validateStrokeTokens } from './lib/stylelint/validateDesignTokens.ts';
import { validateCodiconFontSizes, validateFontSizeTokens, validateFontWeightTokens, validateCornerRadiusTokens, validateSpacingTokens, validateStrokeTokens, validateDeprecatedTokens } from './lib/stylelint/validateDesignTokens.ts';

interface FileWithLines {
__lines?: string[];
Expand All @@ -32,7 +32,7 @@ export default function gulpstylelint(reporter: Reporter, designTokensEverywhere
const layerCheckerDisablePattern = /\/\*\s*stylelint-disable\s+layer-checker\s*\*\//;

// Per-category tally of design-token suggestions for the summary footer.
const designTokenCounts: Record<string, number> = { codicon: 0, 'font-size': 0, weight: 0, radius: 0, spacing: 0, stroke: 0 };
const designTokenCounts: Record<string, number> = { codicon: 0, 'font-size': 0, weight: 0, radius: 0, spacing: 0, stroke: 0, deprecated: 0 };
let designTokenFileCount = 0;

return es.through(function (this, file: FileWithLines) {
Expand Down Expand Up @@ -73,6 +73,7 @@ export default function gulpstylelint(reporter: Reporter, designTokensEverywhere
for (const v of validateCornerRadiusTokens(contents)) { findings.push({ line: v.line, category: 'radius', message: v.message }); }
for (const v of validateSpacingTokens(contents)) { findings.push({ line: v.line, category: 'spacing', message: v.message }); }
for (const v of validateStrokeTokens(contents)) { findings.push({ line: v.line, category: 'stroke', message: v.message }); }
for (const v of validateDeprecatedTokens(contents)) { findings.push({ line: v.line, category: 'deprecated', message: v.message }); }

if (findings.length > 0) {
findings.sort((a, b) => a.line - b.line);
Expand All @@ -91,7 +92,7 @@ export default function gulpstylelint(reporter: Reporter, designTokensEverywhere
if (errorCount > 0) {
reporter('All valid variable names are in `build/lib/stylelint/vscode-known-variables.json`\nTo update that file, run `./scripts/test-documentation.sh|bat.`', false);
}
const designTokenTotal = designTokenCounts.codicon + designTokenCounts['font-size'] + designTokenCounts.weight + designTokenCounts.radius + designTokenCounts.spacing + designTokenCounts.stroke;
const designTokenTotal = designTokenCounts.codicon + designTokenCounts['font-size'] + designTokenCounts.weight + designTokenCounts.radius + designTokenCounts.spacing + designTokenCounts.stroke + designTokenCounts.deprecated;
if (designTokenTotal > 0) {
reporter('', false);
reporter(
Expand All @@ -101,7 +102,8 @@ export default function gulpstylelint(reporter: Reporter, designTokensEverywhere
', weight ' + designTokenCounts.weight +
', radius ' + designTokenCounts.radius +
', spacing ' + designTokenCounts.spacing +
', stroke ' + designTokenCounts.stroke + ')',
', stroke ' + designTokenCounts.stroke +
', deprecated ' + designTokenCounts.deprecated + ')',
false
);
}
Expand Down
57 changes: 51 additions & 6 deletions extensions/copilot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1918,12 +1918,16 @@
},
"maxInputTokens": {
"type": "number",
"description": "Maximum number of input tokens supported by the model"
"markdownDescription": "Maximum number of input (prompt) tokens supported by the model. Optional when `contextWindow` is set, in which case it is derived as `contextWindow - maxOutputTokens`."
},
"maxOutputTokens": {
"type": "number",
"description": "Maximum number of output tokens supported by the model"
},
"contextWindow": {
"type": "number",
"markdownDescription": "The model's full context window (input + output) in tokens, e.g. `1000000` for a 1M model. When set it is the source of truth for the context window and `maxInputTokens` can be omitted. Otherwise the window is derived as `maxInputTokens + maxOutputTokens`."
},
"editTools": {
"type": "array",
"description": "List of edit tools supported by the model. If this is not configured, the editor will try multiple edit tools and pick the best one.\n\n- 'find-replace': Find and replace text in a document.\n- 'multi-find-replace': Find and replace text in a document.\n- 'apply-patch': A file-oriented diff format used by some OpenAI models\n- 'code-rewrite': A general but slower editing tool that allows the model to rewrite and code snippet and provide only the replacement to the editor.",
Expand Down Expand Up @@ -1981,8 +1985,19 @@
"url",
"toolCalling",
"vision",
"maxInputTokens",
"maxOutputTokens"
],
"anyOf": [
{
"required": [
"maxInputTokens"
]
},
{
"required": [
"contextWindow"
]
}
]
}
}
Expand Down Expand Up @@ -2089,12 +2104,16 @@
},
"maxInputTokens": {
"type": "number",
"description": "Maximum number of input tokens supported by the model"
"markdownDescription": "Maximum number of input (prompt) tokens supported by the model. Optional when `contextWindow` is set, in which case it is derived as `contextWindow - maxOutputTokens`."
},
"maxOutputTokens": {
"type": "number",
"description": "Maximum number of output tokens supported by the model"
},
"contextWindow": {
"type": "number",
"markdownDescription": "The model's full context window (input + output) in tokens, e.g. `1000000` for a 1M model. When set it is the source of truth for the context window and `maxInputTokens` can be omitted. Otherwise the window is derived as `maxInputTokens + maxOutputTokens`."
},
"editTools": {
"type": "array",
"description": "List of edit tools supported by the model. If this is not configured, the editor will try multiple edit tools and pick the best one.\n\n- 'find-replace': Find and replace text in a document.\n- 'multi-find-replace': Find and replace text in a document.\n- 'apply-patch': A file-oriented diff format used by some OpenAI models\n- 'code-rewrite': A general but slower editing tool that allows the model to rewrite and code snippet and provide only the replacement to the editor.",
Expand Down Expand Up @@ -2176,8 +2195,19 @@
"url",
"toolCalling",
"vision",
"maxInputTokens",
"maxOutputTokens"
],
"anyOf": [
{
"required": [
"maxInputTokens"
]
},
{
"required": [
"contextWindow"
]
}
]
}
}
Expand Down Expand Up @@ -2240,12 +2270,16 @@
},
"maxInputTokens": {
"type": "number",
"description": "Maximum number of input tokens supported by the model"
"markdownDescription": "Maximum number of input (prompt) tokens supported by the model. Optional when `contextWindow` is set, in which case it is derived as `contextWindow - maxOutputTokens`."
},
"maxOutputTokens": {
"type": "number",
"description": "Maximum number of output tokens supported by the model"
},
"contextWindow": {
"type": "number",
"markdownDescription": "The model's full context window (input + output) in tokens, e.g. `1000000` for a 1M model. When set it is the source of truth for the context window and `maxInputTokens` can be omitted. Otherwise the window is derived as `maxInputTokens + maxOutputTokens`."
},
"thinking": {
"type": "boolean",
"default": false,
Expand Down Expand Up @@ -2290,8 +2324,19 @@
"url",
"toolCalling",
"vision",
"maxInputTokens",
"maxOutputTokens"
],
"anyOf": [
{
"required": [
"maxInputTokens"
]
},
{
"required": [
"contextWindow"
]
}
]
}
}
Expand Down
55 changes: 48 additions & 7 deletions extensions/copilot/src/extension/byok/common/byokProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,19 @@ export type BYOKModelConfig = BYOKGlobalKeyModelConfig | BYOKPerModelConfig | BY
export interface BYOKModelCapabilities {
name: string;
url?: string;
maxInputTokens: number;
/**
* The maximum number of prompt (input) tokens. Optional when {@link contextWindow}
* is supplied, in which case it is derived as `contextWindow - maxOutputTokens`.
*/
maxInputTokens?: number;
maxOutputTokens: number;
/**
* The model's full context window (input + output) in tokens. Many providers
* publish this directly (e.g. "Context Length: 1M"). When set it is used as the
* source of truth for the context window; otherwise the window is derived as
* `maxInputTokens + maxOutputTokens` for backward compatibility.
*/
contextWindow?: number;
toolCalling: boolean;
vision: boolean;
thinking?: boolean;
Expand Down Expand Up @@ -93,14 +104,43 @@ export function isNoAuthConfig(config: BYOKModelConfig): config is BYOKNoAuthMod
return !('apiKey' in config) && !('deploymentUrl' in config);
}

/**
* Resolves a model's token limits from its BYOK capabilities, honoring an explicit
* {@link BYOKModelCapabilities.contextWindow} when provided.
*
* - When `contextWindow` is set it is the source of truth for the full window and, if
* `maxInputTokens` is omitted, the prompt budget is derived as
* `contextWindow - maxOutputTokens`.
* - Otherwise the window falls back to `maxInputTokens + maxOutputTokens` for backward
* compatibility.
*
* The returned limits are always internally consistent: `maxOutputTokens` is clamped so
* it never exceeds the context window, and `maxInputTokens` is clamped to the remaining
* budget (`contextWindow - maxOutputTokens`). This prevents invalid combinations such as
* `maxOutputTokens > contextWindow`, or a `maxInputTokens` supplied alongside a smaller
* `contextWindow` overflowing the window.
*/
export function resolveModelTokenLimits(capabilities: Pick<BYOKModelCapabilities, 'maxInputTokens' | 'maxOutputTokens' | 'contextWindow'>): { contextWindow: number; maxInputTokens: number; maxOutputTokens: number } {
const contextWindow = capabilities.contextWindow ?? ((capabilities.maxInputTokens ?? 0) + capabilities.maxOutputTokens);
// The output budget can never exceed the full window.
const maxOutputTokens = Math.min(capabilities.maxOutputTokens, contextWindow);
// The prompt budget is whatever remains after the output reservation; an explicitly
// provided maxInputTokens is clamped to that remaining budget.
const remainingInputBudget = Math.max(0, contextWindow - maxOutputTokens);
const maxInputTokens = Math.min(capabilities.maxInputTokens ?? remainingInputBudget, remainingInputBudget);
return { contextWindow, maxInputTokens, maxOutputTokens };
}

export function resolveModelInfo(modelId: string, providerName: string, knownModels: BYOKKnownModels | undefined, modelCapabilities?: BYOKModelCapabilities): IChatModelInformation {
// Model Capabilities are something the user has decided on so those take precedence, then we rely on known model info, then defaults.
let knownModelInfo = modelCapabilities;
if (knownModels && !knownModelInfo) {
knownModelInfo = knownModels[modelId];
}
const modelName = knownModelInfo?.name || modelId;
const contextWinow = knownModelInfo ? (knownModelInfo.maxInputTokens + knownModelInfo.maxOutputTokens) : 128000;
const limits = knownModelInfo
? resolveModelTokenLimits(knownModelInfo)
: { contextWindow: 128000, maxInputTokens: 100000, maxOutputTokens: 8192 };
const modelInfo: IChatModelInformation = {
id: modelId,
name: modelName,
Expand All @@ -119,9 +159,9 @@ export function resolveModelInfo(modelId: string, providerName: string, knownMod
},
tokenizer: TokenizerType.O200K,
limits: {
max_context_window_tokens: contextWinow,
max_prompt_tokens: knownModelInfo?.maxInputTokens || 100000,
max_output_tokens: knownModelInfo?.maxOutputTokens || 8192
max_context_window_tokens: limits.contextWindow,
max_prompt_tokens: limits.maxInputTokens,
max_output_tokens: limits.maxOutputTokens
}
},
is_chat_default: false,
Expand All @@ -146,12 +186,13 @@ export function byokKnownModelsToAPIInfo(providerName: string, knownModels: BYOK
}

export function byokKnownModelToAPIInfo(providerName: string, id: string, capabilities: BYOKModelCapabilities): LanguageModelChatInformation {
const limits = resolveModelTokenLimits(capabilities);
return {
id,
name: capabilities.name,
version: '1.0.0',
maxOutputTokens: capabilities.maxOutputTokens,
maxInputTokens: capabilities.maxInputTokens,
maxOutputTokens: limits.maxOutputTokens,
maxInputTokens: limits.maxInputTokens,
// `detail` is intentionally omitted: when this model is resolved
// via a configured provider group, `LanguageModelsService` will
// fall back to the group name so multiple instances of the same
Expand Down
Loading
Loading