@aeondave/pi-skill-optimizer 3.0.0 → 3.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/BENCHMARK.md +3 -3
- package/CHANGELOG.md +25 -0
- package/README.md +10 -4
- package/docs/ARCHITECTURE.md +2 -2
- package/docs/CONFIGURATION.md +8 -2
- package/package.json +6 -5
- package/src/index.ts +62 -16
- package/src/tools.ts +1 -1
package/BENCHMARK.md
CHANGED
|
@@ -62,7 +62,7 @@ The benchmark asks:
|
|
|
62
62
|
2. Is the stable base byte-identical across unrelated human requests?
|
|
63
63
|
3. Does bounded prefetch improve first-turn recall without changing that base?
|
|
64
64
|
4. Can `skill_search` recover relevant tail skills through bounded pagination?
|
|
65
|
-
5. Can `
|
|
65
|
+
5. Can `optimizer_tool_search` defer schemas without making required tools unavailable?
|
|
66
66
|
6. Do output and history reductions preserve protected evidence and exact recovery?
|
|
67
67
|
7. Is every accepted serialized transformation smaller?
|
|
68
68
|
8. What do providers report for tokens, cache reads, cache writes, and cost?
|
|
@@ -174,7 +174,7 @@ Blocking invariants:
|
|
|
174
174
|
|
|
175
175
|
- core, configured, and already used tools remain active;
|
|
176
176
|
- inactive schemas are absent from the initial provider request;
|
|
177
|
-
- `
|
|
177
|
+
- `optimizer_tool_search` remains active while searchable definitions remain;
|
|
178
178
|
- activation makes selected tools callable in the same session;
|
|
179
179
|
- activation is additive and cannot strand an active provider tool loop;
|
|
180
180
|
- schema indexing work and response pagination remain bounded;
|
|
@@ -188,7 +188,7 @@ Reported metrics:
|
|
|
188
188
|
tool_recall
|
|
189
189
|
initial_tool_schema_bytes
|
|
190
190
|
activated_tool_schema_bytes
|
|
191
|
-
|
|
191
|
+
optimizer_tool_search_calls
|
|
192
192
|
activation_failures
|
|
193
193
|
```
|
|
194
194
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes are documented here.
|
|
4
4
|
|
|
5
|
+
## 3.1.0 - 2026-10-03
|
|
6
|
+
|
|
7
|
+
### Breaking
|
|
8
|
+
|
|
9
|
+
- Rename the optimizer's model-callable `tool_search` to `optimizer_tool_search`. Explicit tool calls must use the new name. Pi's built-in `tool_search` now loads alongside the optimizer without a replacement warning.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Preserve an active built-in `tool_search` during optimizer replanning.
|
|
14
|
+
- Retain tools activated later by Pi or another extension, and honor `alwaysTools` for initially inactive `deferred` or `codemode` tools while respecting hidden and inactive direct tools.
|
|
15
|
+
- Capture an explicitly requested benchmark catalog from Pi 1.0's `before_agent_start` skill options.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Require Pi 1.0.0 or newer for this release.
|
|
20
|
+
- Run typechecking and host integration tests against Pi 1.0.0 development packages.
|
|
21
|
+
- Add a reproducible Pi CLI black-box smoke test for the packed artifact.
|
|
22
|
+
|
|
23
|
+
## 3.0.1 - 2026-09-30
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Keep Pi 0.99's initially inactive `deferred` and `codemode` tools discoverable through the optimizer's `tool_search`. Activate only matching search results, retain them across later replanning, and leave initially unavailable direct or hidden tools outside the catalog.
|
|
28
|
+
- Reject blank tool searches without activating fallback results. Document how to disable Pi's replaceable built-in `tool-search` at the same scope as the optimizer, avoiding its startup conflict warning.
|
|
29
|
+
|
|
5
30
|
## 3.0.0 - 2026-09-28
|
|
6
31
|
|
|
7
32
|
### Scoped distribution - 2026-09-29
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ No embedding service or extra model call for ordinary routing. No changes to you
|
|
|
14
14
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
17
|
-
Requires **Pi 0.
|
|
17
|
+
Requires **Pi 1.0.0+** and **Node.js 26.3+**. Upgrade both before installing v3.1.
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
pi install npm:@aeondave/pi-skill-optimizer
|
|
@@ -26,12 +26,18 @@ Restart Pi, then check that it loaded:
|
|
|
26
26
|
/skill-optimizer
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
On Pi 1.0.0, the optimizer's search tool is `optimizer_tool_search`. Pi's
|
|
30
|
+
built-in `tool_search` can load alongside it without a name conflict. If you
|
|
31
|
+
previously disabled `builtin:tool-search` to avoid the warning, you can remove
|
|
32
|
+
that setting after updating the optimizer. See the
|
|
33
|
+
[tool-search configuration](docs/CONFIGURATION.md#tool-search-and-pi-100).
|
|
34
|
+
|
|
29
35
|
That's enough to start. Optionally run `/skill-optimizer init` to generate routing hints for your library. **Init uses your current Pi model and may incur cost**; normal discovery does not.
|
|
30
36
|
|
|
31
37
|
| Need | Command |
|
|
32
38
|
| --- | --- |
|
|
33
39
|
| Install only in this project | `pi install -l npm:@aeondave/pi-skill-optimizer` |
|
|
34
|
-
| Pin the current release | `pi install npm:@aeondave/pi-skill-optimizer@3.
|
|
40
|
+
| Pin the current release | `pi install npm:@aeondave/pi-skill-optimizer@3.1.0` |
|
|
35
41
|
| Update an unpinned install | `pi update npm:@aeondave/pi-skill-optimizer` |
|
|
36
42
|
|
|
37
43
|
Restart after updating. Pinned installs stay pinned until you explicitly install another version.
|
|
@@ -58,7 +64,7 @@ AUTO keeps a compact, stable index of **all eligible names**, adds relevant desc
|
|
|
58
64
|
| Area | What AUTO does | What stays available |
|
|
59
65
|
| --- | --- | --- |
|
|
60
66
|
| Skills | Shortens catalog descriptions; prefetches relevant ones | Every eligible name and exact full-instruction loading |
|
|
61
|
-
| Tools | Defers less relevant schemas behind `
|
|
67
|
+
| Tools | Defers less relevant schemas behind `optimizer_tool_search` | Protected, configured, already-used and activated tools |
|
|
62
68
|
| Large results | Applies deterministic reduction; lossless columnar JSON where suitable | Complete originals through `retrieve_output` during archive retention |
|
|
63
69
|
| Repeated results | Replaces later exact duplicates with recovery references | The first result, errors, protected evidence and mixed media |
|
|
64
70
|
|
|
@@ -76,7 +82,7 @@ You can leave AUTO running with its defaults.
|
|
|
76
82
|
|
|
77
83
|
An optional setup hint appears at the first eligible prompt when initialization is missing or needs attention. It never starts init for you or adds instructions to the model's context.
|
|
78
84
|
|
|
79
|
-
Pi gets three tools: `skill_search`, `
|
|
85
|
+
Pi gets three optimizer tools: `skill_search`, `optimizer_tool_search` and `retrieve_output`. Pi may also provide its built-in `tool_search`. Skill search is paginated and exact loads accept only registered names. Output recovery uses opaque identifiers, not exposed archive paths.
|
|
80
86
|
|
|
81
87
|
Skills can be useful even when you never mention them. Init can tag architecture,
|
|
82
88
|
testing and behavioral guidance by activity, so a matched specialist can bring
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -30,9 +30,9 @@ expand dependencies or treat a behavioral tag as universal. See
|
|
|
30
30
|
|
|
31
31
|
## Dynamic tools
|
|
32
32
|
|
|
33
|
-
AUTO keeps protected and predicted tools active and leaves the rest behind `
|
|
33
|
+
AUTO keeps protected and predicted tools active and leaves the rest behind `optimizer_tool_search`. Search is bounded and paginated. A returned result is activated through Pi's runtime API without replacing already active tools. Core, configured, and previously used tools remain callable, so an in-progress tool loop cannot be stranded. Pi's built-in `tool_search` remains active when the host enables it. Weak or absent routing signal fails open to every permitted tool; safety wins, but that request may retain the full schema cost.
|
|
34
34
|
|
|
35
|
-
Selection is recalculated before each agent run, not just the first request. Used tools and explicit search results stay active for the session. The discoverable set starts from Pi's initially active tools plus the optimizer's own resolvers; tools
|
|
35
|
+
Selection is recalculated before each agent run, not just the first request. Used tools and explicit search results stay active for the session. The discoverable set starts from Pi's initially active tools plus the optimizer's own resolvers. Newly activated host tools are retained; inactive `deferred` and `codemode` tools can be selected through search or `alwaysTools`. Inactive direct and hidden tools are not silently added. This is schema routing, not authorization: another extension's call-time permission checks remain authoritative.
|
|
36
36
|
|
|
37
37
|
See Pi's [extension and dynamic-tool API](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md).
|
|
38
38
|
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -7,13 +7,19 @@
|
|
|
7
7
|
| Tool | Purpose |
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| `skill_search` | Paginated skill search plus exact `load`, contained `resource`, and explicit `location` actions |
|
|
10
|
-
| `
|
|
10
|
+
| `optimizer_tool_search` | Search deferred tool definitions and activate bounded matches additively |
|
|
11
11
|
| `retrieve_output` | Recover archived output or a deduplicated history result by opaque identifier |
|
|
12
12
|
|
|
13
13
|
Exact skill loading accepts only registered names. Resource and location resolution use canonical paths and containment checks to reject traversal and symlink escape. Search cursors bind to the query, catalog and ranked name order; a changed profile or usage prior that reorders results requires a new search, rather than duplicating or skipping a page. This is an exact local resolver guarantee, not a guarantee that the model will select the right skill; see the separate [ranking diagnostics](RANKING.md) and [historical model benchmark](../BENCHMARK.md).
|
|
14
14
|
|
|
15
15
|
`excludeSkills` removes names from discovery and search, not from explicit exact loading. It is a routing preference, not an access-control boundary. The three resolver tools return their content without another output-reduction pass, so full skill instructions and recovered originals remain readable.
|
|
16
16
|
|
|
17
|
+
### Tool search and Pi 1.0.0
|
|
18
|
+
|
|
19
|
+
The extension registers `optimizer_tool_search`, leaving Pi's built-in `tool_search` available under its own name. The optimizer indexes eligible registered tools, including ones it deferred from Pi's active set and Pi-registered `deferred` or `codemode` tools. Matching inactive results activate additively; unrelated fallback results remain inactive. An already active built-in `tool_search` stays active during optimizer replanning. Pi's built-in MCP extension can activate its own `tool_search` when a deferred server connects.
|
|
20
|
+
|
|
21
|
+
If an older optimizer release led you to add `-builtin:tool-search` in `~/.pi/agent/settings.json` or `.pi/settings.json`, remove that entry after updating if you want Pi's built-in search available again. The built-in is inactive by default unless enabled in Pi's `defaultTools` or activated by Pi for deferred MCP tools; the optimizer's search stays available independently. Existing explicit calls to the optimizer's old `tool_search` name must use `optimizer_tool_search` after this update.
|
|
22
|
+
|
|
17
23
|
## Commands
|
|
18
24
|
|
|
19
25
|
| Command | Purpose |
|
|
@@ -49,7 +55,7 @@ Global configuration lives at `~/.pi/agent/skill-optimizer/config.json`. A proje
|
|
|
49
55
|
| `providers` | `[]` | Provider allowlist; empty means all |
|
|
50
56
|
| `toolPrefetchMax` | `5` | Maximum proactive tool activation |
|
|
51
57
|
| `toolSearchPageSize` | `8` | Default tool-search page size |
|
|
52
|
-
| `alwaysTools` | `[]` |
|
|
58
|
+
| `alwaysTools` | `[]` | Keep initially active tools and named `deferred` or `codemode` tools active; hidden tools remain unavailable |
|
|
53
59
|
| `historyDedupMinBytes` | `4096` | Minimum result size for history deduplication |
|
|
54
60
|
| `usageHalfLifeDays` | `30` | Usage-evidence decay half-life |
|
|
55
61
|
| `usageMaxEntries` | `2048` | Persistent usage-evidence bound |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aeondave/pi-skill-optimizer",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Less repeated context for Pi: local skill routing, on-demand tools, and recoverable output reduction.",
|
|
@@ -43,12 +43,13 @@
|
|
|
43
43
|
],
|
|
44
44
|
"scripts": {
|
|
45
45
|
"typecheck": "tsc --noEmit",
|
|
46
|
-
"test": "node --import tsx --test test/request.test.ts test/history.test.ts test/skills.test.ts test/skill-loader.test.ts test/tools.test.ts test/optimize.test.ts test/profile.test.ts test/activation.test.ts test/generate.test.ts test/init.test.ts test/init-readiness.test.ts test/config.test.ts test/fuzz.test.ts test/output.test.ts test/output-recovery.test.ts test/runtime.test.ts test/host-runtime.test.ts test/stats.test.ts test/usage.test.ts test/persistence.test.ts test/corpus.test.ts test/evaluation.test.ts test/luna.test.ts test/release-metadata.test.ts",
|
|
46
|
+
"test": "node --import tsx --test test/request.test.ts test/history.test.ts test/skills.test.ts test/skill-loader.test.ts test/tools.test.ts test/optimize.test.ts test/profile.test.ts test/activation.test.ts test/generate.test.ts test/init.test.ts test/init-readiness.test.ts test/config.test.ts test/fuzz.test.ts test/output.test.ts test/output-recovery.test.ts test/runtime.test.ts test/host-runtime.test.ts test/stats.test.ts test/usage.test.ts test/persistence.test.ts test/corpus.test.ts test/capture-catalog.test.ts test/evaluation.test.ts test/luna.test.ts test/release-metadata.test.ts",
|
|
47
47
|
"measure": "node --import tsx scripts/measure.ts",
|
|
48
48
|
"bench": "node --import tsx scripts/bench.ts",
|
|
49
49
|
"bench:perf": "node --import tsx scripts/perf-bench.ts",
|
|
50
50
|
"bench:ranking": "node --import tsx scripts/ranking-bench.ts",
|
|
51
51
|
"bench:output": "node --import tsx scripts/output-bench.ts",
|
|
52
|
+
"smoke:blackbox": "node --import tsx scripts/black-box-smoke.ts",
|
|
52
53
|
"corpus:build": "node --import tsx scripts/build-real-corpus.ts",
|
|
53
54
|
"bench:real": "node --import tsx scripts/evaluate-real-corpus.ts"
|
|
54
55
|
},
|
|
@@ -69,8 +70,8 @@
|
|
|
69
70
|
}
|
|
70
71
|
},
|
|
71
72
|
"devDependencies": {
|
|
72
|
-
"@earendil-works/pi-ai": "^0.
|
|
73
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
73
|
+
"@earendil-works/pi-ai": "^1.0.0",
|
|
74
|
+
"@earendil-works/pi-coding-agent": "^1.0.0",
|
|
74
75
|
"@types/node": "^26.6.3",
|
|
75
76
|
"tsx": "^4.23.13",
|
|
76
77
|
"typebox": "^1.3.34",
|
|
@@ -80,6 +81,6 @@
|
|
|
80
81
|
"extensions": [
|
|
81
82
|
"./src/index.ts"
|
|
82
83
|
],
|
|
83
|
-
"image": "https://raw.githubusercontent.com/AeonDave/pi-skill-optimizer/v3.
|
|
84
|
+
"image": "https://raw.githubusercontent.com/AeonDave/pi-skill-optimizer/v3.1.0/assets/banner.png"
|
|
84
85
|
}
|
|
85
86
|
}
|
package/src/index.ts
CHANGED
|
@@ -110,7 +110,16 @@ const FLUSH_INTERVAL_MS = 15_000;
|
|
|
110
110
|
const LOAD_RETRY_MS = 1_000;
|
|
111
111
|
const MAX_SEEN_EVIDENCE = 4_096;
|
|
112
112
|
const MAX_HISTORY_ARTIFACTS = 128;
|
|
113
|
-
const PROTECTED_RUNTIME_TOOLS = ["skill_search", "
|
|
113
|
+
const PROTECTED_RUNTIME_TOOLS = ["skill_search", "optimizer_tool_search", "retrieve_output"] as const;
|
|
114
|
+
const RESOLVER_RESULT_TOOLS = new Set<string>([...PROTECTED_RUNTIME_TOOLS, "tool_search"]);
|
|
115
|
+
|
|
116
|
+
function isHostSearchableTool(tool: object): boolean {
|
|
117
|
+
return "exposure" in tool && (tool.exposure === "deferred" || tool.exposure === "codemode");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function isHostHiddenTool(tool: object): boolean {
|
|
121
|
+
return "exposure" in tool && tool.exposure === "hidden";
|
|
122
|
+
}
|
|
114
123
|
|
|
115
124
|
type ConfigRecord = ReturnType<typeof getConfig>;
|
|
116
125
|
|
|
@@ -565,12 +574,34 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
565
574
|
};
|
|
566
575
|
|
|
567
576
|
const rebuildToolCatalog = (state: RuntimeSnapshot): ToolDiscoveryCatalog => {
|
|
577
|
+
const allTools = pi.getAllTools();
|
|
578
|
+
const activeNames = new Set(pi.getActiveTools().map((name) => name.toLowerCase()));
|
|
579
|
+
const alwaysToolPrefixes = state.config.alwaysTools
|
|
580
|
+
.map((pattern) => pattern.trim().toLowerCase())
|
|
581
|
+
.filter((pattern) => pattern.length > 0);
|
|
568
582
|
permittedToolNames ??= new Set([
|
|
569
|
-
...
|
|
583
|
+
...activeNames,
|
|
570
584
|
...PROTECTED_RUNTIME_TOOLS,
|
|
571
585
|
]);
|
|
572
|
-
const
|
|
573
|
-
|
|
586
|
+
for (const tool of allTools) {
|
|
587
|
+
const name = tool.name.toLowerCase();
|
|
588
|
+
if (isHostHiddenTool(tool)) {
|
|
589
|
+
permittedToolNames.delete(name);
|
|
590
|
+
retainedToolNames.delete(name);
|
|
591
|
+
deactivatedToolNames.delete(name);
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
if (activeNames.has(name)) {
|
|
595
|
+
const newlyActive = !permittedToolNames.has(name);
|
|
596
|
+
const reactivated = deactivatedToolNames.delete(name);
|
|
597
|
+
if (newlyActive || reactivated) retainedToolNames.add(name);
|
|
598
|
+
permittedToolNames.add(name);
|
|
599
|
+
} else if (isHostSearchableTool(tool) && alwaysToolPrefixes.some((pattern) => name.startsWith(pattern))) {
|
|
600
|
+
permittedToolNames.add(name);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const discoverable = allTools.filter((tool) =>
|
|
604
|
+
!isHostHiddenTool(tool) && permittedToolNames?.has(tool.name.toLowerCase()),
|
|
574
605
|
);
|
|
575
606
|
toolCatalog = buildToolDiscoveryCatalog(discoverable, {
|
|
576
607
|
protect: [...PROTECTED_RUNTIME_TOOLS, ...state.config.alwaysTools],
|
|
@@ -578,13 +609,25 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
578
609
|
return toolCatalog;
|
|
579
610
|
};
|
|
580
611
|
|
|
612
|
+
const buildToolSearchCatalog = (state: RuntimeSnapshot): ToolDiscoveryCatalog => {
|
|
613
|
+
rebuildToolCatalog(state);
|
|
614
|
+
return buildToolDiscoveryCatalog(pi.getAllTools().filter((tool) =>
|
|
615
|
+
!isHostHiddenTool(tool)
|
|
616
|
+
&& (permittedToolNames?.has(tool.name.toLowerCase()) || isHostSearchableTool(tool)),
|
|
617
|
+
), {
|
|
618
|
+
protect: [...PROTECTED_RUNTIME_TOOLS, ...state.config.alwaysTools],
|
|
619
|
+
});
|
|
620
|
+
};
|
|
621
|
+
|
|
581
622
|
const activateAdditively = (names: readonly string[]): string[] => {
|
|
582
623
|
const requested = new Set(names.map((name) => name.toLowerCase()));
|
|
583
624
|
const current = new Set(pi.getActiveTools().map((name) => name.toLowerCase()));
|
|
584
625
|
const added: string[] = [];
|
|
585
626
|
for (const tool of pi.getAllTools()) {
|
|
586
|
-
if (
|
|
627
|
+
if (isHostHiddenTool(tool)) continue;
|
|
628
|
+
if (!permittedToolNames?.has(tool.name.toLowerCase()) && !isHostSearchableTool(tool)) continue;
|
|
587
629
|
if (!requested.has(tool.name.toLowerCase())) continue;
|
|
630
|
+
permittedToolNames?.add(tool.name.toLowerCase());
|
|
588
631
|
retainedToolNames.add(tool.name.toLowerCase());
|
|
589
632
|
if (current.has(tool.name.toLowerCase())) continue;
|
|
590
633
|
current.add(tool.name.toLowerCase());
|
|
@@ -592,8 +635,8 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
592
635
|
added.push(tool.name);
|
|
593
636
|
}
|
|
594
637
|
const ordered = pi.getAllTools()
|
|
595
|
-
.
|
|
596
|
-
.
|
|
638
|
+
.filter((tool) => !isHostHiddenTool(tool) && current.has(tool.name.toLowerCase()))
|
|
639
|
+
.map((tool) => tool.name);
|
|
597
640
|
pi.setActiveTools(ordered);
|
|
598
641
|
return added;
|
|
599
642
|
};
|
|
@@ -607,8 +650,8 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
607
650
|
for (const name of deactivatedToolNames) active.add(name);
|
|
608
651
|
pi.setActiveTools(
|
|
609
652
|
pi.getAllTools()
|
|
610
|
-
.
|
|
611
|
-
.
|
|
653
|
+
.filter((tool) => !isHostHiddenTool(tool) && active.has(tool.name.toLowerCase()))
|
|
654
|
+
.map((tool) => tool.name),
|
|
612
655
|
);
|
|
613
656
|
deactivatedToolNames.clear();
|
|
614
657
|
toolCatalog = undefined;
|
|
@@ -656,14 +699,15 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
656
699
|
});
|
|
657
700
|
|
|
658
701
|
pi.registerTool({
|
|
659
|
-
name: "
|
|
660
|
-
label: "Tool Search",
|
|
661
|
-
description: "Search
|
|
702
|
+
name: "optimizer_tool_search",
|
|
703
|
+
label: "Optimizer Tool Search",
|
|
704
|
+
description: "Search local tool definitions and activate matching inactive tools without disabling current tools.",
|
|
662
705
|
promptSnippet: "Search and activate additional tools on demand",
|
|
663
706
|
parameters: TOOL_SEARCH_PARAMS,
|
|
664
707
|
async execute(_id, params, _signal, _update, ctx) {
|
|
708
|
+
if (!params.query.trim()) throw new TypeError("query must not be empty");
|
|
665
709
|
const state = ensureSnapshot(ctx);
|
|
666
|
-
const catalog =
|
|
710
|
+
const catalog = buildToolSearchCatalog(state);
|
|
667
711
|
const page = searchToolDiscoveryCatalog(catalog, params.query, {
|
|
668
712
|
cursor: params.cursor,
|
|
669
713
|
pageSize: Math.min(
|
|
@@ -671,7 +715,9 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
671
715
|
state.config.toolSearchPageSize,
|
|
672
716
|
),
|
|
673
717
|
});
|
|
674
|
-
const activated = activateAdditively(page.results
|
|
718
|
+
const activated = activateAdditively(page.results
|
|
719
|
+
.filter((result) => result.matchedTerms.length > 0)
|
|
720
|
+
.map((result) => result.name));
|
|
675
721
|
return {
|
|
676
722
|
content: [{ type: "text", text: JSON.stringify({ ...page, activated }) }],
|
|
677
723
|
details: { activated, confidence: page.confidence, failOpen: page.failOpen },
|
|
@@ -1146,7 +1192,7 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
1146
1192
|
|
|
1147
1193
|
pi.on("tool_result", async (event, ctx) => {
|
|
1148
1194
|
usedTools.add(event.toolName.toLowerCase());
|
|
1149
|
-
if (
|
|
1195
|
+
if (RESOLVER_RESULT_TOOLS.has(event.toolName)) return;
|
|
1150
1196
|
if (isDisabled(ctx.cwd) || event.isError) return;
|
|
1151
1197
|
const config = getRuntimeConfig(ctx);
|
|
1152
1198
|
const providers = config.providers.length > 0 ? config.providers : undefined;
|
|
@@ -1342,7 +1388,7 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
1342
1388
|
` enabled: ${isDisabled(ctx.cwd) ? "no" : "yes"}`,
|
|
1343
1389
|
" skills mode: AUTO (stable TSV + skill_search resolver)",
|
|
1344
1390
|
` catalog budget:${lastBudget.usedChars}/${lastBudget.requestedChars} chars, ${lastBudget.nameOnlyCount} name-only`,
|
|
1345
|
-
` tools: ${pi.getActiveTools().length}/${pi.getAllTools().length} active;
|
|
1391
|
+
` tools: ${pi.getActiveTools().length}/${pi.getAllTools().length} active; optimizer_tool_search additive`,
|
|
1346
1392
|
` output: ${getOutputConfig(state.config).mode}; RTK ${rtkExtensionPresent() ? "detected per result" : "not detected"}`,
|
|
1347
1393
|
` scope: ${state.config.providers.join(", ") || "all providers"}`,
|
|
1348
1394
|
` init readiness: ${retryAfter !== 0 ? "unavailable (profile could not be read)" : readiness.skillCount === 0 ? "not available (no model-invocable skills)" : initReadinessSummary(readiness)}`,
|
package/src/tools.ts
CHANGED
|
@@ -23,7 +23,7 @@ export const CORE_TOOLS = new Set(
|
|
|
23
23
|
"read", "bash", "edit", "write", "multiedit", "str_replace_editor", "notebookedit",
|
|
24
24
|
"glob", "grep", "ls", "find", "todo", "todowrite", "todoread",
|
|
25
25
|
"subagent", "fork", "task", "mcp", "skill", "exitplanmode", "enterplanmode",
|
|
26
|
-
"webfetch", "websearch", "askuserquestion", "powershell",
|
|
26
|
+
"webfetch", "websearch", "askuserquestion", "powershell", "tool_search",
|
|
27
27
|
].map((name) => name.toLowerCase()),
|
|
28
28
|
);
|
|
29
29
|
|