pi-critique-model 1.0.0 → 1.1.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
@@ -1,28 +1,36 @@
1
1
  <div align="center">
2
2
 
3
- ![Critique banner](docs/banner.png)
3
+ ![Critique banner](https://raw.githubusercontent.com/noguerol/critique/main/docs/banner.jpeg)
4
4
 
5
5
  </div>
6
6
 
7
- # Critique — Adversarial Code Review for pi
7
+ # Critique — Adversarial Review for pi
8
8
 
9
- **Critique reviews the last work step with a separate model and feeds the review back to the working model as advisory feedback.** Two thinking machines face off the working model produced a work step, and an independent reviewer picks it apart for correctness, robustness, maintainability and efficiency. The verdict comes back as structured Markdown: `APPROVED`, `APPROVED_WITH_SUGGESTIONS`, or `CHANGES_RECOMMENDED` and the working model stays the final judge. The feedback is **non-mandatory**: it applies, partially applies, or rejects each point as it sees fit.
9
+ **Critique questions the last work step with a separate model and can challenge user instructions before the model starts.** It is not limited to code: it can review implementation work, writing, plans, research, data analysis, ops, or any other project work. Optionally, Critique also runs a fast pre-flight check on sufficiently rich user prompts and shows a short `Critique` widget when the instruction deserves pushback. The feedback is **non-mandatory**: the user and the working model remain the final judges.
10
+
11
+ Additionally, the **Questions** feature detects ambiguous user input and offers clarifying suggestions before the model acts on it.
10
12
 
11
13
  ---
12
14
 
13
15
  ## Features
14
16
 
15
- - **Independent reviewer** — a separate model judges the work step from the serialized context, with no tools of its own (can't modify the codebase, can't see your secrets)
17
+ - **Independent reviewer** — a separate model questions the work step from serialized context, with no tools of its own (can't modify files or see hidden state)
16
18
  - **Auto-detects the work step** — splits the session branch into *episodes* at user-message boundaries; the last episode containing tool calls or assistant output is the work step
17
19
  - **Token-budgeted context** — the user prompt, assistant messages, tool calls and tool results are truncated to a self-contained block so the reviewer sees what it needs without overflow
18
- - **Multi-step review** — review the last `N` episodes in one shot (`/critique 3`) to catch interactions across steps
19
- - **Focus note** — `/critique check the error handling` biases the review without limiting it; the reviewer still scans for everything
20
- - **Structured output** — fixed `Verdict / Issues / Suggestions / Summary` schema so the feedback is always actionable and machine-parseable
21
- - **Independent model picker** — `/critique config` lets you choose the reviewer; the default is a *different* model than the working one, ensuring a genuinely independent perspective
20
+ - **Multi-step review** — review the last `N` episodes in one shot (`/critique 3`) to catch cross-step issues
21
+ - **Focus note** — `/critique check the assumptions` biases the review without limiting it; the reviewer still scans for everything
22
+ - **Structured output** — fixed `Verdict / Issues / Suggestions / Summary` schema for actionable, parseable feedback
23
+ - **Settings menu** — `/critique config` opens an editable menu so you can change one setting at a time without rerunning a full wizard
22
24
  - **Advisory injection** — on by default; toggle off (or use `/critique view`) to keep the review as read-only
23
25
  - **Cancelable loader** — in TUI mode, the review runs behind a loader that you can abort with `Esc`
24
26
  - **No provider surprises** — empty reviews are flagged, provider errors are surfaced as errors instead of silently producing nothing
25
- - **Persistent config** — `~/.pi/agent/critique.json` stores the model choice and auto-inject toggle across all projects
27
+ - **Automatic prompt critique** — optional pre-flight challenge for user instructions before the model starts; trivial inputs (`ok`, tiny commands, quick corrections) are ignored
28
+ - **Three prompt-critique levels** — `Inconsistencies only` (low sensitivity), `Critical` (moderate), or `Corrosive` (high)
29
+ - **Prompt-critique model source** — use either the active working model or the configured critique model
30
+ - **Interactive Critique widget** — ultra-short one-sentence advice in the user's interaction language with `Accept`, `Discard`, or `Reply`; auto-discards after 30 seconds
31
+ - **Persistent config** — `~/.pi/agent/critique.json` stores model choice, auto-inject, and automatic prompt-critique settings across all projects
32
+ - **Questions feature** — optional clarifying widget that detects ambiguous user input and offers three options: two suggested interpretations and a free-text answer; auto-discards after 30 seconds
33
+ - **Questions frequency** — three sensitivity levels: `Essential only` (minimal), `Normal` (moderate), or `Many questions` (high sensitivity)
26
34
 
27
35
  ## Install
28
36
 
@@ -52,38 +60,38 @@ pi remove npm:pi-critique-model
52
60
 
53
61
  > **Security:** pi packages run with full system access — extensions execute arbitrary code. Install only packages you trust and review the source.
54
62
 
55
- **Requirements:** a working pi installation with at least two models configured (one is the *working* model, the other becomes the *reviewer*). Models can be from the same provider as long as they have different IDs.
63
+ **Requirements:** a working pi installation with at least one configured model. For independent reviews, configure a second model as reviewer.
56
64
 
57
65
  ## Quick Start
58
66
 
59
67
  ```
60
- /critique config # (optional) pick a reviewer model — defaults to "different from the working one"
68
+ /critique config # (optional) open the settings menu
61
69
  ... # let the main model do some work
62
70
  /critique # review the last work step and feed the feedback back
63
71
  ```
64
72
 
65
- The main model then sees the review appended to its next turn and decides what to apply. With auto-inject off (or `/critique view`), the review is only displayed to you — useful when you're just exploring whether to apply changes.
73
+ The main model then sees the review appended to its next turn and decides what to apply. With auto-inject off (or `/critique view`), the review is only displayed to you.
66
74
 
67
75
  To focus the review:
68
76
 
69
77
  ```
70
- /critique check the error handling on the retry logic
78
+ /critique check the assumptions behind the plan
71
79
  /critique 3 # review the last 3 work steps
72
- /critique 2 look at the test coverage # combine count + focus
80
+ /critique 2 look at the evidence gaps # combine count + focus
73
81
  ```
74
82
 
75
83
  ## Commands
76
84
 
77
85
  | Command | Description |
78
86
  |---------|-------------|
79
- | `/critique` | Review the last work step and inject the feedback back into the working model |
87
+ | `/critique` | Review/question the last work step and inject feedback into the working model |
80
88
  | `/critique <focus>` | Review the last work step with an additional focus note |
81
89
  | `/critique N` | Review the last `N` work steps (max 5) |
82
90
  | `/critique N <focus>` | Combine count and focus |
83
91
  | `/critique view` | Show the review only, without injecting it |
84
92
  | `/critique view <focus>` | View-only, with a focus note |
85
93
  | `/critique view N` | View-only, last `N` steps |
86
- | `/critique config` | Pick the critique model from pi's native active models and toggle auto-inject |
94
+ | `/critique config` | Open the editable settings menu for model, auto-inject, prompt critique, and questions |
87
95
 
88
96
  **Argument parsing:**
89
97
 
@@ -95,7 +103,7 @@ To focus the review:
95
103
 
96
104
  ### 1. Extract the work step
97
105
 
98
- The session branch is split into *episodes* at user-message boundaries. The last episode containing tool calls or assistant output is the work step: the user request that triggered it, every tool call (with arguments), and every tool result (diffs, command output, errors). Content is truncated to a token budget so the reviewer sees a focused, self-contained context:
106
+ The session branch is split into *episodes* at user-message boundaries. The last episode containing tool calls or assistant output is the work step: the user request that triggered it, every tool call (with arguments), and every tool result (diffs, command output, data, errors). Content is truncated to a token budget so the reviewer sees focused, self-contained context:
99
107
 
100
108
  | Field | Max chars |
101
109
  |-------|-----------|
@@ -109,11 +117,11 @@ Truncated content is marked with `… [truncated]` so the reviewer can tell what
109
117
 
110
118
  ### 2. Ask the reviewer
111
119
 
112
- The critique model is called directly through `ctx.modelRegistry.complete()` with **no tools** — it only judges. The reviewer is told:
120
+ The critique model is called directly through `ctx.modelRegistry.complete()` with **no tools** — it only judges/questions. The reviewer is told:
113
121
 
114
122
  - The work step inside `<work-step>` tags
115
123
  - An optional `<focus-note>` if you passed one
116
- - "Do not invent issues: if the work is correct, say so and keep suggestions minimal"
124
+ - "Do not invent issues: if the work is sound, say so and keep suggestions minimal"
117
125
 
118
126
  It replies in a fixed Markdown structure:
119
127
 
@@ -131,29 +139,65 @@ APPROVED | APPROVED_WITH_SUGGESTIONS | CHANGES_RECOMMENDED
131
139
  2-4 sentence overall assessment.
132
140
  ```
133
141
 
134
- The reviewer is also told explicitly to base its judgment *only* on the provided work step, so a reviewer on a smaller/cheaper model still gives useful feedback.
142
+ The reviewer is told to base its judgment *only* on the provided work step, across any domain: code, writing, planning, research, data, ops, etc.
135
143
 
136
144
  ### 3. Inject the feedback
137
145
 
138
146
  The review is sent back to the working model as a follow-up user message:
139
147
 
140
148
  ```
141
- [Critique — advisory review of your last work step]
149
+ [Critique — advisory]
150
+
151
+ Reviewer: `provider/model`. Advice only: apply useful points; briefly reject bad ones.
142
152
 
143
- A separate reviewer model (`provider/model`) reviewed the work you just
144
- performed. This feedback is **advisory, not mandatory**: you are the final
145
- judge. Apply only the points that genuinely improve the work, and if you
146
- disagree with any of them, briefly explain why and continue.
153
+ ---
147
154
 
148
- --- Review ---
149
155
  <the review>
150
156
  ```
151
157
 
152
158
  The main model then has the freedom to apply, partially apply, or reject each point. If auto-inject is off, the review is only shown to you.
153
159
 
160
+ ### 4. Optional automatic prompt critique
161
+
162
+ When enabled in `/critique config`, Critique listens to user input before prompt-template expansion and before the agent starts. A local heuristic skips acknowledgements, slash commands, tiny corrections, and short commands. For richer instructions, a tool-free model call decides whether there is anything worth challenging.
163
+
164
+ If critique is useful, pi shows an ultra-short `Critique` widget in the user's interaction language. The model always returns both an issue and a proposed fix:
165
+
166
+ - `Accept` includes the proposed fix as extra guidance for the model.
167
+ - `Discard` sends the original prompt unchanged.
168
+ - `Reply` lets the user answer the critique/fix before the model sees the prompt.
169
+ - No interaction within 30 seconds auto-discards the advice and sends the original prompt unchanged.
170
+
171
+ Automatic prompt critique can use either the active working model or the configured critique model. It does not require a separate model.
172
+
173
+ ### 5. Optional Questions feature
174
+
175
+ When enabled in `/critique config`, Critique analyzes user input for ambiguity — unclear pronouns, vague directives, or scope-unclear requests — and shows a `Questions` widget before the model receives the prompt.
176
+
177
+ The widget presents three options in the user's interaction language:
178
+
179
+ - **A** — a suggested interpretation (e.g., "Focus on the primary task")
180
+ - **B** — an alternative interpretation (e.g., "Address all aspects comprehensively")
181
+ - **C** — the user types their own answer in a free-text editor
182
+ - **Dismiss** — send the original prompt unchanged (auto-dismisses after 30 seconds)
183
+
184
+ The selected answer is prepended to the user's prompt as a clarification, so the working model receives a more precise instruction.
185
+
186
+ #### Questions Frequency
187
+
188
+ The sensitivity of the Questions feature is controlled by the **Questions frequency** setting:
189
+
190
+ | Level | Description |
191
+ |-------|-------------|
192
+ | **Essential only** | Only ask when the input is clearly ambiguous (long, multi-sentence, or contains unclear pronouns/references) |
193
+ | **Normal** | Moderate sensitivity; ask for most inputs that could benefit from clarification |
194
+ | **Many questions** | High sensitivity; ask frequently, even for shorter or mildly ambiguous inputs |
195
+
154
196
  ## Model Selection
155
197
 
156
- `/critique config` opens the critic model picker. It only offers models with configured auth, **only** from pi's native model registry the same list you see in `/model`. The picker shows at most ten entries at a time and scrolls past that.
198
+ `/critique config` opens an editable settings menu. Select a setting to change only that value, toggle booleans directly, or choose `Done`/`Esc` to close. Changes are persisted as soon as each setting is edited.
199
+
200
+ The `Critique model` entry opens the critic model picker. It only offers models with configured auth, **only** from pi's native model registry — the same list you see in `/model`. The picker shows at most ten entries at a time and scrolls past that.
157
201
 
158
202
  **Auto** (the default) prefers a *different* model than the working one, so the review is genuinely independent. If no second model is available, it falls back to the working model and warns you when it runs.
159
203
 
@@ -168,14 +212,24 @@ The config is persisted as JSON at `~/.pi/agent/critique.json`:
168
212
  ```json
169
213
  {
170
214
  "model": "anthropic/claude-sonnet-4",
171
- "autoInject": true
215
+ "autoInject": true,
216
+ "autoPromptCritique": false,
217
+ "autoPromptCritiqueLevel": "inconsistencies",
218
+ "autoPromptCritiqueModel": "working",
219
+ "questions": false,
220
+ "questionsFrequency": "normal"
172
221
  }
173
222
  ```
174
223
 
175
224
  - **`model`** — canonical `provider/modelId` of the reviewer. Empty string = Auto (different from working model).
176
225
  - **`autoInject`** — when `true`, the review is injected back into the working model. When `false`, the review is only displayed.
226
+ - **`autoPromptCritique`** — when `true`, sufficiently rich user instructions are challenged before the model starts.
227
+ - **`autoPromptCritiqueLevel`** — `inconsistencies` only flags real misunderstanding risks; `critical` is moderate; `corrosive` is highly sensitive and skips only clearly logical/complete prompts.
228
+ - **`autoPromptCritiqueModel`** — `working` uses the active model; `critique` uses the configured critique model.
229
+ - **`questions`** — when `true`, ambiguous user input triggers a clarifying Questions widget before the model receives the prompt.
230
+ - **`questionsFrequency`** — sensitivity of the Questions feature: `essential` (minimal), `normal` (moderate), or `verbose` (high; "many questions").
177
231
 
178
- The picker offers any model with configured auth that's available in pi's registry; the config persists per-machine (in `getAgentDir()`), shared across all projects.
232
+ The settings menu offers any model with configured auth that's available in pi's registry; the config persists per-machine (in `getAgentDir()`), shared across all projects.
179
233
 
180
234
  ## Architecture
181
235
 
@@ -185,28 +239,30 @@ critique/
185
239
  ├── LICENSE # MIT
186
240
  ├── README.md
187
241
  ├── docs/
188
- │ ├── banner.png # wide README header
189
- │ └── preview.png # npm pi.dev preview card
190
- ├── screenshot.png # full-res master
242
+ │ ├── banner.jpeg # wide README header
243
+ │ └── preview.jpeg # npm pi.dev preview card
191
244
  └── src/
192
- ├── index.ts # /critique command surface, model picker, review UI (≈300 lines)
193
- ├── config.ts # persistence + model resolution: pinned, auto, fallback (≈90 lines)
194
- ├── work-step.ts # episode splitting + token-budgeted serialization (≈200 lines)
195
- └── review.ts # reviewer prompt + model call + injected-message builder (≈115 lines)
245
+ ├── index.ts # /critique command surface, config UI, review UI, input hook
246
+ ├── config.ts # persistence + model resolution: pinned, auto, fallback
247
+ ├── prompt-critique.ts # automatic user-prompt critique prompt, gate, model call, questions detection
248
+ ├── work-step.ts # episode splitting + token-budgeted serialization
249
+ └── review.ts # reviewer prompt + model call + injected-message builder
196
250
  ```
197
251
 
198
- Four-file extension with zero external dependencies (only pi's bundled `@earendil-works/*` + Node built-ins):
252
+ Five-file extension with zero external dependencies (only pi's bundled `@earendil-works/*` + Node built-ins):
199
253
 
200
254
  - **Episode splitter** — splits a session branch into user-message-bounded episodes, picks the last one with work
201
255
  - **Token budgeter** — hard caps per field, marks truncations so the reviewer knows what it didn't see
202
- - **Reviewer call** — tool-free `ctx.modelRegistry.complete()` with a structured system prompt
256
+ - **Reviewer call** — tool-free `ctx.modelRegistry.complete()` with a domain-general structured prompt
203
257
  - **Advisory formatter** — wraps the review in a "non-mandatory" envelope before injecting as a follow-up user message
204
- - **UI** — paginated TUI model picker (SelectList) + Markdown review viewer + cancelable BorderedLoader
258
+ - **Prompt critique** — optional input hook with local trivial-prompt gate, three challenge levels, and ultra-short JSON model output
259
+ - **Questions detection** — heuristic ambiguity detector with three frequency levels; shows a clarifying widget with A/B/C options
260
+ - **UI** — lazy-loaded pickers/viewers/loaders + 30-second Critique widget + 30-second Questions widget
205
261
 
206
262
  ## Notes
207
263
 
208
- - The critique model runs with **no tools** and never touches the filesystem. It judges purely from the serialized work step (which includes the diffs and outputs of `edit`/`write`/`bash` calls).
209
- - In TUI mode the review runs behind a cancelable loader (Esc aborts) and `/critique view` opens a scrollable Markdown viewer. In RPC mode reviews are surfaced through notifications; print mode logs them to stdout.
264
+ - The critique model runs with **no tools** and never touches the filesystem. It judges purely from the serialized work step, whatever the domain.
265
+ - In TUI mode the review runs behind a cancelable loader (Esc aborts) and `/critique view` opens a scrollable Markdown viewer. Automatic prompt critique appears as a compact `Critique` widget with a 30-second auto-discard timeout. The Questions feature appears as a `Questions` widget with the same timeout. In RPC mode reviews are surfaced through notifications/dialogs; print mode logs manual reviews to stdout and skips automatic prompt critique and questions.
210
266
  - Provider errors (bad keys, insufficient balance, rate limit) are surfaced as errors instead of silently producing empty reviews.
211
267
  - Reviews are capped at 16,000 chars to keep the injected follow-up reasonable; longer reviews are truncated with `… [review truncated]`.
212
268
 
package/package.json CHANGED
@@ -1,15 +1,13 @@
1
1
  {
2
2
  "name": "pi-critique-model",
3
- "version": "1.0.0",
4
- "description": "A pi extension that reviews the last work step with a separate model and feeds the review back to the working model as advisory feedback. Independent reviewer with tool-free analysis, structured Markdown verdict (APPROVED / APPROVED_WITH_SUGGESTIONS / CHANGES_RECOMMENDED) and a token-budgeted context.",
3
+ "version": "1.1.0",
4
+ "description": "pi critique: work review + prompt challenge.",
5
5
  "keywords": [
6
6
  "pi-package",
7
7
  "review",
8
8
  "critique",
9
- "feedback",
10
- "code-review",
11
- "second-opinion",
12
- "advisory"
9
+ "adversarial-review",
10
+ "prompt-critique"
13
11
  ],
14
12
  "author": "Javier Noguerol <https://github.com/noguerol>",
15
13
  "license": "MIT",
package/src/config.ts CHANGED
@@ -11,16 +11,38 @@ import type { Model } from "@earendil-works/pi-ai";
11
11
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
12
12
  import { dirname, join } from "node:path";
13
13
 
14
+ import type {
15
+ AutoPromptCritiqueLevel,
16
+ AutoPromptCritiqueModelSource,
17
+ } from "./prompt-critique.ts";
18
+
19
+ export type QuestionsFrequency = "essential" | "normal" | "verbose";
20
+
14
21
  export interface CritiqueConfig {
15
22
  /** Canonical "provider/modelId" of the critique model. Empty string = auto. */
16
23
  model: string;
17
24
  /** Inject the review back into the working model automatically. */
18
25
  autoInject: boolean;
26
+ /** Challenge sufficiently rich user instructions before the agent starts. */
27
+ autoPromptCritique: boolean;
28
+ /** How adversarial the automatic prompt critique should be. */
29
+ autoPromptCritiqueLevel: AutoPromptCritiqueLevel;
30
+ /** Which model is used for automatic prompt critique. */
31
+ autoPromptCritiqueModel: AutoPromptCritiqueModelSource;
32
+ /** Ask clarifying questions when user input is ambiguous. */
33
+ questions: boolean;
34
+ /** Sensitivity level for the questions feature. */
35
+ questionsFrequency: QuestionsFrequency;
19
36
  }
20
37
 
21
38
  export const DEFAULT_CONFIG: CritiqueConfig = {
22
39
  model: "",
23
40
  autoInject: true,
41
+ autoPromptCritique: false,
42
+ autoPromptCritiqueLevel: "inconsistencies",
43
+ autoPromptCritiqueModel: "working",
44
+ questions: false,
45
+ questionsFrequency: "normal",
24
46
  };
25
47
 
26
48
  export function configFilePath(): string {
@@ -30,10 +52,31 @@ export function configFilePath(): string {
30
52
  export function loadConfig(): CritiqueConfig {
31
53
  try {
32
54
  const raw = JSON.parse(readFileSync(configFilePath(), "utf8")) as Partial<CritiqueConfig>;
55
+ const level = raw.autoPromptCritiqueLevel;
56
+ const modelSource = raw.autoPromptCritiqueModel;
57
+ const frequency = raw.questionsFrequency;
33
58
  return {
34
59
  model: typeof raw.model === "string" ? raw.model : DEFAULT_CONFIG.model,
35
60
  autoInject:
36
61
  typeof raw.autoInject === "boolean" ? raw.autoInject : DEFAULT_CONFIG.autoInject,
62
+ autoPromptCritique:
63
+ typeof raw.autoPromptCritique === "boolean"
64
+ ? raw.autoPromptCritique
65
+ : DEFAULT_CONFIG.autoPromptCritique,
66
+ autoPromptCritiqueLevel:
67
+ level === "inconsistencies" || level === "critical" || level === "corrosive"
68
+ ? level
69
+ : DEFAULT_CONFIG.autoPromptCritiqueLevel,
70
+ autoPromptCritiqueModel:
71
+ modelSource === "working" || modelSource === "critique"
72
+ ? modelSource
73
+ : DEFAULT_CONFIG.autoPromptCritiqueModel,
74
+ questions:
75
+ typeof raw.questions === "boolean" ? raw.questions : DEFAULT_CONFIG.questions,
76
+ questionsFrequency:
77
+ frequency === "essential" || frequency === "normal" || frequency === "verbose"
78
+ ? frequency
79
+ : DEFAULT_CONFIG.questionsFrequency,
37
80
  };
38
81
  } catch {
39
82
  return { ...DEFAULT_CONFIG };
@@ -46,7 +89,7 @@ export function saveConfig(config: CritiqueConfig): void {
46
89
  writeFileSync(path, JSON.stringify(config, null, 2) + "\n", "utf8");
47
90
  }
48
91
 
49
- export function modelLabel(model: Model): string {
92
+ export function modelLabel(model: Model<any>): string {
50
93
  return `${model.provider}/${model.id}`;
51
94
  }
52
95
 
@@ -55,7 +98,7 @@ export function modelLabel(model: Model): string {
55
98
  * scoping is configured, otherwise the full available catalogue. Only models
56
99
  * with configured auth are offered.
57
100
  */
58
- export function pickableModels(ctx: ExtensionContext): Model[] {
101
+ export function pickableModels(ctx: ExtensionContext): Model<any>[] {
59
102
  const scoped = (ctx.scopedModels ?? []).map((entry) => entry.model);
60
103
  const candidates = scoped.length > 0 ? scoped : ctx.modelRegistry.getAvailable();
61
104
  return candidates.filter((model) => ctx.modelRegistry.hasConfiguredAuth(model));
@@ -71,13 +114,13 @@ export function pickableModels(ctx: ExtensionContext): Model[] {
71
114
  export function resolveCritiqueModel(
72
115
  ctx: ExtensionContext,
73
116
  config: CritiqueConfig,
74
- ): Model | undefined {
117
+ ): Model<any> | undefined {
75
118
  if (config.model) {
76
119
  const slash = config.model.indexOf("/");
77
120
  const provider = slash >= 0 ? config.model.slice(0, slash) : config.model;
78
121
  const id = slash >= 0 ? config.model.slice(slash + 1) : config.model;
79
122
  const model = ctx.modelRegistry.find(provider, id);
80
- return model && ctx.modelRegistry.hasConfiguredAuth(model) ? model : undefined;
123
+ if (model && ctx.modelRegistry.hasConfiguredAuth(model)) return model;
81
124
  }
82
125
 
83
126
  const candidates = pickableModels(ctx);
@@ -87,3 +130,14 @@ export function resolveCritiqueModel(
87
130
  );
88
131
  return different ?? working ?? candidates[0];
89
132
  }
133
+
134
+ /** Resolve the model used by automatic prompt critique. */
135
+ export function resolveAutoPromptCritiqueModel(
136
+ ctx: ExtensionContext,
137
+ config: CritiqueConfig,
138
+ ): Model<any> | undefined {
139
+ if (config.autoPromptCritiqueModel === "working") {
140
+ return ctx.model ?? pickableModels(ctx)[0];
141
+ }
142
+ return resolveCritiqueModel(ctx, config) ?? ctx.model ?? pickableModels(ctx)[0];
143
+ }