@skydiveai/pi-extensions 0.1.0-beta.2894 → 0.1.0-beta.2899
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/dist/index.mjs +105 -20
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2359,6 +2359,30 @@ async function postSubagentSpawn({ messageId, tasks }) {
|
|
|
2359
2359
|
tasks: body.tasks ?? []
|
|
2360
2360
|
};
|
|
2361
2361
|
}
|
|
2362
|
+
async function postSubagentRearm({ messageId, taskId, timeoutMinutes }) {
|
|
2363
|
+
const client = sandboxClient();
|
|
2364
|
+
if (!client) throw new Error("no api url for subagent re-arm");
|
|
2365
|
+
const res = await client.a2a.tasks[":id"].rearm.$post({
|
|
2366
|
+
param: { id: taskId },
|
|
2367
|
+
json: {
|
|
2368
|
+
messageId,
|
|
2369
|
+
timeoutMinutes
|
|
2370
|
+
}
|
|
2371
|
+
});
|
|
2372
|
+
if (!res.ok) {
|
|
2373
|
+
let detail = "";
|
|
2374
|
+
try {
|
|
2375
|
+
const body = await res.json();
|
|
2376
|
+
if (typeof body.error === "string") detail = `: ${body.error}`;
|
|
2377
|
+
} catch {}
|
|
2378
|
+
throw new Error(`subagent re-arm POST failed (${res.status})${detail}`);
|
|
2379
|
+
}
|
|
2380
|
+
const body = await res.json();
|
|
2381
|
+
return {
|
|
2382
|
+
taskId: body.id,
|
|
2383
|
+
deadlineAt: body.deadlineAt
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2362
2386
|
function createHeartbeatThrottle({ messageId }) {
|
|
2363
2387
|
let lastAt = 0;
|
|
2364
2388
|
let pending = null;
|
|
@@ -4230,7 +4254,7 @@ const soulExtension = (pi) => {
|
|
|
4230
4254
|
//#region src/extensions/subagent/index.ts
|
|
4231
4255
|
const log$1 = logger.child({ module: "subagent-ext" });
|
|
4232
4256
|
const MAX_TASKS = 8;
|
|
4233
|
-
const
|
|
4257
|
+
const SpawnTaskItem = Type.Object({
|
|
4234
4258
|
task: Type.String({ description: "The task to delegate to a subagent run." }),
|
|
4235
4259
|
title: Type.String({
|
|
4236
4260
|
description: "A SHORT name for this task — 3-6 words, sentence case, no trailing period. This is what the person in the chat sees as the row for this subagent, so name the work, do not restate the prompt. Good: \"Audit the billing gate\", \"Compare competitor pricing\", \"Draft the migration\". Bad: \"You are looking at apps/anyone/web and should check every component…\".",
|
|
@@ -4244,9 +4268,18 @@ const TaskItem = Type.Object({
|
|
|
4244
4268
|
maximum: 360
|
|
4245
4269
|
}))
|
|
4246
4270
|
});
|
|
4271
|
+
const RearmTaskItem = Type.Object({
|
|
4272
|
+
taskId: Type.String({ description: "The running subagent task to keep waiting for. Use the taskId returned by an earlier subagent call." }),
|
|
4273
|
+
timeoutMinutes: Type.Integer({
|
|
4274
|
+
description: "Wake again after this many minutes if the subagent is still running. This replaces no work and can be repeated after every timeout. Range 1-360.",
|
|
4275
|
+
minimum: 1,
|
|
4276
|
+
maximum: 360
|
|
4277
|
+
})
|
|
4278
|
+
});
|
|
4279
|
+
const TaskItem = Type.Union([SpawnTaskItem, RearmTaskItem]);
|
|
4247
4280
|
const DEFAULT_SUBAGENT_TIMEOUT_MS = 30 * 6e4;
|
|
4248
4281
|
const SubagentParams = Type.Object({ tasks: Type.Array(TaskItem, {
|
|
4249
|
-
description: "
|
|
4282
|
+
description: "Spawn subagent runs with { task, title, ... }, or keep waiting for a running task with { taskId, timeoutMinutes }. Re-arming schedules another parent wake without restarting or stopping the child.",
|
|
4250
4283
|
minItems: 1,
|
|
4251
4284
|
maxItems: MAX_TASKS
|
|
4252
4285
|
}) });
|
|
@@ -4256,10 +4289,10 @@ function buildTool(messageId) {
|
|
|
4256
4289
|
name: SUBAGENT_TOOL_NAME,
|
|
4257
4290
|
label: "Subagent",
|
|
4258
4291
|
description: [
|
|
4259
|
-
"Delegate
|
|
4292
|
+
"Delegate tasks to isolated subagent runs, or re-arm a running task so it wakes you again later without stopping the child.",
|
|
4260
4293
|
"Use it to parallelize independent work, to keep a large or noisy subtask out of your own context, or to run a task under a specialized persona.",
|
|
4261
4294
|
"Fire-and-forget: this returns immediately after queueing. It does NOT wait for results. Each subagent runs on its own and, when it finishes, sends you its result on this thread — so queue the work, then keep going or end your turn. To chain, re-delegate after a result lands.",
|
|
4262
|
-
"
|
|
4295
|
+
"To spawn, pass { task, title, persona?, model?, timeoutMinutes? }. To keep waiting after a timeout, pass { taskId, timeoutMinutes }; this schedules another wake and leaves the same child running. title is the short human-visible name for new work. persona and model apply only when spawning.",
|
|
4263
4296
|
"Peering: each queued task comes back with its own conversation id. A subagent is a real linked conversation, so to see what one is doing RIGHT NOW while it runs — its reasoning, the tools it has called and their results, its progress — read that conversation with `platform conversations show <conversationId>` (you are already authorized; it is your own delegated run). Check in that way instead of waiting blind for the final result. The read reflects the child's persisted state, which lags a few seconds behind live (tool results land as they complete; in-progress reasoning can be up to ~5s stale), so peek between checkpoints rather than polling in a tight loop.",
|
|
4264
4297
|
"Steering: to add context, correct course, or answer a question a subagent needs mid-run, post to its conversation with `platform conversations post <conversationId> --message \"...\"`. If the subagent is still running, your message lands as a live steer picked up in that same turn; if it has gone idle, it queues as its next turn. This is the same primitive as any conversation message — there is no separate steer channel."
|
|
4265
4298
|
].join(" "),
|
|
@@ -4275,38 +4308,90 @@ function buildTool(messageId) {
|
|
|
4275
4308
|
details: {},
|
|
4276
4309
|
isError: true
|
|
4277
4310
|
};
|
|
4278
|
-
const
|
|
4279
|
-
task
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4311
|
+
const spawnRequests = tasks.flatMap((task, index) => "task" in task ? [{
|
|
4312
|
+
task,
|
|
4313
|
+
index
|
|
4314
|
+
}] : []);
|
|
4315
|
+
const rearmRequests = tasks.flatMap((task, index) => "taskId" in task ? [{
|
|
4316
|
+
task,
|
|
4317
|
+
index
|
|
4318
|
+
}] : []);
|
|
4319
|
+
if (spawnRequests.length > 0 && rearmRequests.length > 0) return {
|
|
4320
|
+
content: [{
|
|
4321
|
+
type: "text",
|
|
4322
|
+
text: "A subagent call must either spawn new tasks or re-arm running tasks, not both."
|
|
4323
|
+
}],
|
|
4324
|
+
details: { error: "mixed subagent operations" }
|
|
4325
|
+
};
|
|
4326
|
+
const spawnTasks = spawnRequests.map(({ task }) => ({
|
|
4327
|
+
task: task.task,
|
|
4328
|
+
title: task.title ?? null,
|
|
4329
|
+
persona: task.persona ?? null,
|
|
4330
|
+
model: task.model ?? null,
|
|
4331
|
+
timeoutMs: task.timeoutMinutes != null ? task.timeoutMinutes * 6e4 : DEFAULT_SUBAGENT_TIMEOUT_MS
|
|
4284
4332
|
}));
|
|
4285
4333
|
try {
|
|
4286
|
-
const spawned = await postSubagentSpawn({
|
|
4334
|
+
const spawned = spawnTasks.length ? await postSubagentSpawn({
|
|
4287
4335
|
messageId,
|
|
4288
4336
|
tasks: spawnTasks
|
|
4289
|
-
})
|
|
4337
|
+
}) : {
|
|
4338
|
+
taskIds: [],
|
|
4339
|
+
tasks: []
|
|
4340
|
+
};
|
|
4341
|
+
const rearmed = await Promise.all(rearmRequests.map(async ({ task, index }) => {
|
|
4342
|
+
try {
|
|
4343
|
+
const result = await postSubagentRearm({
|
|
4344
|
+
messageId,
|
|
4345
|
+
taskId: task.taskId,
|
|
4346
|
+
timeoutMinutes: task.timeoutMinutes
|
|
4347
|
+
});
|
|
4348
|
+
return {
|
|
4349
|
+
index,
|
|
4350
|
+
timeoutMinutes: task.timeoutMinutes,
|
|
4351
|
+
...result
|
|
4352
|
+
};
|
|
4353
|
+
} catch (err) {
|
|
4354
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4355
|
+
log$1.warn({
|
|
4356
|
+
err,
|
|
4357
|
+
event: "subagent_rearm_failed",
|
|
4358
|
+
taskId: task.taskId
|
|
4359
|
+
}, "subagent re-arm failed");
|
|
4360
|
+
return {
|
|
4361
|
+
index,
|
|
4362
|
+
taskId: task.taskId,
|
|
4363
|
+
error: message
|
|
4364
|
+
};
|
|
4365
|
+
}
|
|
4366
|
+
}));
|
|
4290
4367
|
const { taskIds } = spawned;
|
|
4291
4368
|
log$1.info({
|
|
4292
4369
|
event: "subagent_spawned",
|
|
4293
4370
|
count: taskIds.length
|
|
4294
4371
|
}, "subagent tasks queued");
|
|
4295
4372
|
const convByTask = new Map(spawned.tasks.map((t) => [t.taskId, t.conversationId]));
|
|
4296
|
-
const lines =
|
|
4297
|
-
const
|
|
4298
|
-
|
|
4299
|
-
|
|
4373
|
+
const lines = tasks.map((_, index) => {
|
|
4374
|
+
const spawnIndex = spawnRequests.findIndex((request) => request.index === index);
|
|
4375
|
+
if (spawnIndex >= 0) {
|
|
4376
|
+
const id = taskIds[spawnIndex];
|
|
4377
|
+
const label = spawnTasks[spawnIndex]?.title ?? spawnTasks[spawnIndex]?.task ?? "";
|
|
4378
|
+
const conv = id ? convByTask.get(id) : void 0;
|
|
4379
|
+
return conv ? `- conversation ${conv}: ${label} (taskId ${id})` : `- ${label} (taskId ${id}, conversation id unavailable — cannot peer this run)`;
|
|
4380
|
+
}
|
|
4381
|
+
const rearm = rearmed.find((request) => request.index === index);
|
|
4382
|
+
if (!rearm) return "- task update unavailable";
|
|
4383
|
+
return "error" in rearm ? `- taskId ${rearm.taskId ?? "unknown"}: re-arm failed — ${rearm.error}` : `- taskId ${rearm.taskId}: wake again in ${rearm.timeoutMinutes} minutes`;
|
|
4300
4384
|
}).join("\n");
|
|
4301
4385
|
const peerHint = spawned.tasks.length ? "\nEach subagent runs on its own conversation (id shown per task above). To SEE what one is doing while it runs, read it with `platform conversations show <conversationId>`. To STEER one mid-run — add context, correct course, answer a question — post to its conversation with `platform conversations post <conversationId> --message \"...\"`; it lands as a live steer if the subagent is still running, or as its next turn if it has gone idle." : "";
|
|
4302
4386
|
return {
|
|
4303
4387
|
content: [{
|
|
4304
4388
|
type: "text",
|
|
4305
|
-
text: `Queued ${taskIds.length} subagent ${taskIds.length === 1 ? "run" : "runs"}.
|
|
4389
|
+
text: `${taskIds.length ? `Queued ${taskIds.length} subagent ${taskIds.length === 1 ? "run" : "runs"}.` : ""}${rearmed.length ? `${taskIds.length ? " " : ""}Re-armed ${rearmed.length} running ${rearmed.length === 1 ? "task" : "tasks"}.` : ""} Each will wake you on completion or at its next timeout.\n${lines}${peerHint}`
|
|
4306
4390
|
}],
|
|
4307
4391
|
details: {
|
|
4308
4392
|
taskIds,
|
|
4309
|
-
tasks: spawned.tasks
|
|
4393
|
+
tasks: spawned.tasks,
|
|
4394
|
+
rearmed
|
|
4310
4395
|
}
|
|
4311
4396
|
};
|
|
4312
4397
|
} catch (err) {
|
|
@@ -4314,11 +4399,11 @@ function buildTool(messageId) {
|
|
|
4314
4399
|
log$1.warn({
|
|
4315
4400
|
err,
|
|
4316
4401
|
event: "subagent_spawn_failed"
|
|
4317
|
-
}, "subagent
|
|
4402
|
+
}, "subagent request failed");
|
|
4318
4403
|
return {
|
|
4319
4404
|
content: [{
|
|
4320
4405
|
type: "text",
|
|
4321
|
-
text: `Failed to
|
|
4406
|
+
text: `Failed to update subagent tasks: ${message}`
|
|
4322
4407
|
}],
|
|
4323
4408
|
details: {},
|
|
4324
4409
|
isError: true
|