@llblab/pi-actors 0.33.0 → 0.34.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.
Files changed (155) hide show
  1. package/AGENTS.md +22 -11
  2. package/BACKLOG.md +3 -34
  3. package/CHANGELOG.md +14 -0
  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/{actor-recipe-context.d.ts → recipes-context.d.ts} +3 -2
  21. package/dist/lib/{actor-recipe-context.js → recipes-context.js} +2 -1
  22. package/dist/lib/{recipe-discovery.d.ts → recipes-discovery.d.ts} +8 -8
  23. package/dist/lib/{recipe-discovery.js → recipes-discovery.js} +6 -6
  24. package/dist/lib/registry.d.ts +1 -1
  25. package/dist/lib/registry.js +22 -22
  26. package/dist/lib/{actor-rooms.d.ts → rooms.d.ts} +4 -4
  27. package/dist/lib/{actor-rooms.js → rooms.js} +3 -3
  28. package/dist/lib/runs-artifacts.d.ts +21 -0
  29. package/dist/lib/runs-artifacts.js +68 -0
  30. package/dist/lib/runs-control.d.ts +13 -0
  31. package/dist/lib/runs-control.js +59 -0
  32. package/dist/lib/runs-identity.d.ts +5 -0
  33. package/dist/lib/runs-identity.js +11 -0
  34. package/dist/lib/runs-index.d.ts +18 -0
  35. package/dist/lib/runs-index.js +119 -0
  36. package/dist/lib/runs-mailbox.d.ts +25 -0
  37. package/dist/lib/runs-mailbox.js +146 -0
  38. package/dist/lib/runs-messages.d.ts +15 -0
  39. package/dist/lib/runs-messages.js +179 -0
  40. package/dist/lib/runs-outbox.d.ts +41 -0
  41. package/dist/lib/runs-outbox.js +87 -0
  42. package/dist/lib/runs-process.d.ts +7 -0
  43. package/dist/lib/runs-process.js +36 -0
  44. package/dist/lib/runs-retention.d.ts +8 -0
  45. package/dist/lib/runs-retention.js +56 -0
  46. package/dist/lib/runs-start.d.ts +9 -0
  47. package/dist/lib/runs-start.js +67 -0
  48. package/dist/lib/runs-status.d.ts +8 -0
  49. package/dist/lib/runs-status.js +60 -0
  50. package/dist/lib/runtime.d.ts +2 -2
  51. package/dist/lib/runtime.js +5 -5
  52. package/dist/lib/schema.d.ts +9 -0
  53. package/dist/lib/schema.js +40 -0
  54. package/dist/lib/tools-access.d.ts +19 -0
  55. package/dist/lib/tools-access.js +44 -0
  56. package/dist/lib/tools-inspect.d.ts +11 -0
  57. package/dist/lib/tools-inspect.js +534 -0
  58. package/dist/lib/tools-local.d.ts +14 -0
  59. package/dist/lib/tools-local.js +156 -0
  60. package/dist/lib/tools-mailbox.d.ts +8 -0
  61. package/dist/lib/tools-mailbox.js +48 -0
  62. package/dist/lib/tools-message.d.ts +9 -0
  63. package/dist/lib/tools-message.js +428 -0
  64. package/dist/lib/tools-register.d.ts +18 -0
  65. package/dist/lib/tools-register.js +40 -0
  66. package/dist/lib/tools-response.d.ts +21 -0
  67. package/dist/lib/tools-response.js +219 -0
  68. package/dist/lib/tools-spawn.d.ts +12 -0
  69. package/dist/lib/tools-spawn.js +159 -0
  70. package/dist/lib/tools.d.ts +8 -39
  71. package/dist/lib/tools.js +11 -1490
  72. package/dist/recipes/utility-coordinator-lock-snapshot.json +1 -1
  73. package/dist/scripts/actor-worker.mjs +190 -7
  74. package/dist/scripts/async-runner.mjs +171 -8
  75. package/dist/scripts/build-dist.mjs +1 -1
  76. package/dist/scripts/conformance.mjs +3 -3
  77. package/dist/scripts/coordinator.mjs +733 -11
  78. package/dist/scripts/locker.mjs +345 -16
  79. package/dist/scripts/recipe-utils.mjs +478 -14
  80. package/dist/scripts/validate-recipe.mjs +110 -10
  81. package/dist/skills/actors/SKILL.md +1 -1
  82. package/dist/skills/swarm/SKILL.md +1 -1
  83. package/docs/recipe-library.md +1 -1
  84. package/docs/template-recipes.md +1 -1
  85. package/index.ts +11 -18
  86. package/lib/async-runs.ts +124 -1016
  87. package/lib/command-templates.ts +3 -3
  88. package/lib/config.ts +7 -7
  89. package/lib/{output.ts → execution-output.ts} +3 -3
  90. package/lib/execution.ts +5 -1
  91. package/lib/{actor-inspector-tui.ts → inspector.ts} +4 -3
  92. package/lib/mailbox-loop.ts +3 -3
  93. package/lib/{actor-messages.ts → messages.ts} +3 -3
  94. package/lib/{actor-recipe-context.ts → recipes-context.ts} +3 -2
  95. package/lib/{recipe-discovery.ts → recipes-discovery.ts} +19 -19
  96. package/lib/{recipe-usage.ts → recipes-usage.ts} +2 -2
  97. package/lib/registry.ts +37 -24
  98. package/lib/{actor-rooms.ts → rooms.ts} +4 -4
  99. package/lib/runs-artifacts.ts +96 -0
  100. package/lib/runs-control.ts +85 -0
  101. package/lib/runs-identity.ts +14 -0
  102. package/lib/runs-index.ts +156 -0
  103. package/lib/runs-mailbox.ts +208 -0
  104. package/lib/runs-messages.ts +252 -0
  105. package/lib/runs-outbox.ts +144 -0
  106. package/lib/runs-process.ts +51 -0
  107. package/lib/runs-retention.ts +77 -0
  108. package/lib/runs-start.ts +98 -0
  109. package/lib/runs-status.ts +78 -0
  110. package/lib/runtime.ts +6 -6
  111. package/lib/schema.ts +55 -0
  112. package/lib/tools-access.ts +68 -0
  113. package/lib/tools-inspect.ts +735 -0
  114. package/lib/tools-local.ts +234 -0
  115. package/lib/tools-mailbox.ts +56 -0
  116. package/lib/tools-message.ts +569 -0
  117. package/lib/tools-register.ts +64 -0
  118. package/lib/tools-response.ts +267 -0
  119. package/lib/tools-spawn.ts +240 -0
  120. package/lib/tools.ts +20 -2040
  121. package/package.json +1 -1
  122. package/recipes/utility-coordinator-lock-snapshot.json +1 -1
  123. package/scripts/actor-worker.mjs +190 -7
  124. package/scripts/async-runner.mjs +171 -8
  125. package/scripts/build-dist.mjs +1 -1
  126. package/scripts/conformance.mjs +3 -3
  127. package/scripts/coordinator.mjs +733 -11
  128. package/scripts/locker.mjs +345 -16
  129. package/scripts/recipe-utils.mjs +478 -14
  130. package/scripts/validate-recipe.mjs +110 -10
  131. package/skills/actors/SKILL.md +1 -1
  132. package/skills/swarm/SKILL.md +1 -1
  133. package/dist/lib/actor-worker.d.ts +0 -16
  134. package/dist/lib/actor-worker.js +0 -134
  135. package/dist/lib/async-runner.d.ts +0 -5
  136. package/dist/lib/async-runner.js +0 -134
  137. package/dist/lib/coordinator.d.ts +0 -5
  138. package/dist/lib/coordinator.js +0 -660
  139. package/dist/lib/locker.d.ts +0 -5
  140. package/dist/lib/locker.js +0 -310
  141. package/dist/lib/recipe-utils.d.ts +0 -5
  142. package/dist/lib/recipe-utils.js +0 -385
  143. package/dist/lib/validate-recipe.d.ts +0 -6
  144. package/dist/lib/validate-recipe.js +0 -104
  145. package/lib/actor-worker.ts +0 -174
  146. package/lib/async-runner.ts +0 -173
  147. package/lib/coordinator.ts +0 -742
  148. package/lib/locker.ts +0 -340
  149. package/lib/recipe-utils.ts +0 -486
  150. package/lib/validate-recipe.ts +0 -110
  151. /package/dist/lib/{recipe-references.d.ts → recipes-references.d.ts} +0 -0
  152. /package/dist/lib/{recipe-references.js → recipes-references.js} +0 -0
  153. /package/dist/lib/{recipe-usage.d.ts → recipes-usage.d.ts} +0 -0
  154. /package/dist/lib/{recipe-usage.js → recipes-usage.js} +0 -0
  155. /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
+ }