@fiale-plus/pi-rogue-advisor 0.1.6 → 0.1.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiale-plus/pi-rogue-advisor",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Pi-Rogue advisor extension for Pi — multi-model support, SOTA model suggestion, cache-aware session advisory.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -12,7 +12,7 @@ Use this skill for non-trivial decisions before/after significant edits.
12
12
  - `/pi-rogue` — open cockpit and command pointers
13
13
  - `/advisor status` — show current advisor settings and model route
14
14
  - `/advisor <question>` — ask immediate advice
15
- - `/advisor checkins on|off|<minutes>` control low-power check-ins
15
+ - Check-ins are lifecycle-managed by `/loop`, not by the advisor command surface
16
16
 
17
17
  ## Command surface
18
18
 
@@ -24,7 +24,6 @@ Use this skill for non-trivial decisions before/after significant edits.
24
24
  | `/advisor off` | Disable advisor |
25
25
  | `/advisor mode auto\|manual\|off` | Control when advisor auto-runs |
26
26
  | `/advisor review light\|strict\|off` | Set review threshold |
27
- | `/advisor checkins on\|off\|<minutes>` | Configure interval check-ins |
28
27
  | `/advisor config` | Dump full config |
29
28
  | `/advisor model <provider/model>` | Pin model explicitly |
30
29
  | `/advisor <question>` | Run one advisory response |
@@ -33,7 +32,7 @@ Use this skill for non-trivial decisions before/after significant edits.
33
32
 
34
33
  - Preflight is heuristics + quick local gate first.
35
34
  - Review runs after edits and/or at completion points by policy.
36
- - No hidden long-running background daemon: check-ins are interval-gated and lightweight.
35
+ - No standalone check-in command: check-ins are triggered from loop cadence (not from advisor internals), using higher/advanced advisor models first with regular model fallback enabled by default.
37
36
 
38
37
  ## Keep scope clear
39
38
 
@@ -43,6 +42,6 @@ The advisor surface is separate from orchestration (`goal`/`loop`/`autoresearch`
43
42
 
44
43
  - `mode: auto`
45
44
  - `review: light`
46
- - `checkins: off` by default; orchestration enables them while a goal/autoresearch flow is active
45
+ - `checkins: off` by default; loop orchestration owns cadence and enables them when active
47
46
  - `checkinIntervalMinutes: 30`
48
47
  - `model: auto`
@@ -4,7 +4,8 @@ import { advisorArgumentCompletions, piRogueArgumentCompletions } from "./comple
4
4
  describe("advisor completions", () => {
5
5
  it("offers top-level advisor continuations", () => {
6
6
  const values = advisorArgumentCompletions("")?.map((i) => i.value);
7
- expect(values).toEqual(expect.arrayContaining(["status", "config", "checkins", "review"]));
7
+ expect(values).toEqual(expect.arrayContaining(["status", "config", "model", "review"]));
8
+ expect(values).not.toContain("checkins");
8
9
  });
9
10
 
10
11
  it("offers nested review choices", () => {
@@ -12,10 +13,6 @@ describe("advisor completions", () => {
12
13
  expect(values).toEqual(["light", "strict", "off"]);
13
14
  });
14
15
 
15
- it("offers check-in choices", () => {
16
- const values = advisorArgumentCompletions("checkins ")?.map((i) => i.value);
17
- expect(values).toEqual(expect.arrayContaining(["on", "off", "30", "60"]));
18
- });
19
16
  });
20
17
 
21
18
  describe("pi-rogue cockpit completions", () => {
@@ -40,24 +40,19 @@ const advisorTopLevel: Array<[string, string?]> = [
40
40
  ["off", "disable advisor"],
41
41
  ["mode", "set auto/manual/off"],
42
42
  ["review", "set light/strict/off"],
43
- ["checkins", "configure mid-hour check-ins"],
44
- ["checkin", "alias for checkins"],
45
43
  ["model", "set or inspect model override"],
46
44
  ];
47
45
 
48
46
  const advisorNested: Record<string, Array<[string, string?]>> = {
49
47
  mode: [["auto"], ["manual"], ["off"]],
50
48
  review: [["light"], ["strict"], ["off"]],
51
- checkins: [["on"], ["off"], ["10"], ["15"], ["30"], ["60"]],
52
- checkin: [["on"], ["off"], ["10"], ["15"], ["30"], ["60"]],
53
49
  model: [["auto"], ["openai-codex/gpt-5.5"], ["anthropic/claude-opus-4-6"]],
54
50
  };
55
51
 
56
52
  const piRogueTopLevel: Array<[string, string?]> = [
57
53
  ["status", "show cockpit"],
58
- ["advisor", "advisor status and check-ins"],
54
+ ["advisor", "advisor status"],
59
55
  ["orchestration", "goal/loop/autoresearch shortcuts"],
60
- ["checkins", "advisor check-ins"],
61
56
  ["help", "show cockpit help"],
62
57
  ];
63
58
 
@@ -70,8 +65,7 @@ const piRogueNested: Record<string, Array<[string, string?]>> = {
70
65
  ["autoresearch-lab", "parallel research flow"],
71
66
  ["status", "show all surfaces"],
72
67
  ],
73
- checkins: advisorNested.checkins,
74
- help: [["advisor"], ["orchestration"], ["checkins"], ["status"]],
68
+ help: [["advisor"], ["orchestration"], ["status"]],
75
69
  };
76
70
 
77
71
  export function advisorArgumentCompletions(prefix: string): CompletionItem[] | null {
@@ -1,5 +1,14 @@
1
- import { describe, it, expect } from "vitest";
2
- import { normalizeAdvisorConfig, shouldRunCheckin, type AdvisorConfig } from "./extension.js";
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { completeSimple } from "@earendil-works/pi-ai";
3
+ import { normalizeAdvisorConfig, shouldRunCheckin, type AdvisorConfig, completeWithHigherAdvisorModel, completeWithModelFallback } from "./extension.js";
4
+
5
+ vi.mock("@earendil-works/pi-ai", async () => {
6
+ const actual = await vi.importActual<typeof import("@earendil-works/pi-ai")>("@earendil-works/pi-ai");
7
+ return {
8
+ ...actual,
9
+ completeSimple: vi.fn(),
10
+ };
11
+ });
3
12
 
4
13
  function state(overrides: Record<string, unknown> = {}) {
5
14
  return {
@@ -89,6 +98,80 @@ describe("mid-hour check-ins", () => {
89
98
  const cfg = normalizeAdvisorConfig({ checkins: "off" });
90
99
  expect(shouldRunCheckin(cfg, state(), 999999, 1)).toBeNull();
91
100
  });
101
+
102
+ it("flushes queued check-in regardless of turn delta", () => {
103
+ const cfg = normalizeAdvisorConfig({ checkins: "mid-hour", checkinIntervalMinutes: 30 });
104
+ expect(
105
+ shouldRunCheckin(cfg, state({
106
+ checkin: {
107
+ queued: true,
108
+ queuedReason: "queued mid-session check-in",
109
+ },
110
+ })),
111
+ ).toBe("queued mid-session check-in");
112
+ });
113
+ });
114
+
115
+
116
+ describe("advisor completion fallback behavior", () => {
117
+ function mkCtx(allowHighTier: boolean, includeRegular = true) {
118
+ const high = { id: "openai-codex/gpt-5.5", provider: "openai-codex", input: ["text"] };
119
+ const regular = { id: "provider/text-light", provider: "provider", input: ["text"] };
120
+ return {
121
+ modelRegistry: {
122
+ find: (_provider: string, model: string) => {
123
+ if (!allowHighTier) return null;
124
+ if (_provider === "openai-codex" && model === "gpt-5.5") return high;
125
+ if (_provider === "anthropic" && model === "claude-opus-4-6") return { ...high, id: "anthropic/claude-opus-4-6" };
126
+ if (_provider === "anthropic" && model === "claude-sonnet-4-6") return { ...high, id: "anthropic/claude-sonnet-4-6" };
127
+ if (_provider === "openai-codex" && model === "gpt-5.4-mini") return { ...high, id: "openai-codex/gpt-5.4-mini" };
128
+ return null;
129
+ },
130
+ getAvailable: () => (includeRegular ? [regular] : []),
131
+ getApiKeyAndHeaders: async (_model: unknown) => ({ ok: true, apiKey: "k", headers: {} }),
132
+ },
133
+ } as any;
134
+ }
135
+
136
+ it("uses high/advanced models first for check-in completion", async () => {
137
+ const completeSimpleMock = vi.mocked(completeSimple as any);
138
+ completeSimpleMock.mockReset();
139
+ completeSimpleMock.mockResolvedValue({ content: [{ type: "text", text: "ok" }] });
140
+
141
+ const cfg = normalizeAdvisorConfig({ mode: "auto", review: "light" });
142
+ const result = await completeWithHigherAdvisorModel(mkCtx(true, true), cfg, "system", [{ role: "user", content: "x" }], { maxTokens: 128, reasoning: "low" as const });
143
+
144
+ expect(result).not.toBeNull();
145
+ expect(completeSimpleMock).toHaveBeenCalledTimes(1);
146
+ expect(completeSimpleMock.mock.calls[0]?.[0]?.id).toBe("openai-codex/gpt-5.5");
147
+ });
148
+
149
+ it("falls back to regular models for check-in completion when high/advanced are unavailable", async () => {
150
+ const completeSimpleMock = vi.mocked(completeSimple as any);
151
+ completeSimpleMock.mockReset();
152
+ completeSimpleMock.mockResolvedValue({ content: [{ type: "text", text: "ok" }] });
153
+
154
+ const cfg = normalizeAdvisorConfig({ mode: "auto", review: "light" });
155
+ const result = await completeWithHigherAdvisorModel(mkCtx(false, true), cfg, "system", [{ role: "user", content: "x" }], { maxTokens: 128, reasoning: "low" as const });
156
+
157
+ expect(result).not.toBeNull();
158
+ expect(completeSimpleMock).toHaveBeenCalledTimes(1);
159
+ expect(completeSimpleMock.mock.calls[0]?.[0]?.id).toBe("provider/text-light");
160
+ });
161
+
162
+ it("uses regular fallback for non-checkin completion", async () => {
163
+ const completeSimpleMock = vi.mocked(completeSimple as any);
164
+ completeSimpleMock.mockReset();
165
+ completeSimpleMock.mockResolvedValue({ content: [{ type: "text", text: "ok" }] });
166
+
167
+ const cfg = normalizeAdvisorConfig({ mode: "auto", review: "light" });
168
+ const result = await completeWithModelFallback(mkCtx(false), cfg, "system", [{ role: "user", content: "x" }], { maxTokens: 128, reasoning: "low" as const });
169
+
170
+ expect(result).not.toBeNull();
171
+ expect(result?.fallback).toBe(true);
172
+ expect(completeSimpleMock).toHaveBeenCalledTimes(1);
173
+ expect(completeSimpleMock.mock.calls[0]?.[0]?.id).toBe("provider/text-light");
174
+ });
92
175
  });
93
176
 
94
177