@juicesharp/rpiv-advisor 2.5.2 → 2.6.1

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
@@ -78,7 +78,7 @@ write leaves your previous selection untouched and tells you so.
78
78
  | Key | What it does | Default |
79
79
  | --- | --- | --- |
80
80
  | `modelKey` | The reviewer model, as `"provider/modelId"`. Written by `/advisor`. | absent — advisor off |
81
- | `effort` | Reasoning effort for the reviewer: `minimal`, `low`, `medium`, `high`, `xhigh`. Written by `/advisor`. | absent — no reasoning sent |
81
+ | `effort` | Reasoning effort for the reviewer: `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Written by `/advisor`; only levels supported by the selected model are offered. | absent — no reasoning sent |
82
82
  | `disabledForModels` | Executor models the advisor is stripped for. Plain strings block at any effort; `{ "model": "…", "minEffort": "…" }` blocks only at or above that effort. | `[]` |
83
83
 
84
84
  ```json
@@ -2,11 +2,12 @@
2
2
  * command — the /advisor slash command. Reads top-down: interactive guard →
3
3
  * model picker (buildModelItems) → no-advisor branch (applyDisable) → model
4
4
  * lookup → effort picker (buildEffortItems) → enable (applyEnable). The apply
5
- * helpers persist before mutating in-memory state (review I2).
5
+ * helpers persist before mutating in-memory state a save failure must never
6
+ * leave memory ahead of disk.
6
7
  */
7
8
 
8
9
  import type { Api, Model } from "@earendil-works/pi-ai";
9
- import { getSupportedThinkingLevels, type ThinkingLevel } from "@earendil-works/pi-ai";
10
+ import { getSupportedThinkingLevels } from "@earendil-works/pi-ai";
10
11
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
11
12
  import type { SelectItem } from "@earendil-works/pi-tui";
12
13
  import { modelKey } from "@juicesharp/rpiv-config";
@@ -15,11 +16,13 @@ import { saveAdvisorConfig } from "./config.js";
15
16
  import { reconcileAdvisorTool } from "./handlers.js";
16
17
  import {
17
18
  ADVISOR_TOOL_NAME,
18
- BASE_EFFORT_LEVELS,
19
19
  CHECKMARK,
20
20
  DEFAULT_EFFORT,
21
+ EFFORT_ORDINAL,
21
22
  errSelectionNotFound,
23
+ type GradedEffort,
22
24
  MSG_ADVISOR_DISABLED,
25
+ MSG_EFFORT_NOT_SET,
23
26
  MSG_PERSIST_FAILED,
24
27
  MSG_REQUIRES_INTERACTIVE,
25
28
  msgAdvisorEnabled,
@@ -27,11 +30,13 @@ import {
27
30
  NO_ADVISOR_VALUE,
28
31
  OFF_VALUE,
29
32
  RECOMMENDED_EFFORT_SUFFIX,
30
- XHIGH_EFFORT_LEVEL,
31
33
  } from "./messages.js";
32
34
  import { isExecutorBlocked } from "./policy.js";
33
35
  import { getAdvisorEffort, getAdvisorModel, setAdvisorEffort, setAdvisorModel } from "./state.js";
34
36
 
37
+ // Mirror: packages/rpiv-pi/extensions/rpiv-core/rpiv-models/items.ts
38
+ // buildModelItems — structural twin kept in a separate package by the
39
+ // zero-cross-imports contract; evolve model-picker semantics together.
35
40
  function buildModelItems(availableModels: Model<Api>[], currentKey: string | undefined): SelectItem[] {
36
41
  const items: SelectItem[] = availableModels.map((m) => {
37
42
  const key = modelKey(m);
@@ -45,12 +50,20 @@ function buildModelItems(availableModels: Model<Api>[], currentKey: string | und
45
50
  return items;
46
51
  }
47
52
 
53
+ // Mirror: packages/rpiv-pi/extensions/rpiv-core/rpiv-models/items.ts
54
+ // buildEffortItems — same filter-in/map-out shape, different sentinels and
55
+ // persist target; evolve level-picker semantics together.
48
56
  function buildEffortItems(picked: Model<Api>): SelectItem[] {
49
- const levels = getSupportedThinkingLevels(picked).includes("xhigh")
50
- ? [...BASE_EFFORT_LEVELS, XHIGH_EFFORT_LEVEL]
51
- : BASE_EFFORT_LEVELS;
57
+ // Intersect with EFFORT_ORDINAL (which excludes "off") so the picker can
58
+ // never offer — hence saveAdvisorConfig can never persist — a level that
59
+ // minEffort blocklist comparisons don't rank.
60
+ const levels = getSupportedThinkingLevels(picked).filter((level): level is GradedEffort =>
61
+ EFFORT_ORDINAL.includes(level as GradedEffort),
62
+ );
52
63
  return [
53
- { value: OFF_VALUE, label: "off" },
64
+ // "off (no reasoning sent)" ≠ /rpiv-models' "off (disable reasoning)":
65
+ // this row sends NO reasoning option; /rpiv-models persists thinking:"off".
66
+ { value: OFF_VALUE, label: "off (no reasoning sent)" },
54
67
  ...levels.map((level) => ({
55
68
  value: level,
56
69
  label: level === DEFAULT_EFFORT ? `${level}${RECOMMENDED_EFFORT_SUFFIX}` : level,
@@ -59,7 +72,7 @@ function buildEffortItems(picked: Model<Api>): SelectItem[] {
59
72
  }
60
73
 
61
74
  // Disable path — persist BEFORE mutating in-memory state so a save failure
62
- // can't strand "model=undefined + tool still registered" (review I2). The strip
75
+ // can't strand "model=undefined + tool still registered". The strip
63
76
  // is unconditional-on-presence (no advisor at all), so it stays inline rather
64
77
  // than routing through reconcileAdvisorTool's blocked-conditional path.
65
78
  function applyDisable(pi: ExtensionAPI, ctx: ExtensionContext): void {
@@ -76,7 +89,7 @@ function applyDisable(pi: ExtensionAPI, ctx: ExtensionContext): void {
76
89
  ctx.ui.notify(MSG_ADVISOR_DISABLED, "info");
77
90
  }
78
91
 
79
- // Enable path — persist first (review I2), set in-memory state, activate via
92
+ // Enable path — persist first, set in-memory state, activate via
80
93
  // reconcileAdvisorTool (which re-reads the active-tool list post-effort-picker-
81
94
  // await), and notify. Silent reconcile — the enable/inactive notify is the
82
95
  // single trailing notify call here.
@@ -84,7 +97,7 @@ function applyEnable(
84
97
  pi: ExtensionAPI,
85
98
  ctx: ExtensionContext,
86
99
  picked: Model<Api>,
87
- effort: ThinkingLevel | undefined,
100
+ effort: GradedEffort | undefined,
88
101
  ): void {
89
102
  if (!saveAdvisorConfig(modelKey(picked), effort)) {
90
103
  ctx.ui.notify(MSG_PERSIST_FAILED, "error");
@@ -129,7 +142,7 @@ export function registerAdvisorCommand(pi: ExtensionAPI): void {
129
142
  }
130
143
 
131
144
  // Effort picker — only for reasoning-capable models
132
- let effortChoice: ThinkingLevel | undefined;
145
+ let effortChoice: GradedEffort | undefined;
133
146
  if (picked.reasoning) {
134
147
  const effortResult = await showEffortPicker(
135
148
  ctx,
@@ -137,8 +150,17 @@ export function registerAdvisorCommand(pi: ExtensionAPI): void {
137
150
  getAdvisorEffort(),
138
151
  DEFAULT_EFFORT,
139
152
  );
140
- if (!effortResult) return;
141
- effortChoice = effortResult === OFF_VALUE ? undefined : (effortResult as ThinkingLevel);
153
+ if (!effortResult) {
154
+ // Esc at the effort step keeps the model selection — cancelling
155
+ // one step never discards prior choices (the invariant shared
156
+ // with the /rpiv-models stepper). The divergence is deliberate:
157
+ // that twin backs up without writing, while here the enable
158
+ // proceeds and PERSISTS with no explicit effort (model default),
159
+ // announced by this notify before the write.
160
+ ctx.ui.notify(MSG_EFFORT_NOT_SET, "info");
161
+ } else {
162
+ effortChoice = effortResult === OFF_VALUE ? undefined : (effortResult as GradedEffort);
163
+ }
142
164
  }
143
165
 
144
166
  applyEnable(pi, ctx, picked, effortChoice);
package/advisor/config.ts CHANGED
@@ -1,21 +1,21 @@
1
1
  /**
2
2
  * config — persisted advisor config (~/.config/rpiv-advisor/advisor.json) and
3
- * the provider:id key codec. Owns the AdvisorConfig shape, load/validate/save,
4
- * and the modelKey (join) / parseModelKey (split) inverse pair (L4-04).
3
+ * the provider:id key codec. Owns the AdvisorConfig shape and load/validate/save.
4
+ * The modelKey (join) / parseModelKey (split) inverse pair the codec relies on
5
+ * lives in @juicesharp/rpiv-config.
5
6
  */
6
7
 
7
- import type { ThinkingLevel } from "@earendil-works/pi-ai";
8
8
  import type { GuidanceFields } from "@juicesharp/rpiv-config";
9
9
  import { configPath, loadJsonConfigWithLegacyFallback, saveJsonConfig } from "@juicesharp/rpiv-config";
10
- import { EFFORT_ORDINAL } from "./messages.js";
10
+ import { EFFORT_ORDINAL, type GradedEffort } from "./messages.js";
11
11
 
12
12
  const ADVISOR_CONFIG_PATH = configPath("rpiv-advisor", "advisor.json");
13
13
 
14
- export type DisabledForModelsEntry = string | { model: string; minEffort?: ThinkingLevel };
14
+ export type DisabledForModelsEntry = string | { model: string; minEffort?: GradedEffort };
15
15
 
16
16
  interface AdvisorConfig {
17
17
  modelKey?: string;
18
- effort?: ThinkingLevel;
18
+ effort?: GradedEffort;
19
19
  guidance?: GuidanceFields;
20
20
  disabledForModels?: DisabledForModelsEntry[];
21
21
  }
@@ -31,12 +31,19 @@ export function validateDisabledForModels(value: unknown): DisabledForModelsEntr
31
31
  if (typeof entry !== "object" || entry === null) return false;
32
32
  const obj = entry as Record<string, unknown>;
33
33
  if (typeof obj.model !== "string" || obj.model.length === 0) return false;
34
- if (obj.minEffort !== undefined && !EFFORT_ORDINAL.includes(obj.minEffort as ThinkingLevel)) return false;
34
+ if (obj.minEffort !== undefined && !EFFORT_ORDINAL.includes(obj.minEffort as GradedEffort)) {
35
+ // Warn before dropping — the entry's model identity is discarded along
36
+ // with the bad threshold (mirrors models-config's warn-on-miss posture).
37
+ console.warn(
38
+ `[rpiv-advisor] advisor.json: unknown minEffort "${String(obj.minEffort)}" — dropping disabledForModels entry for "${obj.model}"`,
39
+ );
40
+ return false;
41
+ }
35
42
  return true;
36
43
  });
37
44
  }
38
45
 
39
- export function saveAdvisorConfig(key: string | undefined, effort: ThinkingLevel | undefined): boolean {
46
+ export function saveAdvisorConfig(key: string | undefined, effort: GradedEffort | undefined): boolean {
40
47
  const existing = loadAdvisorConfig();
41
48
  const config: AdvisorConfig = { ...existing };
42
49
  // Delete (rather than omit) to clear fields that may exist in the spread
@@ -105,7 +105,12 @@ export async function executeAdvisor(
105
105
  if (!auth.ok) {
106
106
  return buildErrorResult(advisorLabel, effort, errMisconfigured(advisorLabel, auth.error), auth.error);
107
107
  }
108
- if (!auth.apiKey) {
108
+ // OAuth-backed providers resolve `{ ok: true }` with no literal apiKey — their
109
+ // credentials are applied inside Pi's runtime facade. A missing key is only
110
+ // fatal on legacy hosts without that facade, where the global completion
111
+ // fallback needs the key passed explicitly.
112
+ const runtimeCompleteSimple = getRuntimeCompleteSimple(ctx.modelRegistry);
113
+ if (!auth.apiKey && !runtimeCompleteSimple) {
109
114
  return buildErrorResult(advisorLabel, effort, errNoApiKey(advisorLabel), errNoApiKeyDetail(advisor.provider));
110
115
  }
111
116
 
@@ -129,12 +134,12 @@ export async function executeAdvisor(
129
134
  });
130
135
 
131
136
  try {
132
- // Prefer Pi's auth-aware runtime facade. Unlike the global compatibility
133
- // function, it runs request preparation and applies credential-derived
134
- // fields such as GitHub Copilot's OAuth-specific baseUrl. Do not pass the
135
- // preflight key/headers to this path: explicit overrides would bypass that
136
- // resolution and reintroduce the endpoint mismatch.
137
- const runtimeCompleteSimple = getRuntimeCompleteSimple(ctx.modelRegistry);
137
+ // Prefer Pi's auth-aware runtime facade (resolved once above, before the
138
+ // missing-key guard). Unlike the global compatibility function, it runs
139
+ // request preparation and applies credential-derived fields such as GitHub
140
+ // Copilot's OAuth-specific baseUrl. Do not pass the preflight key/headers
141
+ // to this path: explicit overrides would bypass that resolution and
142
+ // reintroduce the endpoint mismatch.
138
143
  const completeSimple = runtimeCompleteSimple ?? (await loadCompleteSimple());
139
144
  const requestOptions = runtimeCompleteSimple
140
145
  ? { signal, reasoning: effort }
@@ -14,11 +14,14 @@ export const TOOL_LABEL = "Advisor";
14
14
  export const NO_ADVISOR_VALUE = "__no_advisor__";
15
15
  export const OFF_VALUE = "__off__";
16
16
 
17
- // Effort levels
18
- export const BASE_EFFORT_LEVELS: ThinkingLevel[] = ["minimal", "low", "medium", "high"];
19
- export const XHIGH_EFFORT_LEVEL: ThinkingLevel = "xhigh";
20
- export const EFFORT_ORDINAL: readonly ThinkingLevel[] = ["minimal", "low", "medium", "high", "xhigh"];
21
- export const DEFAULT_EFFORT: ThinkingLevel = "high";
17
+ // Effort levels. GradedEffort is the ordinal's domain: the graded levels only,
18
+ // never "off" an "off" element would corrupt the indexOf ranking that
19
+ // minEffort thresholds compare against. Today pi-ai's ThinkingLevel already
20
+ // excludes "off" (the Exclude is a defensive no-op); the alias keeps that
21
+ // exclusion structural if the upstream universe ever re-widens.
22
+ export type GradedEffort = Exclude<ThinkingLevel, "off">;
23
+ export const EFFORT_ORDINAL: readonly GradedEffort[] = ["minimal", "low", "medium", "high", "xhigh", "max"];
24
+ export const DEFAULT_EFFORT: GradedEffort = "high";
22
25
  export const RECOMMENDED_EFFORT_SUFFIX = " (recommended)";
23
26
 
24
27
  // UI — labels used by command flow; panel prose/titles live in advisor-ui.ts
@@ -28,6 +31,7 @@ export const CHECKMARK = " ✓";
28
31
  export const MSG_ADVISOR_DISABLED = "Advisor disabled";
29
32
  export const MSG_REQUIRES_INTERACTIVE = "/advisor requires interactive mode";
30
33
  export const MSG_ADVISOR_NUDGE = "Please advise on the executor's situation above.";
34
+ export const MSG_EFFORT_NOT_SET = "Effort not set — advisor uses the model default";
31
35
  export const MSG_PERSIST_FAILED = "Failed to save advisor selection — selection not persisted";
32
36
 
33
37
  // Errors (static)
package/advisor/policy.ts CHANGED
@@ -3,11 +3,11 @@
3
3
  * that decide whether the advisor tool is blocked for a given model/effort.
4
4
  */
5
5
 
6
- import type { Api, Model, ThinkingLevel } from "@earendil-works/pi-ai";
6
+ import type { Api, Model } from "@earendil-works/pi-ai";
7
7
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
8
8
  import { modelKey, parseModelKey } from "@juicesharp/rpiv-config";
9
9
  import type { DisabledForModelsEntry } from "./config.js";
10
- import { EFFORT_ORDINAL } from "./messages.js";
10
+ import { EFFORT_ORDINAL, type GradedEffort } from "./messages.js";
11
11
 
12
12
  let disabledForModelsCache: DisabledForModelsEntry[] = [];
13
13
 
@@ -27,6 +27,12 @@ function canonicalKey(entry: string): string {
27
27
  return parsed ? `${parsed.provider}/${parsed.modelId}` : entry;
28
28
  }
29
29
 
30
+ /**
31
+ * True when `model` is on the disabledForModels blocklist at the executor's
32
+ * current thinking level. Fail-soft ranking contract: an executor level that
33
+ * is unset, "off", or unknown to EFFORT_ORDINAL yields indexOf −1, ranking
34
+ * below every minEffort threshold — such levels never block.
35
+ */
30
36
  export function isModelBlocked(model: Model<Api> | undefined, thinkingLevel?: string): boolean {
31
37
  if (!model) return false;
32
38
  const key = modelKey(model);
@@ -37,7 +43,11 @@ export function isModelBlocked(model: Model<Api> | undefined, thinkingLevel?: st
37
43
  if (canonicalKey(entry.model) !== key) continue;
38
44
  if (entry.minEffort === undefined) return true;
39
45
  const thresholdOrdinal = EFFORT_ORDINAL.indexOf(entry.minEffort);
40
- const executorOrdinal = EFFORT_ORDINAL.indexOf(thinkingLevel as ThinkingLevel);
46
+ // A threshold unknown to the ordinal cannot rank; skip the entry —
47
+ // otherwise its indexOf -1 would equal an unknown executor's -1 and
48
+ // block, breaking the "unknown never blocks" contract above.
49
+ if (thresholdOrdinal === -1) continue;
50
+ const executorOrdinal = EFFORT_ORDINAL.indexOf(thinkingLevel as GradedEffort);
41
51
  if (executorOrdinal >= thresholdOrdinal) return true;
42
52
  }
43
53
  }
@@ -8,7 +8,13 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
8
8
  import { modelKey, parseModelKey } from "@juicesharp/rpiv-config";
9
9
  import { loadAdvisorConfig, validateDisabledForModels } from "./config.js";
10
10
  import { reconcileAdvisorTool } from "./handlers.js";
11
- import { ADVISOR_TOOL_NAME, errModelUnavailable, msgAdvisorRestored, msgAdvisorRestoredInactive } from "./messages.js";
11
+ import {
12
+ ADVISOR_TOOL_NAME,
13
+ EFFORT_ORDINAL,
14
+ errModelUnavailable,
15
+ msgAdvisorRestored,
16
+ msgAdvisorRestoredInactive,
17
+ } from "./messages.js";
12
18
  import { isExecutorBlocked, setDisabledForModels } from "./policy.js";
13
19
  import { setAdvisorEffort, setAdvisorModel } from "./state.js";
14
20
 
@@ -74,14 +80,26 @@ export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): vo
74
80
  }
75
81
 
76
82
  setAdvisorModel(model);
77
- if (config.effort) {
78
- setAdvisorEffort(config.effort);
83
+ // Overwrite — never merge — the in-memory effort with the persisted value.
84
+ // "Model present, effort absent" is a first-class persisted state (the
85
+ // /advisor Esc and off choices both save it), and another process can
86
+ // remove the field from the shared advisor.json mid-session; a guarded set
87
+ // here would leave a stale module-level effort feeding `reasoning` on every
88
+ // advisor call. A hand-edited value unknown to EFFORT_ORDINAL is dropped
89
+ // with a warning rather than restored and sent as `reasoning`.
90
+ let effort = config.effort;
91
+ if (effort !== undefined && !EFFORT_ORDINAL.includes(effort)) {
92
+ console.warn(
93
+ `[rpiv-advisor] advisor.json: unknown effort "${effort}" — ignoring (valid values: ${EFFORT_ORDINAL.join(", ")})`,
94
+ );
95
+ effort = undefined;
79
96
  }
97
+ setAdvisorEffort(effort);
80
98
 
81
99
  if (isExecutorBlocked(ctx, pi.getThinkingLevel())) {
82
100
  reconcileAdvisorTool(pi, ctx, { blocked: true });
83
101
  const advisorLabel = modelKey(model);
84
- notifyOnce(msgAdvisorRestoredInactive(advisorLabel, config.effort), "info");
102
+ notifyOnce(msgAdvisorRestoredInactive(advisorLabel, effort), "info");
85
103
  return;
86
104
  }
87
105
 
@@ -90,7 +108,7 @@ export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): vo
90
108
  pi.setActiveTools([...active, ADVISOR_TOOL_NAME]);
91
109
  }
92
110
 
93
- notifyOnce(msgAdvisorRestored(modelKey(model), config.effort), "info");
111
+ notifyOnce(msgAdvisorRestored(modelKey(model), effort), "info");
94
112
  }
95
113
 
96
114
  export function registerAdvisorSessionStart(pi: ExtensionAPI): void {
package/advisor/state.ts CHANGED
@@ -3,10 +3,11 @@
3
3
  * the persisted form lives in config.ts, the blocklist cache in policy.ts.
4
4
  */
5
5
 
6
- import type { Api, Model, ThinkingLevel } from "@earendil-works/pi-ai";
6
+ import type { Api, Model } from "@earendil-works/pi-ai";
7
+ import type { GradedEffort } from "./messages.js";
7
8
 
8
9
  let selectedAdvisor: Model<Api> | undefined;
9
- let selectedAdvisorEffort: ThinkingLevel | undefined;
10
+ let selectedAdvisorEffort: GradedEffort | undefined;
10
11
 
11
12
  export function getAdvisorModel(): Model<Api> | undefined {
12
13
  return selectedAdvisor;
@@ -16,10 +17,10 @@ export function setAdvisorModel(model: Model<Api> | undefined): void {
16
17
  selectedAdvisor = model;
17
18
  }
18
19
 
19
- export function getAdvisorEffort(): ThinkingLevel | undefined {
20
+ export function getAdvisorEffort(): GradedEffort | undefined {
20
21
  return selectedAdvisorEffort;
21
22
  }
22
23
 
23
- export function setAdvisorEffort(effort: ThinkingLevel | undefined): void {
24
+ export function setAdvisorEffort(effort: GradedEffort | undefined): void {
24
25
  selectedAdvisorEffort = effort;
25
26
  }
@@ -41,7 +41,7 @@ previous selection and the active tool list are left untouched.
41
41
  | Key | Type | Default | Written by |
42
42
  | --- | --- | --- | --- |
43
43
  | `modelKey` | `string` — `"provider/modelId"` | absent (advisor off) | `/advisor` |
44
- | `effort` | `"minimal" \| "low" \| "medium" \| "high" \| "xhigh"` | absent (no `reasoning` sent) | `/advisor` effort picker |
44
+ | `effort` | graded thinking level (`minimal` `max`) | absent (no `reasoning` sent) | `/advisor` effort picker |
45
45
  | `disabledForModels` | `(string \| { model, minEffort? })[]` | `[]` | hand-edited |
46
46
  | `guidance.promptSnippet` | `string` | built-in snippet | hand-edited |
47
47
  | `guidance.promptGuidelines` | `string[]` | six built-in guidelines | hand-edited |
@@ -59,12 +59,18 @@ form the next time you save through `/advisor`.
59
59
  ### `effort`
60
60
 
61
61
  Offered only for models whose registry entry reports reasoning support. The
62
- picker lists `off`, `minimal`, `low`, `medium`, `high`, and adds `xhigh` when
63
- the picked model supports it. `high` is marked `(recommended)`. Choosing `off`
64
- deletes the key, and no `reasoning` parameter is sent with the advisor call.
65
-
66
- `EFFORT_ORDINAL`, lowest to highest, is `minimal`, `low`, `medium`, `high`,
67
- `xhigh`. This ordering is what `minEffort` compares against.
62
+ picker lists `off (no reasoning sent)` plus the graded levels Pi reports for the
63
+ selected model. `high` is marked `(recommended)`. Choosing `off` deletes the
64
+ key, and no `reasoning` parameter is sent with the advisor call — distinct from
65
+ `/rpiv-models`' `off (disable reasoning)`, which persists an explicit
66
+ `thinking: "off"`.
67
+
68
+ `EFFORT_ORDINAL` orders the graded levels lowest → highest; this ordering is what
69
+ `minEffort` compares against.
70
+
71
+ > **Naming note.** Advisor "effort", Pi's "thinking level", and pi-ai's `reasoning`
72
+ > parameter are the same graded-level concept — the name differs per layer (fixed by
73
+ > on-disk config keys and upstream APIs), but there is no semantic distinction.
68
74
 
69
75
  ### `disabledForModels`
70
76
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juicesharp/rpiv-advisor",
3
- "version": "2.5.2",
3
+ "version": "2.6.1",
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,12 +40,13 @@
40
40
  "LICENSE"
41
41
  ],
42
42
  "pi": {
43
+ "image": "https://raw.githubusercontent.com/juicesharp/rpiv-mono/main/packages/rpiv-advisor/docs/cover.png",
43
44
  "extensions": [
44
45
  "./index.ts"
45
46
  ]
46
47
  },
47
48
  "dependencies": {
48
- "@juicesharp/rpiv-config": "^2.5.2",
49
+ "@juicesharp/rpiv-config": "^2.6.1",
49
50
  "typebox": "^1.1.24"
50
51
  },
51
52
  "peerDependencies": {