pi-advisor-flow 0.1.8 → 0.1.9
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 +1 -1
- package/src/tools.ts +21 -6
package/package.json
CHANGED
package/src/tools.ts
CHANGED
|
@@ -49,11 +49,25 @@ export const ADVISOR_SYSTEM = [
|
|
|
49
49
|
"You already have the relevant reconstructed conversation context. No question or other input from the Executor is needed for a general review.",
|
|
50
50
|
"When no targeted focus is supplied, proactively review the task, risks, proposed direction, and validation from the context. Do not ask the Executor for a question, clarification, more input, or confirmation.",
|
|
51
51
|
"The context may be truncated, so state any material uncertainty and make the best recommendation you can from what is present.",
|
|
52
|
-
"You do not act or take over planning.
|
|
52
|
+
"You do not act or take over planning. Answer the Executor's request directly in concise, human-readable Markdown. State uncertainty plainly and never claim verification that the supplied evidence does not show.",
|
|
53
|
+
].join(" ");
|
|
54
|
+
|
|
55
|
+
export const ADVISOR_DECISION_SYSTEM = [
|
|
56
|
+
"You are the Advisor's automatic safety gate for a repeated-tool loop.",
|
|
57
|
+
"Review the supplied context and decide whether the Executor may proceed.",
|
|
58
|
+
"Answer in concise Markdown. Your first line must be exactly `Decision: proceed`, `Decision: revise`, `Decision: insufficient-evidence`, or `Decision: blocked`.",
|
|
59
|
+
"Use blocked only for a critical issue requiring the user. Never claim verification that the supplied evidence does not show.",
|
|
53
60
|
].join(" ");
|
|
54
61
|
|
|
55
62
|
type Advice = { verdict: AdvisorVerdict; criticalFindings: Array<{ severity: string; claim: string; evidence: string }>; missingEvidence: string[]; smallestNextStep: string; verificationRequired: string[]; escalationReason: string | null };
|
|
56
63
|
|
|
64
|
+
export const parseAutomaticDecision = (text: string): Advice => {
|
|
65
|
+
const firstLine = text.split(/\r?\n/, 1)[0];
|
|
66
|
+
const match = /^Decision: (proceed|revise|blocked|insufficient-evidence)$/i.exec(firstLine);
|
|
67
|
+
if (!match) return parseAdvice("");
|
|
68
|
+
return { verdict: match[1] as AdvisorVerdict, criticalFindings: [], missingEvidence: [], smallestNextStep: text.trim(), verificationRequired: [], escalationReason: null };
|
|
69
|
+
};
|
|
70
|
+
|
|
57
71
|
export const parseAdvice = (text: string): Advice => {
|
|
58
72
|
try {
|
|
59
73
|
const value = JSON.parse(text) as Partial<Advice>;
|
|
@@ -61,7 +75,7 @@ export const parseAdvice = (text: string): Advice => {
|
|
|
61
75
|
if (!Array.isArray(value.criticalFindings) || !Array.isArray(value.missingEvidence) || !Array.isArray(value.verificationRequired) || typeof value.smallestNextStep !== "string" || !value.missingEvidence.every((item) => typeof item === "string") || !value.verificationRequired.every((item) => typeof item === "string") || !value.criticalFindings.every((item) => item && typeof item === "object" && typeof (item as Record<string, unknown>).severity === "string" && typeof (item as Record<string, unknown>).claim === "string" && typeof (item as Record<string, unknown>).evidence === "string")) throw new Error("invalid shape");
|
|
62
76
|
return { verdict: value.verdict as AdvisorVerdict, criticalFindings: value.criticalFindings as Advice["criticalFindings"], missingEvidence: value.missingEvidence as string[], smallestNextStep: value.smallestNextStep, verificationRequired: value.verificationRequired as string[], escalationReason: typeof value.escalationReason === "string" ? value.escalationReason : null };
|
|
63
77
|
} catch {
|
|
64
|
-
return { verdict: "insufficient-evidence", criticalFindings: [{ severity: "medium", claim: "Advisor response was not structured", evidence: "The response
|
|
78
|
+
return { verdict: "insufficient-evidence", criticalFindings: [{ severity: "medium", claim: "Advisor response was not structured for an automatic safety decision", evidence: "The response was not valid structured decision data." }], missingEvidence: [], smallestNextStep: "Review the Advisor's guidance before retrying.", verificationRequired: [], escalationReason: null };
|
|
65
79
|
}
|
|
66
80
|
};
|
|
67
81
|
|
|
@@ -78,6 +92,7 @@ export const consult = async (
|
|
|
78
92
|
question?: string,
|
|
79
93
|
signal?: AbortSignal,
|
|
80
94
|
onChunk?: (thinking: string, text: string) => void,
|
|
95
|
+
structuredMode = false,
|
|
81
96
|
) => {
|
|
82
97
|
loadConfig(ctx);
|
|
83
98
|
const [provider, modelId] = splitRef(advisorRef);
|
|
@@ -97,7 +112,7 @@ export const consult = async (
|
|
|
97
112
|
let thinkingText = "";
|
|
98
113
|
let responseText = "";
|
|
99
114
|
|
|
100
|
-
const eventStream = stream(model, { systemPrompt: ADVISOR_SYSTEM, messages }, {
|
|
115
|
+
const eventStream = stream(model, { systemPrompt: structuredMode ? ADVISOR_DECISION_SYSTEM : ADVISOR_SYSTEM, messages }, {
|
|
101
116
|
apiKey: auth.apiKey,
|
|
102
117
|
headers: auth.headers,
|
|
103
118
|
env: auth.env,
|
|
@@ -124,8 +139,8 @@ export const consult = async (
|
|
|
124
139
|
.trim() || responseText;
|
|
125
140
|
|
|
126
141
|
if (!advice) throw new Error("Advisor returned no advice.");
|
|
127
|
-
const structured = parseAdvice(advice);
|
|
128
|
-
return { advice
|
|
142
|
+
const structured = structuredMode ? parseAutomaticDecision(advice) : parseAdvice(advice);
|
|
143
|
+
return { advice, thinkingText, structured };
|
|
129
144
|
};
|
|
130
145
|
|
|
131
146
|
export const registerAdvisorTool = (pi: ExtensionAPI) => {
|
|
@@ -170,7 +185,7 @@ export const registerAdvisorTool = (pi: ExtensionAPI) => {
|
|
|
170
185
|
details: { question: `Loop gate: ${event.toolName} repeated ${advisorLoopThresholdRef} times` },
|
|
171
186
|
}, { deliverAs: "steer" });
|
|
172
187
|
try {
|
|
173
|
-
const { advice, structured } = await consult(ctx, `${reason} Review the repeated actions and recommend the smallest safe next step
|
|
188
|
+
const { advice, structured } = await consult(ctx, `${reason} Review the repeated actions and recommend the smallest safe next step.`, undefined, undefined, true);
|
|
174
189
|
session.recordConsultation("automatic", structured.verdict);
|
|
175
190
|
pi.sendMessage({
|
|
176
191
|
customType: "advisor-manual-result",
|