@aeondave/pi-skill-optimizer 3.0.1 → 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 +18 -0
- package/README.md +9 -10
- package/docs/ARCHITECTURE.md +2 -2
- package/docs/CONFIGURATION.md +5 -5
- package/package.json +6 -5
- package/src/index.ts +25 -10
- 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,24 @@
|
|
|
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
|
+
|
|
5
23
|
## 3.0.1 - 2026-09-30
|
|
6
24
|
|
|
7
25
|
### Fixed
|
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,19 +26,18 @@ Restart Pi, then check that it loaded:
|
|
|
26
26
|
/skill-optimizer
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Pi 0.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
[tool-search configuration](docs/CONFIGURATION.md#replacing-the-built-in-tool-search).
|
|
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).
|
|
35
34
|
|
|
36
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.
|
|
37
36
|
|
|
38
37
|
| Need | Command |
|
|
39
38
|
| --- | --- |
|
|
40
39
|
| Install only in this project | `pi install -l npm:@aeondave/pi-skill-optimizer` |
|
|
41
|
-
| Pin the current release | `pi install npm:@aeondave/pi-skill-optimizer@3.0
|
|
40
|
+
| Pin the current release | `pi install npm:@aeondave/pi-skill-optimizer@3.1.0` |
|
|
42
41
|
| Update an unpinned install | `pi update npm:@aeondave/pi-skill-optimizer` |
|
|
43
42
|
|
|
44
43
|
Restart after updating. Pinned installs stay pinned until you explicitly install another version.
|
|
@@ -65,7 +64,7 @@ AUTO keeps a compact, stable index of **all eligible names**, adds relevant desc
|
|
|
65
64
|
| Area | What AUTO does | What stays available |
|
|
66
65
|
| --- | --- | --- |
|
|
67
66
|
| Skills | Shortens catalog descriptions; prefetches relevant ones | Every eligible name and exact full-instruction loading |
|
|
68
|
-
| Tools | Defers less relevant schemas behind `
|
|
67
|
+
| Tools | Defers less relevant schemas behind `optimizer_tool_search` | Protected, configured, already-used and activated tools |
|
|
69
68
|
| Large results | Applies deterministic reduction; lossless columnar JSON where suitable | Complete originals through `retrieve_output` during archive retention |
|
|
70
69
|
| Repeated results | Replaces later exact duplicates with recovery references | The first result, errors, protected evidence and mixed media |
|
|
71
70
|
|
|
@@ -83,7 +82,7 @@ You can leave AUTO running with its defaults.
|
|
|
83
82
|
|
|
84
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.
|
|
85
84
|
|
|
86
|
-
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.
|
|
87
86
|
|
|
88
87
|
Skills can be useful even when you never mention them. Init can tag architecture,
|
|
89
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,18 +7,18 @@
|
|
|
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
|
-
###
|
|
17
|
+
### Tool search and Pi 1.0.0
|
|
18
18
|
|
|
19
|
-
The extension registers `
|
|
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
20
|
|
|
21
|
-
|
|
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
22
|
|
|
23
23
|
## Commands
|
|
24
24
|
|
|
@@ -55,7 +55,7 @@ Global configuration lives at `~/.pi/agent/skill-optimizer/config.json`. A proje
|
|
|
55
55
|
| `providers` | `[]` | Provider allowlist; empty means all |
|
|
56
56
|
| `toolPrefetchMax` | `5` | Maximum proactive tool activation |
|
|
57
57
|
| `toolSearchPageSize` | `8` | Default tool-search page size |
|
|
58
|
-
| `alwaysTools` | `[]` |
|
|
58
|
+
| `alwaysTools` | `[]` | Keep initially active tools and named `deferred` or `codemode` tools active; hidden tools remain unavailable |
|
|
59
59
|
| `historyDedupMinBytes` | `4096` | Minimum result size for history deduplication |
|
|
60
60
|
| `usageHalfLifeDays` | `30` | Usage-evidence decay half-life |
|
|
61
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.0
|
|
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.0
|
|
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,8 @@ 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"]);
|
|
114
115
|
|
|
115
116
|
function isHostSearchableTool(tool: object): boolean {
|
|
116
117
|
return "exposure" in tool && (tool.exposure === "deferred" || tool.exposure === "codemode");
|
|
@@ -574,16 +575,30 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
574
575
|
|
|
575
576
|
const rebuildToolCatalog = (state: RuntimeSnapshot): ToolDiscoveryCatalog => {
|
|
576
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);
|
|
577
582
|
permittedToolNames ??= new Set([
|
|
578
|
-
...
|
|
583
|
+
...activeNames,
|
|
579
584
|
...PROTECTED_RUNTIME_TOOLS,
|
|
580
585
|
]);
|
|
581
586
|
for (const tool of allTools) {
|
|
582
|
-
if (!isHostHiddenTool(tool)) continue;
|
|
583
587
|
const name = tool.name.toLowerCase();
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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
|
+
}
|
|
587
602
|
}
|
|
588
603
|
const discoverable = allTools.filter((tool) =>
|
|
589
604
|
!isHostHiddenTool(tool) && permittedToolNames?.has(tool.name.toLowerCase()),
|
|
@@ -684,8 +699,8 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
684
699
|
});
|
|
685
700
|
|
|
686
701
|
pi.registerTool({
|
|
687
|
-
name: "
|
|
688
|
-
label: "Tool Search",
|
|
702
|
+
name: "optimizer_tool_search",
|
|
703
|
+
label: "Optimizer Tool Search",
|
|
689
704
|
description: "Search local tool definitions and activate matching inactive tools without disabling current tools.",
|
|
690
705
|
promptSnippet: "Search and activate additional tools on demand",
|
|
691
706
|
parameters: TOOL_SEARCH_PARAMS,
|
|
@@ -1177,7 +1192,7 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
1177
1192
|
|
|
1178
1193
|
pi.on("tool_result", async (event, ctx) => {
|
|
1179
1194
|
usedTools.add(event.toolName.toLowerCase());
|
|
1180
|
-
if (
|
|
1195
|
+
if (RESOLVER_RESULT_TOOLS.has(event.toolName)) return;
|
|
1181
1196
|
if (isDisabled(ctx.cwd) || event.isError) return;
|
|
1182
1197
|
const config = getRuntimeConfig(ctx);
|
|
1183
1198
|
const providers = config.providers.length > 0 ? config.providers : undefined;
|
|
@@ -1373,7 +1388,7 @@ export default function skillOptimizer(pi: ExtensionAPI) {
|
|
|
1373
1388
|
` enabled: ${isDisabled(ctx.cwd) ? "no" : "yes"}`,
|
|
1374
1389
|
" skills mode: AUTO (stable TSV + skill_search resolver)",
|
|
1375
1390
|
` catalog budget:${lastBudget.usedChars}/${lastBudget.requestedChars} chars, ${lastBudget.nameOnlyCount} name-only`,
|
|
1376
|
-
` tools: ${pi.getActiveTools().length}/${pi.getAllTools().length} active;
|
|
1391
|
+
` tools: ${pi.getActiveTools().length}/${pi.getAllTools().length} active; optimizer_tool_search additive`,
|
|
1377
1392
|
` output: ${getOutputConfig(state.config).mode}; RTK ${rtkExtensionPresent() ? "detected per result" : "not detected"}`,
|
|
1378
1393
|
` scope: ${state.config.providers.join(", ") || "all providers"}`,
|
|
1379
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
|
|