@narumitw/pi-subagents 0.11.0 → 0.13.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/README.md CHANGED
@@ -14,7 +14,7 @@ Use it to split research, planning, implementation, and review work across focus
14
14
  - Loads custom user agents from `~/.pi/agent/agents/*.md`.
15
15
  - Optionally loads project agents from `.pi/agents/*.md` with confirmation.
16
16
  - Provides `/subagents:config` to persist per-agent tool allow-lists.
17
- - Supports per-task `cwd`, hard subprocess `timeoutMs`, abort propagation, and streaming progress.
17
+ - Supports per-task `cwd`, hard subprocess `timeoutMs`, `thinkingLevel`, abort propagation, and streaming progress.
18
18
  - Publishes transient runtime status through Pi's generic extension status API while subagents are running.
19
19
  - Returns complete worker output in tool details and a concise result for the main agent.
20
20
 
@@ -49,29 +49,50 @@ Execution modes:
49
49
  - **parallel + aggregator** — run parallel jobs, then pass all outputs into one fan-in agent.
50
50
  - **chain** — run sequential steps, passing prior output with `{previous}`.
51
51
 
52
+ Common controls:
53
+
54
+ - `cwd` — run a job from a different working directory.
55
+ - `timeoutMs` — set a hard subprocess timeout.
56
+ - `thinkingLevel` — request `off`, `minimal`, `low`, `medium`, `high`, or `xhigh` thinking for the spawned Pi process.
57
+
52
58
  ## 🧭 Proactive use
53
59
 
54
- The `subagent` tool now advertises concise prompt guidance so the main Pi agent can choose it
55
- without an explicit user request when delegation is a good fit.
60
+ The `subagent` tool advertises concise prompt guidance so the main Pi agent can decide
61
+ whether to spawn 0, 1, or multiple subagents without an explicit user-specified count.
62
+
63
+ Count-selection guidance:
56
64
 
57
- Use `subagent` proactively for:
65
+ - Use **no subagent** for simple answers, quick targeted edits, latency-sensitive one-step work, or
66
+ tasks that need frequent user back-and-forth.
67
+ - Use **one subagent** for isolated research, high-volume command output, planning, or independent
68
+ review/verification after implementation.
69
+ - Prefer **2–4 parallel read-only subagents** when a broad task naturally splits into independent
70
+ branches that can each return a concise summary.
71
+ - Exceed 4 tasks only when the branches are clearly distinct and worth the extra cost, while staying
72
+ within the existing hard max of 8 parallel tasks.
73
+ - Do not parallelize implementation that may edit the same files or shared state; serialize
74
+ write-heavy work instead.
75
+ - Do not use project-local agents unless the user explicitly opts into them with
76
+ `agentScope: "project"` or `"both"`; keep confirmation enabled for untrusted repositories.
58
77
 
59
- - Independent read-only research, broad codebase reconnaissance, or high-volume command output
60
- that would clutter the main context.
61
- - Parallel multi-domain investigation where each branch can return a concise summary.
62
- - Independent review or verification after implementation, especially with the read-only
63
- `reviewer` agent.
78
+ Examples where the main agent chooses the count:
64
79
 
65
- Do not use `subagent` for:
80
+ No subagent for a known-file edit:
66
81
 
67
- - Simple answers, quick targeted edits, latency-sensitive one-step work, or tasks that need
68
- frequent user back-and-forth.
69
- - Parallel implementation that may edit the same files or shared state; serialize write-heavy work
70
- instead.
71
- - Project-local agents unless the user explicitly opts into them with `agentScope: "project"` or
72
- `"both"`; keep confirmation enabled for untrusted repositories.
82
+ ```txt
83
+ Rename one symbol in src/foo.ts.
84
+ ```
73
85
 
74
- Good delegation example:
86
+ One subagent for an independent review:
87
+
88
+ ```json
89
+ {
90
+ "agent": "reviewer",
91
+ "task": "Review the current changes for release blockers. Do not edit files. Report PASS/FAIL/PARTIAL with evidence."
92
+ }
93
+ ```
94
+
95
+ Two to four parallel subagents for broad independent reconnaissance:
75
96
 
76
97
  ```json
77
98
  {
@@ -83,6 +104,10 @@ Good delegation example:
83
104
  {
84
105
  "agent": "scout",
85
106
  "task": "Research auth-related tests. Report coverage gaps. Do not edit files."
107
+ },
108
+ {
109
+ "agent": "scout",
110
+ "task": "Research API entry points that depend on auth. Report integration risks. Do not edit files."
86
111
  }
87
112
  ],
88
113
  "aggregator": {
@@ -92,9 +117,6 @@ Good delegation example:
92
117
  }
93
118
  ```
94
119
 
95
- Bad delegation example: do not spawn a worker just to rename one symbol in a known file; edit it
96
- directly in the main conversation.
97
-
98
120
  ## 🚀 Examples
99
121
 
100
122
  Run one read-only reconnaissance agent:
@@ -106,7 +128,7 @@ Run one read-only reconnaissance agent:
106
128
  }
107
129
  ```
108
130
 
109
- Run multiple agents in parallel:
131
+ Run multiple agents in parallel with a shared thinking level and one per-task override:
110
132
 
111
133
  ```json
112
134
  {
@@ -114,14 +136,16 @@ Run multiple agents in parallel:
114
136
  {
115
137
  "agent": "scout",
116
138
  "task": "Map package metadata files",
117
- "timeoutMs": 30000
139
+ "timeoutMs": 30000,
140
+ "thinkingLevel": "low"
118
141
  },
119
142
  {
120
143
  "agent": "reviewer",
121
144
  "task": "Review TypeScript config consistency"
122
145
  }
123
146
  ],
124
- "timeoutMs": 120000
147
+ "timeoutMs": 120000,
148
+ "thinkingLevel": "medium"
125
149
  }
126
150
  ```
127
151
 
@@ -196,6 +220,7 @@ name: api-reviewer
196
220
  description: Review API changes for compatibility and tests
197
221
  tools: read, grep, find, ls, bash
198
222
  model: sonnet
223
+ thinkingLevel: high
199
224
  ---
200
225
 
201
226
  You are an API review subagent. Do not edit files. Check compatibility,
@@ -204,7 +229,7 @@ test coverage, and migration risks. Report PASS/FAIL/PARTIAL with evidence.
204
229
 
205
230
  By default, `subagent` loads user agents only. Set `agentScope` to `"project"` or `"both"` to load project-local agents. Interactive sessions ask for confirmation before using project agents unless `confirmProjectAgents` is disabled.
206
231
 
207
- ## ⏱️ Runtime limits
232
+ ## ⏱️ Runtime limits and thinking levels
208
233
 
209
234
  Each subprocess has a hard timeout to avoid runaway workers.
210
235
 
@@ -212,6 +237,10 @@ Each subprocess has a hard timeout to avoid runaway workers.
212
237
  - Set `timeoutMs` on a task, chain step, or aggregator to override it locally.
213
238
  - If omitted, the default is `PI_SUBAGENT_TIMEOUT_MS`, or `600000` milliseconds (10 minutes) when unset.
214
239
 
240
+ Set `thinkingLevel` to pass Pi's `--thinking <level>` to a subprocess. Supported values are `off`, `minimal`, `low`, `medium`, `high`, and `xhigh`.
241
+
242
+ Thinking-level precedence is: task/chain step/aggregator `thinkingLevel` → top-level `thinkingLevel` → agent default from config or frontmatter → Pi subprocess default. Omit `thinkingLevel` to preserve existing behavior. Pi still owns model capability clamping, so unsupported thinking levels are handled by the spawned Pi process.
243
+
215
244
  On timeout, the extension sends `SIGTERM`, escalates to `SIGKILL` after a short grace period, and returns any partial messages or stderr collected so far.
216
245
 
217
246
  ## 📡 Runtime status
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narumitw/pi-subagents",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Pi extension for delegating work to specialized isolated subagents.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/agents.ts CHANGED
@@ -4,8 +4,17 @@
4
4
 
5
5
  import * as fs from "node:fs";
6
6
  import * as path from "node:path";
7
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
7
8
  import { getAgentDir, parseFrontmatter } from "@earendil-works/pi-coding-agent";
8
9
 
10
+ export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const satisfies readonly ThinkingLevel[];
11
+
12
+ export type SubagentThinkingLevel = (typeof THINKING_LEVELS)[number];
13
+
14
+ export function isThinkingLevel(value: unknown): value is SubagentThinkingLevel {
15
+ return typeof value === "string" && THINKING_LEVELS.includes(value as SubagentThinkingLevel);
16
+ }
17
+
9
18
  export type AgentScope = "user" | "project" | "both";
10
19
 
11
20
  export type AgentSource = "built-in" | "user" | "project";
@@ -15,6 +24,7 @@ export interface AgentConfig {
15
24
  description: string;
16
25
  tools?: string[];
17
26
  model?: string;
27
+ thinkingLevel?: SubagentThinkingLevel;
18
28
  timeoutMs?: number;
19
29
  systemPrompt: string;
20
30
  source: AgentSource;
@@ -24,6 +34,7 @@ export interface AgentConfig {
24
34
  export interface SubagentAgentConfig {
25
35
  tools?: string[];
26
36
  model?: string | null;
37
+ thinkingLevel?: SubagentThinkingLevel | null;
27
38
  timeoutMs?: number | null;
28
39
  }
29
40
 
@@ -146,6 +157,7 @@ function loadAgentsFromDir(dir: string, source: "user" | "project"): AgentConfig
146
157
  description: frontmatter.description,
147
158
  tools: tools && tools.length > 0 ? tools : undefined,
148
159
  model: frontmatter.model,
160
+ thinkingLevel: isThinkingLevel(frontmatter.thinkingLevel) ? frontmatter.thinkingLevel : undefined,
149
161
  systemPrompt: body,
150
162
  source,
151
163
  filePath,
@@ -217,6 +229,9 @@ export function discoverAgents(
217
229
  if (hasOwn(override, "model")) {
218
230
  nextAgent.model = override.model === null ? undefined : override.model;
219
231
  }
232
+ if (hasOwn(override, "thinkingLevel")) {
233
+ nextAgent.thinkingLevel = override.thinkingLevel === null ? undefined : override.thinkingLevel;
234
+ }
220
235
  if (hasOwn(override, "timeoutMs")) {
221
236
  nextAgent.timeoutMs = override.timeoutMs === null ? undefined : override.timeoutMs;
222
237
  }
package/src/subagents.ts CHANGED
@@ -39,12 +39,15 @@ import {
39
39
  } from "@earendil-works/pi-tui";
40
40
  import { Type } from "typebox";
41
41
  import {
42
+ THINKING_LEVELS,
42
43
  type AgentConfig,
43
44
  type AgentScope,
44
45
  type AgentSource,
45
46
  type SubagentAgentConfig,
46
47
  type SubagentSettings,
48
+ type SubagentThinkingLevel,
47
49
  discoverAgents,
50
+ isThinkingLevel,
48
51
  } from "./agents.js";
49
52
 
50
53
  const MAX_PARALLEL_TASKS = 8;
@@ -132,6 +135,7 @@ export function formatUsageStats(
132
135
  turns?: number;
133
136
  },
134
137
  model?: string,
138
+ thinkingLevel?: SubagentThinkingLevel,
135
139
  ): string {
136
140
  const parts: string[] = [];
137
141
  if (usage.turns) parts.push(`${usage.turns} turn${usage.turns > 1 ? "s" : ""}`);
@@ -144,6 +148,7 @@ export function formatUsageStats(
144
148
  parts.push(`ctx:${formatTokens(usage.contextTokens)}`);
145
149
  }
146
150
  if (model) parts.push(model);
151
+ if (thinkingLevel) parts.push(`thinking:${thinkingLevel}`);
147
152
  return parts.join(" ");
148
153
  }
149
154
 
@@ -234,6 +239,7 @@ interface SingleResult {
234
239
  stderr: string;
235
240
  usage: UsageStats;
236
241
  model?: string;
242
+ thinkingLevel?: SubagentThinkingLevel;
237
243
  stopReason?: string;
238
244
  errorMessage?: string;
239
245
  step?: number;
@@ -326,6 +332,25 @@ async function writePromptToTempFile(agentName: string, prompt: string): Promise
326
332
  return { dir: tmpDir, filePath };
327
333
  }
328
334
 
335
+ export function buildPiArgs(options: {
336
+ model?: string;
337
+ thinkingLevel?: SubagentThinkingLevel;
338
+ tools?: string[];
339
+ systemPromptPath?: string;
340
+ task: string;
341
+ }): string[] {
342
+ const args: string[] = ["--mode", "json", "-p", "--no-session"];
343
+ if (options.model) args.push("--model", options.model);
344
+ if (options.thinkingLevel) args.push("--thinking", options.thinkingLevel);
345
+ if (Array.isArray(options.tools)) {
346
+ if (options.tools.length > 0) args.push("--tools", options.tools.join(","));
347
+ else args.push("--no-tools");
348
+ }
349
+ if (options.systemPromptPath) args.push("--append-system-prompt", options.systemPromptPath);
350
+ args.push(`Task: ${options.task}`);
351
+ return args;
352
+ }
353
+
329
354
  function getPiInvocation(args: string[]): { command: string; args: string[] } {
330
355
  const currentScript = process.argv[1];
331
356
  const isBunVirtualScript = currentScript?.startsWith("/$bunfs/root/");
@@ -378,6 +403,7 @@ async function runSingleAgent(
378
403
  cwd: string | undefined,
379
404
  step: number | undefined,
380
405
  signal: AbortSignal | undefined,
406
+ thinkingLevel: SubagentThinkingLevel | undefined,
381
407
  timeoutMs: number,
382
408
  onUpdate: OnUpdateCallback | undefined,
383
409
  makeDetails: (results: SingleResult[]) => SubagentDetails,
@@ -394,18 +420,12 @@ async function runSingleAgent(
394
420
  messages: [],
395
421
  stderr: `Unknown agent: "${agentName}". Available agents: ${available}.`,
396
422
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
423
+ thinkingLevel,
397
424
  step,
398
425
  finalOutput: "",
399
426
  };
400
427
  }
401
428
 
402
- const args: string[] = ["--mode", "json", "-p", "--no-session"];
403
- if (agent.model) args.push("--model", agent.model);
404
- if (Array.isArray(agent.tools)) {
405
- if (agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
406
- else args.push("--no-tools");
407
- }
408
-
409
429
  let tmpPromptDir: string | null = null;
410
430
  let tmpPromptPath: string | null = null;
411
431
 
@@ -418,6 +438,7 @@ async function runSingleAgent(
418
438
  stderr: "",
419
439
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
420
440
  model: agent.model ?? undefined,
441
+ thinkingLevel,
421
442
  step,
422
443
  timeoutMs,
423
444
  };
@@ -437,10 +458,15 @@ async function runSingleAgent(
437
458
  const tmp = await writePromptToTempFile(agent.name, agent.systemPrompt);
438
459
  tmpPromptDir = tmp.dir;
439
460
  tmpPromptPath = tmp.filePath;
440
- args.push("--append-system-prompt", tmpPromptPath);
441
461
  }
442
462
 
443
- args.push(`Task: ${task}`);
463
+ const args = buildPiArgs({
464
+ model: agent.model,
465
+ thinkingLevel,
466
+ tools: agent.tools,
467
+ systemPromptPath: tmpPromptPath ?? undefined,
468
+ task,
469
+ });
444
470
  let wasAborted = false;
445
471
  let timedOut = false;
446
472
 
@@ -568,11 +594,16 @@ const TimeoutMs = Type.Number({
568
594
  minimum: 1,
569
595
  });
570
596
 
597
+ const ThinkingLevelSchema = StringEnum(THINKING_LEVELS, {
598
+ description: "Pi thinking level for the subagent process: off, minimal, low, medium, high, or xhigh.",
599
+ });
600
+
571
601
  const TaskItem = Type.Object({
572
602
  agent: Type.String({ description: "Name of the agent to invoke" }),
573
603
  task: Type.String({ description: "Task to delegate to the agent" }),
574
604
  cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
575
605
  timeoutMs: Type.Optional(TimeoutMs),
606
+ thinkingLevel: Type.Optional(ThinkingLevelSchema),
576
607
  });
577
608
 
578
609
  const ChainItem = Type.Object({
@@ -580,6 +611,7 @@ const ChainItem = Type.Object({
580
611
  task: Type.String({ description: "Task with optional {previous} placeholder for prior output" }),
581
612
  cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
582
613
  timeoutMs: Type.Optional(TimeoutMs),
614
+ thinkingLevel: Type.Optional(ThinkingLevelSchema),
583
615
  });
584
616
 
585
617
  const AggregatorItem = Type.Object({
@@ -587,6 +619,7 @@ const AggregatorItem = Type.Object({
587
619
  task: Type.String({ description: "Fan-in task. Use {previous} to include all parallel outputs." }),
588
620
  cwd: Type.Optional(Type.String({ description: "Working directory for the aggregator process" })),
589
621
  timeoutMs: Type.Optional(TimeoutMs),
622
+ thinkingLevel: Type.Optional(ThinkingLevelSchema),
590
623
  });
591
624
 
592
625
  const AgentScopeSchema = StringEnum(["user", "project", "both"] as const, {
@@ -606,6 +639,7 @@ const SubagentParams = Type.Object({
606
639
  ),
607
640
  cwd: Type.Optional(Type.String({ description: "Working directory for the agent process (single mode)" })),
608
641
  timeoutMs: Type.Optional(TimeoutMs),
642
+ thinkingLevel: Type.Optional(ThinkingLevelSchema),
609
643
  });
610
644
 
611
645
  // ---- Settings helpers ----
@@ -644,6 +678,12 @@ export function normalizeAgentSettings(value: unknown): SubagentAgentConfig | un
644
678
  hasKnownField = true;
645
679
  }
646
680
 
681
+ if (hasOwn(value, "thinkingLevel")) {
682
+ if (value.thinkingLevel !== null && !isThinkingLevel(value.thinkingLevel)) return undefined;
683
+ config.thinkingLevel = value.thinkingLevel;
684
+ hasKnownField = true;
685
+ }
686
+
647
687
  if (hasOwn(value, "timeoutMs")) {
648
688
  if (value.timeoutMs !== null && !isPositiveNumber(value.timeoutMs)) return undefined;
649
689
  config.timeoutMs = value.timeoutMs;
@@ -696,8 +736,22 @@ export function sameToolSet(left: string[], right: string[]): boolean {
696
736
  return [...leftSet].every((tool) => rightSet.has(tool));
697
737
  }
698
738
 
739
+ export function resolveSubagentThinkingLevel(
740
+ agents: readonly Pick<AgentConfig, "name" | "thinkingLevel">[],
741
+ agentName: string,
742
+ topLevelThinkingLevel?: SubagentThinkingLevel,
743
+ localThinkingLevel?: SubagentThinkingLevel,
744
+ ): SubagentThinkingLevel | undefined {
745
+ return localThinkingLevel ?? topLevelThinkingLevel ?? agents.find((agent) => agent.name === agentName)?.thinkingLevel;
746
+ }
747
+
699
748
  function hasAnyAgentOverride(config: SubagentAgentConfig): boolean {
700
- return hasOwn(config, "tools") || hasOwn(config, "model") || hasOwn(config, "timeoutMs");
749
+ return (
750
+ hasOwn(config, "tools") ||
751
+ hasOwn(config, "model") ||
752
+ hasOwn(config, "thinkingLevel") ||
753
+ hasOwn(config, "timeoutMs")
754
+ );
701
755
  }
702
756
 
703
757
  // ---- Tool toggle component ----
@@ -770,11 +824,14 @@ export default function (pi: ExtensionAPI) {
770
824
  'To enable project-local agents in .pi/agents, set agentScope: "both" (or "project").',
771
825
  ].join(" "),
772
826
  promptSnippet:
773
- "Delegate independent research, review, verification, or multi-step work to isolated Pi subagents.",
827
+ "Decide whether to spawn 0, 1, or multiple subagents for independent research, review, verification, or multi-step work in isolated Pi processes.",
774
828
  promptGuidelines: [
775
- "Use subagent for independent read-only research, broad codebase reconnaissance, high-volume command output, multi-domain parallel investigation, or an independent reviewer after implementation.",
776
- "Use subagent parallel mode when work splits into independent tasks; prefer read-only agents such as scout or reviewer for fan-out and serialize write-heavy implementation that touches the same files.",
777
- "Do not use subagent for simple answers, quick targeted edits, latency-sensitive one-step work, or tasks requiring frequent user back-and-forth.",
829
+ "Use subagent only when delegation fits; the main agent should decide how many subagents to spawn from task shape instead of waiting for the user to specify a count.",
830
+ "Use no subagent for simple answers, quick targeted edits, latency-sensitive one-step work, or tasks requiring frequent user back-and-forth.",
831
+ "Use one subagent for isolated research, broad command output, planning, or independent review/verification that benefits from a separate context.",
832
+ "Use subagent parallel mode with 2-4 parallel read-only subagents when work has broad independent branches; prefer scout or reviewer for fan-out and add an aggregator when synthesis helps.",
833
+ "Use more than 4 subagent tasks only when clearly justified by distinct independent branches, and stay within the existing hard max 8 parallel tasks.",
834
+ "Do not use subagent parallel mode for write-heavy implementation touching the same files or shared state; serialize those changes in the main agent or one worker.",
778
835
  'Do not use subagent with project-local agents unless the user explicitly wants project agents or sets agentScope to "project" or "both"; keep confirmation enabled for untrusted repositories.',
779
836
  "When using subagent, write self-contained tasks with file paths, context, expected output, and whether the subagent may edit files.",
780
837
  ],
@@ -791,6 +848,8 @@ export default function (pi: ExtensionAPI) {
791
848
  params.timeoutMs ??
792
849
  agents.find((agent) => agent.name === agentName)?.timeoutMs ??
793
850
  DEFAULT_TIMEOUT_MS;
851
+ const resolveThinkingLevel = (agentName: string, localThinkingLevel?: SubagentThinkingLevel) =>
852
+ resolveSubagentThinkingLevel(agents, agentName, params.thinkingLevel, localThinkingLevel);
794
853
 
795
854
  const hasChain = (params.chain?.length ?? 0) > 0;
796
855
  const hasTasks = (params.tasks?.length ?? 0) > 0;
@@ -884,6 +943,7 @@ export default function (pi: ExtensionAPI) {
884
943
  step.cwd,
885
944
  i + 1,
886
945
  signal,
946
+ resolveThinkingLevel(step.agent, step.thinkingLevel),
887
947
  resolveTimeoutMs(step.agent, step.timeoutMs),
888
948
  chainUpdate,
889
949
  makeDetails("chain"),
@@ -939,6 +999,7 @@ export default function (pi: ExtensionAPI) {
939
999
  messages: [],
940
1000
  stderr: "",
941
1001
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
1002
+ thinkingLevel: resolveThinkingLevel(params.tasks[i].agent, params.tasks[i].thinkingLevel),
942
1003
  finalOutput: "",
943
1004
  };
944
1005
  }
@@ -970,6 +1031,7 @@ export default function (pi: ExtensionAPI) {
970
1031
  t.cwd,
971
1032
  undefined,
972
1033
  signal,
1034
+ resolveThinkingLevel(t.agent, t.thinkingLevel),
973
1035
  resolveTimeoutMs(t.agent, t.timeoutMs),
974
1036
  // Per-task update callback
975
1037
  (partial) => {
@@ -1003,6 +1065,7 @@ export default function (pi: ExtensionAPI) {
1003
1065
  aggregator.cwd,
1004
1066
  undefined,
1005
1067
  signal,
1068
+ resolveThinkingLevel(aggregator.agent, aggregator.thinkingLevel),
1006
1069
  resolveTimeoutMs(aggregator.agent, aggregator.timeoutMs),
1007
1070
  (partial) => {
1008
1071
  status.update(fanInStatus(aggregator.agent));
@@ -1060,6 +1123,7 @@ export default function (pi: ExtensionAPI) {
1060
1123
  params.cwd,
1061
1124
  undefined,
1062
1125
  signal,
1126
+ resolveThinkingLevel(params.agent, params.thinkingLevel),
1063
1127
  resolveTimeoutMs(params.agent, params.timeoutMs),
1064
1128
  onUpdate,
1065
1129
  makeDetails("single"),
@@ -1203,7 +1267,7 @@ export default function (pi: ExtensionAPI) {
1203
1267
  container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
1204
1268
  }
1205
1269
  }
1206
- const usageStr = formatUsageStats(r.usage, r.model);
1270
+ const usageStr = formatUsageStats(r.usage, r.model, r.thinkingLevel);
1207
1271
  if (usageStr) {
1208
1272
  container.addChild(new Spacer(1));
1209
1273
  container.addChild(new Text(theme.fg("dim", usageStr), 0, 0));
@@ -1219,7 +1283,7 @@ export default function (pi: ExtensionAPI) {
1219
1283
  text += `\n${renderDisplayItems(displayItems, COLLAPSED_ITEM_COUNT)}`;
1220
1284
  if (displayItems.length > COLLAPSED_ITEM_COUNT) text += `\n${theme.fg("muted", "(Ctrl+O to expand)")}`;
1221
1285
  }
1222
- const usageStr = formatUsageStats(r.usage, r.model);
1286
+ const usageStr = formatUsageStats(r.usage, r.model, r.thinkingLevel);
1223
1287
  if (usageStr) text += `\n${theme.fg("dim", usageStr)}`;
1224
1288
  return new Text(text, 0, 0);
1225
1289
  }
@@ -1288,7 +1352,7 @@ export default function (pi: ExtensionAPI) {
1288
1352
  container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
1289
1353
  }
1290
1354
 
1291
- const stepUsage = formatUsageStats(r.usage, r.model);
1355
+ const stepUsage = formatUsageStats(r.usage, r.model, r.thinkingLevel);
1292
1356
  if (stepUsage) container.addChild(new Text(theme.fg("dim", stepUsage), 0, 0));
1293
1357
  }
1294
1358
 
@@ -1380,7 +1444,7 @@ export default function (pi: ExtensionAPI) {
1380
1444
  container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
1381
1445
  }
1382
1446
 
1383
- const taskUsage = formatUsageStats(r.usage, r.model);
1447
+ const taskUsage = formatUsageStats(r.usage, r.model, r.thinkingLevel);
1384
1448
  if (taskUsage) container.addChild(new Text(theme.fg("dim", taskUsage), 0, 0));
1385
1449
  }
1386
1450
 
@@ -1413,7 +1477,7 @@ export default function (pi: ExtensionAPI) {
1413
1477
  container.addChild(new Spacer(1));
1414
1478
  container.addChild(new Markdown(finalOutput.trim(), 0, 0, mdTheme));
1415
1479
  }
1416
- const fanInUsage = formatUsageStats(aggregator.usage, aggregator.model);
1480
+ const fanInUsage = formatUsageStats(aggregator.usage, aggregator.model, aggregator.thinkingLevel);
1417
1481
  if (fanInUsage) container.addChild(new Text(theme.fg("dim", fanInUsage), 0, 0));
1418
1482
  }
1419
1483