@llblab/pi-actors 0.48.0 → 0.48.1
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 +4 -0
- package/dist/lib/extension-runtime.js +3 -0
- package/dist/lib/registry.d.ts +2 -0
- package/dist/lib/registry.js +8 -4
- package/dist/lib/tools-local.js +4 -3
- package/dist/lib/tools.d.ts +1 -0
- package/dist/lib/tools.js +1 -0
- package/dist/skills/actors/SKILL.md +1 -1
- package/dist/skills/actors/references/persistent-tools.md +2 -0
- package/docs/tool-registry.md +1 -1
- package/lib/extension-runtime.ts +4 -0
- package/lib/registry.ts +8 -6
- package/lib/tools-local.ts +4 -4
- package/lib/tools.ts +2 -0
- package/package.json +1 -1
- package/skills/actors/SKILL.md +1 -1
- package/skills/actors/references/persistent-tools.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
> Each release keeps at most 8 outcome records of at most 512 characters.
|
|
4
4
|
|
|
5
|
+
## 0.48.1: Persistent Skill Composition
|
|
6
|
+
|
|
7
|
+
- `Persistent Skill Composition`: Made `register_tool from=<skill>/<recipe>` use Pi's authoritative active-session Skill snapshot across every admitted Skill location and activate synchronous or asynchronous tools from the resolved effective contract. Compact user Recipes retain logical delegation without copied contracts, absolute helper paths, symlinks, or ambient runtime re-resolution.
|
|
8
|
+
|
|
5
9
|
## 0.48.0: Host-Coordinated Swarms
|
|
6
10
|
|
|
7
11
|
- `Coordinator And Swarm Methodology`: Defined gatewayless host coordination with companion transports as presence only; the coordinator accepts declarative outcomes, creates explicit Runs, stays available, and owns integration/final validation. Reasoning is role-allocated: bounded authors default off, independent reviewers/integrators use medium, and the coordinator selects evidence-worthy fanout. Swarm retains overhead admission, disjoint ownership, isolation, mutation freeze, and event/timer observation.
|
|
@@ -127,6 +127,9 @@ export function createActorExtensionRuntime(pi) {
|
|
|
127
127
|
Pi.registerToolDefinitions(pi, Tools.createCoreActorToolDefinitions({
|
|
128
128
|
configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
|
|
129
129
|
getActiveTools: () => pi.getActiveTools(),
|
|
130
|
+
getRecipeResolutionContext: () => activeRunContext
|
|
131
|
+
? getRecipeResolutionContext(activeRunContext)
|
|
132
|
+
: undefined,
|
|
130
133
|
getRuntimeTool: (name) => Tools.resolveActiveRuntimeTool(name, runtime.getTools(), (activeName) => actorToolDefinitions.get(activeName)),
|
|
131
134
|
getRuntimeToolStatus: runtime.getToolStatus,
|
|
132
135
|
handleRuntimeControl: automaticReview.handleControl,
|
package/dist/lib/registry.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import * as CommandTemplates from "./command-templates.ts";
|
|
7
7
|
import * as Config from "./config.ts";
|
|
8
|
+
import * as RecipesContext from "./recipes-context.ts";
|
|
8
9
|
export interface RegisterToolInput {
|
|
9
10
|
name?: string;
|
|
10
11
|
description?: string;
|
|
@@ -55,6 +56,7 @@ export interface RegisterToolRuntimeDeps<TContext> {
|
|
|
55
56
|
recipeRoot?: string;
|
|
56
57
|
getToolNameBlocker: (name: string) => string | undefined;
|
|
57
58
|
getTools: () => Map<string, Config.RegisteredTool>;
|
|
59
|
+
getRecipeResolutionContext?: () => RecipesContext.RecipeResolutionContext | undefined;
|
|
58
60
|
getActiveTools: () => string[];
|
|
59
61
|
notify: (ctx: TContext, message: string, type: "info" | "warning" | "error") => void;
|
|
60
62
|
registerRuntimeTool: (cfg: Config.RegisteredTool) => RuntimeActivation | void;
|
package/dist/lib/registry.js
CHANGED
|
@@ -233,9 +233,10 @@ function getInputTemplate(value) {
|
|
|
233
233
|
throw new Error(ExecutionOutput.formatToolText("Tool template must be a string, object, or sequence."));
|
|
234
234
|
}
|
|
235
235
|
function getRegistrationResolutionContext(ctx, deps) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
const runtimeContext = deps.getRecipeResolutionContext?.();
|
|
237
|
+
if (runtimeContext)
|
|
238
|
+
return runtimeContext;
|
|
239
|
+
if (ctx && typeof ctx === "object" && "recipeResolutionContext" in ctx) {
|
|
239
240
|
const resolutionContext = ctx.recipeResolutionContext;
|
|
240
241
|
if (resolutionContext)
|
|
241
242
|
return resolutionContext;
|
|
@@ -415,15 +416,18 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
415
416
|
let persisted = false;
|
|
416
417
|
let activation;
|
|
417
418
|
let cfg;
|
|
419
|
+
let transactionStage = "persist";
|
|
418
420
|
try {
|
|
419
421
|
persistToolRecipe(deps, name, authoredRecipe);
|
|
420
422
|
persisted = true;
|
|
423
|
+
transactionStage = "persisted_admission";
|
|
421
424
|
const admitted = RecipesDiscovery.admitUserRecipe(recipePath, resolutionContext);
|
|
422
425
|
if (!admitted.validated || !admitted.tool) {
|
|
423
426
|
throw new Error(`Persisted tool recipe admission failed: ${admitted.diagnostics.join("; ")}`);
|
|
424
427
|
}
|
|
425
428
|
cfg = admitted.tool;
|
|
426
429
|
tools.set(name, cfg);
|
|
430
|
+
transactionStage = "runtime_activation";
|
|
427
431
|
activation = deps.registerRuntimeTool(cfg) ?? undefined;
|
|
428
432
|
if (activation &&
|
|
429
433
|
(!activation.host_registered ||
|
|
@@ -447,7 +451,7 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
447
451
|
tools.delete(name);
|
|
448
452
|
}
|
|
449
453
|
deps.setActiveTools(activeBefore);
|
|
450
|
-
throw new Error(ExecutionOutput.formatToolText(`Tool registration transaction failed: ${error instanceof Error ? error.message : String(error)}`));
|
|
454
|
+
throw new Error(ExecutionOutput.formatToolText(`Tool registration transaction failed at ${transactionStage} (${resolutionContext.generation}; active Skills: ${activeSkillSummary(resolutionContext)}): ${error instanceof Error ? error.message : String(error)}`));
|
|
451
455
|
}
|
|
452
456
|
deps.notify(ctx, `Tool activated: ${name}`, "info");
|
|
453
457
|
const templateWarnings = CommandTemplates.getCommandTemplateWarnings(typeof cfg.recipe?.template === "object" && !Array.isArray(cfg.recipe.template)
|
package/dist/lib/tools-local.js
CHANGED
|
@@ -93,8 +93,9 @@ export function createRuntimeToolDefinition(cfg, exec) {
|
|
|
93
93
|
const paramSchema = {};
|
|
94
94
|
const required = [];
|
|
95
95
|
const isRecipe = RecipesReferences.isRecipeTool(cfg.template, cfg.recipe);
|
|
96
|
-
const isAsyncRecipe = cfg.recipe
|
|
97
|
-
|
|
96
|
+
const isAsyncRecipe = cfg.recipe
|
|
97
|
+
? cfg.recipe.async === true
|
|
98
|
+
: RecipesReferences.isAsyncRecipeReference(cfg.template);
|
|
98
99
|
const recipeTemplate = cfg.recipe?.template ?? RecipesReferences.getRecipeTemplate(cfg.template);
|
|
99
100
|
const requiredTemplate = recipeTemplate ?? cfg.template;
|
|
100
101
|
const requiredTemplateConfig = typeof requiredTemplate === "object" && !Array.isArray(requiredTemplate)
|
|
@@ -112,7 +113,7 @@ export function createRuntimeToolDefinition(cfg, exec) {
|
|
|
112
113
|
const requiredArgs = isRecipe && cfg.storedArgs !== undefined
|
|
113
114
|
? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg) &&
|
|
114
115
|
!Object.hasOwn(recipeInlineDefaults, arg)))
|
|
115
|
-
: RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
|
|
116
|
+
: !cfg.recipe && RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
|
|
116
117
|
? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg)))
|
|
117
118
|
: Schema.getRequiredToolArgNames(requiredTemplateConfig);
|
|
118
119
|
for (const arg of cfg.args) {
|
package/dist/lib/tools.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface ActorToolDefinition {
|
|
|
14
14
|
export interface CoreActorToolDefinitionDeps<TContext extends RuntimeToolContext> {
|
|
15
15
|
configPath: string;
|
|
16
16
|
getActiveTools: () => string[];
|
|
17
|
+
getRecipeResolutionContext: () => import("./recipes-context.ts").RecipeResolutionContext | undefined;
|
|
17
18
|
getRuntimeTool: (name: string) => unknown;
|
|
18
19
|
getRuntimeToolStatus: (name: string) => Record<string, unknown> | undefined;
|
|
19
20
|
handleRuntimeControl?: (action: string, input: unknown) => Record<string, unknown>;
|
package/dist/lib/tools.js
CHANGED
|
@@ -30,6 +30,7 @@ export function createCoreActorToolDefinitions(deps) {
|
|
|
30
30
|
getActiveTools: deps.getActiveTools,
|
|
31
31
|
getToolNameBlocker: deps.registryRuntime.getToolNameBlocker,
|
|
32
32
|
getTools: deps.registryRuntime.getTools,
|
|
33
|
+
getRecipeResolutionContext: deps.getRecipeResolutionContext,
|
|
33
34
|
notify: deps.registryRuntime.notify,
|
|
34
35
|
registerRuntimeTool: deps.registryRuntime.registerRuntimeTool,
|
|
35
36
|
reservedToolNames: RESERVED_TOOL_NAMES,
|
|
@@ -52,7 +52,7 @@ direct delegation ≠ named import composition
|
|
|
52
52
|
Run Control ≠ actor chat
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
A Skill Recipe is a maintained component addressed by `<skill>/<recipe>`. `spawn` creates a Run from a Recipe. `register_tool
|
|
55
|
+
A Skill Recipe is a maintained component addressed by `<skill>/<recipe>`. `spawn` creates a Run from a Recipe. `register_tool from=<skill>/<recipe>` persists compact logical delegation and activates from the resolved effective contract without copying, symlinking, or ambient re-resolution. A tool is callable in the current session only when activation evidence says `callable_now: true`.
|
|
56
56
|
|
|
57
57
|
`actors` owns generic Recipe/tool/Run mechanics. The owning capability Skill owns capability-specific selection and constraints. `swarm` owns multi-actor decomposition and integration methodology.
|
|
58
58
|
|
|
@@ -28,6 +28,8 @@ register_tool
|
|
|
28
28
|
|
|
29
29
|
`from` means logical direct delegation. The source remains authoritative for async behavior, caller args and types, source defaults, artifacts, Control, and runtime-owned origins. The persistent user Recipe stores only the compact specialization; do not copy inherited fields.
|
|
30
30
|
|
|
31
|
+
Resolution uses Pi's authoritative active-session Skill snapshot across every Skill location Pi admits. Registration resolves and validates the maintained source, persists only its logical `<skill>/<recipe>` reference plus caller specialization, and projects the already-resolved effective contract into the runtime tool. Never replace this composition with a copied Recipe, absolute helper path, symlink, or ambient runtime re-resolution.
|
|
32
|
+
|
|
31
33
|
Use `description` to narrow agent-facing intent when useful. Every supplied default must name a caller-owned source arg and satisfy its type or enum. Never default runtime-owned origins.
|
|
32
34
|
|
|
33
35
|
## Prove registration
|
package/docs/tool-registry.md
CHANGED
|
@@ -73,7 +73,7 @@ Usage and lineage live in locked metadata ledgers rather than authored Recipe fi
|
|
|
73
73
|
|
|
74
74
|
## Specializing Existing Recipes
|
|
75
75
|
|
|
76
|
-
Use `register_tool from=<skill>/<recipe> defaults={...}` for one maintained capability under a persistent name or narrower defaults.
|
|
76
|
+
Use `register_tool from=<skill>/<recipe> defaults={...}` for one maintained capability under a persistent name or narrower defaults. Pi supplies one authoritative active-session Skill snapshot across global, project, package, settings, CLI, and extension-contributed locations. Registration resolves the source from that snapshot, stores only the logical direct-delegation reference plus caller specialization, and activates the tool from the already-resolved effective contract without ambient re-resolution. It does not copy async, args/types, Control, artifacts, helpers, or runtime-owned `{recipe_dir}`/`{skill_dir}`; symlinks and absolute helper paths are not substitutes. Named imports remain for multi-node Recipe composition, not one-source specialization. Skill Recipes remain components and are never exposed merely because their Skill is active. Install only specific capabilities; internal automatic-review Recipes must not become user-callable tools.
|
|
77
77
|
|
|
78
78
|
## Safety
|
|
79
79
|
|
package/lib/extension-runtime.ts
CHANGED
|
@@ -160,6 +160,10 @@ export function createActorExtensionRuntime(
|
|
|
160
160
|
Tools.createCoreActorToolDefinitions<Pi.ExtensionContext>({
|
|
161
161
|
configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
|
|
162
162
|
getActiveTools: () => pi.getActiveTools(),
|
|
163
|
+
getRecipeResolutionContext: () =>
|
|
164
|
+
activeRunContext
|
|
165
|
+
? getRecipeResolutionContext(activeRunContext)
|
|
166
|
+
: undefined,
|
|
163
167
|
getRuntimeTool: (name) =>
|
|
164
168
|
Tools.resolveActiveRuntimeTool(
|
|
165
169
|
name,
|
package/lib/registry.ts
CHANGED
|
@@ -73,6 +73,7 @@ export interface RegisterToolRuntimeDeps<TContext> {
|
|
|
73
73
|
recipeRoot?: string;
|
|
74
74
|
getToolNameBlocker: (name: string) => string | undefined;
|
|
75
75
|
getTools: () => Map<string, Config.RegisteredTool>;
|
|
76
|
+
getRecipeResolutionContext?: () => RecipesContext.RecipeResolutionContext | undefined;
|
|
76
77
|
getActiveTools: () => string[];
|
|
77
78
|
notify: (
|
|
78
79
|
ctx: TContext,
|
|
@@ -422,11 +423,9 @@ function getRegistrationResolutionContext<TContext>(
|
|
|
422
423
|
ctx: TContext,
|
|
423
424
|
deps: RegisterToolRuntimeDeps<TContext>,
|
|
424
425
|
): RecipesContext.RecipeResolutionContext {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
"recipeResolutionContext" in ctx
|
|
429
|
-
) {
|
|
426
|
+
const runtimeContext = deps.getRecipeResolutionContext?.();
|
|
427
|
+
if (runtimeContext) return runtimeContext;
|
|
428
|
+
if (ctx && typeof ctx === "object" && "recipeResolutionContext" in ctx) {
|
|
430
429
|
const resolutionContext = (ctx as {
|
|
431
430
|
recipeResolutionContext?: RecipesContext.RecipeResolutionContext;
|
|
432
431
|
}).recipeResolutionContext;
|
|
@@ -697,9 +696,11 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
697
696
|
let persisted = false;
|
|
698
697
|
let activation: RuntimeActivation | undefined;
|
|
699
698
|
let cfg: Config.RegisteredTool;
|
|
699
|
+
let transactionStage = "persist";
|
|
700
700
|
try {
|
|
701
701
|
persistToolRecipe(deps, name, authoredRecipe);
|
|
702
702
|
persisted = true;
|
|
703
|
+
transactionStage = "persisted_admission";
|
|
703
704
|
const admitted = RecipesDiscovery.admitUserRecipe(
|
|
704
705
|
recipePath,
|
|
705
706
|
resolutionContext,
|
|
@@ -711,6 +712,7 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
711
712
|
}
|
|
712
713
|
cfg = admitted.tool;
|
|
713
714
|
tools.set(name, cfg);
|
|
715
|
+
transactionStage = "runtime_activation";
|
|
714
716
|
activation = deps.registerRuntimeTool(cfg) ?? undefined;
|
|
715
717
|
if (
|
|
716
718
|
activation &&
|
|
@@ -737,7 +739,7 @@ function executeRegisterToolUnlocked<TContext>(
|
|
|
737
739
|
deps.setActiveTools(activeBefore);
|
|
738
740
|
throw new Error(
|
|
739
741
|
ExecutionOutput.formatToolText(
|
|
740
|
-
`Tool registration transaction failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
742
|
+
`Tool registration transaction failed at ${transactionStage} (${resolutionContext.generation}; active Skills: ${activeSkillSummary(resolutionContext)}): ${error instanceof Error ? error.message : String(error)}`,
|
|
741
743
|
),
|
|
742
744
|
);
|
|
743
745
|
}
|
package/lib/tools-local.ts
CHANGED
|
@@ -147,9 +147,9 @@ export function createRuntimeToolDefinition(
|
|
|
147
147
|
const paramSchema: Record<string, JsonSchema> = {};
|
|
148
148
|
const required: string[] = [];
|
|
149
149
|
const isRecipe = RecipesReferences.isRecipeTool(cfg.template, cfg.recipe);
|
|
150
|
-
const isAsyncRecipe =
|
|
151
|
-
cfg.recipe
|
|
152
|
-
RecipesReferences.isAsyncRecipeReference(cfg.template);
|
|
150
|
+
const isAsyncRecipe = cfg.recipe
|
|
151
|
+
? cfg.recipe.async === true
|
|
152
|
+
: RecipesReferences.isAsyncRecipeReference(cfg.template);
|
|
153
153
|
const recipeTemplate =
|
|
154
154
|
cfg.recipe?.template ?? RecipesReferences.getRecipeTemplate(cfg.template);
|
|
155
155
|
const requiredTemplate = recipeTemplate ?? cfg.template!;
|
|
@@ -177,7 +177,7 @@ export function createRuntimeToolDefinition(
|
|
|
177
177
|
!Object.hasOwn(recipeInlineDefaults, arg),
|
|
178
178
|
),
|
|
179
179
|
)
|
|
180
|
-
: RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
|
|
180
|
+
: !cfg.recipe && RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
|
|
181
181
|
? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg)))
|
|
182
182
|
: Schema.getRequiredToolArgNames(requiredTemplateConfig);
|
|
183
183
|
for (const arg of cfg.args) {
|
package/lib/tools.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface CoreActorToolDefinitionDeps<
|
|
|
24
24
|
> {
|
|
25
25
|
configPath: string;
|
|
26
26
|
getActiveTools: () => string[];
|
|
27
|
+
getRecipeResolutionContext: () => import("./recipes-context.ts").RecipeResolutionContext | undefined;
|
|
27
28
|
getRuntimeTool: (name: string) => unknown;
|
|
28
29
|
getRuntimeToolStatus: (name: string) => Record<string, unknown> | undefined;
|
|
29
30
|
handleRuntimeControl?: (
|
|
@@ -68,6 +69,7 @@ export function createCoreActorToolDefinitions<
|
|
|
68
69
|
getActiveTools: deps.getActiveTools,
|
|
69
70
|
getToolNameBlocker: deps.registryRuntime.getToolNameBlocker,
|
|
70
71
|
getTools: deps.registryRuntime.getTools,
|
|
72
|
+
getRecipeResolutionContext: deps.getRecipeResolutionContext,
|
|
71
73
|
notify: deps.registryRuntime.notify,
|
|
72
74
|
registerRuntimeTool: deps.registryRuntime.registerRuntimeTool,
|
|
73
75
|
reservedToolNames: RESERVED_TOOL_NAMES,
|
package/package.json
CHANGED
package/skills/actors/SKILL.md
CHANGED
|
@@ -52,7 +52,7 @@ direct delegation ≠ named import composition
|
|
|
52
52
|
Run Control ≠ actor chat
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
A Skill Recipe is a maintained component addressed by `<skill>/<recipe>`. `spawn` creates a Run from a Recipe. `register_tool
|
|
55
|
+
A Skill Recipe is a maintained component addressed by `<skill>/<recipe>`. `spawn` creates a Run from a Recipe. `register_tool from=<skill>/<recipe>` persists compact logical delegation and activates from the resolved effective contract without copying, symlinking, or ambient re-resolution. A tool is callable in the current session only when activation evidence says `callable_now: true`.
|
|
56
56
|
|
|
57
57
|
`actors` owns generic Recipe/tool/Run mechanics. The owning capability Skill owns capability-specific selection and constraints. `swarm` owns multi-actor decomposition and integration methodology.
|
|
58
58
|
|
|
@@ -28,6 +28,8 @@ register_tool
|
|
|
28
28
|
|
|
29
29
|
`from` means logical direct delegation. The source remains authoritative for async behavior, caller args and types, source defaults, artifacts, Control, and runtime-owned origins. The persistent user Recipe stores only the compact specialization; do not copy inherited fields.
|
|
30
30
|
|
|
31
|
+
Resolution uses Pi's authoritative active-session Skill snapshot across every Skill location Pi admits. Registration resolves and validates the maintained source, persists only its logical `<skill>/<recipe>` reference plus caller specialization, and projects the already-resolved effective contract into the runtime tool. Never replace this composition with a copied Recipe, absolute helper path, symlink, or ambient runtime re-resolution.
|
|
32
|
+
|
|
31
33
|
Use `description` to narrow agent-facing intent when useful. Every supplied default must name a caller-owned source arg and satisfy its type or enum. Never default runtime-owned origins.
|
|
32
34
|
|
|
33
35
|
## Prove registration
|