@llblab/pi-actors 0.33.0 → 0.34.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/AGENTS.md +22 -11
- package/BACKLOG.md +1 -1
- package/CHANGELOG.md +22 -1
- package/dist/index.js +10 -10
- package/dist/lib/async-runs.d.ts +23 -75
- package/dist/lib/async-runs.js +49 -801
- package/dist/lib/command-templates.d.ts +3 -3
- package/dist/lib/command-templates.js +3 -3
- package/dist/lib/config.d.ts +2 -2
- package/dist/lib/config.js +5 -5
- package/dist/lib/{output.d.ts → execution-output.d.ts} +3 -3
- package/dist/lib/{output.js → execution-output.js} +3 -3
- package/dist/lib/execution.js +1 -1
- package/dist/lib/{actor-inspector-tui.d.ts → inspector.d.ts} +3 -2
- package/dist/lib/{actor-inspector-tui.js → inspector.js} +3 -2
- package/dist/lib/mailbox-loop.d.ts +3 -3
- package/dist/lib/mailbox-loop.js +3 -3
- package/dist/lib/{actor-messages.d.ts → messages.d.ts} +3 -3
- package/dist/lib/{actor-messages.js → messages.js} +3 -3
- package/dist/lib/{actor-recipe-context.d.ts → recipes-context.d.ts} +3 -2
- package/dist/lib/{actor-recipe-context.js → recipes-context.js} +2 -1
- package/dist/lib/{recipe-discovery.d.ts → recipes-discovery.d.ts} +8 -8
- package/dist/lib/{recipe-discovery.js → recipes-discovery.js} +6 -6
- package/dist/lib/registry.d.ts +1 -1
- package/dist/lib/registry.js +22 -22
- package/dist/lib/{actor-rooms.d.ts → rooms.d.ts} +4 -4
- package/dist/lib/{actor-rooms.js → rooms.js} +3 -3
- package/dist/lib/runs-artifacts.d.ts +21 -0
- package/dist/lib/runs-artifacts.js +68 -0
- package/dist/lib/runs-control.d.ts +13 -0
- package/dist/lib/runs-control.js +59 -0
- package/dist/lib/runs-identity.d.ts +5 -0
- package/dist/lib/runs-identity.js +11 -0
- package/dist/lib/runs-index.d.ts +18 -0
- package/dist/lib/runs-index.js +119 -0
- package/dist/lib/runs-mailbox.d.ts +25 -0
- package/dist/lib/runs-mailbox.js +146 -0
- package/dist/lib/runs-messages.d.ts +15 -0
- package/dist/lib/runs-messages.js +179 -0
- package/dist/lib/runs-outbox.d.ts +41 -0
- package/dist/lib/runs-outbox.js +87 -0
- package/dist/lib/runs-process.d.ts +7 -0
- package/dist/lib/runs-process.js +36 -0
- package/dist/lib/runs-retention.d.ts +8 -0
- package/dist/lib/runs-retention.js +56 -0
- package/dist/lib/runs-start.d.ts +9 -0
- package/dist/lib/runs-start.js +67 -0
- package/dist/lib/runs-status.d.ts +8 -0
- package/dist/lib/runs-status.js +60 -0
- package/dist/lib/runtime.d.ts +2 -2
- package/dist/lib/runtime.js +5 -5
- package/dist/lib/schema.d.ts +9 -0
- package/dist/lib/schema.js +40 -0
- package/dist/lib/tools-access.d.ts +19 -0
- package/dist/lib/tools-access.js +44 -0
- package/dist/lib/tools-inspect.d.ts +11 -0
- package/dist/lib/tools-inspect.js +534 -0
- package/dist/lib/tools-local.d.ts +14 -0
- package/dist/lib/tools-local.js +156 -0
- package/dist/lib/tools-mailbox.d.ts +8 -0
- package/dist/lib/tools-mailbox.js +48 -0
- package/dist/lib/tools-message.d.ts +9 -0
- package/dist/lib/tools-message.js +346 -0
- package/dist/lib/tools-register.d.ts +18 -0
- package/dist/lib/tools-register.js +40 -0
- package/dist/lib/tools-response.d.ts +21 -0
- package/dist/lib/tools-response.js +219 -0
- package/dist/lib/tools-spawn.d.ts +12 -0
- package/dist/lib/tools-spawn.js +159 -0
- package/dist/lib/tools.d.ts +8 -39
- package/dist/lib/tools.js +11 -1490
- package/dist/recipes/utility-coordinator-lock-snapshot.json +1 -1
- package/dist/scripts/actor-worker.mjs +186 -7
- package/dist/scripts/async-runner.mjs +171 -8
- package/dist/scripts/build-dist.mjs +1 -1
- package/dist/scripts/conformance.mjs +3 -3
- package/dist/scripts/coordinator.mjs +733 -11
- package/dist/scripts/locker.mjs +345 -16
- package/dist/scripts/recipe-utils.mjs +478 -14
- package/dist/scripts/validate-recipe.mjs +110 -10
- package/dist/skills/actors/SKILL.md +1 -1
- package/dist/skills/swarm/SKILL.md +1 -1
- package/docs/recipe-library.md +1 -1
- package/docs/template-recipes.md +1 -1
- package/index.ts +11 -18
- package/lib/async-runs.ts +124 -1016
- package/lib/command-templates.ts +3 -3
- package/lib/config.ts +7 -7
- package/lib/{output.ts → execution-output.ts} +3 -3
- package/lib/execution.ts +5 -1
- package/lib/{actor-inspector-tui.ts → inspector.ts} +4 -3
- package/lib/mailbox-loop.ts +3 -3
- package/lib/{actor-messages.ts → messages.ts} +3 -3
- package/lib/{actor-recipe-context.ts → recipes-context.ts} +3 -2
- package/lib/{recipe-discovery.ts → recipes-discovery.ts} +19 -19
- package/lib/{recipe-usage.ts → recipes-usage.ts} +2 -2
- package/lib/registry.ts +37 -24
- package/lib/{actor-rooms.ts → rooms.ts} +4 -4
- package/lib/runs-artifacts.ts +96 -0
- package/lib/runs-control.ts +85 -0
- package/lib/runs-identity.ts +14 -0
- package/lib/runs-index.ts +156 -0
- package/lib/runs-mailbox.ts +208 -0
- package/lib/runs-messages.ts +252 -0
- package/lib/runs-outbox.ts +144 -0
- package/lib/runs-process.ts +51 -0
- package/lib/runs-retention.ts +77 -0
- package/lib/runs-start.ts +98 -0
- package/lib/runs-status.ts +78 -0
- package/lib/runtime.ts +6 -6
- package/lib/schema.ts +55 -0
- package/lib/tools-access.ts +68 -0
- package/lib/tools-inspect.ts +735 -0
- package/lib/tools-local.ts +234 -0
- package/lib/tools-mailbox.ts +56 -0
- package/lib/tools-message.ts +483 -0
- package/lib/tools-register.ts +64 -0
- package/lib/tools-response.ts +267 -0
- package/lib/tools-spawn.ts +240 -0
- package/lib/tools.ts +20 -2040
- package/package.json +1 -1
- package/recipes/utility-coordinator-lock-snapshot.json +1 -1
- package/scripts/actor-worker.mjs +186 -7
- package/scripts/async-runner.mjs +171 -8
- package/scripts/build-dist.mjs +1 -1
- package/scripts/conformance.mjs +3 -3
- package/scripts/coordinator.mjs +733 -11
- package/scripts/locker.mjs +345 -16
- package/scripts/recipe-utils.mjs +478 -14
- package/scripts/validate-recipe.mjs +110 -10
- package/skills/actors/SKILL.md +1 -1
- package/skills/swarm/SKILL.md +1 -1
- package/dist/lib/actor-worker.d.ts +0 -16
- package/dist/lib/actor-worker.js +0 -134
- package/dist/lib/async-runner.d.ts +0 -5
- package/dist/lib/async-runner.js +0 -134
- package/dist/lib/coordinator.d.ts +0 -5
- package/dist/lib/coordinator.js +0 -660
- package/dist/lib/locker.d.ts +0 -5
- package/dist/lib/locker.js +0 -310
- package/dist/lib/recipe-utils.d.ts +0 -5
- package/dist/lib/recipe-utils.js +0 -385
- package/dist/lib/validate-recipe.d.ts +0 -6
- package/dist/lib/validate-recipe.js +0 -104
- package/lib/actor-worker.ts +0 -174
- package/lib/async-runner.ts +0 -173
- package/lib/coordinator.ts +0 -742
- package/lib/locker.ts +0 -340
- package/lib/recipe-utils.ts +0 -486
- package/lib/validate-recipe.ts +0 -110
- /package/dist/lib/{recipe-references.d.ts → recipes-references.d.ts} +0 -0
- /package/dist/lib/{recipe-references.js → recipes-references.js} +0 -0
- /package/dist/lib/{recipe-usage.d.ts → recipes-usage.d.ts} +0 -0
- /package/dist/lib/{recipe-usage.js → recipes-usage.js} +0 -0
- /package/lib/{recipe-references.ts → recipes-references.ts} +0 -0
package/lib/command-templates.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Command-template standard
|
|
3
|
-
* Zones:
|
|
4
|
-
* Owns
|
|
2
|
+
* Command-template execution standard.
|
|
3
|
+
* Zones: shell-free command parsing, placeholder expansion, local process execution, composition semantics
|
|
4
|
+
* Owns portable command-template parsing, expansion, risk checks, retries, timeouts, and direct execution.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { spawn } from "node:child_process";
|
package/lib/config.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { CommandTemplateValue } from "./command-templates.ts";
|
|
|
10
10
|
import * as CommandTemplates from "./command-templates.ts";
|
|
11
11
|
import { writeJsonAtomic } from "./file-state.ts";
|
|
12
12
|
import { normalizeToolName } from "./identity.ts";
|
|
13
|
-
import * as
|
|
13
|
+
import * as RecipesReferences from "./recipes-references.ts";
|
|
14
14
|
import * as Schema from "./schema.ts";
|
|
15
15
|
|
|
16
16
|
export interface RegisteredTool {
|
|
@@ -19,7 +19,7 @@ export interface RegisteredTool {
|
|
|
19
19
|
args: string[];
|
|
20
20
|
defaults: Record<string, string>;
|
|
21
21
|
argTypes?: Record<string, Schema.ToolArgType>;
|
|
22
|
-
recipe?:
|
|
22
|
+
recipe?: RecipesReferences.TemplateRecipeConfig;
|
|
23
23
|
template?: CommandTemplateValue;
|
|
24
24
|
storedArgs?: string[];
|
|
25
25
|
storedDefaults?: Record<string, string>;
|
|
@@ -141,7 +141,7 @@ export function normalizeStoredTool(
|
|
|
141
141
|
}
|
|
142
142
|
const recipeName =
|
|
143
143
|
keyedRecipeName ?? (typeof record.async === "boolean" ? name : undefined);
|
|
144
|
-
const recipe:
|
|
144
|
+
const recipe: RecipesReferences.TemplateRecipeConfig | undefined = recipeName
|
|
145
145
|
? {
|
|
146
146
|
name: recipeName,
|
|
147
147
|
...(typeof record.async === "boolean" ? { async: record.async } : {}),
|
|
@@ -156,14 +156,14 @@ export function normalizeStoredTool(
|
|
|
156
156
|
: {}),
|
|
157
157
|
}
|
|
158
158
|
: undefined;
|
|
159
|
-
const isRecipe =
|
|
160
|
-
const recipeTemplate =
|
|
159
|
+
const isRecipe = RecipesReferences.isRecipeTool(template, recipe);
|
|
160
|
+
const recipeTemplate = RecipesReferences.getRecipeTemplate(template);
|
|
161
161
|
const argTemplate = recipeTemplate ?? template;
|
|
162
162
|
const description =
|
|
163
163
|
typeof record.description === "string" && record.description.trim()
|
|
164
164
|
? record.description.trim()
|
|
165
165
|
: isRecipe
|
|
166
|
-
? `${recipe?.async === true ||
|
|
166
|
+
? `${recipe?.async === true || RecipesReferences.isAsyncRecipeReference(template) ? "Start async" : "Execute"} template recipe: ${recipe?.name ?? formatTemplateForDescription(template)}`
|
|
167
167
|
: `Execute command template: ${formatTemplateForDescription(template)}`;
|
|
168
168
|
const declarations = Schema.normalizeStoredToolArgDeclarations(
|
|
169
169
|
record.args,
|
|
@@ -199,7 +199,7 @@ export function normalizeStoredTool(
|
|
|
199
199
|
args:
|
|
200
200
|
isRecipe && storedArgs !== undefined
|
|
201
201
|
? Schema.getExplicitToolArgNames(storedArgs)
|
|
202
|
-
:
|
|
202
|
+
: RecipesReferences.isRecipeReference(template) && !recipeTemplate
|
|
203
203
|
? Schema.getExplicitToolArgNames(storedArgs)
|
|
204
204
|
: Schema.getToolArgNames(argTemplateConfig),
|
|
205
205
|
defaults: declarations.defaults,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Zones:
|
|
4
|
-
* Owns stdout/stderr failure formatting, tail truncation, and full-output temp-file persistence
|
|
2
|
+
* Registered tool execution output.
|
|
3
|
+
* Zones: command execution results, bounded output formatting, temp artifacts
|
|
4
|
+
* Owns stdout/stderr failure formatting, tail truncation, and full-output temp-file persistence.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
package/lib/execution.ts
CHANGED
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
import * as CommandTemplates from "./command-templates.ts";
|
|
8
8
|
import type { RegisteredTool } from "./config.ts";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
formatFailureOutput,
|
|
11
|
+
formatOutput,
|
|
12
|
+
formatToolText,
|
|
13
|
+
} from "./execution-output.ts";
|
|
10
14
|
import * as Schema from "./schema.ts";
|
|
11
15
|
|
|
12
16
|
export interface ToolExecOptions {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Zones: terminal
|
|
2
|
+
* Inspector preview rendering.
|
|
3
|
+
* Zones: terminal run inspection, room/direct message previews, no-dependency UI formatting
|
|
4
|
+
* Owns read-only previews and TUI-ready summaries; actor routing stays outside.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import * as fs from "node:fs";
|
|
@@ -8,7 +9,7 @@ import * as path from "node:path";
|
|
|
8
9
|
|
|
9
10
|
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
10
11
|
|
|
11
|
-
import type { ActorMessage } from "./
|
|
12
|
+
import type { ActorMessage } from "./messages.ts";
|
|
12
13
|
import * as Limits from "./limits.ts";
|
|
13
14
|
import * as Paths from "./paths.ts";
|
|
14
15
|
import {
|
package/lib/mailbox-loop.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Mailbox worker loop primitives.
|
|
3
3
|
* Zones: mailbox-consuming actors, run/branch inbox claiming, handler status transitions
|
|
4
|
-
* Owns
|
|
4
|
+
* Owns reusable claim/handle/drain behavior across run and branch inboxes; scheduling and task policy stay outside.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
claimBranchInboxMessage,
|
|
9
9
|
updateBranchInboxMessageStatus,
|
|
10
10
|
type BranchInboxRecord,
|
|
11
|
-
} from "./
|
|
11
|
+
} from "./rooms.ts";
|
|
12
12
|
import {
|
|
13
13
|
claimRunInboxMessage,
|
|
14
14
|
updateRunInboxMessageStatus,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Actor message protocol
|
|
3
|
-
* Zones:
|
|
4
|
-
* Owns pure validation/normalization for
|
|
2
|
+
* Actor message protocol.
|
|
3
|
+
* Zones: addressed envelopes, address parsing, route normalization
|
|
4
|
+
* Owns pure validation/normalization for semantic actor messages; transport routing stays in adapters.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
export type ActorAddressKind =
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Recipe context prompt assembly.
|
|
3
3
|
* Zones: async runner prompt context, recipe provenance, LLM child launches
|
|
4
|
+
* Owns compact actor recipe context records appended to child-agent prompts.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import { basename } from "node:path";
|
|
7
8
|
|
|
8
9
|
import type { CommandTemplateActorRecipeContext } from "./command-templates.ts";
|
|
9
|
-
import type { TemplateRecipeContextRecord } from "./
|
|
10
|
+
import type { TemplateRecipeContextRecord } from "./recipes-references.ts";
|
|
10
11
|
|
|
11
12
|
export interface MarkedRecipeContextRecord extends TemplateRecipeContextRecord {
|
|
12
13
|
you_are_here?: true;
|
|
@@ -10,8 +10,8 @@ import { join } from "node:path";
|
|
|
10
10
|
|
|
11
11
|
import * as CommandTemplates from "./command-templates.ts";
|
|
12
12
|
import type { RegisteredTool } from "./config.ts";
|
|
13
|
-
import type { TemplateRecipeConfig } from "./
|
|
14
|
-
import * as
|
|
13
|
+
import type { TemplateRecipeConfig } from "./recipes-references.ts";
|
|
14
|
+
import * as RecipesReferences from "./recipes-references.ts";
|
|
15
15
|
import * as Schema from "./schema.ts";
|
|
16
16
|
|
|
17
17
|
export interface DiscoveredRecipe {
|
|
@@ -43,13 +43,13 @@ export interface RecipeIntegrityManifestEntry {
|
|
|
43
43
|
shadowed: boolean;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
export interface
|
|
46
|
+
export interface RecipesDiscoveryResult {
|
|
47
47
|
active: Map<string, DiscoveredRecipe>;
|
|
48
48
|
entries: DiscoveredRecipe[];
|
|
49
49
|
diagnostics: string[];
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export interface
|
|
52
|
+
export interface RecipesDiscoverySource {
|
|
53
53
|
root?: string;
|
|
54
54
|
file?: string;
|
|
55
55
|
defaultTool?: boolean;
|
|
@@ -115,7 +115,7 @@ function getRecipeConfigDiagnostics(
|
|
|
115
115
|
config: TemplateRecipeConfig | undefined,
|
|
116
116
|
): string[] {
|
|
117
117
|
if (!config) {
|
|
118
|
-
const reason =
|
|
118
|
+
const reason = RecipesReferences.diagnoseRawRecipeConfigFailure(file);
|
|
119
119
|
return [`Invalid recipe: ${file}${reason ? `: ${reason}` : ""}`];
|
|
120
120
|
}
|
|
121
121
|
const commandTemplateConfig =
|
|
@@ -134,9 +134,9 @@ function readDiscoveredRecipe(
|
|
|
134
134
|
defaultTool = false,
|
|
135
135
|
mutableUsage = false,
|
|
136
136
|
): DiscoveredRecipe {
|
|
137
|
-
const id =
|
|
137
|
+
const id = RecipesReferences.getRecipeIdFromPath(file);
|
|
138
138
|
try {
|
|
139
|
-
const config =
|
|
139
|
+
const config = RecipesReferences.readResolvedRecipeConfig(file);
|
|
140
140
|
const invalid = !config;
|
|
141
141
|
const disabled = config?.disabled === true;
|
|
142
142
|
return {
|
|
@@ -174,7 +174,7 @@ function readDiscoveredRecipe(
|
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
function filesForSource(source:
|
|
177
|
+
function filesForSource(source: RecipesDiscoverySource): Array<{
|
|
178
178
|
root: string;
|
|
179
179
|
file: string;
|
|
180
180
|
defaultTool: boolean;
|
|
@@ -201,7 +201,7 @@ function filesForSource(source: RecipeDiscoverySource): Array<{
|
|
|
201
201
|
: [];
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
function getRecipeRootDiagnostics(sources:
|
|
204
|
+
function getRecipeRootDiagnostics(sources: RecipesDiscoverySource[]): string[] {
|
|
205
205
|
const diagnostics: string[] = [];
|
|
206
206
|
const roots = new Set(
|
|
207
207
|
sources
|
|
@@ -232,8 +232,8 @@ function getRecipeRootDiagnostics(sources: RecipeDiscoverySource[]): string[] {
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
export function discoverRecipeSources(
|
|
235
|
-
sources:
|
|
236
|
-
):
|
|
235
|
+
sources: RecipesDiscoverySource[],
|
|
236
|
+
): RecipesDiscoveryResult {
|
|
237
237
|
const entries = sources.flatMap((source, priority) =>
|
|
238
238
|
filesForSource(source).map(({ root, file, defaultTool, mutableUsage }) =>
|
|
239
239
|
readDiscoveredRecipe(root, file, priority, defaultTool, mutableUsage),
|
|
@@ -286,7 +286,7 @@ export function discoverRecipeSources(
|
|
|
286
286
|
return { active, entries, diagnostics };
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
export function discoverRecipes(roots: string[]):
|
|
289
|
+
export function discoverRecipes(roots: string[]): RecipesDiscoveryResult {
|
|
290
290
|
return discoverRecipeSources(roots.map((root) => ({ root })));
|
|
291
291
|
}
|
|
292
292
|
|
|
@@ -362,7 +362,7 @@ function cleanupRecommendation(
|
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
export function createRecipeIntegrityManifest(
|
|
365
|
-
result:
|
|
365
|
+
result: RecipesDiscoveryResult,
|
|
366
366
|
): RecipeIntegrityManifestEntry[] {
|
|
367
367
|
return result.entries
|
|
368
368
|
.map((entry) => {
|
|
@@ -425,7 +425,7 @@ function diagnosticSuggestedAction(message: string): string {
|
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
function diagnosticDetails(
|
|
428
|
-
result:
|
|
428
|
+
result: RecipesDiscoveryResult,
|
|
429
429
|
): Array<Record<string, unknown>> {
|
|
430
430
|
const details: Array<Record<string, unknown>> = [];
|
|
431
431
|
const seen = new Set<string>();
|
|
@@ -529,7 +529,7 @@ function remediationRank(item: Record<string, unknown>): number {
|
|
|
529
529
|
}
|
|
530
530
|
|
|
531
531
|
function discoveryRemediations(
|
|
532
|
-
result:
|
|
532
|
+
result: RecipesDiscoveryResult,
|
|
533
533
|
): Array<Record<string, unknown>> {
|
|
534
534
|
return result.entries
|
|
535
535
|
.map((entry) =>
|
|
@@ -560,7 +560,7 @@ function recommendationForEntry(
|
|
|
560
560
|
}
|
|
561
561
|
|
|
562
562
|
export function getShadowedLaunchDiagnostic(
|
|
563
|
-
result:
|
|
563
|
+
result: RecipesDiscoveryResult,
|
|
564
564
|
id: string,
|
|
565
565
|
): Record<string, unknown> | undefined {
|
|
566
566
|
const active = result.active.get(id.trim());
|
|
@@ -576,8 +576,8 @@ export function getShadowedLaunchDiagnostic(
|
|
|
576
576
|
|
|
577
577
|
export function listDraftRecipes(root: string): Array<Record<string, unknown>> {
|
|
578
578
|
return listRecipeFiles(root).map((path) => {
|
|
579
|
-
const id =
|
|
580
|
-
const config =
|
|
579
|
+
const id = RecipesReferences.getRecipeIdFromPath(path);
|
|
580
|
+
const config = RecipesReferences.readRawRecipeConfig(path);
|
|
581
581
|
return {
|
|
582
582
|
id,
|
|
583
583
|
path,
|
|
@@ -587,7 +587,7 @@ export function listDraftRecipes(root: string): Array<Record<string, unknown>> {
|
|
|
587
587
|
}
|
|
588
588
|
|
|
589
589
|
export function summarizeDiscovery(
|
|
590
|
-
result:
|
|
590
|
+
result: RecipesDiscoveryResult,
|
|
591
591
|
): Record<string, unknown> {
|
|
592
592
|
const recommendations = result.entries
|
|
593
593
|
.map((entry) =>
|
|
@@ -9,7 +9,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
9
9
|
|
|
10
10
|
import { writeJsonAtomic } from "./file-state.ts";
|
|
11
11
|
|
|
12
|
-
interface
|
|
12
|
+
interface RecipesUsageRecord {
|
|
13
13
|
calls?: number;
|
|
14
14
|
direct_calls?: number;
|
|
15
15
|
fingerprint?: string;
|
|
@@ -62,7 +62,7 @@ export function recordRecipeLaunch(
|
|
|
62
62
|
try {
|
|
63
63
|
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
64
64
|
if (!isRecord(raw)) return false;
|
|
65
|
-
const usage:
|
|
65
|
+
const usage: RecipesUsageRecord = isRecord(raw.usage) ? raw.usage : {};
|
|
66
66
|
const fingerprint = getRecipeFingerprint(raw);
|
|
67
67
|
const changed =
|
|
68
68
|
typeof usage.fingerprint === "string" &&
|
package/lib/registry.ts
CHANGED
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
import { existsSync, mkdirSync, unlinkSync } from "node:fs";
|
|
8
8
|
import { dirname, join } from "node:path";
|
|
9
9
|
|
|
10
|
-
import * as Config from "./config.ts";
|
|
11
|
-
import * as Identity from "./identity.ts";
|
|
12
|
-
import * as Output from "./output.ts";
|
|
13
10
|
import * as CommandTemplates from "./command-templates.ts";
|
|
11
|
+
import * as Config from "./config.ts";
|
|
12
|
+
import * as ExecutionOutput from "./execution-output.ts";
|
|
14
13
|
import { writeJsonAtomic } from "./file-state.ts";
|
|
14
|
+
import * as Identity from "./identity.ts";
|
|
15
15
|
import * as Paths from "./paths.ts";
|
|
16
|
-
import * as
|
|
16
|
+
import * as RecipesReferences from "./recipes-references.ts";
|
|
17
17
|
import * as Schema from "./schema.ts";
|
|
18
18
|
|
|
19
19
|
export interface RegisterToolInput {
|
|
@@ -71,7 +71,7 @@ function listTools<TContext>(
|
|
|
71
71
|
return {
|
|
72
72
|
content: [
|
|
73
73
|
textContent(
|
|
74
|
-
|
|
74
|
+
ExecutionOutput.formatToolText(
|
|
75
75
|
names.length > 0
|
|
76
76
|
? `Registered tools:\n${names.map((name) => `- ${name}`).join("\n")}`
|
|
77
77
|
: "No registered tools.",
|
|
@@ -122,7 +122,9 @@ function deleteTool<TContext>(
|
|
|
122
122
|
if (!tools.has(name)) {
|
|
123
123
|
return {
|
|
124
124
|
content: [
|
|
125
|
-
textContent(
|
|
125
|
+
textContent(
|
|
126
|
+
ExecutionOutput.formatToolText(`Tool "${name}" not found.`),
|
|
127
|
+
),
|
|
126
128
|
],
|
|
127
129
|
details: { tool: name },
|
|
128
130
|
};
|
|
@@ -137,7 +139,7 @@ function deleteTool<TContext>(
|
|
|
137
139
|
return {
|
|
138
140
|
content: [
|
|
139
141
|
textContent(
|
|
140
|
-
|
|
142
|
+
ExecutionOutput.formatToolText(
|
|
141
143
|
`Deleted tool "${name}". Reload to remove it from the complete registry.`,
|
|
142
144
|
),
|
|
143
145
|
),
|
|
@@ -157,7 +159,7 @@ function getInputTemplate(
|
|
|
157
159
|
});
|
|
158
160
|
if (steps.length === 0)
|
|
159
161
|
throw new Error(
|
|
160
|
-
|
|
162
|
+
ExecutionOutput.formatToolText("Tool template sequence is empty."),
|
|
161
163
|
);
|
|
162
164
|
return value;
|
|
163
165
|
}
|
|
@@ -168,7 +170,9 @@ function getInputTemplate(
|
|
|
168
170
|
return value as CommandTemplates.CommandTemplateConfig;
|
|
169
171
|
}
|
|
170
172
|
throw new Error(
|
|
171
|
-
|
|
173
|
+
ExecutionOutput.formatToolText(
|
|
174
|
+
"Tool template must be a string, object, or sequence.",
|
|
175
|
+
),
|
|
172
176
|
);
|
|
173
177
|
}
|
|
174
178
|
|
|
@@ -182,26 +186,30 @@ function buildConfig(
|
|
|
182
186
|
? undefined
|
|
183
187
|
: Schema.parseToolArgDeclarations(input.args);
|
|
184
188
|
if (explicitArgs?.error)
|
|
185
|
-
throw new Error(
|
|
189
|
+
throw new Error(ExecutionOutput.formatToolText(explicitArgs.error));
|
|
186
190
|
const description = (input.description ?? existing?.description ?? "").trim();
|
|
187
191
|
if (!description) {
|
|
188
192
|
throw new Error(
|
|
189
|
-
|
|
193
|
+
ExecutionOutput.formatToolText(
|
|
194
|
+
"Tool description is required unless deleting.",
|
|
195
|
+
),
|
|
190
196
|
);
|
|
191
197
|
}
|
|
192
198
|
const template = getInputTemplate(input.template);
|
|
193
199
|
if (template === null) {
|
|
194
200
|
throw new Error(
|
|
195
|
-
|
|
201
|
+
ExecutionOutput.formatToolText("Tool template cannot be null here."),
|
|
196
202
|
);
|
|
197
203
|
}
|
|
198
204
|
const finalTemplate =
|
|
199
205
|
template === undefined || template === "" ? existing?.template : template;
|
|
200
206
|
if (!finalTemplate) {
|
|
201
|
-
throw new Error(
|
|
207
|
+
throw new Error(
|
|
208
|
+
ExecutionOutput.formatToolText("Tool template is required."),
|
|
209
|
+
);
|
|
202
210
|
}
|
|
203
211
|
const inputRecipe = typeof input.async === "boolean" ? name : undefined;
|
|
204
|
-
const recipe:
|
|
212
|
+
const recipe: RecipesReferences.TemplateRecipeConfig | undefined = inputRecipe
|
|
205
213
|
? {
|
|
206
214
|
name: inputRecipe,
|
|
207
215
|
...(typeof input.async === "boolean" ? { async: input.async } : {}),
|
|
@@ -222,7 +230,7 @@ function buildConfig(
|
|
|
222
230
|
: existing?.storedArgs;
|
|
223
231
|
const storedDefaults =
|
|
224
232
|
Object.keys(defaults).length > 0 ? defaults : undefined;
|
|
225
|
-
const recipeTemplate =
|
|
233
|
+
const recipeTemplate = RecipesReferences.getRecipeTemplate(finalTemplate);
|
|
226
234
|
const argTemplate = recipeTemplate ?? finalTemplate;
|
|
227
235
|
const argTemplateConfig: CommandTemplates.CommandTemplateConfig =
|
|
228
236
|
typeof argTemplate === "object" && !Array.isArray(argTemplate)
|
|
@@ -248,10 +256,10 @@ function buildConfig(
|
|
|
248
256
|
template: finalTemplate,
|
|
249
257
|
...(recipe ? { recipe } : {}),
|
|
250
258
|
args:
|
|
251
|
-
|
|
259
|
+
RecipesReferences.isRecipeTool(finalTemplate, recipe) &&
|
|
252
260
|
storedArgs !== undefined
|
|
253
261
|
? Schema.getExplicitToolArgNames(storedArgs)
|
|
254
|
-
:
|
|
262
|
+
: RecipesReferences.isRecipeReference(finalTemplate) && !recipeTemplate
|
|
255
263
|
? Schema.getExplicitToolArgNames(storedArgs)
|
|
256
264
|
: Schema.getToolArgNames(argTemplateConfig),
|
|
257
265
|
defaults,
|
|
@@ -269,9 +277,12 @@ export async function executeRegisterTool<TContext>(
|
|
|
269
277
|
const input = params as RegisterToolInput;
|
|
270
278
|
if (!input.name) return listTools(deps);
|
|
271
279
|
const name = Identity.normalizeToolName(input.name);
|
|
272
|
-
if (!name)
|
|
280
|
+
if (!name)
|
|
281
|
+
throw new Error(ExecutionOutput.formatToolText("Invalid tool name."));
|
|
273
282
|
if (deps.reservedToolNames.has(name)) {
|
|
274
|
-
throw new Error(
|
|
283
|
+
throw new Error(
|
|
284
|
+
ExecutionOutput.formatToolText(`Reserved tool name: ${name}`),
|
|
285
|
+
);
|
|
275
286
|
}
|
|
276
287
|
const templateProvided = Object.hasOwn(input, "template");
|
|
277
288
|
const template = getInputTemplate(input.template);
|
|
@@ -280,17 +291,19 @@ export async function executeRegisterTool<TContext>(
|
|
|
280
291
|
const tools = deps.getTools();
|
|
281
292
|
const existing = tools.get(name);
|
|
282
293
|
const conflict = deps.getExternalToolConflict(name);
|
|
283
|
-
if (conflict) throw new Error(
|
|
294
|
+
if (conflict) throw new Error(ExecutionOutput.formatToolText(conflict));
|
|
284
295
|
if (existing && !input.update) {
|
|
285
296
|
throw new Error(
|
|
286
|
-
|
|
297
|
+
ExecutionOutput.formatToolText(
|
|
287
298
|
`Tool "${name}" already registered. Use update=true to overwrite.`,
|
|
288
299
|
),
|
|
289
300
|
);
|
|
290
301
|
}
|
|
291
302
|
if (template === undefined && !existing) {
|
|
292
303
|
throw new Error(
|
|
293
|
-
|
|
304
|
+
ExecutionOutput.formatToolText(
|
|
305
|
+
"Tool template is required for new registrations.",
|
|
306
|
+
),
|
|
294
307
|
);
|
|
295
308
|
}
|
|
296
309
|
const cfg = buildConfig(name, input, existing);
|
|
@@ -299,7 +312,7 @@ export async function executeRegisterTool<TContext>(
|
|
|
299
312
|
recipePath = persistToolRecipe(deps, cfg);
|
|
300
313
|
} catch (error) {
|
|
301
314
|
throw new Error(
|
|
302
|
-
|
|
315
|
+
ExecutionOutput.formatToolText(
|
|
303
316
|
`Failed to persist tool recipe: ${error instanceof Error ? error.message : String(error)}`,
|
|
304
317
|
),
|
|
305
318
|
);
|
|
@@ -320,7 +333,7 @@ export async function executeRegisterTool<TContext>(
|
|
|
320
333
|
return {
|
|
321
334
|
content: [
|
|
322
335
|
textContent(
|
|
323
|
-
|
|
336
|
+
ExecutionOutput.formatToolText(
|
|
324
337
|
`${existing ? "Updated" : "Registered"} tool "${name}" (args: ${Schema.formatToolArgs(cfg.args)}).${warningText}`,
|
|
325
338
|
),
|
|
326
339
|
),
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Actor room persistence
|
|
3
|
-
* Zones: room timelines,
|
|
4
|
-
* Owns
|
|
2
|
+
* Actor room persistence.
|
|
3
|
+
* Zones: room timelines, rosters, branch inboxes, cross-branch discovery state
|
|
4
|
+
* Owns file-backed room and branch-mailbox state; routing policy stays in tools/runtime adapters.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
|
|
11
|
-
import type { ActorMessage } from "./
|
|
11
|
+
import type { ActorMessage } from "./messages.ts";
|
|
12
12
|
import * as Limits from "./limits.ts";
|
|
13
13
|
import { notifyRuntimeWake } from "./runtime-notifier.ts";
|
|
14
14
|
import {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async run artifact declarations and manifest resolution.
|
|
3
|
+
* Owns artifact path template expansion and filesystem-backed artifact metadata.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
|
|
9
|
+
import { substituteCommandTemplateToken } from "./command-templates.ts";
|
|
10
|
+
|
|
11
|
+
export type RunArtifactDeclaration =
|
|
12
|
+
| string
|
|
13
|
+
| { path: string; kind?: string; media_type?: string; required?: boolean };
|
|
14
|
+
|
|
15
|
+
export interface RunArtifactManifestEntry {
|
|
16
|
+
exists: boolean;
|
|
17
|
+
kind?: string;
|
|
18
|
+
media_type?: string;
|
|
19
|
+
path: string;
|
|
20
|
+
required?: boolean;
|
|
21
|
+
sha256?: string;
|
|
22
|
+
size?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resolveArtifactPaths(
|
|
26
|
+
artifacts: Record<string, RunArtifactDeclaration> | undefined,
|
|
27
|
+
values: Record<string, unknown>,
|
|
28
|
+
): Record<string, RunArtifactDeclaration> | undefined {
|
|
29
|
+
if (!artifacts) return undefined;
|
|
30
|
+
const resolved: Record<string, RunArtifactDeclaration> = {};
|
|
31
|
+
for (const [key, value] of Object.entries(artifacts)) {
|
|
32
|
+
if (!key.trim()) continue;
|
|
33
|
+
if (typeof value === "string") {
|
|
34
|
+
resolved[key] = substituteCommandTemplateToken(
|
|
35
|
+
value,
|
|
36
|
+
values,
|
|
37
|
+
`recipe artifacts.${key}`,
|
|
38
|
+
);
|
|
39
|
+
} else if (
|
|
40
|
+
value &&
|
|
41
|
+
typeof value === "object" &&
|
|
42
|
+
typeof value.path === "string"
|
|
43
|
+
) {
|
|
44
|
+
resolved[key] = {
|
|
45
|
+
...value,
|
|
46
|
+
path: substituteCommandTemplateToken(
|
|
47
|
+
value.path,
|
|
48
|
+
values,
|
|
49
|
+
`recipe artifacts.${key}.path`,
|
|
50
|
+
),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return Object.keys(resolved).length > 0 ? resolved : undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function resolveArtifactManifest(
|
|
58
|
+
artifacts: Record<string, RunArtifactDeclaration> | undefined,
|
|
59
|
+
): Record<string, RunArtifactManifestEntry> | undefined {
|
|
60
|
+
if (!artifacts) return undefined;
|
|
61
|
+
const manifest: Record<string, RunArtifactManifestEntry> = {};
|
|
62
|
+
for (const [name, artifact] of Object.entries(artifacts)) {
|
|
63
|
+
const declaration =
|
|
64
|
+
typeof artifact === "string" ? { path: artifact } : artifact;
|
|
65
|
+
if (!declaration?.path) continue;
|
|
66
|
+
try {
|
|
67
|
+
const content = readFileSync(declaration.path);
|
|
68
|
+
manifest[name] = {
|
|
69
|
+
exists: true,
|
|
70
|
+
...(declaration.kind ? { kind: declaration.kind } : {}),
|
|
71
|
+
...(declaration.media_type
|
|
72
|
+
? { media_type: declaration.media_type }
|
|
73
|
+
: {}),
|
|
74
|
+
path: declaration.path,
|
|
75
|
+
...(declaration.required !== undefined
|
|
76
|
+
? { required: declaration.required }
|
|
77
|
+
: {}),
|
|
78
|
+
sha256: createHash("sha256").update(content).digest("hex"),
|
|
79
|
+
size: content.byteLength,
|
|
80
|
+
};
|
|
81
|
+
} catch {
|
|
82
|
+
manifest[name] = {
|
|
83
|
+
exists: false,
|
|
84
|
+
...(declaration.kind ? { kind: declaration.kind } : {}),
|
|
85
|
+
...(declaration.media_type
|
|
86
|
+
? { media_type: declaration.media_type }
|
|
87
|
+
: {}),
|
|
88
|
+
path: declaration.path,
|
|
89
|
+
...(declaration.required !== undefined
|
|
90
|
+
? { required: declaration.required }
|
|
91
|
+
: {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return Object.keys(manifest).length > 0 ? manifest : undefined;
|
|
96
|
+
}
|