@llblab/pi-actors 0.29.3 → 0.30.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.
package/index.ts CHANGED
@@ -5,294 +5,106 @@
5
5
  * Wraps command templates as callable pi tools, stores durable user tools as recipe files, and exposes actor orchestration across reloads and sessions.
6
6
  */
7
7
 
8
- import { existsSync, readdirSync, watch, type FSWatcher } from "node:fs";
9
- import { dirname, join } from "node:path";
10
- import { fileURLToPath } from "node:url";
11
-
12
- import type {
13
- ExtensionAPI,
14
- ExtensionContext,
15
- } from "@earendil-works/pi-coding-agent";
16
-
17
8
  import * as ActorInspectorTui from "./lib/actor-inspector-tui.ts";
18
9
  import * as AsyncRuns from "./lib/async-runs.ts";
19
10
  import * as CommandTemplates from "./lib/command-templates.ts";
20
11
  import * as Observability from "./lib/observability.ts";
21
12
  import * as Paths from "./lib/paths.ts";
13
+ import * as Pi from "./lib/pi.ts";
22
14
  import * as Prompts from "./lib/prompts.ts";
23
15
  import * as Runtime from "./lib/runtime.ts";
24
16
  import * as Temp from "./lib/temp.ts";
25
17
  import * as Tools from "./lib/tools.ts";
26
18
 
27
- const EXTENSION_DIR = dirname(fileURLToPath(import.meta.url));
28
- const EXTENSION_SKILLS_DIR = join(EXTENSION_DIR, "skills");
29
- const CONFIG_PATH = Paths.getConfigPath();
30
- const TEMP_DIR = Paths.getExtensionTmpDir();
31
- const RUN_STATE_ROOT = Paths.getRunStateRoot();
32
- const RESERVED_TOOL_NAMES = new Set([
33
- "read",
34
- "write",
35
- "edit",
36
- "bash",
37
- "find",
38
- "grep",
39
- "ls",
40
- "register_tool",
41
- "message",
42
- "spawn",
43
- "inspect",
44
- ]);
45
-
46
- export default function toolRegistryExtension(pi: ExtensionAPI) {
19
+ export default function toolRegistryExtension(pi: Pi.ExtensionAPI) {
47
20
  let runsAnimationInterval: NodeJS.Timeout | undefined;
48
21
  let runsNotifyTimeout: NodeJS.Timeout | undefined;
49
- let recipeReloadTimeout: NodeJS.Timeout | undefined;
50
- let recipeRootWatcher: FSWatcher | undefined;
51
- let stateRootWatcher: FSWatcher | undefined;
52
- const runDirWatchers = new Map<string, FSWatcher>();
53
- const observedRuns = new Map<string, Observability.RunObservedStatus>();
54
- const observedRunEventLines = new Map<string, number>();
55
- const observedRunOutboxEventIds = new Map<string, Set<string>>();
22
+ let activeRunContext: Pi.ExtensionContext | undefined;
23
+ const runUi = Observability.createRunUiObservationState();
56
24
  const retirementAttempts = new Set<string>();
57
- let runStatusFrame = 0;
58
- let communicationWidgetVisible = false;
59
- let actorInspectorRows = 12;
60
- let actorInspectorChannels:
61
- | ActorInspectorTui.ActorInspectorPreview["channel"][]
62
- | undefined;
63
- let actorInspectorMention: string | undefined;
64
- let actorInspectorBranch: string | undefined;
65
- let actorInspectorUnreadOnly = false;
66
- let actorInspectorRoomLimitPerRun = 12;
67
- let selectedInspectorSequence: number | undefined;
68
- const actorInspectorReadKeys = new Set<string>();
69
- let recipeWatcherFailureNotified = false;
70
- const getRunOwnerId = (ctx: ExtensionContext): string =>
71
- ctx.sessionManager.getSessionId();
25
+ const actorInspector =
26
+ ActorInspectorTui.createActorInspectorControllerState();
27
+ const getRunOwnerId = Pi.getSessionId;
72
28
  const retireCandidateRuns = (
73
- ctx: ExtensionContext,
29
+ ctx: Pi.ExtensionContext,
74
30
  summary: Observability.RunSummary,
75
31
  ): void => {
76
32
  void Observability.executeRunRetirements(summary, {
77
33
  attempted: retirementAttempts,
78
34
  cancelRun: (candidate) => AsyncRuns.cancelRun(candidate.stateDir),
79
35
  notify: (message, level) => ctx.ui.notify(message, level),
80
- sendStop: (candidate) => AsyncRuns.sendRunMessage(candidate.stateDir, "stop"),
36
+ sendStop: (candidate) =>
37
+ AsyncRuns.sendRunMessage(candidate.stateDir, "stop"),
81
38
  });
82
39
  };
83
- const updateRunUi = (ctx: ExtensionContext, notify = false): void => {
40
+ const updateRunUi = (ctx: Pi.ExtensionContext, notify = false): void => {
84
41
  const ownerId = getRunOwnerId(ctx);
85
- const summary = Observability.summarizeRuns(undefined, ownerId);
86
- const status = Observability.renderRunStatus(summary, runStatusFrame++);
42
+ const snapshot = Observability.readRunUiSnapshot(runUi, ownerId);
87
43
  ctx.ui.setStatus(
88
44
  "zz-pi-actors-runs",
89
- status ? ctx.ui.theme.fg("dim", status) : undefined,
45
+ snapshot.status ? ctx.ui.theme.fg("dim", snapshot.status) : undefined,
90
46
  );
91
47
  ctx.ui.setWidget(
92
48
  "zz-pi-actors-comms",
93
- communicationWidgetVisible
94
- ? () => {
95
- const style = {
96
- actor: (text: string) => ctx.ui.theme.fg("accent", text),
97
- muted: (text: string) => ctx.ui.theme.fg("dim", text),
98
- preview: (text: string) => ctx.ui.theme.fg("text", text),
99
- stripe: (text: string) => text,
100
- stripeAlt: (text: string) =>
101
- ctx.ui.theme.bg("customMessageBg", text),
102
- target: (text: string) => ctx.ui.theme.fg("success", text),
103
- type: (text: string) => ctx.ui.theme.fg("warning", text),
104
- };
105
- return {
106
- invalidate() {},
107
- render(width: number) {
108
- const previews = ActorInspectorTui.readActorInspectorPreviews(
109
- RUN_STATE_ROOT,
110
- actorInspectorRows,
111
- {
112
- channels: actorInspectorChannels,
113
- currentRunOnly: true,
114
- branch: actorInspectorBranch,
115
- mention: actorInspectorMention,
116
- ownerId,
117
- readKeys: actorInspectorReadKeys,
118
- roomLimitPerRun: actorInspectorRoomLimitPerRun,
119
- unreadOnly: actorInspectorUnreadOnly,
120
- },
121
- );
122
- const rows =
123
- (selectedInspectorSequence !== undefined
124
- ? ActorInspectorTui.renderInspectorItemView(
125
- previews,
126
- width,
127
- style,
128
- { sequence: selectedInspectorSequence },
129
- )
130
- : ActorInspectorTui.renderInspectorWidget(
131
- previews,
132
- width,
133
- style,
134
- )) ?? [];
135
- const run = previews[0]?.run;
136
- const roster =
137
- selectedInspectorSequence === undefined && run
138
- ? ActorInspectorTui.renderInspectorRosterPanel(
139
- ActorInspectorTui.readActorInspectorRoster(
140
- RUN_STATE_ROOT,
141
- run,
142
- ),
143
- width,
144
- style,
145
- )
146
- : undefined;
147
- return roster ? [...roster, ...rows] : rows;
148
- },
149
- };
150
- }
49
+ actorInspector.visible
50
+ ? () => ({
51
+ invalidate() {},
52
+ render(width: number) {
53
+ return ActorInspectorTui.renderActorInspectorPanel({
54
+ stateRoot: Paths.EXTENSION_RUNTIME_PATHS.runStateRoot,
55
+ state: actorInspector,
56
+ ownerId,
57
+ width,
58
+ style: {
59
+ actor: (text: string) => ctx.ui.theme.fg("accent", text),
60
+ muted: (text: string) => ctx.ui.theme.fg("dim", text),
61
+ preview: (text: string) => ctx.ui.theme.fg("text", text),
62
+ stripe: (text: string) => text,
63
+ stripeAlt: (text: string) =>
64
+ ctx.ui.theme.bg("customMessageBg", text),
65
+ target: (text: string) => ctx.ui.theme.fg("success", text),
66
+ type: (text: string) => ctx.ui.theme.fg("warning", text),
67
+ },
68
+ });
69
+ },
70
+ })
151
71
  : undefined,
152
72
  { placement: "belowEditor" },
153
73
  );
154
- const transitions = Observability.detectRunTransitions(
155
- observedRuns,
156
- summary,
157
- );
158
- const outboxEvents = Observability.detectRunOutboxEvents(
159
- observedRunEventLines,
160
- summary,
161
- observedRunOutboxEventIds,
162
- );
163
74
  if (!notify) return;
164
- retireCandidateRuns(ctx, summary);
165
- for (const transition of transitions) {
166
- if (!Observability.shouldNotifyRunTransition(transition)) continue;
167
- const text = Observability.formatRunTransitionMessage(transition);
168
- const notificationType =
169
- Observability.getRunTransitionNotificationType(transition);
170
- ctx.ui.notify(text, notificationType);
171
- if (!Observability.shouldSendRunTransitionFollowUp(transition)) continue;
172
- pi.sendMessage(
173
- {
174
- customType: "pi-actors-run",
175
- content: text,
176
- display: true,
177
- details: transition,
178
- },
179
- { deliverAs: "followUp", triggerTurn: true },
180
- );
181
- }
182
- Observability.pruneRunObservationState(
183
- observedRuns,
184
- observedRunEventLines,
185
- summary,
186
- transitions.map((transition) => transition.stateDir ?? transition.run),
187
- observedRunOutboxEventIds,
75
+ const notificationSink = Pi.createNotificationSink(pi, ctx);
76
+ retireCandidateRuns(ctx, snapshot.summary);
77
+ Observability.deliverRunTransitionNotifications(
78
+ snapshot.transitions,
79
+ notificationSink,
80
+ );
81
+ Observability.pruneRunUiObservationState(runUi, snapshot);
82
+ Observability.deliverRunOutboxNotifications(
83
+ snapshot.outboxEvents,
84
+ notificationSink,
188
85
  );
189
- for (const event of outboxEvents) {
190
- if (!Observability.shouldNotifyRunOutboxEvent(event)) continue;
191
- const text = Observability.formatRunOutboxMessage(event);
192
- const notificationType =
193
- Observability.getRunOutboxNotificationType(event);
194
- ctx.ui.notify(text, notificationType);
195
- if (!Observability.shouldSendRunOutboxFollowUp(event)) continue;
196
- pi.sendMessage(
197
- {
198
- customType: "pi-actors-run-message",
199
- content: text,
200
- display: true,
201
- details: event,
202
- },
203
- { deliverAs: "followUp", triggerTurn: true },
204
- );
205
- }
206
86
  };
207
87
  const closeRunWatchers = (): void => {
208
- stateRootWatcher?.close();
209
- stateRootWatcher = undefined;
210
- for (const watcher of runDirWatchers.values()) watcher.close();
211
- runDirWatchers.clear();
88
+ runWatcher.close();
212
89
  if (runsNotifyTimeout) clearTimeout(runsNotifyTimeout);
213
90
  runsNotifyTimeout = undefined;
214
91
  };
215
- const scheduleRunEventUpdate = (ctx: ExtensionContext): void => {
92
+ const scheduleRunEventUpdate = (ctx: Pi.ExtensionContext): void => {
216
93
  if (runsNotifyTimeout) clearTimeout(runsNotifyTimeout);
217
94
  runsNotifyTimeout = setTimeout(() => {
218
- refreshRunWatchers(ctx);
95
+ runWatcher.refresh();
219
96
  updateRunUi(ctx, true);
220
97
  }, 50);
221
98
  runsNotifyTimeout.unref?.();
222
99
  };
223
- const watchRunDir = (ctx: ExtensionContext, stateDir: string): void => {
224
- if (runDirWatchers.has(stateDir) || !existsSync(stateDir)) return;
225
- try {
226
- const watcher = watch(stateDir, () => scheduleRunEventUpdate(ctx));
227
- watcher.on("error", () => {
228
- watcher.close();
229
- runDirWatchers.delete(stateDir);
230
- });
231
- runDirWatchers.set(stateDir, watcher);
232
- } catch {
233
- // Watching is best-effort; explicit inspect remains available.
234
- }
235
- };
236
- function refreshRunWatchers(ctx: ExtensionContext): void {
237
- if (!existsSync(RUN_STATE_ROOT)) return;
238
- if (!stateRootWatcher) {
239
- try {
240
- stateRootWatcher = watch(RUN_STATE_ROOT, () =>
241
- scheduleRunEventUpdate(ctx),
242
- );
243
- stateRootWatcher.on("error", () => {
244
- stateRootWatcher?.close();
245
- stateRootWatcher = undefined;
246
- });
247
- } catch {
248
- // Watching is best-effort; explicit inspect remains available.
249
- }
250
- }
251
- for (const entry of readdirSync(RUN_STATE_ROOT, { withFileTypes: true })) {
252
- if (!entry.isDirectory()) continue;
253
- watchRunDir(ctx, `${RUN_STATE_ROOT}/${entry.name}`);
254
- }
255
- }
256
- const closeRecipeWatcher = (): void => {
257
- recipeRootWatcher?.close();
258
- recipeRootWatcher = undefined;
259
- if (recipeReloadTimeout) clearTimeout(recipeReloadTimeout);
260
- recipeReloadTimeout = undefined;
261
- };
262
- const notifyRecipeWatcherFailure = (ctx: ExtensionContext): void => {
263
- if (recipeWatcherFailureNotified) return;
264
- recipeWatcherFailureNotified = true;
265
- ctx.ui.notify(
266
- "Recipe live reload watcher failed; restart the session or use register_tool again to refresh recipe tools.",
267
- "warning",
268
- );
269
- };
270
- const scheduleRecipeReload = (ctx: ExtensionContext): void => {
271
- recipeWatcherFailureNotified = false;
272
- if (recipeReloadTimeout) clearTimeout(recipeReloadTimeout);
273
- recipeReloadTimeout = setTimeout(() => {
274
- runtime.loadTools(ctx);
275
- ctx.ui.notify("Recipe tools refreshed from ~/.pi/agent/recipes", "info");
276
- }, 150);
277
- recipeReloadTimeout.unref?.();
278
- };
279
- const watchRecipeRoot = (ctx: ExtensionContext): void => {
280
- const recipeRoot = Paths.getRecipeRoot();
281
- if (recipeRootWatcher || !existsSync(recipeRoot)) return;
282
- try {
283
- recipeRootWatcher = watch(recipeRoot, () => scheduleRecipeReload(ctx));
284
- recipeRootWatcher.on("error", () => {
285
- recipeRootWatcher?.close();
286
- recipeRootWatcher = undefined;
287
- notifyRecipeWatcherFailure(ctx);
288
- });
289
- } catch {
290
- notifyRecipeWatcherFailure(ctx);
291
- }
292
- };
100
+ const runWatcher = Observability.createRunStateWatcher({
101
+ stateRoot: Paths.EXTENSION_RUNTIME_PATHS.runStateRoot,
102
+ onChange: () =>
103
+ activeRunContext && scheduleRunEventUpdate(activeRunContext),
104
+ });
293
105
  const actorToolDefinitions = new Map<string, any>();
294
106
  const runtime = Runtime.createAutoToolsRuntime({
295
- configPath: CONFIG_PATH,
107
+ configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
296
108
  exec: CommandTemplates.execCommandTemplate,
297
109
  getActiveTools: () => pi.getActiveTools(),
298
110
  getAllTools: () => pi.getAllTools(),
@@ -300,21 +112,24 @@ export default function toolRegistryExtension(pi: ExtensionAPI) {
300
112
  actorToolDefinitions.set(definition.name, definition);
301
113
  pi.registerTool(definition);
302
114
  },
303
- reservedToolNames: RESERVED_TOOL_NAMES,
115
+ reservedToolNames: Tools.RESERVED_TOOL_NAMES,
304
116
  setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
305
117
  });
118
+ const recipeReload = Runtime.createRecipeToolReloadWatcher(runtime);
306
119
  pi.on("resources_discover", async () => {
307
- if (!existsSync(EXTENSION_SKILLS_DIR)) return;
308
- return { skillPaths: [EXTENSION_SKILLS_DIR] };
120
+ const skillPaths = Paths.getExistingExtensionSkillPaths(import.meta.url);
121
+ if (skillPaths.length === 0) return;
122
+ return { skillPaths };
309
123
  });
310
124
  pi.on("session_start", async (_event, ctx) => {
311
- await Temp.prepareExtensionTempDir(TEMP_DIR);
125
+ activeRunContext = ctx;
126
+ await Temp.prepareExtensionTempDir(Paths.EXTENSION_RUNTIME_PATHS.tempDir);
312
127
  runtime.loadTools(ctx);
313
128
  updateRunUi(ctx);
314
129
  closeRunWatchers();
315
- closeRecipeWatcher();
316
- refreshRunWatchers(ctx);
317
- watchRecipeRoot(ctx);
130
+ recipeReload.close();
131
+ runWatcher.refresh();
132
+ recipeReload.watch(ctx);
318
133
  if (runsAnimationInterval) clearInterval(runsAnimationInterval);
319
134
  runsAnimationInterval = setInterval(() => updateRunUi(ctx, false), 1000);
320
135
  runsAnimationInterval.unref?.();
@@ -322,158 +137,63 @@ export default function toolRegistryExtension(pi: ExtensionAPI) {
322
137
  pi.on("session_shutdown", async () => {
323
138
  if (runsAnimationInterval) clearInterval(runsAnimationInterval);
324
139
  runsAnimationInterval = undefined;
140
+ activeRunContext = undefined;
325
141
  closeRunWatchers();
326
- closeRecipeWatcher();
142
+ recipeReload.close();
327
143
  });
328
144
  pi.registerCommand("actors-inspector-toggle", {
329
- description: "Toggle actor inspector widget; optional row count",
145
+ description: ActorInspectorTui.ACTOR_INSPECTOR_COMMAND_DESCRIPTIONS.toggle,
330
146
  handler: async (args, ctx) => {
331
- const raw = Array.isArray(args) ? args[0] : String(args ?? "");
332
- if (String(raw).trim()) {
333
- const rows = Number.parseInt(String(raw), 10);
334
- if (!Number.isFinite(rows) || rows <= 0) {
335
- ctx.ui.notify(
336
- "Usage: /actors-inspector-toggle [rows] where rows > 0",
337
- "warning",
338
- );
339
- return;
340
- }
341
- actorInspectorRows = rows;
342
- actorInspectorRoomLimitPerRun = rows;
343
- selectedInspectorSequence = undefined;
344
- communicationWidgetVisible = true;
345
- updateRunUi(ctx);
346
- ctx.ui.notify(`Actor inspector rows ${rows}`, "info");
347
- return;
348
- }
349
- if (selectedInspectorSequence !== undefined) {
350
- selectedInspectorSequence = undefined;
351
- communicationWidgetVisible = true;
352
- updateRunUi(ctx);
353
- ctx.ui.notify("Actor inspector table", "info");
354
- return;
355
- }
356
- if (communicationWidgetVisible) {
357
- communicationWidgetVisible = false;
358
- } else {
359
- actorInspectorRows = 12;
360
- actorInspectorRoomLimitPerRun = 12;
361
- communicationWidgetVisible = true;
362
- }
363
- updateRunUi(ctx);
364
- ctx.ui.notify(
365
- `Actor inspector ${communicationWidgetVisible ? "shown" : "hidden"}`,
366
- "info",
147
+ const result = ActorInspectorTui.handleActorInspectorToggle(
148
+ actorInspector,
149
+ args,
367
150
  );
151
+ if (result.update) updateRunUi(ctx);
152
+ ctx.ui.notify(result.notify, result.type);
368
153
  },
369
154
  });
370
155
  pi.registerCommand("actors-inspector-filter", {
371
- description:
372
- "Filter actor inspector rows: all, room, direct, broadcast, unread, branch <name>, mention <text>",
156
+ description: ActorInspectorTui.ACTOR_INSPECTOR_COMMAND_DESCRIPTIONS.filter,
373
157
  handler: async (args, ctx) => {
374
- const parts = Array.isArray(args)
375
- ? args.map(String)
376
- : String(args ?? "").split(/\s+/);
377
- const mode = (parts[0] ?? "").trim().toLowerCase();
378
- if (!mode || mode === "all" || mode === "clear") {
379
- actorInspectorChannels = undefined;
380
- actorInspectorMention = undefined;
381
- actorInspectorBranch = undefined;
382
- actorInspectorUnreadOnly = false;
383
- } else if (mode === "room" || mode === "direct" || mode === "broadcast") {
384
- actorInspectorChannels = [mode];
385
- actorInspectorMention = undefined;
386
- } else if (mode === "unread") {
387
- actorInspectorUnreadOnly = true;
388
- } else if (mode === "branch" || mode === "current-branch") {
389
- const branch = parts.slice(1).join(" ").trim();
390
- if (!branch) {
391
- ctx.ui.notify(
392
- `Usage: /actors-inspector-filter ${mode} <branch-name>`,
393
- "warning",
394
- );
395
- return;
396
- }
397
- actorInspectorBranch = branch;
398
- } else if (mode === "mention") {
399
- const mention = parts.slice(1).join(" ").trim();
400
- if (!mention) {
401
- ctx.ui.notify(
402
- "Usage: /actors-inspector-filter mention <text>",
403
- "warning",
404
- );
405
- return;
406
- }
407
- actorInspectorChannels = undefined;
408
- actorInspectorMention = mention;
409
- } else {
410
- ctx.ui.notify(
411
- "Usage: /actors-inspector-filter all|room|direct|broadcast|unread|branch <name>|mention <text>",
412
- "warning",
413
- );
414
- return;
415
- }
416
- selectedInspectorSequence = undefined;
417
- communicationWidgetVisible = true;
418
- updateRunUi(ctx);
419
- ctx.ui.notify(`Actor inspector filter ${mode || "all"}`, "info");
158
+ const result = ActorInspectorTui.handleActorInspectorFilter(
159
+ actorInspector,
160
+ args,
161
+ );
162
+ if (result.update) updateRunUi(ctx);
163
+ ctx.ui.notify(result.notify, result.type);
420
164
  },
421
165
  });
422
166
  pi.registerCommand("actors-inspect", {
423
- description: "Inspect actor message by visible number",
167
+ description: ActorInspectorTui.ACTOR_INSPECTOR_COMMAND_DESCRIPTIONS.inspect,
424
168
  handler: async (args, ctx) => {
425
- const raw = Array.isArray(args) ? args[0] : String(args ?? "");
426
- const sequence = Number.parseInt(String(raw), 10);
427
- if (!Number.isFinite(sequence) || sequence <= 0) {
428
- ctx.ui.notify("Usage: /actors-inspect <number>", "warning");
429
- return;
430
- }
431
169
  const previews = ActorInspectorTui.readActorInspectorPreviews(
432
- RUN_STATE_ROOT,
433
- actorInspectorRows,
434
- {
435
- channels: actorInspectorChannels,
436
- currentRunOnly: true,
437
- branch: actorInspectorBranch,
438
- mention: actorInspectorMention,
439
- ownerId: getRunOwnerId(ctx),
440
- readKeys: actorInspectorReadKeys,
441
- roomLimitPerRun: actorInspectorRoomLimitPerRun,
442
- unreadOnly: actorInspectorUnreadOnly,
443
- },
170
+ Paths.EXTENSION_RUNTIME_PATHS.runStateRoot,
171
+ actorInspector.rows,
172
+ ActorInspectorTui.getActorInspectorPreviewOptions(
173
+ actorInspector,
174
+ getRunOwnerId(ctx),
175
+ ),
444
176
  );
445
- const preview = previews.find((item) => item.sequence === sequence);
446
- if (preview) actorInspectorReadKeys.add(ActorInspectorTui.inspectorPreviewReadKey(preview));
447
- selectedInspectorSequence = sequence;
448
- communicationWidgetVisible = true;
449
- updateRunUi(ctx);
450
- ctx.ui.notify(`Actor inspect item ${sequence}`, "info");
177
+ const result = ActorInspectorTui.handleActorInspectorInspect(
178
+ actorInspector,
179
+ args,
180
+ previews,
181
+ );
182
+ if (result.update) updateRunUi(ctx);
183
+ ctx.ui.notify(result.notify, result.type);
451
184
  },
452
185
  });
453
186
  pi.on("before_agent_start", async (event) => ({
454
187
  systemPrompt: `${event.systemPrompt}\n\n${Prompts.ONBOARDING_SYSTEM_PROMPT}`,
455
188
  }));
456
- pi.registerTool(
457
- Tools.createRegisterToolDefinition<ExtensionContext>({
458
- configPath: CONFIG_PATH,
189
+ Pi.registerToolDefinitions(
190
+ pi,
191
+ Tools.createCoreActorToolDefinitions<Pi.ExtensionContext>({
192
+ configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
459
193
  getActiveTools: () => pi.getActiveTools(),
460
- getExternalToolConflict: runtime.getExternalToolConflict,
461
- getTools: runtime.getTools,
462
- notify: runtime.notify,
463
- registerRuntimeTool: runtime.registerRuntimeTool,
464
- reservedToolNames: RESERVED_TOOL_NAMES,
194
+ getRuntimeTool: (name) => actorToolDefinitions.get(name),
195
+ registryRuntime: runtime,
465
196
  setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
466
197
  }),
467
198
  );
468
- pi.registerTool(Tools.createSpawnToolDefinition<ExtensionContext>());
469
- pi.registerTool(
470
- Tools.createActorMessageToolDefinition<ExtensionContext>({
471
- getTool: (name) => actorToolDefinitions.get(name),
472
- }),
473
- );
474
- pi.registerTool(
475
- Tools.createInspectToolDefinition<ExtensionContext>({
476
- getTool: (name) => actorToolDefinitions.get(name),
477
- }),
478
- );
479
199
  }