@juicesharp/rpiv-advisor 1.17.0 → 1.18.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 +1 -1
- package/advisor/command.ts +2 -1
- package/advisor/config.ts +0 -10
- package/advisor/handlers.ts +1 -1
- package/advisor/policy.ts +16 -3
- package/advisor/restore.ts +4 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Let the model ask a stronger model for a second opinion before it acts. `rpiv-ad
|
|
|
14
14
|
|
|
15
15
|
## Features
|
|
16
16
|
|
|
17
|
-
- **Reviewer model selector** - `/advisor` opens a picker over any model in Pi's registry, plus a reasoning-effort picker for reasoning-capable models. Start typing to fuzzy-filter the list by model name or `provider
|
|
17
|
+
- **Reviewer model selector** - `/advisor` opens a picker over any model in Pi's registry, plus a reasoning-effort picker for reasoning-capable models. Start typing to fuzzy-filter the list by model name or `provider/id`.
|
|
18
18
|
- **Persisted across sessions** - selection saved at `~/.config/rpiv-advisor/advisor.json` (chmod 0600).
|
|
19
19
|
- **Off by default** - the `advisor` tool is excluded until you pick a model; choose "No advisor" to disable.
|
|
20
20
|
- **Per-executor blocklist** - list executor models in `disabledForModels` (in `advisor.json`) to strip the `advisor` tool when those models drive the session. Entries can be plain strings (block at any effort) or `{ "model": "<provider:id>", "minEffort": "<level>" }` to block only when the executor's effort meets or exceeds the threshold. Available levels, lowest to highest: `minimal`, `low`, `medium`, `high`, `xhigh`.
|
package/advisor/command.ts
CHANGED
|
@@ -9,8 +9,9 @@ import type { Api, Model } from "@earendil-works/pi-ai";
|
|
|
9
9
|
import { getSupportedThinkingLevels, type ThinkingLevel } from "@earendil-works/pi-ai";
|
|
10
10
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
11
11
|
import type { SelectItem } from "@earendil-works/pi-tui";
|
|
12
|
+
import { modelKey } from "@juicesharp/rpiv-config";
|
|
12
13
|
import { showAdvisorPicker, showEffortPicker } from "../advisor-ui.js";
|
|
13
|
-
import {
|
|
14
|
+
import { saveAdvisorConfig } from "./config.js";
|
|
14
15
|
import { reconcileAdvisorTool } from "./handlers.js";
|
|
15
16
|
import {
|
|
16
17
|
ADVISOR_TOOL_NAME,
|
package/advisor/config.ts
CHANGED
|
@@ -48,13 +48,3 @@ export function saveAdvisorConfig(key: string | undefined, effort: ThinkingLevel
|
|
|
48
48
|
else delete config.effort;
|
|
49
49
|
return saveJsonConfig(ADVISOR_CONFIG_PATH, config);
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
export function parseModelKey(key: string): { provider: string; modelId: string } | undefined {
|
|
53
|
-
const idx = key.indexOf(":");
|
|
54
|
-
if (idx < 1) return undefined;
|
|
55
|
-
return { provider: key.slice(0, idx), modelId: key.slice(idx + 1) };
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function modelKey(m: { provider: string; id: string }): string {
|
|
59
|
-
return `${m.provider}:${m.id}`;
|
|
60
|
-
}
|
package/advisor/handlers.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
9
|
-
import { modelKey } from "
|
|
9
|
+
import { modelKey } from "@juicesharp/rpiv-config";
|
|
10
10
|
import { ADVISOR_TOOL_NAME, MSG_ADVISOR_DISABLED, msgAdvisorRestored } from "./messages.js";
|
|
11
11
|
import { isExecutorBlocked, isModelBlocked } from "./policy.js";
|
|
12
12
|
import { getAdvisorEffort, getAdvisorModel } from "./state.js";
|
package/advisor/policy.ts
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import type { Api, Model, ThinkingLevel } from "@earendil-works/pi-ai";
|
|
7
7
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
import {
|
|
8
|
+
import { modelKey, parseModelKey } from "@juicesharp/rpiv-config";
|
|
9
|
+
import type { DisabledForModelsEntry } from "./config.js";
|
|
9
10
|
import { EFFORT_ORDINAL } from "./messages.js";
|
|
10
11
|
|
|
11
12
|
let disabledForModelsCache: DisabledForModelsEntry[] = [];
|
|
@@ -14,14 +15,26 @@ export function setDisabledForModels(models: DisabledForModelsEntry[]): void {
|
|
|
14
15
|
disabledForModelsCache = models;
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Normalise a stored blocklist entry's model key to the canonical slash form.
|
|
20
|
+
* Tolerates legacy colon-form persisted lists so `disabledForModels:
|
|
21
|
+
* ["anthropic:sonnet"]` keeps blocking post-slash-canonical-migration without
|
|
22
|
+
* requiring a re-save. Pass-through for already-canonical (slash) values and
|
|
23
|
+
* for malformed input.
|
|
24
|
+
*/
|
|
25
|
+
function canonicalKey(entry: string): string {
|
|
26
|
+
const parsed = parseModelKey(entry);
|
|
27
|
+
return parsed ? `${parsed.provider}/${parsed.modelId}` : entry;
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
export function isModelBlocked(model: Model<Api> | undefined, thinkingLevel?: string): boolean {
|
|
18
31
|
if (!model) return false;
|
|
19
32
|
const key = modelKey(model);
|
|
20
33
|
for (const entry of disabledForModelsCache) {
|
|
21
34
|
if (typeof entry === "string") {
|
|
22
|
-
if (entry === key) return true;
|
|
35
|
+
if (canonicalKey(entry) === key) return true;
|
|
23
36
|
} else {
|
|
24
|
-
if (entry.model !== key) continue;
|
|
37
|
+
if (canonicalKey(entry.model) !== key) continue;
|
|
25
38
|
if (entry.minEffort === undefined) return true;
|
|
26
39
|
const thresholdOrdinal = EFFORT_ORDINAL.indexOf(entry.minEffort);
|
|
27
40
|
const executorOrdinal = EFFORT_ORDINAL.indexOf(thinkingLevel as ThinkingLevel);
|
package/advisor/restore.ts
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
8
|
-
import {
|
|
8
|
+
import { modelKey, parseModelKey } from "@juicesharp/rpiv-config";
|
|
9
|
+
import { loadAdvisorConfig, validateDisabledForModels } from "./config.js";
|
|
9
10
|
import { ADVISOR_TOOL_NAME, errModelUnavailable, msgAdvisorRestored, msgAdvisorRestoredInactive } from "./messages.js";
|
|
10
11
|
import { isExecutorBlocked, setDisabledForModels } from "./policy.js";
|
|
11
12
|
import { setAdvisorEffort, setAdvisorModel } from "./state.js";
|
|
@@ -54,7 +55,7 @@ export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): vo
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
if (isExecutorBlocked(ctx, pi.getThinkingLevel())) {
|
|
57
|
-
const advisorLabel =
|
|
58
|
+
const advisorLabel = modelKey(model);
|
|
58
59
|
notifyOnce(msgAdvisorRestoredInactive(advisorLabel, config.effort), "info");
|
|
59
60
|
return;
|
|
60
61
|
}
|
|
@@ -64,7 +65,7 @@ export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): vo
|
|
|
64
65
|
pi.setActiveTools([...active, ADVISOR_TOOL_NAME]);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
notifyOnce(msgAdvisorRestored(
|
|
68
|
+
notifyOnce(msgAdvisorRestored(modelKey(model), config.effort), "info");
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
export function registerAdvisorSessionStart(pi: ExtensionAPI): void {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juicesharp/rpiv-advisor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "Pi extension. A second opinion the model can request from a stronger reviewer model before it acts.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
]
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@juicesharp/rpiv-config": "^1.
|
|
44
|
+
"@juicesharp/rpiv-config": "^1.18.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@earendil-works/pi-ai": "*",
|