@ferris1225/pi-subagents 4.2.13 → 4.3.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/CHANGELOG.md +15 -0
- package/README.md +63 -57
- package/agents/{executor.md → artisan.md} +5 -12
- package/agents/{explorer.md → scout.md} +2 -3
- package/agents/steward.md +51 -0
- package/package.json +4 -3
- package/src/agents.ts +3 -10
- package/src/announcements.ts +12 -5
- package/src/config.ts +161 -27
- package/src/dispatch.ts +5 -16
- package/src/index.ts +1 -1
- package/src/monitor.ts +2 -2
- package/src/prompt.ts +13 -7
- package/src/setup.ts +121 -101
- package/src/thread-lifecycle.ts +8 -20
package/src/setup.ts
CHANGED
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Interactive configuration wizard for /subagents-setup.
|
|
3
3
|
*
|
|
4
|
-
* The wizard stays one level deep
|
|
5
|
-
*
|
|
6
|
-
* Everything else (agent scope, idle timeout, result
|
|
7
|
-
* config-file-only
|
|
8
|
-
* and thinking defaults to capability-aware Auto.
|
|
4
|
+
* The wizard stays one level deep: which agents run, then a model and an
|
|
5
|
+
* optional thinking override per agent. Role thinking defaults apply until
|
|
6
|
+
* the user picks a level. Everything else (agent scope, idle timeout, result
|
|
7
|
+
* lines) is config-file-only.
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
import { stat } from "node:fs/promises";
|
|
12
11
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
13
12
|
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
14
|
-
import { discoverAgents } from "./agents.ts";
|
|
15
13
|
import {
|
|
14
|
+
AGENT_PROFILES,
|
|
16
15
|
BUILTIN_AGENT_NAMES,
|
|
17
16
|
DEFAULT_CONFIG,
|
|
18
17
|
DEFAULT_ENABLED_AGENTS,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
type ThinkingLevel,
|
|
18
|
+
REQUIRED_ENABLED_AGENTS,
|
|
19
|
+
agentProfile,
|
|
22
20
|
errorMessage,
|
|
23
21
|
getConfigPath,
|
|
24
22
|
loadConfig,
|
|
23
|
+
roleThinkingLevel,
|
|
25
24
|
saveConfig,
|
|
25
|
+
withRequiredAgents,
|
|
26
|
+
type SubagentsConfig,
|
|
27
|
+
type ThinkingLevel,
|
|
26
28
|
} from "./config.ts";
|
|
27
29
|
import {
|
|
28
30
|
CURRENT_MAIN_MODEL,
|
|
@@ -37,15 +39,31 @@ import {
|
|
|
37
39
|
} from "./models.ts";
|
|
38
40
|
import { promptSelectMany, promptSelectOne } from "./ui.ts";
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
const THINKING_LEVEL_HINTS: Record<ThinkingLevel, string> = {
|
|
43
|
+
off: "no reasoning tokens",
|
|
44
|
+
minimal: "minimal reasoning",
|
|
45
|
+
low: "light reasoning",
|
|
46
|
+
medium: "balanced reasoning",
|
|
47
|
+
high: "deep reasoning",
|
|
48
|
+
xhigh: "extra-deep reasoning",
|
|
49
|
+
max: "strongest reasoning",
|
|
44
50
|
};
|
|
45
51
|
|
|
52
|
+
function agentPickerItems(): Array<{ value: string; label: string; description: string }> {
|
|
53
|
+
return BUILTIN_AGENT_NAMES.map((name) => {
|
|
54
|
+
const profile = AGENT_PROFILES[name];
|
|
55
|
+
const required = (REQUIRED_ENABLED_AGENTS as readonly string[]).includes(name);
|
|
56
|
+
return {
|
|
57
|
+
value: name,
|
|
58
|
+
label: required ? `${name} (always on)` : name,
|
|
59
|
+
description: `${profile.summary} — ${profile.remark}`,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
46
64
|
function moduleLabel(name: string): string {
|
|
47
|
-
const
|
|
48
|
-
return
|
|
65
|
+
const profile = agentProfile(name);
|
|
66
|
+
return profile ? `${name} — ${profile.summary}` : name;
|
|
49
67
|
}
|
|
50
68
|
|
|
51
69
|
async function configExists(configPath: string): Promise<boolean> {
|
|
@@ -61,14 +79,23 @@ async function pickEnabledAgents(
|
|
|
61
79
|
ctx: ExtensionCommandContext,
|
|
62
80
|
current: readonly string[],
|
|
63
81
|
): Promise<string[] | undefined> {
|
|
64
|
-
const
|
|
65
|
-
return promptSelectMany(
|
|
82
|
+
const picked = await promptSelectMany(
|
|
66
83
|
ctx,
|
|
67
|
-
"
|
|
68
|
-
"Space toggles • Enter confirms • Esc
|
|
69
|
-
|
|
84
|
+
"Which agents should run?",
|
|
85
|
+
"Each line is a role and its job. All three stay on. Space toggles • Enter confirms • Esc back",
|
|
86
|
+
agentPickerItems(),
|
|
70
87
|
current,
|
|
71
88
|
);
|
|
89
|
+
if (picked === undefined) return undefined;
|
|
90
|
+
const enabled = withRequiredAgents(picked);
|
|
91
|
+
const forced = REQUIRED_ENABLED_AGENTS.filter((name) => !picked.includes(name));
|
|
92
|
+
if (forced.length > 0) {
|
|
93
|
+
ctx.ui.notify(
|
|
94
|
+
`pi-subagents: ${forced.join(", ")} stay enabled — the shipped team stays on.`,
|
|
95
|
+
"info",
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return enabled;
|
|
72
99
|
}
|
|
73
100
|
|
|
74
101
|
async function pickConfiguredModel(
|
|
@@ -86,7 +113,7 @@ async function pickConfiguredModel(
|
|
|
86
113
|
return promptSelectOne(
|
|
87
114
|
ctx,
|
|
88
115
|
title,
|
|
89
|
-
`Type to filter by provider, model,
|
|
116
|
+
`Type to filter by provider, model, or capability • ↑/↓ • Enter selects • Esc ${escNote}`,
|
|
90
117
|
items,
|
|
91
118
|
configuredRef ?? CURRENT_MAIN_MODEL,
|
|
92
119
|
);
|
|
@@ -98,34 +125,11 @@ async function pickAgentModel(
|
|
|
98
125
|
currentRef: string | undefined,
|
|
99
126
|
escNote = "cancels this setup pass",
|
|
100
127
|
): Promise<string | undefined> {
|
|
101
|
-
|
|
128
|
+
const profile = agentProfile(agentName);
|
|
129
|
+
const duty = profile ? ` — ${profile.summary}` : "";
|
|
130
|
+
return pickConfiguredModel(ctx, `Model for ${agentName}${duty}?`, currentRef, escNote);
|
|
102
131
|
}
|
|
103
132
|
|
|
104
|
-
const AUTO_THINKING = "__auto_thinking__";
|
|
105
|
-
|
|
106
|
-
function actualAgentThinkingDefault(
|
|
107
|
-
ctx: ExtensionCommandContext,
|
|
108
|
-
config: SubagentsConfig,
|
|
109
|
-
agentName: string,
|
|
110
|
-
): ThinkingLevel {
|
|
111
|
-
const { agents } = discoverAgents(ctx.cwd, {
|
|
112
|
-
scope: config.agentScope,
|
|
113
|
-
enabledNames: config.enabledAgents,
|
|
114
|
-
projectTrusted: ctx.isProjectTrusted(),
|
|
115
|
-
});
|
|
116
|
-
return agents.find((agent) => agent.name === agentName)?.thinking ?? DEFAULT_THINKING_LEVEL;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const THINKING_LEVEL_HINTS: Record<ThinkingLevel, string> = {
|
|
120
|
-
off: "no reasoning tokens",
|
|
121
|
-
minimal: "minimal reasoning",
|
|
122
|
-
low: "light reasoning",
|
|
123
|
-
medium: "balanced reasoning",
|
|
124
|
-
high: "deep reasoning",
|
|
125
|
-
xhigh: "extra-deep reasoning",
|
|
126
|
-
max: "strongest reasoning",
|
|
127
|
-
};
|
|
128
|
-
|
|
129
133
|
function effectiveModelForChoice(
|
|
130
134
|
ctx: ExtensionCommandContext,
|
|
131
135
|
choice: string,
|
|
@@ -134,41 +138,37 @@ function effectiveModelForChoice(
|
|
|
134
138
|
return findModelByRef(availableModelsInScope(ctx), choice);
|
|
135
139
|
}
|
|
136
140
|
|
|
137
|
-
/**
|
|
138
|
-
* selected model; unsupported xhigh/max entries never appear. */
|
|
141
|
+
/** Role default is the first row. Picking it clears a stored override. */
|
|
139
142
|
async function pickAgentStrength(
|
|
140
143
|
ctx: ExtensionCommandContext,
|
|
141
144
|
agentName: string,
|
|
142
145
|
model: Model<Api> | undefined,
|
|
143
146
|
current: ThinkingLevel | undefined,
|
|
144
|
-
agentDefault: ThinkingLevel,
|
|
145
147
|
escNote = "cancels this setup pass",
|
|
146
|
-
): Promise<ThinkingLevel |
|
|
148
|
+
): Promise<ThinkingLevel | undefined> {
|
|
147
149
|
const supported = supportedThinkingLevels(model);
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
// Auto is already the complete and least surprising choice.
|
|
151
|
-
if (supported.length <= 1) return AUTO_THINKING;
|
|
150
|
+
const roleDefault = resolveThinkingLevel(model, roleThinkingLevel(agentName));
|
|
151
|
+
if (supported.length <= 1) return roleDefault;
|
|
152
152
|
|
|
153
|
-
const currentEffective = current ? resolveThinkingLevel(model, current) :
|
|
153
|
+
const currentEffective = current ? resolveThinkingLevel(model, current) : roleDefault;
|
|
154
154
|
const modelName = model ? modelRef(model) : "current main model";
|
|
155
|
-
const options =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
const options = supported.map((level) => {
|
|
156
|
+
const tags = [
|
|
157
|
+
level === roleDefault ? "role default" : "",
|
|
158
|
+
current !== undefined && currentEffective === level ? "current" : "",
|
|
159
|
+
].filter(Boolean);
|
|
160
|
+
return {
|
|
161
161
|
value: level,
|
|
162
|
-
label: `${level} — ${THINKING_LEVEL_HINTS[level]}${
|
|
163
|
-
}
|
|
164
|
-
|
|
162
|
+
label: `${level} — ${THINKING_LEVEL_HINTS[level]}${tags.length ? ` (${tags.join(", ")})` : ""}`,
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
165
|
return promptSelectOne(
|
|
166
166
|
ctx,
|
|
167
|
-
`Thinking for
|
|
168
|
-
|
|
167
|
+
`Thinking for ${agentName}?`,
|
|
168
|
+
`${agentName} defaults to ${roleDefault} on ${modelName} • Enter selects • Esc ${escNote}`,
|
|
169
169
|
options,
|
|
170
|
-
|
|
171
|
-
) as Promise<ThinkingLevel |
|
|
170
|
+
currentEffective,
|
|
171
|
+
) as Promise<ThinkingLevel | undefined>;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
async function pickAgentToConfigure(
|
|
@@ -182,19 +182,24 @@ async function pickAgentToConfigure(
|
|
|
182
182
|
return promptSelectOne(
|
|
183
183
|
ctx,
|
|
184
184
|
"Configure which agent?",
|
|
185
|
-
"
|
|
186
|
-
enabledAgents.map((name) =>
|
|
185
|
+
"Name, then what it owns • ↑/↓ • Enter selects • Esc returns to settings",
|
|
186
|
+
enabledAgents.map((name) => {
|
|
187
|
+
const profile = agentProfile(name);
|
|
188
|
+
return {
|
|
189
|
+
value: name,
|
|
190
|
+
label: moduleLabel(name),
|
|
191
|
+
description: profile?.remark,
|
|
192
|
+
};
|
|
193
|
+
}),
|
|
187
194
|
);
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
interface ConfiguredAgentChoice {
|
|
191
198
|
name: string;
|
|
192
199
|
model: string;
|
|
193
|
-
strength: ThinkingLevel
|
|
200
|
+
strength: ThinkingLevel;
|
|
194
201
|
}
|
|
195
202
|
|
|
196
|
-
/** Configure one agent while preserving the UI back stack: thinking → model →
|
|
197
|
-
* agent selection. Esc from agent selection ends this configuration pass. */
|
|
198
203
|
async function configureOneAgent(
|
|
199
204
|
ctx: ExtensionCommandContext,
|
|
200
205
|
config: SubagentsConfig,
|
|
@@ -202,6 +207,8 @@ async function configureOneAgent(
|
|
|
202
207
|
while (true) {
|
|
203
208
|
const name = await pickAgentToConfigure(ctx, config.enabledAgents);
|
|
204
209
|
if (name === undefined) return undefined;
|
|
210
|
+
const profile = agentProfile(name);
|
|
211
|
+
if (profile) ctx.ui.notify(`${name}: ${profile.remark}`, "info");
|
|
205
212
|
|
|
206
213
|
while (true) {
|
|
207
214
|
const modelChoice = await pickAgentModel(
|
|
@@ -217,7 +224,6 @@ async function configureOneAgent(
|
|
|
217
224
|
name,
|
|
218
225
|
model,
|
|
219
226
|
config.agentThinkingLevels[name],
|
|
220
|
-
actualAgentThinkingDefault(ctx, config, name),
|
|
221
227
|
"returns to model selection",
|
|
222
228
|
);
|
|
223
229
|
if (strength === undefined) continue;
|
|
@@ -231,12 +237,43 @@ function keepAgentEntries<T>(record: Record<string, T>, enabled: readonly string
|
|
|
231
237
|
return Object.fromEntries(Object.entries(record).filter(([name]) => keep.has(name)));
|
|
232
238
|
}
|
|
233
239
|
|
|
240
|
+
function applyThinkingChoice(
|
|
241
|
+
levels: Record<string, ThinkingLevel>,
|
|
242
|
+
agentName: string,
|
|
243
|
+
strength: ThinkingLevel,
|
|
244
|
+
): Record<string, ThinkingLevel> {
|
|
245
|
+
const next = { ...levels };
|
|
246
|
+
if (strength === roleThinkingLevel(agentName)) delete next[agentName];
|
|
247
|
+
else next[agentName] = strength;
|
|
248
|
+
return next;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function introduceSetup(ctx: ExtensionCommandContext): Promise<boolean> {
|
|
252
|
+
const lines = BUILTIN_AGENT_NAMES.map((name) => {
|
|
253
|
+
const profile = AGENT_PROFILES[name];
|
|
254
|
+
const required = (REQUIRED_ENABLED_AGENTS as readonly string[]).includes(name) ? " · always on" : "";
|
|
255
|
+
return `${name} — ${profile.summary}${required}. ${profile.remark}`;
|
|
256
|
+
});
|
|
257
|
+
ctx.ui.notify(
|
|
258
|
+
`pi-subagents: ${lines.join(" ")} Pick a model for each role next. Thinking defaults per role (scout low, artisan high, steward medium); change it on a role when you want.`,
|
|
259
|
+
"info",
|
|
260
|
+
);
|
|
261
|
+
const choice = await ctx.ui.select("How to configure pi-subagents", [
|
|
262
|
+
"Continue — pick a model for each role (thinking has a role default you can change later)",
|
|
263
|
+
]);
|
|
264
|
+
return choice !== undefined;
|
|
265
|
+
}
|
|
266
|
+
|
|
234
267
|
async function runFullSetup(ctx: ExtensionCommandContext, configPath: string, base: SubagentsConfig): Promise<boolean> {
|
|
268
|
+
if (!(await introduceSetup(ctx))) return false;
|
|
269
|
+
|
|
235
270
|
const enabled = await pickEnabledAgents(ctx, base.enabledAgents);
|
|
236
271
|
if (enabled === undefined) return false;
|
|
237
272
|
|
|
238
273
|
let agentModels = keepAgentEntries(base.agentModels, enabled);
|
|
239
274
|
for (const agentName of enabled) {
|
|
275
|
+
const profile = agentProfile(agentName);
|
|
276
|
+
if (profile) ctx.ui.notify(`${agentName}: ${profile.remark}`, "info");
|
|
240
277
|
const choice = await pickAgentModel(ctx, agentName, agentModels[agentName]);
|
|
241
278
|
if (choice === undefined) return false;
|
|
242
279
|
agentModels = applyAgentModelChoice(agentModels, agentName, choice);
|
|
@@ -244,27 +281,27 @@ async function runFullSetup(ctx: ExtensionCommandContext, configPath: string, ba
|
|
|
244
281
|
|
|
245
282
|
const next: SubagentsConfig = {
|
|
246
283
|
enabledAgents: enabled,
|
|
247
|
-
// The wizard surfaces every built-in, so an untoggled one was seen and
|
|
248
|
-
// deliberately left off — record them all as known.
|
|
249
284
|
knownAgents: [...BUILTIN_AGENT_NAMES],
|
|
250
285
|
agentModels,
|
|
251
|
-
|
|
252
|
-
agentThinkingLevels: {},
|
|
286
|
+
agentThinkingLevels: keepAgentEntries(base.agentThinkingLevels, enabled),
|
|
253
287
|
maxResultLines: base.maxResultLines,
|
|
254
288
|
agentScope: base.agentScope,
|
|
255
289
|
idleTimeoutSec: base.idleTimeoutSec,
|
|
256
290
|
};
|
|
257
291
|
await saveConfig(next, configPath);
|
|
258
|
-
ctx.ui.notify(
|
|
292
|
+
ctx.ui.notify(
|
|
293
|
+
`pi-subagents saved to ${configPath}. Role thinking defaults apply; open Configure an agent to change one.`,
|
|
294
|
+
"info",
|
|
295
|
+
);
|
|
259
296
|
return true;
|
|
260
297
|
}
|
|
261
298
|
|
|
262
299
|
async function runMenu(ctx: ExtensionCommandContext, configPath: string, config: SubagentsConfig): Promise<void> {
|
|
263
300
|
while (true) {
|
|
264
301
|
const choice = await ctx.ui.select("pi-subagents settings", [
|
|
265
|
-
"Enable/disable agents",
|
|
266
|
-
"Configure an agent
|
|
267
|
-
"Full re-setup",
|
|
302
|
+
"Enable/disable agents — scout, artisan, and steward stay on",
|
|
303
|
+
"Configure an agent — model and thinking, with its job on the row",
|
|
304
|
+
"Full re-setup — walk through the team and pick models again",
|
|
268
305
|
]);
|
|
269
306
|
if (choice === undefined) return;
|
|
270
307
|
if (choice.startsWith("Full")) {
|
|
@@ -281,33 +318,16 @@ async function runMenu(ctx: ExtensionCommandContext, configPath: string, config:
|
|
|
281
318
|
const enabled = await pickEnabledAgents(ctx, config.enabledAgents);
|
|
282
319
|
if (enabled === undefined) continue;
|
|
283
320
|
next.enabledAgents = enabled;
|
|
284
|
-
// A newly enabled role inherits explorer's configured model and
|
|
285
|
-
// thinking level, so the file reflects what it will actually run
|
|
286
|
-
// instead of silently falling back to the current main model: these
|
|
287
|
-
// roles do light migration-grade work on the fast explorer lane.
|
|
288
|
-
for (const agent of enabled) {
|
|
289
|
-
if (agent === "explorer" || config.enabledAgents.includes(agent)) continue;
|
|
290
|
-
if (!next.agentModels[agent] && config.agentModels.explorer) {
|
|
291
|
-
next.agentModels[agent] = config.agentModels.explorer;
|
|
292
|
-
}
|
|
293
|
-
if (!next.agentThinkingLevels[agent] && config.agentThinkingLevels.explorer) {
|
|
294
|
-
next.agentThinkingLevels[agent] = config.agentThinkingLevels.explorer;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
321
|
next.agentModels = keepAgentEntries(next.agentModels, enabled);
|
|
298
322
|
next.agentThinkingLevels = keepAgentEntries(next.agentThinkingLevels, enabled);
|
|
299
323
|
} else {
|
|
300
|
-
// Per-agent loop: thinking Esc returns to that agent's model picker;
|
|
301
|
-
// model Esc returns to the agent picker; agent-picker Esc saves completed
|
|
302
|
-
// choices and returns to this settings menu.
|
|
303
324
|
let configuredAny = false;
|
|
304
325
|
while (true) {
|
|
305
326
|
const picked = await configureOneAgent(ctx, next);
|
|
306
327
|
if (!picked) break;
|
|
307
328
|
configuredAny = true;
|
|
308
329
|
next.agentModels = applyAgentModelChoice(next.agentModels, picked.name, picked.model);
|
|
309
|
-
|
|
310
|
-
else next.agentThinkingLevels[picked.name] = picked.strength;
|
|
330
|
+
next.agentThinkingLevels = applyThinkingChoice(next.agentThinkingLevels, picked.name, picked.strength);
|
|
311
331
|
}
|
|
312
332
|
if (!configuredAny) continue;
|
|
313
333
|
await saveConfig(next, configPath);
|
package/src/thread-lifecycle.ts
CHANGED
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
} from "./agents.ts";
|
|
21
21
|
import { type CompletionMessageItem } from "./completion.ts";
|
|
22
22
|
import {
|
|
23
|
-
DEFAULT_THINKING_LEVEL,
|
|
24
23
|
loadConfig,
|
|
24
|
+
roleThinkingLevel,
|
|
25
25
|
type SubagentsConfig,
|
|
26
26
|
type ThinkingLevel,
|
|
27
27
|
} from "./config.ts";
|
|
@@ -265,11 +265,8 @@ export interface ResumeReservation {
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
/** The dispatcher's full internal entry point; the public tool surface only
|
|
268
|
-
* uses the first four parameters
|
|
268
|
+
* uses the first four parameters. */
|
|
269
269
|
export interface StartBackgroundOptions {
|
|
270
|
-
/** Reasoning strength this dispatch asked for; the user's manual
|
|
271
|
-
* `/subagents-setup` choice still outranks it (see resolveDispatchModelRoute). */
|
|
272
|
-
thinking?: ThinkingLevel;
|
|
273
270
|
/** Resume path only: the thread whose retained context continues. */
|
|
274
271
|
existingThread?: SubagentThread;
|
|
275
272
|
appendedObjectiveOnResume?: boolean;
|
|
@@ -307,7 +304,6 @@ export function resolveDispatchModelRoute(
|
|
|
307
304
|
agent: AgentConfig,
|
|
308
305
|
config: SubagentsConfig,
|
|
309
306
|
ctx: ExtensionContext,
|
|
310
|
-
requestedThinking?: ThinkingLevel,
|
|
311
307
|
): DispatchModelRoute {
|
|
312
308
|
const availableModels = availableModelsInScope(ctx);
|
|
313
309
|
const mainRef = currentModelRef(ctx);
|
|
@@ -316,11 +312,10 @@ export function resolveDispatchModelRoute(
|
|
|
316
312
|
mainRef,
|
|
317
313
|
availableRefs: availableModels.map(modelRef),
|
|
318
314
|
});
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
// dispatching model's per-call guess, which in turn outranks frontmatter.
|
|
315
|
+
// A `/subagents-setup` override wins; otherwise the role default. No
|
|
316
|
+
// per-call or frontmatter thinking.
|
|
322
317
|
const preferred =
|
|
323
|
-
config.agentThinkingLevels[agent.name] ??
|
|
318
|
+
config.agentThinkingLevels[agent.name] ?? roleThinkingLevel(agent.name);
|
|
324
319
|
const thinkingLevelForModel = (ref?: string): ThinkingLevel => {
|
|
325
320
|
const model = ref === mainRef && ctx.model
|
|
326
321
|
? ctx.model
|
|
@@ -372,7 +367,6 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
|
|
|
372
367
|
startOptions: StartBackgroundOptions = {},
|
|
373
368
|
): Promise<SingleResult> => {
|
|
374
369
|
const {
|
|
375
|
-
thinking,
|
|
376
370
|
existingThread,
|
|
377
371
|
appendedObjectiveOnResume = false,
|
|
378
372
|
environment,
|
|
@@ -396,7 +390,7 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
|
|
|
396
390
|
const agent = resolveLiveAgentTools(discoveredAgent);
|
|
397
391
|
if (isolation === "worktree" && !isWorktreeCapableAgent(agent)) {
|
|
398
392
|
return {
|
|
399
|
-
...failedStartResult(agentName, task, `Agent "${agentName}" is read-only; worktree isolation is available only to write-capable agents such as
|
|
393
|
+
...failedStartResult(agentName, task, `Agent "${agentName}" is read-only; worktree isolation is available only to write-capable agents such as artisan.`),
|
|
400
394
|
isolation,
|
|
401
395
|
};
|
|
402
396
|
}
|
|
@@ -431,8 +425,7 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
|
|
|
431
425
|
const worktreeGroup = worktree ? worktreeGroupId(worktree) : undefined;
|
|
432
426
|
// A resume re-runs at the strength its dispatch asked for, so the retained
|
|
433
427
|
// request survives generations (and, via the durable record, restarts).
|
|
434
|
-
const
|
|
435
|
-
const resolvedRoute = resolveDispatchModelRoute(agent, runConfig, runCtx, requestedThinking);
|
|
428
|
+
const resolvedRoute = resolveDispatchModelRoute(agent, runConfig, runCtx);
|
|
436
429
|
// Isolation is a persistent system-level invariant, not a one-shot task
|
|
437
430
|
// prefix: resumes and main-model
|
|
438
431
|
// handoffs all keep the same worktree boundary.
|
|
@@ -493,7 +486,6 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
|
|
|
493
486
|
thread.cwd = originalCwd;
|
|
494
487
|
thread.executionCwd = executionCwd;
|
|
495
488
|
thread.thinkingLevel = thinkingLevel;
|
|
496
|
-
thread.requestedThinkingLevel = requestedThinking;
|
|
497
489
|
thread.isolation = isolation;
|
|
498
490
|
thread.worktree = worktree;
|
|
499
491
|
thread.state = "queued";
|
|
@@ -517,7 +509,6 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
|
|
|
517
509
|
cwd: originalCwd,
|
|
518
510
|
executionCwd,
|
|
519
511
|
thinkingLevel,
|
|
520
|
-
requestedThinkingLevel: requestedThinking,
|
|
521
512
|
isolation,
|
|
522
513
|
worktree,
|
|
523
514
|
state: "queued",
|
|
@@ -557,7 +548,7 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
|
|
|
557
548
|
let activeIdleTimeoutMs = runConfig.idleTimeoutSec * 1000;
|
|
558
549
|
try {
|
|
559
550
|
const startConfig = await loadConfig(runtime.configPath);
|
|
560
|
-
const resolvedStart = resolveDispatchModelRoute(agent, startConfig, runCtx
|
|
551
|
+
const resolvedStart = resolveDispatchModelRoute(agent, startConfig, runCtx);
|
|
561
552
|
activeRoute = isolation === "worktree"
|
|
562
553
|
? { ...resolvedStart, agent: withWorktreeSystemPrompt(resolvedStart.agent) }
|
|
563
554
|
: resolvedStart;
|
|
@@ -1182,9 +1173,6 @@ function createRestoredThread(
|
|
|
1182
1173
|
cwd: record.cwd,
|
|
1183
1174
|
executionCwd: record.executionCwd,
|
|
1184
1175
|
...(record.thinkingLevel ? { thinkingLevel: record.thinkingLevel as ThinkingLevel } : {}),
|
|
1185
|
-
...(record.requestedThinkingLevel
|
|
1186
|
-
? { requestedThinkingLevel: record.requestedThinkingLevel as ThinkingLevel }
|
|
1187
|
-
: {}),
|
|
1188
1176
|
isolation: record.isolation,
|
|
1189
1177
|
worktree,
|
|
1190
1178
|
state,
|