@ferris1225/pi-subagents 2.3.1 → 3.0.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
@@ -61,11 +61,11 @@ index.
61
61
  into the main system prompt, so the main model sends broad searches to `explore`,
62
62
  self-contained implementations to `worker`, explicit cleanup intent to `cleaner`,
63
63
  and pre-commit reviews to `reviewer`. You just use pi; delegation happens by itself.
64
- - **Vision-capable image tasks** — flag screenshot/mockup/design work with
65
- `vision: true`. The configured vision model hands directly to the current main
66
- model on model/provider failure. Setup lists only in-scope, image-capable models
67
- from providers with configured authentication, and failures never silently
68
- rewrite your configuration.
64
+ - **Multimodal work is a model choice, not a mode** — an agent that should see
65
+ screenshots, mockups, or its own rendered pages simply gets a multimodal model
66
+ through `/subagents-setup` (the picker labels each model `vision` or
67
+ `text-only`). The agent reads images with its `read` tool on whatever model it
68
+ runs; no per-task flag, no separate vision override.
69
69
  - **Results come back on their own** — completions are delivered as messages that
70
70
  wake the main agent automatically, even mid-turn. No polling, no `sleep`, no
71
71
  "go check" step. `subagent_wait` is a **non-blocking** in-turn lookup by default
@@ -201,15 +201,16 @@ subagent({
201
201
 
202
202
  ### Cleanup routing and lifecycle
203
203
 
204
- The injected guidance routes `cleaner` by explicit semantic intent: **code cleanup**,
205
- **dead code**, **代码清理**, **精简**, **清理冗余**, **简化**, or **去除过度设计**.
206
- Requested periodic maintenance passes also qualify; PR counts do not, and cleaner is
207
- never run automatically as the pre-commit gate.
204
+ The injected guidance routes `cleaner` by explicit semantic intent in any
205
+ language the conversation uses: **code cleanup**, **dead code**, redundancy,
206
+ simplification, or over-engineering. Requested periodic maintenance passes also
207
+ qualify; PR counts do not, and cleaner is never run automatically as the
208
+ pre-commit gate.
208
209
 
209
- - **Audit mode:** audit/find/report/review or 审计/查找/检查/报告 wording produces
210
- read-only ranked evidence.
211
- - **Apply mode:** explicit remove/clean/simplify/refactor or 清理/删除/移除/精简/简化/重构
212
- wording permits the smallest proven edits plus narrow-then-broad verification.
210
+ - **Audit mode:** audit/find/report/review wording produces read-only ranked
211
+ evidence.
212
+ - **Apply mode:** explicit remove/clean/simplify/refactor wording permits the
213
+ smallest proven edits plus narrow-then-broad verification.
213
214
 
214
215
  ```text
215
216
  explicit cleanup intent → cleaner (audit or apply)
@@ -220,33 +221,23 @@ cleaner apply → reviewer gate → worker auto-fix (on REVIEW_FAIL) → reviewe
220
221
  portion runs only when enabled by `maxFixRounds`; cleaner itself is not a pre-commit
221
222
  hook or a PR-count scheduler.
222
223
 
223
- ### Vision tasks (screenshots / mockups / designs)
224
+ ### Image work (screenshots / mockups / designs)
224
225
 
225
- When a task may require viewing images frontend work, UI review, design
226
- comparisons set `vision: true` and give the sub-agent the exact image paths:
226
+ There is no vision flag or separate vision model. Give the agent a multimodal
227
+ model in `/subagents-setup` and name the exact image paths in the task:
227
228
 
228
229
  ```ts
229
230
  subagent({
230
231
  agent: "reviewer",
231
232
  task: "Compare the UI in screenshots/settings.png against the mockup design.png; list every visual mismatch.",
232
- vision: true,
233
233
  });
234
234
  ```
235
235
 
236
- The sub-agent reads images with its `read` tool. Runtime order for a
237
- vision-flagged run is `visionModel` current main-window model. A stale or
238
- currently unavailable vision selection is skipped immediately without rewriting
239
- it. A vision-flagged auto-fix chain keeps the flag for worker/re-review rounds
240
- because they may need to inspect the same images.
241
-
242
- As a deterministic fallback, a brief that names an image file (an extension such
243
- as `.png`, `.jpg`, `.webp`) or describes frontend/UI work — Vue/React/Svelte
244
- pages, mockups, screenshots, page styling — is dispatched as
245
- vision even without the flag: the model cannot be swapped mid-run, so a worker
246
- that screenshots and visually verifies what it builds must start on a
247
- vision-capable model. How do you verify which model ran? The live widget line,
248
- dispatch result row, and `subagent_status` all show each run's effective model
249
- id, and a selected→main handoff is labeled with its origin.
236
+ The sub-agent reads images with its `read` tool on its configured model; the
237
+ setup picker labels each model `vision` or `text-only` so the choice is visible.
238
+ The live widget line, dispatch result row, and `subagent_status` all show each
239
+ run's effective model id, and a selected→main handoff is labeled with its
240
+ origin.
250
241
 
251
242
  ### Controlling and stopping
252
243
 
@@ -302,8 +293,8 @@ sessions show the recovery paths again until the artifacts are removed.
302
293
  ## Configuration
303
294
 
304
295
  Stored at `~/.pi/agent/pi-subagents.json` (follows `PI_CODING_AGENT_DIR` when
305
- set). `/subagents-setup` has five top-level choices: enable agents, configure one
306
- agent's model/thinking, choose a vision model, runtime settings, or full setup.
296
+ set). `/subagents-setup` has four top-level choices: enable agents, configure one
297
+ agent's model/thinking, runtime settings, or full setup.
307
298
  After one agent's model + thinking picks, the wizard returns to the agent picker
308
299
  so several agents can be configured in one pass; Esc at any step ends the pass
309
300
  and keeps every agent already configured. There is no backup pool or global thinking menu. Model pickers show only in-scope
@@ -321,7 +312,6 @@ direct-file settings.
321
312
  "agentThinkingLevels": {
322
313
  "reviewer": "high"
323
314
  },
324
- "visionModel": "anthropic/claude-sonnet-4-5",
325
315
  "notifyOnReviewPass": false,
326
316
  "maxResultLines": 80,
327
317
  "proactiveInjection": true,
@@ -337,7 +327,6 @@ direct-file settings.
337
327
  | `enabledAgents` | Agent names exposed to discovery and prompt injection. An empty array disables all agents. |
338
328
  | `agentModels` | Optional selected `provider/model-id` per agent. Missing = current main model. Model-level failure hands directly to current main. |
339
329
  | `agentThinkingLevels` | Optional manual preference per agent. Missing = Auto (agent frontmatter preference, or `high`, clamped to the effective model's supported levels). |
340
- | `visionModel` | Optional vision-capable model for `vision: true` tasks (screenshots/mockups/designs). Unset = falls back to the main session's current model. |
341
330
  | `notifyOnReviewPass` | When `true`, a passing reviewer result is delivered without waking the main agent (default `false`). |
342
331
  | `maxResultLines` | Max lines of a sub-agent result carried in the completion message (default `80`). Longer results are truncated; full text is written to an extension-named temporary `.md`. At session start and on each write, only recognized result files older than 7 days are removed; each canonical project path has its own newest-50 bucket. |
343
332
  | `proactiveInjection` | Whether to add the delegation directive to the main system prompt. |
@@ -349,7 +338,7 @@ direct-file settings.
349
338
  ### Model routing and thinking
350
339
 
351
340
  ```text
352
- selected agent/vision model → current main-window model
341
+ selected agent model → current main-window model
353
342
  ```
354
343
 
355
344
  Without a selected model, current main runs immediately; agent frontmatter model
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ferris1225/pi-subagents",
3
- "version": "2.3.1",
3
+ "version": "3.0.0",
4
4
  "description": "Controllable background sub-agent threads for pi: specialized roles, capability-aware thinking, direct main-model fallback, auto-fix chains, and Git worktree isolation.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -13,12 +13,6 @@ const ANNOUNCEMENTS: Array<{
13
13
  condition: (config: Awaited<ReturnType<typeof loadConfig>>) => boolean;
14
14
  message: string;
15
15
  }> = [
16
- {
17
- key: "visionModel",
18
- condition: (config) => config.visionModel === undefined,
19
- message:
20
- "pi-subagents: new — a vision-capable model can now handle image tasks (screenshots, mockups, designs). Run /subagents-setup to configure it; until set, vision tasks use the main session's current model.",
21
- },
22
16
  {
23
17
  key: "cleanerAgent",
24
18
  condition: (config) => !config.enabledAgents.includes("cleaner"),
package/src/config.ts CHANGED
@@ -99,15 +99,8 @@ export interface SubagentsConfig {
99
99
  */
100
100
  idleTimeoutSec: number;
101
101
  /**
102
- * Vision-capable model for tasks flagged `vision: true` (viewing screenshots,
103
- * mockups, designs). Unset means such tasks fall back to the main session's
104
- * current model.
105
- */
106
- visionModel?: string;
107
- /**
108
- * One-time feature announcements already shown to the user (e.g. "vision
109
- * model" after an update that introduced it). Persisted so the notice never
110
- * nags again.
102
+ * One-time feature announcements already shown to the user. Persisted so
103
+ * the notice never nags again.
111
104
  */
112
105
  announcedFeatures: string[];
113
106
  }
@@ -212,10 +205,6 @@ export function normalizeConfig(raw: unknown): SubagentsConfig {
212
205
  config.idleTimeoutSec = Math.max(0, Math.min(IDLE_TIMEOUT_SEC_LIMIT, Math.round(raw.idleTimeoutSec)));
213
206
  }
214
207
 
215
- if (isModelReference(raw.visionModel)) {
216
- config.visionModel = (raw.visionModel as string).trim();
217
- }
218
-
219
208
  if (Array.isArray(raw.announcedFeatures)) {
220
209
  config.announcedFeatures = raw.announcedFeatures.filter(
221
210
  (feature): feature is string => typeof feature === "string" && feature.trim().length > 0,
package/src/dispatch.ts CHANGED
@@ -3,9 +3,6 @@
3
3
  * child processes, single or parallel. Owns the public dispatch contract,
4
4
  * per-run status tracking, the auto-fix chain (REVIEW_FAIL → worker → re-review),
5
5
  * and completion delivery. Stable thread generations live in thread-lifecycle.ts.
6
- *
7
- * Vision: a task flagged `vision: true` uses the configured vision model, then
8
- * hands directly to the current main-window model on model/provider failure.
9
6
  */
10
7
 
11
8
  import { StringEnum } from "@earendil-works/pi-ai";
@@ -58,9 +55,6 @@ export { FORK_CONTINUATION_PROMPT, isWorktreeCapableAgent } from "./thread-lifec
58
55
 
59
56
  const NON_BLANK_TASK_OPTIONS = { minLength: 1, pattern: "\\S" } as const;
60
57
 
61
- const VISION_DESCRIPTION =
62
- "Set true when the task may require viewing images (screenshots, mockups, designs) — the configured vision model is used first, then model-level failures hand directly to the current main-window model. A task that names an image file or describes frontend/UI work (Vue/React, mockups, screenshots, page styling) is dispatched as vision automatically";
63
-
64
58
  const ISOLATION_DESCRIPTION =
65
59
  "Filesystem isolation: shared uses the caller's working tree; worktree creates a detached temporary Git worktree (write-capable agents, including worker and cleaner, only)";
66
60
 
@@ -75,7 +69,6 @@ const TaskItem = Type.Object({
75
69
  description: "Self-contained task to delegate (the agent has no memory of this conversation)",
76
70
  }),
77
71
  cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
78
- vision: Type.Optional(Type.Boolean({ description: VISION_DESCRIPTION })),
79
72
  isolation: IsolationSchema,
80
73
  });
81
74
 
@@ -86,7 +79,6 @@ const SubagentParams = Type.Object({
86
79
  ),
87
80
  tasks: Type.Optional(Type.Array(TaskItem, { description: "Array of {agent, task} for parallel execution" })),
88
81
  cwd: Type.Optional(Type.String({ description: "Working directory for the agent process (single mode)" })),
89
- vision: Type.Optional(Type.Boolean({ description: VISION_DESCRIPTION })),
90
82
  isolation: IsolationSchema,
91
83
  });
92
84
 
@@ -95,27 +87,6 @@ export function defaultIsolationMode(mode: "single" | "parallel", agentName: str
95
87
  return mode === "parallel" && agentName === "worker" ? "worktree" : "shared";
96
88
  }
97
89
 
98
- const IMAGE_FILE_PATTERN = /\.(?:png|jpe?g|webp|gif|bmp|tiff?|avif)\b/i;
99
- /** Frontend/UI work: the agent may screenshot and visually verify what it
100
- * builds, and the model cannot be swapped mid-run — vision must be on at
101
- * spawn. Only language-neutral signals: code terms and file names stay in
102
- * English even in non-English briefs; purely semantic wording is the LLM's
103
- * job via the vision flag, not a per-language keyword list. Word boundaries
104
- * keep ordinary words (build, guide, reactor) from matching. */
105
- const FRONTEND_PATTERN = /\b(?:vue|react|svelte|angular|nuxt|next\.?js|vite|tailwind|screenshots?|mockups?|wireframes?|UI)\b/i;
106
- const FRONTEND_FILE_PATTERN = /\.(?:vue|html?|css|svg)\b/i;
107
-
108
- /** Deterministic vision fallback: a brief that names an image file or describes
109
- * frontend/UI work is vision work even when the dispatcher forgot the flag —
110
- * prompting alone cannot guarantee `vision: true`, and a non-vision model can
111
- * neither see reference images nor visually verify what it builds. */
112
- export function taskImpliesVision(task: string): boolean {
113
- return IMAGE_FILE_PATTERN.test(task) || FRONTEND_FILE_PATTERN.test(task) || FRONTEND_PATTERN.test(task);
114
- }
115
-
116
- const wantsVision = (flag: boolean | undefined, task: string): boolean =>
117
- flag === true || taskImpliesVision(task);
118
-
119
90
  const autoFixRootTails = new Map<string, Promise<void>>();
120
91
 
121
92
  async function canonicalAutoFixRoot(cwd: string): Promise<string> {
@@ -172,7 +143,6 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
172
143
  "It starts agents in the background and immediately returns control to the main window; completion messages automatically wake the main agent to continue.",
173
144
  "Each agent has no memory of this conversation — brief it fully (goal, exact paths, constraints, expected output).",
174
145
  "Results arrive as wake-up messages automatically — you do NOT need to wait. If you must get a result in-turn, subagent_wait is a non-blocking lookup by default (pass timeoutMs to block).",
175
- "Vision: set vision: true when the task may require viewing images (screenshots, mockups, design files — e.g. frontend work) — the configured vision model is used first, then model-level failures hand directly to the current main-window model.",
176
146
  ].join(" "),
177
147
  promptSnippet:
178
148
  "Start background subagents: explore (read-only search), worker (implement), cleaner (explicit evidence-first cleanup), reviewer (pre-commit review); completion automatically resumes the main agent. Simple tasks: use direct tools, not subagents.",
@@ -188,7 +158,6 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
188
158
  "Use isolation: worktree only for worker, cleaner, or another write-capable agent and only inside a Git repository with a committed HEAD; parallel worker tasks default to worktree, while cleaner must opt in. Setup or integration failures never silently fall back to shared.",
189
159
  "NEVER sleep or poll, and do NOT call subagent_wait to hold the turn — subagent ends the turn immediately and the result arrives as a message that wakes you automatically (even mid-turn). Ending your turn is the default and the only correct way to wait.",
190
160
  "If you must keep the turn for a result, call subagent_wait with an explicit timeoutMs (non-blocking by default) — never bash sleep/timeout to wait for a sub-agent.",
191
- "When a delegated task may require viewing images (frontend screenshots, mockups, design comparisons), pass vision: true and give the sub-agent the exact image paths — it reads them with its read tool. The configured vision model is used first; model-level failures hand directly to the current main-window model.",
192
161
  "When a sub-agent result arrives it is already shown to the user — do NOT restate, paraphrase, or summarize it; reply with only your own conclusion or next action (often just one line), since duplicating the result wastes tokens for nothing.",
193
162
  ],
194
163
  parameters: SubagentParams,
@@ -320,13 +289,10 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
320
289
  executionCwd: string,
321
290
  signal: AbortSignal,
322
291
  meta: RunChainMeta,
323
- vision = false,
324
292
  ): Promise<{ runId?: number; result: SingleResult }> => {
325
293
  const agent = agents.find((candidate) => candidate.name === agentName);
326
294
  if (!agent) return { result: failedStartResult(agentName, task, `Unknown agent: "${agentName}".`) };
327
- // Vision chains use the vision override first; every model-level failure
328
- // hands directly to the current main model with re-clamped thinking.
329
- const route = resolveDispatchModelRoute(agent, config, ctx, vision);
295
+ const route = resolveDispatchModelRoute(agent, config, ctx);
330
296
  const thinkingLevel = route.thinkingLevel;
331
297
  const runId = monitor.addRun(agent.name, task, route.agent.model, thinkingLevel, meta);
332
298
  const onLive = makeLiveHandler(runId);
@@ -397,7 +363,6 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
397
363
  parentGroupId: string,
398
364
  parentRunId: number,
399
365
  executionCwd: string,
400
- vision = false,
401
366
  ): void => {
402
367
  const parentThreadAtStart = runtime.threads.get(parentRunId);
403
368
  if (!parentThreadAtStart) return;
@@ -446,7 +411,7 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
446
411
  groupId: parentGroupId,
447
412
  relationLabel: `fix round ${round}`,
448
413
  parentRunId,
449
- }, vision);
414
+ });
450
415
  // Preserve the newest sub-step before checking chain ownership. A
451
416
  // destructive stop invalidates ownsParent() while this child is
452
417
  // aborting, and its partial output must become the parent's stopped
@@ -470,7 +435,7 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
470
435
  groupId: parentGroupId,
471
436
  relationLabel: `re-review round ${round}`,
472
437
  parentRunId,
473
- }, vision);
438
+ });
474
439
  if (
475
440
  runtime.threads.get(parentRunId) === parentThreadAtStart &&
476
441
  parentThreadAtStart.generation === parentGeneration
@@ -649,7 +614,6 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
649
614
  item.agent,
650
615
  item.task,
651
616
  item.cwd,
652
- wantsVision(item.vision, item.task),
653
617
  defaultIsolationMode("parallel", item.agent, item.isolation as IsolationMode | undefined),
654
618
  ));
655
619
  }
@@ -687,7 +651,6 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
687
651
  params.agent as string,
688
652
  params.task as string,
689
653
  params.cwd,
690
- wantsVision(params.vision, params.task as string),
691
654
  defaultIsolationMode("single", params.agent as string, params.isolation as IsolationMode | undefined),
692
655
  );
693
656
  if (result.exitCode !== -1) {
package/src/index.ts CHANGED
@@ -69,7 +69,7 @@ export default function (pi: ExtensionAPI): void {
69
69
  registerLookupTools(pi, runtime);
70
70
 
71
71
  pi.registerCommand("subagents-setup", {
72
- description: "Configure pi-subagents: agents, selected models, capability-aware thinking, vision, and runtime settings",
72
+ description: "Configure pi-subagents: agents, selected models, capability-aware thinking, and runtime settings",
73
73
  handler: async (_args, ctx) => {
74
74
  await runSetup(ctx, configPath);
75
75
  },
package/src/models.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Model routing, capability-aware thinking, and setup-picker helpers.
3
3
  *
4
- * Runtime has one explicit fallback only: a configured agent/vision model hands
4
+ * Runtime has one explicit fallback only: a configured agent model hands
5
5
  * off directly to the current main-window model. Setup lists only currently
6
6
  * available models and derives thinking choices from Pi's model metadata.
7
7
  */
@@ -20,8 +20,6 @@ export type ModelContext = Pick<ExtensionContext, "model" | "modelRegistry"> &
20
20
 
21
21
  export const CURRENT_MAIN_MODEL = "__current_main_model__";
22
22
 
23
- export type ModelPickerSlot = "agent" | "vision";
24
-
25
23
  export interface ModelPickerItem {
26
24
  value: string;
27
25
  label: string;
@@ -136,11 +134,10 @@ function modelCapabilities(model: ModelListEntry): string {
136
134
  return `${input} · thinking: ${thinking}`;
137
135
  }
138
136
 
139
- /** Build one searchable list for agent or vision selection. Only models Pi
137
+ /** Build one searchable list for agent model selection. Only models Pi
140
138
  * currently reports as available are supplied by setup. */
141
139
  export function buildModelPickerItems(options: {
142
140
  models: readonly ModelListEntry[];
143
- slot: ModelPickerSlot;
144
141
  configuredRef?: string;
145
142
  mainRef?: string;
146
143
  }): ModelPickerItem[] {
@@ -153,7 +150,6 @@ export function buildModelPickerItems(options: {
153
150
  }
154
151
 
155
152
  const refs = [...byRef.keys()]
156
- .filter((ref) => options.slot !== "vision" || byRef.get(ref)?.input.includes("image") === true)
157
153
  .sort((left, right) => {
158
154
  const leftRank = left === configuredRef ? 0 : left === mainRef ? 1 : 2;
159
155
  const rightRank = right === configuredRef ? 0 : right === mainRef ? 1 : 2;
@@ -163,9 +159,7 @@ export function buildModelPickerItems(options: {
163
159
  const dynamic: ModelPickerItem = {
164
160
  value: CURRENT_MAIN_MODEL,
165
161
  label: "Current main model (dynamic)",
166
- description: options.slot === "vision"
167
- ? "Clear vision override; use the current main model for image tasks"
168
- : "Clear agent override; use the current main model dynamically",
162
+ description: "Clear agent override; use the current main model dynamically",
169
163
  };
170
164
  const items: ModelPickerItem[] = [dynamic];
171
165
  for (const ref of refs) {
package/src/prompt.ts CHANGED
@@ -66,10 +66,6 @@ ${hasMultiple ? `- Run INDEPENDENT tasks in parallel: one subagent call with a \
66
66
  - Treat delegated agents as leaf workers: do not ask a sub-agent to dispatch another sub-agent; child processes do not have this tool. Use \`subagent_control fork\` on a parked/settled retained thread when you need an independent continuation with preserved context and a new run id.
67
67
  - Trust but verify: a sub-agent's summary describes intent, not outcome. Check the actual changes/results before reporting work done.
68
68
  ${hasExplore ? "- Treat `explore` findings as a retrieval index, never as sole proof for edits, deletion, security, compatibility, persistence, or dynamic reachability. Re-read load-bearing files before acting. An underpowered model can be false economy on complex dynamic, concurrent, migration, or security-sensitive code; use a stronger model or specialist there.\n" : ""}
69
- Vision tasks:
70
- - Judge whether a delegated task may require viewing images (frontend screenshots, mockups, design files, visual regression comparisons). If it might, pass \`vision: true\` in the subagent call and give the sub-agent the exact image paths — it reads them with its read tool. Naming an image file or describing frontend/UI work (Vue/React page, mockup, page styling) dispatches as vision automatically, but keep passing the flag for image work described without those signals.
71
- - \`vision: true\` runs the sub-agent on the vision-capable model configured in /subagents-setup; when none is configured it falls back to the main session's current model. Do not skip the flag because the agent's default model looks fast — a non-vision model cannot see the images.
72
-
73
69
  Result handoff (do not re-state):
74
70
  - A sub-agent's result arrives as a message that is already shown to the user. Do NOT restate, paraphrase, or re-summarize its findings in your reply — that just burns tokens duplicating what is already visible. The user can read the result above.
75
71
  - Reply only with what you ADD: your own conclusion, the next action you are taking, or a one-line acknowledgement. When the result already answers the user, a single sentence is enough — then end your turn or proceed.
package/src/runtime.ts CHANGED
@@ -52,7 +52,6 @@ export interface SubagentThread {
52
52
  cwd: string;
53
53
  /** Actual child cwd (the equivalent path inside an isolated worktree). */
54
54
  executionCwd: string;
55
- vision: boolean;
56
55
  thinkingLevel?: ThinkingLevel;
57
56
  isolation: IsolationMode;
58
57
  worktree?: WorktreeIsolation;
package/src/setup.ts CHANGED
@@ -37,7 +37,6 @@ import {
37
37
  modelRef,
38
38
  resolveThinkingLevel,
39
39
  supportedThinkingLevels,
40
- type ModelPickerSlot,
41
40
  } from "./models.ts";
42
41
  import { promptSelectMany, promptSelectOne } from "./ui.ts";
43
42
  import { discoverAgents } from "./agents.ts";
@@ -96,14 +95,12 @@ async function pickEnabledAgents(
96
95
  async function pickConfiguredModel(
97
96
  ctx: ExtensionCommandContext,
98
97
  title: string,
99
- slot: ModelPickerSlot,
100
98
  configuredRef: string | undefined,
101
99
  escNote: string,
102
100
  ): Promise<string | undefined> {
103
101
  const models = availableModelsInScope(ctx);
104
102
  const items = buildModelPickerItems({
105
103
  models,
106
- slot,
107
104
  configuredRef,
108
105
  mainRef: currentModelRef(ctx),
109
106
  });
@@ -122,20 +119,7 @@ async function pickAgentModel(
122
119
  currentRef: string | undefined,
123
120
  escNote = "cancels setup",
124
121
  ): Promise<string | undefined> {
125
- return pickConfiguredModel(ctx, `Model for "${agentName}"?`, "agent", currentRef, escNote);
126
- }
127
-
128
- async function pickVisionModel(
129
- ctx: ExtensionCommandContext,
130
- currentRef: string | undefined,
131
- ): Promise<string | undefined> {
132
- return pickConfiguredModel(
133
- ctx,
134
- "Vision model for image tasks? (failure → current main model)",
135
- "vision",
136
- currentRef,
137
- "cancels setup",
138
- );
122
+ return pickConfiguredModel(ctx, `Model for "${agentName}"?`, currentRef, escNote);
139
123
  }
140
124
 
141
125
  const THINKING_LEVEL_HINTS: Record<ThinkingLevel, string> = {
@@ -304,8 +288,6 @@ async function runFullSetup(ctx: ExtensionCommandContext, configPath: string, ba
304
288
  agentModels = applyAgentModelChoice(agentModels, agentName, choice);
305
289
  }
306
290
 
307
- const visionModel = await pickVisionModel(ctx, base.visionModel);
308
- if (visionModel === undefined) return notifyCancelled(ctx);
309
291
  const injection = await pickInjection(ctx, base.proactiveInjection);
310
292
  if (injection === undefined) return notifyCancelled(ctx);
311
293
  const scope = await pickScope(ctx, base.agentScope);
@@ -349,7 +331,6 @@ async function runFullSetup(ctx: ExtensionCommandContext, configPath: string, ba
349
331
  idleTimeoutSec,
350
332
  announcedFeatures: base.announcedFeatures,
351
333
  };
352
- if (visionModel !== CURRENT_MAIN_MODEL) next.visionModel = visionModel;
353
334
  await saveConfig(next, configPath);
354
335
  ctx.ui.notify(`pi-subagents configured with Auto thinking. Saved to ${configPath}`, "info");
355
336
  }
@@ -395,7 +376,6 @@ async function runMenu(ctx: ExtensionCommandContext, configPath: string, config:
395
376
  const choice = await ctx.ui.select("pi-subagents settings", [
396
377
  "Enable/disable agents",
397
378
  "Configure an agent (model + thinking)",
398
- "Change vision model",
399
379
  "Runtime settings",
400
380
  "Full re-setup",
401
381
  ]);
@@ -427,11 +407,6 @@ async function runMenu(ctx: ExtensionCommandContext, configPath: string, config:
427
407
  else next.agentThinkingLevels[picked.name] = picked.strength;
428
408
  }
429
409
  if (!configuredAny) return notifyCancelled(ctx);
430
- } else if (choice.startsWith("Change vision")) {
431
- const visionModel = await pickVisionModel(ctx, config.visionModel);
432
- if (visionModel === undefined) return notifyCancelled(ctx);
433
- if (visionModel === CURRENT_MAIN_MODEL) delete next.visionModel;
434
- else next.visionModel = visionModel;
435
410
  } else {
436
411
  const updated = await updateRuntimeSetting(ctx, next);
437
412
  if (updated === undefined) return notifyCancelled(ctx);
@@ -92,12 +92,11 @@ export function resolveDispatchModelRoute(
92
92
  agent: AgentConfig,
93
93
  config: SubagentsConfig,
94
94
  ctx: ExtensionContext,
95
- vision: boolean,
96
95
  ): DispatchModelRoute {
97
96
  const availableModels = availableModelsInScope(ctx);
98
97
  const mainRef = currentModelRef(ctx);
99
98
  const route = resolveAgentModelRoute({
100
- selectedRef: vision ? config.visionModel : config.agentModels[agent.name],
99
+ selectedRef: config.agentModels[agent.name],
101
100
  mainRef,
102
101
  declaredDefaultRef: agent.model,
103
102
  availableRefs: availableModels.map(modelRef),
@@ -137,7 +136,6 @@ interface BackgroundDispatcherOptions extends DispatchEnvironment {
137
136
  parentGroupId: string,
138
137
  parentRunId: number,
139
138
  executionCwd: string,
140
- vision?: boolean,
141
139
  ) => void;
142
140
  }
143
141
 
@@ -145,7 +143,6 @@ type BackgroundStarter = (
145
143
  agentName: string,
146
144
  task: string,
147
145
  cwd: string | undefined,
148
- vision?: boolean,
149
146
  isolation?: IsolationMode,
150
147
  ) => Promise<SingleResult>;
151
148
 
@@ -204,7 +201,6 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
204
201
  agentName: string,
205
202
  task: string,
206
203
  cwd: string | undefined,
207
- vision = false,
208
204
  isolation: IsolationMode = "shared",
209
205
  existingThread?: SubagentThread,
210
206
  newObjectiveOnResume = false,
@@ -253,7 +249,7 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
253
249
  }
254
250
  }
255
251
  const executionCwd = worktree?.cwd ?? originalCwd;
256
- const resolvedRoute = resolveDispatchModelRoute(agent, runConfig, runCtx, vision);
252
+ const resolvedRoute = resolveDispatchModelRoute(agent, runConfig, runCtx);
257
253
  // Isolation is a persistent system-level invariant, not a one-shot task
258
254
  // prefix: queued retargets, live retargets, resumes, and main-model
259
255
  // handoffs all keep the same worktree boundary.
@@ -319,7 +315,6 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
319
315
  thread.task = task;
320
316
  thread.cwd = originalCwd;
321
317
  thread.executionCwd = executionCwd;
322
- thread.vision = vision;
323
318
  thread.thinkingLevel = thinkingLevel;
324
319
  thread.isolation = isolation;
325
320
  thread.worktree = worktree;
@@ -343,7 +338,6 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
343
338
  task,
344
339
  cwd: originalCwd,
345
340
  executionCwd,
346
- vision,
347
341
  thinkingLevel,
348
342
  isolation,
349
343
  worktree,
@@ -622,7 +616,6 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
622
616
  thread.agentName,
623
617
  nextTask,
624
618
  thread.cwd,
625
- thread.vision,
626
619
  thread.isolation,
627
620
  thread,
628
621
  objective !== undefined,
@@ -784,7 +777,6 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
784
777
  thread.agentName,
785
778
  childTask,
786
779
  thread.cwd,
787
- thread.vision,
788
780
  thread.isolation,
789
781
  undefined,
790
782
  false,
@@ -926,7 +918,7 @@ export function createBackgroundDispatcher(options: BackgroundDispatcherOptions)
926
918
  // the same row now represents the chain until it resolves.
927
919
  monitor.setStatus(runId, "running");
928
920
  monitor.setActivity(runId, "auto-fix chain running");
929
- startFixLoop(result, `fix-${runId}`, runId, thread.executionCwd, vision);
921
+ startFixLoop(result, `fix-${runId}`, runId, thread.executionCwd);
930
922
  return;
931
923
  }
932
924
  // Claim terminal settlement synchronously before the first slow await.