@llblab/pi-actors 0.16.2 → 0.16.4
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 +12 -0
- package/docs/template-recipes.md +2 -2
- package/docs/tool-registry.md +1 -1
- package/lib/recipe-references.ts +7 -3
- package/lib/recipe-usage.ts +24 -2
- package/package.json +1 -1
- package/skills/actors/SKILL.md +1 -1
- package/skills/swarm/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.16.4: Recipe Usage Fingerprints
|
|
4
|
+
|
|
5
|
+
- `[Recipe Usage]` Added content fingerprints to user recipe usage metadata. Impact: when a recipe file is edited and its authored meaning changes, the next launch resets `usage.calls`, records `usage.reset_at`, and starts counting usage for the current recipe content.
|
|
6
|
+
- `[Docs]` Documented fingerprint-backed usage reset semantics in the template recipe and tool registry docs.
|
|
7
|
+
- `[Package]` Bumped package and packaged skill metadata to `0.16.4` for the hotfix release.
|
|
8
|
+
|
|
9
|
+
## 0.16.3: Recipe Import Path Placeholders
|
|
10
|
+
|
|
11
|
+
- `[Template Recipes]` Added static `{repo}` and `{agent}` expansion for recipe paths, including `imports` and `from` bindings. Impact: recipes can import sibling packaged/user recipes without hard-coded absolute paths while keeping imports load-time deterministic.
|
|
12
|
+
- `[Docs]` Documented `{repo}` and `{agent}` import path placeholders in the template recipe standard.
|
|
13
|
+
- `[Package]` Bumped package and packaged skill metadata to `0.16.3` for the hotfix release.
|
|
14
|
+
|
|
3
15
|
## 0.16.2: Recipe Registry Diagnostics Hotfix
|
|
4
16
|
|
|
5
17
|
- `[Schema]` Derived recipe tool arguments without expanding runtime-dependent repeat nodes. Impact: valid recipes using repeat expressions such as `{lenses.length}` can be exposed as tools instead of being skipped during startup schema generation.
|
package/docs/template-recipes.md
CHANGED
|
@@ -95,7 +95,7 @@ User-owned recipes may accumulate extension-maintained usage metadata:
|
|
|
95
95
|
}
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
The extension increments `usage.calls` and updates `usage.last_called` when it starts that concrete recipe, either through a recipe-backed tool call or a direct async recipe-file run. Agents should treat these fields as cleanup evidence, not as authored recipe contract. Packaged standard-library recipes are not mutated for usage metadata.
|
|
98
|
+
The extension increments `usage.calls` and updates `usage.last_called` when it starts that concrete recipe, either through a recipe-backed tool call or a direct async recipe-file run. It also stores a content `usage.fingerprint`; if the authored recipe content changes, the next launch resets `usage.calls` before counting the new launch and records `usage.reset_at`. Agents should treat these fields as cleanup evidence, not as authored recipe contract. Packaged standard-library recipes are not mutated for usage metadata.
|
|
99
99
|
|
|
100
100
|
There is intentionally no failure counter in the recipe contract. A failed launch can reflect caller misuse, missing runtime values, or an environmental problem rather than recipe uselessness. Cleanup decisions should be explicit operator work: keep as a tool, set `tool: false`, merge, delete, or archive.
|
|
101
101
|
|
|
@@ -245,7 +245,7 @@ File-backed recipes may import other file-backed recipes at the recipe layer. Im
|
|
|
245
245
|
|
|
246
246
|
An import binding may be either a string recipe path/name or an object with:
|
|
247
247
|
|
|
248
|
-
- `from`: recipe path or bare name.
|
|
248
|
+
- `from`: recipe path or bare name. Import paths support static load-time placeholders: `{repo}` expands to the directory above the active recipe root, and `{agent}` expands to the pi agent directory. For a packaged recipe in `<repo>/recipes/name.json`, `{repo}/recipes/other.json` resolves to a sibling packaged recipe. For a user recipe in `~/.pi/agent/recipes/name.json`, `{repo}` and `{agent}` both resolve to `~/.pi/agent`.
|
|
249
249
|
- `defaults`: extra default values exposed through the import.
|
|
250
250
|
- `values`: explicit values for embedding that imported recipe.
|
|
251
251
|
|
package/docs/tool-registry.md
CHANGED
|
@@ -17,7 +17,7 @@ The 0.16 registry source is file-discovered recipes, not a live tool-only JSON f
|
|
|
17
17
|
|
|
18
18
|
`~/.pi/agent/actors-tools.json` is legacy compatibility input. On startup, pi-actors migrates it into recipe files when possible, writes a migration report, and archives the source only when migration has no conflicts or invalid generated recipes.
|
|
19
19
|
|
|
20
|
-
Because the user recipe directory is sticky agent muscle memory, runtime launches update `usage.calls` and `usage.
|
|
20
|
+
Because the user recipe directory is sticky agent muscle memory, runtime launches update `usage.calls`, `usage.last_called`, and a content `usage.fingerprint` on user-owned recipe files. If authored recipe content changes, the next launch resets `usage.calls` and records `usage.reset_at` before counting the launch, so usage evidence follows the current recipe meaning rather than an older file history. Use that evidence during focused cleanup passes: keep valuable tools, set `tool: false` for useful components that should leave the active tool surface, merge duplicates, or delete/archive low-value files. The extension does not maintain a failure counter and agents should not silently clean tools during unrelated work.
|
|
21
21
|
|
|
22
22
|
`register_tool` is the preferred agent-facing mutation API. It creates, updates, and deletes recipe files in `~/.pi/agent/recipes`; agents do not need to edit the files directly for normal registration. Direct file edits are still valid for operators and advanced agents. Runtime behavior is reactive: file creation, deletion, or edits in the user recipe root trigger validation and tool-set refresh, with invalid recipes surfaced as diagnostics rather than silently ignored.
|
|
23
23
|
|
package/lib/recipe-references.ts
CHANGED
|
@@ -75,11 +75,15 @@ export function resolveRecipePath(
|
|
|
75
75
|
recipeRoot = Paths.getRecipeRoot(),
|
|
76
76
|
): string {
|
|
77
77
|
const trimmed = value.trim();
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
const repoRoot = resolve(recipeRoot, "..");
|
|
79
|
+
const expanded = trimmed
|
|
80
|
+
.replaceAll("{repo}", repoRoot)
|
|
81
|
+
.replaceAll("{agent}", Paths.getAgentDir());
|
|
82
|
+
if (expanded.startsWith("~/")) return resolve(homedir(), expanded.slice(2));
|
|
83
|
+
if (expanded.includes("/")) return resolve(expanded);
|
|
80
84
|
return resolve(
|
|
81
85
|
recipeRoot,
|
|
82
|
-
|
|
86
|
+
expanded.endsWith(".json") ? expanded : `${expanded}.json`,
|
|
83
87
|
);
|
|
84
88
|
}
|
|
85
89
|
|
package/lib/recipe-usage.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Owns lightweight launch counters for user-owned recipe files
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
7
8
|
import { existsSync, readFileSync } from "node:fs";
|
|
8
9
|
|
|
9
10
|
import { writeJsonAtomic } from "./file-state.ts";
|
|
@@ -11,6 +12,8 @@ import { writeJsonAtomic } from "./file-state.ts";
|
|
|
11
12
|
interface RecipeUsageRecord {
|
|
12
13
|
calls?: number;
|
|
13
14
|
last_called?: string;
|
|
15
|
+
fingerprint?: string;
|
|
16
|
+
reset_at?: string;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
@@ -23,18 +26,37 @@ function normalizeCalls(value: unknown): number {
|
|
|
23
26
|
: 0;
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
function stableStringify(value: unknown): string {
|
|
30
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
31
|
+
if (!isRecord(value)) return JSON.stringify(value);
|
|
32
|
+
return `{${Object.keys(value)
|
|
33
|
+
.sort()
|
|
34
|
+
.map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`)
|
|
35
|
+
.join(",")}}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getRecipeFingerprint(raw: Record<string, unknown>): string {
|
|
39
|
+
const { usage: _usage, ...content } = raw;
|
|
40
|
+
return createHash("sha256").update(stableStringify(content)).digest("hex");
|
|
41
|
+
}
|
|
42
|
+
|
|
26
43
|
export function recordRecipeLaunch(path: string, now = new Date()): boolean {
|
|
27
44
|
if (!existsSync(path)) return false;
|
|
28
45
|
try {
|
|
29
46
|
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
30
47
|
if (!isRecord(raw)) return false;
|
|
31
48
|
const usage: RecipeUsageRecord = isRecord(raw.usage) ? raw.usage : {};
|
|
49
|
+
const fingerprint = getRecipeFingerprint(raw);
|
|
50
|
+
const changed = typeof usage.fingerprint === "string" && usage.fingerprint !== fingerprint;
|
|
51
|
+
const nowIso = now.toISOString();
|
|
32
52
|
writeJsonAtomic(path, {
|
|
33
53
|
...raw,
|
|
34
54
|
usage: {
|
|
35
55
|
...usage,
|
|
36
|
-
calls: normalizeCalls(usage.calls) + 1,
|
|
37
|
-
last_called:
|
|
56
|
+
calls: (changed ? 0 : normalizeCalls(usage.calls)) + 1,
|
|
57
|
+
last_called: nowIso,
|
|
58
|
+
fingerprint,
|
|
59
|
+
...(changed ? { reset_at: nowIso } : {}),
|
|
38
60
|
},
|
|
39
61
|
});
|
|
40
62
|
return true;
|
package/package.json
CHANGED
package/skills/actors/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: actors
|
|
3
3
|
description: Highest-density practical guide for pi-actors. Read this skill whenever prompt and tools are not enough for spawn, message, inspect, actor runs, tools, recipes, command templates, async lifecycle, mailboxes, artifacts, and local orchestration mechanics.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.16.
|
|
5
|
+
version: 0.16.4
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Actors (pi-actors)
|
package/skills/swarm/SKILL.md
CHANGED