@jianxx/dsh-cc-tool-search 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.
- package/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +42 -0
- package/README.zh.md +41 -0
- package/lib/index.d.ts +141 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +297 -0
- package/lib/index.js.map +1 -0
- package/lib/invariant.d.ts +16 -0
- package/lib/invariant.d.ts.map +1 -0
- package/lib/invariant.js +24 -0
- package/lib/invariant.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/core/tool-search/README.md
|
|
5
|
+
README.md: 3d64b50c6a37ccb683d786ecba7618f888b9015e
|
|
6
|
+
README.zh.md: d347ab0bedf02e7c16a9cd8e98f949263448e550
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# dsh-tool-search
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Deferred tool registration plus a model-facing **ToolSearch** tool that loads heavy tools on demand. A tool that is expensive to load or token-heavy in the prompt can be registered **deferred**: it contributes a name, description, and search hint to a searchable registry, but its real definition stays **out of the model-visible schema and prompt** until the model asks for it.
|
|
6
|
+
|
|
7
|
+
## Why defer tools
|
|
8
|
+
|
|
9
|
+
Every visible tool schema costs prompt tokens and, for a heavy capability, load time. Most sessions need only a handful of tools from a large catalog. Deferral carries the *capability metadata* cheaply and loads the material definition only when the model actually summons it — generalizing the `shouldDefer`/ToolSearch mechanism (and the MCP `_meta['anthropic/alwaysLoad']` escape hatch) into the harness's effect-based registry model.
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
[`DeferredToolRegistry`](src/index.ts) is the `ctx.toolSearch` service. A plugin registers a capability deferred:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
ctx.toolSearch.registerDeferred({
|
|
17
|
+
name: 'big_fs_tool',
|
|
18
|
+
description: 'Heavy filesystem capability invoked once per session.',
|
|
19
|
+
searchHint: 'read write edit files',
|
|
20
|
+
alwaysLoad: false,
|
|
21
|
+
activate: () => ctx.tools.register(bigFsToolDefinition), // returns the exact disposer
|
|
22
|
+
})
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The **ToolSearch** model tool then ranks the deferred set against a `query` (`max_results`, default 5) using weighted substring/token matching over name, `searchHint`, and description. On a hit it calls the registration's `activate()` callback — a real `ctx.tools.register()` — so the tool becomes visible to the **next** assembly and then callable exactly like any top-of-prompt tool. `alwaysLoad: true` registers immediately at defer time and is never a deferred candidate.
|
|
26
|
+
|
|
27
|
+
The design rides the repo's effect conventions:
|
|
28
|
+
|
|
29
|
+
- **Deferred registration is an effect.** The returned disposer reclaims the deferred entry *and* any activated `ctx.tools` registration together, so a plugin unloading mid-session tears down both.
|
|
30
|
+
- **Activation is idempotent.** Re-activating an already-loaded tool is a no-op; re-registration (which would throw on a duplicate name) never happens.
|
|
31
|
+
- **Restriction stays authoritative.** `registerDeferred` reserves the tool's name in the `dsh-tools` registry (known but not visible), so a scoped `restrict()` can deny it *before* it loads. ToolSearch checks that gate: a deferred tool a scope denies is **not** activated for that scope, and the result says why.
|
|
32
|
+
- **Search is scope-visible.** A deferred registration lands in the calling scope's layer, and ToolSearch searches the *calling agent's* scope chain (itself and ancestors) — so a tool an agent deferred is visible to that agent's search and its descendants, but a sibling scope or the global view never sees it. A globally-deferred tool remains globally visible as before.
|
|
33
|
+
- **Deferred names never leak into the prompt.** Only activated (`alwaysLoad` or loaded) tools enter the schema; reserved-but-unloaded names are known for restriction/`toolOrder` purposes but never model-visible.
|
|
34
|
+
|
|
35
|
+
## Model Experience
|
|
36
|
+
|
|
37
|
+
Turn one, the model sees only `ToolSearch` plus whatever is already loaded (including `alwaysLoad` tools). It searches for a capability by keywords, and the result names the now-available tools. On the next turn those tools are first-class: declare them, call them. Already-loaded tools drop out of the deferred set, so a second search for them is correctly empty.
|
|
38
|
+
|
|
39
|
+
## Known Limitations and Deferred Work
|
|
40
|
+
|
|
41
|
+
- **Matching is lexical, not semantic.** Ranking uses weighted substring/token scoring; there is no embedding/vector search. This keeps the seam dependency-free and deterministic, at the cost of synonyms that share no token.
|
|
42
|
+
- **Global activation.** Loading happens on the host plane (global registration); a per-agent scope sees a loaded tool only if its restriction admits it. There is no per-conversation discovery history — loading is an in-memory effect, so a re-registered composition starts from the deferred pool again.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# dsh-tool-search
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
延迟工具注册,外加一个模型可见的 **ToolSearch** 工具,按需加载重工具。一个加载成本高、或提示词里占用 token 很多的工具,可以**延迟**注册:它只贡献名字、描述和搜索提示到这个可搜索的注册表,真正的定义在模型主动索要之前始终**不进模型可见的 schema 与提示词**。
|
|
6
|
+
|
|
7
|
+
## 为什么要延迟工具
|
|
8
|
+
|
|
9
|
+
每一个可见的工具 schema 都要花提示词 token,重工具还要花加载时间。大多数会话只需要一个大目录里的一小部分工具。延迟机制以很低的成本携带*能力元数据*,只有当模型真正召唤时才加载实体定义——把 `shouldDefer`/ToolSearch 机制(以及 MCP 的 `_meta['anthropic/alwaysLoad']` 逃生舱)泛化进本仓基于 effect 的注册表模型。
|
|
10
|
+
|
|
11
|
+
## 它做什么
|
|
12
|
+
|
|
13
|
+
[`DeferredToolRegistry`](src/index.ts) 就是 `ctx.toolSearch` 服务。插件可以这样延迟注册一个能力:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
ctx.toolSearch.registerDeferred({
|
|
17
|
+
name: 'big_fs_tool',
|
|
18
|
+
description: 'Heavy filesystem capability invoked once per session.',
|
|
19
|
+
searchHint: 'read write edit files',
|
|
20
|
+
alwaysLoad: false,
|
|
21
|
+
activate: () => ctx.tools.register(bigFsToolDefinition), // returns the exact disposer
|
|
22
|
+
})
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**ToolSearch** 模型工具随后针对 `query`(`max_results`,默认 5)对延迟集合做排序——在名字、`searchHint`、描述上做加权的子串/词元匹配。命中后就调用该注册的 `activate()` 回调——一次真实的 `ctx.tools.register()`——于是该工具在**下一轮**组装中变得可见,此后与任何提示词顶部的工具无异地被调用。`alwaysLoad: true` 在延迟之时立即注册,且永远不会成为延迟候选。
|
|
26
|
+
|
|
27
|
+
这套设计贴合本仓的 effect 约定:
|
|
28
|
+
|
|
29
|
+
- **延迟注册本身就是 effect。** 返回的 disposer 会连同回收延迟条目*以及*任何已激活的 `ctx.tools` 注册,因此插件在会话中途卸载时,两者一起被拆除。
|
|
30
|
+
- **激活是幂等的。** 再次激活一个已加载的工具是空操作;重复注册(否则会因重名而抛错)绝不会发生。
|
|
31
|
+
- **限制仍然优先。** `registerDeferred` 会在 `dsh-tools` 注册表里预留这个工具名(已知但不可见),因此局部的 `restrict()` 可以在它*加载前*将其拒绝。ToolSearch 会检查这道闸:被某个作用域拒绝的延迟工具,绝不会为该作用域激活,结果里会说明原因。
|
|
32
|
+
- **延迟名字永不泄漏进提示词。** 只有已激活(`alwaysLoad` 或已加载)的工具才进 schema;被预留而未加载的名字仅用于限制/`toolOrder` 判定,不对外可见。
|
|
33
|
+
|
|
34
|
+
## 模型体验
|
|
35
|
+
|
|
36
|
+
第一轮,模型只看到 `ToolSearch` 加已加载的(包括 `alwaysLoad` 的)工具。它按关键字搜索某个能力,结果里点名现在可用哪些工具。下一轮这些工具就成头等公民:声明它们,调用它们。已加载的工具会退出延迟集合,因此再次搜索它们会正确地得到空结果。
|
|
37
|
+
|
|
38
|
+
## 已知限制与暂缓事项
|
|
39
|
+
|
|
40
|
+
- **匹配是词法而非语义的。** 排序用加权的子串/词元打分;没有嵌入/向量检索。这让接缝保持零依赖且确定,代价是无法命中不共享词元的同义词。
|
|
41
|
+
- **全局激活。** 加载发生在宿主平面(全局注册);某个 per-agent 作用域只有在它的限制放行时才能看到已加载的工具。没有按会话的记忆历史——加载是内存里的 effect,因此重新组装后又会从延迟池重新开始。
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deferred tool registration and the model-facing ToolSearch tool that loads
|
|
3
|
+
* heavy tools on demand.
|
|
4
|
+
*
|
|
5
|
+
* A tool that is expensive to load or token-heavy in the prompt can register
|
|
6
|
+
* DEFERRED: it contributes name + description + search hint to a registry the
|
|
7
|
+
* model can search, but its real definition stays out of the model-visible
|
|
8
|
+
* schema and prompt until the model asks for it. The ToolSearch tool ranks the
|
|
9
|
+
* deferred set against a query and, on a hit, runs the deferred registration's
|
|
10
|
+
* activation callback — which performs the real `ctx.tools.register()`. Because
|
|
11
|
+
* registration is an effect, the tool becomes visible to the NEXT assembly and
|
|
12
|
+
* lives exactly as long as its owning plugin fiber.
|
|
13
|
+
*
|
|
14
|
+
* The design generalizes the `shouldDefer`/ToolSearch mechanism (and the MCP
|
|
15
|
+
* `anthropic/alwaysLoad` escape hatch) into the harness's effect-based registry
|
|
16
|
+
* model: {@link DeferredToolRegistry.registerDeferred} is itself an effect, and
|
|
17
|
+
* {@link registry.activate} gate the load behind the calling scope's tool
|
|
18
|
+
* restriction, so a deferred tool a scope denies is never loaded for it.
|
|
19
|
+
* @module @jianxx/dsh-cc-tool-search
|
|
20
|
+
*/
|
|
21
|
+
import { Context, Service } from '@deepseek-ai/cordis';
|
|
22
|
+
import type { ScopeKey } from '@deepseek-ai/dsh-scope';
|
|
23
|
+
/** The model-facing ToolSearch tool name. */
|
|
24
|
+
export declare const TOOL_SEARCH_NAME = "ToolSearch";
|
|
25
|
+
/** A deferred registration: capability metadata before its heavy definition loads. */
|
|
26
|
+
export interface DeferredToolRegistration {
|
|
27
|
+
/** The eventual registered tool name, unique within one deferred registry layer. */
|
|
28
|
+
readonly name: string;
|
|
29
|
+
/** The model-facing description, shown in the ToolSearch result and later the tool schema. */
|
|
30
|
+
readonly description: string;
|
|
31
|
+
/** A short capability phrase for keyword matching; prefer terms not in the name. */
|
|
32
|
+
readonly searchHint?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Escape hatch that never defers: `true` activates the tool immediately at
|
|
35
|
+
* registration, generalizing MCP's `_meta['anthropic/alwaysLoad']`. An
|
|
36
|
+
* `alwaysLoad` tool is registered and model-visible from the start and is
|
|
37
|
+
* never a ToolSearch candidate.
|
|
38
|
+
*/
|
|
39
|
+
readonly alwaysLoad?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Perform the real registration. Called at most once (the first admitting
|
|
42
|
+
* ToolSearch hit, or immediately for an {@link DeferredToolRegistration.alwaysLoad}
|
|
43
|
+
* tool). Must register a definition on `ctx.tools` and return that exact
|
|
44
|
+
* disposer, so the tool unloads with the deferred entry.
|
|
45
|
+
*/
|
|
46
|
+
readonly activate: () => () => void;
|
|
47
|
+
}
|
|
48
|
+
/** One ranked deferred-tool match returned by a ToolSearch query. */
|
|
49
|
+
export interface DeferredSearchHit {
|
|
50
|
+
/** The deferred tool name. */
|
|
51
|
+
readonly name: string;
|
|
52
|
+
/** The deferred tool description. */
|
|
53
|
+
readonly description: string;
|
|
54
|
+
/** The deferred tool's optional search hint. */
|
|
55
|
+
readonly searchHint?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Result of attempting to load one deferred tool for a scope. */
|
|
58
|
+
export type DeferredActivationResult = {
|
|
59
|
+
readonly status: 'loaded';
|
|
60
|
+
readonly name: string;
|
|
61
|
+
} | {
|
|
62
|
+
readonly status: 'already-loaded';
|
|
63
|
+
readonly name: string;
|
|
64
|
+
} | {
|
|
65
|
+
readonly status: 'denied';
|
|
66
|
+
readonly name: string;
|
|
67
|
+
readonly reason: string;
|
|
68
|
+
} | {
|
|
69
|
+
readonly status: 'unknown';
|
|
70
|
+
readonly name: string;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Deferred tool registry and the ToolSearch tool.
|
|
74
|
+
*
|
|
75
|
+
* Deferred registrations are host-plane effects: they land in the calling
|
|
76
|
+
* context's scope layer and unwind with it. The tool itself (registered on the
|
|
77
|
+
* `tools` row) lets a model search the deferred set and load a hit — gated by
|
|
78
|
+
* the calling agent's tool restriction, so a deferred tool a scope denies is
|
|
79
|
+
* never loaded for it.
|
|
80
|
+
*/
|
|
81
|
+
export declare class DeferredToolRegistry extends Service {
|
|
82
|
+
static inject: string[];
|
|
83
|
+
private readonly layers;
|
|
84
|
+
constructor(ctx: Context);
|
|
85
|
+
/**
|
|
86
|
+
* Register a deferred capability. The name+description (+hint) are searchable
|
|
87
|
+
* but invisible until activated; an {@link DeferredToolRegistration.alwaysLoad}
|
|
88
|
+
* tool activates immediately for everyone. Registration is an effect: the
|
|
89
|
+
* returned disposer removes the deferred entry and, if it was activated, its
|
|
90
|
+
* real `ctx.tools` registration together.
|
|
91
|
+
* @param reg - the deferred descriptor and activation callback.
|
|
92
|
+
* @returns the exact disposer that reclaims both the deferred entry and any loaded tool.
|
|
93
|
+
*/
|
|
94
|
+
registerDeferred(reg: DeferredToolRegistration): () => void;
|
|
95
|
+
/**
|
|
96
|
+
* Rank the deferred, not-yet-loaded tools against a query, searching the scope
|
|
97
|
+
* chain the caller lives in. Returns the top `maxResults` accessible
|
|
98
|
+
* candidates in descending relevance. This is the pure matching step; loading
|
|
99
|
+
* (and its restriction gate) happens in {@link DeferredToolRegistry.activate}.
|
|
100
|
+
* @param query - free-text keyword query.
|
|
101
|
+
* @param maxResults - how many hits to return (default 5).
|
|
102
|
+
* @param scope - the calling scope whose deferred set (and its ancestors') is
|
|
103
|
+
* searched; defaults to this registry's own scope ([`scopeOf`]) on the
|
|
104
|
+
* service context, which is global for a global registry.
|
|
105
|
+
* @returns ranked, scored matches that are still deferred.
|
|
106
|
+
*/
|
|
107
|
+
search(query: string, maxResults?: number, scope?: ScopeKey): DeferredSearchHit[];
|
|
108
|
+
/**
|
|
109
|
+
* Load one deferred tool for a scope, idempotently. A hit that the scope's
|
|
110
|
+
* tool restriction denies is NOT loaded (guard semantics take priority over
|
|
111
|
+
* ToolSearch, so the loading gate is not an end-run around `restrict()`); an
|
|
112
|
+
* already-loaded or `alwaysLoad` tool reports `already-loaded` without
|
|
113
|
+
* re-registering; an absent name reports `unknown`.
|
|
114
|
+
* @param name - the deferred tool name.
|
|
115
|
+
* @param scope - the calling agent scope whose restriction gates the load.
|
|
116
|
+
* @returns the load outcome for the model-facing result.
|
|
117
|
+
*/
|
|
118
|
+
activate(name: string, scope?: ScopeKey): DeferredActivationResult;
|
|
119
|
+
/**
|
|
120
|
+
* Every deferred entry in scope order (global then the scope chain nearest
|
|
121
|
+
* last) for the calling scope. A caller with no explicit scope searches the
|
|
122
|
+
* registry's own scope: a global registry resolves to the global layer
|
|
123
|
+
* (`scopeOf(this.ctx)` is `undefined` on an unscoped service context), while
|
|
124
|
+
* a registry hosted under a scoped preset backs a child scope so its deferred
|
|
125
|
+
* set — and its ancestors' — stays visible to it.
|
|
126
|
+
*/
|
|
127
|
+
private allDeferred;
|
|
128
|
+
/** Run the entry's activation callback once and retain its disposer. */
|
|
129
|
+
private activateStore;
|
|
130
|
+
/** Tear down an activated tool's real registration, if any. */
|
|
131
|
+
private deactivateStore;
|
|
132
|
+
/** The model-facing ToolSearch tool, registered once at construction. */
|
|
133
|
+
private toolDefinition;
|
|
134
|
+
}
|
|
135
|
+
declare module '@deepseek-ai/cordis' {
|
|
136
|
+
interface Context {
|
|
137
|
+
toolSearch: DeferredToolRegistry;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export default DeferredToolRegistry;
|
|
141
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAEtD,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,wBAAwB,CAAA;AAMlE,6CAA6C;AAC7C,eAAO,MAAM,gBAAgB,eAAe,CAAA;AAE5C,sFAAsF;AACtF,MAAM,WAAW,wBAAwB;IACvC,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,8FAA8F;IAC9F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,oFAAoF;IACpF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,MAAM,IAAI,CAAA;CACpC;AAED,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qCAAqC;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,gDAAgD;IAChD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED,kEAAkE;AAClE,MAAM,MAAM,wBAAwB,GAChC;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7E;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AA2DzD;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,SAAQ,OAAO;IAC/C,MAAM,CAAC,MAAM,WAAY;IAEzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAKtB;gBAEW,GAAG,EAAE,OAAO;IAOxB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,GAAG,EAAE,wBAAwB,GAAG,MAAM,IAAI;IA4B3D;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,GAAE,MAAU,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,iBAAiB,EAAE;IAepF;;;;;;;;;OASG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,GAAG,wBAAwB;IAelE;;;;;;;OAOG;IACH,OAAO,CAAC,WAAW;IAKnB,wEAAwE;IACxE,OAAO,CAAC,aAAa;IAQrB,+DAA+D;IAC/D,OAAO,CAAC,eAAe;IAQvB,yEAAyE;IACzE,OAAO,CAAC,cAAc;CAyEvB;AAqBD,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,UAAU,EAAE,oBAAoB,CAAA;KACjC;CACF;AAED,eAAe,oBAAoB,CAAA"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deferred tool registration and the model-facing ToolSearch tool that loads
|
|
3
|
+
* heavy tools on demand.
|
|
4
|
+
*
|
|
5
|
+
* A tool that is expensive to load or token-heavy in the prompt can register
|
|
6
|
+
* DEFERRED: it contributes name + description + search hint to a registry the
|
|
7
|
+
* model can search, but its real definition stays out of the model-visible
|
|
8
|
+
* schema and prompt until the model asks for it. The ToolSearch tool ranks the
|
|
9
|
+
* deferred set against a query and, on a hit, runs the deferred registration's
|
|
10
|
+
* activation callback — which performs the real `ctx.tools.register()`. Because
|
|
11
|
+
* registration is an effect, the tool becomes visible to the NEXT assembly and
|
|
12
|
+
* lives exactly as long as its owning plugin fiber.
|
|
13
|
+
*
|
|
14
|
+
* The design generalizes the `shouldDefer`/ToolSearch mechanism (and the MCP
|
|
15
|
+
* `anthropic/alwaysLoad` escape hatch) into the harness's effect-based registry
|
|
16
|
+
* model: {@link DeferredToolRegistry.registerDeferred} is itself an effect, and
|
|
17
|
+
* {@link registry.activate} gate the load behind the calling scope's tool
|
|
18
|
+
* restriction, so a deferred tool a scope denies is never loaded for it.
|
|
19
|
+
* @module @jianxx/dsh-cc-tool-search
|
|
20
|
+
*/
|
|
21
|
+
import { Service } from '@deepseek-ai/cordis';
|
|
22
|
+
import { NamedEntries, ScopedLayers, scopeOf } from '@deepseek-ai/dsh-scope';
|
|
23
|
+
import { defineTool } from '@jianxx/dsh-cc-tools';
|
|
24
|
+
/** The model-facing ToolSearch tool name. */
|
|
25
|
+
export const TOOL_SEARCH_NAME = 'ToolSearch';
|
|
26
|
+
/** One scope's aggregate deferred-tool registration. */
|
|
27
|
+
class DeferredLayer {
|
|
28
|
+
tools = new NamedEntries(name => new Error(`tool "${name}" is already registered as deferred in this scope`));
|
|
29
|
+
isEmpty() {
|
|
30
|
+
return this.tools.isEmpty();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* How much a deferred tool matches a query, summed over query tokens and the
|
|
35
|
+
* weighted name/description/searchHint fields. `name` carries the most weight,
|
|
36
|
+
* `searchHint` next, then `description`; an exact name match is conclusive.
|
|
37
|
+
* Pure and deterministic: used only to rank the candidate set.
|
|
38
|
+
* @param stored - the deferred registration.
|
|
39
|
+
* @param query - the raw ToolSearch query.
|
|
40
|
+
* @returns a non-negative score; `0` means no match.
|
|
41
|
+
*/
|
|
42
|
+
function scoreStored(stored, query) {
|
|
43
|
+
const q = query.toLowerCase().trim();
|
|
44
|
+
if (q.length === 0)
|
|
45
|
+
return 0;
|
|
46
|
+
const qTokens = tokenize(q);
|
|
47
|
+
const fields = [
|
|
48
|
+
[stored.reg.name.toLowerCase(), 10],
|
|
49
|
+
[(stored.reg.searchHint ?? '').toLowerCase(), 4],
|
|
50
|
+
[stored.reg.description.toLowerCase(), 2],
|
|
51
|
+
];
|
|
52
|
+
let total = 0;
|
|
53
|
+
for (const [text, weight] of fields) {
|
|
54
|
+
if (text.length === 0)
|
|
55
|
+
continue;
|
|
56
|
+
for (const token of qTokens) {
|
|
57
|
+
if (token.length === 0)
|
|
58
|
+
continue;
|
|
59
|
+
if (text.includes(token)) {
|
|
60
|
+
total += weight;
|
|
61
|
+
}
|
|
62
|
+
else if (tokenize(text).some(word => word.startsWith(token) || token.startsWith(word))) {
|
|
63
|
+
total += Math.max(1, Math.floor(weight / 2));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return total;
|
|
68
|
+
}
|
|
69
|
+
/** Lowercase the input and split into alphanumeric tokens, dropping empty ones. */
|
|
70
|
+
function tokenize(value) {
|
|
71
|
+
return value.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Deferred tool registry and the ToolSearch tool.
|
|
75
|
+
*
|
|
76
|
+
* Deferred registrations are host-plane effects: they land in the calling
|
|
77
|
+
* context's scope layer and unwind with it. The tool itself (registered on the
|
|
78
|
+
* `tools` row) lets a model search the deferred set and load a hit — gated by
|
|
79
|
+
* the calling agent's tool restriction, so a deferred tool a scope denies is
|
|
80
|
+
* never loaded for it.
|
|
81
|
+
*/
|
|
82
|
+
export class DeferredToolRegistry extends Service {
|
|
83
|
+
static inject = ['tools'];
|
|
84
|
+
layers = new ScopedLayers(() => new DeferredLayer(),
|
|
85
|
+
// Deferred-set changes are not model-visible (deferred tools never enter
|
|
86
|
+
// the prompt); actual activations fire `tools/change` through `register()`.
|
|
87
|
+
() => { });
|
|
88
|
+
constructor(ctx) {
|
|
89
|
+
super(ctx, 'toolSearch');
|
|
90
|
+
// The ToolSearch tool itself is never deferred: it is the load path, so it
|
|
91
|
+
// must be visible on the first assembly.
|
|
92
|
+
ctx.tools.register(this.toolDefinition());
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Register a deferred capability. The name+description (+hint) are searchable
|
|
96
|
+
* but invisible until activated; an {@link DeferredToolRegistration.alwaysLoad}
|
|
97
|
+
* tool activates immediately for everyone. Registration is an effect: the
|
|
98
|
+
* returned disposer removes the deferred entry and, if it was activated, its
|
|
99
|
+
* real `ctx.tools` registration together.
|
|
100
|
+
* @param reg - the deferred descriptor and activation callback.
|
|
101
|
+
* @returns the exact disposer that reclaims both the deferred entry and any loaded tool.
|
|
102
|
+
*/
|
|
103
|
+
registerDeferred(reg) {
|
|
104
|
+
const stored = {
|
|
105
|
+
reg,
|
|
106
|
+
alwaysLoad: reg.alwaysLoad === true,
|
|
107
|
+
activated: false,
|
|
108
|
+
disposer: undefined,
|
|
109
|
+
};
|
|
110
|
+
const unwind = this.layers.effect(this.ctx, (layer) => {
|
|
111
|
+
const undo = layer.tools.insert(reg.name, stored);
|
|
112
|
+
if (stored.alwaysLoad)
|
|
113
|
+
this.activateStore(stored);
|
|
114
|
+
return () => {
|
|
115
|
+
undo();
|
|
116
|
+
this.deactivateStore(stored);
|
|
117
|
+
};
|
|
118
|
+
}, { label: 'toolSearch.registerDeferred()' });
|
|
119
|
+
// Reserve the name in the tools registry so a scoped restriction can gate
|
|
120
|
+
// it before its definition loads (restrict only names known capabilities).
|
|
121
|
+
const reserve = this.ctx.tools.reserve(reg.name);
|
|
122
|
+
return () => {
|
|
123
|
+
unwind();
|
|
124
|
+
reserve();
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Rank the deferred, not-yet-loaded tools against a query, searching the scope
|
|
129
|
+
* chain the caller lives in. Returns the top `maxResults` accessible
|
|
130
|
+
* candidates in descending relevance. This is the pure matching step; loading
|
|
131
|
+
* (and its restriction gate) happens in {@link DeferredToolRegistry.activate}.
|
|
132
|
+
* @param query - free-text keyword query.
|
|
133
|
+
* @param maxResults - how many hits to return (default 5).
|
|
134
|
+
* @param scope - the calling scope whose deferred set (and its ancestors') is
|
|
135
|
+
* searched; defaults to this registry's own scope ([`scopeOf`]) on the
|
|
136
|
+
* service context, which is global for a global registry.
|
|
137
|
+
* @returns ranked, scored matches that are still deferred.
|
|
138
|
+
*/
|
|
139
|
+
search(query, maxResults = 5, scope) {
|
|
140
|
+
const candidates = [];
|
|
141
|
+
for (const stored of this.allDeferred(scope)) {
|
|
142
|
+
if (stored.alwaysLoad || stored.activated)
|
|
143
|
+
continue;
|
|
144
|
+
const score = scoreStored(stored, query);
|
|
145
|
+
if (score > 0)
|
|
146
|
+
candidates.push({ stored, score });
|
|
147
|
+
}
|
|
148
|
+
candidates.sort((a, b) => b.score - a.score || a.stored.reg.name.localeCompare(b.stored.reg.name));
|
|
149
|
+
return candidates.slice(0, maxResults).map(({ stored }) => ({
|
|
150
|
+
name: stored.reg.name,
|
|
151
|
+
description: stored.reg.description,
|
|
152
|
+
...stored.reg.searchHint !== undefined ? { searchHint: stored.reg.searchHint } : {},
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Load one deferred tool for a scope, idempotently. A hit that the scope's
|
|
157
|
+
* tool restriction denies is NOT loaded (guard semantics take priority over
|
|
158
|
+
* ToolSearch, so the loading gate is not an end-run around `restrict()`); an
|
|
159
|
+
* already-loaded or `alwaysLoad` tool reports `already-loaded` without
|
|
160
|
+
* re-registering; an absent name reports `unknown`.
|
|
161
|
+
* @param name - the deferred tool name.
|
|
162
|
+
* @param scope - the calling agent scope whose restriction gates the load.
|
|
163
|
+
* @returns the load outcome for the model-facing result.
|
|
164
|
+
*/
|
|
165
|
+
activate(name, scope) {
|
|
166
|
+
const stored = this.allDeferred(scope).find(candidate => candidate.reg.name === name);
|
|
167
|
+
if (stored === undefined) {
|
|
168
|
+
return { status: 'unknown', name };
|
|
169
|
+
}
|
|
170
|
+
if (stored.alwaysLoad || stored.activated) {
|
|
171
|
+
return { status: 'already-loaded', name };
|
|
172
|
+
}
|
|
173
|
+
if (!this.ctx.tools.isAdmitted(name, scope)) {
|
|
174
|
+
return { status: 'denied', name, reason: `"${name}" is restricted for this agent; loading it would be refused` };
|
|
175
|
+
}
|
|
176
|
+
this.activateStore(stored);
|
|
177
|
+
return { status: 'loaded', name };
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Every deferred entry in scope order (global then the scope chain nearest
|
|
181
|
+
* last) for the calling scope. A caller with no explicit scope searches the
|
|
182
|
+
* registry's own scope: a global registry resolves to the global layer
|
|
183
|
+
* (`scopeOf(this.ctx)` is `undefined` on an unscoped service context), while
|
|
184
|
+
* a registry hosted under a scoped preset backs a child scope so its deferred
|
|
185
|
+
* set — and its ancestors' — stays visible to it.
|
|
186
|
+
*/
|
|
187
|
+
allDeferred(scope) {
|
|
188
|
+
const key = scope ?? scopeOf(this.ctx) ?? undefined;
|
|
189
|
+
return [...this.layers.merge(key, layer => layer.tools).values()];
|
|
190
|
+
}
|
|
191
|
+
/** Run the entry's activation callback once and retain its disposer. */
|
|
192
|
+
activateStore(stored) {
|
|
193
|
+
if (stored.activated)
|
|
194
|
+
return;
|
|
195
|
+
// The callback performs `ctx.tools.register(...)` and returns that exact
|
|
196
|
+
// disposer, so unloading the deferred entry also unregisters the tool.
|
|
197
|
+
stored.disposer = stored.reg.activate();
|
|
198
|
+
stored.activated = true;
|
|
199
|
+
}
|
|
200
|
+
/** Tear down an activated tool's real registration, if any. */
|
|
201
|
+
deactivateStore(stored) {
|
|
202
|
+
if (stored.activated) {
|
|
203
|
+
stored.disposer?.();
|
|
204
|
+
stored.disposer = undefined;
|
|
205
|
+
stored.activated = false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** The model-facing ToolSearch tool, registered once at construction. */
|
|
209
|
+
toolDefinition() {
|
|
210
|
+
return defineTool({
|
|
211
|
+
name: TOOL_SEARCH_NAME,
|
|
212
|
+
description: 'Search for deferred tools that are NOT currently loaded, then load the ones you need by their name. '
|
|
213
|
+
+ 'Deferred tools are capabilities (e.g. filesystem, shell, or web tools) omitted from your function list to save prompt '
|
|
214
|
+
+ 'space. Search with the capability you need; loading a tool makes it available to call exactly like any tool defined at '
|
|
215
|
+
+ 'the top of the prompt. Loading is idempotent: loading an already-available tool is a harmless no-op.',
|
|
216
|
+
parameters: {
|
|
217
|
+
query: {
|
|
218
|
+
type: 'string',
|
|
219
|
+
required: true,
|
|
220
|
+
description: 'The capability or tool to find, as keywords (e.g. "read file", "edit", "bash").',
|
|
221
|
+
},
|
|
222
|
+
max_results: {
|
|
223
|
+
type: 'number',
|
|
224
|
+
description: 'How many matching deferred tools to evaluate (default 5).',
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
output: {
|
|
228
|
+
schema: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
additionalProperties: false,
|
|
231
|
+
properties: {
|
|
232
|
+
query: { type: 'string', required: true },
|
|
233
|
+
results: {
|
|
234
|
+
type: 'array',
|
|
235
|
+
required: true,
|
|
236
|
+
items: {
|
|
237
|
+
type: 'object',
|
|
238
|
+
additionalProperties: false,
|
|
239
|
+
properties: {
|
|
240
|
+
name: { type: 'string', required: true },
|
|
241
|
+
description: { type: 'string', required: true },
|
|
242
|
+
status: {
|
|
243
|
+
type: 'string',
|
|
244
|
+
required: true,
|
|
245
|
+
enum: ['loaded', 'already-loaded', 'unknown', 'denied'],
|
|
246
|
+
},
|
|
247
|
+
reason: { type: 'string' },
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
render: (_args, value) => [{
|
|
254
|
+
type: 'text',
|
|
255
|
+
text: renderToolSearchText(value.query, value.results),
|
|
256
|
+
}],
|
|
257
|
+
},
|
|
258
|
+
// Arrow bodies keep `this` bound to the registry service; the schema
|
|
259
|
+
// narrows args to match the parameter spec (`query` required, `max_results`
|
|
260
|
+
// optional).
|
|
261
|
+
execute: (args, exec) => {
|
|
262
|
+
const scope = exec.agent;
|
|
263
|
+
const maxResults = args.max_results ?? 5;
|
|
264
|
+
const hits = this.search(args.query, maxResults, scope);
|
|
265
|
+
const results = hits.map((hit) => {
|
|
266
|
+
const outcome = this.activate(hit.name, scope);
|
|
267
|
+
return {
|
|
268
|
+
name: outcome.name,
|
|
269
|
+
description: hit.description,
|
|
270
|
+
status: outcome.status,
|
|
271
|
+
...outcome.status === 'denied' ? { reason: outcome.reason } : {},
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
return Promise.resolve({ query: args.query, results });
|
|
275
|
+
},
|
|
276
|
+
presentCall: (args) => ({ card: 'generic', title: 'Search deferred tools', kind: 'search', rawInput: args.query }),
|
|
277
|
+
presentResult: (_args, result) => ({ card: 'generic', title: 'Tool search', content: result.content }),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/** Compose the model-facing summary of a ToolSearch outcome. */
|
|
282
|
+
function renderToolSearchText(query, results) {
|
|
283
|
+
if (results.length === 0) {
|
|
284
|
+
return `No deferred tools matched "${query}".`;
|
|
285
|
+
}
|
|
286
|
+
const lines = results.map((result) => {
|
|
287
|
+
const statusLabel = result.status === 'loaded' ? 'now available'
|
|
288
|
+
: result.status === 'already-loaded' ? 'already available'
|
|
289
|
+
: result.status === 'denied' ? 'denied'
|
|
290
|
+
: 'not found';
|
|
291
|
+
const tail = result.status === 'denied' && result.reason !== undefined ? ` — ${result.reason}` : '';
|
|
292
|
+
return `- ${result.name}: ${result.description} (${statusLabel})${tail}`;
|
|
293
|
+
});
|
|
294
|
+
return `ToolSearch "${query}":\n${lines.join('\n')}`;
|
|
295
|
+
}
|
|
296
|
+
export default DeferredToolRegistry;
|
|
297
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@jianxx/dsh-cc-tool-search`.
|
|
3
|
+
* @module @jianxx/dsh-cc-tool-search/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "tool-search-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.d.ts","sourceRoot":"","sources":["../src/invariant.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKlD,oCAAoC;AACpC,eAAO,MAAM,IAAI,0BAA0B,CAAA;AAC3C,2EAA2E;AAC3E,eAAO,MAAM,MAAM,UAAiB,CAAA;AAUpC;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAI,KAAK,OAAO,KAAG,OAAO,CAAC,MAAM,IAAI,CACU,CAAA"}
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@jianxx/dsh-cc-tool-search`.
|
|
3
|
+
* @module @jianxx/dsh-cc-tool-search/invariant
|
|
4
|
+
*/
|
|
5
|
+
const PACKAGE_NAME = '@jianxx/dsh-cc-tool-search';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export const name = 'tool-search-invariant';
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export const inject = ['invariants'];
|
|
10
|
+
/**
|
|
11
|
+
* No runtime invariant: this package owns no event or snapshot of its own. The
|
|
12
|
+
* relation it establishes — a deferred tool being loaded into the tool registry
|
|
13
|
+
* after a ToolSearch hit — is the tool registry's to hold, and `dsh-tools`
|
|
14
|
+
* observes registration there through `tools/change`.
|
|
15
|
+
*/
|
|
16
|
+
const install = () => { };
|
|
17
|
+
/**
|
|
18
|
+
* Register this package's invariant companion.
|
|
19
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
20
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
21
|
+
*/
|
|
22
|
+
export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
23
|
+
/* jscpd:ignore-end */
|
|
24
|
+
//# sourceMappingURL=invariant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invariant.js","sourceRoot":"","sources":["../src/invariant.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,YAAY,GAAG,4BAA4B,CAAA;AAEjD,oCAAoC;AACpC,MAAM,CAAC,MAAM,IAAI,GAAG,uBAAuB,CAAA;AAC3C,2EAA2E;AAC3E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,YAAY,CAAC,CAAA;AAEpC;;;;;GAKG;AACH,MAAM,OAAO,GAAuB,GAAG,EAAE,GAAE,CAAC,CAAA;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,GAAY,EAAuB,EAAE,CACzD,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAA;AACjE,sBAAsB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jianxx/dsh-cc-tool-search",
|
|
3
|
+
"description": "Deferred tool registration and a ToolSearch model tool that loads heavy tools on demand",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/jianxx/dsh-cc-plugins.git",
|
|
8
|
+
"directory": "packages/core/tool-search"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./lib/index.d.ts",
|
|
14
|
+
"default": "./lib/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./invariant": {
|
|
17
|
+
"types": "./lib/invariant.d.ts",
|
|
18
|
+
"default": "./lib/invariant.js"
|
|
19
|
+
},
|
|
20
|
+
"./src/*": "./src/*",
|
|
21
|
+
"./package.json": "./package.json"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"lib"
|
|
25
|
+
],
|
|
26
|
+
"license": "Apache-2.0",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@deepseek-ai/dsh-invariants": ">=0.1.1-rc.2",
|
|
29
|
+
"@deepseek-ai/dsh-scope": ">=0.1.1-rc.2",
|
|
30
|
+
"@deepseek-ai/dsh-system-prompt": ">=0.1.1-rc.2",
|
|
31
|
+
"@deepseek-ai/cordis": ">=0.1.1-rc.2",
|
|
32
|
+
"@jianxx/dsh-cc-tools": "^0.1.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@deepseek-ai/dsh-agent": "link:../../../../deepseek-harness/packages/core/agent",
|
|
36
|
+
"@deepseek-ai/dsh-invariants": "link:../../../../deepseek-harness/packages/runtime-diagnostics/invariants",
|
|
37
|
+
"@deepseek-ai/dsh-llm": "link:../../../../deepseek-harness/packages/llm/llm",
|
|
38
|
+
"@deepseek-ai/dsh-scope": "link:../../../../deepseek-harness/packages/core/scope",
|
|
39
|
+
"@deepseek-ai/dsh-session": "link:../../../../deepseek-harness/packages/core/session",
|
|
40
|
+
"@deepseek-ai/dsh-system-prompt": "link:../../../../deepseek-harness/packages/core/system-prompt",
|
|
41
|
+
"@deepseek-ai/cordis": "link:../../../../deepseek-harness/vendor/cordis",
|
|
42
|
+
"@jianxx/dsh-cc-tools": "^0.1.0"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
}
|
|
47
|
+
}
|