@hk_net/pi-advisor 0.1.3 → 0.1.5
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 +14 -0
- package/README.md +5 -4
- package/advisor.ts +119 -51
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.5 - 2026-07-20
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Correct and clarify the current Pi compatibility and autocomplete documentation.
|
|
8
|
+
|
|
9
|
+
## 0.1.4 - 2026-07-20
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Derive advisor thinking-level choices from Pi's supported levels for the selected reviewer model.
|
|
14
|
+
- Add `max` support where the selected reviewer model exposes it.
|
|
15
|
+
- Improve `/advisor` autocomplete: `/adviso...` completes without a trailing space; model completion leads to that model's thinking-level picker; `on-done` and `when-stuck` open their value pickers directly.
|
|
16
|
+
|
|
3
17
|
## 0.1.3 - 2026-06-24
|
|
4
18
|
|
|
5
19
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-advisor
|
|
2
2
|
|
|
3
|
-
A [pi](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) extension that offers a
|
|
3
|
+
A [pi](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) extension for pi `>=0.80.10` that offers a
|
|
4
4
|
parameterless `advisor` tool — inspired by Claude Code's advisor, but expanded with additional
|
|
5
5
|
nudges and a manual review procedure. The regular model calls `advisor` to get a second opinion
|
|
6
6
|
from an explicitly configured **stronger reviewer model** that sees the *entire* conversation transcript. Beyond the
|
|
@@ -66,7 +66,7 @@ JSON, resolved **project-over-global** (first scope that defines a key wins):
|
|
|
66
66
|
```jsonc
|
|
67
67
|
{
|
|
68
68
|
"model": "openai-codex/gpt-5.5", // "provider/id", or "none" to disable + hide the tool
|
|
69
|
-
"thinking": "high", //
|
|
69
|
+
"thinking": "high", // a level supported by the selected reviewer model (default high)
|
|
70
70
|
"onDone": false, // auto-review when the agent finishes a task
|
|
71
71
|
"whenStuck": 0, // auto-consult after N consecutive errors or N repeated identical tool calls (0 = off)
|
|
72
72
|
"timeoutMs": 120000 // advisor call timeout in ms (0 = use provider default)
|
|
@@ -100,6 +100,8 @@ are selectable.
|
|
|
100
100
|
| `/advisor status` | Show the resolved configuration |
|
|
101
101
|
| `/advise [show\|pipe\|steer]` | Run a one-off review now; default is `pipe` when idle and `steer` while the agent is running |
|
|
102
102
|
|
|
103
|
+
Autocomplete completes `/adviso...` to `/advisor` without Pi's trailing-space insertion. A completed reviewer model opens that model's supported thinking-level picker on the next Tab. `/advisor on-done` and `/advisor when-stuck` open their value pickers directly. `/advise` keeps Pi's standard completion behavior.
|
|
104
|
+
|
|
103
105
|
### `/advise` modes
|
|
104
106
|
|
|
105
107
|
- **`/advise`** — quick advice injection: sends feedback as a user message when idle, or as a
|
|
@@ -168,5 +170,4 @@ tool's `promptGuidelines`. Two opt-in deterministic triggers, configurable per p
|
|
|
168
170
|
also layers a `ctx.ui.addAutocompleteProvider()` on `session_start` so `/advisor ...` and
|
|
169
171
|
`/advise ...` completions replace the whole argument segment and suppress irrelevant path
|
|
170
172
|
completion while typing command arguments (pi ≥ 0.79.1).
|
|
171
|
-
-
|
|
172
|
-
`0.80.1`, import legacy `complete()` calls from `@earendil-works/pi-ai/compat`.
|
|
173
|
+
- Use `complete()` from `@earendil-works/pi-ai/compat` for Pi's compatibility streaming helper.
|
package/advisor.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* {
|
|
16
16
|
* "model": "provider/id" | "none", // "none" disables + hides the tool
|
|
17
|
-
* "thinking":"
|
|
17
|
+
* "thinking":"<model-supported level>", // default "high"
|
|
18
18
|
* "onDone": true, // auto-review when the agent finishes (default off)
|
|
19
19
|
* "whenStuck": 3, // auto-consult after N consecutive tool errors (0/off)
|
|
20
20
|
* "timeoutMs": 120000 // advisor call timeout in ms (0 = use provider default)
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
* call advisor, nudged by the tool's prompt guidelines. The optional deterministic
|
|
41
41
|
* triggers and `/advise` command provide additional ways to request reviewer feedback.
|
|
42
42
|
*/
|
|
43
|
-
import { Type } from "@earendil-works/pi-ai";
|
|
44
|
-
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
43
|
+
import { getSupportedThinkingLevels, Type } from "@earendil-works/pi-ai";
|
|
44
|
+
import type { Api, Model, ModelThinkingLevel } from "@earendil-works/pi-ai";
|
|
45
45
|
import { complete } from "@earendil-works/pi-ai/compat";
|
|
46
46
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
47
47
|
import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
|
@@ -51,9 +51,8 @@ import * as fs from "node:fs";
|
|
|
51
51
|
import * as os from "node:os";
|
|
52
52
|
import * as path from "node:path";
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const DEFAULT_THINKING: ThinkingLevel = "high";
|
|
54
|
+
type ThinkingLevel = ModelThinkingLevel;
|
|
55
|
+
const DEFAULT_THINKING = "high";
|
|
57
56
|
const DISABLED = "none";
|
|
58
57
|
const MAX_VISIBLE_MODEL_CHOICES = 12;
|
|
59
58
|
export const MAX_TOOL_CALL_ARGS_CHARS = 800;
|
|
@@ -71,23 +70,21 @@ const ADVISOR_FIRST_TOKEN_ITEMS: AutocompleteItem[] = [
|
|
|
71
70
|
{ value: "?", label: "?", description: "Show /advisor usage" },
|
|
72
71
|
];
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
off: "Disable extended thinking",
|
|
76
|
-
minimal: "Smallest available thinking budget",
|
|
77
|
-
low: "Light reasoning",
|
|
78
|
-
medium: "Balanced default reasoning",
|
|
79
|
-
high: "More reasoning for harder tasks",
|
|
80
|
-
xhigh: "Maximum reasoning budget",
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// Cached model list for autocomplete (refreshed on session_start)
|
|
73
|
+
// Cached model list for autocomplete (refreshed on session_start).
|
|
84
74
|
let cachedModelSpecs: string[] = [];
|
|
75
|
+
let cachedModels = new Map<string, Model<Api>>();
|
|
76
|
+
|
|
77
|
+
function cacheModels(models: Model<Api>[]): void {
|
|
78
|
+
cachedModels = new Map(models.map((model) => [`${model.provider}/${model.id}`, model]));
|
|
79
|
+
cachedModelSpecs = [...cachedModels.keys()].sort();
|
|
80
|
+
}
|
|
85
81
|
|
|
86
|
-
function thinkingLevelItems(prefix: string): AutocompleteItem[] {
|
|
82
|
+
function thinkingLevelItems(model: Model<Api> | undefined, prefix: string): AutocompleteItem[] {
|
|
83
|
+
if (!model) return [];
|
|
87
84
|
const normalized = prefix.toLowerCase().trim();
|
|
88
|
-
return (
|
|
85
|
+
return getSupportedThinkingLevels(model)
|
|
89
86
|
.filter((level) => level.startsWith(normalized))
|
|
90
|
-
.map((level) => ({ value: level, label: level, description:
|
|
87
|
+
.map((level) => ({ value: level, label: level, description: "Supported by this reviewer model" }));
|
|
91
88
|
}
|
|
92
89
|
|
|
93
90
|
export function getAdvisorCompletions(args: string): AutocompleteItem[] | null {
|
|
@@ -99,12 +96,11 @@ export function getAdvisorCompletions(args: string): AutocompleteItem[] | null {
|
|
|
99
96
|
const normalized = prefix.toLowerCase();
|
|
100
97
|
|
|
101
98
|
if (tokens.length === 0) {
|
|
102
|
-
// No tokens yet — suggest subcommands
|
|
103
|
-
const levels = thinkingLevelItems(prefix);
|
|
99
|
+
// No tokens yet — suggest subcommands and available reviewer models.
|
|
104
100
|
const models = cachedModelSpecs
|
|
105
101
|
.filter((spec) => spec.toLowerCase().includes(normalized))
|
|
106
102
|
.map((spec) => ({ value: spec, label: spec }));
|
|
107
|
-
return [...ADVISOR_FIRST_TOKEN_ITEMS, ...
|
|
103
|
+
return [...ADVISOR_FIRST_TOKEN_ITEMS, ...models];
|
|
108
104
|
}
|
|
109
105
|
|
|
110
106
|
const head = tokens[0].toLowerCase();
|
|
@@ -127,14 +123,27 @@ export function getAdvisorCompletions(args: string): AutocompleteItem[] | null {
|
|
|
127
123
|
return []; // These are terminal commands
|
|
128
124
|
}
|
|
129
125
|
|
|
126
|
+
// A model plus thinking level is a complete /advisor command. Do not offer
|
|
127
|
+
// another level picker after the user types a trailing space.
|
|
128
|
+
if (tokens.length > 1 && hasTrailingSpace) return [];
|
|
129
|
+
|
|
130
130
|
if (completingSecondToken) {
|
|
131
|
-
return thinkingLevelItems(prefix).map((item) => ({
|
|
131
|
+
return thinkingLevelItems(cachedModels.get(tokens[0]), prefix).map((item) => ({
|
|
132
|
+
...item,
|
|
133
|
+
value: `${tokens[0]} ${item.value}`,
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// After model-name completion, a further Tab opens that model's level picker.
|
|
138
|
+
const exactModel = cachedModels.get(tokens[0]);
|
|
139
|
+
if (exactModel) {
|
|
140
|
+
return thinkingLevelItems(exactModel, "").map((item) => ({
|
|
132
141
|
...item,
|
|
133
142
|
value: `${tokens[0]} ${item.value}`,
|
|
134
143
|
}));
|
|
135
144
|
}
|
|
136
145
|
|
|
137
|
-
// First token: could be a subcommand
|
|
146
|
+
// First token: could be a subcommand or model spec — prefer explicit commands.
|
|
138
147
|
const firstTokenMatches = ADVISOR_FIRST_TOKEN_ITEMS.filter((item) => item.value.startsWith(normalized));
|
|
139
148
|
const modelMatches = cachedModelSpecs
|
|
140
149
|
.filter((spec) => spec.toLowerCase().includes(normalized))
|
|
@@ -142,7 +151,7 @@ export function getAdvisorCompletions(args: string): AutocompleteItem[] | null {
|
|
|
142
151
|
if (firstTokenMatches.length > 0 || modelMatches.length > 0) {
|
|
143
152
|
return [...firstTokenMatches, ...modelMatches];
|
|
144
153
|
}
|
|
145
|
-
return
|
|
154
|
+
return [];
|
|
146
155
|
}
|
|
147
156
|
|
|
148
157
|
function getAdviseCompletions(prefix: string): AutocompleteItem[] | null {
|
|
@@ -160,6 +169,10 @@ function commandArgumentCompletions(command: "advisor" | "advise", args: string)
|
|
|
160
169
|
return { prefix: args, items };
|
|
161
170
|
}
|
|
162
171
|
|
|
172
|
+
function isAdvisorCommandPrefix(value: string): boolean {
|
|
173
|
+
return value.startsWith("/adviso") && "/advisor".startsWith(value);
|
|
174
|
+
}
|
|
175
|
+
|
|
163
176
|
export type AdviseMode = "show" | "pipe" | "steer";
|
|
164
177
|
|
|
165
178
|
export function resolveAdviseMode(args: string | undefined, isIdle: boolean): AdviseMode | undefined {
|
|
@@ -198,7 +211,7 @@ Always return your advice as visible assistant text. Do not return reasoning-onl
|
|
|
198
211
|
|
|
199
212
|
type AdvisorConfig = {
|
|
200
213
|
model?: string;
|
|
201
|
-
thinking?:
|
|
214
|
+
thinking?: string;
|
|
202
215
|
onDone?: boolean;
|
|
203
216
|
whenStuck?: number;
|
|
204
217
|
timeoutMs?: number;
|
|
@@ -222,10 +235,10 @@ export function validateAdvisorConfig(raw: unknown, source = "advisor config"):
|
|
|
222
235
|
else warn('"model" must be a string');
|
|
223
236
|
}
|
|
224
237
|
if (input.thinking !== undefined) {
|
|
225
|
-
if (typeof input.thinking === "string" &&
|
|
226
|
-
clean.thinking = input.thinking
|
|
238
|
+
if (typeof input.thinking === "string" && input.thinking.trim()) {
|
|
239
|
+
clean.thinking = input.thinking.trim();
|
|
227
240
|
} else {
|
|
228
|
-
warn(
|
|
241
|
+
warn('"thinking" must be a non-empty string');
|
|
229
242
|
}
|
|
230
243
|
}
|
|
231
244
|
if (input.onDone !== undefined) {
|
|
@@ -279,15 +292,14 @@ const DEFAULT_TIMEOUT_MS = 120_000; // 2 minutes
|
|
|
279
292
|
type EffectiveAdvisorConfig = {
|
|
280
293
|
spec: string | undefined;
|
|
281
294
|
source: string;
|
|
282
|
-
thinking:
|
|
295
|
+
thinking: string;
|
|
283
296
|
onDone: boolean;
|
|
284
297
|
whenStuck: number;
|
|
285
298
|
timeoutMs: number;
|
|
286
299
|
};
|
|
287
300
|
|
|
288
|
-
function envThinkingLevel():
|
|
289
|
-
|
|
290
|
-
return env && (THINKING_LEVELS as readonly string[]).includes(env) ? (env as ThinkingLevel) : undefined;
|
|
301
|
+
function envThinkingLevel(): string | undefined {
|
|
302
|
+
return process.env.PI_ADVISOR_EFFORT?.trim() || undefined;
|
|
291
303
|
}
|
|
292
304
|
|
|
293
305
|
function envTimeoutMs(): number | undefined {
|
|
@@ -332,7 +344,7 @@ function effectiveModelSpec(cwd: string, projectTrusted = true): { spec: string
|
|
|
332
344
|
return { spec, source };
|
|
333
345
|
}
|
|
334
346
|
|
|
335
|
-
function effectiveThinking(cwd: string, projectTrusted = true):
|
|
347
|
+
function effectiveThinking(cwd: string, projectTrusted = true): string {
|
|
336
348
|
return resolveEffectiveConfig(cwd, projectTrusted).thinking;
|
|
337
349
|
}
|
|
338
350
|
|
|
@@ -396,7 +408,7 @@ async function resolveAdvisor(ctx: ExtensionContext): Promise<Resolved | null> {
|
|
|
396
408
|
const cwd = ctx.cwd;
|
|
397
409
|
const projectTrusted = contextProjectTrusted(ctx);
|
|
398
410
|
const { spec, source } = effectiveModelSpec(cwd, projectTrusted);
|
|
399
|
-
const
|
|
411
|
+
const requestedThinking = effectiveThinking(cwd, projectTrusted);
|
|
400
412
|
const timeoutMs = effectiveTimeoutMs(cwd, projectTrusted);
|
|
401
413
|
const warnings: string[] = [];
|
|
402
414
|
|
|
@@ -404,14 +416,23 @@ async function resolveAdvisor(ctx: ExtensionContext): Promise<Resolved | null> {
|
|
|
404
416
|
|
|
405
417
|
// Refresh before resolving so OAuth/subscription-backed model mutations and
|
|
406
418
|
// newly logged-in providers are visible to advisor just like they are to /model.
|
|
407
|
-
refreshAvailableModels(ctx);
|
|
419
|
+
cacheModels(refreshAvailableModels(ctx));
|
|
408
420
|
|
|
409
421
|
if (!spec) {
|
|
410
422
|
throw new Error("Advisor is not configured. Choose a trusted reviewer model with /advisor before sending transcripts.");
|
|
411
423
|
}
|
|
412
424
|
|
|
413
425
|
const hit = await tryModel(ctx, spec);
|
|
414
|
-
if (hit)
|
|
426
|
+
if (hit) {
|
|
427
|
+
const supported = getSupportedThinkingLevels(hit.model);
|
|
428
|
+
const thinking = supported.includes(requestedThinking as ThinkingLevel)
|
|
429
|
+
? (requestedThinking as ThinkingLevel)
|
|
430
|
+
: (supported.includes(DEFAULT_THINKING) ? DEFAULT_THINKING : supported[0] ?? "off");
|
|
431
|
+
if (thinking !== requestedThinking) {
|
|
432
|
+
warnings.push(`Thinking level "${requestedThinking}" is unsupported by ${spec}; using "${thinking}".`);
|
|
433
|
+
}
|
|
434
|
+
return { ...hit, thinking, timeoutMs, warnings };
|
|
435
|
+
}
|
|
415
436
|
|
|
416
437
|
throw new Error(
|
|
417
438
|
`Configured advisor model "${spec}" (${source}) is unavailable or lacks auth. Choose another model with /advisor or set PI_ADVISOR_MODEL.`,
|
|
@@ -677,9 +698,7 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
677
698
|
|
|
678
699
|
pi.on("session_start", async (_event, ctx) => {
|
|
679
700
|
// Cache model specs for autocomplete.
|
|
680
|
-
|
|
681
|
-
.map((m) => `${m.provider}/${m.id}`)
|
|
682
|
-
.sort();
|
|
701
|
+
cacheModels(refreshAvailableModels(ctx));
|
|
683
702
|
stuckErrors = 0;
|
|
684
703
|
autoReviewedThisRound = false;
|
|
685
704
|
applyActivation(ctx.cwd, contextProjectTrusted(ctx));
|
|
@@ -694,8 +713,24 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
694
713
|
async getSuggestions(lines, cursorLine, cursorCol, options) {
|
|
695
714
|
const line = lines[cursorLine] ?? "";
|
|
696
715
|
const beforeCursor = line.slice(0, cursorCol);
|
|
697
|
-
|
|
716
|
+
if (cursorCol === line.length && isAdvisorCommandPrefix(beforeCursor)) {
|
|
717
|
+
if (beforeCursor === "/advisor") {
|
|
718
|
+
return { prefix: "", items: getAdvisorCompletions("") ?? [] };
|
|
719
|
+
}
|
|
720
|
+
return {
|
|
721
|
+
prefix: beforeCursor,
|
|
722
|
+
items: [{ value: "advisor", label: "advisor", description: "Configure the advisor" }],
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
if (beforeCursor === "/advisor ") {
|
|
726
|
+
return { prefix: "", items: getAdvisorCompletions("") ?? [] };
|
|
727
|
+
}
|
|
728
|
+
const triggerMatch = beforeCursor.match(/^\/advisor\s+(on-done|when-stuck)$/);
|
|
729
|
+
if (triggerMatch && cursorCol === line.length) {
|
|
730
|
+
return { prefix: "", items: getAdvisorCompletions(`${triggerMatch[1]} `) ?? [] };
|
|
731
|
+
}
|
|
698
732
|
|
|
733
|
+
const match = beforeCursor.match(/^\/(advisor|advise)\s+(.*)$/);
|
|
699
734
|
if (!match) return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
700
735
|
|
|
701
736
|
const command = match[1] as "advisor" | "advise";
|
|
@@ -704,13 +739,40 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
704
739
|
},
|
|
705
740
|
|
|
706
741
|
applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
|
|
742
|
+
const line = lines[cursorLine] ?? "";
|
|
743
|
+
const beforeCursor = line.slice(0, cursorCol);
|
|
744
|
+
if (cursorCol === line.length && isAdvisorCommandPrefix(beforeCursor)) {
|
|
745
|
+
if (beforeCursor !== "/advisor") {
|
|
746
|
+
return {
|
|
747
|
+
lines: [...lines.slice(0, cursorLine), "/advisor", ...lines.slice(cursorLine + 1)],
|
|
748
|
+
cursorLine,
|
|
749
|
+
cursorCol: "/advisor".length,
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
const nextLine = `/advisor ${item.value}`;
|
|
753
|
+
return {
|
|
754
|
+
lines: [...lines.slice(0, cursorLine), nextLine, ...lines.slice(cursorLine + 1)],
|
|
755
|
+
cursorLine,
|
|
756
|
+
cursorCol: nextLine.length,
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
if (
|
|
760
|
+
(beforeCursor === "/advisor " || /^\/advisor\s+(on-done|when-stuck)$/.test(beforeCursor)) &&
|
|
761
|
+
cursorCol === line.length
|
|
762
|
+
) {
|
|
763
|
+
const nextLine = `/advisor ${item.value}`;
|
|
764
|
+
return {
|
|
765
|
+
lines: [...lines.slice(0, cursorLine), nextLine, ...lines.slice(cursorLine + 1)],
|
|
766
|
+
cursorLine,
|
|
767
|
+
cursorCol: nextLine.length,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
707
770
|
return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
|
|
708
771
|
},
|
|
709
772
|
|
|
710
773
|
shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
if (/^\/(advisor|advise)\s+/.test(beforeCursor)) return false;
|
|
774
|
+
// Let Tab reach getSuggestions(). This provider handles advisor syntax
|
|
775
|
+
// before the built-in file provider is consulted.
|
|
714
776
|
return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;
|
|
715
777
|
},
|
|
716
778
|
}));
|
|
@@ -895,7 +957,7 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
895
957
|
const tokens = (args ?? "").trim().split(/\s+/).filter(Boolean);
|
|
896
958
|
const cwd = ctx.cwd;
|
|
897
959
|
const head = tokens[0]?.toLowerCase();
|
|
898
|
-
refreshAvailableModels(ctx);
|
|
960
|
+
cacheModels(refreshAvailableModels(ctx));
|
|
899
961
|
|
|
900
962
|
if (head === "?") {
|
|
901
963
|
ctx.ui.notify(
|
|
@@ -987,10 +1049,13 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
987
1049
|
}
|
|
988
1050
|
modelValue = tokens[0];
|
|
989
1051
|
if (tokens[1]) {
|
|
990
|
-
|
|
991
|
-
|
|
1052
|
+
const model = ctx.modelRegistry.find(parsed.provider, parsed.id);
|
|
1053
|
+
const supported = model ? getSupportedThinkingLevels(model) : [];
|
|
1054
|
+
const requested = tokens[1].toLowerCase() as ThinkingLevel;
|
|
1055
|
+
if (!supported.includes(requested)) {
|
|
1056
|
+
return ctx.ui.notify(`Invalid thinking level "${tokens[1]}". Supported: ${supported.join(", ") || "off"}.`, "error");
|
|
992
1057
|
}
|
|
993
|
-
thinkingArg =
|
|
1058
|
+
thinkingArg = requested;
|
|
994
1059
|
}
|
|
995
1060
|
}
|
|
996
1061
|
|
|
@@ -998,11 +1063,14 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
998
1063
|
if (!file) return;
|
|
999
1064
|
|
|
1000
1065
|
let thinking = thinkingArg;
|
|
1001
|
-
if (!thinking && modelValue !== DISABLED && tokens.length === 0) {
|
|
1066
|
+
if (!thinking && modelValue !== DISABLED && tokens.length === 0 && modelValue) {
|
|
1067
|
+
const parsed = parseSpec(modelValue);
|
|
1068
|
+
const model = parsed ? ctx.modelRegistry.find(parsed.provider, parsed.id) : undefined;
|
|
1069
|
+
const supported = model ? getSupportedThinkingLevels(model) : [];
|
|
1002
1070
|
const KEEP = "keep current";
|
|
1003
|
-
const pick = await ctx.ui.select("Thinking level", [
|
|
1071
|
+
const pick = await ctx.ui.select("Thinking level", [...supported, KEEP]);
|
|
1004
1072
|
if (pick === undefined) return;
|
|
1005
|
-
if (pick !== KEEP) thinking = pick
|
|
1073
|
+
if (pick !== KEEP) thinking = pick as ThinkingLevel;
|
|
1006
1074
|
}
|
|
1007
1075
|
|
|
1008
1076
|
persist(file, { model: modelValue, ...(thinking ? { thinking } : {}) });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hk_net/pi-advisor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Pi advisor extension: consult a configured reviewer model on the full conversation transcript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"CHANGELOG.md"
|
|
28
28
|
],
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@earendil-works/pi-ai": ">=0.80.
|
|
31
|
-
"@earendil-works/pi-coding-agent": ">=0.80.
|
|
32
|
-
"@earendil-works/pi-tui": ">=0.80.
|
|
30
|
+
"@earendil-works/pi-ai": ">=0.80.10",
|
|
31
|
+
"@earendil-works/pi-coding-agent": ">=0.80.10",
|
|
32
|
+
"@earendil-works/pi-tui": ">=0.80.10"
|
|
33
33
|
},
|
|
34
34
|
"pi": {
|
|
35
35
|
"extensions": [
|