闭架书库的索书条
市图书馆的老馆有两种书架。阅览室的开架区只摆最常用的那几百本——字典、年鉴、地图册,伸手就能拿。剩下的两百万册藏在地下三层的闭架书库里,读者进不去。
阅览室墙上贴着一张长长的书目单:只有书名,一行一个,没有简介,没有目录。想看哪本,不能自己去搬,得去服务台。
服务台有两种借法。你若知道确切的书名,就写一张索书条——「《营造法式》,《天工开物》,《考工记》」——一张条子可以写好几本,馆员照单取书,一趟全拿来。你若只有个模糊的方向,就口头描述:「找讲宋代木结构的」。馆员翻目录卡,按书名字眼、主题词的吻合程度逐本打分,把得分最高的几本抱出来。你还可以加重语气:「必须和『桥梁』有关」——她就先剔掉所有不沾边的,再给剩下的排序。
取来的书不是塞给你就完事——馆员在你的座位登记簿上记一笔。此后一整天,无论你换几次座位,只要登记簿上有这本书,它就一直摊在你桌面上,不必再借第二次。哪怕中午图书馆清桌、把你摊开的资料收拢成一页摘要,馆员也会先抄下登记簿,清完桌再把那几本书原样摆回去。
馆规里还有几条很妙:你若写索书条要一本其实就在开架区的书,馆员不训你,顺手从开架上抽给你——总比让你白跑一趟强。有的分馆(设备旧,做不了这套流程)干脆没有闭架服务,一切照旧全摆开架。书目单也有两种贴法:老办法是每天早上重印整张单子;新办法是只贴增补启事——「今日新到某某」「某书已注销,别再来问」——省得整面墙天天重糊。
这座图书馆用一张只有书名的清单,替代了「把两百万册书全搬进阅览室」的荒唐做法。Claude Code 对工具做了同一件事——这就是延迟工具加载与工具搜索(deferred tool loading & ToolSearch)。
先猜揭晓前,先押一个猜测 · 你觉得这讲的是?
谜底 · The Concept
Deferred tool loading & ToolSearch — names up front, schemas on demand
Tools · 工具系统
中文速览 · Quick read
Deferred tool loading is Claude Code's answer to tool-schema bloat. Instead of expanding every tool definition into every request, the harness marks a subset of tools as deferred: their schemas ride to the API with defer_loading: true — a beta field on the tool schema (claude-code/src/utils/api.ts:69-78) set at serialization time (claude-code/src/utils/api.ts:223-226) — and the model is told about them by name only. One always-loaded tool, named ToolSearch (claude-code/src/tools/ToolSearchTool/constants.ts:1), is the retrieval interface: the model calls it with a query string plus an optional max_results defaulting to 5 (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:21-34), and the result carries tool_reference content blocks that the API expands into full tool definitions (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:444-470).
Which tools are deferred is decided by isDeferredTool, in strict order: alwaysLoad: true opts out first, every MCP tool is deferred, ToolSearch itself never is (the model needs it to load everything else), a few communication-critical tools are exempted behind build features, and otherwise the tool's own shouldDefer flag decides (claude-code/src/tools/ToolSearchTool/prompt.ts:62-108). The per-tool fields involved — searchHint, isMcp, shouldDefer, alwaysLoad — are declared on the Tool type (claude-code/src/Tool.ts:378,436,442,449).
How it works
Registration is optimistic: ToolSearchTool.isEnabled() just calls isToolSearchEnabledOptimistic() (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:304-313), which only rules out the definitely-off cases: standard mode, or — when ENABLE_TOOL_SEARCH is unset — a first-party provider whose ANTHROPIC_BASE_URL points at a non-Anthropic proxy, since such proxies typically reject tool_reference blocks; setting any non-empty value overrides this heuristic (claude-code/src/utils/toolSearch.ts:270-320). The mode itself maps ENABLE_TOOL_SEARCH to 'tst' | 'tst-auto' | 'standard' — auto/auto:1-99 → tst-auto, true/auto:0 → tst, false/auto:100 → standard, unset → tst — with CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS acting as a kill switch that forces standard (claude-code/src/utils/toolSearch.ts:172-198). The same kill switch also strips defer_loading (and every other non-allowlisted beta field) at the one choke point all tool schemas pass through, so no beta shape reaches the wire (claude-code/src/utils/api.ts:232-243).
The definitive per-request check, isToolSearchEnabled, layers three more gates: the model must support tool_reference — a negative test defaulting to ['haiku'], live-overridable via the GrowthBook feature tengu_tool_search_unsupported_models (claude-code/src/utils/toolSearch.ts:204,239-252,419-426); ToolSearchTool must actually be in the tool list, respecting disallowedTools (claude-code/src/utils/toolSearch.ts:429-435); and finally the mode switch, where tst-auto additionally measures total deferred-tool description size against a threshold (claude-code/src/utils/toolSearch.ts:437-473). The query path in claude.ts runs this check per request (claude-code/src/services/api/claude.ts:1120-1126), precomputes the deferred name set once (claude-code/src/services/api/claude.ts:1128-1134), and disables tool search when there is nothing to defer and no MCP servers are still connecting (claude-code/src/services/api/claude.ts:1139-1148).
With tool search on, filteredTools keeps every non-deferred tool, always keeps ToolSearch, and keeps a deferred tool only if it appears in extractDiscoveredToolNames(messages) (claude-code/src/services/api/claude.ts:1154-1172) — the code comments that this "removes limits on tool quantity" because deferred tools no longer need to be predeclared upfront (claude-code/src/services/api/claude.ts:1155-1157). A provider-specific beta header is pushed (Bedrock routes it through body params instead) (claude-code/src/services/api/claude.ts:1177-1182). Each surviving tool is serialized via toolToAPISchema(tool, { deferLoading: willDefer(tool), ... }) (claude-code/src/services/api/claude.ts:1232-1246), which sets schema.defer_loading = true (claude-code/src/utils/api.ts:223-226). One subtlety: the full tools list — not filteredTools — is passed into schema generation, so ToolSearch's own prompt can describe all MCP tools even though only discovered ones are actually sent (claude-code/src/services/api/claude.ts:1232-1234).
How the model learns the deferred names depends on isDeferredToolsDeltaEnabled() — USER_TYPE === 'ant' or the GrowthBook flag tengu_glacier_2xr (claude-code/src/utils/toolSearch.ts:629-634). With the flag off, claude.ts prepends an ephemeral meta user message wrapping the sorted name list in <available-deferred-tools> tags on every call (claude-code/src/services/api/claude.ts:1330-1345). With it on, getDeferredToolsDeltaAttachment emits a persisted deferred_tools_delta attachment instead (claude-code/src/utils/attachments.ts:1455-1475), rendered to the model as a system-reminder listing newly available and newly removed tools (claude-code/src/utils/messages.ts:4178-4193). The delta is computed by replaying all prior delta attachments to reconstruct the announced set, then diffing against the current pool — and a tool that was announced but has since stopped being deferred, yet is still in the pool, is deliberately not reported as removed, because it's now loaded directly and "no longer available" would be a lie (claude-code/src/utils/toolSearch.ts:646-706). Each announced line is just the tool name; searchHint is intentionally omitted after an A/B test showed no benefit (claude-code/src/tools/ToolSearchTool/prompt.ts:110-117). ToolSearch's own prompt duplicates the delta gate by hand to tell the model where the names appear, and carries a comment that it must stay in sync (claude-code/src/tools/ToolSearchTool/prompt.ts:35-42).
call() recomputes deferredTools = tools.filter(isDeferredTool) and invalidates a description cache memoized by tool name whenever the deferred name-set changes (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:328-332,66-105). A select: query is comma-split and each name resolved with findToolByName — which matches primary names or aliases (claude-code/src/Tool.ts:348-360) — against the deferred set first, then the full set; missing names are tolerated, and selecting an already-loaded tool is a designed no-op that "lets the model proceed without retry churn" (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:358-406). Keyword queries go through searchToolsWithKeywords: an exact-name fast path over deferred then full tools (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:199-204), an mcp__ prefix branch for server-name queries (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:208-216), a +term partition where +-prefixed terms are required and pre-filter the candidates (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:218-257), and finally scoring: exact name-part match scores 10 (12 for MCP), substring 5 (6 for MCP), full-name fallback 3, a word-boundary hit in searchHint 4, and in the tool description 2 (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:266-301). Names are decomposed by parseToolName, which splits mcp__server__action on underscores and regular tool names on CamelCase (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:132-161). An empty result includes pending_mcp_servers (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:37-47,335-339) so the model knows to retry once servers finish connecting.
Matches are mapped into a tool_result whose content is a list of { type: 'tool_reference', tool_name } blocks — cast through as unknown as ToolResultBlockParam because tool_reference is a beta content type absent from the SDK types (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:444-470). The API expands these into real definitions, but the next request is rebuilt from scratch — so extractDiscoveredToolNames re-scans the message history for tool_result → tool_reference blocks each turn to decide which deferred tools stay in filteredTools (claude-code/src/utils/toolSearch.ts:545-592). Compaction would destroy that evidence (the summary preserves no tool_reference blocks), so the compactor snapshots the discovered set onto the boundary marker's compactMetadata.preCompactDiscoveredTools (claude-code/src/services/compact/compact.ts:605-610), and the scanner reads it back from any compact-boundary message it encounters (claude-code/src/utils/toolSearch.ts:553-560).
Why it matters
MCP servers can contribute hundreds of tools, each with a description and JSON schema. Deferral means the initial prompt carries a name list instead of full schemas, and the model pays the schema cost only for tools it actually fetches — which is exactly why the code notes this "eliminates the need to predeclare all deferred tools upfront and removes limits on tool quantity" (claude-code/src/services/api/claude.ts:1155-1157).
The two announcement channels exist because the ephemeral <available-deferred-tools> prepend "busts cache whenever the pool changes"; the persisted delta attachment only appends increments (claude-code/src/services/api/claude.ts:1327-1330; claude-code/src/utils/toolSearch.ts:624-634).
Because defer_loading and tool_reference are beta API shapes, the harness hedges at every layer: proxies that would 400 on tool_reference are heuristically detected (claude-code/src/utils/toolSearch.ts:282-311), the kill switch strips beta fields at a single choke point (claude-code/src/utils/api.ts:232-243), unsupported models like Haiku are excluded by a live-updatable negative list (claude-code/src/utils/toolSearch.ts:204,239-252), and select: on an already-loaded tool is a graceful no-op precisely because subagents and post-compaction turns were observed doing it (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:194-204,358-362).
The shape — announce names cheaply, retrieve schemas on demand, persist discovery in the transcript, carry it across compaction — is the harness's general recipe for making an unbounded resource pool fit a bounded context window.
Read the source
Suggested order:
- claude-code/src/tools/ToolSearchTool/prompt.ts — start with
isDeferredTool(prompt.ts:62-108) to see exactly what gets deferred, then the tool's own prompt text and the hand-synced location hint (prompt.ts:35-51,110-121). - claude-code/src/utils/toolSearch.ts — the mode mapping (172-198), model support (239-252), optimistic vs. definitive gates (270-320, 385-473), the discovery scan (545-592), and the delta diff (629-706).
- claude-code/src/services/api/claude.ts:1118-1182,1232-1246,1330-1345 — the per-request assembly: gate,
deferredToolNames,filteredTools, beta header, schema serialization, and the ephemeral announcement. - claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts — schemas (21-47), the description cache (66-105), name parsing and scoring (132-161, 186-302),
call()with theselect:branch (328-434), and thetool_referenceresult mapping (444-470). - claude-code/src/utils/api.ts:69-78,215-243 — how
defer_loadingreaches the wire, and how the kill switch strips it. - claude-code/src/utils/attachments.ts:1455-1475, claude-code/src/utils/messages.ts:4178-4193, claude-code/src/services/compact/compact.ts:605-610 — the persisted announcement channel and compaction survival.
classDiagram
class isDeferredTool {
<<rule order>>
+alwaysLoad neverDefer
+mcp defer
+toolSearch neverDefer
+else shouldDefer
}
class ToolSearchTool {
+call(query, max_results)
-descCacheMemoized
+maybeInvalidateCache()
}
class SelectPath {
<<select exact>>
+splitOnComma()
+lookupDeferredThenFull()
}
class KeywordPath {
+exactNameFastPath()
+requiredGate allMustMatch
+scoreTiers high_to_low
+sortSliceMaxResults()
}
class tool_reference {
+matchedNames
}
ToolSearchTool ..> isDeferredTool : filter deferred set
ToolSearchTool ..> SelectPath : select prefix
ToolSearchTool ..> KeywordPath : keywords
SelectPath ..> tool_reference : found
KeywordPath ..> tool_reference : top matches 读法:isDeferredTool 决定哪些工具只露名字(prompt.ts:62-107)。
ToolSearchTool.call 先过滤延迟集(:331)再二选一:select: 精确取(:374),或
关键词——+ 前缀是必含硬闸(:236),再按 12/10/6/5/4/2 打分排序截断(:267)。
描述按名 memoize、池变即失效(:66,91)。命中包成 tool_reference 块,API 再展开成完整
schema(:462)。
目录墙上是 14 件延迟工具——只露名字,schema 全收在库里。下面的预算条说明了原因: 把每件的 schema 都装上来会撑爆上下文。要真用一件,就给 ToolSearch 一条查询:报几个 关键词、用 + 标出必含项、或直接 select:确切名字。只有点名的、或排进前 max_results 名的,才会从「名字」展开成「完整 schema」。
这正是 延迟工具加载与工具搜索(deferred tool loading & tool search):会话里成百上千件工具
先只摆名字,只有 ToolSearch 按名(select:)或按词把命中的几件包成 tool_reference,
API 再展开成完整定义——上下文只为真正要用的那几件付费。最隐蔽的坑:一个命中为零的必含项,
会在打分之前就把全部候选划掉,纵然可选词命中再多,结果仍是空集。
Deferred tool loading is Claude Code's answer to tool-schema bloat. Instead of expanding every tool definition into every request, the harness marks a subset of tools as deferred: their schemas ride to the API with defer_loading: true — a beta field on the tool schema (claude-code/src/utils/api.ts:69-78) set at serialization time (claude-code/src/utils/api.ts:223-226) — and the model is told about them by name only. One always-loaded tool, named ToolSearch (claude-code/src/tools/ToolSearchTool/constants.ts:1), is the retrieval interface: the model calls it with a query string plus an optional max_results defaulting to 5 (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:21-34), and the result carries tool_reference content blocks that the API expands into full tool definitions (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:444-470).
Which tools are deferred is decided by isDeferredTool, in strict order: alwaysLoad: true opts out first, every MCP tool is deferred, ToolSearch itself never is (the model needs it to load everything else), a few communication-critical tools are exempted behind build features, and otherwise the tool's own shouldDefer flag decides (claude-code/src/tools/ToolSearchTool/prompt.ts:62-108). The per-tool fields involved — searchHint, isMcp, shouldDefer, alwaysLoad — are declared on the Tool type (claude-code/src/Tool.ts:378,436,442,449).
How it works
A layered enablement gate. Registration is optimistic: ToolSearchTool.isEnabled() just calls isToolSearchEnabledOptimistic() (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:304-313), which only rules out the definitely-off cases: standard mode, or — when ENABLE_TOOL_SEARCH is unset — a first-party provider whose ANTHROPIC_BASE_URL points at a non-Anthropic proxy, since such proxies typically reject tool_reference blocks; setting any non-empty value overrides this heuristic (claude-code/src/utils/toolSearch.ts:270-320). The mode itself maps ENABLE_TOOL_SEARCH to 'tst' | 'tst-auto' | 'standard' — auto/auto:1-99 → tst-auto, true/auto:0 → tst, false/auto:100 → standard, unset → tst — with CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS acting as a kill switch that forces standard (claude-code/src/utils/toolSearch.ts:172-198). The same kill switch also strips defer_loading (and every other non-allowlisted beta field) at the one choke point all tool schemas pass through, so no beta shape reaches the wire (claude-code/src/utils/api.ts:232-243).
The definitive per-request check, isToolSearchEnabled, layers three more gates: the model must support tool_reference — a negative test defaulting to ['haiku'], live-overridable via the GrowthBook feature tengu_tool_search_unsupported_models (claude-code/src/utils/toolSearch.ts:204,239-252,419-426); ToolSearchTool must actually be in the tool list, respecting disallowedTools (claude-code/src/utils/toolSearch.ts:429-435); and finally the mode switch, where tst-auto additionally measures total deferred-tool description size against a threshold (claude-code/src/utils/toolSearch.ts:437-473). The query path in claude.ts runs this check per request (claude-code/src/services/api/claude.ts:1120-1126), precomputes the deferred name set once (claude-code/src/services/api/claude.ts:1128-1134), and disables tool search when there is nothing to defer and no MCP servers are still connecting (claude-code/src/services/api/claude.ts:1139-1148).
Request assembly. With tool search on, filteredTools keeps every non-deferred tool, always keeps ToolSearch, and keeps a deferred tool only if it appears in extractDiscoveredToolNames(messages) (claude-code/src/services/api/claude.ts:1154-1172) — the code comments that this "removes limits on tool quantity" because deferred tools no longer need to be predeclared upfront (claude-code/src/services/api/claude.ts:1155-1157). A provider-specific beta header is pushed (Bedrock routes it through body params instead) (claude-code/src/services/api/claude.ts:1177-1182). Each surviving tool is serialized via toolToAPISchema(tool, { deferLoading: willDefer(tool), ... }) (claude-code/src/services/api/claude.ts:1232-1246), which sets schema.defer_loading = true (claude-code/src/utils/api.ts:223-226). One subtlety: the full tools list — not filteredTools — is passed into schema generation, so ToolSearch's own prompt can describe all MCP tools even though only discovered ones are actually sent (claude-code/src/services/api/claude.ts:1232-1234).
Two announcement channels. How the model learns the deferred names depends on isDeferredToolsDeltaEnabled() — USER_TYPE === 'ant' or the GrowthBook flag tengu_glacier_2xr (claude-code/src/utils/toolSearch.ts:629-634). With the flag off, claude.ts prepends an ephemeral meta user message wrapping the sorted name list in <available-deferred-tools> tags on every call (claude-code/src/services/api/claude.ts:1330-1345). With it on, getDeferredToolsDeltaAttachment emits a persisted deferred_tools_delta attachment instead (claude-code/src/utils/attachments.ts:1455-1475), rendered to the model as a system-reminder listing newly available and newly removed tools (claude-code/src/utils/messages.ts:4178-4193). The delta is computed by replaying all prior delta attachments to reconstruct the announced set, then diffing against the current pool — and a tool that was announced but has since stopped being deferred, yet is still in the pool, is deliberately not reported as removed, because it's now loaded directly and "no longer available" would be a lie (claude-code/src/utils/toolSearch.ts:646-706). Each announced line is just the tool name; searchHint is intentionally omitted after an A/B test showed no benefit (claude-code/src/tools/ToolSearchTool/prompt.ts:110-117). ToolSearch's own prompt duplicates the delta gate by hand to tell the model where the names appear, and carries a comment that it must stay in sync (claude-code/src/tools/ToolSearchTool/prompt.ts:35-42).
The search itself. call() recomputes deferredTools = tools.filter(isDeferredTool) and invalidates a description cache memoized by tool name whenever the deferred name-set changes (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:328-332,66-105). A select: query is comma-split and each name resolved with findToolByName — which matches primary names or aliases (claude-code/src/Tool.ts:348-360) — against the deferred set first, then the full set; missing names are tolerated, and selecting an already-loaded tool is a designed no-op that "lets the model proceed without retry churn" (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:358-406). Keyword queries go through searchToolsWithKeywords: an exact-name fast path over deferred then full tools (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:199-204), an mcp__ prefix branch for server-name queries (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:208-216), a +term partition where +-prefixed terms are required and pre-filter the candidates (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:218-257), and finally scoring: exact name-part match scores 10 (12 for MCP), substring 5 (6 for MCP), full-name fallback 3, a word-boundary hit in searchHint 4, and in the tool description 2 (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:266-301). Names are decomposed by parseToolName, which splits mcp__server__action on underscores and regular tool names on CamelCase (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:132-161). An empty result includes pending_mcp_servers (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:37-47,335-339) so the model knows to retry once servers finish connecting.
Delivering and keeping tools live. Matches are mapped into a tool_result whose content is a list of { type: 'tool_reference', tool_name } blocks — cast through as unknown as ToolResultBlockParam because tool_reference is a beta content type absent from the SDK types (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:444-470). The API expands these into real definitions, but the next request is rebuilt from scratch — so extractDiscoveredToolNames re-scans the message history for tool_result → tool_reference blocks each turn to decide which deferred tools stay in filteredTools (claude-code/src/utils/toolSearch.ts:545-592). Compaction would destroy that evidence (the summary preserves no tool_reference blocks), so the compactor snapshots the discovered set onto the boundary marker's compactMetadata.preCompactDiscoveredTools (claude-code/src/services/compact/compact.ts:605-610), and the scanner reads it back from any compact-boundary message it encounters (claude-code/src/utils/toolSearch.ts:553-560).
Why it matters
Context economy at scale. MCP servers can contribute hundreds of tools, each with a description and JSON schema. Deferral means the initial prompt carries a name list instead of full schemas, and the model pays the schema cost only for tools it actually fetches — which is exactly why the code notes this "eliminates the need to predeclare all deferred tools upfront and removes limits on tool quantity" (claude-code/src/services/api/claude.ts:1155-1157).
Prompt-cache friendliness. The two announcement channels exist because the ephemeral <available-deferred-tools> prepend "busts cache whenever the pool changes"; the persisted delta attachment only appends increments (claude-code/src/services/api/claude.ts:1327-1330; claude-code/src/utils/toolSearch.ts:624-634).
Defensive engineering against a beta wire format. Because defer_loading and tool_reference are beta API shapes, the harness hedges at every layer: proxies that would 400 on tool_reference are heuristically detected (claude-code/src/utils/toolSearch.ts:282-311), the kill switch strips beta fields at a single choke point (claude-code/src/utils/api.ts:232-243), unsupported models like Haiku are excluded by a live-updatable negative list (claude-code/src/utils/toolSearch.ts:204,239-252), and select: on an already-loaded tool is a graceful no-op precisely because subagents and post-compaction turns were observed doing it (claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:194-204,358-362).
A reusable pattern. The shape — announce names cheaply, retrieve schemas on demand, persist discovery in the transcript, carry it across compaction — is the harness's general recipe for making an unbounded resource pool fit a bounded context window.
Read the source
Suggested order:
- claude-code/src/tools/ToolSearchTool/prompt.ts — start with
isDeferredTool(prompt.ts:62-108) to see exactly what gets deferred, then the tool's own prompt text and the hand-synced location hint (prompt.ts:35-51,110-121). - claude-code/src/utils/toolSearch.ts — the mode mapping (172-198), model support (239-252), optimistic vs. definitive gates (270-320, 385-473), the discovery scan (545-592), and the delta diff (629-706).
- claude-code/src/services/api/claude.ts:1118-1182,1232-1246,1330-1345 — the per-request assembly: gate,
deferredToolNames,filteredTools, beta header, schema serialization, and the ephemeral announcement. - claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts — schemas (21-47), the description cache (66-105), name parsing and scoring (132-161, 186-302),
call()with theselect:branch (328-434), and thetool_referenceresult mapping (444-470). - claude-code/src/utils/api.ts:69-78,215-243 — how
defer_loadingreaches the wire, and how the kill switch strips it. - claude-code/src/utils/attachments.ts:1455-1475, claude-code/src/utils/messages.ts:4178-4193, claude-code/src/services/compact/compact.ts:605-610 — the persisted announcement channel and compaction survival.
来源 · Source citations
- [1]
claude-code/src/tools/ToolSearchTool/constants.ts:1 - [2]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:21-34 - [3]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:37-47 - [4]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:66-105 - [5]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:132-161 - [6]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:186-302 - [7]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:199-204 - [8]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:208-216 - [9]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:218-257 - [10]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:266-301 - [11]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:304-313 - [12]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:328-332 - [13]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:335-339 - [14]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:358-406 - [15]
claude-code/src/tools/ToolSearchTool/ToolSearchTool.ts:444-470 - [16]
claude-code/src/tools/ToolSearchTool/prompt.ts:35-42 - [17]
claude-code/src/tools/ToolSearchTool/prompt.ts:62-108 - [18]
claude-code/src/tools/ToolSearchTool/prompt.ts:110-117 - [19]
claude-code/src/utils/toolSearch.ts:161 - [20]
claude-code/src/utils/toolSearch.ts:172-198 - [21]
claude-code/src/utils/toolSearch.ts:181-183 - [22]
claude-code/src/utils/toolSearch.ts:204 - [23]
claude-code/src/utils/toolSearch.ts:239-252 - [24]
claude-code/src/utils/toolSearch.ts:270-320 - [25]
claude-code/src/utils/toolSearch.ts:299-311 - [26]
claude-code/src/utils/toolSearch.ts:385-473 - [27]
claude-code/src/utils/toolSearch.ts:429-435 - [28]
claude-code/src/utils/toolSearch.ts:545-592 - [29]
claude-code/src/utils/toolSearch.ts:553-560 - [30]
claude-code/src/utils/toolSearch.ts:594-599 - [31]
claude-code/src/utils/toolSearch.ts:629-634 - [32]
claude-code/src/utils/toolSearch.ts:646-706 - [33]
claude-code/src/services/api/claude.ts:1120-1126 - [34]
claude-code/src/services/api/claude.ts:1128-1148 - [35]
claude-code/src/services/api/claude.ts:1154-1172 - [36]
claude-code/src/services/api/claude.ts:1155-1157 - [37]
claude-code/src/services/api/claude.ts:1177-1182 - [38]
claude-code/src/services/api/claude.ts:1232-1246 - [39]
claude-code/src/services/api/claude.ts:1327-1330 - [40]
claude-code/src/services/api/claude.ts:1330-1345 - [41]
claude-code/src/utils/api.ts:69-78 - [42]
claude-code/src/utils/api.ts:223-226 - [43]
claude-code/src/utils/api.ts:232-243 - [44]
claude-code/src/utils/attachments.ts:1455-1475 - [45]
claude-code/src/utils/messages.ts:4178-4193 - [46]
claude-code/src/Tool.ts:348-360 - [47]
claude-code/src/Tool.ts:378 - [48]
claude-code/src/Tool.ts:436 - [49]
claude-code/src/Tool.ts:442 - [50]
claude-code/src/Tool.ts:449 - [51]
claude-code/src/services/compact/compact.ts:605-610