@juicesharp/rpiv-advisor 1.0.14 → 1.0.16
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 +29 -3
- package/package.json +1 -1
package/advisor.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { homedir } from "node:os";
|
|
|
18
18
|
import { dirname, join } from "node:path";
|
|
19
19
|
import { fileURLToPath } from "node:url";
|
|
20
20
|
import type { Api, Model, StopReason, Usage } from "@mariozechner/pi-ai";
|
|
21
|
-
import { completeSimple, type Message,
|
|
21
|
+
import { completeSimple, getSupportedThinkingLevels, type Message, type ThinkingLevel } from "@mariozechner/pi-ai";
|
|
22
22
|
import {
|
|
23
23
|
type AgentToolResult,
|
|
24
24
|
type AgentToolUpdateCallback,
|
|
@@ -62,6 +62,11 @@ const CHECKMARK = " ✓";
|
|
|
62
62
|
const MSG_ADVISOR_DISABLED = "Advisor disabled";
|
|
63
63
|
const MSG_REQUIRES_INTERACTIVE = "/advisor requires interactive mode";
|
|
64
64
|
|
|
65
|
+
// User-tail nudge — appended when stripping leaves an assistant tail (some
|
|
66
|
+
// providers, e.g. recent Anthropic models, reject payloads not ending with
|
|
67
|
+
// a user message: "This model does not support assistant message prefill.").
|
|
68
|
+
const ADVISOR_NUDGE_TEXT = "Please advise on the executor's situation above.";
|
|
69
|
+
|
|
65
70
|
// Errors (static)
|
|
66
71
|
const ERR_NO_MODEL = "No advisor model is configured. The user can enable one with the /advisor command.";
|
|
67
72
|
const ERR_CALL_ABORTED = "Advisor call was cancelled before it completed.";
|
|
@@ -206,6 +211,25 @@ export function stripInflightAdvisorCall(messages: Message[]): Message[] {
|
|
|
206
211
|
return [...messages.slice(0, -1), { ...last, content: filtered }];
|
|
207
212
|
}
|
|
208
213
|
|
|
214
|
+
// Some providers (recent Anthropic Claude models) reject payloads that end on
|
|
215
|
+
// an assistant turn — they treat a trailing assistant message as a prefill and
|
|
216
|
+
// require user-tail. After stripInflightAdvisorCall, the tail can be assistant
|
|
217
|
+
// (e.g. the executor wrote thinking text before calling advisor). Append a
|
|
218
|
+
// minimal user-role nudge so the request is well-formed for those providers.
|
|
219
|
+
export function ensureUserTail(messages: Message[]): Message[] {
|
|
220
|
+
if (messages.length === 0) return messages;
|
|
221
|
+
const last = messages[messages.length - 1];
|
|
222
|
+
if (last.role === "user" || last.role === "toolResult") return messages;
|
|
223
|
+
return [
|
|
224
|
+
...messages,
|
|
225
|
+
{
|
|
226
|
+
role: "user",
|
|
227
|
+
content: [{ type: "text", text: ADVISOR_NUDGE_TEXT }],
|
|
228
|
+
timestamp: Date.now(),
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
}
|
|
232
|
+
|
|
209
233
|
// Returns `undefined` when the registry is empty (no extensions loaded) so
|
|
210
234
|
// callers can skip prepending an empty block that would still cost a cache unit.
|
|
211
235
|
export function getInventoryMessage(tools: ToolInfo[]): Message | undefined {
|
|
@@ -337,7 +361,7 @@ async function executeAdvisor(
|
|
|
337
361
|
const agentMessages = branch
|
|
338
362
|
.filter((e): e is SessionEntry & { type: "message" } => e.type === "message")
|
|
339
363
|
.map((e) => e.message);
|
|
340
|
-
const branchMessages = stripInflightAdvisorCall(convertToLlm(agentMessages));
|
|
364
|
+
const branchMessages = ensureUserTail(stripInflightAdvisorCall(convertToLlm(agentMessages)));
|
|
341
365
|
const inventoryMessage = getInventoryMessage(pi.getAllTools());
|
|
342
366
|
const messages: Message[] = inventoryMessage ? [inventoryMessage, ...branchMessages] : branchMessages;
|
|
343
367
|
|
|
@@ -530,7 +554,9 @@ export function registerAdvisorCommand(pi: ExtensionAPI): void {
|
|
|
530
554
|
// Effort picker — only for reasoning-capable models
|
|
531
555
|
let effortChoice: ThinkingLevel | undefined;
|
|
532
556
|
if (picked.reasoning) {
|
|
533
|
-
const levels =
|
|
557
|
+
const levels = getSupportedThinkingLevels(picked).includes("xhigh")
|
|
558
|
+
? [...BASE_EFFORT_LEVELS, XHIGH_EFFORT_LEVEL]
|
|
559
|
+
: BASE_EFFORT_LEVELS;
|
|
534
560
|
|
|
535
561
|
const effortItems: SelectItem[] = [
|
|
536
562
|
{ value: OFF_VALUE, label: "off" },
|