@llblab/pi-actors 0.32.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.
Files changed (162) hide show
  1. package/AGENTS.md +23 -11
  2. package/BACKLOG.md +2 -30
  3. package/CHANGELOG.md +30 -1
  4. package/dist/index.js +10 -10
  5. package/dist/lib/async-runs.d.ts +23 -75
  6. package/dist/lib/async-runs.js +49 -801
  7. package/dist/lib/command-templates.d.ts +3 -3
  8. package/dist/lib/command-templates.js +3 -3
  9. package/dist/lib/config.d.ts +2 -2
  10. package/dist/lib/config.js +5 -5
  11. package/dist/lib/{output.d.ts → execution-output.d.ts} +3 -3
  12. package/dist/lib/{output.js → execution-output.js} +3 -3
  13. package/dist/lib/execution.js +1 -1
  14. package/dist/lib/{actor-inspector-tui.d.ts → inspector.d.ts} +3 -2
  15. package/dist/lib/{actor-inspector-tui.js → inspector.js} +3 -2
  16. package/dist/lib/mailbox-loop.d.ts +3 -3
  17. package/dist/lib/mailbox-loop.js +3 -3
  18. package/dist/lib/{actor-messages.d.ts → messages.d.ts} +3 -3
  19. package/dist/lib/{actor-messages.js → messages.js} +3 -3
  20. package/dist/lib/paths.d.ts +1 -1
  21. package/dist/lib/paths.js +3 -3
  22. package/dist/lib/{actor-recipe-context.d.ts → recipes-context.d.ts} +3 -2
  23. package/dist/lib/{actor-recipe-context.js → recipes-context.js} +2 -1
  24. package/dist/lib/{recipe-discovery.d.ts → recipes-discovery.d.ts} +9 -9
  25. package/dist/lib/{recipe-discovery.js → recipes-discovery.js} +17 -17
  26. package/dist/lib/registry.d.ts +1 -1
  27. package/dist/lib/registry.js +22 -22
  28. package/dist/lib/{actor-rooms.d.ts → rooms.d.ts} +4 -4
  29. package/dist/lib/{actor-rooms.js → rooms.js} +3 -3
  30. package/dist/lib/runs-artifacts.d.ts +21 -0
  31. package/dist/lib/runs-artifacts.js +68 -0
  32. package/dist/lib/runs-control.d.ts +13 -0
  33. package/dist/lib/runs-control.js +59 -0
  34. package/dist/lib/runs-identity.d.ts +5 -0
  35. package/dist/lib/runs-identity.js +11 -0
  36. package/dist/lib/runs-index.d.ts +18 -0
  37. package/dist/lib/runs-index.js +119 -0
  38. package/dist/lib/runs-mailbox.d.ts +25 -0
  39. package/dist/lib/runs-mailbox.js +146 -0
  40. package/dist/lib/runs-messages.d.ts +15 -0
  41. package/dist/lib/runs-messages.js +179 -0
  42. package/dist/lib/runs-outbox.d.ts +41 -0
  43. package/dist/lib/runs-outbox.js +87 -0
  44. package/dist/lib/runs-process.d.ts +7 -0
  45. package/dist/lib/runs-process.js +36 -0
  46. package/dist/lib/runs-retention.d.ts +8 -0
  47. package/dist/lib/runs-retention.js +56 -0
  48. package/dist/lib/runs-start.d.ts +9 -0
  49. package/dist/lib/runs-start.js +67 -0
  50. package/dist/lib/runs-status.d.ts +8 -0
  51. package/dist/lib/runs-status.js +60 -0
  52. package/dist/lib/runtime.d.ts +2 -2
  53. package/dist/lib/runtime.js +5 -5
  54. package/dist/lib/schema.d.ts +9 -0
  55. package/dist/lib/schema.js +40 -0
  56. package/dist/lib/tools-access.d.ts +19 -0
  57. package/dist/lib/tools-access.js +44 -0
  58. package/dist/lib/tools-inspect.d.ts +11 -0
  59. package/dist/lib/tools-inspect.js +534 -0
  60. package/dist/lib/tools-local.d.ts +14 -0
  61. package/dist/lib/tools-local.js +156 -0
  62. package/dist/lib/tools-mailbox.d.ts +8 -0
  63. package/dist/lib/tools-mailbox.js +48 -0
  64. package/dist/lib/tools-message.d.ts +9 -0
  65. package/dist/lib/tools-message.js +346 -0
  66. package/dist/lib/tools-register.d.ts +18 -0
  67. package/dist/lib/tools-register.js +40 -0
  68. package/dist/lib/tools-response.d.ts +21 -0
  69. package/dist/lib/tools-response.js +219 -0
  70. package/dist/lib/tools-spawn.d.ts +12 -0
  71. package/dist/lib/tools-spawn.js +159 -0
  72. package/dist/lib/tools.d.ts +13 -39
  73. package/dist/lib/tools.js +11 -1497
  74. package/dist/recipes/utility-coordinator-lock-snapshot.json +1 -1
  75. package/dist/scripts/actor-worker.mjs +186 -7
  76. package/dist/scripts/async-runner.mjs +171 -8
  77. package/dist/scripts/build-dist.mjs +1 -1
  78. package/dist/scripts/conformance.mjs +34 -18
  79. package/dist/scripts/coordinator.mjs +733 -11
  80. package/dist/scripts/locker.mjs +345 -16
  81. package/dist/scripts/recipe-utils.mjs +478 -14
  82. package/dist/scripts/validate-recipe.mjs +110 -10
  83. package/dist/skills/actors/SKILL.md +2 -2
  84. package/dist/skills/swarm/SKILL.md +2 -2
  85. package/docs/recipe-library.md +1 -1
  86. package/docs/template-recipes.md +1 -1
  87. package/docs/tool-registry.md +3 -3
  88. package/index.ts +12 -19
  89. package/lib/async-runs.ts +124 -1016
  90. package/lib/command-templates.ts +3 -3
  91. package/lib/config.ts +7 -7
  92. package/lib/{output.ts → execution-output.ts} +3 -3
  93. package/lib/execution.ts +5 -1
  94. package/lib/{actor-inspector-tui.ts → inspector.ts} +4 -3
  95. package/lib/mailbox-loop.ts +3 -3
  96. package/lib/{actor-messages.ts → messages.ts} +3 -3
  97. package/lib/paths.ts +3 -3
  98. package/lib/{actor-recipe-context.ts → recipes-context.ts} +3 -2
  99. package/lib/{recipe-discovery.ts → recipes-discovery.ts} +30 -30
  100. package/lib/{recipe-usage.ts → recipes-usage.ts} +2 -2
  101. package/lib/registry.ts +37 -24
  102. package/lib/{actor-rooms.ts → rooms.ts} +4 -4
  103. package/lib/runs-artifacts.ts +96 -0
  104. package/lib/runs-control.ts +85 -0
  105. package/lib/runs-identity.ts +14 -0
  106. package/lib/runs-index.ts +156 -0
  107. package/lib/runs-mailbox.ts +208 -0
  108. package/lib/runs-messages.ts +252 -0
  109. package/lib/runs-outbox.ts +144 -0
  110. package/lib/runs-process.ts +51 -0
  111. package/lib/runs-retention.ts +77 -0
  112. package/lib/runs-start.ts +98 -0
  113. package/lib/runs-status.ts +78 -0
  114. package/lib/runtime.ts +6 -6
  115. package/lib/schema.ts +55 -0
  116. package/lib/tools-access.ts +68 -0
  117. package/lib/tools-inspect.ts +735 -0
  118. package/lib/tools-local.ts +234 -0
  119. package/lib/tools-mailbox.ts +56 -0
  120. package/lib/tools-message.ts +483 -0
  121. package/lib/tools-register.ts +64 -0
  122. package/lib/tools-response.ts +267 -0
  123. package/lib/tools-spawn.ts +240 -0
  124. package/lib/tools.ts +26 -2051
  125. package/package.json +1 -1
  126. package/recipes/utility-coordinator-lock-snapshot.json +1 -1
  127. package/scripts/actor-worker.mjs +186 -7
  128. package/scripts/async-runner.mjs +171 -8
  129. package/scripts/build-dist.mjs +1 -1
  130. package/scripts/conformance.mjs +34 -18
  131. package/scripts/coordinator.mjs +733 -11
  132. package/scripts/locker.mjs +345 -16
  133. package/scripts/recipe-utils.mjs +478 -14
  134. package/scripts/validate-recipe.mjs +110 -10
  135. package/skills/actors/SKILL.md +2 -2
  136. package/skills/swarm/SKILL.md +2 -2
  137. package/dist/lib/actor-worker.d.ts +0 -16
  138. package/dist/lib/actor-worker.js +0 -134
  139. package/dist/lib/async-runner.d.ts +0 -5
  140. package/dist/lib/async-runner.js +0 -134
  141. package/dist/lib/conformance.d.ts +0 -12
  142. package/dist/lib/conformance.js +0 -28
  143. package/dist/lib/coordinator.d.ts +0 -5
  144. package/dist/lib/coordinator.js +0 -660
  145. package/dist/lib/locker.d.ts +0 -5
  146. package/dist/lib/locker.js +0 -310
  147. package/dist/lib/recipe-utils.d.ts +0 -5
  148. package/dist/lib/recipe-utils.js +0 -385
  149. package/dist/lib/validate-recipe.d.ts +0 -6
  150. package/dist/lib/validate-recipe.js +0 -104
  151. package/lib/actor-worker.ts +0 -174
  152. package/lib/async-runner.ts +0 -173
  153. package/lib/conformance.ts +0 -46
  154. package/lib/coordinator.ts +0 -742
  155. package/lib/locker.ts +0 -340
  156. package/lib/recipe-utils.ts +0 -486
  157. package/lib/validate-recipe.ts +0 -110
  158. /package/dist/lib/{recipe-references.d.ts → recipes-references.d.ts} +0 -0
  159. /package/dist/lib/{recipe-references.js → recipes-references.js} +0 -0
  160. /package/dist/lib/{recipe-usage.d.ts → recipes-usage.d.ts} +0 -0
  161. /package/dist/lib/{recipe-usage.js → recipes-usage.js} +0 -0
  162. /package/lib/{recipe-references.ts → recipes-references.ts} +0 -0
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Local tool definition behavior
3
+ * Zones: user recipe tools, generated schemas, async recipe launch
4
+ * Owns wrapping saved local capabilities as executable pi tools
5
+ */
6
+
7
+ import * as Rooms from "./rooms.ts";
8
+ import * as AsyncRuns from "./async-runs.ts";
9
+ import * as CommandTemplates from "./command-templates.ts";
10
+ import type { RegisteredTool } from "./config.ts";
11
+ import * as Execution from "./execution.ts";
12
+ import * as Prompts from "./prompts.ts";
13
+ import * as RecipesReferences from "./recipes-references.ts";
14
+ import * as RecipesUsage from "./recipes-usage.ts";
15
+ import * as Schema from "./schema.ts";
16
+ import * as ToolsResponse from "./tools-response.ts";
17
+
18
+ type JsonSchema = Schema.JsonSchema;
19
+
20
+ export interface RuntimeToolContext {
21
+ cwd: string;
22
+ sessionManager?: { getSessionId?: () => string };
23
+ }
24
+
25
+ function getRunOwnerId(ctx: RuntimeToolContext): string | undefined {
26
+ return ctx.sessionManager?.getSessionId?.();
27
+ }
28
+
29
+ function typedArgSchema(
30
+ arg: string,
31
+ type: Schema.ToolArgType | undefined,
32
+ ): JsonSchema {
33
+ const description =
34
+ !type || type.kind === "string"
35
+ ? `Argument: ${arg}`
36
+ : type.kind === "path"
37
+ ? `Path argument: ${arg}`
38
+ : `${type.kind[0].toUpperCase()}${type.kind.slice(1)} argument: ${arg}`;
39
+ return Schema.typedArgSchema(description, type);
40
+ }
41
+
42
+ function sampleValueForArg(
43
+ arg: string,
44
+ type: Schema.ToolArgType | undefined,
45
+ defaults: Record<string, unknown>,
46
+ ): unknown {
47
+ if (Object.hasOwn(defaults, arg)) return defaults[arg];
48
+ if (!type || type.kind === "string") return `<${arg}>`;
49
+ if (type.kind === "path") return `./${arg}`;
50
+ if (type.kind === "int") return 1;
51
+ if (type.kind === "number") return 1.5;
52
+ if (type.kind === "bool") return true;
53
+ if (type.kind === "array") return [`<${arg}>`];
54
+ return type.values[0] ?? `<${arg}>`;
55
+ }
56
+
57
+ function shouldAddRuntimeToolUsageHint(error: unknown): boolean {
58
+ const message = error instanceof Error ? error.message : String(error);
59
+ return (
60
+ /^Argument \S+ must /.test(message) || /^Missing .* value: /.test(message)
61
+ );
62
+ }
63
+
64
+ function formatRuntimeToolUsageHint(
65
+ cfg: RegisteredTool,
66
+ required: string[],
67
+ includeRunId: boolean,
68
+ ): string {
69
+ const optional = cfg.args.filter((arg) => !required.includes(arg));
70
+ const example: Record<string, unknown> = {};
71
+ for (const arg of required)
72
+ example[arg] = sampleValueForArg(arg, cfg.argTypes?.[arg], cfg.defaults);
73
+ for (const arg of optional)
74
+ example[arg] = sampleValueForArg(arg, cfg.argTypes?.[arg], cfg.defaults);
75
+ if (includeRunId) example.run_id = `${cfg.name}-1`;
76
+ const lines = [
77
+ `Expected call shape for ${cfg.name}:`,
78
+ `${cfg.name}(${JSON.stringify(example, null, 2)})`,
79
+ ];
80
+ if (required.length) lines.push(`Required: ${required.join(", ")}`);
81
+ if (optional.length || includeRunId)
82
+ lines.push(
83
+ `Optional: ${[...optional, ...(includeRunId ? ["run_id"] : [])].join(", ")}`,
84
+ );
85
+ return lines.join("\n");
86
+ }
87
+
88
+ function formatRuntimeToolArgumentError(
89
+ cfg: RegisteredTool,
90
+ error: unknown,
91
+ required: string[],
92
+ includeRunId: boolean,
93
+ ): Error {
94
+ const message = error instanceof Error ? error.message : String(error);
95
+ if (!shouldAddRuntimeToolUsageHint(error))
96
+ return error instanceof Error ? error : new Error(message);
97
+ return new Error(
98
+ `Invalid arguments for tool "${cfg.name}": ${message}\n\n${formatRuntimeToolUsageHint(
99
+ cfg,
100
+ required,
101
+ includeRunId,
102
+ )}`,
103
+ );
104
+ }
105
+
106
+ export function createRuntimeToolDefinition(
107
+ cfg: RegisteredTool,
108
+ exec: Execution.RegisteredToolExec,
109
+ ): any {
110
+ const paramSchema: Record<string, JsonSchema> = {};
111
+ const required: string[] = [];
112
+ const isRecipe = RecipesReferences.isRecipeTool(cfg.template, cfg.recipe);
113
+ const isAsyncRecipe =
114
+ cfg.recipe?.async === true ||
115
+ RecipesReferences.isAsyncRecipeReference(cfg.template);
116
+ const recipeTemplate =
117
+ cfg.recipe?.template ?? RecipesReferences.getRecipeTemplate(cfg.template);
118
+ const requiredTemplate = recipeTemplate ?? cfg.template!;
119
+ const requiredTemplateConfig: CommandTemplates.CommandTemplateConfig =
120
+ typeof requiredTemplate === "object" && !Array.isArray(requiredTemplate)
121
+ ? {
122
+ ...requiredTemplate,
123
+ args: cfg.args,
124
+ defaults: { ...(requiredTemplate.defaults ?? {}), ...cfg.defaults },
125
+ }
126
+ : {
127
+ args: cfg.args,
128
+ defaults: cfg.defaults,
129
+ template: requiredTemplate,
130
+ };
131
+ const requiredArgs =
132
+ isRecipe && cfg.storedArgs !== undefined
133
+ ? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg)))
134
+ : RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
135
+ ? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg)))
136
+ : Schema.getRequiredToolArgNames(requiredTemplateConfig);
137
+ for (const arg of cfg.args) {
138
+ paramSchema[arg] = typedArgSchema(arg, cfg.argTypes?.[arg]);
139
+ if (requiredArgs.has(arg)) required.push(arg);
140
+ }
141
+ if (isAsyncRecipe)
142
+ paramSchema.run_id = Schema.stringSchema(
143
+ "Optional run id override for this async template recipe invocation.",
144
+ );
145
+ return {
146
+ name: cfg.name,
147
+ label: cfg.name,
148
+ description: cfg.description,
149
+ parameters: Schema.objectSchema(paramSchema, required),
150
+ promptSnippet: isRecipe
151
+ ? Prompts.formatRecipeToolPromptSnippet(
152
+ cfg.recipe?.name ?? String(cfg.template),
153
+ isAsyncRecipe,
154
+ )
155
+ : Prompts.formatRegisteredToolPromptSnippet(cfg.template),
156
+ async execute(
157
+ _toolCallId: string,
158
+ params: unknown,
159
+ signal: AbortSignal | undefined,
160
+ _onUpdate: unknown,
161
+ ctx: RuntimeToolContext,
162
+ ) {
163
+ try {
164
+ if (cfg.sourcePath)
165
+ RecipesUsage.recordRecipeLaunch(cfg.sourcePath, new Date(), "tool");
166
+ if (isAsyncRecipe) {
167
+ const input = params as Record<string, unknown>;
168
+ const { run_id, ...values } = input;
169
+ const base = cfg.recipe ? cfg.recipe : { file: String(cfg.template) };
170
+ const runId =
171
+ typeof run_id === "string" && run_id.trim()
172
+ ? run_id.trim()
173
+ : `${cfg.name}-${Date.now()}`;
174
+ const meta = AsyncRuns.startRun(
175
+ {
176
+ ...base,
177
+ launch_source: "tool",
178
+ ownerId: getRunOwnerId(ctx),
179
+ run_id: runId,
180
+ tool: cfg.name,
181
+ values: Schema.normalizeRuntimeValues(
182
+ { ...(cfg.recipe?.values ?? {}), ...cfg.defaults, ...values },
183
+ cfg.argTypes,
184
+ ),
185
+ },
186
+ ctx.cwd,
187
+ );
188
+ Rooms.ensureDefaultRoom(meta.state_dir, String(meta.run));
189
+ Rooms.writeCommunicationSnapshot(meta.state_dir, String(meta.run));
190
+ return {
191
+ content: [
192
+ {
193
+ type: "text" as const,
194
+ text: ToolsResponse.compactAsyncRunStatus(meta),
195
+ },
196
+ ],
197
+ details: meta,
198
+ };
199
+ }
200
+ if (isRecipe && recipeTemplate) {
201
+ const paramsWithDefaults = {
202
+ ...(cfg.recipe?.values ?? {}),
203
+ ...cfg.defaults,
204
+ ...(params as Record<string, unknown>),
205
+ };
206
+ return await Execution.executeRegisteredTool(
207
+ { ...cfg, template: recipeTemplate },
208
+ Schema.normalizeRuntimeValues(paramsWithDefaults, cfg.argTypes),
209
+ exec,
210
+ ctx.cwd,
211
+ signal,
212
+ );
213
+ }
214
+ return await Execution.executeRegisteredTool(
215
+ cfg,
216
+ Schema.normalizeRuntimeValues(
217
+ params as Record<string, unknown>,
218
+ cfg.argTypes,
219
+ ),
220
+ exec,
221
+ ctx.cwd,
222
+ signal,
223
+ );
224
+ } catch (error) {
225
+ throw formatRuntimeToolArgumentError(
226
+ cfg,
227
+ error,
228
+ required,
229
+ isAsyncRecipe,
230
+ );
231
+ }
232
+ },
233
+ };
234
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Public tool mailbox contract helpers
3
+ * Zones: accepted/emitted message type declarations, contract normalization, compact type extraction
4
+ * Owns mailbox metadata normalization for public message and inspect tool paths
5
+ */
6
+
7
+ function asRecord(value: unknown): Record<string, unknown> {
8
+ return value && typeof value === "object" && !Array.isArray(value)
9
+ ? (value as Record<string, unknown>)
10
+ : {};
11
+ }
12
+
13
+ export function normalizeMailboxEntry(
14
+ value: unknown,
15
+ ): Record<string, unknown> | undefined {
16
+ if (typeof value === "string") return { type: value };
17
+ const record = asRecord(value);
18
+ if (typeof record.type !== "string" || !record.type.trim()) return undefined;
19
+ return {
20
+ type: record.type.trim(),
21
+ ...(record.body_schema !== undefined
22
+ ? { body_schema: record.body_schema }
23
+ : {}),
24
+ ...(record.ack !== undefined ? { ack: record.ack } : {}),
25
+ ...(typeof record.idempotency === "string"
26
+ ? { idempotency: record.idempotency }
27
+ : {}),
28
+ ...(typeof record.level === "string" ? { level: record.level } : {}),
29
+ ...(record.requires_response === true ? { requires_response: true } : {}),
30
+ ...(typeof record.summary === "string" ? { summary: record.summary } : {}),
31
+ };
32
+ }
33
+
34
+ export function normalizeMailboxContracts(
35
+ mailbox: Record<string, unknown>,
36
+ ): Record<string, unknown[]> {
37
+ const accepts = Array.isArray(mailbox.accepts)
38
+ ? mailbox.accepts
39
+ .map(normalizeMailboxEntry)
40
+ .filter((entry): entry is Record<string, unknown> => Boolean(entry))
41
+ : [];
42
+ const emits = Array.isArray(mailbox.emits)
43
+ ? mailbox.emits
44
+ .map(normalizeMailboxEntry)
45
+ .filter((entry): entry is Record<string, unknown> => Boolean(entry))
46
+ : [];
47
+ return { accepts, emits };
48
+ }
49
+
50
+ export function mailboxTypes(entries: unknown[]): string[] {
51
+ return entries.flatMap((entry) =>
52
+ typeof asRecord(entry).type === "string"
53
+ ? [String(asRecord(entry).type)]
54
+ : [],
55
+ );
56
+ }