Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion src/extension/intents/node/agentIntent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ export const getAgentTools = async (accessor: ServicesAccessor, request: vscode.

allowTools[ToolName.CoreRunTest] = await testService.hasAnyTests();
allowTools[ToolName.CoreRunTask] = tasksService.getTasks().length > 0;
allowTools[ToolName.SearchSubagent] = (isGptFamily(model) || isAnthropicFamily(model)) && configurationService.getExperimentBasedConfig(ConfigKey.Advanced.SearchSubagentToolEnabled, experimentationService);

const useAgenticProxy = configurationService.getConfig(ConfigKey.Advanced.SearchSubagentUseAgenticProxy);
const searchSubagentEnabled = configurationService.getExperimentBasedConfig(ConfigKey.Advanced.SearchSubagentToolEnabled, experimentationService);
const isGptOrAnthropic = isGptFamily(model) || isAnthropicFamily(model);
allowTools[ToolName.SearchSubagent] = isGptOrAnthropic && (useAgenticProxy || searchSubagentEnabled);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The || here is odd because if the setting SearchSubagentToolEnabled is disabled, then shouldn't the tool be disabled?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see microsoft/vscode#291154 too


if (model.family.includes('grok-code')) {
allowTools[ToolName.CoreManageTodoList] = false;
Expand Down
21 changes: 11 additions & 10 deletions src/extension/prompt/node/searchSubagentToolCallingLoop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { randomUUID } from 'crypto';
import type { CancellationToken, ChatRequest, ChatResponseStream, LanguageModelToolInformation, Progress } from 'vscode';
import { IAuthenticationChatUpgradeService } from '../../../platform/authentication/common/authenticationUpgrade';
import { ChatLocation, ChatResponse } from '../../../platform/chat/common/commonTypes';
import { IConfigurationService } from '../../../platform/configuration/common/configurationService';
import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';
import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';
import { ProxyAgenticSearchEndpoint } from '../../../platform/endpoint/node/proxyAgenticSearchEndpoint';
import { ILogService } from '../../../platform/log/common/logService';
import { IRequestLogger } from '../../../platform/requestLogger/node/requestLogger';
import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService';
Expand Down Expand Up @@ -42,7 +43,7 @@ export class SearchSubagentToolCallingLoop extends ToolCallingLoop<ISearchSubage
@IToolsService private readonly toolsService: IToolsService,
@IAuthenticationChatUpgradeService authenticationChatUpgradeService: IAuthenticationChatUpgradeService,
@ITelemetryService telemetryService: ITelemetryService,
@IConfigurationService configurationService: IConfigurationService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IExperimentationService experimentationService: IExperimentationService,
) {
super(options, instantiationService, endpointProvider, logService, requestLogger, authenticationChatUpgradeService, telemetryService, configurationService, experimentationService);
Expand All @@ -62,16 +63,16 @@ export class SearchSubagentToolCallingLoop extends ToolCallingLoop<ISearchSubage
return context;
}

private async getEndpoint(request: ChatRequest) {
let endpoint = await this.endpointProvider.getChatEndpoint(this.options.request);
if (!endpoint.supportsToolCalls) {
endpoint = await this.endpointProvider.getChatEndpoint('gpt-4.1');
private async getEndpoint() {
const useAgenticProxy = this.configurationService.getConfig(ConfigKey.Advanced.SearchSubagentUseAgenticProxy);
if (useAgenticProxy) {
return this.instantiationService.createInstance(ProxyAgenticSearchEndpoint);
}
return endpoint;
return this.endpointProvider.getChatEndpoint(this.options.request);
}

protected async buildPrompt(buildPromptContext: IBuildPromptContext, progress: Progress<ChatResponseReferencePart | ChatResponseProgressPart>, token: CancellationToken): Promise<IBuildPromptResult> {
const endpoint = await this.getEndpoint(this.options.request);
const endpoint = await this.getEndpoint();
const renderer = PromptRenderer.create(
this.instantiationService,
endpoint,
Expand All @@ -84,7 +85,7 @@ export class SearchSubagentToolCallingLoop extends ToolCallingLoop<ISearchSubage
}

protected async getAvailableTools(): Promise<LanguageModelToolInformation[]> {
const endpoint = await this.getEndpoint(this.options.request);
const endpoint = await this.getEndpoint();
const allTools = this.toolsService.getEnabledTools(this.options.request, endpoint);

// Only include tools relevant for search operations.
Expand All @@ -101,7 +102,7 @@ export class SearchSubagentToolCallingLoop extends ToolCallingLoop<ISearchSubage
}

protected async fetch({ messages, finishedCb, requestOptions }: ToolCallingLoopFetchOptions, token: CancellationToken): Promise<ChatResponse> {
const endpoint = await this.getEndpoint(this.options.request);
const endpoint = await this.getEndpoint();
return endpoint.makeChatRequest2({
debugName: SearchSubagentToolCallingLoop.ID,
messages,
Expand Down
1 change: 1 addition & 0 deletions src/platform/configuration/common/configurationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ export namespace ConfigKey {
export const DefaultToolsGrouped = defineAndMigrateExpSetting<boolean>('chat.advanced.tools.defaultToolsGrouped', 'chat.tools.defaultToolsGrouped', false);
export const Gpt5AlternativePatch = defineAndMigrateExpSetting<boolean>('chat.advanced.gpt5AlternativePatch', 'chat.gpt5AlternativePatch', false);
export const SearchSubagentToolEnabled = defineSetting<boolean>('chat.searchSubagent.enabled', ConfigType.ExperimentBased, false);
export const SearchSubagentUseAgenticProxy = defineTeamInternalSetting<boolean>('chat.advanced.searchSubagent.useAgenticProxy', ConfigType.Simple, false);
export const InlineEditsTriggerOnEditorChangeAfterSeconds = defineAndMigrateExpSetting<number | undefined>('chat.advanced.inlineEdits.triggerOnEditorChangeAfterSeconds', 'chat.inlineEdits.triggerOnEditorChangeAfterSeconds', undefined);
export const InlineEditsNextCursorPredictionDisplayLine = defineAndMigrateExpSetting<boolean>('chat.advanced.inlineEdits.nextCursorPrediction.displayLine', 'chat.inlineEdits.nextCursorPrediction.displayLine', true);
export const InlineEditsNextCursorPredictionCurrentFileMaxTokens = defineAndMigrateExpSetting<number>('chat.advanced.inlineEdits.nextCursorPrediction.currentFileMaxTokens', 'chat.inlineEdits.nextCursorPrediction.currentFileMaxTokens', xtabPromptOptions.DEFAULT_OPTIONS.currentFile.maxTokens);
Expand Down
75 changes: 75 additions & 0 deletions src/platform/endpoint/node/proxyAgenticSearchEndpoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { RequestType } from '@vscode/copilot-api';
import { TokenizerType } from '../../../util/common/tokenizer';
import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';
import { IAuthenticationService } from '../../authentication/common/authentication';
import { IChatMLFetcher } from '../../chat/common/chatMLFetcher';
import { IConfigurationService } from '../../configuration/common/configurationService';
import { ILogService } from '../../log/common/logService';
import { IFetcherService } from '../../networking/common/fetcherService';
import { IExperimentationService } from '../../telemetry/common/nullExperimentationService';
import { ITelemetryService } from '../../telemetry/common/telemetry';
import { ITokenizerProvider } from '../../tokenizer/node/tokenizer';
import { ICAPIClientService } from '../common/capiClient';
import { IDomainService } from '../common/domainService';
import { IChatModelInformation } from '../common/endpointProvider';
import { ChatEndpoint } from './chatEndpoint';

export class ProxyAgenticSearchEndpoint extends ChatEndpoint {

constructor(
@IDomainService domainService: IDomainService,
@ICAPIClientService capiClientService: ICAPIClientService,
@IFetcherService fetcherService: IFetcherService,
@ITelemetryService telemetryService: ITelemetryService,
@IAuthenticationService authService: IAuthenticationService,
@IChatMLFetcher chatMLFetcher: IChatMLFetcher,
@ITokenizerProvider tokenizerProvider: ITokenizerProvider,
@IInstantiationService instantiationService: IInstantiationService,
@IConfigurationService configurationService: IConfigurationService,
@IExperimentationService experimentationService: IExperimentationService,
@ILogService logService: ILogService,
) {
const model = 'agentic-search-v1';
const modelInfo: IChatModelInformation = {
id: model,
name: model,
version: 'unknown',
model_picker_enabled: false,
is_chat_default: false,
is_chat_fallback: false,
capabilities: {
type: 'chat',
family: model,
tokenizer: TokenizerType.O200K,
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tokenizer type O200K is typically associated with OpenAI's GPT-4 and GPT-4o models. According to the PR description, this endpoint is for a fine-tuned Qwen3-4b model. Verify that O200K is the correct tokenizer for this model, as Qwen models typically use their own tokenizers. If the model was fine-tuned to be compatible with O200K tokenization, this is acceptable, but it should be documented why this choice was made.

Suggested change
tokenizer: TokenizerType.O200K,
tokenizer: TokenizerType.Unknown,

Copilot uses AI. Check for mistakes.
supports: { streaming: true, parallel_tool_calls: true, tool_calls: true, vision: false },
limits: {
max_prompt_tokens: 128000,
max_output_tokens: 16000,
}
}
};
super(
modelInfo,
domainService,
capiClientService,
fetcherService,
telemetryService,
authService,
chatMLFetcher,
tokenizerProvider,
instantiationService,
configurationService,
experimentationService,
logService
);
}

override get urlOrRequestMetadata() {
return { type: RequestType.ProxyChatCompletions };
}
}
Loading