Skip to content

Commit d75a407

Browse files
authored
Remove server-side tool search and consolidate on client-side tool_search (#310343)
- Remove all server-side tool_search_tool_regex types, handlers, and stream processing from messagesApi.ts - Remove isAnthropicToolSearchEnabled/isAnthropicCustomToolSearchEnabled functions - Remove AnthropicToolSearchEnabled and AnthropicToolSearchMode settings - Remove TOOL_SEARCH_TOOL_NAME, TOOL_SEARCH_TOOL_TYPE, TOOL_SEARCH_SUPPORTED_MODELS constants - Refactor modelSupportsToolSearch to use version parsing instead of prefix list - Add models filter to ToolSearchTool registration for Claude Sonnet/Opus 4.5+ - Fix MockEndpoint to derive supportsToolSearch from model family - Gate advanced-tool-use beta header directly on endpoint.supportsToolSearch - Update prompts to use client-side tool_search name and semantic search instructions - Update 24 snapshot files to reflect new tool name and instructions
1 parent f58e28c commit d75a407

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+212
-521
lines changed

extensions/copilot/package.json

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3196,27 +3196,6 @@
31963196
"preview",
31973197
"onExp"
31983198
]
3199-
},
3200-
"github.copilot.chat.anthropic.toolSearchTool.enabled": {
3201-
"type": "boolean",
3202-
"default": true,
3203-
"markdownDescription": "%github.copilot.config.anthropic.toolSearchTool.enabled%",
3204-
"tags": [
3205-
"preview"
3206-
]
3207-
},
3208-
"github.copilot.chat.anthropic.toolSearchTool.mode": {
3209-
"type": "string",
3210-
"enum": [
3211-
"server",
3212-
"client"
3213-
],
3214-
"default": "server",
3215-
"markdownDescription": "%github.copilot.config.anthropic.toolSearchTool.mode%",
3216-
"tags": [
3217-
"preview",
3218-
"onExp"
3219-
]
32203199
}
32213200
}
32223201
},

extensions/copilot/package.nls.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,6 @@
333333
"copilot.toolSet.web.description": "Fetch information from the web",
334334
"github.copilot.config.useMessagesApi": "Use the Messages API instead of the Chat Completions API when supported.",
335335
"github.copilot.config.anthropic.contextEditing.mode": "Select the context editing mode for Anthropic models. Automatically manages conversation context as it grows, helping optimize costs and stay within context window limits.\n\n- `off`: Context editing is disabled.\n- `clear-thinking`: Clears thinking blocks while preserving tool uses.\n- `clear-tooluse`: Clears tool uses while preserving thinking blocks.\n- `clear-both`: Clears both thinking blocks and tool uses.\n\n**Note**: This is an experimental feature. Context editing may cause additional cache rewrites. Enable with caution.",
336-
"github.copilot.config.anthropic.toolSearchTool.enabled": "Enable tool search tool for Anthropic models. When enabled, tools are dynamically discovered and loaded on-demand using natural language search, reducing context window usage when many tools are available.",
337-
"github.copilot.config.anthropic.toolSearchTool.mode": "Controls how tool search works for Anthropic models. 'server' uses Anthropic's built-in regex-based tool search. 'client' uses local embeddings-based semantic search for more accurate tool discovery.",
338336
"github.copilot.config.useResponsesApi": "Use the Responses API instead of the Chat Completions API when supported. Enables reasoning and reasoning summaries.\n\n**Note**: This is an experimental feature that is not yet activated for all users.\n\n**Important**: URL API path resolution for custom OpenAI-compatible and Azure models is independent of this setting and fully determined by `url` property of `#github.copilot.chat.customOAIModels#` or `#github.copilot.chat.azureModels#` respectively.",
339337
"github.copilot.config.responsesApiReasoningSummary": "Sets the reasoning summary style used for the Responses API. Requires `#github.copilot.chat.useResponsesApi#`.",
340338
"github.copilot.config.responsesApiContextManagement.enabled": "Enables context management for the Responses API. Requires `#github.copilot.chat.useResponsesApi#`.",

extensions/copilot/src/extension/byok/vscode-node/anthropicProvider.ts

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import { CancellationToken, LanguageModelChatInformation, LanguageModelChatMessa
99
import { ChatFetchResponseType, ChatLocation } from '../../../platform/chat/common/commonTypes';
1010
import { ConfigKey, IConfigurationService } from '../../../platform/configuration/common/configurationService';
1111
import { CustomDataPartMimeTypes } from '../../../platform/endpoint/common/endpointTypes';
12+
import { modelSupportsToolSearch } from '../../../platform/endpoint/common/chatModelCapabilities';
1213
import { buildToolInputSchema } from '../../../platform/endpoint/node/messagesApi';
1314
import { ILogService } from '../../../platform/log/common/logService';
14-
import { ContextManagementResponse, getContextManagementFromConfig, isAnthropicContextEditingEnabled, isAnthropicMemoryToolEnabled, isAnthropicToolSearchEnabled, TOOL_SEARCH_TOOL_NAME, TOOL_SEARCH_TOOL_TYPE, ToolSearchToolResult, ToolSearchToolSearchResult } from '../../../platform/networking/common/anthropic';
15+
import { ContextManagementResponse, CUSTOM_TOOL_SEARCH_NAME, getContextManagementFromConfig, isAnthropicContextEditingEnabled, isAnthropicMemoryToolEnabled } from '../../../platform/networking/common/anthropic';
1516
import { IToolDeferralService } from '../../../platform/networking/common/toolDeferralService';
1617
import { IResponseDelta, OpenAiFunctionTool } from '../../../platform/networking/common/fetch';
1718
import { APIUsage } from '../../../platform/networking/common/openai';
@@ -146,19 +147,14 @@ export class AnthropicLMProvider extends AbstractLanguageModelChatProvider {
146147

147148
const memoryToolEnabled = isAnthropicMemoryToolEnabled(model.id, this._configurationService, this._experimentationService);
148149

149-
const toolSearchEnabled = isAnthropicToolSearchEnabled(model.id.replace(/-/g, '.'), this._configurationService);
150+
// Requires the client-side tool_search tool in the request: without it, defer-loaded tools can't be retrieved.
151+
// If the user disables tool_search in the tool picker, it won't be present here and tool search is skipped.
152+
const toolSearchEnabled = modelSupportsToolSearch(model.id)
153+
&& !!options.tools?.some(t => t.name === CUSTOM_TOOL_SEARCH_NAME);
150154

151155
// Build tools array, handling both standard tools and native Anthropic tools
152156
const tools: Anthropic.Beta.BetaToolUnion[] = [];
153157

154-
// Add tool search tool if enabled (must be first in the array)
155-
if (toolSearchEnabled) {
156-
tools.push({
157-
name: TOOL_SEARCH_TOOL_NAME,
158-
type: TOOL_SEARCH_TOOL_TYPE,
159-
defer_loading: false
160-
} as Anthropic.Beta.BetaToolUnion);
161-
}
162158
let hasMemoryTool = false;
163159
for (const tool of (options.tools ?? [])) {
164160
// Handle native Anthropic memory tool (only for models that support it)
@@ -646,33 +642,6 @@ export class AnthropicLMProvider extends AbstractLanguageModelChatProvider {
646642
[new LanguageModelTextPart(searchResults)]
647643
));
648644
pendingServerToolCall = undefined;
649-
} else if ('content_block' in chunk && chunk.content_block.type === 'tool_search_tool_result') {
650-
const toolSearchResult = chunk.content_block as unknown as ToolSearchToolResult;
651-
if (toolSearchResult.content.type === 'tool_search_tool_search_result') {
652-
const searchResult = toolSearchResult.content as ToolSearchToolSearchResult;
653-
const toolNames = searchResult.tool_references.map(ref => ref.tool_name);
654-
655-
this._logService.trace(`Tool search discovered ${toolNames.length} tools: ${toolNames.join(', ')}`);
656-
657-
let query: string | undefined;
658-
if (pendingServerToolCall) {
659-
try {
660-
const parsed = JSON.parse(pendingServerToolCall.jsonInput || '{}');
661-
query = parsed.query;
662-
} catch {
663-
// Ignore parse errors
664-
}
665-
}
666-
667-
progress.report(new LanguageModelToolResultPart(
668-
toolSearchResult.tool_use_id,
669-
[new LanguageModelTextPart(JSON.stringify({ query, discovered_tools: toolNames }))]
670-
));
671-
pendingServerToolCall = undefined;
672-
} else if (toolSearchResult.content.type === 'tool_search_tool_result_error') {
673-
this._logService.warn(`Tool search error: ${toolSearchResult.content.error_code}`);
674-
pendingServerToolCall = undefined;
675-
}
676645
}
677646
continue;
678647
}

extensions/copilot/src/extension/conversation/vscode-node/languageModelAccess.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { CopilotToken } from '../../../platform/authentication/common/copilotTok
1111
import { IBlockedExtensionService } from '../../../platform/chat/common/blockedExtensionService';
1212
import { ChatFetchResponseType, ChatLocation, getErrorDetailsFromChatFetchError } from '../../../platform/chat/common/commonTypes';
1313
import { getTextPart } from '../../../platform/chat/common/globalStringUtils';
14-
import { IConfigurationService } from '../../../platform/configuration/common/configurationService';
1514
import { EmbeddingType, getWellKnownEmbeddingTypeInfo, IEmbeddingsComputer } from '../../../platform/embeddings/common/embeddingsComputer';
1615
import { IEndpointProvider } from '../../../platform/endpoint/common/endpointProvider';
1716
import { CustomDataPartMimeTypes } from '../../../platform/endpoint/common/endpointTypes';
@@ -23,7 +22,6 @@ import { IEnvService, isScenarioAutomation } from '../../../platform/env/common/
2322
import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext';
2423
import { IOctoKitService } from '../../../platform/github/common/githubService';
2524
import { ILogService } from '../../../platform/log/common/logService';
26-
import { isAnthropicToolSearchEnabled } from '../../../platform/networking/common/anthropic';
2725
import { FinishedCallback, OpenAiFunctionTool, OptionalChatRequestParams } from '../../../platform/networking/common/fetch';
2826
import { IChatEndpoint, IEndpoint } from '../../../platform/networking/common/networking';
2927
import { IOTelService, type OTelModelOptions } from '../../../platform/otel/common/otelService';
@@ -495,7 +493,6 @@ export class CopilotLanguageModelWrapper extends Disposable {
495493
@ILogService private readonly _logService: ILogService,
496494
@IAuthenticationService private readonly _authenticationService: IAuthenticationService,
497495
@IEnvService private readonly _envService: IEnvService,
498-
@IConfigurationService private readonly _configurationService: IConfigurationService,
499496
@IOTelService private readonly _otelService: IOTelService,
500497
@IOctoKitService private readonly _octoKitService: IOctoKitService,
501498
) {
@@ -561,7 +558,7 @@ export class CopilotLanguageModelWrapper extends Disposable {
561558
throw new Error('Message exceeds token limit.');
562559
}
563560

564-
if (_options.tools && _options.tools.length > 128 && !isAnthropicToolSearchEnabled(_endpoint, this._configurationService)) {
561+
if (_options.tools && _options.tools.length > 128 && !_endpoint.supportsToolSearch) {
565562
throw new Error('Cannot have more than 128 tools per request.');
566563
}
567564

extensions/copilot/src/extension/intents/node/agentIntent.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { IAutomodeService } from '../../../platform/endpoint/node/automodeServic
1616
import { IEnvService } from '../../../platform/env/common/envService';
1717
import { ILogService } from '../../../platform/log/common/logService';
1818
import { IEditLogService } from '../../../platform/multiFileEdit/common/editLogService';
19-
import { CUSTOM_TOOL_SEARCH_NAME, isAnthropicCustomToolSearchEnabled, isAnthropicContextEditingEnabled, isAnthropicToolSearchEnabled } from '../../../platform/networking/common/anthropic';
19+
import { CUSTOM_TOOL_SEARCH_NAME, isAnthropicContextEditingEnabled } from '../../../platform/networking/common/anthropic';
2020
import { IChatEndpoint } from '../../../platform/networking/common/networking';
2121
import { modelsWithoutResponsesContextManagement } from '../../../platform/networking/common/openai';
2222
import { INotebookService } from '../../../platform/notebook/common/notebookService';
@@ -139,7 +139,7 @@ export const getAgentTools = async (accessor: ServicesAccessor, request: vscode.
139139
allowTools[ToolName.MultiReplaceString] = true;
140140
}
141141

142-
allowTools[CUSTOM_TOOL_SEARCH_NAME] = isAnthropicCustomToolSearchEnabled(model, configurationService, experimentationService);
142+
allowTools[CUSTOM_TOOL_SEARCH_NAME] = !!model.supportsToolSearch;
143143

144144
const tools = toolsService.getEnabledTools(request, model, tool => {
145145
if (typeof allowTools[tool.name] === 'boolean') {
@@ -406,7 +406,7 @@ export class AgentIntentInvocation extends EditCodeIntentInvocation implements I
406406
}
407407

408408
const tools = promptContext.tools?.availableTools;
409-
const toolSearchEnabled = isAnthropicToolSearchEnabled(this.endpoint, this.configurationService);
409+
const toolSearchEnabled = !!this.endpoint.supportsToolSearch;
410410
const toolTokens = tools?.length ? await this.endpoint.acquireTokenizer().countToolTokens(tools) : 0;
411411

412412
const summarizeThresholdOverride = this.configurationService.getConfig<number | undefined>(ConfigKey.Advanced.SummarizeAgentConversationHistoryThreshold);
@@ -674,7 +674,7 @@ export class AgentIntentInvocation extends EditCodeIntentInvocation implements I
674674
this._lastModelCapabilities = {
675675
enableThinking: !isAnthropicFamily(this.endpoint) || ToolCallingLoop.messagesContainThinking(strippedMessages),
676676
reasoningEffort: typeof rawEffort === 'string' ? rawEffort : undefined,
677-
enableToolSearch: !isSubagent && isAnthropicToolSearchEnabled(this.endpoint, this.configurationService),
677+
enableToolSearch: !isSubagent && !!this.endpoint.supportsToolSearch,
678678
enableContextEditing: !isSubagent && isAnthropicContextEditingEnabled(this.endpoint, this.configurationService, this.expService),
679679
};
680680
}

extensions/copilot/src/extension/prompt/node/chatMLFetcher.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import { ICAPIClientService } from '../../../platform/endpoint/common/capiClient
1919
import { isAutoModel } from '../../../platform/endpoint/node/autoChatEndpoint';
2020
import { getResponsesApiCompactionThresholdFromBody, OpenAIResponsesProcessor, responseApiInputToRawMessagesForLogging, sendCompletionOutputTelemetry } from '../../../platform/endpoint/node/responsesApi';
2121
import { collectSingleLineErrorMessage, ILogService } from '../../../platform/log/common/logService';
22-
import { isAnthropicToolSearchEnabled } from '../../../platform/networking/common/anthropic';
2322
import { FinishedCallback, getRequestId, IResponseDelta, OptionalChatRequestParams, RequestId } from '../../../platform/networking/common/fetch';
2423
import { FetcherId, IFetcherService, Response } from '../../../platform/networking/common/fetcherService';
2524
import { IBackgroundRequestOptions, IChatEndpoint, IEndpointBody, ISubagentRequestOptions, postRequest, stringifyUrlOrRequestMetadata } from '../../../platform/networking/common/networking';
@@ -2172,7 +2171,7 @@ function isValidChatPayload(messages: Raw.ChatMessage[], postOptions: OptionalCh
21722171
return { isValid: false, reason: asUnexpected('Function names must match ^[a-zA-Z0-9_-]+$') };
21732172
}
21742173

2175-
if (postOptions?.tools && postOptions.tools.length > HARD_TOOL_LIMIT && !isAnthropicToolSearchEnabled(endpoint, configurationService)) {
2174+
if (postOptions?.tools && postOptions.tools.length > HARD_TOOL_LIMIT && !endpoint.supportsToolSearch) {
21762175
return { isValid: false, reason: `Tool limit exceeded (${postOptions.tools.length}/${HARD_TOOL_LIMIT}). Click "Configure Tools" in the chat input to disable ${postOptions.tools.length - HARD_TOOL_LIMIT} tools and retry.` };
21772176
}
21782177

extensions/copilot/src/extension/prompt/node/defaultIntentRequestHandler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { IGitService } from '../../../platform/git/common/gitService';
2121
import { IOctoKitService } from '../../../platform/github/common/githubService';
2222
import { HAS_IGNORED_FILES_MESSAGE } from '../../../platform/ignore/common/ignoreService';
2323
import { ILogService } from '../../../platform/log/common/logService';
24-
import { isAnthropicContextEditingEnabled, isAnthropicToolSearchEnabled } from '../../../platform/networking/common/anthropic';
24+
import { isAnthropicContextEditingEnabled } from '../../../platform/networking/common/anthropic';
2525
import { FilterReason } from '../../../platform/networking/common/openai';
2626
import { IOTelService } from '../../../platform/otel/common/otelService';
2727
import { CapturingToken } from '../../../platform/requestLogger/common/capturingToken';
@@ -701,7 +701,7 @@ class DefaultToolCallingLoop extends ToolCallingLoop<IDefaultToolLoopOptions> {
701701
...opts.modelCapabilities,
702702
enableThinking: isThinkingLocation && opts.modelCapabilities?.enableThinking,
703703
reasoningEffort,
704-
enableToolSearch: !isSubagent && isAnthropicToolSearchEnabled(this.options.invocation.endpoint, this._configurationService),
704+
enableToolSearch: !isSubagent && !!this.options.invocation.endpoint.supportsToolSearch,
705705
enableContextEditing: !isSubagent && isAnthropicContextEditingEnabled(this.options.invocation.endpoint, this._configurationService, this._experimentationService),
706706
},
707707
debugName,
@@ -741,7 +741,7 @@ class DefaultToolCallingLoop extends ToolCallingLoop<IDefaultToolLoopOptions> {
741741
const tools = await this.options.invocation.getAvailableTools?.() ?? [];
742742

743743
// Skip tool grouping when Anthropic tool search is enabled
744-
if (isAnthropicFamily(this.options.invocation.endpoint) && isAnthropicToolSearchEnabled(this.options.invocation.endpoint, this._configurationService)) {
744+
if (isAnthropicFamily(this.options.invocation.endpoint) && this.options.invocation.endpoint.supportsToolSearch) {
745745
return tools;
746746
}
747747

0 commit comments

Comments
 (0)