mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 13:55:50 +00:00
feat: 实现 Tool Search 基础设施层(CORE_TOOLS 白名单 + TF-IDF 索引 + ExecuteTool + 搜索增强)
- 新增 CORE_TOOLS 白名单常量(31 个核心工具),重构 isDeferredTool 为白名单制判定 - 新建 TF-IDF 工具索引模块(toolIndex.ts),复用 localSearch.ts 算法函数 - 新建 ExecuteTool 跨 API provider 统一工具执行入口 - 增强 ToolSearchTool:TF-IDF 搜索路径、discover: 模式、并行搜索合并、文本模式回退 - 新增 27 个单元测试,precheck 零错误通过(4108 tests pass) Co-Authored-By: glm-5.1[1m] <zai-org@claude-code-best.win>
This commit is contained in:
@@ -1,4 +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 {
|
||||
logEvent,
|
||||
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
@@ -97,6 +98,12 @@ 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')
|
||||
? {
|
||||
prefetch:
|
||||
require('../services/toolSearch/prefetch.js') as typeof import('../services/toolSearch/prefetch.js'),
|
||||
}
|
||||
: null
|
||||
const autoModeStateModule = feature('TRANSCRIPT_CLASSIFIER')
|
||||
? (require('./permissions/autoModeState.js') as typeof import('./permissions/autoModeState.js'))
|
||||
: null
|
||||
@@ -553,6 +560,14 @@ export type Attachment =
|
||||
activePath?: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
type: 'tool_discovery'
|
||||
tools: ToolDiscoveryResult[]
|
||||
trigger: 'assistant_turn' | 'user_input'
|
||||
queryText: string
|
||||
durationMs: number
|
||||
indexSize: number
|
||||
}
|
||||
| {
|
||||
type: 'queued_command'
|
||||
prompt: string | Array<ContentBlockParam>
|
||||
@@ -830,6 +845,25 @@ export async function getAttachments(
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
// Tool discovery on turn 0. Inter-turn discovery runs via
|
||||
// startToolSearchPrefetch in query.ts.
|
||||
...(feature('EXPERIMENTAL_TOOL_SEARCH') &&
|
||||
toolSearchModules &&
|
||||
!options?.skipSkillDiscovery
|
||||
? [
|
||||
maybe('tool_discovery', async () => {
|
||||
if (suppressNextDiscovery) {
|
||||
return []
|
||||
}
|
||||
const result =
|
||||
await toolSearchModules.prefetch.getTurnZeroToolSearchPrefetch(
|
||||
input,
|
||||
context.options.tools ?? [],
|
||||
)
|
||||
return result ? [result] : []
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
]
|
||||
: []
|
||||
|
||||
|
||||
@@ -3909,7 +3909,24 @@ Read the team config to discover your teammates' names. Check the task list peri
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- teammate_mailbox/team_context/skill_discovery/bagel_console handled above
|
||||
// tool_discovery handled here (not in the switch) so the 'tool_discovery'
|
||||
// string literal lives inside a feature()-guarded block.
|
||||
if (feature('EXPERIMENTAL_TOOL_SEARCH')) {
|
||||
if (attachment.type === 'tool_discovery') {
|
||||
if (attachment.tools.length === 0) return []
|
||||
const lines = attachment.tools.map(
|
||||
t => `- ${t.name}: ${t.description.slice(0, 100)}`,
|
||||
)
|
||||
return wrapMessagesInSystemReminder([
|
||||
createUserMessage({
|
||||
content: `The following tools were discovered as relevant to your task. Use ExecuteTool to invoke any of them by name:\n\n${lines.join('\n')}`,
|
||||
isMeta: true,
|
||||
}),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check -- teammate_mailbox/team_context/skill_discovery/tool_discovery/bagel_console handled above
|
||||
switch (attachment.type) {
|
||||
case 'directory': {
|
||||
return wrapMessagesInSystemReminder([
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/**
|
||||
* Tool Search utilities for dynamically discovering deferred tools.
|
||||
*
|
||||
* When enabled, deferred tools (MCP and shouldDefer tools) are sent with
|
||||
* When enabled, deferred tools (all non-core tools) are sent with
|
||||
* defer_loading: true and discovered via ToolSearchTool rather than being
|
||||
* loaded upfront.
|
||||
* loaded upfront. Core tools are defined in CORE_TOOLS (src/constants/tools.ts).
|
||||
*/
|
||||
|
||||
import memoize from 'lodash-es/memoize.js'
|
||||
@@ -152,8 +152,8 @@ const getDeferredToolTokenCount = memoize(
|
||||
)
|
||||
|
||||
/**
|
||||
* Tool search mode. Determines how deferrable tools (MCP + shouldDefer) are
|
||||
* surfaced:
|
||||
* Tool search mode. Determines how deferred tools (all non-core tools)
|
||||
* are surfaced:
|
||||
* - 'tst': Tool Search Tool — deferred tools discovered via ToolSearchTool (always enabled)
|
||||
* - 'tst-auto': auto — tools deferred only when they exceed threshold
|
||||
* - 'standard': tool search disabled — all tools exposed inline
|
||||
@@ -167,7 +167,7 @@ export type ToolSearchMode = 'tst' | 'tst-auto' | 'standard'
|
||||
* auto / auto:1-99 tst-auto
|
||||
* true / auto:0 tst
|
||||
* false / auto:100 standard
|
||||
* (unset) tst (default: always defer MCP and shouldDefer tools)
|
||||
* (unset) tst (default: always defer non-core tools)
|
||||
*/
|
||||
export function getToolSearchMode(): ToolSearchMode {
|
||||
// CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS is a kill switch for beta API
|
||||
@@ -194,7 +194,7 @@ export function getToolSearchMode(): ToolSearchMode {
|
||||
|
||||
if (isEnvTruthy(value)) return 'tst'
|
||||
if (isEnvDefinedFalsy(process.env.ENABLE_TOOL_SEARCH)) return 'standard'
|
||||
return 'tst' // default: always defer MCP and shouldDefer tools
|
||||
return 'tst' // default: always defer non-core tools
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user