@ferris1225/pi-subagents 4.1.12 → 4.1.13

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.
Files changed (3) hide show
  1. package/README.md +6 -3
  2. package/package.json +55 -55
  3. package/src/setup.ts +109 -15
package/README.md CHANGED
@@ -203,7 +203,9 @@ Each agent runs on the current main model or one picked in `/subagents-setup`
203
203
  or fails at the provider level, the **same retained session** continues on the
204
204
  main model — finished searches, reads, and edits are preserved; ordinary task
205
205
  failures do not trigger a handoff. Thinking defaults to **Auto**: the role's
206
- preference, clamped to what the effective model supports. There is no separate
206
+ preference, clamped to what the effective model supports. `/subagents-setup`
207
+ *Configure an agent* also offers a manual strength per agent, listing only the
208
+ levels that model supports. There is no separate
207
209
  vision mode: assign a multimodal model and name the image paths in the task.
208
210
 
209
211
  Every dispatch, managed stage, resume, retry, and fallback snapshots the
@@ -216,8 +218,9 @@ stripped so children stay leaves. An empty snapshot starts the child with
216
218
 
217
219
  ## Configuration
218
220
 
219
- `/subagents-setup` stays one level deep: enabled agents, per-agent models, and
220
- the delegation-injection toggle. Everything else is config-file only, stored at
221
+ `/subagents-setup` stays one level deep: enabled agents, per-agent models and
222
+ thinking strengths, and the delegation-injection toggle. Everything else is
223
+ config-file only, stored at
221
224
  `~/.pi/agent/pi-subagents.json` (follows `PI_CODING_AGENT_DIR`):
222
225
 
223
226
  ```json
package/package.json CHANGED
@@ -1,55 +1,55 @@
1
- {
2
- "name": "@ferris1225/pi-subagents",
3
- "version": "4.1.12",
4
- "description": "A managed sub-agent team for pi: specialized roles, pre-commit documentation sync, retained threads, auto-fix chains, model fallback, and Git worktree isolation.",
5
- "type": "module",
6
- "license": "MIT",
7
- "publishConfig": {
8
- "access": "public"
9
- },
10
- "keywords": [
11
- "pi-package",
12
- "pi-extension",
13
- "subagent",
14
- "sub-agent",
15
- "delegation",
16
- "code-cleanup",
17
- "dead-code"
18
- ],
19
- "files": [
20
- "src",
21
- "agents",
22
- "README.md",
23
- "LICENSE"
24
- ],
25
- "pi": {
26
- "extensions": [
27
- "./src/index.ts"
28
- ]
29
- },
30
- "scripts": {
31
- "check": "tsc --noEmit",
32
- "test": "vitest run tests",
33
- "prepack": "npm run check && npm test"
34
- },
35
- "peerDependencies": {
36
- "@earendil-works/pi-agent-core": ">=0.83.0",
37
- "@earendil-works/pi-ai": ">=0.83.0",
38
- "@earendil-works/pi-coding-agent": ">=0.83.0",
39
- "@earendil-works/pi-tui": ">=0.83.0",
40
- "typebox": "*"
41
- },
42
- "devDependencies": {
43
- "@earendil-works/pi-agent-core": "^0.83.0",
44
- "@earendil-works/pi-ai": "^0.83.0",
45
- "@earendil-works/pi-coding-agent": "^0.83.0",
46
- "@earendil-works/pi-tui": "^0.83.0",
47
- "@types/node": "^22.10.0",
48
- "typebox": "^1.3.9",
49
- "typescript": "^5.9.0",
50
- "vitest": "^4.1.0"
51
- },
52
- "engines": {
53
- "node": ">=22.19.0"
54
- }
55
- }
1
+ {
2
+ "name": "@ferris1225/pi-subagents",
3
+ "version": "4.1.13",
4
+ "description": "A managed sub-agent team for pi: specialized roles, pre-commit documentation sync, retained threads, auto-fix chains, model fallback, and Git worktree isolation.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "keywords": [
11
+ "pi-package",
12
+ "pi-extension",
13
+ "subagent",
14
+ "sub-agent",
15
+ "delegation",
16
+ "code-cleanup",
17
+ "dead-code"
18
+ ],
19
+ "files": [
20
+ "src",
21
+ "agents",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "pi": {
26
+ "extensions": [
27
+ "./src/index.ts"
28
+ ]
29
+ },
30
+ "scripts": {
31
+ "check": "tsc --noEmit",
32
+ "test": "vitest run tests",
33
+ "prepack": "npm run check && npm test"
34
+ },
35
+ "peerDependencies": {
36
+ "@earendil-works/pi-agent-core": ">=0.83.0",
37
+ "@earendil-works/pi-ai": ">=0.83.0",
38
+ "@earendil-works/pi-coding-agent": ">=0.83.0",
39
+ "@earendil-works/pi-tui": ">=0.83.0",
40
+ "typebox": "*"
41
+ },
42
+ "devDependencies": {
43
+ "@earendil-works/pi-agent-core": "^0.83.0",
44
+ "@earendil-works/pi-ai": "^0.83.0",
45
+ "@earendil-works/pi-coding-agent": "^0.83.0",
46
+ "@earendil-works/pi-tui": "^0.83.0",
47
+ "@types/node": "^22.10.0",
48
+ "typebox": "^1.3.9",
49
+ "typescript": "^5.9.0",
50
+ "vitest": "^4.1.0"
51
+ },
52
+ "engines": {
53
+ "node": ">=22.19.0"
54
+ }
55
+ }
package/src/setup.ts CHANGED
@@ -2,20 +2,24 @@
2
2
  * Interactive configuration wizard for /subagents-setup.
3
3
  *
4
4
  * The wizard stays one level deep and exposes only what most users touch:
5
- * which agents run, the model each runs on, and the delegation directive
6
- * toggle. Everything else (per-agent thinking, agent scope, idle timeout,
5
+ * which agents run, the model and thinking strength each runs on, and the
6
+ * delegation directive toggle. Everything else (agent scope, idle timeout,
7
7
  * result lines, notifications) is config-file-only; model failures hand
8
8
  * directly to the current main model, and thinking defaults to capability-
9
9
  * aware Auto.
10
10
  */
11
11
 
12
12
  import { stat } from "node:fs/promises";
13
+ import type { Api, Model } from "@earendil-works/pi-ai";
13
14
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
15
+ import { discoverAgents } from "./agents.ts";
14
16
  import {
15
17
  BUILTIN_AGENT_NAMES,
16
18
  DEFAULT_CONFIG,
17
19
  DEFAULT_ENABLED_AGENTS,
20
+ DEFAULT_THINKING_LEVEL,
18
21
  type SubagentsConfig,
22
+ type ThinkingLevel,
19
23
  errorMessage,
20
24
  getConfigPath,
21
25
  loadConfig,
@@ -27,7 +31,10 @@ import {
27
31
  availableModelsInScope,
28
32
  buildModelPickerItems,
29
33
  currentModelRef,
34
+ findModelByRef,
30
35
  modelRef,
36
+ resolveThinkingLevel,
37
+ supportedThinkingLevels,
31
38
  } from "./models.ts";
32
39
  import { promptSelectMany, promptSelectOne } from "./ui.ts";
33
40
 
@@ -98,6 +105,76 @@ async function pickAgentModel(
98
105
  return pickConfiguredModel(ctx, `Model for "${agentName}"?`, currentRef, escNote);
99
106
  }
100
107
 
108
+ const AUTO_THINKING = "__auto_thinking__";
109
+
110
+ function actualAgentThinkingDefault(
111
+ ctx: ExtensionCommandContext,
112
+ config: SubagentsConfig,
113
+ agentName: string,
114
+ ): ThinkingLevel {
115
+ const { agents } = discoverAgents(ctx.cwd, {
116
+ scope: config.agentScope,
117
+ enabledNames: config.enabledAgents,
118
+ projectTrusted: ctx.isProjectTrusted(),
119
+ });
120
+ return agents.find((agent) => agent.name === agentName)?.thinking ?? DEFAULT_THINKING_LEVEL;
121
+ }
122
+
123
+ const THINKING_LEVEL_HINTS: Record<ThinkingLevel, string> = {
124
+ off: "no reasoning tokens",
125
+ minimal: "minimal reasoning",
126
+ low: "light reasoning",
127
+ medium: "balanced reasoning",
128
+ high: "deep reasoning",
129
+ xhigh: "extra-deep reasoning",
130
+ max: "strongest reasoning",
131
+ };
132
+
133
+ function effectiveModelForChoice(
134
+ ctx: ExtensionCommandContext,
135
+ choice: string,
136
+ ): Model<Api> | undefined {
137
+ if (choice === CURRENT_MAIN_MODEL) return ctx.model;
138
+ return findModelByRef(availableModelsInScope(ctx), choice);
139
+ }
140
+
141
+ /** Auto is the default. Manual rows are exactly the levels Pi exposes for the
142
+ * selected model; unsupported xhigh/max entries never appear. */
143
+ async function pickAgentStrength(
144
+ ctx: ExtensionCommandContext,
145
+ agentName: string,
146
+ model: Model<Api> | undefined,
147
+ current: ThinkingLevel | undefined,
148
+ agentDefault: ThinkingLevel,
149
+ escNote = "cancels this setup pass",
150
+ ): Promise<ThinkingLevel | typeof AUTO_THINKING | undefined> {
151
+ const supported = supportedThinkingLevels(model);
152
+ const automatic = resolveThinkingLevel(model, agentDefault);
153
+ // No model metadata, or a non-reasoning model whose only valid value is off:
154
+ // Auto is already the complete and least surprising choice.
155
+ if (supported.length <= 1) return AUTO_THINKING;
156
+
157
+ const currentEffective = current ? resolveThinkingLevel(model, current) : undefined;
158
+ const modelName = model ? modelRef(model) : "current main model";
159
+ const options = [
160
+ {
161
+ value: AUTO_THINKING,
162
+ label: `auto — ${automatic} for ${modelName}${current === undefined ? " (current, recommended)" : " (recommended)"}`,
163
+ },
164
+ ...supported.map((level) => ({
165
+ value: level,
166
+ label: `${level} — ${THINKING_LEVEL_HINTS[level]}${current !== undefined && currentEffective === level ? " (current)" : ""}`,
167
+ })),
168
+ ];
169
+ return promptSelectOne(
170
+ ctx,
171
+ `Thinking for "${agentName}"?`,
172
+ `Only levels supported by ${modelName} are shown • Enter selects • Esc ${escNote}`,
173
+ options,
174
+ current === undefined ? AUTO_THINKING : currentEffective,
175
+ ) as Promise<ThinkingLevel | typeof AUTO_THINKING | undefined>;
176
+ }
177
+
101
178
  async function pickAgentToConfigure(
102
179
  ctx: ExtensionCommandContext,
103
180
  enabledAgents: readonly string[],
@@ -117,10 +194,11 @@ async function pickAgentToConfigure(
117
194
  interface ConfiguredAgentChoice {
118
195
  name: string;
119
196
  model: string;
197
+ strength: ThinkingLevel | typeof AUTO_THINKING;
120
198
  }
121
199
 
122
- /** Configure agents while preserving the UI back stack: model selection returns
123
- * to the agent picker on Esc; agent-picker Esc ends this configuration pass. */
200
+ /** Configure one agent while preserving the UI back stack: thinking → model
201
+ * agent selection. Esc from agent selection ends this configuration pass. */
124
202
  async function configureOneAgent(
125
203
  ctx: ExtensionCommandContext,
126
204
  config: SubagentsConfig,
@@ -128,14 +206,27 @@ async function configureOneAgent(
128
206
  while (true) {
129
207
  const name = await pickAgentToConfigure(ctx, config.enabledAgents);
130
208
  if (name === undefined) return undefined;
131
- const model = await pickAgentModel(
132
- ctx,
133
- name,
134
- config.agentModels[name],
135
- "returns to agent selection",
136
- );
137
- if (model === undefined) continue;
138
- return { name, model };
209
+
210
+ while (true) {
211
+ const modelChoice = await pickAgentModel(
212
+ ctx,
213
+ name,
214
+ config.agentModels[name],
215
+ "returns to agent selection",
216
+ );
217
+ if (modelChoice === undefined) break;
218
+ const model = effectiveModelForChoice(ctx, modelChoice);
219
+ const strength = await pickAgentStrength(
220
+ ctx,
221
+ name,
222
+ model,
223
+ config.agentThinkingLevels[name],
224
+ actualAgentThinkingDefault(ctx, config, name),
225
+ "returns to model selection",
226
+ );
227
+ if (strength === undefined) continue;
228
+ return { name, model: modelChoice, strength };
229
+ }
139
230
  }
140
231
  }
141
232
 
@@ -186,7 +277,7 @@ async function runMenu(ctx: ExtensionCommandContext, configPath: string, config:
186
277
  while (true) {
187
278
  const choice = await ctx.ui.select("pi-subagents settings", [
188
279
  "Enable/disable agents",
189
- "Configure agent models",
280
+ "Configure an agent (model + thinking)",
190
281
  "Proactive injection",
191
282
  "Full re-setup",
192
283
  ]);
@@ -230,14 +321,17 @@ async function runMenu(ctx: ExtensionCommandContext, configPath: string, config:
230
321
  next.agentModels = keepAgentEntries(next.agentModels, enabled);
231
322
  next.agentThinkingLevels = keepAgentEntries(next.agentThinkingLevels, enabled);
232
323
  } else if (choice.startsWith("Configure")) {
233
- // Per-agent loop: model Esc returns to the agent picker; agent-picker
234
- // Esc saves completed choices and returns to this settings menu.
324
+ // Per-agent loop: thinking Esc returns to that agent's model picker;
325
+ // model Esc returns to the agent picker; agent-picker Esc saves completed
326
+ // choices and returns to this settings menu.
235
327
  let configuredAny = false;
236
328
  while (true) {
237
329
  const picked = await configureOneAgent(ctx, next);
238
330
  if (!picked) break;
239
331
  configuredAny = true;
240
332
  next.agentModels = applyAgentModelChoice(next.agentModels, picked.name, picked.model);
333
+ if (picked.strength === AUTO_THINKING) delete next.agentThinkingLevels[picked.name];
334
+ else next.agentThinkingLevels[picked.name] = picked.strength;
241
335
  }
242
336
  if (!configuredAny) continue;
243
337
  await saveConfig(next, configPath);