@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.
- package/CHANGELOG.md +124 -0
- package/CONTRIBUTING.md +32 -0
- package/LICENSE +22 -0
- package/README.md +246 -0
- package/README.zh-CN.md +216 -0
- package/SECURITY.md +22 -0
- package/THIRD_PARTY_NOTICES.md +8 -0
- package/cordis.patch.yml +3 -0
- package/docs/architecture.md +225 -0
- package/docs/configuration.md +238 -0
- package/docs/progressive-disclosure.md +82 -0
- package/lib/catalog.d.ts +12 -0
- package/lib/catalog.js +267 -0
- package/lib/defaults.d.ts +16 -0
- package/lib/defaults.js +122 -0
- package/lib/index.d.ts +50 -0
- package/lib/index.js +908 -0
- package/lib/state.d.ts +16 -0
- package/lib/state.js +110 -0
- package/lib/types.d.ts +120 -0
- package/lib/types.js +1 -0
- package/package.json +96 -0
package/lib/catalog.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
const WORD_PATTERN = /[\p{L}\p{N}]+/gu;
|
|
2
|
+
function normalize(value) {
|
|
3
|
+
return value
|
|
4
|
+
.replace(/([a-z\d])([A-Z])/g, '$1 $2')
|
|
5
|
+
.replaceAll('_', ' ')
|
|
6
|
+
.replaceAll('-', ' ')
|
|
7
|
+
.toLocaleLowerCase('en-US')
|
|
8
|
+
.match(WORD_PATTERN)
|
|
9
|
+
?.join(' ') ?? '';
|
|
10
|
+
}
|
|
11
|
+
const CJK_RUN_PATTERN = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]+/gu;
|
|
12
|
+
/**
|
|
13
|
+
* CJK text has no space-delimited word boundaries, so whole-phrase tokens
|
|
14
|
+
* would never overlap between queries and definitions. Character bigrams give
|
|
15
|
+
* both sides comparable terms without a segmentation dictionary.
|
|
16
|
+
*/
|
|
17
|
+
function tokens(value) {
|
|
18
|
+
const normalized = normalize(value);
|
|
19
|
+
if (normalized === '')
|
|
20
|
+
return [];
|
|
21
|
+
const result = [];
|
|
22
|
+
for (const token of normalized.split(' ')) {
|
|
23
|
+
result.push(token);
|
|
24
|
+
for (const run of token.match(CJK_RUN_PATTERN) ?? []) {
|
|
25
|
+
for (let index = 0; index + 1 < run.length; index += 1) {
|
|
26
|
+
const bigram = run.slice(index, index + 2);
|
|
27
|
+
if (bigram !== token)
|
|
28
|
+
result.push(bigram);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
function wildcard(pattern) {
|
|
35
|
+
const escaped = pattern.replace(/[|\\{}()[\]^$+?.]/g, String.raw `\$&`);
|
|
36
|
+
return new RegExp(`^${escaped.replaceAll('*', '.*')}$`, 'i');
|
|
37
|
+
}
|
|
38
|
+
export function matchesToolName(name, patterns) {
|
|
39
|
+
return patterns.some(pattern => wildcard(pattern).test(name));
|
|
40
|
+
}
|
|
41
|
+
function parameterKeys(value) {
|
|
42
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
43
|
+
return [];
|
|
44
|
+
const record = value;
|
|
45
|
+
const own = Object.keys(record);
|
|
46
|
+
return [...own, ...Object.values(record).flatMap(parameterKeys)];
|
|
47
|
+
}
|
|
48
|
+
function schemaSearchText(value) {
|
|
49
|
+
if (value === null || typeof value !== 'object')
|
|
50
|
+
return typeof value === 'string' ? value : '';
|
|
51
|
+
if (Array.isArray(value))
|
|
52
|
+
return value.map(schemaSearchText).join(' ');
|
|
53
|
+
return Object.entries(value)
|
|
54
|
+
.flatMap(([key, child]) => [key, schemaSearchText(child)])
|
|
55
|
+
.join(' ');
|
|
56
|
+
}
|
|
57
|
+
export function estimateSchemaTokens(schema, charactersPerToken) {
|
|
58
|
+
return Math.max(1, Math.ceil(JSON.stringify(schema).length / charactersPerToken));
|
|
59
|
+
}
|
|
60
|
+
function createCatalogTool(schema, charactersPerToken) {
|
|
61
|
+
return {
|
|
62
|
+
...schema,
|
|
63
|
+
estimatedTokens: estimateSchemaTokens(schema, charactersPerToken),
|
|
64
|
+
searchText: normalize(`${schema.name} ${schema.description} ${parameterKeys(schema.parameters).join(' ')} ${schemaSearchText(schema.parameters)}`),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function createGroup(id, description, aliases, tools) {
|
|
68
|
+
return {
|
|
69
|
+
id,
|
|
70
|
+
description,
|
|
71
|
+
aliases,
|
|
72
|
+
tools,
|
|
73
|
+
estimatedTokens: tools.reduce((total, tool) => total + tool.estimatedTokens, 0),
|
|
74
|
+
searchText: normalize(`${id} ${description} ${aliases.join(' ')} ${tools.map(tool => tool.searchText).join(' ')}`),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Prefixes shared by unrelated tools across plugins. Merging on them would
|
|
79
|
+
* bundle strangers (get_goal with get_image_generation_task), so these tools
|
|
80
|
+
* stay single-tool groups instead.
|
|
81
|
+
*/
|
|
82
|
+
const GENERIC_AUTO_PREFIXES = new Set([
|
|
83
|
+
'get', 'set', 'list', 'create', 'delete', 'update', 'add', 'remove',
|
|
84
|
+
'cancel', 'run', 'start', 'stop', 'send', 'read', 'write', 'new', 'check',
|
|
85
|
+
]);
|
|
86
|
+
function automaticGroupId(name, prefixCounts) {
|
|
87
|
+
const prefix = name.includes('_') ? name.slice(0, name.indexOf('_')) : name;
|
|
88
|
+
if (GENERIC_AUTO_PREFIXES.has(prefix))
|
|
89
|
+
return name;
|
|
90
|
+
return (prefixCounts.get(prefix) ?? 0) >= 2 ? prefix : name;
|
|
91
|
+
}
|
|
92
|
+
export function buildCatalog(schemas, configuredGroups, charactersPerToken, excludedNames = new Set()) {
|
|
93
|
+
const tools = new Map();
|
|
94
|
+
for (const schema of schemas) {
|
|
95
|
+
if (!excludedNames.has(schema.name))
|
|
96
|
+
tools.set(schema.name, createCatalogTool(schema, charactersPerToken));
|
|
97
|
+
}
|
|
98
|
+
const assigned = new Set();
|
|
99
|
+
const groups = new Map();
|
|
100
|
+
for (const config of configuredGroups) {
|
|
101
|
+
const members = [...tools.values()].filter(tool => !assigned.has(tool.name)
|
|
102
|
+
&& matchesToolName(tool.name, config.include)
|
|
103
|
+
&& !matchesToolName(tool.name, config.exclude ?? []));
|
|
104
|
+
if (members.length === 0)
|
|
105
|
+
continue;
|
|
106
|
+
for (const tool of members)
|
|
107
|
+
assigned.add(tool.name);
|
|
108
|
+
groups.set(config.id, createGroup(config.id, config.description ?? `${config.id} tools`, config.aliases ?? [], members));
|
|
109
|
+
}
|
|
110
|
+
const unassigned = [...tools.values()].filter(tool => !assigned.has(tool.name));
|
|
111
|
+
const prefixCounts = new Map();
|
|
112
|
+
for (const tool of unassigned) {
|
|
113
|
+
const prefix = tool.name.includes('_') ? tool.name.slice(0, tool.name.indexOf('_')) : tool.name;
|
|
114
|
+
prefixCounts.set(prefix, (prefixCounts.get(prefix) ?? 0) + 1);
|
|
115
|
+
}
|
|
116
|
+
const automatic = new Map();
|
|
117
|
+
for (const tool of unassigned) {
|
|
118
|
+
const id = automaticGroupId(tool.name, prefixCounts);
|
|
119
|
+
const bucket = automatic.get(id) ?? [];
|
|
120
|
+
bucket.push(tool);
|
|
121
|
+
automatic.set(id, bucket);
|
|
122
|
+
}
|
|
123
|
+
for (const [id, members] of automatic) {
|
|
124
|
+
const safeId = groups.has(id) ? `auto:${id}` : id;
|
|
125
|
+
groups.set(safeId, createGroup(safeId, members.length > 1 ? `${id} tool family` : members[0].description, [], members));
|
|
126
|
+
}
|
|
127
|
+
const toolToGroup = new Map();
|
|
128
|
+
for (const group of groups.values()) {
|
|
129
|
+
for (const tool of group.tools)
|
|
130
|
+
toolToGroup.set(tool.name, group.id);
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
tools,
|
|
134
|
+
groups,
|
|
135
|
+
toolToGroup,
|
|
136
|
+
totalEstimatedTokens: [...tools.values()].reduce((total, tool) => total + tool.estimatedTokens, 0),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function scoreGroup(group, query) {
|
|
140
|
+
const normalizedQuery = normalize(query);
|
|
141
|
+
if (normalizedQuery === '')
|
|
142
|
+
return 0;
|
|
143
|
+
const queryTokens = tokens(query);
|
|
144
|
+
const labels = [group.id, ...group.aliases, ...group.tools.map(tool => tool.name)]
|
|
145
|
+
.map(normalize)
|
|
146
|
+
.filter(label => label !== '');
|
|
147
|
+
const groupTokens = new Set(tokens(`${group.id} ${group.aliases.join(' ')}`));
|
|
148
|
+
const toolNameTokens = new Set(group.tools.flatMap(tool => tokens(tool.name)));
|
|
149
|
+
const descriptionTokens = new Set(tokens(`${group.description} ${group.tools.map(tool => tool.description).join(' ')}`));
|
|
150
|
+
let score = 0;
|
|
151
|
+
if (normalize(group.id) === normalizedQuery)
|
|
152
|
+
score += 120;
|
|
153
|
+
if (group.aliases.some(alias => normalize(alias) === normalizedQuery))
|
|
154
|
+
score += 110;
|
|
155
|
+
if (group.tools.some(tool => normalize(tool.name) === normalizedQuery))
|
|
156
|
+
score += 100;
|
|
157
|
+
if (labels.some(label => normalizedQuery.includes(label)))
|
|
158
|
+
score += 36;
|
|
159
|
+
if (group.searchText.includes(normalizedQuery))
|
|
160
|
+
score += 24;
|
|
161
|
+
for (const token of queryTokens) {
|
|
162
|
+
if (groupTokens.has(token))
|
|
163
|
+
score += 20;
|
|
164
|
+
if (toolNameTokens.has(token))
|
|
165
|
+
score += 12;
|
|
166
|
+
if (descriptionTokens.has(token))
|
|
167
|
+
score += 4;
|
|
168
|
+
}
|
|
169
|
+
return score;
|
|
170
|
+
}
|
|
171
|
+
export function searchCatalog(catalog, query, limit) {
|
|
172
|
+
return [...catalog.groups.values()]
|
|
173
|
+
.map(group => ({ group, score: scoreGroup(group, query) }))
|
|
174
|
+
.filter(candidate => candidate.score > 0)
|
|
175
|
+
.sort((left, right) => right.score - left.score
|
|
176
|
+
|| left.group.estimatedTokens - right.group.estimatedTokens
|
|
177
|
+
|| left.group.id.localeCompare(right.group.id))
|
|
178
|
+
.slice(0, limit)
|
|
179
|
+
.map(({ group, score }) => ({
|
|
180
|
+
group: group.id,
|
|
181
|
+
description: group.description.slice(0, 180),
|
|
182
|
+
score,
|
|
183
|
+
estimatedTokens: group.estimatedTokens,
|
|
184
|
+
tools: group.tools.map(tool => tool.name),
|
|
185
|
+
}));
|
|
186
|
+
}
|
|
187
|
+
function termFrequency(documentTokens, term) {
|
|
188
|
+
return documentTokens.reduce((count, token) => count + (token === term ? 1 : 0), 0);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Rank individual tools with exact-name bonuses and a compact BM25-style score.
|
|
192
|
+
* Definitions, parameter descriptions, enums, and nested property names all
|
|
193
|
+
* participate in the searchable document.
|
|
194
|
+
*/
|
|
195
|
+
export function searchTools(catalog, query, limit) {
|
|
196
|
+
const normalizedQuery = normalize(query);
|
|
197
|
+
const queryTokens = [...new Set(tokens(query))];
|
|
198
|
+
if (normalizedQuery === '' || queryTokens.length === 0)
|
|
199
|
+
return [];
|
|
200
|
+
const documents = [...catalog.tools.values()].map(tool => ({
|
|
201
|
+
tool,
|
|
202
|
+
group: catalog.groups.get(catalog.toolToGroup.get(tool.name) ?? ''),
|
|
203
|
+
text: '',
|
|
204
|
+
tokens: [],
|
|
205
|
+
}));
|
|
206
|
+
for (const document of documents) {
|
|
207
|
+
const groupText = document.group === undefined
|
|
208
|
+
? ''
|
|
209
|
+
: `${document.group.id} ${document.group.description} ${document.group.aliases.join(' ')}`;
|
|
210
|
+
document.text = normalize(`${document.tool.searchText} ${groupText}`);
|
|
211
|
+
document.tokens = tokens(document.text);
|
|
212
|
+
}
|
|
213
|
+
const averageLength = documents.length === 0
|
|
214
|
+
? 1
|
|
215
|
+
: documents.reduce((total, document) => total + document.tokens.length, 0) / documents.length;
|
|
216
|
+
const k1 = 1.2;
|
|
217
|
+
const b = 0.75;
|
|
218
|
+
return documents
|
|
219
|
+
.map(({ tool, group, text, tokens: documentTokens }) => {
|
|
220
|
+
let score = 0;
|
|
221
|
+
const normalizedName = normalize(tool.name);
|
|
222
|
+
if (normalizedName === normalizedQuery)
|
|
223
|
+
score += 160;
|
|
224
|
+
else if (normalizedName.includes(normalizedQuery))
|
|
225
|
+
score += 48;
|
|
226
|
+
if (text.includes(normalizedQuery))
|
|
227
|
+
score += 20;
|
|
228
|
+
const labels = [group?.id ?? '', ...group?.aliases ?? []]
|
|
229
|
+
.map(normalize)
|
|
230
|
+
.filter(label => label !== '');
|
|
231
|
+
if (labels.some(label => normalizedQuery.includes(label)))
|
|
232
|
+
score += 40;
|
|
233
|
+
for (const term of queryTokens) {
|
|
234
|
+
const frequency = termFrequency(documentTokens, term);
|
|
235
|
+
if (frequency === 0)
|
|
236
|
+
continue;
|
|
237
|
+
const documentFrequency = documents.reduce((count, document) => count + (document.tokens.includes(term) ? 1 : 0), 0);
|
|
238
|
+
const inverseFrequency = Math.log(1 + (documents.length - documentFrequency + 0.5) / (documentFrequency + 0.5));
|
|
239
|
+
const denominator = frequency + k1 * (1 - b + b * documentTokens.length / averageLength);
|
|
240
|
+
score += inverseFrequency * (frequency * (k1 + 1)) / denominator * 10;
|
|
241
|
+
if (tokens(tool.name).includes(term))
|
|
242
|
+
score += 18;
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
tool,
|
|
246
|
+
score,
|
|
247
|
+
group: catalog.toolToGroup.get(tool.name) ?? tool.name,
|
|
248
|
+
};
|
|
249
|
+
})
|
|
250
|
+
.filter(candidate => candidate.score > 0)
|
|
251
|
+
.sort((left, right) => right.score - left.score
|
|
252
|
+
|| left.tool.estimatedTokens - right.tool.estimatedTokens
|
|
253
|
+
|| left.tool.name.localeCompare(right.tool.name))
|
|
254
|
+
.slice(0, limit)
|
|
255
|
+
.map(({ tool, score, group }) => ({
|
|
256
|
+
name: tool.name,
|
|
257
|
+
description: tool.description,
|
|
258
|
+
parameters: tool.parameters,
|
|
259
|
+
group,
|
|
260
|
+
score: Math.round(score * 100) / 100,
|
|
261
|
+
estimatedTokens: tool.estimatedTokens,
|
|
262
|
+
groupTools: catalog.groups.get(group)?.tools.map(member => member.name) ?? [tool.name],
|
|
263
|
+
}));
|
|
264
|
+
}
|
|
265
|
+
export function matchingToolNames(catalog, patterns) {
|
|
266
|
+
return [...catalog.tools.keys()].filter(name => matchesToolName(name, patterns));
|
|
267
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { SkillBindingConfig, ToolGroupConfig } from './types.js';
|
|
2
|
+
export declare const DEFAULT_MODE: "stable-proxy";
|
|
3
|
+
export declare const DEFAULT_TOOL_NAME = "tool_search";
|
|
4
|
+
export declare const DEFAULT_DISPATCH_TOOL_NAME = "tool_dispatch";
|
|
5
|
+
export declare const DEFAULT_MAX_RESULTS = 5;
|
|
6
|
+
export declare const DEFAULT_ACTIVATION_GROUP_LIMIT = 1;
|
|
7
|
+
export declare const DEFAULT_MAX_ACTIVE_GROUPS = 3;
|
|
8
|
+
export declare const DEFAULT_MAX_ACTIVE_TOOL_TOKENS = 6000;
|
|
9
|
+
export declare const DEFAULT_RETENTION_TURNS = 6;
|
|
10
|
+
export declare const DEFAULT_CHARACTERS_PER_TOKEN = 4;
|
|
11
|
+
export declare const DEFAULT_REQUIRE_DISCOVERY = true;
|
|
12
|
+
export declare const DEFAULT_STATUS_GRANTS_DISCOVERY = false;
|
|
13
|
+
export declare const DEFAULT_DEFER_TOOL_GUIDANCE = true;
|
|
14
|
+
export declare const DEFAULT_ALWAYS_VISIBLE: readonly ["skill", "ask_user_question", "read", "write", "edit", "glob", "grep", "bash", "todo_write", "dsh_im_return_file", "report", "submit_*", "structured_output*"];
|
|
15
|
+
export declare const DEFAULT_SKILL_BINDINGS: readonly SkillBindingConfig[];
|
|
16
|
+
export declare const DEFAULT_GROUPS: readonly ToolGroupConfig[];
|
package/lib/defaults.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export const DEFAULT_MODE = 'stable-proxy';
|
|
2
|
+
export const DEFAULT_TOOL_NAME = 'tool_search';
|
|
3
|
+
export const DEFAULT_DISPATCH_TOOL_NAME = 'tool_dispatch';
|
|
4
|
+
export const DEFAULT_MAX_RESULTS = 5;
|
|
5
|
+
export const DEFAULT_ACTIVATION_GROUP_LIMIT = 1;
|
|
6
|
+
export const DEFAULT_MAX_ACTIVE_GROUPS = 3;
|
|
7
|
+
export const DEFAULT_MAX_ACTIVE_TOOL_TOKENS = 6_000;
|
|
8
|
+
export const DEFAULT_RETENTION_TURNS = 6;
|
|
9
|
+
export const DEFAULT_CHARACTERS_PER_TOKEN = 4;
|
|
10
|
+
export const DEFAULT_REQUIRE_DISCOVERY = true;
|
|
11
|
+
export const DEFAULT_STATUS_GRANTS_DISCOVERY = false;
|
|
12
|
+
export const DEFAULT_DEFER_TOOL_GUIDANCE = true;
|
|
13
|
+
export const DEFAULT_ALWAYS_VISIBLE = [
|
|
14
|
+
'skill',
|
|
15
|
+
'ask_user_question',
|
|
16
|
+
'read',
|
|
17
|
+
'write',
|
|
18
|
+
'edit',
|
|
19
|
+
'glob',
|
|
20
|
+
'grep',
|
|
21
|
+
'bash',
|
|
22
|
+
'todo_write',
|
|
23
|
+
'dsh_im_return_file',
|
|
24
|
+
'report',
|
|
25
|
+
'submit_*',
|
|
26
|
+
'structured_output*',
|
|
27
|
+
];
|
|
28
|
+
export const DEFAULT_SKILL_BINDINGS = [];
|
|
29
|
+
export const DEFAULT_GROUPS = [
|
|
30
|
+
{
|
|
31
|
+
id: 'browser',
|
|
32
|
+
description: 'Interactive browser navigation, page inspection, clicks, forms, screenshots, and tabs.',
|
|
33
|
+
aliases: ['browser', 'web page', '网页', '浏览器'],
|
|
34
|
+
include: ['browser_*', 'navigate', 'click', 'screenshot', 'computer_*'],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'vision',
|
|
38
|
+
description: 'Image understanding, OCR, comparison, annotation, and visual routing.',
|
|
39
|
+
aliases: ['vision', 'image analysis', '图片', '视觉', '识图'],
|
|
40
|
+
include: ['vision_*', 'ocr*', 'analyze_image*', 'compare_image*', 'describe_image*'],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'image-generation',
|
|
44
|
+
description: 'Image generation and image editing.',
|
|
45
|
+
aliases: ['image generation', 'generate image', '生图', '图片生成'],
|
|
46
|
+
include: [
|
|
47
|
+
'imagegen*',
|
|
48
|
+
'image_gen*',
|
|
49
|
+
'generate_image*',
|
|
50
|
+
'edit_image*',
|
|
51
|
+
'get_image_generation*',
|
|
52
|
+
'cancel_image_generation*',
|
|
53
|
+
'image_generation*',
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'filesystem',
|
|
58
|
+
description: 'Read, search, create, and edit files and directories.',
|
|
59
|
+
aliases: ['files', 'filesystem', 'code editing', '文件', '代码编辑'],
|
|
60
|
+
include: ['read', 'write', 'edit', 'glob', 'grep', 'read_file*', 'write_file*', 'list_dir*', 'search_file*', 'str_replace*', 'fs_*'],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'terminal',
|
|
64
|
+
description: 'Shell commands, terminal sessions, jobs, and local process control.',
|
|
65
|
+
aliases: ['terminal', 'shell', 'command', '终端', '命令行'],
|
|
66
|
+
include: ['bash', 'pwsh', 'shell_*', 'terminal_*', 'exec_*', 'job_*'],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: 'web',
|
|
70
|
+
description: 'Web search, HTTP fetching, and URL content retrieval.',
|
|
71
|
+
aliases: ['web search', 'internet', 'http', '联网', '网页搜索'],
|
|
72
|
+
include: ['web_*', 'http_*', 'fetch*', 'search_web*'],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'database',
|
|
76
|
+
description: 'Database inspection, queries, migrations, and records.',
|
|
77
|
+
aliases: ['database', 'sql', '数据库'],
|
|
78
|
+
include: ['database_*', 'db_*', 'sql_*', 'query_*'],
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'remote-ops',
|
|
82
|
+
description: 'SSH, SFTP, tunnels, and remote host operations.',
|
|
83
|
+
aliases: ['ssh', 'remote', 'server', '远程', '服务器'],
|
|
84
|
+
include: ['ssh_*', 'sftp_*', 'tunnel_*', 'remote_*'],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 'memory',
|
|
88
|
+
description: 'Durable memory, recall, notes, and knowledge retrieval.',
|
|
89
|
+
aliases: ['memory', 'recall', '记忆', '知识库'],
|
|
90
|
+
include: ['memory_*', 'recall*', 'mneme_*', 'note_*'],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'workbench',
|
|
94
|
+
description: 'Workspace workbench, artifacts, previews, and project utilities.',
|
|
95
|
+
aliases: ['workbench', 'workspace', '工作台'],
|
|
96
|
+
include: ['workbench_*', 'workspace_*', 'artifact_*', 'preview_*'],
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'agent-teams',
|
|
100
|
+
description: 'Team members, delegated tasks, messages, and coordination.',
|
|
101
|
+
aliases: ['team', 'delegate', '协作', '团队', '子任务'],
|
|
102
|
+
include: ['team_*', 'agent_team*', 'spawn_agent*', 'send_message*', 'followup_task*', 'wait_agent*', 'list_agent*'],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: 'subagents',
|
|
106
|
+
description: 'Subagent spawning, continuation, inspection, and collection.',
|
|
107
|
+
aliases: ['subagent', 'delegate', '子智能体', '委派'],
|
|
108
|
+
include: ['subagent*', 'spawn*', 'fork_agent*', 'continue_agent*'],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'workflow',
|
|
112
|
+
description: 'Workflow definitions, runs, schedules, and automation control.',
|
|
113
|
+
aliases: ['workflow', 'automation', 'schedule', '工作流', '自动化'],
|
|
114
|
+
include: ['workflow_*', 'schedule_*', 'automation_*', 'cron_*'],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 'interface',
|
|
118
|
+
description: 'Generated interface components, interactive artifacts, and structured UI.',
|
|
119
|
+
aliases: ['interface', 'ui', '组件', '界面'],
|
|
120
|
+
include: ['genui_*', 'ui_*', 'component_*'],
|
|
121
|
+
},
|
|
122
|
+
];
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache-stable progressive disclosure for the DeepSeek Harness tool registry.
|
|
3
|
+
*
|
|
4
|
+
* The default mode keeps one byte-stable model-facing surface and dispatches
|
|
5
|
+
* deferred tools through the ordinary Harness execution pipeline. A legacy
|
|
6
|
+
* dynamic mode remains available for deployments that require native schemas.
|
|
7
|
+
*/
|
|
8
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
9
|
+
import z from '@deepseek-ai/schemastery';
|
|
10
|
+
import type { ProgressiveMode, ResolvedConfig, SkillBindingConfig, ToolGroupConfig } from './types.js';
|
|
11
|
+
export { buildCatalog, estimateSchemaTokens, searchCatalog, searchTools } from './catalog.js';
|
|
12
|
+
export { activateGroups, createProgressiveState, expireGroups, proposeSearch, restoreSnapshot, snapshotState, touchTool, } from './state.js';
|
|
13
|
+
export type { ActiveGroupState, CatalogTool, DeferredGroupSummary, DeferredToolMatch, ProgressiveMode, ProxySearchResultValue, ResolvedConfig, SearchMatch, SearchResultValue, SkillBindingConfig, StateSnapshot, ToolCatalog, ToolGroup, ToolGroupConfig, ToolSchemaView, } from './types.js';
|
|
14
|
+
export declare const name = "tokens-progressive-tools";
|
|
15
|
+
export declare const inject: string[];
|
|
16
|
+
export interface Config {
|
|
17
|
+
/** Stable proxy is cache-friendly; dynamic exposes changing native families. */
|
|
18
|
+
readonly mode?: ProgressiveMode;
|
|
19
|
+
/** Registered discovery tool name. */
|
|
20
|
+
readonly toolName?: string;
|
|
21
|
+
/** Registered stable dispatcher name. */
|
|
22
|
+
readonly dispatchToolName?: string;
|
|
23
|
+
/** Tool-name wildcard patterns that stay directly visible. */
|
|
24
|
+
readonly alwaysVisible?: readonly string[];
|
|
25
|
+
/** Ordered family rules. The first matching family owns a tool. */
|
|
26
|
+
readonly groups?: readonly ToolGroupConfig[];
|
|
27
|
+
/** Successful skill calls that make bound tools dispatchable. */
|
|
28
|
+
readonly skillBindings?: readonly SkillBindingConfig[];
|
|
29
|
+
/** Maximum exact search matches returned to the caller. */
|
|
30
|
+
readonly maxResults?: number;
|
|
31
|
+
/** Highest-ranked families activated by one dynamic-mode search. */
|
|
32
|
+
readonly activationGroupLimit?: number;
|
|
33
|
+
/** Maximum retained active families in dynamic mode. */
|
|
34
|
+
readonly maxActiveGroups?: number;
|
|
35
|
+
/** Approximate schema-token budget for active dynamic-mode families. */
|
|
36
|
+
readonly maxActiveToolTokens?: number;
|
|
37
|
+
/** Dynamic-mode inactivity turns before expiry; zero disables expiry. */
|
|
38
|
+
readonly retentionTurns?: number;
|
|
39
|
+
/** Schema characters represented by one estimated token. */
|
|
40
|
+
readonly charactersPerToken?: number;
|
|
41
|
+
/** Require a successful search or skill binding before proxy dispatch. */
|
|
42
|
+
readonly requireDiscovery?: boolean;
|
|
43
|
+
/** Let one status listing make every cataloged name dispatchable. */
|
|
44
|
+
readonly statusGrantsDiscovery?: boolean;
|
|
45
|
+
/** Remove exact hidden tool guidance sections from the stable prompt. */
|
|
46
|
+
readonly deferToolGuidance?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare const Config: z<Config>;
|
|
49
|
+
export declare function resolveConfig(config?: Config): ResolvedConfig;
|
|
50
|
+
export declare function apply(ctx: Context, input: Config): void;
|