@llblab/pi-actors 0.58.0 → 0.58.2
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/AGENTS.md +5 -5
- package/BACKLOG.md +1 -1
- package/CHANGELOG.md +12 -1
- package/README.md +37 -35
- package/dist/lib/draft-sleep.js +3 -3
- package/dist/lib/extension-runtime.js +7 -2
- package/dist/lib/pi.js +1 -1
- package/dist/lib/prompts.d.ts +3 -3
- package/dist/lib/prompts.js +10 -9
- package/dist/lib/recipes-references.js +7 -7
- package/dist/lib/registry.js +27 -24
- package/dist/lib/review-control.js +1 -1
- package/dist/lib/run-delivery.d.ts +1 -1
- package/dist/lib/run-delivery.js +19 -9
- package/dist/lib/run-evidence-policy.js +2 -2
- package/dist/lib/runtime.d.ts +3 -0
- package/dist/lib/runtime.js +24 -10
- package/dist/lib/tool-review-scheduler.js +7 -7
- package/dist/lib/tools-access.js +1 -1
- package/dist/lib/tools-inspect.js +10 -10
- package/dist/lib/tools-message.d.ts +1 -1
- package/dist/lib/tools-message.js +10 -10
- package/dist/lib/tools-register.d.ts +3 -3
- package/dist/lib/tools-register.js +4 -4
- package/dist/lib/tools-response.d.ts +1 -1
- package/dist/lib/tools-response.js +27 -28
- package/dist/lib/tools-spawn.js +1 -1
- package/dist/lib/tools.d.ts +7 -0
- package/dist/lib/tools.js +25 -0
- package/dist/skills/actors/SKILL.md +29 -21
- package/dist/skills/actors/references/diagnostics.md +11 -11
- package/dist/skills/actors/references/persistent-tools.md +19 -15
- package/dist/skills/actors/references/recipes.md +1 -1
- package/dist/skills/actors/references/runs.md +8 -8
- package/dist/skills/music-player/SKILL.md +4 -4
- package/dist/skills/music-player/scripts/playback.mjs +1 -1
- package/dist/skills/recipe-memory/SKILL.md +7 -7
- package/docs/README.md +2 -2
- package/docs/actor-inspector.md +1 -1
- package/docs/agent-experience.md +5 -6
- package/docs/async-runs.md +13 -13
- package/docs/capability-memory.md +11 -56
- package/docs/coordinator-delivery.md +2 -2
- package/docs/inspection.md +21 -21
- package/docs/output-projection-map.md +1 -1
- package/docs/releasing.md +1 -1
- package/docs/run-supervision.md +21 -21
- package/docs/tool-registry.md +46 -21
- package/docs/windows-process-observation.md +1 -1
- package/lib/draft-sleep.ts +3 -3
- package/lib/extension-runtime.ts +7 -5
- package/lib/pi.ts +1 -1
- package/lib/prompts.ts +10 -9
- package/lib/recipes-references.ts +7 -7
- package/lib/registry.ts +26 -24
- package/lib/review-control.ts +1 -1
- package/lib/run-delivery.ts +22 -11
- package/lib/run-evidence-policy.ts +2 -2
- package/lib/runtime.ts +26 -11
- package/lib/tool-review-scheduler.ts +7 -7
- package/lib/tools-access.ts +1 -1
- package/lib/tools-inspect.ts +10 -10
- package/lib/tools-message.ts +10 -10
- package/lib/tools-register.ts +4 -4
- package/lib/tools-response.ts +25 -25
- package/lib/tools-spawn.ts +1 -1
- package/lib/tools.ts +28 -0
- package/package.json +1 -1
- package/skills/actors/SKILL.md +29 -21
- package/skills/actors/references/diagnostics.md +11 -11
- package/skills/actors/references/persistent-tools.md +19 -15
- package/skills/actors/references/recipes.md +1 -1
- package/skills/actors/references/runs.md +8 -8
- package/skills/music-player/SKILL.md +4 -4
- package/skills/music-player/scripts/playback.mjs +1 -1
- package/skills/recipe-memory/SKILL.md +7 -7
package/dist/lib/registry.js
CHANGED
|
@@ -43,7 +43,7 @@ function listTools(deps) {
|
|
|
43
43
|
content: [
|
|
44
44
|
textContent(ExecutionOutput.formatToolText(registryListText(rows))),
|
|
45
45
|
],
|
|
46
|
-
details: { tool: "
|
|
46
|
+
details: { tool: "actors_tool_register" },
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
function getRecipeRoot(deps) {
|
|
@@ -65,18 +65,18 @@ function activationBoundary(activation) {
|
|
|
65
65
|
}
|
|
66
66
|
function recipeDoctorAction(source) {
|
|
67
67
|
return /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*\/[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u.test(source)
|
|
68
|
-
? `
|
|
69
|
-
: "
|
|
68
|
+
? `actors_inspect target=recipes view=doctor identity=${source}`
|
|
69
|
+
: "actors_inspect target=recipes view=doctor";
|
|
70
70
|
}
|
|
71
71
|
function registrationNextActions(tool, source, callableNow) {
|
|
72
72
|
if (callableNow) {
|
|
73
73
|
return [
|
|
74
74
|
`call tool ${tool}`,
|
|
75
|
-
`
|
|
75
|
+
`actors_inspect target=tool:${tool} view=status`,
|
|
76
76
|
];
|
|
77
77
|
}
|
|
78
78
|
return [
|
|
79
|
-
`
|
|
79
|
+
`actors_inspect target=tool:${tool} view=status`,
|
|
80
80
|
...(source === "template" || source === "draft"
|
|
81
81
|
? []
|
|
82
82
|
: [recipeDoctorAction(source)]),
|
|
@@ -134,7 +134,7 @@ function registrationReceiptText(data) {
|
|
|
134
134
|
const omittedNext = omission("next_action", 1, !nextWellFormed);
|
|
135
135
|
// This producer knows only its existing status hint; invocation advice stays opaque.
|
|
136
136
|
const next = part(nextWellFormed
|
|
137
|
-
? data.callable ? { instruction: data.next } : { next: { tool: "
|
|
137
|
+
? data.callable ? { instruction: data.next } : { next: { tool: "actors_inspect", target: `tool:${data.tool}`, view: "status" } }
|
|
138
138
|
: omittedNext, omittedNext);
|
|
139
139
|
const render = () => renderPart({ ...tool.selected, result: data.result, ...source.selected, callable_now: data.callable,
|
|
140
140
|
...(data.boundary === undefined ? {} : { activation_boundary: data.boundary }), ...required.selected, ...optional.selected,
|
|
@@ -195,7 +195,7 @@ function draftPathFailureText(kind, reference) {
|
|
|
195
195
|
const selected = registrySelected(kind === "root" ? "allowed_root" : "path", reference);
|
|
196
196
|
const render = () => ({ field: "draft", ...selected.selected,
|
|
197
197
|
result: kind === "root" ? "Draft must be under the allowed root." : "Draft not found.",
|
|
198
|
-
...(kind === "root" ? { instruction: "Use
|
|
198
|
+
...(kind === "root" ? { instruction: "Use actors_inspect target=recipes view=summary to list drafts." } : {}) });
|
|
199
199
|
return growRegistryDocument(render, [selected]);
|
|
200
200
|
}
|
|
201
201
|
function assertDraftPath(deps, draft) {
|
|
@@ -226,8 +226,8 @@ function draftReceiptText(result, tool, callable, next) {
|
|
|
226
226
|
const identity = part("tool", tool, { tool });
|
|
227
227
|
const flag = part("callable_now", callable, { callable_now: callable });
|
|
228
228
|
// Only this producer's exact canonical read-only status hint is typed, never body advice.
|
|
229
|
-
const status = /^
|
|
230
|
-
const hint = part("next_action", next, status ? { next: { tool: "
|
|
229
|
+
const status = /^actors_inspect target=(tool:[a-z][a-z0-9_]{0,63}) view=status$/u.exec(next);
|
|
230
|
+
const hint = part("next_action", next, status ? { next: { tool: "actors_inspect", target: status[1], view: "status" } } : { instruction: next });
|
|
231
231
|
const render = () => renderPart({ ...identity.selected, result, source: "draft", ...flag.selected, ...hint.selected });
|
|
232
232
|
for (const current of [identity, flag, hint]) {
|
|
233
233
|
if (current.selected === current.full)
|
|
@@ -341,6 +341,9 @@ function deleteTool(name, ctx, deps) {
|
|
|
341
341
|
details: { tool: name },
|
|
342
342
|
};
|
|
343
343
|
}
|
|
344
|
+
const blocker = deps.getToolNameBlocker(name);
|
|
345
|
+
if (blocker)
|
|
346
|
+
throw new Error(ExecutionOutput.formatToolText(blocker));
|
|
344
347
|
const recipePath = getToolRecipePath(deps, name);
|
|
345
348
|
if (existsSync(recipePath))
|
|
346
349
|
unlinkSync(recipePath);
|
|
@@ -390,7 +393,7 @@ function assertTemplateIsNotNestedRecipe(value) {
|
|
|
390
393
|
(Object.keys(record).length === 1 ||
|
|
391
394
|
["artifacts", "async", "control", "description", "imports", "values"].some((key) => Object.hasOwn(record, key)))) {
|
|
392
395
|
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "template",
|
|
393
|
-
result: "Nested Recipe-shaped templates are not a
|
|
396
|
+
result: "Nested Recipe-shaped templates are not a actors_tool_register source mode.",
|
|
394
397
|
instruction: "retry with from=<skill>/<recipe> and defaults={...}." })));
|
|
395
398
|
}
|
|
396
399
|
}
|
|
@@ -437,7 +440,7 @@ function normalizeDefaults(value) {
|
|
|
437
440
|
function normalizeFromReference(value, resolutionContext) {
|
|
438
441
|
const trimmed = value.trim();
|
|
439
442
|
if (!trimmed) {
|
|
440
|
-
throw new Error(ExecutionOutput.formatToolText("Tool from must be a non-empty Recipe reference. Next: retry
|
|
443
|
+
throw new Error(ExecutionOutput.formatToolText("Tool from must be a non-empty Recipe reference. Next: retry actors_tool_register with from=<skill>/<recipe> or an explicit .json/.md path."));
|
|
441
444
|
}
|
|
442
445
|
if (trimmed.startsWith("std:")) {
|
|
443
446
|
throw new Error(ExecutionOutput.formatToolText("std: Recipe references were removed; use <skill>/<recipe> or an explicit .json/.md file path."));
|
|
@@ -472,7 +475,7 @@ function buildAuthoredRecipe(input, existing, existingRecipe) {
|
|
|
472
475
|
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "defaults",
|
|
473
476
|
...registrySelected("key", runtimeOwnedDefault).selected,
|
|
474
477
|
result: "Tool defaults cannot set runtime-owned input.",
|
|
475
|
-
instruction: "remove that default and retry
|
|
478
|
+
instruction: "remove that default and retry actors_tool_register; the runtime supplies it." })));
|
|
476
479
|
}
|
|
477
480
|
const authored = {
|
|
478
481
|
...(description ? { description } : {}),
|
|
@@ -522,9 +525,9 @@ function buildAuthoredRecipe(input, existing, existingRecipe) {
|
|
|
522
525
|
function assertRegisterToolInputModes(input) {
|
|
523
526
|
const record = input;
|
|
524
527
|
if (Object.hasOwn(record, "values")) {
|
|
525
|
-
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "values", result: "
|
|
528
|
+
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "values", result: "actors_tool_register values was removed.",
|
|
526
529
|
replacement_fields: ["defaults", "from"],
|
|
527
|
-
instruction: "retry
|
|
530
|
+
instruction: "retry actors_tool_register with defaults for caller inputs, or use from=<skill>/<recipe> for maintained composition." })));
|
|
528
531
|
}
|
|
529
532
|
const fromProvided = Object.hasOwn(record, "from");
|
|
530
533
|
if (fromProvided &&
|
|
@@ -532,22 +535,22 @@ function assertRegisterToolInputModes(input) {
|
|
|
532
535
|
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "from",
|
|
533
536
|
result: "Tool from must be a non-empty Recipe reference.",
|
|
534
537
|
reference_forms: ["<skill>/<recipe>", "explicit .json path", "explicit .md path"],
|
|
535
|
-
instruction: "retry
|
|
538
|
+
instruction: "retry actors_tool_register with from=<skill>/<recipe> or an explicit .json/.md path." })));
|
|
536
539
|
}
|
|
537
540
|
const draftProvided = typeof input.draft === "string" && input.draft.trim().length > 0;
|
|
538
541
|
const templateProvided = Object.hasOwn(record, "template");
|
|
539
542
|
const modeCount = Number(fromProvided) + Number(draftProvided) + Number(templateProvided);
|
|
540
543
|
if (modeCount > 1) {
|
|
541
|
-
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ result: "Use exactly one
|
|
544
|
+
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ result: "Use exactly one actors_tool_register source mode.",
|
|
542
545
|
source_modes: ["from", "template", "draft"],
|
|
543
|
-
instruction: "remove the extra source fields and retry
|
|
546
|
+
instruction: "remove the extra source fields and retry actors_tool_register." })));
|
|
544
547
|
}
|
|
545
548
|
if (fromProvided &&
|
|
546
549
|
(Object.hasOwn(record, "args") || Object.hasOwn(record, "async"))) {
|
|
547
550
|
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ field: "from",
|
|
548
|
-
result: "
|
|
551
|
+
result: "actors_tool_register from inherits args and async behavior.",
|
|
549
552
|
inherited_fields: ["args", "async"],
|
|
550
|
-
instruction: "retry
|
|
553
|
+
instruction: "retry actors_tool_register with from and optional defaults only; omit args and async." })));
|
|
551
554
|
}
|
|
552
555
|
}
|
|
553
556
|
function reservedRegistrationNameText(value) {
|
|
@@ -613,7 +616,7 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
613
616
|
if (template === undefined && !input.from && !existing) {
|
|
614
617
|
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ result: "New registration requires exactly one source mode.",
|
|
615
618
|
source_modes: ["from", "template", "draft"],
|
|
616
|
-
instruction: "retry
|
|
619
|
+
instruction: "retry actors_tool_register with one source field." })));
|
|
617
620
|
}
|
|
618
621
|
const recipePath = getToolRecipePath(deps, name);
|
|
619
622
|
const authoredRecipe = buildAuthoredRecipe(input, existing, authoritative.recipe);
|
|
@@ -645,7 +648,7 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
|
|
|
645
648
|
(!activation.host_registered ||
|
|
646
649
|
!activation.active_tool ||
|
|
647
650
|
!activation.callable_now)) {
|
|
648
|
-
throw new Error(`Tool "${name}" activation failed at ${activationBoundary(activation)}; host_registered=${activation.host_registered}, active_tool=${activation.active_tool}, callable_now=${activation.callable_now}. Registration was rolled back. Next:
|
|
651
|
+
throw new Error(`Tool "${name}" activation failed at ${activationBoundary(activation)}; host_registered=${activation.host_registered}, active_tool=${activation.active_tool}, callable_now=${activation.callable_now}. Registration was rolled back. Next: actors_inspect target=runtime view=status; do not use spawn as proof of tool invocation.`);
|
|
649
652
|
}
|
|
650
653
|
}
|
|
651
654
|
catch (error) {
|
|
@@ -872,11 +875,11 @@ function retainRecipe(input, ctx, deps) {
|
|
|
872
875
|
const facts = { kind: "retained_recipe", result: "retained", persisted: true, resolved: true,
|
|
873
876
|
validated: true, activation: "not_requested", async: admitted.async };
|
|
874
877
|
const text = growRegistryDocument(() => ({ ...selectedName.selected, ...facts, ...recipe.selected, ...selectedSource.selected,
|
|
875
|
-
...required.selected, ...optional.selected, next: { tool: "
|
|
878
|
+
...required.selected, ...optional.selected, next: { tool: "actors_inspect", target: "recipes", view: "summary", verbose: true } }), [recipe, selectedName, selectedSource, required, optional]);
|
|
876
879
|
const result = {
|
|
877
880
|
content: [textContent(ExecutionOutput.formatToolText(text))],
|
|
878
881
|
details: { ...facts, tool: name, recipe: path, source, required_args: args.required, optional_args: args.optional,
|
|
879
|
-
next_actions: ["
|
|
882
|
+
next_actions: ["actors_inspect target=recipes view=summary verbose=true"] },
|
|
880
883
|
};
|
|
881
884
|
stage = "release";
|
|
882
885
|
return result;
|
|
@@ -888,7 +891,7 @@ function retainRecipe(input, ctx, deps) {
|
|
|
888
891
|
const reason = error instanceof RetainedRecipeRefusal ? { reason: error.reason } : {};
|
|
889
892
|
throw new Error(ExecutionOutput.formatToolText(registryMetadataText({ operation: "retain", stage, result: "unconfirmed",
|
|
890
893
|
effects: "unknown; inspect retained inventory before retry", ...reason,
|
|
891
|
-
next: { tool: "
|
|
894
|
+
next: { tool: "actors_inspect", target: "recipes", view: "summary", verbose: true } })), { cause: error });
|
|
892
895
|
}
|
|
893
896
|
}
|
|
894
897
|
export async function executeRegisterTool(params, ctx, deps) {
|
|
@@ -90,7 +90,7 @@ export function controlAutomaticReview(action, scope, options = {}) {
|
|
|
90
90
|
});
|
|
91
91
|
if (result.changed === true)
|
|
92
92
|
schedule(scope, options);
|
|
93
|
-
const nextActions = ["
|
|
93
|
+
const nextActions = ["actors_inspect target=recipes view=reviews"];
|
|
94
94
|
if (action === "review.retry" &&
|
|
95
95
|
scope === "tool" &&
|
|
96
96
|
(result.phase === "approved" || result.phase === "lineage_pending"))
|
|
@@ -66,7 +66,7 @@ export interface RunCompletionBatch {
|
|
|
66
66
|
/** Retained singleton capture; absence preserves older indexed bytes. Never a new-capture selector. */
|
|
67
67
|
readonly single_result?: true;
|
|
68
68
|
/** Captured record-list shape; no public format/version choice or source authority. */
|
|
69
|
-
readonly result_layout?: "records" | "run_headers" | "headings" | "headings_flat_omissions" | "headings_outcomes" | "headings_shared_results" | "headings_shared_kinds" | "frontmatter_v1" | "frontmatter_v2" | "completion_yaml_core_v1" | "completion_yaml_files_v1";
|
|
69
|
+
readonly result_layout?: "records" | "run_headers" | "headings" | "headings_flat_omissions" | "headings_outcomes" | "headings_shared_results" | "headings_shared_kinds" | "frontmatter_v1" | "frontmatter_v2" | "completion_yaml_core_v1" | "completion_yaml_files_v1" | "completion_yaml_files_v2";
|
|
70
70
|
/** Immutable scope/order/range data, not a caller-selected format or allocation authority. */
|
|
71
71
|
readonly numbering?: RunCompletionNumbering;
|
|
72
72
|
/** Formatting version/data only; no recipient ownership, read or publication capability. */
|
package/dist/lib/run-delivery.js
CHANGED
|
@@ -278,8 +278,11 @@ function parseInventorySource(value, batch) {
|
|
|
278
278
|
function isFrontmatterCompletionLayout(layout) {
|
|
279
279
|
return layout === "frontmatter_v1" || layout === "frontmatter_v2";
|
|
280
280
|
}
|
|
281
|
+
function isRootedCompletionLayout(layout) {
|
|
282
|
+
return layout === "completion_yaml_files_v1" || layout === "completion_yaml_files_v2";
|
|
283
|
+
}
|
|
281
284
|
function isYamlCompletionLayout(layout) {
|
|
282
|
-
return layout === "completion_yaml_core_v1" || layout
|
|
285
|
+
return layout === "completion_yaml_core_v1" || isRootedCompletionLayout(layout);
|
|
283
286
|
}
|
|
284
287
|
function isSharedCompletionLayout(layout) {
|
|
285
288
|
return layout === "headings_shared_results" || layout === "headings_shared_kinds" || isYamlCompletionLayout(layout) || isFrontmatterCompletionLayout(layout);
|
|
@@ -688,7 +691,7 @@ export function requestRunCompletionStream(input) {
|
|
|
688
691
|
});
|
|
689
692
|
}
|
|
690
693
|
export function admitRunCompletionBatch(input) {
|
|
691
|
-
return captureCompletionBatch(input, false, "
|
|
694
|
+
return captureCompletionBatch(input, false, "completion_yaml_files_v2");
|
|
692
695
|
}
|
|
693
696
|
/** Kernel-only opt-in; ordinary Pi capture stays fenced until session/lifecycle integration is admitted. */
|
|
694
697
|
export function captureRunCompletionStreamBatch(input) {
|
|
@@ -696,7 +699,7 @@ export function captureRunCompletionStreamBatch(input) {
|
|
|
696
699
|
}
|
|
697
700
|
/** Private ordinary candidate composition; stream capture retains its separately gated codec. */
|
|
698
701
|
export function captureRunCompletionYamlCandidateBatch(input) {
|
|
699
|
-
return captureCompletionBatch(input, false, "
|
|
702
|
+
return captureCompletionBatch(input, false, "completion_yaml_files_v2");
|
|
700
703
|
}
|
|
701
704
|
function captureCompletionBatch(input, numbered, layout = "frontmatter_v2") {
|
|
702
705
|
const now = (input.now ?? new Date()).toISOString();
|
|
@@ -1697,13 +1700,14 @@ function completionRootedFiles(row, member, locations) {
|
|
|
1697
1700
|
}
|
|
1698
1701
|
function prepareCompletionYamlProjection(safe, candidates, references, ordered) {
|
|
1699
1702
|
const packet = { batchId: safe.batch_id, records: [] };
|
|
1700
|
-
const rooted = safe.result_layout
|
|
1703
|
+
const rooted = isRootedCompletionLayout(safe.result_layout);
|
|
1704
|
+
const localSingleton = safe.result_layout === "completion_yaml_files_v2" && !safe.numbering && candidates.length === 1;
|
|
1701
1705
|
if (!safe.batch_id.isWellFormed())
|
|
1702
1706
|
return { state: "unsupported" };
|
|
1703
1707
|
for (const [index, { row, location }] of candidates.entries()) {
|
|
1704
1708
|
const member = ordered[index];
|
|
1705
1709
|
const displayed = safe.numbering ? safe.numbering.kind === "stream" ? safe.numbering.first_index + index : "?" : index;
|
|
1706
|
-
const metadata = { index: displayed };
|
|
1710
|
+
const metadata = localSingleton ? {} : { index: displayed };
|
|
1707
1711
|
for (const piece of row.pieces) {
|
|
1708
1712
|
if (piece.block)
|
|
1709
1713
|
continue;
|
|
@@ -1763,7 +1767,9 @@ function prepareCompletionYamlProjection(safe, candidates, references, ordered)
|
|
|
1763
1767
|
}
|
|
1764
1768
|
packet.records.push({ metadata, parts });
|
|
1765
1769
|
}
|
|
1766
|
-
const service = rooted ? {
|
|
1770
|
+
const service = rooted ? {
|
|
1771
|
+
header_layout: safe.result_layout === "completion_yaml_files_v2" ? "rooted_files_v2" : "rooted_files_v1",
|
|
1772
|
+
} : {};
|
|
1767
1773
|
const omitted = safe.members.length - candidates.length;
|
|
1768
1774
|
if (omitted) {
|
|
1769
1775
|
service.omitted_results = omitted;
|
|
@@ -2302,7 +2308,7 @@ export function readRunCompletionPresentation(content, value) {
|
|
|
2302
2308
|
hint.content_sha256 !== createHash("sha256").update(content).digest("hex"))
|
|
2303
2309
|
return full;
|
|
2304
2310
|
const segments = [];
|
|
2305
|
-
const rooted = core.packet.service?.header_layout === "rooted_files_v1";
|
|
2311
|
+
const rooted = core.packet.service?.header_layout === "rooted_files_v1" || core.packet.service?.header_layout === "rooted_files_v2";
|
|
2306
2312
|
const facts = Object.fromEntries(Object.entries(core.packet.service ?? {}).filter(([key]) => key !== "header_layout"));
|
|
2307
2313
|
for (const [index, record] of core.packet.records.entries()) {
|
|
2308
2314
|
if (index)
|
|
@@ -2551,6 +2557,8 @@ export function encodeCompletionYamlCarrier(input) {
|
|
|
2551
2557
|
(Object.hasOwn(packet, "service") && (!completionYamlMapping(packet.service) || !Object.keys(packet.service).length)) ||
|
|
2552
2558
|
(!packet.records.length && !Object.hasOwn(packet, "service")))
|
|
2553
2559
|
return unavailable;
|
|
2560
|
+
const localSingleton = packet.records.length === 1 && completionYamlMapping(packet.service) &&
|
|
2561
|
+
packet.service.header_layout === "rooted_files_v2" && !Object.hasOwn(packet.service, "numbering");
|
|
2554
2562
|
const rows = [];
|
|
2555
2563
|
for (let index = 0; index < Math.max(1, packet.records.length); index++) {
|
|
2556
2564
|
const row = packet.records[index];
|
|
@@ -2568,14 +2576,16 @@ export function encodeCompletionYamlCarrier(input) {
|
|
|
2568
2576
|
!completionYamlMapping(row.metadata) || !Array.isArray(row.parts))
|
|
2569
2577
|
return unavailable;
|
|
2570
2578
|
const meta = row.metadata;
|
|
2571
|
-
|
|
2579
|
+
const validIndex = localSingleton ? !Object.hasOwn(meta, "index")
|
|
2580
|
+
: meta.index === "?" || (typeof meta.index === "number" && Number.isSafeInteger(meta.index) && meta.index >= 0);
|
|
2581
|
+
if (!validIndex ||
|
|
2572
2582
|
typeof meta.run !== "string" || !meta.run.length || typeof meta.state !== "string" || !meta.state.length ||
|
|
2573
2583
|
(Object.hasOwn(meta, "kind") && meta.kind !== "primary" && meta.kind !== "diagnostic") ||
|
|
2574
2584
|
Object.hasOwn(meta, completionYamlServiceKey) ||
|
|
2575
2585
|
// JS enumerates array-index keys before semantic core fields; do not silently reorder the header.
|
|
2576
2586
|
Object.keys(meta).some(key => /^(0|[1-9]\d*)$/u.test(key) && Number(key) < 4294967295))
|
|
2577
2587
|
return unavailable;
|
|
2578
|
-
for (const key of ["index", "run", "state", ...(Object.hasOwn(meta, "kind") ? ["kind"] : []),
|
|
2588
|
+
for (const key of [...(localSingleton ? [] : ["index"]), "run", "state", ...(Object.hasOwn(meta, "kind") ? ["kind"] : []),
|
|
2579
2589
|
...Object.keys(meta).filter(key => !["index", "run", "state", "kind"].includes(key))]) {
|
|
2580
2590
|
Object.defineProperty(header, key, { value: meta[key], enumerable: true });
|
|
2581
2591
|
}
|
|
@@ -12,8 +12,8 @@ export const TRACE_COMPACTION_VERSION = 1;
|
|
|
12
12
|
const PENDING_CONTROL_STATUSES = new Set(["queued", "delivered", "claimed"]);
|
|
13
13
|
const TERMINAL_CONTROL_STATUSES = new Set(["handled", "failed"]);
|
|
14
14
|
const CONTROL_ADMISSION_NEXT_ACTIONS = [
|
|
15
|
-
"
|
|
16
|
-
"
|
|
15
|
+
"actors_inspect target=run:<id> view=control",
|
|
16
|
+
"actors_inspect target=runtime view=triage",
|
|
17
17
|
];
|
|
18
18
|
function isCount(value) {
|
|
19
19
|
return Number.isSafeInteger(value) && value >= 0;
|
package/dist/lib/runtime.d.ts
CHANGED
|
@@ -27,6 +27,9 @@ export interface ToolRegistryRuntimeDeps {
|
|
|
27
27
|
getActiveTools?: () => string[];
|
|
28
28
|
getAllTools?: () => Array<{
|
|
29
29
|
name: string;
|
|
30
|
+
sourceInfo?: {
|
|
31
|
+
path: string;
|
|
32
|
+
};
|
|
30
33
|
}>;
|
|
31
34
|
registerTool: (definition: ReturnType<typeof ToolsLocal.createRuntimeToolDefinition>) => void;
|
|
32
35
|
reservedToolNames: Set<string>;
|
package/dist/lib/runtime.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync, watch } from "node:fs";
|
|
7
7
|
import { basename, dirname } from "node:path";
|
|
8
|
+
import * as Identity from "./identity.js";
|
|
8
9
|
import * as Paths from "./paths.js";
|
|
9
10
|
import * as RecipesDiscovery from "./recipes-discovery.js";
|
|
10
11
|
import * as RecipesReferences from "./recipes-references.js";
|
|
@@ -15,6 +16,8 @@ export function createAutoToolsRuntime(deps) {
|
|
|
15
16
|
const tools = new Map();
|
|
16
17
|
const runtimeToolFingerprints = new Map();
|
|
17
18
|
const runtimeTools = new Set();
|
|
19
|
+
// Host declarations survive deactivation; retain their observed provenance separately.
|
|
20
|
+
const runtimeToolSources = new Map();
|
|
18
21
|
const recipeRoot = deps.recipeRoot ?? Paths.getRecipeRoot();
|
|
19
22
|
const status = {
|
|
20
23
|
active_tool_count: 0,
|
|
@@ -28,9 +31,13 @@ export function createAutoToolsRuntime(deps) {
|
|
|
28
31
|
ctx.ui.notify(message, type);
|
|
29
32
|
}
|
|
30
33
|
function getToolNameBlocker(name) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
:
|
|
34
|
+
const normalized = Identity.normalizeToolName(name);
|
|
35
|
+
if ([...deps.reservedToolNames].some((reserved) => Identity.normalizeToolName(reserved) === normalized))
|
|
36
|
+
return `Reserved tool name: ${name}`;
|
|
37
|
+
const foreign = deps.getAllTools?.().find((tool) => Identity.normalizeToolName(tool.name) === normalized &&
|
|
38
|
+
!(tool.name === name && runtimeToolSources.has(name) &&
|
|
39
|
+
tool.sourceInfo?.path === runtimeToolSources.get(name)));
|
|
40
|
+
return foreign ? `Host tool name collision: ${name} conflicts with ${foreign.name}` : undefined;
|
|
34
41
|
}
|
|
35
42
|
function getToolFingerprint(cfg) {
|
|
36
43
|
return JSON.stringify({
|
|
@@ -61,13 +68,15 @@ export function createAutoToolsRuntime(deps) {
|
|
|
61
68
|
const stale = [...runtimeTools].filter((name) => !activeNames.has(name));
|
|
62
69
|
if (stale.length === 0)
|
|
63
70
|
return;
|
|
71
|
+
const hostTools = deps.getAllTools?.();
|
|
72
|
+
const staleOwned = stale.filter((name) => !hostTools || hostTools.some((tool) => tool.name === name && tool.sourceInfo?.path === runtimeToolSources.get(name)));
|
|
64
73
|
for (const name of stale) {
|
|
65
74
|
runtimeTools.delete(name);
|
|
66
75
|
runtimeToolFingerprints.delete(name);
|
|
67
76
|
}
|
|
68
77
|
if (!deps.getActiveTools || !deps.setActiveTools)
|
|
69
78
|
return;
|
|
70
|
-
const staleSet = new Set(
|
|
79
|
+
const staleSet = new Set(staleOwned);
|
|
71
80
|
deps.setActiveTools(deps.getActiveTools().filter((name) => !staleSet.has(name)));
|
|
72
81
|
}
|
|
73
82
|
function activationFor(name) {
|
|
@@ -81,10 +90,14 @@ export function createAutoToolsRuntime(deps) {
|
|
|
81
90
|
};
|
|
82
91
|
}
|
|
83
92
|
function registerRuntimeTool(cfg) {
|
|
93
|
+
const blocker = getToolNameBlocker(cfg.name);
|
|
94
|
+
if (blocker)
|
|
95
|
+
throw new Error(blocker);
|
|
84
96
|
const fingerprint = getToolFingerprint(cfg);
|
|
85
97
|
if (runtimeToolFingerprints.get(cfg.name) !== fingerprint) {
|
|
86
98
|
deps.registerTool(ToolsLocal.createRuntimeToolDefinition(cfg, deps.exec));
|
|
87
99
|
runtimeTools.add(cfg.name);
|
|
100
|
+
runtimeToolSources.set(cfg.name, deps.getAllTools?.().find((tool) => tool.name === cfg.name)?.sourceInfo?.path);
|
|
88
101
|
runtimeToolFingerprints.set(cfg.name, fingerprint);
|
|
89
102
|
}
|
|
90
103
|
if (deps.getActiveTools && deps.setActiveTools) {
|
|
@@ -129,7 +142,7 @@ export function createAutoToolsRuntime(deps) {
|
|
|
129
142
|
lines.push(...other.map((warning) => `• ${warning}`));
|
|
130
143
|
groups[groups.length] = ["other_diagnostics", start, lines.length];
|
|
131
144
|
}
|
|
132
|
-
lines.push("Next:
|
|
145
|
+
lines.push("Next: actors_inspect target=recipes view=doctor");
|
|
133
146
|
// Preserve the original layout join/coercion and its faults before projecting owned warning slots.
|
|
134
147
|
void `${lines.join("\n")}\n`;
|
|
135
148
|
let text = ToolsResponse.formatMarkdownField("report", "pi-actors recipe registry warning");
|
|
@@ -141,7 +154,7 @@ export function createAutoToolsRuntime(deps) {
|
|
|
141
154
|
: " - warning:\n - result: unavailable\n - reason: malformed_selected_text");
|
|
142
155
|
}
|
|
143
156
|
}
|
|
144
|
-
return text + "\n" + ToolsResponse.formatMarkdownField("instruction", "Next:
|
|
157
|
+
return text + "\n" + ToolsResponse.formatMarkdownField("instruction", "Next: actors_inspect target=recipes view=doctor") + "\n";
|
|
145
158
|
}
|
|
146
159
|
function loadTools(ctx, resolutionContext) {
|
|
147
160
|
const warnings = [];
|
|
@@ -170,6 +183,7 @@ export function createAutoToolsRuntime(deps) {
|
|
|
170
183
|
const blocker = getToolNameBlocker(cfg.name);
|
|
171
184
|
if (blocker) {
|
|
172
185
|
warnings.push(blocker);
|
|
186
|
+
tools.delete(cfg.name);
|
|
173
187
|
continue;
|
|
174
188
|
}
|
|
175
189
|
registerRuntimeTool(cfg);
|
|
@@ -195,7 +209,7 @@ export function createAutoToolsRuntime(deps) {
|
|
|
195
209
|
}),
|
|
196
210
|
getToolStatus: (name) => {
|
|
197
211
|
const cfg = tools.get(name);
|
|
198
|
-
if (!cfg)
|
|
212
|
+
if (!cfg || getToolNameBlocker(name))
|
|
199
213
|
return undefined;
|
|
200
214
|
const usage = cfg.sourcePath
|
|
201
215
|
? RecipesUsage.readRecipeUsage(cfg.sourcePath)
|
|
@@ -217,8 +231,8 @@ export function createAutoToolsRuntime(deps) {
|
|
|
217
231
|
next_actions: activation.callable_now
|
|
218
232
|
? [`call tool ${name}`]
|
|
219
233
|
: [
|
|
220
|
-
`
|
|
221
|
-
`
|
|
234
|
+
`actors_tool_register name=${name} update=true`,
|
|
235
|
+
`actors_inspect target=tool:${name} view=status`,
|
|
222
236
|
],
|
|
223
237
|
...(usage?.launch_kind ? { launch_kind: usage.launch_kind } : {}),
|
|
224
238
|
spawn_calls: Number(usage?.spawn_calls ?? 0),
|
|
@@ -271,7 +285,7 @@ export function createRecipeToolReloadWatcher(runtime, deps = {}) {
|
|
|
271
285
|
failureNotified = true;
|
|
272
286
|
setWatchStatus("failed");
|
|
273
287
|
try {
|
|
274
|
-
ctx.ui.notify("- report: Recipe live reload watcher failed\n- instruction: restart the session or use
|
|
288
|
+
ctx.ui.notify("- report: Recipe live reload watcher failed\n- instruction: restart the session or use actors_tool_register again to refresh recipe tools.", "warning");
|
|
275
289
|
}
|
|
276
290
|
catch (error) {
|
|
277
291
|
reportCallbackError(error);
|
|
@@ -264,7 +264,7 @@ export function applyApprovedToolReviewAtSessionBoundary(options = {}) {
|
|
|
264
264
|
...state,
|
|
265
265
|
failedStage: "approval_state",
|
|
266
266
|
lastError: "approved review path is unavailable",
|
|
267
|
-
nextAction: "
|
|
267
|
+
nextAction: "actors_control_apply target=runtime action=review.retry input={\"scope\":\"tool\"}",
|
|
268
268
|
phase: "processing_failed",
|
|
269
269
|
updatedAt: (options.now ?? (() => new Date()))().toISOString(),
|
|
270
270
|
};
|
|
@@ -287,7 +287,7 @@ export function applyApprovedToolReviewAtSessionBoundary(options = {}) {
|
|
|
287
287
|
...state,
|
|
288
288
|
failedStage: "transaction",
|
|
289
289
|
lastError: `tool review transaction remained ${transaction.phase}`,
|
|
290
|
-
nextAction: "
|
|
290
|
+
nextAction: "actors_control_apply target=runtime action=review.retry input={\"scope\":\"tool\"}",
|
|
291
291
|
phase: "processing_failed",
|
|
292
292
|
updatedAt: (options.now ?? (() => new Date()))().toISOString(),
|
|
293
293
|
};
|
|
@@ -316,7 +316,7 @@ export function applyApprovedToolReviewAtSessionBoundary(options = {}) {
|
|
|
316
316
|
...pending,
|
|
317
317
|
failedStage: "lineage",
|
|
318
318
|
lastError: error instanceof Error ? error.message : String(error),
|
|
319
|
-
nextAction: "
|
|
319
|
+
nextAction: "actors_control_apply target=runtime action=review.retry input={\"scope\":\"tool\"}",
|
|
320
320
|
};
|
|
321
321
|
writeJsonAtomic(statePath, failedPending);
|
|
322
322
|
return { outcome: "lineage_pending", state: failedPending };
|
|
@@ -337,7 +337,7 @@ export function applyApprovedToolReviewAtSessionBoundary(options = {}) {
|
|
|
337
337
|
...state,
|
|
338
338
|
failedStage: "transaction",
|
|
339
339
|
lastError: error instanceof Error ? error.message : String(error),
|
|
340
|
-
nextAction: "
|
|
340
|
+
nextAction: "actors_control_apply target=runtime action=review.retry input={\"scope\":\"tool\"}",
|
|
341
341
|
phase: "processing_failed",
|
|
342
342
|
updatedAt: (options.now ?? (() => new Date()))().toISOString(),
|
|
343
343
|
};
|
|
@@ -401,7 +401,7 @@ export function createToolReviewScheduler(deps) {
|
|
|
401
401
|
...existing,
|
|
402
402
|
failedStage: processed.stage ?? "review_result",
|
|
403
403
|
lastError: processed.error ?? "automatic tool reviewer failed",
|
|
404
|
-
nextAction: "
|
|
404
|
+
nextAction: "actors_control_apply target=runtime action=review.retry input={\"scope\":\"tool\"}",
|
|
405
405
|
phase: processed.outcome === "processing_failed"
|
|
406
406
|
? "processing_failed"
|
|
407
407
|
: "failed",
|
|
@@ -437,7 +437,7 @@ export function createToolReviewScheduler(deps) {
|
|
|
437
437
|
attempts: existing.attempts + 1,
|
|
438
438
|
failedStage: "review_launch",
|
|
439
439
|
lastError: error instanceof Error ? error.message : String(error),
|
|
440
|
-
nextAction: "
|
|
440
|
+
nextAction: "actors_control_apply target=runtime action=review.retry input={\"scope\":\"tool\"}",
|
|
441
441
|
phase: "failed",
|
|
442
442
|
updatedAt: now().toISOString(),
|
|
443
443
|
});
|
|
@@ -471,7 +471,7 @@ export function createToolReviewScheduler(deps) {
|
|
|
471
471
|
failedStage: "review_launch",
|
|
472
472
|
inputPath: batch.inputPath,
|
|
473
473
|
lastError: error instanceof Error ? error.message : String(error),
|
|
474
|
-
nextAction: "
|
|
474
|
+
nextAction: "actors_control_apply target=runtime action=review.retry input={\"scope\":\"tool\"}",
|
|
475
475
|
phase: "failed",
|
|
476
476
|
reviewerInputPath: batch.reviewerInputPath,
|
|
477
477
|
reviewId: batch.reviewId,
|
package/dist/lib/tools-access.js
CHANGED
|
@@ -33,7 +33,7 @@ export function sessionMismatchError(input) {
|
|
|
33
33
|
const actor = input.run ? `run:${input.run}` : (input.target ?? "session");
|
|
34
34
|
return Object.assign(new Error(`${actor} reason=session_mismatch owner_session=${ownerSession} current_session=${currentSession} hint=inspect_runtime_runs`), {
|
|
35
35
|
current_session: input.currentSession,
|
|
36
|
-
hint: "
|
|
36
|
+
hint: "actors_inspect target=runtime view=runs",
|
|
37
37
|
owner_session: input.expectedSession,
|
|
38
38
|
reason: "session_mismatch",
|
|
39
39
|
run: input.run,
|
|
@@ -145,10 +145,10 @@ function runtimeTriage(ctx, deps) {
|
|
|
145
145
|
trace_diagnostic_count: traceDiagnostics.length, trace_diagnostics: traceDiagnostics.slice(0, 40),
|
|
146
146
|
attention_events: attentionEvents.slice(-40).reverse(),
|
|
147
147
|
next_actions: [
|
|
148
|
-
...(failed.length ? ["
|
|
149
|
-
...new Set([...staleControls, ...backpressuredRuns].slice(0, 3).map((entry) => `
|
|
148
|
+
...(failed.length ? ["actors_inspect target=runtime view=runs status=failed"] : []),
|
|
149
|
+
...new Set([...staleControls, ...backpressuredRuns].slice(0, 3).map((entry) => `actors_inspect target=run:${entry.run} view=control`)),
|
|
150
150
|
...(attentionEvents.length
|
|
151
|
-
? attentionEvents.slice(-3).map((entry) => `
|
|
151
|
+
? attentionEvents.slice(-3).map((entry) => `actors_inspect target=run:${String(entry.run)} view=trace source=runtime`)
|
|
152
152
|
: []),
|
|
153
153
|
],
|
|
154
154
|
};
|
|
@@ -209,7 +209,7 @@ function formatInspectFailure(fields, next) {
|
|
|
209
209
|
return { omittable, full, selected };
|
|
210
210
|
});
|
|
211
211
|
// Only producer-known read-only inspect literals become a typed next, never a parsed action.
|
|
212
|
-
const typedNext = next ? { next: { tool: "
|
|
212
|
+
const typedNext = next ? { next: { tool: "actors_inspect", target: next[0], view: next[1] } } : undefined;
|
|
213
213
|
const nextFallback = { next_action: omitted };
|
|
214
214
|
const document = () => ({ ...Object.assign({}, ...parts.map((part) => part.selected)),
|
|
215
215
|
...(typedNext ?? nextFallback) });
|
|
@@ -336,15 +336,15 @@ function inspectRecipeIdentity(identity, resolutionContext, namespaces, inventor
|
|
|
336
336
|
...(rejectedReason ? { rejected_reason: rejectedReason } : {}),
|
|
337
337
|
next_actions: resolvable
|
|
338
338
|
? [
|
|
339
|
-
`
|
|
340
|
-
`
|
|
339
|
+
`actors_run_spawn recipe=${identity}`,
|
|
340
|
+
`actors_tool_register name=<tool-name> from=${identity}`,
|
|
341
341
|
]
|
|
342
342
|
: roots.length === 0 && skill
|
|
343
343
|
? [
|
|
344
344
|
`activate Skill ${skill}`,
|
|
345
|
-
`
|
|
345
|
+
`actors_inspect target=recipes view=doctor identity=${identity}`,
|
|
346
346
|
]
|
|
347
|
-
: ["
|
|
347
|
+
: ["actors_inspect target=recipes view=imports verbose=true"],
|
|
348
348
|
};
|
|
349
349
|
}
|
|
350
350
|
function inspectRecipes(requestedView, input, deps, context) {
|
|
@@ -583,7 +583,7 @@ function compactResult(target, view, details) {
|
|
|
583
583
|
? String(details.next_actions[0])
|
|
584
584
|
: details.callable_now === true
|
|
585
585
|
? `call tool ${name}`
|
|
586
|
-
: `
|
|
586
|
+
: `actors_tool_register name=${name} update=true`;
|
|
587
587
|
const hint = ToolsResponse.nextActionMetadata(next, Limits.RUN_DELIVERY_MODEL_MAX_BYTES);
|
|
588
588
|
const required = compactArguments("required_args", details.required_args);
|
|
589
589
|
const optional = compactArguments("optional_args", details.optional_args);
|
|
@@ -601,7 +601,7 @@ function compactResult(target, view, details) {
|
|
|
601
601
|
}
|
|
602
602
|
export function createInspectToolDefinition(deps = {}) {
|
|
603
603
|
return {
|
|
604
|
-
name: "
|
|
604
|
+
name: "actors_inspect",
|
|
605
605
|
label: "Inspect",
|
|
606
606
|
description: "Inspect a Run's Recipe, Trace, or Control evidence, or runtime/recipe/tool diagnostics.",
|
|
607
607
|
parameters: Schema.objectSchema({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Public Control facade under the stable `
|
|
2
|
+
* Public Control facade under the stable `actors_control_apply` tool name.
|
|
3
3
|
* Zones: Control request validation, Run/runtime dispatch, recipient-scoped receipts
|
|
4
4
|
* Owns public Control execution; journaling, delivery, and lifecycle mutation stay in Run domains.
|
|
5
5
|
*/
|