docs: 添加 ToolSearch 设计指南 + 禁用 turn-zero 工具推荐弹窗

- 新增 docs/design/tool-search-design-guide.md,涵盖架构、搜索算法、执行管道、演进历史
- 禁用 getTurnZeroSearchExtraToolsPrefetch,消除用户输入时的频繁弹窗
- inter-turn 发现机制保持不变

Co-Authored-By: glm-5-turbo <zai-org@claude-code-best.win>
This commit is contained in:
claude-code-best
2026-05-09 16:45:56 +08:00
parent bd2253846f
commit 2cf18c4c49
61 changed files with 753 additions and 423 deletions

View File

@@ -1,5 +1,5 @@
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
import type { ToolDiscoveryResult } from '../services/toolSearch/prefetch.js'
import type { ToolDiscoveryResult } from '../services/searchExtraTools/prefetch.js'
import {
logEvent,
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
@@ -98,10 +98,10 @@ const skillSearchModules = feature('EXPERIMENTAL_SKILL_SEARCH')
require('../services/skillSearch/prefetch.js') as typeof import('../services/skillSearch/prefetch.js'),
}
: null
const toolSearchModules = feature('EXPERIMENTAL_TOOL_SEARCH')
const searchExtraToolsModules = feature('EXPERIMENTAL_SEARCH_EXTRA_TOOLS')
? {
prefetch:
require('../services/toolSearch/prefetch.js') as typeof import('../services/toolSearch/prefetch.js'),
require('../services/searchExtraTools/prefetch.js') as typeof import('../services/searchExtraTools/prefetch.js'),
}
: null
const autoModeStateModule = feature('TRANSCRIPT_CLASSIFIER')
@@ -166,17 +166,17 @@ import type { QuerySource } from '../constants/querySource.js'
import {
getDeferredToolsDelta,
isDeferredToolsDeltaEnabled,
isToolSearchEnabledOptimistic,
isToolSearchToolAvailable,
isSearchExtraToolsEnabledOptimistic,
isSearchExtraToolsToolAvailable,
type DeferredToolsDeltaScanContext,
} from './toolSearch.js'
} from './searchExtraTools.js'
import {
getMcpInstructionsDelta,
isMcpInstructionsDeltaEnabled,
type ClientSideInstruction,
} from './mcpInstructionsDelta.js'
import { CLAUDE_IN_CHROME_MCP_SERVER_NAME } from './claudeInChrome/common.js'
import { CHROME_TOOL_SEARCH_INSTRUCTIONS } from './claudeInChrome/prompt.js'
import { CHROME_SEARCH_EXTRA_TOOLS_INSTRUCTIONS } from './claudeInChrome/prompt.js'
import type { MCPServerConnection } from '../services/mcp/types.js'
import type {
HookEvent,
@@ -845,9 +845,9 @@ export async function getAttachments(
]
: []),
// Tool discovery on turn 0. Inter-turn discovery runs via
// startToolSearchPrefetch in query.ts.
...(feature('EXPERIMENTAL_TOOL_SEARCH') &&
toolSearchModules &&
// startSearchExtraToolsPrefetch in query.ts.
...(feature('EXPERIMENTAL_SEARCH_EXTRA_TOOLS') &&
searchExtraToolsModules &&
!options?.skipSkillDiscovery
? [
maybe('tool_discovery', async () => {
@@ -855,7 +855,7 @@ export async function getAttachments(
return []
}
const result =
await toolSearchModules.prefetch.getTurnZeroToolSearchPrefetch(
await searchExtraToolsModules.prefetch.getTurnZeroSearchExtraToolsPrefetch(
input,
context.options.tools ?? [],
)
@@ -1513,15 +1513,15 @@ export function getDeferredToolsDeltaAttachment(
scanContext?: DeferredToolsDeltaScanContext,
): Attachment[] {
if (!isDeferredToolsDeltaEnabled()) return []
// These three checks mirror the sync parts of isToolSearchEnabled —
// the attachment text says "available via ToolSearch", so ToolSearch
// These three checks mirror the sync parts of isSearchExtraToolsEnabled —
// the attachment text says "available via SearchExtraTools", so SearchExtraTools
// has to actually be in the request. The async auto-threshold check
// is not replicated (would double-fire tengu_tool_search_mode_decision);
// in tst-auto below-threshold the attachment can fire while ToolSearch
// is not replicated (would double-fire tengu_search_extra_tools_mode_decision);
// in tst-auto below-threshold the attachment can fire while SearchExtraTools
// is filtered out, but that's a narrow case and the tools announced
// are directly callable anyway.
if (!isToolSearchEnabledOptimistic()) return []
if (!isToolSearchToolAvailable(tools)) return []
if (!isSearchExtraToolsEnabledOptimistic()) return []
if (!isSearchExtraToolsToolAvailable(tools)) return []
const delta = getDeferredToolsDelta(tools, messages ?? [], scanContext)
if (!delta) return []
return [{ type: 'deferred_tools_delta', ...delta }]
@@ -1618,14 +1618,17 @@ export function getMcpInstructionsDeltaAttachment(
): Attachment[] {
if (!isMcpInstructionsDeltaEnabled()) return []
// The chrome ToolSearch hint is client-authored and ToolSearch-conditional;
// The chrome SearchExtraTools hint is client-authored and SearchExtraTools-conditional;
// actual server `instructions` are unconditional. Decide the chrome part
// here, pass it into the pure diff as a synthesized entry.
const clientSide: ClientSideInstruction[] = []
if (isToolSearchEnabledOptimistic() && isToolSearchToolAvailable(tools)) {
if (
isSearchExtraToolsEnabledOptimistic() &&
isSearchExtraToolsToolAvailable(tools)
) {
clientSide.push({
serverName: CLAUDE_IN_CHROME_MCP_SERVER_NAME,
block: CHROME_TOOL_SEARCH_INSTRUCTIONS,
block: CHROME_SEARCH_EXTRA_TOOLS_INSTRUCTIONS,
})
}