advisor-pi 1.0.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/README.md +102 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +489 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/index.ts +577 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# advisor-pi
|
|
2
|
+
|
|
3
|
+
Advisor-style strategic guidance for Pi Coding Agent.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
`advisor-pi` adds an LLM-callable `advisor` tool. During complex workflows, the
|
|
8
|
+
executor model can pause and consult a configured higher-capability advisor model
|
|
9
|
+
for planning, risk analysis, course correction, or review guidance.
|
|
10
|
+
|
|
11
|
+
The advisor receives the current conversation transcript plus the executor's
|
|
12
|
+
question. It has no tools and cannot modify files; it only returns strategic
|
|
13
|
+
advice to the executor.
|
|
14
|
+
|
|
15
|
+
## Behavior
|
|
16
|
+
|
|
17
|
+
- Registers an `advisor` tool for complex or high-risk tasks.
|
|
18
|
+
- Lets the executor decide when a consultation is useful.
|
|
19
|
+
- Calls a configured advisor model through Pi's model registry and auth.
|
|
20
|
+
- Tracks advisor uses per session branch and stops after the configured limit.
|
|
21
|
+
- Passes a prompt-cache preference (`none`, `short`, or `long`) where the
|
|
22
|
+
selected provider supports it.
|
|
23
|
+
- Shows a compact `advisor:<remaining>` status in Pi's footer when UI is
|
|
24
|
+
available.
|
|
25
|
+
|
|
26
|
+
## Commands
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
/advisor-pi status
|
|
30
|
+
/advisor-pi enable
|
|
31
|
+
/advisor-pi disable
|
|
32
|
+
/advisor-pi model <provider>/<model>
|
|
33
|
+
/advisor-pi max-uses <number>
|
|
34
|
+
/advisor-pi cache <none|short|long>
|
|
35
|
+
/advisor-pi reset
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
/advisor-pi model anthropic/claude-opus-4-5
|
|
42
|
+
/advisor-pi max-uses 5
|
|
43
|
+
/advisor-pi cache long
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## CLI flags
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pi --advisor-model anthropic/claude-opus-4-5 \
|
|
50
|
+
--advisor-max-uses 3 \
|
|
51
|
+
--advisor-cache short
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Disable on startup:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pi --advisor-enabled=false
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
From the repo root:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cp -r extensions/advisor-pi ~/.pi/agent/extensions/
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then run `/reload` in Pi.
|
|
69
|
+
|
|
70
|
+
## Cost and latency
|
|
71
|
+
|
|
72
|
+
Each advisor consultation is a separate model call. That means:
|
|
73
|
+
|
|
74
|
+
- Advisor input and output are billed separately by the selected provider.
|
|
75
|
+
- Streaming from the executor pauses while the advisor call runs.
|
|
76
|
+
- Longer transcripts cost more because the advisor reads the conversation
|
|
77
|
+
context.
|
|
78
|
+
- The `max-uses` setting is a safety budget; raise it only when deeper review is
|
|
79
|
+
worth the extra cost.
|
|
80
|
+
|
|
81
|
+
## Caching
|
|
82
|
+
|
|
83
|
+
`advisor-pi` passes the configured cache preference to Pi's AI provider layer:
|
|
84
|
+
|
|
85
|
+
- `none` — do not request prompt caching.
|
|
86
|
+
- `short` — request normal/short cache retention where supported.
|
|
87
|
+
- `long` — request long cache retention where supported.
|
|
88
|
+
|
|
89
|
+
Provider support varies. Some providers ignore cache preferences, some require
|
|
90
|
+
specific model compatibility, and cache reads/writes may still be billed.
|
|
91
|
+
|
|
92
|
+
## Known limitations
|
|
93
|
+
|
|
94
|
+
- This is a portable Pi custom-tool approximation, not Anthropic's native beta
|
|
95
|
+
`advisor_20260301` server tool.
|
|
96
|
+
- Native provider-specific advisor usage fields may not appear in provider usage
|
|
97
|
+
reports.
|
|
98
|
+
- The advisor has no tools and cannot inspect files beyond what appears in the
|
|
99
|
+
transcript.
|
|
100
|
+
- Very long conversations can make advisor calls slower and more expensive.
|
|
101
|
+
- `max-uses` is tracked per Pi session branch from extension state and tool
|
|
102
|
+
result details; manual session editing can affect reconstruction.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAIN,KAAK,YAAY,EAEjB,MAAM,iCAAiC,CAAC;AAgEzC,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,EAAE,YAAY,QAkW1D"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
import { complete, StringEnum } from "@earendil-works/pi-ai";
|
|
2
|
+
import { buildSessionContext, convertToLlm, serializeConversation, } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
const STATE_ENTRY = "advisor-pi-state";
|
|
5
|
+
const TOOL_NAME = "advisor";
|
|
6
|
+
const DEFAULT_ADVISOR_MODEL = "openai-codex/gpt-5.5";
|
|
7
|
+
const DEFAULT_MAX_USES = 3;
|
|
8
|
+
const DEFAULT_CACHE_RETENTION = "short";
|
|
9
|
+
const DEFAULT_TIMEOUT_MS = 600_000;
|
|
10
|
+
const DEFAULT_MAX_TOKENS = 4_000;
|
|
11
|
+
const advisorToolSchema = Type.Object({
|
|
12
|
+
question: Type.String({
|
|
13
|
+
description: "Strategic question for the advisor. Ask for planning, risk analysis, course correction, or review guidance.",
|
|
14
|
+
}),
|
|
15
|
+
phase: Type.Optional(StringEnum(["planning", "course_correction", "review", "stuck", "other"], {
|
|
16
|
+
description: "Why the executor is consulting the advisor.",
|
|
17
|
+
default: "other",
|
|
18
|
+
})),
|
|
19
|
+
context: Type.Optional(Type.String({
|
|
20
|
+
description: "Optional extra context that is not obvious from the transcript, such as constraints, current plan, or failed attempts.",
|
|
21
|
+
})),
|
|
22
|
+
});
|
|
23
|
+
export default function advisorPiExtension(pi) {
|
|
24
|
+
let config = defaultConfig();
|
|
25
|
+
let useCount = 0;
|
|
26
|
+
pi.registerFlag("advisor-model", {
|
|
27
|
+
description: "Advisor model as provider/model, e.g. openai-codex/gpt-5.5",
|
|
28
|
+
type: "string",
|
|
29
|
+
});
|
|
30
|
+
pi.registerFlag("advisor-max-uses", {
|
|
31
|
+
description: "Maximum advisor calls per session branch",
|
|
32
|
+
type: "string",
|
|
33
|
+
});
|
|
34
|
+
pi.registerFlag("advisor-cache", {
|
|
35
|
+
description: "Advisor prompt-cache preference: none, short, or long",
|
|
36
|
+
type: "string",
|
|
37
|
+
});
|
|
38
|
+
pi.registerFlag("advisor-enabled", {
|
|
39
|
+
description: "Enable the advisor tool on startup",
|
|
40
|
+
type: "boolean",
|
|
41
|
+
default: true,
|
|
42
|
+
});
|
|
43
|
+
pi.registerTool({
|
|
44
|
+
name: TOOL_NAME,
|
|
45
|
+
label: "Advisor",
|
|
46
|
+
description: "Consult a configured higher-capability advisor model for strategic guidance during complex agent tasks. The advisor reads the current conversation transcript and returns planning, risk, or course-correction advice. It has no tools and does not modify files.",
|
|
47
|
+
promptSnippet: "Consult a higher-capability advisor model for strategic planning, risk checks, and course correction on complex tasks.",
|
|
48
|
+
promptGuidelines: [
|
|
49
|
+
"Use advisor before starting a complex, multi-step, or high-risk task when strategic planning would reduce mistakes.",
|
|
50
|
+
"Use advisor when stuck, when tests keep failing, or when choosing between competing implementation approaches.",
|
|
51
|
+
"Do not use advisor for simple lookups, trivial edits, or when the user explicitly wants the fastest possible answer.",
|
|
52
|
+
],
|
|
53
|
+
parameters: advisorToolSchema,
|
|
54
|
+
executionMode: "sequential",
|
|
55
|
+
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
56
|
+
refreshStateFromBranch(ctx);
|
|
57
|
+
if (!config.enabled) {
|
|
58
|
+
return advisorDisabledResult(config, useCount, params);
|
|
59
|
+
}
|
|
60
|
+
if (useCount >= config.maxUses) {
|
|
61
|
+
return advisorLimitResult(config, useCount, params);
|
|
62
|
+
}
|
|
63
|
+
const model = ctx.modelRegistry.find(config.provider, config.modelId);
|
|
64
|
+
if (!model) {
|
|
65
|
+
throw new Error(`Advisor model not found: ${config.provider}/${config.modelId}. Run /advisor-pi model <provider>/<model>.`);
|
|
66
|
+
}
|
|
67
|
+
onUpdate?.({
|
|
68
|
+
content: [
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: `Consulting advisor ${config.provider}/${config.modelId}...`,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
details: makeSkippedDetails(config, useCount, params),
|
|
75
|
+
});
|
|
76
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
77
|
+
if (!auth.ok)
|
|
78
|
+
throw new Error(auth.error);
|
|
79
|
+
const startedAt = Date.now();
|
|
80
|
+
const conversationText = serializeCurrentConversation(ctx);
|
|
81
|
+
const userMessage = {
|
|
82
|
+
role: "user",
|
|
83
|
+
content: [
|
|
84
|
+
{
|
|
85
|
+
type: "text",
|
|
86
|
+
text: buildAdvisorUserPrompt(params, conversationText),
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
};
|
|
91
|
+
const response = await complete(model, {
|
|
92
|
+
systemPrompt: ADVISOR_SYSTEM_PROMPT,
|
|
93
|
+
messages: [userMessage],
|
|
94
|
+
}, {
|
|
95
|
+
apiKey: auth.apiKey,
|
|
96
|
+
headers: auth.headers,
|
|
97
|
+
signal,
|
|
98
|
+
cacheRetention: config.cacheRetention,
|
|
99
|
+
sessionId: `advisor-pi:${ctx.sessionManager.getSessionId()}`,
|
|
100
|
+
maxTokens: config.maxTokens,
|
|
101
|
+
timeoutMs: config.timeoutMs,
|
|
102
|
+
});
|
|
103
|
+
if (response.stopReason === "error") {
|
|
104
|
+
throw new Error(response.errorMessage ?? "Advisor model returned an error");
|
|
105
|
+
}
|
|
106
|
+
if (response.stopReason === "aborted") {
|
|
107
|
+
throw new Error("Advisor call aborted");
|
|
108
|
+
}
|
|
109
|
+
useCount += 1;
|
|
110
|
+
persistState(pi, config, useCount);
|
|
111
|
+
updateStatus(ctx);
|
|
112
|
+
const elapsedMs = Date.now() - startedAt;
|
|
113
|
+
const text = extractText(response.content) || "Advisor returned no text guidance.";
|
|
114
|
+
const details = {
|
|
115
|
+
advisor: {
|
|
116
|
+
provider: response.provider,
|
|
117
|
+
model: response.model,
|
|
118
|
+
phase: params.phase ?? "other",
|
|
119
|
+
useCount,
|
|
120
|
+
maxUses: config.maxUses,
|
|
121
|
+
cacheRetention: config.cacheRetention,
|
|
122
|
+
elapsedMs,
|
|
123
|
+
stopReason: response.stopReason,
|
|
124
|
+
usage: response.usage,
|
|
125
|
+
},
|
|
126
|
+
state: makeStateEntry(config, useCount),
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
content: [
|
|
130
|
+
{
|
|
131
|
+
type: "text",
|
|
132
|
+
text: `Advisor guidance (${useCount}/${config.maxUses}, ${config.provider}/${config.modelId}):\n\n${text}`,
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
details,
|
|
136
|
+
};
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
pi.registerCommand("advisor-pi", {
|
|
140
|
+
description: "Configure advisor-pi: status, enable, disable, model, max-uses, cache, reset",
|
|
141
|
+
handler: async (args, ctx) => {
|
|
142
|
+
const result = handleCommand(args.trim(), ctx);
|
|
143
|
+
if (result.persist)
|
|
144
|
+
persistState(pi, config, useCount);
|
|
145
|
+
if (result.updateToolState)
|
|
146
|
+
syncActiveTool(pi);
|
|
147
|
+
updateStatus(ctx);
|
|
148
|
+
ctx.ui.notify(result.message, result.level);
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
152
|
+
refreshStateFromBranch(ctx);
|
|
153
|
+
});
|
|
154
|
+
pi.on("session_tree", async (_event, ctx) => {
|
|
155
|
+
refreshStateFromBranch(ctx);
|
|
156
|
+
});
|
|
157
|
+
pi.on("before_agent_start", async (event) => {
|
|
158
|
+
if (!config.enabled)
|
|
159
|
+
return;
|
|
160
|
+
return {
|
|
161
|
+
systemPrompt: `${event.systemPrompt}\n\n${buildExecutorGuidance(config, useCount)}`,
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
pi.on("turn_start", async () => {
|
|
165
|
+
persistState(pi, config, useCount);
|
|
166
|
+
});
|
|
167
|
+
function refreshStateFromBranch(ctx) {
|
|
168
|
+
config = defaultConfig();
|
|
169
|
+
useCount = 0;
|
|
170
|
+
const restoredFromBranch = restoreStateFromSession(ctx);
|
|
171
|
+
if (!restoredFromBranch)
|
|
172
|
+
applyStartupFlags(pi);
|
|
173
|
+
syncActiveTool(pi);
|
|
174
|
+
updateStatus(ctx);
|
|
175
|
+
}
|
|
176
|
+
function restoreStateFromSession(ctx) {
|
|
177
|
+
let restored = false;
|
|
178
|
+
const branch = ctx.sessionManager.getBranch();
|
|
179
|
+
for (const entry of branch) {
|
|
180
|
+
if (entry.type === "custom" && entry.customType === STATE_ENTRY) {
|
|
181
|
+
restored = true;
|
|
182
|
+
const data = entry.data;
|
|
183
|
+
if (data?.config)
|
|
184
|
+
config = normalizeConfig(data.config, config);
|
|
185
|
+
if (typeof data?.useCount === "number")
|
|
186
|
+
useCount = Math.max(0, data.useCount);
|
|
187
|
+
}
|
|
188
|
+
if (entry.type === "message" && entry.message.role === "toolResult" && entry.message.toolName === TOOL_NAME) {
|
|
189
|
+
restored = true;
|
|
190
|
+
const details = entry.message.details;
|
|
191
|
+
if (details?.state?.config)
|
|
192
|
+
config = normalizeConfig(details.state.config, config);
|
|
193
|
+
if (typeof details?.state?.useCount === "number")
|
|
194
|
+
useCount = Math.max(useCount, details.state.useCount);
|
|
195
|
+
else if (details?.advisor?.useCount)
|
|
196
|
+
useCount = Math.max(useCount, details.advisor.useCount);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return restored;
|
|
200
|
+
}
|
|
201
|
+
function applyStartupFlags(api) {
|
|
202
|
+
const enabledFlag = api.getFlag("advisor-enabled");
|
|
203
|
+
if (typeof enabledFlag === "boolean")
|
|
204
|
+
config.enabled = enabledFlag;
|
|
205
|
+
const modelFlag = api.getFlag("advisor-model");
|
|
206
|
+
if (typeof modelFlag === "string" && modelFlag.trim()) {
|
|
207
|
+
const parsed = parseModelSpec(modelFlag.trim());
|
|
208
|
+
if (parsed) {
|
|
209
|
+
config.provider = parsed.provider;
|
|
210
|
+
config.modelId = parsed.modelId;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const maxUsesFlag = api.getFlag("advisor-max-uses");
|
|
214
|
+
if (typeof maxUsesFlag === "string") {
|
|
215
|
+
const maxUses = parsePositiveInt(maxUsesFlag);
|
|
216
|
+
if (maxUses !== undefined)
|
|
217
|
+
config.maxUses = maxUses;
|
|
218
|
+
}
|
|
219
|
+
const cacheFlag = api.getFlag("advisor-cache");
|
|
220
|
+
if (typeof cacheFlag === "string") {
|
|
221
|
+
const cacheRetention = parseCacheRetention(cacheFlag);
|
|
222
|
+
if (cacheRetention)
|
|
223
|
+
config.cacheRetention = cacheRetention;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function handleCommand(args, ctx) {
|
|
227
|
+
if (!args || args === "status") {
|
|
228
|
+
return {
|
|
229
|
+
message: formatStatus(ctx),
|
|
230
|
+
level: "info",
|
|
231
|
+
persist: false,
|
|
232
|
+
updateToolState: false,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const [command, ...rest] = args.split(/\s+/);
|
|
236
|
+
const value = rest.join(" ").trim();
|
|
237
|
+
switch (command) {
|
|
238
|
+
case "enable":
|
|
239
|
+
config.enabled = true;
|
|
240
|
+
return { message: "advisor-pi enabled", level: "info", persist: true, updateToolState: true };
|
|
241
|
+
case "disable":
|
|
242
|
+
config.enabled = false;
|
|
243
|
+
return { message: "advisor-pi disabled", level: "info", persist: true, updateToolState: true };
|
|
244
|
+
case "reset":
|
|
245
|
+
useCount = 0;
|
|
246
|
+
return { message: "advisor-pi use count reset", level: "info", persist: true, updateToolState: false };
|
|
247
|
+
case "model": {
|
|
248
|
+
const parsed = parseModelSpec(value);
|
|
249
|
+
if (!parsed) {
|
|
250
|
+
return {
|
|
251
|
+
message: "Usage: /advisor-pi model <provider>/<model>",
|
|
252
|
+
level: "error",
|
|
253
|
+
persist: false,
|
|
254
|
+
updateToolState: false,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
const model = ctx.modelRegistry.find(parsed.provider, parsed.modelId);
|
|
258
|
+
if (!model) {
|
|
259
|
+
return {
|
|
260
|
+
message: `Advisor model not found: ${parsed.provider}/${parsed.modelId}`,
|
|
261
|
+
level: "error",
|
|
262
|
+
persist: false,
|
|
263
|
+
updateToolState: false,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
config.provider = parsed.provider;
|
|
267
|
+
config.modelId = parsed.modelId;
|
|
268
|
+
return {
|
|
269
|
+
message: `advisor-pi model set to ${config.provider}/${config.modelId}`,
|
|
270
|
+
level: "info",
|
|
271
|
+
persist: true,
|
|
272
|
+
updateToolState: false,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
case "max-uses": {
|
|
276
|
+
const maxUses = parsePositiveInt(value);
|
|
277
|
+
if (maxUses === undefined) {
|
|
278
|
+
return {
|
|
279
|
+
message: "Usage: /advisor-pi max-uses <positive-number>",
|
|
280
|
+
level: "error",
|
|
281
|
+
persist: false,
|
|
282
|
+
updateToolState: false,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
config.maxUses = maxUses;
|
|
286
|
+
return {
|
|
287
|
+
message: `advisor-pi max uses set to ${maxUses}`,
|
|
288
|
+
level: "info",
|
|
289
|
+
persist: true,
|
|
290
|
+
updateToolState: false,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
case "cache": {
|
|
294
|
+
const cacheRetention = parseCacheRetention(value);
|
|
295
|
+
if (!cacheRetention) {
|
|
296
|
+
return {
|
|
297
|
+
message: "Usage: /advisor-pi cache <none|short|long>",
|
|
298
|
+
level: "error",
|
|
299
|
+
persist: false,
|
|
300
|
+
updateToolState: false,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
config.cacheRetention = cacheRetention;
|
|
304
|
+
return {
|
|
305
|
+
message: `advisor-pi cache set to ${cacheRetention}`,
|
|
306
|
+
level: "info",
|
|
307
|
+
persist: true,
|
|
308
|
+
updateToolState: false,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
default:
|
|
312
|
+
return {
|
|
313
|
+
message: "Usage: /advisor-pi [status|enable|disable|model <provider>/<model>|max-uses <n>|cache <none|short|long>|reset]",
|
|
314
|
+
level: "error",
|
|
315
|
+
persist: false,
|
|
316
|
+
updateToolState: false,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function syncActiveTool(api) {
|
|
321
|
+
const activeTools = api.getActiveTools();
|
|
322
|
+
const hasAdvisor = activeTools.includes(TOOL_NAME);
|
|
323
|
+
if (config.enabled && !hasAdvisor) {
|
|
324
|
+
api.setActiveTools([...activeTools, TOOL_NAME]);
|
|
325
|
+
}
|
|
326
|
+
else if (!config.enabled && hasAdvisor) {
|
|
327
|
+
api.setActiveTools(activeTools.filter((tool) => tool !== TOOL_NAME));
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function updateStatus(ctx) {
|
|
331
|
+
if (!ctx.hasUI)
|
|
332
|
+
return;
|
|
333
|
+
if (!config.enabled) {
|
|
334
|
+
ctx.ui.setStatus("advisor-pi", undefined);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const remaining = Math.max(0, config.maxUses - useCount);
|
|
338
|
+
ctx.ui.setStatus("advisor-pi", ctx.ui.theme.fg(remaining > 0 ? "accent" : "warning", `advisor:${remaining}`));
|
|
339
|
+
}
|
|
340
|
+
function formatStatus(ctx) {
|
|
341
|
+
const model = ctx.modelRegistry.find(config.provider, config.modelId);
|
|
342
|
+
const availability = model ? "available" : "not found";
|
|
343
|
+
return [
|
|
344
|
+
`advisor-pi ${config.enabled ? "enabled" : "disabled"}`,
|
|
345
|
+
`model: ${config.provider}/${config.modelId} (${availability})`,
|
|
346
|
+
`uses: ${useCount}/${config.maxUses}`,
|
|
347
|
+
`cache: ${config.cacheRetention}`,
|
|
348
|
+
].join(" • ");
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const ADVISOR_SYSTEM_PROMPT = `You are an advisor model for Pi Coding Agent.
|
|
352
|
+
|
|
353
|
+
Your role is strategic guidance only. You do not have tools and you do not make changes. Given the executor's question and conversation transcript:
|
|
354
|
+
|
|
355
|
+
- Identify the best next plan or course correction.
|
|
356
|
+
- Call out risks, missing information, edge cases, and test strategy.
|
|
357
|
+
- Prefer concise, actionable guidance the executor can apply immediately.
|
|
358
|
+
- Do not restate the full transcript.
|
|
359
|
+
- If the task is unsafe, impossible, or underspecified, say what must be clarified.
|
|
360
|
+
|
|
361
|
+
Return guidance in short sections with bullets when useful.`;
|
|
362
|
+
function defaultConfig() {
|
|
363
|
+
const parsed = parseModelSpec(DEFAULT_ADVISOR_MODEL) ?? { provider: "openai-codex", modelId: "gpt-5.5" };
|
|
364
|
+
return {
|
|
365
|
+
enabled: true,
|
|
366
|
+
provider: parsed.provider,
|
|
367
|
+
modelId: parsed.modelId,
|
|
368
|
+
maxUses: DEFAULT_MAX_USES,
|
|
369
|
+
cacheRetention: DEFAULT_CACHE_RETENTION,
|
|
370
|
+
maxTokens: DEFAULT_MAX_TOKENS,
|
|
371
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function buildExecutorGuidance(config, useCount) {
|
|
375
|
+
const remaining = Math.max(0, config.maxUses - useCount);
|
|
376
|
+
return [
|
|
377
|
+
"Advisor-pi is enabled.",
|
|
378
|
+
`The advisor tool consults ${config.provider}/${config.modelId} for strategic guidance and has ${remaining}/${config.maxUses} uses remaining on this branch.`,
|
|
379
|
+
"Use advisor for complex planning, risky implementation choices, repeated failures, or course correction. Do not use advisor for trivial edits or simple facts.",
|
|
380
|
+
`Advisor cache preference is ${config.cacheRetention}; caching support is provider-dependent.`,
|
|
381
|
+
].join("\n");
|
|
382
|
+
}
|
|
383
|
+
function serializeCurrentConversation(ctx) {
|
|
384
|
+
const entries = ctx.sessionManager.getEntries();
|
|
385
|
+
const leafId = ctx.sessionManager.getLeafId();
|
|
386
|
+
const sessionContext = buildSessionContext(entries, leafId);
|
|
387
|
+
const llmMessages = convertToLlm(sessionContext.messages);
|
|
388
|
+
return serializeConversation(llmMessages);
|
|
389
|
+
}
|
|
390
|
+
function buildAdvisorUserPrompt(params, conversationText) {
|
|
391
|
+
return [
|
|
392
|
+
"## Executor Question",
|
|
393
|
+
params.question,
|
|
394
|
+
"",
|
|
395
|
+
"## Consultation Phase",
|
|
396
|
+
params.phase ?? "other",
|
|
397
|
+
"",
|
|
398
|
+
...(params.context ? ["## Extra Context", params.context, ""] : []),
|
|
399
|
+
"## Conversation Transcript",
|
|
400
|
+
conversationText,
|
|
401
|
+
].join("\n");
|
|
402
|
+
}
|
|
403
|
+
function extractText(content) {
|
|
404
|
+
return content
|
|
405
|
+
.filter((part) => part.type === "text" && typeof part.text === "string")
|
|
406
|
+
.map((part) => part.text)
|
|
407
|
+
.join("\n")
|
|
408
|
+
.trim();
|
|
409
|
+
}
|
|
410
|
+
function advisorDisabledResult(config, useCount, params) {
|
|
411
|
+
return {
|
|
412
|
+
content: [
|
|
413
|
+
{
|
|
414
|
+
type: "text",
|
|
415
|
+
text: `advisor-pi is disabled. The executor should continue without advisor guidance for: ${params.question}`,
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
details: makeSkippedDetails(config, useCount, params),
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
function advisorLimitResult(config, useCount, params) {
|
|
422
|
+
return {
|
|
423
|
+
content: [
|
|
424
|
+
{
|
|
425
|
+
type: "text",
|
|
426
|
+
text: `Advisor use limit reached. The executor should continue without another advisor call for: ${params.question}`,
|
|
427
|
+
},
|
|
428
|
+
],
|
|
429
|
+
details: makeSkippedDetails(config, useCount, params),
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function makeSkippedDetails(config, useCount, params) {
|
|
433
|
+
return {
|
|
434
|
+
advisor: {
|
|
435
|
+
provider: config.provider,
|
|
436
|
+
model: config.modelId,
|
|
437
|
+
phase: params.phase ?? "other",
|
|
438
|
+
useCount,
|
|
439
|
+
maxUses: config.maxUses,
|
|
440
|
+
cacheRetention: config.cacheRetention,
|
|
441
|
+
elapsedMs: 0,
|
|
442
|
+
stopReason: "skipped",
|
|
443
|
+
},
|
|
444
|
+
state: makeStateEntry(config, useCount),
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function makeStateEntry(config, useCount) {
|
|
448
|
+
return {
|
|
449
|
+
version: 1,
|
|
450
|
+
config: { ...config },
|
|
451
|
+
useCount,
|
|
452
|
+
updatedAt: new Date().toISOString(),
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
function persistState(pi, config, useCount) {
|
|
456
|
+
pi.appendEntry(STATE_ENTRY, makeStateEntry(config, useCount));
|
|
457
|
+
}
|
|
458
|
+
function normalizeConfig(input, fallback) {
|
|
459
|
+
return {
|
|
460
|
+
enabled: typeof input.enabled === "boolean" ? input.enabled : fallback.enabled,
|
|
461
|
+
provider: typeof input.provider === "string" && input.provider ? input.provider : fallback.provider,
|
|
462
|
+
modelId: typeof input.modelId === "string" && input.modelId ? input.modelId : fallback.modelId,
|
|
463
|
+
maxUses: typeof input.maxUses === "number" && input.maxUses > 0 ? Math.floor(input.maxUses) : fallback.maxUses,
|
|
464
|
+
cacheRetention: parseCacheRetention(input.cacheRetention) ?? fallback.cacheRetention,
|
|
465
|
+
maxTokens: typeof input.maxTokens === "number" && input.maxTokens > 0 ? Math.floor(input.maxTokens) : fallback.maxTokens,
|
|
466
|
+
timeoutMs: typeof input.timeoutMs === "number" && input.timeoutMs > 0 ? Math.floor(input.timeoutMs) : fallback.timeoutMs,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
function parseModelSpec(value) {
|
|
470
|
+
const slash = value.indexOf("/");
|
|
471
|
+
if (slash <= 0 || slash === value.length - 1)
|
|
472
|
+
return undefined;
|
|
473
|
+
return {
|
|
474
|
+
provider: value.slice(0, slash),
|
|
475
|
+
modelId: value.slice(slash + 1),
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
function parsePositiveInt(value) {
|
|
479
|
+
const parsed = Number.parseInt(value, 10);
|
|
480
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
481
|
+
return undefined;
|
|
482
|
+
return parsed;
|
|
483
|
+
}
|
|
484
|
+
function parseCacheRetention(value) {
|
|
485
|
+
if (value === "none" || value === "short" || value === "long")
|
|
486
|
+
return value;
|
|
487
|
+
return undefined;
|
|
488
|
+
}
|
|
489
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "advisor-pi",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Advisor-style strategic model guidance for Pi Coding Agent workflows",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"pi": {
|
|
24
|
+
"extensions": ["./src/index.ts"]
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"pi",
|
|
28
|
+
"advisor",
|
|
29
|
+
"strategic-guidance",
|
|
30
|
+
"model-delegation",
|
|
31
|
+
"agent-workflows"
|
|
32
|
+
],
|
|
33
|
+
"author": "pi-extensions contributors",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/luongnv89/pi-extensions.git"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/luongnv89/pi-extensions/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/luongnv89/pi-extensions/tree/main/extensions/advisor-pi",
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@earendil-works/pi-agent-core": "^0.75.4",
|
|
45
|
+
"@earendil-works/pi-ai": "^0.75.4",
|
|
46
|
+
"@earendil-works/pi-coding-agent": "^0.75.4",
|
|
47
|
+
"typebox": "^1.0.55"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"typescript": "^5.6.0"
|
|
51
|
+
},
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
import { complete, StringEnum, type CacheRetention, type Message, type Usage } from "@earendil-works/pi-ai";
|
|
2
|
+
import {
|
|
3
|
+
buildSessionContext,
|
|
4
|
+
convertToLlm,
|
|
5
|
+
serializeConversation,
|
|
6
|
+
type ExtensionAPI,
|
|
7
|
+
type ExtensionContext,
|
|
8
|
+
} from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import { Type, type Static } from "typebox";
|
|
10
|
+
|
|
11
|
+
const STATE_ENTRY = "advisor-pi-state";
|
|
12
|
+
const TOOL_NAME = "advisor";
|
|
13
|
+
const DEFAULT_ADVISOR_MODEL = "openai-codex/gpt-5.5";
|
|
14
|
+
const DEFAULT_MAX_USES = 3;
|
|
15
|
+
const DEFAULT_CACHE_RETENTION: CacheRetention = "short";
|
|
16
|
+
const DEFAULT_TIMEOUT_MS = 600_000;
|
|
17
|
+
const DEFAULT_MAX_TOKENS = 4_000;
|
|
18
|
+
|
|
19
|
+
const advisorToolSchema = Type.Object({
|
|
20
|
+
question: Type.String({
|
|
21
|
+
description:
|
|
22
|
+
"Strategic question for the advisor. Ask for planning, risk analysis, course correction, or review guidance.",
|
|
23
|
+
}),
|
|
24
|
+
phase: Type.Optional(
|
|
25
|
+
StringEnum(["planning", "course_correction", "review", "stuck", "other"] as const, {
|
|
26
|
+
description: "Why the executor is consulting the advisor.",
|
|
27
|
+
default: "other",
|
|
28
|
+
}),
|
|
29
|
+
),
|
|
30
|
+
context: Type.Optional(
|
|
31
|
+
Type.String({
|
|
32
|
+
description:
|
|
33
|
+
"Optional extra context that is not obvious from the transcript, such as constraints, current plan, or failed attempts.",
|
|
34
|
+
}),
|
|
35
|
+
),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
type AdvisorToolInput = Static<typeof advisorToolSchema>;
|
|
39
|
+
|
|
40
|
+
type AdvisorConfig = {
|
|
41
|
+
enabled: boolean;
|
|
42
|
+
provider: string;
|
|
43
|
+
modelId: string;
|
|
44
|
+
maxUses: number;
|
|
45
|
+
cacheRetention: CacheRetention;
|
|
46
|
+
maxTokens: number;
|
|
47
|
+
timeoutMs: number;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type AdvisorStateEntry = {
|
|
51
|
+
version: 1;
|
|
52
|
+
config: AdvisorConfig;
|
|
53
|
+
useCount: number;
|
|
54
|
+
updatedAt: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
type AdvisorToolDetails = {
|
|
58
|
+
advisor: {
|
|
59
|
+
provider: string;
|
|
60
|
+
model: string;
|
|
61
|
+
phase: string;
|
|
62
|
+
useCount: number;
|
|
63
|
+
maxUses: number;
|
|
64
|
+
cacheRetention: CacheRetention;
|
|
65
|
+
elapsedMs: number;
|
|
66
|
+
stopReason: string;
|
|
67
|
+
usage?: Usage;
|
|
68
|
+
};
|
|
69
|
+
state: AdvisorStateEntry;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default function advisorPiExtension(pi: ExtensionAPI) {
|
|
73
|
+
let config = defaultConfig();
|
|
74
|
+
let useCount = 0;
|
|
75
|
+
|
|
76
|
+
pi.registerFlag("advisor-model", {
|
|
77
|
+
description: "Advisor model as provider/model, e.g. openai-codex/gpt-5.5",
|
|
78
|
+
type: "string",
|
|
79
|
+
});
|
|
80
|
+
pi.registerFlag("advisor-max-uses", {
|
|
81
|
+
description: "Maximum advisor calls per session branch",
|
|
82
|
+
type: "string",
|
|
83
|
+
});
|
|
84
|
+
pi.registerFlag("advisor-cache", {
|
|
85
|
+
description: "Advisor prompt-cache preference: none, short, or long",
|
|
86
|
+
type: "string",
|
|
87
|
+
});
|
|
88
|
+
pi.registerFlag("advisor-enabled", {
|
|
89
|
+
description: "Enable the advisor tool on startup",
|
|
90
|
+
type: "boolean",
|
|
91
|
+
default: true,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
pi.registerTool<typeof advisorToolSchema, AdvisorToolDetails>({
|
|
95
|
+
name: TOOL_NAME,
|
|
96
|
+
label: "Advisor",
|
|
97
|
+
description:
|
|
98
|
+
"Consult a configured higher-capability advisor model for strategic guidance during complex agent tasks. The advisor reads the current conversation transcript and returns planning, risk, or course-correction advice. It has no tools and does not modify files.",
|
|
99
|
+
promptSnippet:
|
|
100
|
+
"Consult a higher-capability advisor model for strategic planning, risk checks, and course correction on complex tasks.",
|
|
101
|
+
promptGuidelines: [
|
|
102
|
+
"Use advisor before starting a complex, multi-step, or high-risk task when strategic planning would reduce mistakes.",
|
|
103
|
+
"Use advisor when stuck, when tests keep failing, or when choosing between competing implementation approaches.",
|
|
104
|
+
"Do not use advisor for simple lookups, trivial edits, or when the user explicitly wants the fastest possible answer.",
|
|
105
|
+
],
|
|
106
|
+
parameters: advisorToolSchema,
|
|
107
|
+
executionMode: "sequential",
|
|
108
|
+
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
109
|
+
refreshStateFromBranch(ctx);
|
|
110
|
+
|
|
111
|
+
if (!config.enabled) {
|
|
112
|
+
return advisorDisabledResult(config, useCount, params);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (useCount >= config.maxUses) {
|
|
116
|
+
return advisorLimitResult(config, useCount, params);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const model = ctx.modelRegistry.find(config.provider, config.modelId);
|
|
120
|
+
if (!model) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Advisor model not found: ${config.provider}/${config.modelId}. Run /advisor-pi model <provider>/<model>.`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
onUpdate?.({
|
|
127
|
+
content: [
|
|
128
|
+
{
|
|
129
|
+
type: "text",
|
|
130
|
+
text: `Consulting advisor ${config.provider}/${config.modelId}...`,
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
details: makeSkippedDetails(config, useCount, params),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
137
|
+
if (!auth.ok) throw new Error(auth.error);
|
|
138
|
+
|
|
139
|
+
const startedAt = Date.now();
|
|
140
|
+
const conversationText = serializeCurrentConversation(ctx);
|
|
141
|
+
const userMessage: Message = {
|
|
142
|
+
role: "user",
|
|
143
|
+
content: [
|
|
144
|
+
{
|
|
145
|
+
type: "text",
|
|
146
|
+
text: buildAdvisorUserPrompt(params, conversationText),
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
timestamp: Date.now(),
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const response = await complete(
|
|
153
|
+
model,
|
|
154
|
+
{
|
|
155
|
+
systemPrompt: ADVISOR_SYSTEM_PROMPT,
|
|
156
|
+
messages: [userMessage],
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
apiKey: auth.apiKey,
|
|
160
|
+
headers: auth.headers,
|
|
161
|
+
signal,
|
|
162
|
+
cacheRetention: config.cacheRetention,
|
|
163
|
+
sessionId: `advisor-pi:${ctx.sessionManager.getSessionId()}`,
|
|
164
|
+
maxTokens: config.maxTokens,
|
|
165
|
+
timeoutMs: config.timeoutMs,
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (response.stopReason === "error") {
|
|
170
|
+
throw new Error(response.errorMessage ?? "Advisor model returned an error");
|
|
171
|
+
}
|
|
172
|
+
if (response.stopReason === "aborted") {
|
|
173
|
+
throw new Error("Advisor call aborted");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
useCount += 1;
|
|
177
|
+
persistState(pi, config, useCount);
|
|
178
|
+
updateStatus(ctx);
|
|
179
|
+
|
|
180
|
+
const elapsedMs = Date.now() - startedAt;
|
|
181
|
+
const text = extractText(response.content) || "Advisor returned no text guidance.";
|
|
182
|
+
const details: AdvisorToolDetails = {
|
|
183
|
+
advisor: {
|
|
184
|
+
provider: response.provider,
|
|
185
|
+
model: response.model,
|
|
186
|
+
phase: params.phase ?? "other",
|
|
187
|
+
useCount,
|
|
188
|
+
maxUses: config.maxUses,
|
|
189
|
+
cacheRetention: config.cacheRetention,
|
|
190
|
+
elapsedMs,
|
|
191
|
+
stopReason: response.stopReason,
|
|
192
|
+
usage: response.usage,
|
|
193
|
+
},
|
|
194
|
+
state: makeStateEntry(config, useCount),
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
content: [
|
|
199
|
+
{
|
|
200
|
+
type: "text",
|
|
201
|
+
text: `Advisor guidance (${useCount}/${config.maxUses}, ${config.provider}/${config.modelId}):\n\n${text}`,
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
details,
|
|
205
|
+
};
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
pi.registerCommand("advisor-pi", {
|
|
210
|
+
description: "Configure advisor-pi: status, enable, disable, model, max-uses, cache, reset",
|
|
211
|
+
handler: async (args, ctx) => {
|
|
212
|
+
const result = handleCommand(args.trim(), ctx);
|
|
213
|
+
if (result.persist) persistState(pi, config, useCount);
|
|
214
|
+
if (result.updateToolState) syncActiveTool(pi);
|
|
215
|
+
updateStatus(ctx);
|
|
216
|
+
ctx.ui.notify(result.message, result.level);
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
221
|
+
refreshStateFromBranch(ctx);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
pi.on("session_tree", async (_event, ctx) => {
|
|
225
|
+
refreshStateFromBranch(ctx);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
pi.on("before_agent_start", async (event) => {
|
|
229
|
+
if (!config.enabled) return;
|
|
230
|
+
return {
|
|
231
|
+
systemPrompt: `${event.systemPrompt}\n\n${buildExecutorGuidance(config, useCount)}`,
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
pi.on("turn_start", async () => {
|
|
236
|
+
persistState(pi, config, useCount);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
function refreshStateFromBranch(ctx: ExtensionContext): void {
|
|
240
|
+
config = defaultConfig();
|
|
241
|
+
useCount = 0;
|
|
242
|
+
const restoredFromBranch = restoreStateFromSession(ctx);
|
|
243
|
+
if (!restoredFromBranch) applyStartupFlags(pi);
|
|
244
|
+
syncActiveTool(pi);
|
|
245
|
+
updateStatus(ctx);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function restoreStateFromSession(ctx: ExtensionContext): boolean {
|
|
249
|
+
let restored = false;
|
|
250
|
+
const branch = ctx.sessionManager.getBranch();
|
|
251
|
+
for (const entry of branch) {
|
|
252
|
+
if (entry.type === "custom" && entry.customType === STATE_ENTRY) {
|
|
253
|
+
restored = true;
|
|
254
|
+
const data = entry.data as Partial<AdvisorStateEntry> | undefined;
|
|
255
|
+
if (data?.config) config = normalizeConfig(data.config, config);
|
|
256
|
+
if (typeof data?.useCount === "number") useCount = Math.max(0, data.useCount);
|
|
257
|
+
}
|
|
258
|
+
if (entry.type === "message" && entry.message.role === "toolResult" && entry.message.toolName === TOOL_NAME) {
|
|
259
|
+
restored = true;
|
|
260
|
+
const details = entry.message.details as Partial<AdvisorToolDetails> | undefined;
|
|
261
|
+
if (details?.state?.config) config = normalizeConfig(details.state.config, config);
|
|
262
|
+
if (typeof details?.state?.useCount === "number") useCount = Math.max(useCount, details.state.useCount);
|
|
263
|
+
else if (details?.advisor?.useCount) useCount = Math.max(useCount, details.advisor.useCount);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return restored;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function applyStartupFlags(api: ExtensionAPI): void {
|
|
270
|
+
const enabledFlag = api.getFlag("advisor-enabled");
|
|
271
|
+
if (typeof enabledFlag === "boolean") config.enabled = enabledFlag;
|
|
272
|
+
|
|
273
|
+
const modelFlag = api.getFlag("advisor-model");
|
|
274
|
+
if (typeof modelFlag === "string" && modelFlag.trim()) {
|
|
275
|
+
const parsed = parseModelSpec(modelFlag.trim());
|
|
276
|
+
if (parsed) {
|
|
277
|
+
config.provider = parsed.provider;
|
|
278
|
+
config.modelId = parsed.modelId;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const maxUsesFlag = api.getFlag("advisor-max-uses");
|
|
283
|
+
if (typeof maxUsesFlag === "string") {
|
|
284
|
+
const maxUses = parsePositiveInt(maxUsesFlag);
|
|
285
|
+
if (maxUses !== undefined) config.maxUses = maxUses;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const cacheFlag = api.getFlag("advisor-cache");
|
|
289
|
+
if (typeof cacheFlag === "string") {
|
|
290
|
+
const cacheRetention = parseCacheRetention(cacheFlag);
|
|
291
|
+
if (cacheRetention) config.cacheRetention = cacheRetention;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function handleCommand(
|
|
296
|
+
args: string,
|
|
297
|
+
ctx: ExtensionContext,
|
|
298
|
+
): { message: string; level: "info" | "warning" | "error"; persist: boolean; updateToolState: boolean } {
|
|
299
|
+
if (!args || args === "status") {
|
|
300
|
+
return {
|
|
301
|
+
message: formatStatus(ctx),
|
|
302
|
+
level: "info",
|
|
303
|
+
persist: false,
|
|
304
|
+
updateToolState: false,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const [command, ...rest] = args.split(/\s+/);
|
|
309
|
+
const value = rest.join(" ").trim();
|
|
310
|
+
|
|
311
|
+
switch (command) {
|
|
312
|
+
case "enable":
|
|
313
|
+
config.enabled = true;
|
|
314
|
+
return { message: "advisor-pi enabled", level: "info", persist: true, updateToolState: true };
|
|
315
|
+
case "disable":
|
|
316
|
+
config.enabled = false;
|
|
317
|
+
return { message: "advisor-pi disabled", level: "info", persist: true, updateToolState: true };
|
|
318
|
+
case "reset":
|
|
319
|
+
useCount = 0;
|
|
320
|
+
return { message: "advisor-pi use count reset", level: "info", persist: true, updateToolState: false };
|
|
321
|
+
case "model": {
|
|
322
|
+
const parsed = parseModelSpec(value);
|
|
323
|
+
if (!parsed) {
|
|
324
|
+
return {
|
|
325
|
+
message: "Usage: /advisor-pi model <provider>/<model>",
|
|
326
|
+
level: "error",
|
|
327
|
+
persist: false,
|
|
328
|
+
updateToolState: false,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
const model = ctx.modelRegistry.find(parsed.provider, parsed.modelId);
|
|
332
|
+
if (!model) {
|
|
333
|
+
return {
|
|
334
|
+
message: `Advisor model not found: ${parsed.provider}/${parsed.modelId}`,
|
|
335
|
+
level: "error",
|
|
336
|
+
persist: false,
|
|
337
|
+
updateToolState: false,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
config.provider = parsed.provider;
|
|
341
|
+
config.modelId = parsed.modelId;
|
|
342
|
+
return {
|
|
343
|
+
message: `advisor-pi model set to ${config.provider}/${config.modelId}`,
|
|
344
|
+
level: "info",
|
|
345
|
+
persist: true,
|
|
346
|
+
updateToolState: false,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
case "max-uses": {
|
|
350
|
+
const maxUses = parsePositiveInt(value);
|
|
351
|
+
if (maxUses === undefined) {
|
|
352
|
+
return {
|
|
353
|
+
message: "Usage: /advisor-pi max-uses <positive-number>",
|
|
354
|
+
level: "error",
|
|
355
|
+
persist: false,
|
|
356
|
+
updateToolState: false,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
config.maxUses = maxUses;
|
|
360
|
+
return {
|
|
361
|
+
message: `advisor-pi max uses set to ${maxUses}`,
|
|
362
|
+
level: "info",
|
|
363
|
+
persist: true,
|
|
364
|
+
updateToolState: false,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
case "cache": {
|
|
368
|
+
const cacheRetention = parseCacheRetention(value);
|
|
369
|
+
if (!cacheRetention) {
|
|
370
|
+
return {
|
|
371
|
+
message: "Usage: /advisor-pi cache <none|short|long>",
|
|
372
|
+
level: "error",
|
|
373
|
+
persist: false,
|
|
374
|
+
updateToolState: false,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
config.cacheRetention = cacheRetention;
|
|
378
|
+
return {
|
|
379
|
+
message: `advisor-pi cache set to ${cacheRetention}`,
|
|
380
|
+
level: "info",
|
|
381
|
+
persist: true,
|
|
382
|
+
updateToolState: false,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
default:
|
|
386
|
+
return {
|
|
387
|
+
message:
|
|
388
|
+
"Usage: /advisor-pi [status|enable|disable|model <provider>/<model>|max-uses <n>|cache <none|short|long>|reset]",
|
|
389
|
+
level: "error",
|
|
390
|
+
persist: false,
|
|
391
|
+
updateToolState: false,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function syncActiveTool(api: ExtensionAPI): void {
|
|
397
|
+
const activeTools = api.getActiveTools();
|
|
398
|
+
const hasAdvisor = activeTools.includes(TOOL_NAME);
|
|
399
|
+
if (config.enabled && !hasAdvisor) {
|
|
400
|
+
api.setActiveTools([...activeTools, TOOL_NAME]);
|
|
401
|
+
} else if (!config.enabled && hasAdvisor) {
|
|
402
|
+
api.setActiveTools(activeTools.filter((tool) => tool !== TOOL_NAME));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function updateStatus(ctx: ExtensionContext): void {
|
|
407
|
+
if (!ctx.hasUI) return;
|
|
408
|
+
if (!config.enabled) {
|
|
409
|
+
ctx.ui.setStatus("advisor-pi", undefined);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const remaining = Math.max(0, config.maxUses - useCount);
|
|
413
|
+
ctx.ui.setStatus("advisor-pi", ctx.ui.theme.fg(remaining > 0 ? "accent" : "warning", `advisor:${remaining}`));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function formatStatus(ctx: ExtensionContext): string {
|
|
417
|
+
const model = ctx.modelRegistry.find(config.provider, config.modelId);
|
|
418
|
+
const availability = model ? "available" : "not found";
|
|
419
|
+
return [
|
|
420
|
+
`advisor-pi ${config.enabled ? "enabled" : "disabled"}`,
|
|
421
|
+
`model: ${config.provider}/${config.modelId} (${availability})`,
|
|
422
|
+
`uses: ${useCount}/${config.maxUses}`,
|
|
423
|
+
`cache: ${config.cacheRetention}`,
|
|
424
|
+
].join(" • ");
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const ADVISOR_SYSTEM_PROMPT = `You are an advisor model for Pi Coding Agent.
|
|
429
|
+
|
|
430
|
+
Your role is strategic guidance only. You do not have tools and you do not make changes. Given the executor's question and conversation transcript:
|
|
431
|
+
|
|
432
|
+
- Identify the best next plan or course correction.
|
|
433
|
+
- Call out risks, missing information, edge cases, and test strategy.
|
|
434
|
+
- Prefer concise, actionable guidance the executor can apply immediately.
|
|
435
|
+
- Do not restate the full transcript.
|
|
436
|
+
- If the task is unsafe, impossible, or underspecified, say what must be clarified.
|
|
437
|
+
|
|
438
|
+
Return guidance in short sections with bullets when useful.`;
|
|
439
|
+
|
|
440
|
+
function defaultConfig(): AdvisorConfig {
|
|
441
|
+
const parsed = parseModelSpec(DEFAULT_ADVISOR_MODEL) ?? { provider: "openai-codex", modelId: "gpt-5.5" };
|
|
442
|
+
return {
|
|
443
|
+
enabled: true,
|
|
444
|
+
provider: parsed.provider,
|
|
445
|
+
modelId: parsed.modelId,
|
|
446
|
+
maxUses: DEFAULT_MAX_USES,
|
|
447
|
+
cacheRetention: DEFAULT_CACHE_RETENTION,
|
|
448
|
+
maxTokens: DEFAULT_MAX_TOKENS,
|
|
449
|
+
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function buildExecutorGuidance(config: AdvisorConfig, useCount: number): string {
|
|
454
|
+
const remaining = Math.max(0, config.maxUses - useCount);
|
|
455
|
+
return [
|
|
456
|
+
"Advisor-pi is enabled.",
|
|
457
|
+
`The advisor tool consults ${config.provider}/${config.modelId} for strategic guidance and has ${remaining}/${config.maxUses} uses remaining on this branch.`,
|
|
458
|
+
"Use advisor for complex planning, risky implementation choices, repeated failures, or course correction. Do not use advisor for trivial edits or simple facts.",
|
|
459
|
+
`Advisor cache preference is ${config.cacheRetention}; caching support is provider-dependent.`,
|
|
460
|
+
].join("\n");
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function serializeCurrentConversation(ctx: ExtensionContext): string {
|
|
464
|
+
const entries = ctx.sessionManager.getEntries();
|
|
465
|
+
const leafId = ctx.sessionManager.getLeafId();
|
|
466
|
+
const sessionContext = buildSessionContext(entries, leafId);
|
|
467
|
+
const llmMessages = convertToLlm(sessionContext.messages);
|
|
468
|
+
return serializeConversation(llmMessages);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function buildAdvisorUserPrompt(params: AdvisorToolInput, conversationText: string): string {
|
|
472
|
+
return [
|
|
473
|
+
"## Executor Question",
|
|
474
|
+
params.question,
|
|
475
|
+
"",
|
|
476
|
+
"## Consultation Phase",
|
|
477
|
+
params.phase ?? "other",
|
|
478
|
+
"",
|
|
479
|
+
...(params.context ? ["## Extra Context", params.context, ""] : []),
|
|
480
|
+
"## Conversation Transcript",
|
|
481
|
+
conversationText,
|
|
482
|
+
].join("\n");
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function extractText(content: Array<{ type: string; text?: string }>): string {
|
|
486
|
+
return content
|
|
487
|
+
.filter((part): part is { type: "text"; text: string } => part.type === "text" && typeof part.text === "string")
|
|
488
|
+
.map((part) => part.text)
|
|
489
|
+
.join("\n")
|
|
490
|
+
.trim();
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function advisorDisabledResult(config: AdvisorConfig, useCount: number, params: AdvisorToolInput) {
|
|
494
|
+
return {
|
|
495
|
+
content: [
|
|
496
|
+
{
|
|
497
|
+
type: "text" as const,
|
|
498
|
+
text: `advisor-pi is disabled. The executor should continue without advisor guidance for: ${params.question}`,
|
|
499
|
+
},
|
|
500
|
+
],
|
|
501
|
+
details: makeSkippedDetails(config, useCount, params),
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function advisorLimitResult(config: AdvisorConfig, useCount: number, params: AdvisorToolInput) {
|
|
506
|
+
return {
|
|
507
|
+
content: [
|
|
508
|
+
{
|
|
509
|
+
type: "text" as const,
|
|
510
|
+
text: `Advisor use limit reached. The executor should continue without another advisor call for: ${params.question}`,
|
|
511
|
+
},
|
|
512
|
+
],
|
|
513
|
+
details: makeSkippedDetails(config, useCount, params),
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
function makeSkippedDetails(config: AdvisorConfig, useCount: number, params: AdvisorToolInput): AdvisorToolDetails {
|
|
518
|
+
return {
|
|
519
|
+
advisor: {
|
|
520
|
+
provider: config.provider,
|
|
521
|
+
model: config.modelId,
|
|
522
|
+
phase: params.phase ?? "other",
|
|
523
|
+
useCount,
|
|
524
|
+
maxUses: config.maxUses,
|
|
525
|
+
cacheRetention: config.cacheRetention,
|
|
526
|
+
elapsedMs: 0,
|
|
527
|
+
stopReason: "skipped",
|
|
528
|
+
},
|
|
529
|
+
state: makeStateEntry(config, useCount),
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function makeStateEntry(config: AdvisorConfig, useCount: number): AdvisorStateEntry {
|
|
534
|
+
return {
|
|
535
|
+
version: 1,
|
|
536
|
+
config: { ...config },
|
|
537
|
+
useCount,
|
|
538
|
+
updatedAt: new Date().toISOString(),
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function persistState(pi: ExtensionAPI, config: AdvisorConfig, useCount: number): void {
|
|
543
|
+
pi.appendEntry(STATE_ENTRY, makeStateEntry(config, useCount));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function normalizeConfig(input: Partial<AdvisorConfig>, fallback: AdvisorConfig): AdvisorConfig {
|
|
547
|
+
return {
|
|
548
|
+
enabled: typeof input.enabled === "boolean" ? input.enabled : fallback.enabled,
|
|
549
|
+
provider: typeof input.provider === "string" && input.provider ? input.provider : fallback.provider,
|
|
550
|
+
modelId: typeof input.modelId === "string" && input.modelId ? input.modelId : fallback.modelId,
|
|
551
|
+
maxUses: typeof input.maxUses === "number" && input.maxUses > 0 ? Math.floor(input.maxUses) : fallback.maxUses,
|
|
552
|
+
cacheRetention: parseCacheRetention(input.cacheRetention) ?? fallback.cacheRetention,
|
|
553
|
+
maxTokens: typeof input.maxTokens === "number" && input.maxTokens > 0 ? Math.floor(input.maxTokens) : fallback.maxTokens,
|
|
554
|
+
timeoutMs: typeof input.timeoutMs === "number" && input.timeoutMs > 0 ? Math.floor(input.timeoutMs) : fallback.timeoutMs,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function parseModelSpec(value: string): { provider: string; modelId: string } | undefined {
|
|
559
|
+
const slash = value.indexOf("/");
|
|
560
|
+
if (slash <= 0 || slash === value.length - 1) return undefined;
|
|
561
|
+
return {
|
|
562
|
+
provider: value.slice(0, slash),
|
|
563
|
+
modelId: value.slice(slash + 1),
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function parsePositiveInt(value: string): number | undefined {
|
|
568
|
+
const parsed = Number.parseInt(value, 10);
|
|
569
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return undefined;
|
|
570
|
+
return parsed;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function parseCacheRetention(value: unknown): CacheRetention | undefined {
|
|
574
|
+
if (value === "none" || value === "short" || value === "long") return value;
|
|
575
|
+
return undefined;
|
|
576
|
+
}
|
|
577
|
+
|