@juicesharp/rpiv-advisor 1.8.2 → 1.9.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/advisor.ts +70 -14
- package/index.ts +5 -2
- package/package.json +2 -2
package/advisor.ts
CHANGED
|
@@ -50,6 +50,7 @@ const OFF_VALUE = "__off__";
|
|
|
50
50
|
// Effort levels
|
|
51
51
|
const BASE_EFFORT_LEVELS: ThinkingLevel[] = ["minimal", "low", "medium", "high"];
|
|
52
52
|
const XHIGH_EFFORT_LEVEL: ThinkingLevel = "xhigh";
|
|
53
|
+
const EFFORT_ORDINAL: readonly ThinkingLevel[] = ["minimal", "low", "medium", "high", "xhigh"];
|
|
53
54
|
const DEFAULT_EFFORT: ThinkingLevel = "high";
|
|
54
55
|
const RECOMMENDED_EFFORT_SUFFIX = " (recommended)";
|
|
55
56
|
|
|
@@ -98,7 +99,7 @@ interface AdvisorConfig {
|
|
|
98
99
|
modelKey?: string;
|
|
99
100
|
effort?: ThinkingLevel;
|
|
100
101
|
guidance?: GuidanceFields;
|
|
101
|
-
disabledForModels?: string
|
|
102
|
+
disabledForModels?: Array<string | { model: string; minEffort?: ThinkingLevel }>;
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
export function loadAdvisorConfig(): AdvisorConfig {
|
|
@@ -107,9 +108,16 @@ export function loadAdvisorConfig(): AdvisorConfig {
|
|
|
107
108
|
|
|
108
109
|
// validateGuidanceFields is now imported from @juicesharp/rpiv-config
|
|
109
110
|
|
|
110
|
-
function validateDisabledForModels(value: unknown): string
|
|
111
|
+
function validateDisabledForModels(value: unknown): Array<string | { model: string; minEffort?: ThinkingLevel }> {
|
|
111
112
|
if (!Array.isArray(value)) return [];
|
|
112
|
-
return value.filter((entry): entry is string
|
|
113
|
+
return value.filter((entry): entry is string | { model: string; minEffort?: ThinkingLevel } => {
|
|
114
|
+
if (typeof entry === "string") return entry.length > 0;
|
|
115
|
+
if (typeof entry !== "object" || entry === null) return false;
|
|
116
|
+
const obj = entry as Record<string, unknown>;
|
|
117
|
+
if (typeof obj.model !== "string" || obj.model.length === 0) return false;
|
|
118
|
+
if (obj.minEffort !== undefined && !EFFORT_ORDINAL.includes(obj.minEffort as ThinkingLevel)) return false;
|
|
119
|
+
return true;
|
|
120
|
+
});
|
|
113
121
|
}
|
|
114
122
|
|
|
115
123
|
export function saveAdvisorConfig(key: string | undefined, effort: ThinkingLevel | undefined): boolean {
|
|
@@ -271,9 +279,9 @@ export function setAdvisorEffort(effort: ThinkingLevel | undefined): void {
|
|
|
271
279
|
selectedAdvisorEffort = effort;
|
|
272
280
|
}
|
|
273
281
|
|
|
274
|
-
let disabledForModelsCache: string
|
|
282
|
+
let disabledForModelsCache: Array<string | { model: string; minEffort?: ThinkingLevel }> = [];
|
|
275
283
|
|
|
276
|
-
export function setDisabledForModels(models: string
|
|
284
|
+
export function setDisabledForModels(models: Array<string | { model: string; minEffort?: ThinkingLevel }>): void {
|
|
277
285
|
disabledForModelsCache = models;
|
|
278
286
|
}
|
|
279
287
|
|
|
@@ -304,7 +312,7 @@ export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): vo
|
|
|
304
312
|
setAdvisorEffort(config.effort);
|
|
305
313
|
}
|
|
306
314
|
|
|
307
|
-
if (isExecutorBlocked(ctx)) {
|
|
315
|
+
if (isExecutorBlocked(ctx, pi.getThinkingLevel())) {
|
|
308
316
|
if (ctx.hasUI) {
|
|
309
317
|
const advisorLabel = `${model.provider}:${model.id}`;
|
|
310
318
|
ctx.ui.notify(msgAdvisorRestoredInactive(advisorLabel, config.effort), "info");
|
|
@@ -503,12 +511,21 @@ export function registerAdvisorTool(pi: ExtensionAPI): void {
|
|
|
503
511
|
|
|
504
512
|
export function registerAdvisorBeforeAgentStart(pi: ExtensionAPI): void {
|
|
505
513
|
pi.on("before_agent_start", async (_event, ctx) => {
|
|
506
|
-
const
|
|
507
|
-
if (
|
|
514
|
+
const advisor = getAdvisorModel();
|
|
515
|
+
if (!advisor) {
|
|
508
516
|
const active = pi.getActiveTools();
|
|
509
517
|
if (active.includes(ADVISOR_TOOL_NAME)) {
|
|
510
518
|
pi.setActiveTools(active.filter((n) => n !== ADVISOR_TOOL_NAME));
|
|
511
519
|
}
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const blocked = isExecutorBlocked(ctx, pi.getThinkingLevel());
|
|
523
|
+
const active = pi.getActiveTools();
|
|
524
|
+
const hasTool = active.includes(ADVISOR_TOOL_NAME);
|
|
525
|
+
if (blocked && hasTool) {
|
|
526
|
+
pi.setActiveTools(active.filter((n) => n !== ADVISOR_TOOL_NAME));
|
|
527
|
+
} else if (!blocked && !hasTool) {
|
|
528
|
+
pi.setActiveTools([...active, ADVISOR_TOOL_NAME]);
|
|
512
529
|
}
|
|
513
530
|
});
|
|
514
531
|
}
|
|
@@ -527,7 +544,7 @@ export function registerModelSelectHandler(pi: ExtensionAPI): void {
|
|
|
527
544
|
const advisor = getAdvisorModel();
|
|
528
545
|
if (!advisor) return;
|
|
529
546
|
|
|
530
|
-
const blocked = isModelBlocked(event.model);
|
|
547
|
+
const blocked = isModelBlocked(event.model, pi.getThinkingLevel());
|
|
531
548
|
const active = pi.getActiveTools();
|
|
532
549
|
const hasTool = active.includes(ADVISOR_TOOL_NAME);
|
|
533
550
|
|
|
@@ -545,6 +562,33 @@ export function registerModelSelectHandler(pi: ExtensionAPI): void {
|
|
|
545
562
|
});
|
|
546
563
|
}
|
|
547
564
|
|
|
565
|
+
// ---------------------------------------------------------------------------
|
|
566
|
+
// thinking_level_select handler — mid-session effort changes strip/re-add advisor
|
|
567
|
+
// ---------------------------------------------------------------------------
|
|
568
|
+
|
|
569
|
+
export function registerThinkingLevelSelectHandler(pi: ExtensionAPI): void {
|
|
570
|
+
pi.on("thinking_level_select", async (event, ctx) => {
|
|
571
|
+
const advisor = getAdvisorModel();
|
|
572
|
+
if (!advisor) return;
|
|
573
|
+
|
|
574
|
+
const blocked = isModelBlocked(ctx?.model, event.level);
|
|
575
|
+
const active = pi.getActiveTools();
|
|
576
|
+
const hasTool = active.includes(ADVISOR_TOOL_NAME);
|
|
577
|
+
|
|
578
|
+
if (blocked && hasTool) {
|
|
579
|
+
pi.setActiveTools(active.filter((n) => n !== ADVISOR_TOOL_NAME));
|
|
580
|
+
if (ctx.hasUI) {
|
|
581
|
+
ctx.ui.notify(`Advisor disabled for ${modelKey(ctx.model!)}`, "info");
|
|
582
|
+
}
|
|
583
|
+
} else if (!blocked && !hasTool) {
|
|
584
|
+
pi.setActiveTools([...active, ADVISOR_TOOL_NAME]);
|
|
585
|
+
if (ctx.hasUI) {
|
|
586
|
+
ctx.ui.notify(msgAdvisorRestored(modelKey(advisor), getAdvisorEffort()), "info");
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
|
|
548
592
|
// ---------------------------------------------------------------------------
|
|
549
593
|
// /advisor slash command — opens selector panel for picking the advisor model
|
|
550
594
|
// ---------------------------------------------------------------------------
|
|
@@ -553,13 +597,25 @@ function modelKey(m: { provider: string; id: string }): string {
|
|
|
553
597
|
return `${m.provider}:${m.id}`;
|
|
554
598
|
}
|
|
555
599
|
|
|
556
|
-
function isModelBlocked(model: Model<Api> | undefined): boolean {
|
|
600
|
+
function isModelBlocked(model: Model<Api> | undefined, thinkingLevel?: string): boolean {
|
|
557
601
|
if (!model) return false;
|
|
558
|
-
|
|
602
|
+
const key = modelKey(model);
|
|
603
|
+
for (const entry of disabledForModelsCache) {
|
|
604
|
+
if (typeof entry === "string") {
|
|
605
|
+
if (entry === key) return true;
|
|
606
|
+
} else {
|
|
607
|
+
if (entry.model !== key) continue;
|
|
608
|
+
if (entry.minEffort === undefined) return true;
|
|
609
|
+
const thresholdOrdinal = EFFORT_ORDINAL.indexOf(entry.minEffort);
|
|
610
|
+
const executorOrdinal = EFFORT_ORDINAL.indexOf(thinkingLevel as ThinkingLevel);
|
|
611
|
+
if (executorOrdinal >= thresholdOrdinal) return true;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return false;
|
|
559
615
|
}
|
|
560
616
|
|
|
561
|
-
function isExecutorBlocked(ctx: ExtensionContext): boolean {
|
|
562
|
-
return isModelBlocked(ctx?.model);
|
|
617
|
+
function isExecutorBlocked(ctx: ExtensionContext, thinkingLevel?: string): boolean {
|
|
618
|
+
return isModelBlocked(ctx?.model, thinkingLevel);
|
|
563
619
|
}
|
|
564
620
|
|
|
565
621
|
export function registerAdvisorCommand(pi: ExtensionAPI): void {
|
|
@@ -652,7 +708,7 @@ export function registerAdvisorCommand(pi: ExtensionAPI): void {
|
|
|
652
708
|
// `showEffortPicker` is stale once execution yields.
|
|
653
709
|
const activeToolsNow = pi.getActiveTools();
|
|
654
710
|
const activeHasNow = activeToolsNow.includes(ADVISOR_TOOL_NAME);
|
|
655
|
-
const blocked = isExecutorBlocked(ctx);
|
|
711
|
+
const blocked = isExecutorBlocked(ctx, pi.getThinkingLevel());
|
|
656
712
|
if (!activeHasNow && !blocked) {
|
|
657
713
|
pi.setActiveTools([...activeToolsNow, ADVISOR_TOOL_NAME]);
|
|
658
714
|
}
|
package/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* rpiv-advisor — Pi extension
|
|
3
3
|
*
|
|
4
|
-
* Registers the `advisor` tool, `/advisor` command, and
|
|
4
|
+
* Registers the `advisor` tool, `/advisor` command, and four lifecycle
|
|
5
5
|
* hooks (session_start restore, before_agent_start strip, model_select
|
|
6
|
-
* re-evaluation) that together
|
|
6
|
+
* re-evaluation, thinking_level_select re-evaluation) that together
|
|
7
|
+
* implement the advisor-strategy pattern.
|
|
7
8
|
*
|
|
8
9
|
* Config persists at ~/.config/rpiv-advisor/advisor.json. Tool name
|
|
9
10
|
* preserved verbatim from rpiv-pi@7525a5d.
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
registerAdvisorCommand,
|
|
16
17
|
registerAdvisorTool,
|
|
17
18
|
registerModelSelectHandler,
|
|
19
|
+
registerThinkingLevelSelectHandler,
|
|
18
20
|
restoreAdvisorState,
|
|
19
21
|
} from "./advisor.js";
|
|
20
22
|
|
|
@@ -23,6 +25,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
23
25
|
registerAdvisorCommand(pi);
|
|
24
26
|
registerAdvisorBeforeAgentStart(pi);
|
|
25
27
|
registerModelSelectHandler(pi);
|
|
28
|
+
registerThinkingLevelSelectHandler(pi);
|
|
26
29
|
|
|
27
30
|
pi.on("session_start", async (_event, ctx) => {
|
|
28
31
|
restoreAdvisorState(ctx, pi);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juicesharp/rpiv-advisor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.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",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
]
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@juicesharp/rpiv-config": "^1.
|
|
43
|
+
"@juicesharp/rpiv-config": "^1.9.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@earendil-works/pi-ai": "*",
|