Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
967ee28
fix: replace typescript.tsdk.desc with new js/ts.tsdk.path
thernstig May 8, 2026
781806c
Potential fix for pull request finding
thernstig May 8, 2026
c045dd8
fix: keep typescript.tsdk.desc as source of truth
thernstig May 9, 2026
10a499b
Responses API: translate terminal events into typed completions
zhichli May 11, 2026
830b948
Merge pull request #315268 from thernstig/jsts-tsdk-path
mjbvz May 11, 2026
acdf223
agent host: handle elicitation requests from copilot SDK (#315882)
connor4312 May 11, 2026
cc1934d
Responses API: propagate response.error + Azure-spec'd copyright fall…
zhichli May 11, 2026
d8dd020
Forward RFC 8707 resource indicator through auth provider (#314784)
TylerLeonhardt May 11, 2026
ba053f0
Responses API tests: use single-quoted string to satisfy lint rule
zhichli May 11, 2026
4566b63
Remove github.copilot.chat.responsesApi.toolSearchTool.enabled settin…
bhavyaus May 11, 2026
e565d7d
Merge pull request #315873 from microsoft/zhichli/fixrapi
zhichli May 11, 2026
d486da9
[cherry-pick] OSS tool: update third-party notices (v1.120) (#315921)
vs-code-engineering[bot] May 12, 2026
e5ebfeb
sessions: cache tunnel inside connect() so listSessions runs on first…
connor4312 May 12, 2026
e52f92d
Disable chat input notifications for PRU users (#315898)
pwang347 May 12, 2026
812e5d0
Fix aria-label for model list with icons (#315908)
pwang347 May 12, 2026
123d29a
Cache UBB state for startup (#315913)
pwang347 May 12, 2026
85e7e6b
Improve "Export agent host logs" action (#315930)
roblourens May 12, 2026
29d735f
Remove obsolete search-process flags (#315931)
roblourens May 12, 2026
d079656
chat: show agent host model pricing in turn details (#315159)
roblourens May 12, 2026
63a4d48
Restore remote-row options picker in session workspace picker (#315939)
roblourens May 12, 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 ThirdPartyNotices.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1363,7 +1363,7 @@ SOFTWARE.
---------------------------------------------------------

dotnet/razor 1.0.0 - MIT
https://github.com/dotnet/razor
https://github.com/dotnet/roslyn

MIT License

Expand Down
14 changes: 10 additions & 4 deletions cli/ThirdPartyNotices.txt
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
[`digest-io`]: ./digest-io
[`hex-literal`]: ./hex-literal
[`inout`]: ./inout
[`sponge-cursor`]: ./sponge-cursor
[`wycheproof2blb`]: ./wycheproof2blb
[`zeroize`]: ./zeroize

Expand Down Expand Up @@ -781,6 +782,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
[`digest-io`]: ./digest-io
[`hex-literal`]: ./hex-literal
[`inout`]: ./inout
[`sponge-cursor`]: ./sponge-cursor
[`wycheproof2blb`]: ./wycheproof2blb
[`zeroize`]: ./zeroize

Expand Down Expand Up @@ -1421,6 +1423,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
[`digest-io`]: ./digest-io
[`hex-literal`]: ./hex-literal
[`inout`]: ./inout
[`sponge-cursor`]: ./sponge-cursor
[`wycheproof2blb`]: ./wycheproof2blb
[`zeroize`]: ./zeroize

Expand Down Expand Up @@ -3367,6 +3370,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
[`digest-io`]: ./digest-io
[`hex-literal`]: ./hex-literal
[`inout`]: ./inout
[`sponge-cursor`]: ./sponge-cursor
[`wycheproof2blb`]: ./wycheproof2blb
[`zeroize`]: ./zeroize

Expand Down Expand Up @@ -4248,6 +4252,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
[`digest-io`]: ./digest-io
[`hex-literal`]: ./hex-literal
[`inout`]: ./inout
[`sponge-cursor`]: ./sponge-cursor
[`wycheproof2blb`]: ./wycheproof2blb
[`zeroize`]: ./zeroize

Expand Down Expand Up @@ -6228,7 +6233,7 @@ OTHER DEALINGS IN THE SOFTWARE.

---------------------------------------------------------

openssl 0.10.78 - Apache-2.0
openssl 0.10.79 - Apache-2.0
https://github.com/rust-openssl/rust-openssl

Copyright 2011-2017 Google Inc.
Expand Down Expand Up @@ -6307,7 +6312,7 @@ DEALINGS IN THE SOFTWARE.

---------------------------------------------------------

openssl-sys 0.9.114 - MIT
openssl-sys 0.9.115 - MIT
https://github.com/rust-openssl/rust-openssl

The MIT License (MIT)
Expand Down Expand Up @@ -10663,8 +10668,8 @@ THE SOFTWARE.

---------------------------------------------------------

tunnels 4be50b3cc5ade8cb6beec4038c53ea4f2cdac5a2
https://github.com/connor4312/dev-tunnels
tunnels 64048c1409ff56cb958b879de7ea069ec71edc8b
https://github.com/microsoft/dev-tunnels

MIT License

Expand Down Expand Up @@ -13684,6 +13689,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
[`digest-io`]: ./digest-io
[`hex-literal`]: ./hex-literal
[`inout`]: ./inout
[`sponge-cursor`]: ./sponge-cursor
[`wycheproof2blb`]: ./wycheproof2blb
[`zeroize`]: ./zeroize

Expand Down
9 changes: 0 additions & 9 deletions extensions/copilot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3825,15 +3825,6 @@
"onExp"
]
},
"github.copilot.chat.responsesApi.toolSearchTool.enabled": {
"type": "boolean",
"default": false,
"markdownDescription": "%github.copilot.config.responsesApi.toolSearchTool.enabled%",
"tags": [
"experimental",
"onExp"
]
},
"github.copilot.chat.updated53CodexPrompt.enabled": {
"type": "boolean",
"default": true,
Expand Down
1 change: 0 additions & 1 deletion extensions/copilot/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,6 @@
"github.copilot.config.responsesApiReasoningSummary": "Sets the reasoning summary style used for the Responses API. Requires `#github.copilot.chat.useResponsesApi#`.",
"github.copilot.config.responsesApiContextManagement.enabled": "Enables context management for the Responses API. Requires `#github.copilot.chat.useResponsesApi#`.",
"github.copilot.config.responsesApi.promptCacheKey.enabled": "Enables prompt cache key being set for the Responses API.",
"github.copilot.config.responsesApi.toolSearchTool.enabled": "Enable tool search for OpenAI Responses API models. When enabled, tools are dynamically discovered and loaded on-demand using embeddings-based search, reducing context window usage when many tools are available.",
"github.copilot.config.updated53CodexPrompt.enabled": "Enables the updated prompt for gpt-5.3-codex model.",
"github.copilot.config.claude47OpusPrompt.enabled": "Enables the updated system prompt tuned for the Claude Opus 4.7 model.",
"github.copilot.config.gpt54ConcisePrompt.enabled": "Enables the concise prompt experiment for gpt-5.4 model.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ interface IQuotaWarning {
/**
* Manages a single chat input notification for quota and rate limit status.
*
* Listens to {@link IChatQuotaService.onDidChange} and determines whether a
* Listens to `IChatQuotaService.onDidChange` and determines whether a
* new threshold has been crossed, then shows the highest-priority notification:
*
* 1. **Quota exhausted** — info, not auto-dismissed, only dismissible via X.
Expand Down Expand Up @@ -72,17 +72,23 @@ export class ChatInputNotificationContribution extends Disposable {
return;
}

// Skip quota notifications for PRU users — only show for UBB.
const isQuotaNotificationEligible = !hasCopilotToken
|| !!this._authService.copilotToken?.isUsageBasedBilling;

// Priority 1: Quota exhausted — sticky info notification
if (this._chatQuotaService.quotaExhausted) {
if (isQuotaNotificationEligible && this._chatQuotaService.quotaExhausted) {
this._showExhaustedNotification();
return;
}

// Priority 2: Quota approaching threshold
const quotaWarning = this._computeQuotaWarning();
if (quotaWarning) {
this._showQuotaApproachingWarning(quotaWarning);
return;
if (isQuotaNotificationEligible) {
const quotaWarning = this._computeQuotaWarning();
if (quotaWarning) {
this._showQuotaApproachingWarning(quotaWarning);
return;
}
}

// Priority 3: Rate-limit warning (session > weekly)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function createAuthService(opts?: { anyGitHubSession?: unknown; copilotToken?: u
const authService = {
_serviceBrand: undefined,
anyGitHubSession: hasSession ? opts.anyGitHubSession : { accessToken: 'tok' },
copilotToken: hasToken ? opts.copilotToken : { isFreeUser: false, isNoAuthUser: false },
copilotToken: hasToken ? opts.copilotToken : { isFreeUser: false, isNoAuthUser: false, isUsageBasedBilling: true },
onDidAuthenticationChange: emitter.event,
} as unknown as IAuthenticationService;
return { authService, emitter };
Expand Down Expand Up @@ -156,7 +156,7 @@ describe('ChatInputNotificationContribution', () => {
authEmitter.fire();

// Sign back in
(authService as any).copilotToken = { isFreeUser: false, isNoAuthUser: false };
(authService as any).copilotToken = { isFreeUser: false, isNoAuthUser: false, isUsageBasedBilling: true };
authEmitter.fire();

// Threshold was cleared, so it should re-show
Expand All @@ -179,7 +179,7 @@ describe('ChatInputNotificationContribution', () => {
authEmitter.fire();

// Sign back in, quota no longer exhausted
(authService as any).copilotToken = { isFreeUser: false, isNoAuthUser: false };
(authService as any).copilotToken = { isFreeUser: false, isNoAuthUser: false, isUsageBasedBilling: true };
(quotaService as any).quotaExhausted = false;
(quotaService as any).quotaInfo = undefined;
(quotaService as any).rateLimitInfo = { session: undefined, weekly: undefined };
Expand All @@ -202,28 +202,39 @@ describe('ChatInputNotificationContribution', () => {
expect(mockNotification.hide).not.toHaveBeenCalled();
});

test('anonymous user with no GitHub session still sees quota notifications', () => {
test('anonymous UBB user with no GitHub session still sees quota notifications', () => {
setup(
{ anyGitHubSession: undefined, copilotToken: { isNoAuthUser: true, isFreeUser: false } },
{ anyGitHubSession: undefined, copilotToken: { isNoAuthUser: true, isFreeUser: false, isUsageBasedBilling: true } },
{ quotaExhausted: true },
);

// Anonymous user has a copilotToken but no GitHub session.
// Anonymous UBB user has a copilotToken but no GitHub session.
// They should still see the exhausted notification.
quotaEmitter.fire();

expect(mockNotification.show).toHaveBeenCalled();
expect(mockNotification.message).toBe('Credit Limit Reached');
expect(mockNotification.description).toBe('Sign in to keep going.');
});

test('anonymous PRU user does not see quota notifications', () => {
setup(
{ anyGitHubSession: undefined, copilotToken: { isNoAuthUser: true, isFreeUser: false, isUsageBasedBilling: false } },
{ quotaExhausted: true },
);

quotaEmitter.fire();

expect(mockNotification.show).not.toHaveBeenCalled();
});
});

// --- basic notification lifecycle ----------------------------------------

describe('quota exhausted', () => {
test('shows exhausted notification', () => {
setup(
{ copilotToken: { isFreeUser: true, isNoAuthUser: false } },
{ copilotToken: { isFreeUser: true, isNoAuthUser: false, isUsageBasedBilling: true } },
{ quotaExhausted: true },
);

Expand Down Expand Up @@ -362,4 +373,62 @@ describe('ChatInputNotificationContribution', () => {
expect(mockNotification.message).toBe('Credit Limit Reached');
});
});

describe('PRU users do not see quota notifications', () => {
test('does not show exhausted notification for individual PRU user', () => {
setup(
{ copilotToken: { isFreeUser: false, isNoAuthUser: false, isManagedPlan: false, isUsageBasedBilling: false } },
{ quotaExhausted: true },
);

quotaEmitter.fire();

expect(mockNotification.show).not.toHaveBeenCalled();
});

test('does not show exhausted notification for free PRU user', () => {
setup(
{ copilotToken: { isFreeUser: true, isNoAuthUser: false, isManagedPlan: false, isUsageBasedBilling: false } },
{ quotaExhausted: true },
);

quotaEmitter.fire();

expect(mockNotification.show).not.toHaveBeenCalled();
});

test('does not show exhausted notification for managed plan PRU user', () => {
setup(
{ copilotToken: { isFreeUser: false, isNoAuthUser: false, isManagedPlan: true, isUsageBasedBilling: false } },
{ quotaExhausted: true },
);

quotaEmitter.fire();

expect(mockNotification.show).not.toHaveBeenCalled();
});

test('does not show approaching notification for PRU user', () => {
setup(
{ copilotToken: { isFreeUser: false, isNoAuthUser: false, isManagedPlan: false, isUsageBasedBilling: false } },
{ quotaInfo: makeQuota(5) }, // 95% used
);

quotaEmitter.fire();

expect(mockNotification.show).not.toHaveBeenCalled();
});

test('still shows rate limit warning for PRU user', () => {
setup(
{ copilotToken: { isFreeUser: false, isNoAuthUser: false, isManagedPlan: false, isUsageBasedBilling: false } },
{ session: makeQuota(25) }, // 75% used
);

quotaEmitter.fire();

expect(mockNotification.show).toHaveBeenCalled();
expect(mockNotification.message).toContain('session');
});
});
});
5 changes: 5 additions & 0 deletions extensions/copilot/src/extension/tools/node/toolSearchTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,18 @@ ToolRegistry.registerModelSpecificTool(
required: ['query'],
},
models: [
{ family: 'gpt-5.4' },
{ family: 'gpt-5.5' },
{ family: 'claude-sonnet-4.5' },
{ family: 'claude-sonnet-4.6' },
{ family: 'claude-opus-4.5' },
{ family: 'claude-opus-4.6' },
{ family: 'claude-opus-4.6-1m' },
{ family: 'claude-opus-4.7' },
{ family: 'claude-opus-4.7-1m' },
{ family: 'claude-opus-4.7-1m-internal' },
{ family: 'claude-opus-4.7-high' },
{ family: 'claude-opus-4.7-xhigh' },
],
},
ToolSearchTool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ export class CopilotToken {
return plan === 'business' || plan === 'enterprise';
}

get isUsageBasedBilling(): boolean {
return this._info.token_based_billing === true;
}

get isChatQuotaExceeded(): boolean {
return this.isFreeUser && (this._info.limited_user_quotas?.chat ?? 1) <= 0;
}
Expand Down Expand Up @@ -530,6 +534,7 @@ export interface CopilotUserInfo extends CopilotUserQuotaInfo {
name: string | null;
}>;
codex_agent_enabled?: boolean;
token_based_billing?: boolean;
}

/**
Expand All @@ -540,7 +545,7 @@ export type ExtendedTokenInfo = TokenEnvelope & {
// Extended fields added by client
username: string;
isVscodeTeamMember: boolean;
} & Pick<CopilotUserInfo, 'copilot_plan' | 'quota_snapshots' | 'quota_reset_date' | 'codex_agent_enabled' | 'organization_login_list'>;
} & Pick<CopilotUserInfo, 'copilot_plan' | 'quota_snapshots' | 'quota_reset_date' | 'codex_agent_enabled' | 'organization_login_list' | 'token_based_billing'>;

/**
* Creates a minimal ExtendedTokenInfo for testing purposes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ export abstract class BaseCopilotTokenManager extends Disposable implements ICop
quota_reset_date: userInfo?.quota_reset_date,
codex_agent_enabled: userInfo?.codex_agent_enabled,
organization_login_list: userInfo?.organization_login_list ?? [],
token_based_billing: userInfo?.token_based_billing,
username: login,
isVscodeTeamMember: containsVSCodeOrg(tokenInfo.organization_list ?? []),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -933,8 +933,6 @@ export namespace ConfigKey {
export const ResponsesApiContextManagementEnabled = defineSetting<boolean>('chat.responsesApiContextManagement.enabled', ConfigType.ExperimentBased, false);
/** Enable client-side prompt_cache_key (conversationId:modelFamily) sent to Responses API */
export const ResponsesApiPromptCacheKeyEnabled = defineSetting<boolean>('chat.responsesApi.promptCacheKey.enabled', ConfigType.ExperimentBased, false);
/** Enable tool search for Responses API (client-side deferred tool loading). */
export const ResponsesApiToolSearchEnabled = defineSetting<boolean>('chat.responsesApi.toolSearchTool.enabled', ConfigType.ExperimentBased, false);
/** Enable updated prompt for 5.3Codex model */
export const Updated53CodexPromptEnabled = defineSetting<boolean>('chat.updated53CodexPrompt.enabled', ConfigType.ExperimentBased, true);
/** Enable updated prompt for Claude Opus 4.7 model */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,36 +421,20 @@ export function getVerbosityForModelSync(model: IChatEndpoint): 'low' | 'medium'
* - Claude Opus 4.5 (claude-opus-4-5-* or claude-opus-4.5-*)
* - Claude Opus 4.6 (claude-opus-4-6-* or claude-opus-4.6-*)
* - Claude Opus 4.7 (claude-opus-4-7-* or claude-opus-4.7-*)
* - OpenAI gpt-5.4/gpt-5.5, but only when the `ResponsesApiToolSearchEnabled` setting is enabled
* - OpenAI gpt-5.4 and gpt-5.5 (via Responses API client-side tool search)
*/
export function modelSupportsToolSearch(modelId: string, configurationService?: IConfigurationService, experimentationService?: IExperimentationService): boolean {
export function modelSupportsToolSearch(modelId: string): boolean {
const normalized = modelId.toLowerCase().replace(/\./g, '-');
if (isResponsesApiToolSearchModelId(normalized)) {
return !!configurationService && !!experimentationService && isResponsesApiToolSearchEnabled(modelId, configurationService, experimentationService);
}

return normalized.startsWith('claude-sonnet-4-5') ||
return normalized === 'gpt-5-4' ||
normalized === 'gpt-5-5' ||
normalized.startsWith('claude-sonnet-4-5') ||
normalized.startsWith('claude-sonnet-4-6') ||
normalized.startsWith('claude-opus-4-5') ||
normalized.startsWith('claude-opus-4-6') ||
normalized.startsWith('claude-opus-4-7') ||
isHiddenModelG(modelId);
}

function isResponsesApiToolSearchModelId(normalizedModelId: string): boolean {
return normalizedModelId === 'gpt-5-4' || normalizedModelId === 'gpt-5-5';
}

export function isResponsesApiToolSearchEnabled(
endpoint: IChatEndpoint | string,
configurationService: IConfigurationService,
experimentationService: IExperimentationService,
): boolean {
const modelId = typeof endpoint === 'string' ? endpoint : endpoint.model;
const normalized = modelId.toLowerCase().replace(/\./g, '-');
return isResponsesApiToolSearchModelId(normalized) && configurationService.getExperimentBasedConfig(ConfigKey.ResponsesApiToolSearchEnabled, experimentationService);
}

/**
* Context editing is supported by:
* - Claude Haiku 4.5 (claude-haiku-4-5-* or claude-haiku-4.5-*)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export class ChatEndpoint implements IChatEndpoint {
this.minThinkingBudget = modelMetadata.capabilities.supports.min_thinking_budget;
this.maxThinkingBudget = modelMetadata.capabilities.supports.max_thinking_budget;
this.supportsReasoningEffort = modelMetadata.capabilities.supports.reasoning_effort;
this.supportsToolSearch = modelMetadata.capabilities.supports.tool_search ?? modelSupportsToolSearch(this.model, this._configurationService, this._expService);
this.supportsToolSearch = modelMetadata.capabilities.supports.tool_search ?? modelSupportsToolSearch(this.model);
this.supportsContextEditing = modelMetadata.capabilities.supports.context_editing ?? modelSupportsContextEditing(this.model);
this._supportsStreaming = !!modelMetadata.capabilities.supports.streaming;
this.customModel = modelMetadata.custom_model;
Expand Down
Loading
Loading