@tokensapi/dsh-progressive-tools 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,225 @@
1
+ # Architecture
2
+
3
+ ## Goals and invariants
4
+
5
+ The default architecture has four invariants:
6
+
7
+ 1. The first AgentLoop request already carries the small surface.
8
+ 2. Discovery never changes the top-level tool list or generated SDK.
9
+ 3. Deferred calls still traverse the complete DSH execution pipeline.
10
+ 4. A caller cannot bypass discovery by naming a hidden tool directly.
11
+
12
+ The plugin uses only public Harness APIs and extension points:
13
+
14
+ - `ctx.systemPrompt.section()` for stable discovery guidance;
15
+ - `system-prompt/assemble` for the authoritative request projection;
16
+ - `ctx.tools.register()` for search and dispatch;
17
+ - `ctx.tools.guard()` for monotonic routing enforcement;
18
+ - `ctx.tools.execute()` for nested real-tool execution;
19
+ - `tools/result` for authoritative discovery commits;
20
+ - `tools/change` for in-process catalog invalidation;
21
+ - `agent/session-start` and durable session events for state initialization;
22
+ - `agent/disposed` and Cordis effects for cleanup.
23
+
24
+ ## The DSH lifecycle boundary
25
+
26
+ DSH assembles prompt sections and tool schemas before `agent/pre-step`:
27
+
28
+ ```text
29
+ claim inbox input
30
+
31
+
32
+ systemPrompt.assemble()
33
+
34
+ ├── collect sections and tools
35
+ └── system-prompt/assemble waterfall
36
+
37
+
38
+ agent/pre-step
39
+
40
+
41
+ LLM request
42
+ ```
43
+
44
+ Version 0.1.0 installed a restriction in `agent/pre-step`, so it could affect
45
+ only the following assembly. Version 0.2.0 performs the authoritative
46
+ projection in `system-prompt/assemble`, after all providers have contributed
47
+ but before AgentLoop stores or sends the request.
48
+
49
+ `agent/session-start` eagerly initializes the catalog for normal creation and
50
+ resume. The assembly hook remains authoritative and also covers hot reload,
51
+ late registration, and callers that assemble without a normal startup event.
52
+
53
+ ## Stable-proxy mode
54
+
55
+ ### Request projection
56
+
57
+ On the first assembly for one agent, the plugin freezes that session's stable
58
+ name set:
59
+
60
+ - `tool_search`;
61
+ - `tool_dispatch`;
62
+ - registered names matching `alwaysVisible`;
63
+ - the reserved `run_code` transport when DSH exposes it.
64
+
65
+ The Tokens distribution defaults `alwaysVisible` to the common file, shell,
66
+ Skill, task, interaction, and file-return tools used on nearly every product
67
+ session. This keeps routine work direct while deferring plugin-specific and
68
+ low-frequency schemas.
69
+
70
+ The complete registry remains visible to in-process code. The assembly
71
+ waterfall filters only the final `PromptAssembly.tools` projection. In Code
72
+ Mode and `both` mode, the `tools:sdk` section is regenerated from the same
73
+ stable names, preserving one coherent presentation.
74
+
75
+ `deferToolGuidance` conservatively removes a section only when its name is an
76
+ exact hidden-tool guidance slot (`tool:<name>` or `tool:<name>:...`). General
77
+ guidance and sections that cannot be mapped safely remain untouched.
78
+
79
+ The stable name set does not grow after first assembly. A later registry change
80
+ refreshes only the searchable catalog, so installing a new deferred tool does
81
+ not silently change an active session's cache prefix.
82
+
83
+ ### Discovery
84
+
85
+ The catalog stores detached model-facing definitions in process memory. Search
86
+ operates on individual tools, not whole families. A searchable document
87
+ contains:
88
+
89
+ - tool name and description;
90
+ - nested parameter keys, descriptions, constants, and enums;
91
+ - configured family ID, description, and aliases.
92
+
93
+ Ranking combines exact-name and contained-label bonuses with a deterministic
94
+ BM25-style lexical score. CJK text is additionally tokenized into character
95
+ bigrams, so queries without space-delimited words can match definitions and
96
+ family metadata without configured aliases. Search returns at most
97
+ `maxResults` exact definitions; larger `max_results` requests are clamped.
98
+ Those definitions enter the ordinary tool result and therefore extend history
99
+ append-only.
100
+
101
+ Each match also lists every member name of its family (`groupTools`), and the
102
+ whole family becomes discovered in the same call. One query therefore opens a
103
+ plugin's complete tool surface even when only its top-ranked members carry
104
+ full schemas; the remaining siblings dispatch by name and validate against
105
+ their original definitions, or can be schema-loaded first with one exact-name
106
+ search.
107
+
108
+ The `status` action lists every deferred family with its member tool names, so
109
+ the model can browse the catalog when a search query has no lexical overlap.
110
+ By default the listing is browse-only; `statusGrantsDiscovery` optionally
111
+ turns it into a catalog-wide discovery grant.
112
+
113
+ Successful `tools/result` observation commits the returned names to the
114
+ agent's discovered set. Failed or invalid searches do not mutate live state.
115
+
116
+ ### Dispatch
117
+
118
+ `tool_dispatch` accepts an exact discovered name and one JSON object of
119
+ arguments. It then calls the ordinary registry:
120
+
121
+ ```text
122
+ tool_dispatch root execution
123
+
124
+ ├── check catalog membership and discovery state
125
+ ├── preserve agent, rootCallId, signal, and arguments
126
+ └── ctx.tools.execute(real tool, parent = dispatcher token)
127
+
128
+ ├── pre-execute / approval
129
+ ├── monotonic guards
130
+ ├── timeout and retry wrappers
131
+ ├── original schema validation and body
132
+ ├── post-execute and finalization
133
+ └── tools/result
134
+ ```
135
+
136
+ Nested contexts and a successful turn-conclusion marker are ferried back to
137
+ the outer result. The outer rendering uses the real tool's finalized content,
138
+ including non-text blocks. A nested failure is rethrown with the real tool's
139
+ structured error code preserved, and the dispatcher delegates its
140
+ parallel-scheduling classification to the target tool's own declaration, so
141
+ concurrency-safe deferred tools keep overlapping with sibling calls.
142
+
143
+ ### Routing guard
144
+
145
+ Prompt filtering alone does not change registry lookup. Stable mode therefore
146
+ registers a monotonic guard:
147
+
148
+ - stable direct names are allowed;
149
+ - deferred direct names are denied;
150
+ - a nested execution whose parent token belongs to `tool_dispatch` is allowed;
151
+ - descendants of that authorized nested execution inherit the authorization
152
+ for the duration of their execution tree.
153
+
154
+ Tokens are registry-minted opaque identities, so a caller cannot manufacture
155
+ the parent capability. Authorized tokens are removed on result and plugin
156
+ cleanup. The guard prepares the agent's state on demand, so a call that
157
+ arrives before the first assembly or session-start event is still classified
158
+ against the deferred catalog instead of passing through unexamined.
159
+
160
+ The guard is not an authorization boundary for the underlying capability. It
161
+ enforces presentation-to-dispatch alignment while existing approval, sandbox,
162
+ and policy layers continue to own security decisions.
163
+
164
+ ## Cache behavior
165
+
166
+ For an unchanged session composition:
167
+
168
+ ```text
169
+ request 1: stable tools + stable system + user history
170
+ request 2: stable tools + stable system + prior history + search result
171
+ request 3: stable tools + stable system + prior history + dispatch result
172
+ ```
173
+
174
+ Only history grows. The tool/system prefix remains byte-identical. The
175
+ AgentLoop integration test captures actual `GenerateOptions` values and asserts
176
+ both the first request surface and post-search equality.
177
+
178
+ A real composition change can still alter the prefix: changing plugin config,
179
+ removing a stable tool, changing its definition, or replacing another system
180
+ section is outside the discovery invariant.
181
+
182
+ ## Resume behavior
183
+
184
+ Discovery state is recorded asymmetrically. The rendered search result — the
185
+ text the model reads and re-reads in history — carries only the names newly
186
+ discovered by that call, so conversation growth stays bounded no matter how
187
+ much has been discovered. The result's presentation metadata, which never
188
+ reaches the model, carries the cumulative discovered list and the action kind.
189
+
190
+ On resume the plugin replays successful search results and skill bindings,
191
+ preferring the cumulative metadata when present and unioning per-call
192
+ increments otherwise. The metadata path restores full state from the latest
193
+ surviving entry even when older events were compacted. Nested Code Mode calls
194
+ have no top-level presentation metadata, so their standard
195
+ `tool/code-dispatch` content increments are folded instead. A replayed
196
+ `status` result also restores the catalog-listing grant used by
197
+ `statusGrantsDiscovery`.
198
+
199
+ The plugin introduces no custom session event vocabulary. Discovered names
200
+ survive registry refreshes such as provider reconnects; dispatch validates
201
+ catalog membership at call time, so a stale name fails the individual call
202
+ without losing the rest of the discovery state.
203
+
204
+ ## Dynamic compatibility mode
205
+
206
+ `mode: dynamic` retains the v0.1 family activation design for deployments that
207
+ need provider-native definitions after search. Its lifecycle is corrected:
208
+
209
+ - initial restriction is installed at `agent/session-start`;
210
+ - turn expiry is reconciled at `agent/inbox/claimed`;
211
+ - successful search and skill results reinstall the restriction immediately;
212
+ - the assembly waterfall filters the already-collected current assembly and
213
+ regenerates Code Mode SDK text from the same visible set.
214
+
215
+ This mode aligns presentation, lookup, and execution through
216
+ `agent.ctx.tools.restrict()`, but changing families changes the tool prefix and
217
+ can reduce cache reuse. It cannot hide tools registered in the exact agent
218
+ scope because scoped restrictions intentionally preserve scope-local tools.
219
+
220
+ ## Cleanup
221
+
222
+ Tool registrations, the prompt section, assembly listener, guard, and event
223
+ listeners are Cordis-owned effects. Agent disposal removes its state and lifts
224
+ any dynamic restriction. Plugin unload lifts all remaining restrictions and
225
+ clears authorization tokens before its registered tools disappear.
@@ -0,0 +1,238 @@
1
+ # Configuration reference
2
+
3
+ Configuration is validated when the plugin loads. Invalid modes, names,
4
+ limits, duplicate family IDs, empty patterns, and bindings to unknown families
5
+ fail loudly.
6
+
7
+ ## Options
8
+
9
+ | Option | Type | Default | Meaning |
10
+ | --- | --- | --- | --- |
11
+ | `mode` | `stable-proxy` \| `dynamic` | `stable-proxy` | Cache-stable dispatch or changing native family activation. |
12
+ | `toolName` | string | `tool_search` | Discovery tool name. |
13
+ | `dispatchToolName` | string | `tool_dispatch` | Stable dispatcher name. Must differ from `toolName`. |
14
+ | `alwaysVisible` | string[] | essential direct tools | Exact names or `*` patterns kept on the fixed direct surface. |
15
+ | `groups` | group[] | built-in rules | Ordered search and dynamic activation families; first match wins. |
16
+ | `skillBindings` | binding[] | `[]` | Successful Skill calls that discover or activate named families. |
17
+ | `maxResults` | integer | `5` | Maximum exact definitions returned by stable search, or group matches in dynamic mode. Caller `max_results` values outside `1..maxResults` are clamped, not rejected. |
18
+ | `requireDiscovery` | boolean | `true` | Require a search hit, a family-wide discovery, or a Skill binding before stable dispatch. |
19
+ | `statusGrantsDiscovery` | boolean | `false` | Let one `status` listing make every cataloged name dispatchable. Off by default so dispatch always follows a seen schema. |
20
+ | `deferToolGuidance` | boolean | `true` | Remove exact hidden `tool:<name>` prompt sections. |
21
+ | `activationGroupLimit` | integer | `1` | Dynamic mode: highest-ranked families activated by one search. |
22
+ | `maxActiveGroups` | integer | `3` | Dynamic mode: maximum retained active families. |
23
+ | `maxActiveToolTokens` | integer | `6000` | Dynamic mode: approximate active-schema budget. |
24
+ | `retentionTurns` | integer | `6` | Dynamic mode: inactive turns before expiry; `0` disables expiry. |
25
+ | `charactersPerToken` | integer | `4` | Compact schema characters represented by one estimate token. |
26
+
27
+ `activationGroupLimit` cannot exceed `maxActiveGroups`. Dynamic-only fields are
28
+ still validated in stable mode so switching modes cannot reveal a latent bad
29
+ configuration.
30
+
31
+ ## Stable direct tools
32
+
33
+ The default patterns are:
34
+
35
+ ```yaml
36
+ alwaysVisible:
37
+ - read
38
+ - write
39
+ - edit
40
+ - glob
41
+ - grep
42
+ - bash
43
+ - skill
44
+ - ask_user_question
45
+ - todo_write
46
+ - dsh_im_return_file
47
+ - report
48
+ - submit_*
49
+ - structured_output*
50
+ ```
51
+
52
+ `tool_search` and `tool_dispatch` are added automatically. A matching tool must
53
+ exist when the first assembly freezes the session surface. Tools registered
54
+ later enter the deferred catalog even when their names match an
55
+ `alwaysVisible` wildcard; this keeps the active session prefix stable. A new
56
+ session sees the new composition.
57
+
58
+ Keep this list small. Add only tools whose direct schema or completion role is
59
+ worth paying on every request.
60
+
61
+ ## Wildcards
62
+
63
+ `alwaysVisible`, `groups[].include`, and `groups[].exclude` use anchored `*`
64
+ wildcards over complete tool names. Every other character is matched literally.
65
+ Matching is case-insensitive.
66
+
67
+ ```yaml
68
+ alwaysVisible:
69
+ - approval_*
70
+ - submit_*
71
+ ```
72
+
73
+ ## Family rules
74
+
75
+ ```yaml
76
+ groups:
77
+ - id: browser
78
+ description: Browser navigation and page interaction
79
+ aliases: [browser, web page, 浏览器]
80
+ include: [browser_*]
81
+ exclude: [browser_experimental_*]
82
+ ```
83
+
84
+ Rules are evaluated in list order. A tool belongs to at most one configured
85
+ family. Unmatched tools are grouped by the first underscore-delimited prefix
86
+ when at least two share it; otherwise each tool receives a singleton family.
87
+ Generic verb prefixes (`get`, `set`, `list`, `create`, `delete`, `update`,
88
+ `add`, `remove`, `cancel`, `run`, `start`, `stop`, `send`, `read`, `write`,
89
+ `new`, `check`) never merge, because unrelated plugins routinely share them;
90
+ such tools stay singleton families unless a configured rule claims them.
91
+
92
+ In stable mode, family metadata improves exact-tool search, the result
93
+ contains the highest-ranked individual definitions, and each match lists every
94
+ member name of its family so siblings become dispatchable from one query. In
95
+ dynamic mode, the highest-ranked whole family becomes natively visible.
96
+ Because family membership now also widens discovery, a wrong rule no longer
97
+ just skews ranking — it unlocks unrelated names. Keep custom rules precise.
98
+
99
+ The built-in order covers browser, vision, image generation, filesystem,
100
+ terminal, web, database, remote operations, memory, workbench, teams,
101
+ subagents, workflows, and generated interfaces. Explicit rules are recommended
102
+ when third-party packages use unrelated names for one capability.
103
+
104
+ ## Skill bindings
105
+
106
+ Bindings inspect the `name` or `skill` argument of a successful tool named
107
+ `skill`:
108
+
109
+ ```yaml
110
+ skillBindings:
111
+ - skill: browser-automation
112
+ groups: [browser]
113
+ - skill: database-operations
114
+ groups: [database]
115
+ ```
116
+
117
+ Stable mode marks bound tools as dispatchable. The Skill instructions should
118
+ describe the tools and their arguments; otherwise call `tool_search` to load
119
+ the exact definitions into history. Dynamic mode activates the bound native
120
+ families under its normal cap, budget, and LRU rules.
121
+
122
+ ## Discovery gate
123
+
124
+ With `requireDiscovery: true`, `tool_dispatch` accepts names that were matched
125
+ by a successful search, listed as a family sibling of a match, or introduced
126
+ through a Skill binding. This catches guessed or stale tool names before
127
+ nested execution.
128
+
129
+ A `status` listing is browse-only by default: it shows every family and member
130
+ name but does not unlock dispatch, so the model must load a schema before
131
+ calling. The rejection message points to the deterministic recovery — search
132
+ the exact name once (exact matches always rank first) and dispatch. Set
133
+ `statusGrantsDiscovery: true` to let one status call unlock the whole catalog;
134
+ this trades away the seen-schema guarantee, so reserve it for deployments with
135
+ approval layers or read-only tool surfaces.
136
+
137
+ Set `requireDiscovery: false` only when another trusted catalog supplies exact
138
+ names and schemas. Direct calls to deferred names remain denied; they must
139
+ still pass through `tool_dispatch`.
140
+
141
+ ## Guidance deferral
142
+
143
+ `deferToolGuidance: true` removes only sections whose names map exactly to a
144
+ deferred tool:
145
+
146
+ ```text
147
+ tool:<deferred-name>
148
+ tool:<deferred-name>:<suffix>
149
+ ```
150
+
151
+ It does not guess package ownership or delete general sections. This avoids
152
+ silently removing unrelated policy text. A tool package that registers one
153
+ shared family section should move large operational instructions into a Skill
154
+ or keep the section always visible.
155
+
156
+ ## Onboarding an existing plugin ecosystem
157
+
158
+ Three configuration moves cover most friction when this plugin fronts an
159
+ already-installed tool ecosystem:
160
+
161
+ 1. Add high-frequency small tools to `alwaysVisible`. Anything the model calls
162
+ nearly every turn (todo updates, reporting) should not pay the
163
+ search-then-dispatch round trip.
164
+ 2. Bind plugin-shipped Skills with `skillBindings`. Loading a Skill should make
165
+ its tools dispatchable in the same turn; without a binding the model still
166
+ needs one search after the Skill call.
167
+ 3. Write explicit `groups` rules, with multilingual aliases, for packages whose
168
+ tool names do not follow common prefixes. This fixes automatic-group
169
+ scatter, improves family search recall, and keeps family-wide discovery
170
+ from unlocking strangers.
171
+
172
+ ## Token estimates
173
+
174
+ The estimate for one tool is:
175
+
176
+ ```text
177
+ ceil(JSON.stringify(schema).length / charactersPerToken)
178
+ ```
179
+
180
+ It is deterministic diagnostic data, not provider billing. In stable mode,
181
+ `estimatedSavedTokens` is the complete deferred catalog estimate because none
182
+ of those definitions appears in the top-level request. Search results add only
183
+ the matched definitions to history.
184
+
185
+ ## Dynamic-mode budgets
186
+
187
+ When a dynamic activation exceeds `maxActiveGroups` or
188
+ `maxActiveToolTokens`, the least recently used unprotected family is removed
189
+ first. Families activated by the current search are protected for that
190
+ operation. A requested family that alone exceeds the budget remains active and
191
+ reports the over-budget estimate.
192
+
193
+ Dynamic mode changes the request tool set on activation, eviction, and expiry.
194
+ Prefer stable mode when context-cache reuse is important.
195
+
196
+ ## Full stable example
197
+
198
+ ```yaml
199
+ - id: tokens-progressive-tools
200
+ config:
201
+ mode: stable-proxy
202
+ toolName: tool_search
203
+ dispatchToolName: tool_dispatch
204
+ maxResults: 5
205
+ requireDiscovery: true
206
+ statusGrantsDiscovery: false
207
+ deferToolGuidance: true
208
+ alwaysVisible: [read, write, edit, glob, grep, bash, skill, ask_user_question, todo_write, dsh_im_return_file, report, submit_*, structured_output*]
209
+ groups:
210
+ - id: browser
211
+ description: Browser navigation and page interaction
212
+ aliases: [browser, web page, 浏览器]
213
+ include: [browser_*]
214
+ - id: database
215
+ description: Database inspection and queries
216
+ aliases: [database, sql, 数据库]
217
+ include: [db_*, sql_*]
218
+ skillBindings:
219
+ - skill: browser-automation
220
+ groups: [browser]
221
+ ```
222
+
223
+ ## v0.1 migration
224
+
225
+ Version 0.2 defaults to `stable-proxy`, so a prior configuration now returns
226
+ exact definitions and uses `tool_dispatch` instead of exposing a native family.
227
+
228
+ To retain v0.1 call semantics while taking the lifecycle fixes:
229
+
230
+ ```yaml
231
+ - id: tokens-progressive-tools
232
+ config:
233
+ mode: dynamic
234
+ ```
235
+
236
+ Dynamic mode now affects the first request and makes a successful search
237
+ visible on the immediately following request, but it remains intentionally
238
+ cache-hostile when the active family set changes.
@@ -0,0 +1,82 @@
1
+ # Progressive disclosure model
2
+
3
+ This plugin separates two related mechanisms that are often conflated:
4
+
5
+ - Agent Skills progressively load instructions and resources.
6
+ - Tool discovery progressively loads callable schemas.
7
+
8
+ DeepSeek Harness already owns the first mechanism. This plugin supplies a
9
+ cache-stable fallback for the second where the provider protocol has no native
10
+ deferred-tool content blocks.
11
+
12
+ ## Skills layers
13
+
14
+ The open Agent Skills format defines three disclosure levels:
15
+
16
+ | Level | Session-visible material | Load boundary |
17
+ | --- | --- | --- |
18
+ | Metadata | `name` and `description` | Skill catalog publication |
19
+ | Instructions | Complete `SKILL.md` body | `skill` activation |
20
+ | Resources | Referenced scripts, files, and assets | Explicit need |
21
+
22
+ DSH's Skills subsystem already publishes a compact name/description catalog,
23
+ loads the complete body through the `skill` tool, and resolves resources only
24
+ when needed. The plugin does not duplicate or replace that subsystem.
25
+
26
+ References:
27
+
28
+ - [Agent Skills specification](https://github.com/agentskills/agentskills/blob/main/docs/specification.mdx)
29
+ - [DSH Skills subsystem](https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/skills)
30
+
31
+ ## Tool layers
32
+
33
+ Stable proxy mode implements an analogous three-level tool path:
34
+
35
+ | Level | Session-visible material | Load boundary |
36
+ | --- | --- | --- |
37
+ | Discovery entry | `tool_search`, `tool_dispatch`, common direct tools | First request |
38
+ | Exact definitions | Matching names, descriptions, and parameter schemas | `tool_search` result |
39
+ | Execution | Original tool body and result | `tool_dispatch` nested call |
40
+
41
+ The complete catalog and real executors stay in process memory. Only exact
42
+ matches enter conversation history, but each match also names every sibling in
43
+ its family, so one search opens a plugin's whole dispatchable surface. The
44
+ `status` action browses the complete family catalog when no lexical query
45
+ fits; by default it informs without unlocking dispatch.
46
+
47
+ ## Native deferred tools versus stable proxy
48
+
49
+ A provider-native deferred-tool protocol can receive all definitions out of
50
+ band, initially render only non-deferred tools, and later return typed tool
51
+ references without changing its cache prefix. DSH's current generic
52
+ `ToolSchema` contains only `name`, `description`, and `parameters`; the DeepSeek
53
+ Chat Completions tool protocol also has no equivalent deferred-reference block.
54
+
55
+ Stable proxy therefore keeps two generic schemas fixed and performs real-tool
56
+ validation at dispatch time. This preserves prefix stability and ordinary DSH
57
+ policy, with two explicit trade-offs:
58
+
59
+ - the outer request has no provider-native grammar for a deferred tool;
60
+ - discovery and execution are separate calls.
61
+
62
+ When DSH adds provider capability negotiation and native deferred references,
63
+ a future native mode can use those features without changing the stable proxy
64
+ fallback.
65
+
66
+ References:
67
+
68
+ - [DSH tool subsystem](https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/tools)
69
+ - [DeepSeek Chat Completions](https://api-docs.deepseek.com/api/create-chat-completion/)
70
+
71
+ ## Cache contract
72
+
73
+ The stable request prefix is:
74
+
75
+ ```text
76
+ fixed tool schemas → fixed system sections → append-only message history
77
+ ```
78
+
79
+ Discovery adds one tool result after the reusable prefix. It does not change
80
+ the fixed schemas or the generated Code Mode SDK. This is the central
81
+ difference from `dynamic` mode, whose native family activation intentionally
82
+ changes the request header.
@@ -0,0 +1,12 @@
1
+ import type { DeferredToolMatch, SearchMatch, ToolCatalog, ToolGroupConfig, ToolSchemaView } from './types.js';
2
+ export declare function matchesToolName(name: string, patterns: readonly string[]): boolean;
3
+ export declare function estimateSchemaTokens(schema: ToolSchemaView, charactersPerToken: number): number;
4
+ export declare function buildCatalog(schemas: readonly ToolSchemaView[], configuredGroups: readonly ToolGroupConfig[], charactersPerToken: number, excludedNames?: ReadonlySet<string>): ToolCatalog;
5
+ export declare function searchCatalog(catalog: ToolCatalog, query: string, limit: number): SearchMatch[];
6
+ /**
7
+ * Rank individual tools with exact-name bonuses and a compact BM25-style score.
8
+ * Definitions, parameter descriptions, enums, and nested property names all
9
+ * participate in the searchable document.
10
+ */
11
+ export declare function searchTools(catalog: ToolCatalog, query: string, limit: number): DeferredToolMatch[];
12
+ export declare function matchingToolNames(catalog: ToolCatalog, patterns: readonly string[]): string[];