@arhen/pi-core-subagent 1.3.58 → 1.3.60
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/README.md +3 -1
- package/package.json +1 -1
- package/src/child.ts +12 -4
- package/src/format.ts +11 -0
- package/src/index.ts +5 -4
- package/src/manager.ts +65 -16
- package/src/schemas.ts +6 -0
package/README.md
CHANGED
|
@@ -305,13 +305,15 @@ Background (default) + intercom — the run returns a runId immediately; you sta
|
|
|
305
305
|
|
|
306
306
|
| Tool | Meaning |
|
|
307
307
|
|---|---|
|
|
308
|
-
| `ask_parent` | blocking question to the leader; parent answers via `reply_subagent` |
|
|
308
|
+
| `ask_parent` | blocking question to the leader; delivered mid-turn as a **steering** message labelled `[URGENT]` or `[not urgent]`, parent answers via `reply_subagent` |
|
|
309
309
|
| `notify_parent` | one-way message to the leader |
|
|
310
310
|
| `send_agent_message` | message to a sibling subagent's mailbox (`to` = its task id, or `"leader"`) |
|
|
311
311
|
| `poll_agent_messages` | drain this subagent's mailbox |
|
|
312
312
|
|
|
313
313
|
> **Intercom anti-deadlock:** children are told to never block indefinitely on intercom replies — an unanswered `ask_parent` times out after 10 minutes (the child is told to proceed with best judgment), and sibling polls are capped (~5 tries) with the same fallback. Gated siblings (later waves) may not be running yet — waiting on them is the top stall cause, so children are instructed not to.
|
|
314
314
|
|
|
315
|
+
> **Ask urgency:** `ask_parent` takes `urgent` (default `false`). Both variants steer into the leader's current turn so the question is never deferred to the end of a long turn. `[URGENT]` tells the leader to answer before its next step; `[not urgent]` tells it that the child keeps waiting, so it may finish its current step first. Failures steer for the same reason; completions and aborts queue as follow-ups.
|
|
316
|
+
|
|
315
317
|
## Commands
|
|
316
318
|
|
|
317
319
|
- `/subagents` — list runs; `/subagents peek` (or `ctrl+shift+a`) — browsable pane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arhen/pi-core-subagent",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.60",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "pi extension: fast in-process subagents with a dependency-graph scheduler (needs edges gate tasks and carry upstream output into dependent prompts), plus background runs, intercom and agent-to-agent mailbox. Leader defines agents inline.",
|
|
6
6
|
"license": "MIT",
|
package/src/child.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { MailboxMessage } from "./mailbox.ts";
|
|
|
6
6
|
export const CHILD_TALK_TOOLS = ["ask_parent", "notify_parent", "send_agent_message", "poll_agent_messages"] as const;
|
|
7
7
|
|
|
8
8
|
export interface ChildHandlers {
|
|
9
|
-
onAskParent(taskId: string, question: string): Promise<string>;
|
|
9
|
+
onAskParent(taskId: string, question: string, urgent: boolean): Promise<string>;
|
|
10
10
|
onNotifyParent(taskId: string, message: string, level: "info" | "warning" | "error"): void;
|
|
11
11
|
onSendMessage(taskId: string, to: string, text: string): boolean;
|
|
12
12
|
onPollMailbox(taskId: string): MailboxMessage[];
|
|
@@ -18,18 +18,26 @@ export function createChildTools(taskId: string, handlers: ChildHandlers): ToolD
|
|
|
18
18
|
name: "ask_parent",
|
|
19
19
|
label: "Ask Parent",
|
|
20
20
|
description:
|
|
21
|
-
"Ask the parent agent a clarifying question and BLOCK until it replies (10 min cap — then proceed with best judgment). Use sparingly — only when you truly cannot proceed without information only the parent has. Prefer figuring it out yourself.",
|
|
21
|
+
"Ask the parent agent a clarifying question and BLOCK until it replies (10 min cap — then proceed with best judgment). Use sparingly — only when you truly cannot proceed without information only the parent has. Prefer figuring it out yourself. The parent sees the question mid-turn: set urgent when you cannot continue until it answers, leave it unset when the parent may finish its current step first.",
|
|
22
22
|
promptSnippet: "Ask the parent agent a question when truly blocked.",
|
|
23
23
|
promptGuidelines: [
|
|
24
24
|
"Use ask_parent only as a last resort when blocked on information only the parent has.",
|
|
25
25
|
"Ask one focused question at a time. The parent's reply resumes your work.",
|
|
26
|
+
"Set urgent: true only when you cannot keep working while waiting; otherwise the parent is told it may answer after its current step.",
|
|
26
27
|
],
|
|
27
28
|
parameters: Type.Object({
|
|
28
29
|
question: Type.String({ description: "A single, focused question for the parent agent" }),
|
|
30
|
+
urgent: Type.Optional(
|
|
31
|
+
Type.Boolean({
|
|
32
|
+
description:
|
|
33
|
+
"True when nothing else can proceed until the parent answers — it is told to stop and reply now",
|
|
34
|
+
default: false,
|
|
35
|
+
}),
|
|
36
|
+
),
|
|
29
37
|
}),
|
|
30
38
|
async execute(_toolCallId, params) {
|
|
31
|
-
const { question } = params as { question: string };
|
|
32
|
-
const answer = await handlers.onAskParent(taskId, question);
|
|
39
|
+
const { question, urgent } = params as { question: string; urgent?: boolean };
|
|
40
|
+
const answer = await handlers.onAskParent(taskId, question, urgent === true);
|
|
33
41
|
return { content: [{ type: "text" as const, text: answer || "(parent gave no answer)" }], details: {} };
|
|
34
42
|
},
|
|
35
43
|
},
|
package/src/format.ts
CHANGED
|
@@ -250,6 +250,17 @@ export function makeTaskNotice(run: RunSnapshot, task: TaskSnapshot, kind: strin
|
|
|
250
250
|
: `Session file kept — resume_subagent(runId: "${run.id}", taskId: "${task.id}", model?: ...) revives it with full context. subagent_result for what it produced so far.`,
|
|
251
251
|
].join("\n");
|
|
252
252
|
}
|
|
253
|
+
export function makeAskNotice(
|
|
254
|
+
run: RunSnapshot,
|
|
255
|
+
extra: { taskId?: string; agent?: string; question?: string; urgent?: boolean },
|
|
256
|
+
): string {
|
|
257
|
+
const who = extra.agent ? `${extra.agent} (${extra.taskId ?? "task"})` : (extra.taskId ?? "a subagent");
|
|
258
|
+
const reply = `reply_subagent(runId: "${run.id}", taskId: "${extra.taskId ?? ""}", message: ...)`;
|
|
259
|
+
return extra.urgent
|
|
260
|
+
? `[URGENT] Subagent ${who} is blocked and cannot continue until you answer: ${extra.question ?? ""}\nAnswer now, before your next step, with ${reply}.`
|
|
261
|
+
: `[not urgent] Subagent ${who} asks: ${extra.question ?? ""}\nIt waits while you keep working — finish your current step first if you want, then answer with ${reply}.`;
|
|
262
|
+
}
|
|
263
|
+
|
|
253
264
|
export function makeNotice(run: RunSnapshot, kind: string): string {
|
|
254
265
|
const lines = [
|
|
255
266
|
`Background subagent run ${run.id} ${kind}: ${run.tasks.filter((t) => t.status === "completed").length}/${run.tasks.length} succeeded.`,
|
package/src/index.ts
CHANGED
|
@@ -381,23 +381,24 @@ export default function (pi: ExtensionAPI) {
|
|
|
381
381
|
name: "resume_subagent",
|
|
382
382
|
label: "Resume Subagent",
|
|
383
383
|
description:
|
|
384
|
-
"Revive a failed/aborted task in its original session (full context + worktree branch preserved). Optional `model` swaps provider (e.g. after a rate limit); optional `message` replaces the default 'recap and continue' prompt. Refuses tasks that never started — respawn those.",
|
|
384
|
+
"Revive a failed/aborted task in its original session (full context + worktree branch preserved). Optional `model` swaps provider (e.g. after a rate limit); optional `thinking` sets the effort — the stored level is clamped to what the target model accepts, so a resume never dies on an unsupported effort; optional `message` replaces the default 'recap and continue' prompt. Refuses tasks that never started — respawn those.",
|
|
385
385
|
parameters: ResumeParam,
|
|
386
386
|
async execute(_id, params, _signal, _onUpdate, ctx) {
|
|
387
|
-
const { runId, taskId, message, model } = params as {
|
|
387
|
+
const { runId, taskId, message, model, thinking } = params as {
|
|
388
388
|
runId: string;
|
|
389
389
|
taskId: string;
|
|
390
390
|
message?: string;
|
|
391
391
|
model?: string;
|
|
392
|
+
thinking?: string;
|
|
392
393
|
};
|
|
393
|
-
const res = manager.resumeTask(runId, taskId, ctx, { message, model });
|
|
394
|
+
const res = manager.resumeTask(runId, taskId, ctx, { message, model, thinking });
|
|
394
395
|
if (!res.ok) return { content: [{ type: "text", text: res.reason }], isError: true, details: {} };
|
|
395
396
|
const run = manager.getRun(runId);
|
|
396
397
|
return {
|
|
397
398
|
content: [
|
|
398
399
|
{
|
|
399
400
|
type: "text",
|
|
400
|
-
text: `Resumed ${runId}/${taskId} (${res.task.agent})${model ? ` on ${model}` : ""} from ${res.task.sessionFile}${res.task.branch ? `, branch ${res.task.branch}` : ""}
|
|
401
|
+
text: `Resumed ${runId}/${taskId} (${res.task.agent})${model ? ` on ${model}` : ""} from ${res.task.sessionFile}${res.task.branch ? `, branch ${res.task.branch}` : ""}.${res.note ? ` Adjusted ${res.note}.` : ""}\nNext: subagent_status("${runId}") to confirm it is running; completion will notify you.`,
|
|
401
402
|
},
|
|
402
403
|
],
|
|
403
404
|
details: { run: run ? cloneRun(run) : undefined },
|
package/src/manager.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
getFirstText,
|
|
30
30
|
isStartupFailure,
|
|
31
31
|
isTalking,
|
|
32
|
+
makeAskNotice,
|
|
32
33
|
makeNotice,
|
|
33
34
|
makeTaskNotice,
|
|
34
35
|
SubagentsWidget,
|
|
@@ -67,8 +68,8 @@ const DEFAULT_RUNTIME_MS = 3_600_000;
|
|
|
67
68
|
const UNLIMITED_RUNTIME_MS = 21_600_000;
|
|
68
69
|
const PARENT_REPLY_TIMEOUT_MS = 600_000;
|
|
69
70
|
const PARKED_MSG_CAP = 24;
|
|
70
|
-
const READONLY_TOOLS = ["read", "grep", "find", "ls"];
|
|
71
|
-
const WRITE_TOOLS = ["read", "grep", "find", "ls", "bash", "edit", "write"];
|
|
71
|
+
const READONLY_TOOLS = ["read", "grep", "find", "ls", "codemode"];
|
|
72
|
+
const WRITE_TOOLS = ["read", "grep", "find", "ls", "bash", "edit", "write", "codemode"];
|
|
72
73
|
const WRITE_CAPABLE = ["bash", "edit", "write"];
|
|
73
74
|
const SAFE_TASK_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
74
75
|
const WIDGET_THROTTLE_MS = 150;
|
|
@@ -76,6 +77,25 @@ const WIDGET_THROTTLE_MS = 150;
|
|
|
76
77
|
function newId(prefix: string): string {
|
|
77
78
|
return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
78
79
|
}
|
|
80
|
+
|
|
81
|
+
type ChildExtensionFactories = ConstructorParameters<typeof DefaultResourceLoader>[0]["extensionFactories"];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Children run with `noExtensions`, so they get none of the configured extensions — codemode is the
|
|
85
|
+
* one exception, because it is how a child batches tool calls. `createCodemodeExtension()` is the
|
|
86
|
+
* supported factory (pi >= 1.0); hosts that do not export it simply give children no codemode.
|
|
87
|
+
*/
|
|
88
|
+
async function codemodeFactories(): Promise<ChildExtensionFactories> {
|
|
89
|
+
try {
|
|
90
|
+
const host = (await import("@earendil-works/pi-coding-agent")) as unknown as {
|
|
91
|
+
createCodemodeExtension?: () => unknown;
|
|
92
|
+
};
|
|
93
|
+
const factory = host.createCodemodeExtension?.();
|
|
94
|
+
return factory ? ([factory] as ChildExtensionFactories) : [];
|
|
95
|
+
} catch {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
79
99
|
function emptyUsage(): UsageStats {
|
|
80
100
|
return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
|
|
81
101
|
}
|
|
@@ -142,6 +162,18 @@ function updateUsageFromMessage(task: TaskSnapshot, message: AssistantMessage):
|
|
|
142
162
|
export function cloneRun(run: RunSnapshot): RunSnapshot {
|
|
143
163
|
return JSON.parse(JSON.stringify(run)) as RunSnapshot;
|
|
144
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* A resumed task keeps its stored thinking level, clamped to what the target model accepts — a
|
|
167
|
+
* resume that swaps model must not fail on an effort the new model does not define.
|
|
168
|
+
*/
|
|
169
|
+
export function clampResumeThinking(
|
|
170
|
+
model: Model<Api> | undefined,
|
|
171
|
+
thinking: ThinkingLevel | undefined,
|
|
172
|
+
): ThinkingLevel | undefined {
|
|
173
|
+
if (!thinking || !model) return thinking;
|
|
174
|
+
return clampThinkingLevel(model, thinking) as ThinkingLevel;
|
|
175
|
+
}
|
|
176
|
+
|
|
145
177
|
export function resolveChildModel(ctx: ExtensionContext, explicit: string | undefined) {
|
|
146
178
|
if (!explicit?.trim()) return ctx.model;
|
|
147
179
|
const ref = explicit.trim();
|
|
@@ -494,19 +526,21 @@ export class SubagentManager {
|
|
|
494
526
|
private notifyParent(
|
|
495
527
|
run: RunSnapshot,
|
|
496
528
|
kind: "completed" | "failed" | "aborted" | "asked",
|
|
497
|
-
extra?: { taskId?: string; question?: string },
|
|
529
|
+
extra?: { taskId?: string; agent?: string; question?: string; urgent?: boolean },
|
|
498
530
|
): void {
|
|
499
531
|
if (kind !== "asked" && run.awaited) return;
|
|
500
532
|
// single-task completed run: the task notice already said everything (failure paths may not have notified per-task)
|
|
501
533
|
if (kind === "completed" && run.tasks.length === 1 && run.notifyPerTask) return;
|
|
502
|
-
const body =
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
534
|
+
const body = kind === "asked" ? makeAskNotice(run, extra ?? {}) : makeNotice(run, kind);
|
|
535
|
+
// asks steer: the leader sees the question during its turn and the urgent flag tells it whether to
|
|
536
|
+
// answer now or after the current step. Failures steer for the same reason — a broken result must
|
|
537
|
+
// not be consumed. Completions and aborts queue as follow-ups.
|
|
506
538
|
try {
|
|
507
|
-
this.pi.sendUserMessage(body, {
|
|
539
|
+
this.pi.sendUserMessage(body, {
|
|
540
|
+
deliverAs: kind === "completed" || kind === "aborted" ? "followUp" : "steer",
|
|
541
|
+
});
|
|
508
542
|
} catch {}
|
|
509
|
-
this.emit("subagent:notification", { runId: run.id, kind, body });
|
|
543
|
+
this.emit("subagent:notification", { runId: run.id, taskId: extra?.taskId, kind, body });
|
|
510
544
|
}
|
|
511
545
|
|
|
512
546
|
private widgetTui: TUI | null = null;
|
|
@@ -614,14 +648,14 @@ export class SubagentManager {
|
|
|
614
648
|
|
|
615
649
|
private makeChildHandlers(run: RunSnapshot, task: TaskSnapshot, ctx: ExtensionContext): ChildHandlers {
|
|
616
650
|
return {
|
|
617
|
-
onAskParent: async (_taskId, question) => {
|
|
651
|
+
onAskParent: async (_taskId, question, urgent) => {
|
|
618
652
|
if (TERMINAL.includes(task.status)) {
|
|
619
653
|
return "(your task has already ended — stop work and return immediately)";
|
|
620
654
|
}
|
|
621
655
|
this.updateTask(run, task, { status: "awaiting_parent" }, ctx);
|
|
622
656
|
|
|
623
657
|
if (!this.collectParked(run.id, { kind: "ask", taskId: task.id, agent: task.agent, text: question })) {
|
|
624
|
-
this.notifyParent(run, "asked", { taskId: task.id, question });
|
|
658
|
+
this.notifyParent(run, "asked", { taskId: task.id, agent: task.agent, question, urgent });
|
|
625
659
|
}
|
|
626
660
|
|
|
627
661
|
const reply = await this.awaitParentReply(run.id, task.id, PARENT_REPLY_TIMEOUT_MS);
|
|
@@ -891,12 +925,13 @@ export class SubagentManager {
|
|
|
891
925
|
const worktreeNote = wt
|
|
892
926
|
? ` You work in an isolated git worktree (branch ${wt.branch})${task.stackedOn ? `, stacked on ${task.stackedOn} (its changes are already in your tree)` : ""}. Never run git commands that switch branches, create branches, or move the worktree (git switch/checkout/branch/worktree). The extension commits your changes when you finish. git status/diff are fine for inspecting your own changes. node_modules is a SHARED symlink to the main checkout: never install, upgrade, or delete dependencies (no npm/bun/yarn/pnpm install, no \`rm -rf node_modules\`) — those writes escape your worktree and damage the user's project. If the task truly needs a dependency change, edit the manifest only and say so in your answer.`
|
|
893
927
|
: "";
|
|
894
|
-
const subagentInstruction = `You are running as a subagent. Your bash tool already executes in the project working directory — never prefix commands with \`cd\`. Do not call subagent/delegation tools unless the parent explicitly asks. Return a concise final answer. You MAY use ask_parent only when truly blocked on information only the parent has; notify_parent for one-way updates; send_agent_message/poll_agent_messages to coordinate with siblings. Your mailbox address and siblings: ${task.roster ?? "(none)"}. Use the exact task ids (e.g. task_2) as send_agent_message targets. Siblings run independently and may start late or finish early — never block indefinitely on their replies: poll at most 5 times, then proceed with your best judgment. A gated sibling (marked ↳ waits in the graph) may not be running yet; do not wait for it. An unanswered ask_parent times out after 10 minutes — proceed with your best judgment then. When your work is done, call notify_parent ONCE with a concise result summary — key findings, verdicts, file:line evidence — so the leader can start consuming your output before the run finishes.${worktreeNote}`;
|
|
928
|
+
const subagentInstruction = `You are running as a subagent. Your bash tool already executes in the project working directory — never prefix commands with \`cd\`. Do not call subagent/delegation tools unless the parent explicitly asks. Return a concise final answer. You MAY use ask_parent only when truly blocked on information only the parent has (set urgent: true only when nothing else can proceed while you wait); notify_parent for one-way updates; send_agent_message/poll_agent_messages to coordinate with siblings. Your mailbox address and siblings: ${task.roster ?? "(none)"}. Use the exact task ids (e.g. task_2) as send_agent_message targets. Siblings run independently and may start late or finish early — never block indefinitely on their replies: poll at most 5 times, then proceed with your best judgment. A gated sibling (marked ↳ waits in the graph) may not be running yet; do not wait for it. An unanswered ask_parent times out after 10 minutes — proceed with your best judgment then. When your work is done, call notify_parent ONCE with a concise result summary — key findings, verdicts, file:line evidence — so the leader can start consuming your output before the run finishes.${worktreeNote}`;
|
|
895
929
|
|
|
896
930
|
const loader = new DefaultResourceLoader({
|
|
897
931
|
cwd: childCwd,
|
|
898
932
|
agentDir: getAgentDir(),
|
|
899
933
|
noExtensions: true,
|
|
934
|
+
extensionFactories: await codemodeFactories(),
|
|
900
935
|
appendSystemPromptOverride: (base) => [
|
|
901
936
|
...base,
|
|
902
937
|
[prompt?.trim(), subagentInstruction].filter(Boolean).join("\n\n"),
|
|
@@ -1377,8 +1412,8 @@ export class SubagentManager {
|
|
|
1377
1412
|
runId: string,
|
|
1378
1413
|
taskId: string,
|
|
1379
1414
|
ctx: ExtensionContext,
|
|
1380
|
-
opts: { message?: string; model?: string } = {},
|
|
1381
|
-
): { ok: true; task: TaskSnapshot } | { ok: false; reason: string } {
|
|
1415
|
+
opts: { message?: string; model?: string; thinking?: string } = {},
|
|
1416
|
+
): { ok: true; task: TaskSnapshot; note?: string } | { ok: false; reason: string } {
|
|
1382
1417
|
const run = this.runs.get(runId);
|
|
1383
1418
|
const task = run?.tasks.find((t) => t.id === taskId);
|
|
1384
1419
|
if (!run || !task) return { ok: false, reason: `Unknown ${runId}/${taskId}.` };
|
|
@@ -1396,6 +1431,19 @@ export class SubagentManager {
|
|
|
1396
1431
|
|
|
1397
1432
|
const tools = task.tools?.filter((t) => !(CHILD_TALK_TOOLS as readonly string[]).includes(t));
|
|
1398
1433
|
const write = tools?.some((t) => WRITE_CAPABLE.includes(t)) ?? false;
|
|
1434
|
+
// A resume may swap the model, so the level stored on the task can be one the new model
|
|
1435
|
+
// rejects (a mode-clamped xhigh onto a model that only takes low|high|max). Clamp it, or take
|
|
1436
|
+
// the caller's explicit level and clamp that.
|
|
1437
|
+
let resumeModel: Model<Api> | undefined;
|
|
1438
|
+
try {
|
|
1439
|
+
resumeModel = resolveChildModel(ctx, opts.model ?? task.model);
|
|
1440
|
+
} catch {}
|
|
1441
|
+
const requestedThinking = (opts.thinking ?? task.thinking) as ThinkingLevel | undefined;
|
|
1442
|
+
const thinking = clampResumeThinking(resumeModel, requestedThinking);
|
|
1443
|
+
const thinkingNote =
|
|
1444
|
+
requestedThinking && thinking !== requestedThinking
|
|
1445
|
+
? `thinking ${requestedThinking} → ${thinking} (${resumeModel?.provider}/${resumeModel?.id} does not accept ${requestedThinking})`
|
|
1446
|
+
: undefined;
|
|
1399
1447
|
const input: TaskInput = {
|
|
1400
1448
|
id: task.id,
|
|
1401
1449
|
agent: task.agent,
|
|
@@ -1404,7 +1452,7 @@ export class SubagentManager {
|
|
|
1404
1452
|
write,
|
|
1405
1453
|
tools: tools?.length ? tools : undefined,
|
|
1406
1454
|
model: opts.model ?? task.model,
|
|
1407
|
-
thinking:
|
|
1455
|
+
thinking: thinking as TaskInput["thinking"],
|
|
1408
1456
|
needs: task.needs,
|
|
1409
1457
|
};
|
|
1410
1458
|
const resume: ResumeInput = {
|
|
@@ -1419,6 +1467,7 @@ export class SubagentManager {
|
|
|
1419
1467
|
this.turnActivity = true;
|
|
1420
1468
|
Object.assign(task, {
|
|
1421
1469
|
status: "queued" as TaskStatus,
|
|
1470
|
+
thinking,
|
|
1422
1471
|
error: undefined,
|
|
1423
1472
|
endedAt: undefined,
|
|
1424
1473
|
finalText: undefined,
|
|
@@ -1451,7 +1500,7 @@ export class SubagentManager {
|
|
|
1451
1500
|
if (run.notifyPerTask) this.notifyTask(run, task, task.status as "completed" | "failed" | "aborted");
|
|
1452
1501
|
this.finishRunIfSettled(run, ctx);
|
|
1453
1502
|
});
|
|
1454
|
-
return { ok: true, task };
|
|
1503
|
+
return { ok: true, task, note: thinkingNote };
|
|
1455
1504
|
}
|
|
1456
1505
|
|
|
1457
1506
|
private finishRunIfSettled(run: RunSnapshot, ctx: ExtensionContext): void {
|
package/src/schemas.ts
CHANGED
|
@@ -89,6 +89,12 @@ export const ResumeParam = Type.Object({
|
|
|
89
89
|
"Model override for the resumed session (provider/model-id) — use when the original provider is rate-limited",
|
|
90
90
|
}),
|
|
91
91
|
),
|
|
92
|
+
thinking: Type.Optional(
|
|
93
|
+
StringEnum(THINKING_LEVELS, {
|
|
94
|
+
description:
|
|
95
|
+
"Thinking level for the resumed session. Default: the task's stored level, clamped to what the target model accepts",
|
|
96
|
+
}),
|
|
97
|
+
),
|
|
92
98
|
});
|
|
93
99
|
export const SteerParam = Type.Object({
|
|
94
100
|
runId: Type.String(),
|