@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
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public tool response formatting
|
|
3
|
+
* Zones: compact text summaries, verbose JSON switching, next-action rendering
|
|
4
|
+
* Owns model-facing response helpers shared by public tool execution paths
|
|
5
|
+
*/
|
|
6
|
+
import * as Limits from "./limits.js";
|
|
7
|
+
import * as ToolsMailbox from "./tools-mailbox.js";
|
|
8
|
+
export function asRecord(value) {
|
|
9
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
10
|
+
? value
|
|
11
|
+
: {};
|
|
12
|
+
}
|
|
13
|
+
export function jsonText(value) {
|
|
14
|
+
return `\n${JSON.stringify(value, null, 2)}`;
|
|
15
|
+
}
|
|
16
|
+
export function compactPreview(value, maxLength = Limits.COMPACT_PREVIEW_CHARS) {
|
|
17
|
+
if (value === undefined)
|
|
18
|
+
return undefined;
|
|
19
|
+
const text = typeof value === "string" ? value : JSON.stringify(value, undefined, 0);
|
|
20
|
+
const compact = text.replaceAll(/\s+/g, "_");
|
|
21
|
+
return compact.length > maxLength
|
|
22
|
+
? `${compact.slice(0, Math.max(0, maxLength - 1))}…`
|
|
23
|
+
: compact;
|
|
24
|
+
}
|
|
25
|
+
export function compactNextActions(actions) {
|
|
26
|
+
return actions.length
|
|
27
|
+
? ` next=${actions.map((action) => action.replaceAll(/\s+/g, "_")).join("|")}`
|
|
28
|
+
: "";
|
|
29
|
+
}
|
|
30
|
+
function formatFailureCount(value) {
|
|
31
|
+
return Array.isArray(value) ? value.length : undefined;
|
|
32
|
+
}
|
|
33
|
+
export function actorRunNextActions(run) {
|
|
34
|
+
const id = String(run ?? "").trim();
|
|
35
|
+
if (!id)
|
|
36
|
+
return [];
|
|
37
|
+
return [
|
|
38
|
+
`inspect target=run:${id} view=status`,
|
|
39
|
+
`inspect target=run:${id} view=messages`,
|
|
40
|
+
`message to=run:${id} type=<actor.action>`,
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
export function compactAsyncRunStatus(value) {
|
|
44
|
+
const status = asRecord(value);
|
|
45
|
+
const progress = asRecord(status.progress);
|
|
46
|
+
const result = asRecord(status.result);
|
|
47
|
+
const run = String(status.run ?? "<unknown>");
|
|
48
|
+
const tokens = [`run=${run}`, `status=${String(status.status ?? "unknown")}`];
|
|
49
|
+
if (status.tool)
|
|
50
|
+
tokens.push(`tool=${String(status.tool)}`);
|
|
51
|
+
if (status.recipe)
|
|
52
|
+
tokens.push(`recipe=${String(status.recipe)}`);
|
|
53
|
+
if (status.retire_when)
|
|
54
|
+
tokens.push(`retire_when=${String(status.retire_when)}`);
|
|
55
|
+
if (Number(status.pid) > 0)
|
|
56
|
+
tokens.push(`pid=${Number(status.pid)}`);
|
|
57
|
+
if (progress.phase && progress.phase !== status.status)
|
|
58
|
+
tokens.push(`phase=${String(progress.phase)}`);
|
|
59
|
+
if (Number(progress.activeSubagents) > 0)
|
|
60
|
+
tokens.push(`active=${Number(progress.activeSubagents)}`);
|
|
61
|
+
if (Number(progress.completed) > 0)
|
|
62
|
+
tokens.push(`completed=${Number(progress.completed)}`);
|
|
63
|
+
const failures = formatFailureCount(progress.failures);
|
|
64
|
+
if (failures !== undefined && failures > 0)
|
|
65
|
+
tokens.push(`failures=${failures}`);
|
|
66
|
+
if (result.code !== undefined)
|
|
67
|
+
tokens.push(`code=${String(result.code)}`);
|
|
68
|
+
if (result.killed === true)
|
|
69
|
+
tokens.push("killed=true");
|
|
70
|
+
const draftRecipe = status.draft_recipe;
|
|
71
|
+
if (draftRecipe)
|
|
72
|
+
tokens.push(`draft_recipe=${String(draftRecipe)}`);
|
|
73
|
+
const nextActions = actorRunNextActions(run);
|
|
74
|
+
if (nextActions.length > 0)
|
|
75
|
+
tokens.push(`next=${nextActions.map((action) => action.replaceAll(/\s+/g, "_")).join("|")}`);
|
|
76
|
+
return `\n${tokens.join(" ")}`;
|
|
77
|
+
}
|
|
78
|
+
export function compactInboxMessages(messages, emptyLabel) {
|
|
79
|
+
if (messages.length === 0)
|
|
80
|
+
return `\n(no ${emptyLabel} messages)`;
|
|
81
|
+
return `\n${messages
|
|
82
|
+
.map((message) => [
|
|
83
|
+
...(message.id ? [`id=${String(message.id)}`] : []),
|
|
84
|
+
`status=${String(message.status ?? "")}`,
|
|
85
|
+
`type=${String(message.type ?? "")}`,
|
|
86
|
+
`from=${String(message.from ?? "")}`,
|
|
87
|
+
`to=${String(message.to ?? "")}`,
|
|
88
|
+
...(message.queued_at
|
|
89
|
+
? [`queued_at=${String(message.queued_at)}`]
|
|
90
|
+
: []),
|
|
91
|
+
...(message.sent_at ? [`sent_at=${String(message.sent_at)}`] : []),
|
|
92
|
+
...(message.claimed_at
|
|
93
|
+
? [`claimed_at=${String(message.claimed_at)}`]
|
|
94
|
+
: []),
|
|
95
|
+
...(message.handled_at
|
|
96
|
+
? [`handled_at=${String(message.handled_at)}`]
|
|
97
|
+
: []),
|
|
98
|
+
...(message.failed_at
|
|
99
|
+
? [`failed_at=${String(message.failed_at)}`]
|
|
100
|
+
: []),
|
|
101
|
+
].join(" "))
|
|
102
|
+
.join("\n")}`;
|
|
103
|
+
}
|
|
104
|
+
export function compactBranchInbox(messages) {
|
|
105
|
+
return compactInboxMessages(messages, "branch inbox");
|
|
106
|
+
}
|
|
107
|
+
export function compactRunMailbox(run, mailbox, messages) {
|
|
108
|
+
const normalized = ToolsMailbox.normalizeMailboxContracts(mailbox);
|
|
109
|
+
return `\nrun=${run} accepts=${ToolsMailbox.mailboxTypes(normalized.accepts).join(",")} emits=${ToolsMailbox.mailboxTypes(normalized.emits).join(",")}${compactInboxMessages(messages, "run inbox")}`;
|
|
110
|
+
}
|
|
111
|
+
export function artifactNextActions(run, artifacts) {
|
|
112
|
+
const id = String(run ?? "").trim();
|
|
113
|
+
if (!id || Object.keys(artifacts).length === 0)
|
|
114
|
+
return [];
|
|
115
|
+
return [
|
|
116
|
+
`inspect target=run:${id} view=artifacts verbose=true`,
|
|
117
|
+
`inspect target=run:${id} view=messages`,
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
export function maybeJsonText(value, verbose, compact) {
|
|
121
|
+
return verbose ? jsonText(value) : compact;
|
|
122
|
+
}
|
|
123
|
+
export function compactRecipeImports(summary) {
|
|
124
|
+
const active = Array.isArray(summary.active)
|
|
125
|
+
? summary.active
|
|
126
|
+
: [];
|
|
127
|
+
const lines = active.flatMap((entry) => {
|
|
128
|
+
const imports = asRecord(entry.imports);
|
|
129
|
+
return Object.entries(imports).map(([alias, value]) => {
|
|
130
|
+
const binding = typeof value === "string" ? { from: value } : asRecord(value);
|
|
131
|
+
return `recipe=${String(entry.id ?? "<unknown>")} alias=${alias} from=${String(binding.from ?? value)}`;
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
return lines.length ? `\n${lines.join("\n")}` : "\n(no recipe imports)";
|
|
135
|
+
}
|
|
136
|
+
export function compactRecipeDoctor(summary) {
|
|
137
|
+
const details = Array.isArray(summary.diagnostic_details)
|
|
138
|
+
? summary.diagnostic_details
|
|
139
|
+
: [];
|
|
140
|
+
const remediations = Array.isArray(summary.remediations)
|
|
141
|
+
? summary.remediations
|
|
142
|
+
: [];
|
|
143
|
+
const recommendations = Array.isArray(summary.recommendations)
|
|
144
|
+
? summary.recommendations
|
|
145
|
+
: [];
|
|
146
|
+
const counts = { error: 0, info: 0, warning: 0 };
|
|
147
|
+
for (const detail of details) {
|
|
148
|
+
const severity = String(detail.severity ?? "info");
|
|
149
|
+
if (severity === "error" || severity === "warning" || severity === "info")
|
|
150
|
+
counts[severity] += 1;
|
|
151
|
+
}
|
|
152
|
+
const topAction = asRecord(summary.top_action);
|
|
153
|
+
const lines = [
|
|
154
|
+
`recipes doctor errors=${counts.error} warnings=${counts.warning} info=${counts.info} actions=${remediations.length} recommendations=${recommendations.length}`,
|
|
155
|
+
];
|
|
156
|
+
if (Object.keys(topAction).length > 0) {
|
|
157
|
+
const action = compactPreview(topAction.action, Limits.DOCTOR_ACTION_PREVIEW_CHARS);
|
|
158
|
+
lines.push(`top severity=${String(topAction.severity ?? "info")} kind=${String(topAction.kind ?? "inspect")} id=${String(topAction.id ?? "root")} action=${action ?? "inspect"}`);
|
|
159
|
+
}
|
|
160
|
+
for (const item of remediations.slice(0, 8)) {
|
|
161
|
+
const action = compactPreview(item.action, Limits.DOCTOR_ACTION_PREVIEW_CHARS);
|
|
162
|
+
const blocked = item.blocked_fallback
|
|
163
|
+
? ` blocked=${compactPreview(item.blocked_fallback, Limits.DOCTOR_ACTION_PREVIEW_CHARS)}`
|
|
164
|
+
: "";
|
|
165
|
+
lines.push(`${String(item.severity ?? "info")} kind=${String(item.kind ?? "inspect")} id=${String(item.id ?? "root")}${blocked} action=${action ?? "inspect"}`);
|
|
166
|
+
}
|
|
167
|
+
const nextActions = Array.isArray(summary.next_actions)
|
|
168
|
+
? summary.next_actions
|
|
169
|
+
: [];
|
|
170
|
+
if (nextActions.length > 0)
|
|
171
|
+
lines[0] = `${lines[0]}${compactNextActions(nextActions)}`;
|
|
172
|
+
return `\n${lines.join("\n")}`;
|
|
173
|
+
}
|
|
174
|
+
export function recipeRegistryNextActions(summary, view) {
|
|
175
|
+
const actions = [];
|
|
176
|
+
const drafts = Array.isArray(summary.drafts)
|
|
177
|
+
? summary.drafts
|
|
178
|
+
: [];
|
|
179
|
+
const invalid = Array.isArray(summary.invalid) ? summary.invalid.length : 0;
|
|
180
|
+
const diagnostics = Array.isArray(summary.diagnostics)
|
|
181
|
+
? summary.diagnostics.length
|
|
182
|
+
: 0;
|
|
183
|
+
const topAction = asRecord(summary.top_action);
|
|
184
|
+
if (view !== "doctor" && (invalid > 0 || diagnostics > 0)) {
|
|
185
|
+
actions.push("inspect target=recipes view=doctor");
|
|
186
|
+
}
|
|
187
|
+
if (view === "doctor" && typeof topAction.action === "string") {
|
|
188
|
+
actions.push(String(topAction.action));
|
|
189
|
+
}
|
|
190
|
+
if (drafts.length > 0) {
|
|
191
|
+
actions.push("inspect target=recipes view=summary verbose=true");
|
|
192
|
+
const firstPath = typeof drafts[0]?.path === "string" ? drafts[0].path : undefined;
|
|
193
|
+
if (firstPath)
|
|
194
|
+
actions.push(`spawn file=${firstPath}`);
|
|
195
|
+
}
|
|
196
|
+
return [...new Set(actions)].slice(0, 4);
|
|
197
|
+
}
|
|
198
|
+
export function compactRecipeRegistry(summary) {
|
|
199
|
+
const active = Array.isArray(summary.active) ? summary.active.length : 0;
|
|
200
|
+
const shadowed = Array.isArray(summary.shadowed)
|
|
201
|
+
? summary.shadowed.length
|
|
202
|
+
: 0;
|
|
203
|
+
const invalid = Array.isArray(summary.invalid) ? summary.invalid.length : 0;
|
|
204
|
+
const disabled = Array.isArray(summary.disabled)
|
|
205
|
+
? summary.disabled.length
|
|
206
|
+
: 0;
|
|
207
|
+
const diagnostics = Array.isArray(summary.diagnostics)
|
|
208
|
+
? summary.diagnostics.length
|
|
209
|
+
: 0;
|
|
210
|
+
const drafts = Array.isArray(summary.drafts) ? summary.drafts.length : 0;
|
|
211
|
+
const recommendations = Array.isArray(summary.recommendations)
|
|
212
|
+
? summary.recommendations.length
|
|
213
|
+
: 0;
|
|
214
|
+
const nextActions = Array.isArray(summary.next_actions)
|
|
215
|
+
? summary.next_actions
|
|
216
|
+
: [];
|
|
217
|
+
return `\nrecipes active=${active} drafts=${drafts} shadowed=${shadowed} invalid=${invalid} disabled=${disabled} recommendations=${recommendations} diagnostics=${diagnostics}${compactNextActions(nextActions)}`;
|
|
218
|
+
}
|
|
219
|
+
export const DEFAULT_INSPECT_LINES = Limits.DEFAULT_INSPECT_LINES;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public spawn tool behavior
|
|
3
|
+
* Zones: actor launch, draft recipe capture, launch diagnostics
|
|
4
|
+
* Owns the public spawn execution path for run-backed actors
|
|
5
|
+
*/
|
|
6
|
+
export interface SpawnToolContext {
|
|
7
|
+
cwd: string;
|
|
8
|
+
sessionManager?: {
|
|
9
|
+
getSessionId?: () => string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export declare function createSpawnToolDefinition<TContext extends SpawnToolContext>(): any;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public spawn tool behavior
|
|
3
|
+
* Zones: actor launch, draft recipe capture, launch diagnostics
|
|
4
|
+
* Owns the public spawn execution path for run-backed actors
|
|
5
|
+
*/
|
|
6
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import * as AsyncRuns from "./async-runs.js";
|
|
9
|
+
import * as Messages from "./messages.js";
|
|
10
|
+
import * as Paths from "./paths.js";
|
|
11
|
+
import * as RecipesDiscovery from "./recipes-discovery.js";
|
|
12
|
+
import * as Rooms from "./rooms.js";
|
|
13
|
+
import * as Schema from "./schema.js";
|
|
14
|
+
import * as ToolsResponse from "./tools-response.js";
|
|
15
|
+
const asRecord = ToolsResponse.asRecord;
|
|
16
|
+
const maybeJsonText = ToolsResponse.maybeJsonText;
|
|
17
|
+
function getRunOwnerId(ctx) {
|
|
18
|
+
return ctx.sessionManager?.getSessionId?.();
|
|
19
|
+
}
|
|
20
|
+
function shadowedRecipeLaunchDiagnostic(recipe) {
|
|
21
|
+
if (typeof recipe !== "string" ||
|
|
22
|
+
recipe.includes("/") ||
|
|
23
|
+
recipe.includes("~"))
|
|
24
|
+
return undefined;
|
|
25
|
+
const discovery = RecipesDiscovery.discoverRecipeSources([
|
|
26
|
+
{ root: Paths.getRecipeRoot(), defaultTool: true, mutableUsage: true },
|
|
27
|
+
{ root: Paths.getPackagedRecipeRoot(), defaultTool: false },
|
|
28
|
+
]);
|
|
29
|
+
return RecipesDiscovery.getShadowedLaunchDiagnostic(discovery, recipe);
|
|
30
|
+
}
|
|
31
|
+
function draftRecipeName(run) {
|
|
32
|
+
return `${run.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "spawn"}.json`;
|
|
33
|
+
}
|
|
34
|
+
function draftRecipeDefaults(values) {
|
|
35
|
+
const ignored = new Set([
|
|
36
|
+
"actor_address",
|
|
37
|
+
"communication_file",
|
|
38
|
+
"default_room",
|
|
39
|
+
"run_id",
|
|
40
|
+
"state_dir",
|
|
41
|
+
]);
|
|
42
|
+
const defaults = Object.fromEntries(Object.entries(values).filter(([key]) => !ignored.has(key)));
|
|
43
|
+
return Object.keys(defaults).length > 0 ? defaults : undefined;
|
|
44
|
+
}
|
|
45
|
+
function writeSpawnDraftRecipe(input, meta) {
|
|
46
|
+
if (process.env.NODE_TEST_CONTEXT &&
|
|
47
|
+
process.env.PI_ACTORS_ENABLE_SPAWN_DRAFTS_IN_TEST !== "1")
|
|
48
|
+
return undefined;
|
|
49
|
+
if (input.template === undefined ||
|
|
50
|
+
input.file !== undefined ||
|
|
51
|
+
input.recipe !== undefined)
|
|
52
|
+
return undefined;
|
|
53
|
+
const root = Paths.getRecipeDraftRoot();
|
|
54
|
+
mkdirSync(root, { recursive: true });
|
|
55
|
+
const path = join(root, draftRecipeName(String(meta.run)));
|
|
56
|
+
const defaults = draftRecipeDefaults(meta.values);
|
|
57
|
+
const recipe = {
|
|
58
|
+
async: true,
|
|
59
|
+
description: `Draft recipe captured from spawn run ${String(meta.run)}`,
|
|
60
|
+
...(meta.artifacts ? { artifacts: meta.artifacts } : {}),
|
|
61
|
+
...(defaults ? { defaults } : {}),
|
|
62
|
+
template: input.template,
|
|
63
|
+
};
|
|
64
|
+
writeFileSync(path, `${JSON.stringify(recipe, null, 2)}\n`, { flag: "wx" });
|
|
65
|
+
return path;
|
|
66
|
+
}
|
|
67
|
+
function enhanceSpawnRecipeError(error, recipe) {
|
|
68
|
+
const diagnostic = shadowedRecipeLaunchDiagnostic(recipe);
|
|
69
|
+
if (!diagnostic)
|
|
70
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
71
|
+
const original = error instanceof Error ? error.message : String(error);
|
|
72
|
+
return Object.assign(new Error(`${original} reason=${diagnostic.reason} active_path=${diagnostic.active_path} blocked_fallback=${diagnostic.blocked_fallback} hint=${diagnostic.hint}`), {
|
|
73
|
+
...diagnostic,
|
|
74
|
+
original_error: original,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function runIdFromActorAddress(address) {
|
|
78
|
+
if (!address)
|
|
79
|
+
return undefined;
|
|
80
|
+
const parsed = Messages.parseActorAddress(address);
|
|
81
|
+
if (parsed.kind !== "run" || !parsed.value) {
|
|
82
|
+
throw new Error(`Expected run:<id> actor address, received: ${address}`);
|
|
83
|
+
}
|
|
84
|
+
return parsed.value;
|
|
85
|
+
}
|
|
86
|
+
export function createSpawnToolDefinition() {
|
|
87
|
+
return {
|
|
88
|
+
name: "spawn",
|
|
89
|
+
label: "Spawn",
|
|
90
|
+
description: "Create an addressable actor from a recipe file or inline command template. Use instead of ad hoc shell backgrounding for work that may outlive this turn, needs steering/follow-up/artifacts, runs as a service, fans out, or should be inspected later. Currently spawns run:<id> actors backed by async runs.",
|
|
91
|
+
parameters: Schema.objectSchema({
|
|
92
|
+
artifacts: Schema.looseObjectSchema("Optional named artifact paths for the spawned actor."),
|
|
93
|
+
as: Schema.stringSchema("Optional actor address for the spawned run, e.g. run:<id>."),
|
|
94
|
+
file: Schema.stringSchema("Optional template recipe JSON file. Bare names resolve under ~/.pi/agent/recipes."),
|
|
95
|
+
recipe: Schema.stringSchema("Alias for file; template recipe JSON file/name to spawn."),
|
|
96
|
+
state_dir: Schema.stringSchema("Optional explicit run state directory."),
|
|
97
|
+
template: Schema.unionSchema([
|
|
98
|
+
Schema.stringSchema("Inline command template string"),
|
|
99
|
+
Schema.arraySchema("Inline command-template sequence or parallel tree"),
|
|
100
|
+
Schema.looseObjectSchema("Inline command-template object with flags such as parallel, repeat, retry, failure, and nested template."),
|
|
101
|
+
]),
|
|
102
|
+
values: Schema.looseObjectSchema("Runtime placeholder values passed to the actor."),
|
|
103
|
+
verbose: Schema.booleanSchema("Return full JSON instead of compact text."),
|
|
104
|
+
}, []),
|
|
105
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
106
|
+
const input = asRecord(params);
|
|
107
|
+
const runId = runIdFromActorAddress(typeof input.as === "string" ? input.as : undefined);
|
|
108
|
+
const recipe = typeof input.file === "string"
|
|
109
|
+
? input.file
|
|
110
|
+
: typeof input.recipe === "string"
|
|
111
|
+
? input.recipe
|
|
112
|
+
: undefined;
|
|
113
|
+
let meta;
|
|
114
|
+
try {
|
|
115
|
+
meta = AsyncRuns.startRun({
|
|
116
|
+
file: recipe,
|
|
117
|
+
launch_source: "spawn",
|
|
118
|
+
ownerId: getRunOwnerId(ctx),
|
|
119
|
+
run_id: runId,
|
|
120
|
+
state_dir: typeof input.state_dir === "string" ? input.state_dir : undefined,
|
|
121
|
+
...(input.template !== undefined
|
|
122
|
+
? {
|
|
123
|
+
template: input.template,
|
|
124
|
+
}
|
|
125
|
+
: {}),
|
|
126
|
+
values: asRecord(input.values),
|
|
127
|
+
...(input.artifacts &&
|
|
128
|
+
typeof input.artifacts === "object" &&
|
|
129
|
+
!Array.isArray(input.artifacts)
|
|
130
|
+
? {
|
|
131
|
+
artifacts: input.artifacts,
|
|
132
|
+
}
|
|
133
|
+
: {}),
|
|
134
|
+
}, ctx.cwd);
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
throw enhanceSpawnRecipeError(error, recipe);
|
|
138
|
+
}
|
|
139
|
+
const draftRecipe = writeSpawnDraftRecipe(input, meta);
|
|
140
|
+
const nextActions = ToolsResponse.actorRunNextActions(meta.run);
|
|
141
|
+
const details = {
|
|
142
|
+
...meta,
|
|
143
|
+
...(draftRecipe ? { draft_recipe: draftRecipe } : {}),
|
|
144
|
+
next_actions: nextActions,
|
|
145
|
+
};
|
|
146
|
+
Rooms.ensureDefaultRoom(meta.state_dir, String(meta.run));
|
|
147
|
+
Rooms.writeCommunicationSnapshot(meta.state_dir, String(meta.run));
|
|
148
|
+
return {
|
|
149
|
+
content: [
|
|
150
|
+
{
|
|
151
|
+
type: "text",
|
|
152
|
+
text: maybeJsonText(details, input.verbose === true, ToolsResponse.compactAsyncRunStatus(details)),
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
details,
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
package/dist/lib/tools.d.ts
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Zones:
|
|
4
|
-
* Owns
|
|
2
|
+
* Public tool family composition
|
|
3
|
+
* Zones: tool set, reserved tool names, pi-facing tool wiring
|
|
4
|
+
* Owns public tool-family composition without owning individual tool behavior
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
7
|
-
import * as
|
|
8
|
-
|
|
9
|
-
export type RegisterToolInput = Registry.RegisterToolInput;
|
|
10
|
-
export type RegisterToolRuntimeDeps<TContext> = Registry.RegisterToolRuntimeDeps<TContext>;
|
|
6
|
+
import type { RuntimeToolContext } from "./tools-local.ts";
|
|
7
|
+
import * as ToolsRegister from "./tools-register.ts";
|
|
8
|
+
export type RegisterToolRuntimeDeps<TContext> = ToolsRegister.RegisterToolRuntimeDeps<TContext>;
|
|
11
9
|
export interface ActorToolDefinition {
|
|
12
10
|
name: string;
|
|
13
11
|
execute?: (...args: never[]) => unknown;
|
|
14
12
|
[key: string]: unknown;
|
|
15
13
|
}
|
|
16
|
-
export interface CoreActorToolDefinitionDeps<TContext extends
|
|
14
|
+
export interface CoreActorToolDefinitionDeps<TContext extends RuntimeToolContext> {
|
|
17
15
|
configPath: string;
|
|
18
16
|
getActiveTools: () => string[];
|
|
19
17
|
getRuntimeTool: (name: string) => unknown;
|
|
@@ -21,33 +19,4 @@ export interface CoreActorToolDefinitionDeps<TContext extends AsyncRunToolContex
|
|
|
21
19
|
setActiveTools: (toolNames: string[]) => void;
|
|
22
20
|
}
|
|
23
21
|
export declare const RESERVED_TOOL_NAMES: Set<string>;
|
|
24
|
-
|
|
25
|
-
export declare function createRegisterToolDefinition<TContext>(deps: RegisterToolRuntimeDeps<TContext>): {
|
|
26
|
-
name: string;
|
|
27
|
-
label: string;
|
|
28
|
-
description: string;
|
|
29
|
-
promptSnippet: string;
|
|
30
|
-
promptGuidelines: string[];
|
|
31
|
-
parameters: JsonSchema;
|
|
32
|
-
execute: (_toolCallId: string, params: unknown, _signal: AbortSignal | undefined, _onUpdate: unknown, ctx: TContext) => Promise<Registry.RegisterToolResult>;
|
|
33
|
-
};
|
|
34
|
-
export interface AsyncRunToolContext {
|
|
35
|
-
cwd: string;
|
|
36
|
-
sessionManager?: {
|
|
37
|
-
getSessionId?: () => string;
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
export declare function createSpawnToolDefinition<TContext extends AsyncRunToolContext>(): any;
|
|
41
|
-
export interface InspectToolDeps<TContext = unknown> {
|
|
42
|
-
getTool?: (name: string) => any | undefined;
|
|
43
|
-
packagedRecipeRoot?: string;
|
|
44
|
-
recipeRoot?: string;
|
|
45
|
-
}
|
|
46
|
-
export declare function createInspectToolDefinition<TContext = unknown>(deps?: InspectToolDeps<TContext>): any;
|
|
47
|
-
export interface ActorMessageToolDeps<TContext = unknown> {
|
|
48
|
-
getTool?: (name: string) => any | undefined;
|
|
49
|
-
}
|
|
50
|
-
export declare function createActorMessageToolDefinition<TContext = unknown>(deps?: ActorMessageToolDeps<TContext>): any;
|
|
51
|
-
export declare function createCoreActorToolDefinitions<TContext extends AsyncRunToolContext>(deps: CoreActorToolDefinitionDeps<TContext>): ActorToolDefinition[];
|
|
52
|
-
export declare function createRuntimeToolDefinition(cfg: RegisteredTool, exec: Execution.RegisteredToolExec): any;
|
|
53
|
-
export {};
|
|
22
|
+
export declare function createCoreActorToolDefinitions<TContext extends RuntimeToolContext>(deps: CoreActorToolDefinitionDeps<TContext>): ActorToolDefinition[];
|