pi-advisor-flow 0.1.8 → 0.2.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 +15 -11
- package/extensions/index.ts +17 -1
- package/package.json +25 -21
- package/src/commands.ts +346 -99
- package/src/config.ts +345 -94
- package/src/conversation.ts +199 -48
- package/src/herdr.ts +145 -30
- package/src/session-state.ts +182 -41
- package/src/tools.ts +696 -173
- package/src/ui.ts +317 -81
package/src/commands.ts
CHANGED
|
@@ -1,68 +1,197 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ExtensionAPI,
|
|
3
|
+
type ExtensionContext,
|
|
4
|
+
getMarkdownTheme,
|
|
5
|
+
} from "@earendil-works/pi-coding-agent";
|
|
2
6
|
import { Box, Markdown, Text } from "@earendil-works/pi-tui";
|
|
3
7
|
import {
|
|
4
|
-
advisorAutoLoopGateRef,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
advisorAutoLoopGateRef,
|
|
9
|
+
advisorBlockOnBlockedRef,
|
|
10
|
+
advisorCollapseResponsesRef,
|
|
11
|
+
advisorCompletionGateRef,
|
|
12
|
+
advisorCustomInvocationRef,
|
|
13
|
+
advisorEffortRef,
|
|
14
|
+
advisorFailureGateRef,
|
|
15
|
+
advisorFailureModeRef,
|
|
16
|
+
advisorHerdrIntegrationRef,
|
|
17
|
+
advisorLoopThresholdRef,
|
|
18
|
+
advisorMaxCallsPerSessionRef,
|
|
19
|
+
advisorPlanGateRef,
|
|
20
|
+
advisorRef,
|
|
21
|
+
advisorSessionSummaryRef,
|
|
22
|
+
advisorToolResultMaxBytesRef,
|
|
23
|
+
advisorToolResultMaxLinesRef,
|
|
24
|
+
contextMaxCharsRef,
|
|
25
|
+
executorEffortRef,
|
|
26
|
+
executorRef,
|
|
27
|
+
loadConfig,
|
|
28
|
+
parseArgs,
|
|
29
|
+
saveConfig,
|
|
30
|
+
setAdvisorAutoLoopGateRef,
|
|
31
|
+
setAdvisorBlockOnBlockedRef,
|
|
32
|
+
setAdvisorCollapseResponsesRef,
|
|
33
|
+
setAdvisorCompletionGateRef,
|
|
34
|
+
setAdvisorCustomInvocationRef,
|
|
35
|
+
setAdvisorEffortRef,
|
|
36
|
+
setAdvisorFailureGateRef,
|
|
37
|
+
setAdvisorFailureModeRef,
|
|
38
|
+
setAdvisorHerdrIntegrationRef,
|
|
39
|
+
setAdvisorLoopThresholdRef,
|
|
40
|
+
setAdvisorMaxCallsPerSessionRef,
|
|
41
|
+
setAdvisorPlanGateRef,
|
|
42
|
+
setAdvisorRef,
|
|
43
|
+
setAdvisorSessionSummaryRef,
|
|
44
|
+
setAdvisorToolResultMaxBytesRef,
|
|
45
|
+
setAdvisorToolResultMaxLinesRef,
|
|
46
|
+
setContextMaxCharsRef,
|
|
47
|
+
setExecutorEffortRef,
|
|
48
|
+
setExecutorRef,
|
|
49
|
+
splitRef,
|
|
9
50
|
} from "./config.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
51
|
+
import { herdrAdvisorActivity, notifyHerdrAdvisorFailure } from "./herdr.js";
|
|
52
|
+
import {
|
|
53
|
+
adviceForDisplay,
|
|
54
|
+
advisorSessionState,
|
|
55
|
+
consultAdvisor,
|
|
56
|
+
renderAdvisorCallBox,
|
|
57
|
+
resolveAdvisorRequest,
|
|
58
|
+
} from "./tools.js";
|
|
59
|
+
import {
|
|
60
|
+
type AdvisorSettings,
|
|
61
|
+
AdvisorSettingsSelector,
|
|
62
|
+
type ContextPreset,
|
|
63
|
+
SearchableModelSelector,
|
|
64
|
+
} from "./ui.js";
|
|
13
65
|
|
|
14
|
-
const EFFORT_LEVELS = [
|
|
66
|
+
const EFFORT_LEVELS = [
|
|
67
|
+
"Default (Model Default)",
|
|
68
|
+
"off",
|
|
69
|
+
"minimal",
|
|
70
|
+
"low",
|
|
71
|
+
"medium",
|
|
72
|
+
"high",
|
|
73
|
+
"xhigh",
|
|
74
|
+
"max",
|
|
75
|
+
];
|
|
15
76
|
|
|
16
77
|
const CONTEXT_PRESETS: ContextPreset[] = [
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
78
|
+
{
|
|
79
|
+
description:
|
|
80
|
+
"No conversation history. The Advisor receives only its standing instructions.",
|
|
81
|
+
label: "0",
|
|
82
|
+
value: 0,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
description: "The most recent 10,000 characters of the current branch.",
|
|
86
|
+
label: "10k",
|
|
87
|
+
value: 10_000,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
description: "The most recent 25,000 characters of the current branch.",
|
|
91
|
+
label: "25k",
|
|
92
|
+
value: 25_000,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
description: "The most recent 100,000 characters of the current branch.",
|
|
96
|
+
label: "100k",
|
|
97
|
+
value: 100_000,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
description: "The most recent 200,000 characters of the current branch.",
|
|
101
|
+
label: "200k",
|
|
102
|
+
value: 200_000,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
description:
|
|
106
|
+
"The complete reconstructed conversation branch. Cost and model context limits apply.",
|
|
107
|
+
label: "ALL",
|
|
108
|
+
value: Number.MAX_SAFE_INTEGER,
|
|
109
|
+
},
|
|
23
110
|
];
|
|
24
111
|
|
|
25
|
-
type ManualConsult = (
|
|
112
|
+
type ManualConsult = (
|
|
113
|
+
ctx: ExtensionContext,
|
|
114
|
+
question?: string,
|
|
115
|
+
signal?: AbortSignal
|
|
116
|
+
) => Promise<{ markdown: string; thinkingText: string }>;
|
|
26
117
|
|
|
27
|
-
export const registerCommands = (
|
|
118
|
+
export const registerCommands = (
|
|
119
|
+
pi: ExtensionAPI,
|
|
120
|
+
dependencies: { consult?: ManualConsult } = {}
|
|
121
|
+
) => {
|
|
28
122
|
const flowEnabled = () => pi.getActiveTools().includes("ask_advisor");
|
|
29
|
-
const requestAdvisor =
|
|
123
|
+
const requestAdvisor =
|
|
124
|
+
dependencies.consult ??
|
|
125
|
+
((ctx, question, signal) =>
|
|
126
|
+
consultAdvisor(ctx, question, signal, undefined, "manual"));
|
|
30
127
|
const manualConsultations = new Set<AbortController>();
|
|
31
128
|
|
|
32
|
-
pi.registerEntryRenderer?.(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
129
|
+
pi.registerEntryRenderer?.(
|
|
130
|
+
"advisor-manual-call",
|
|
131
|
+
(entry, _options, theme) => {
|
|
132
|
+
const { question } = (entry.data ?? {}) as { question?: string };
|
|
133
|
+
return renderAdvisorCallBox(question, theme);
|
|
134
|
+
}
|
|
135
|
+
);
|
|
36
136
|
|
|
37
|
-
pi.registerMessageRenderer?.(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
137
|
+
pi.registerMessageRenderer?.(
|
|
138
|
+
"advisor-manual-result",
|
|
139
|
+
(message, { expanded }, theme) => {
|
|
140
|
+
const details = message.details as
|
|
141
|
+
| { advisor?: string; text?: string }
|
|
142
|
+
| undefined;
|
|
143
|
+
const box = new Box(1, 1, (text) => theme.bg("customMessageBg", text));
|
|
144
|
+
box.addChild(
|
|
145
|
+
new Text(theme.fg("warning", theme.bold("◆ ADVISOR RESPONSE")), 0, 0)
|
|
146
|
+
);
|
|
147
|
+
if (details?.advisor) {
|
|
148
|
+
box.addChild(new Text(theme.fg("dim", ` ${details.advisor}`), 0, 0));
|
|
149
|
+
}
|
|
150
|
+
const advice =
|
|
151
|
+
details?.text ??
|
|
152
|
+
(typeof message.content === "string"
|
|
153
|
+
? message.content
|
|
154
|
+
: "(Advisor returned no advice.)");
|
|
155
|
+
box.addChild(
|
|
156
|
+
new Markdown(
|
|
157
|
+
adviceForDisplay(advice, expanded),
|
|
158
|
+
0,
|
|
159
|
+
0,
|
|
160
|
+
getMarkdownTheme()
|
|
161
|
+
)
|
|
162
|
+
);
|
|
163
|
+
return box;
|
|
164
|
+
}
|
|
165
|
+
);
|
|
46
166
|
|
|
47
167
|
pi.on("session_shutdown", () => {
|
|
48
|
-
for (const controller of manualConsultations)
|
|
168
|
+
for (const controller of manualConsultations) {
|
|
169
|
+
controller.abort();
|
|
170
|
+
}
|
|
49
171
|
manualConsultations.clear();
|
|
50
172
|
herdrAdvisorActivity.clear();
|
|
51
173
|
});
|
|
52
174
|
|
|
53
175
|
pi.registerCommand("advisor-manual", {
|
|
54
|
-
description:
|
|
176
|
+
description:
|
|
177
|
+
"Consult the Advisor in parallel; accepts an optional focused question and fans its response out to the Executor",
|
|
55
178
|
handler: async (args, ctx) => {
|
|
56
179
|
loadConfig(ctx);
|
|
57
|
-
if (!advisorSessionState.
|
|
58
|
-
|
|
180
|
+
if (!advisorSessionState.canConsult(advisorMaxCallsPerSessionRef)) {
|
|
181
|
+
const message = "Advisor call budget exhausted for this session.";
|
|
182
|
+
if (ctx.hasUI) {
|
|
183
|
+
ctx.ui.notify(message, "warning");
|
|
184
|
+
}
|
|
185
|
+
notifyHerdrAdvisorFailure("Advisor budget exhausted", message);
|
|
59
186
|
return;
|
|
60
187
|
}
|
|
61
|
-
advisorSessionState.
|
|
188
|
+
advisorSessionState.consumeCall();
|
|
62
189
|
const question = resolveAdvisorRequest(args);
|
|
63
190
|
// A single visible progress surface avoids competing consultations overwriting
|
|
64
191
|
// each other's streamed state. A newer manual request replaces the previous one.
|
|
65
|
-
for (const pending of manualConsultations)
|
|
192
|
+
for (const pending of manualConsultations) {
|
|
193
|
+
pending.abort();
|
|
194
|
+
}
|
|
66
195
|
manualConsultations.clear();
|
|
67
196
|
const controller = new AbortController();
|
|
68
197
|
manualConsultations.add(controller);
|
|
@@ -70,25 +199,49 @@ export const registerCommands = (pi: ExtensionAPI, dependencies: { consult?: Man
|
|
|
70
199
|
|
|
71
200
|
herdrAdvisorActivity.start();
|
|
72
201
|
void requestAdvisor(ctx, question, controller.signal)
|
|
73
|
-
.then(({
|
|
74
|
-
advisorSessionState.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
display: true,
|
|
80
|
-
details: { advisor: advisorRef, question, text: advice },
|
|
81
|
-
}, {
|
|
82
|
-
// Steer lets the current turn finish its active work; the Executor sees
|
|
83
|
-
// the result before its next model call rather than being interrupted.
|
|
84
|
-
deliverAs: "steer",
|
|
85
|
-
triggerTurn: true,
|
|
202
|
+
.then(({ markdown }) => {
|
|
203
|
+
advisorSessionState.recordInvocation({
|
|
204
|
+
executionEffect: "continued",
|
|
205
|
+
kind: "markdown",
|
|
206
|
+
model: advisorRef,
|
|
207
|
+
trigger: "manual",
|
|
86
208
|
});
|
|
209
|
+
const advice = markdown;
|
|
210
|
+
if (controller.signal.aborted) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
pi.sendMessage(
|
|
214
|
+
{
|
|
215
|
+
content: `Manual Advisor consultation${question ? ` (${question})` : ""}:\n\n${advice}`,
|
|
216
|
+
customType: "advisor-manual-result",
|
|
217
|
+
details: { advisor: advisorRef, question, text: advice },
|
|
218
|
+
display: true,
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
// Steer lets the current turn finish its active work; the Executor sees
|
|
222
|
+
// the result before its next model call rather than being interrupted.
|
|
223
|
+
deliverAs: "steer",
|
|
224
|
+
triggerTurn: true,
|
|
225
|
+
}
|
|
226
|
+
);
|
|
87
227
|
})
|
|
88
228
|
.catch((error: unknown) => {
|
|
89
|
-
if (controller.signal.aborted)
|
|
90
|
-
|
|
91
|
-
|
|
229
|
+
if (controller.signal.aborted) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const message =
|
|
233
|
+
error instanceof Error ? error.message : String(error);
|
|
234
|
+
advisorSessionState.recordInvocation({
|
|
235
|
+
executionEffect: "continued",
|
|
236
|
+
failure: "provider-error",
|
|
237
|
+
kind: "markdown",
|
|
238
|
+
model: advisorRef,
|
|
239
|
+
trigger: "manual",
|
|
240
|
+
});
|
|
241
|
+
if (ctx.hasUI) {
|
|
242
|
+
ctx.ui.notify(`Advisor consultation failed: ${message}`, "error");
|
|
243
|
+
}
|
|
244
|
+
notifyHerdrAdvisorFailure("Advisor consultation failed", message);
|
|
92
245
|
})
|
|
93
246
|
.finally(() => {
|
|
94
247
|
manualConsultations.delete(controller);
|
|
@@ -98,55 +251,125 @@ export const registerCommands = (pi: ExtensionAPI, dependencies: { consult?: Man
|
|
|
98
251
|
});
|
|
99
252
|
|
|
100
253
|
pi.registerCommand("advisor", {
|
|
101
|
-
description:
|
|
254
|
+
description:
|
|
255
|
+
"Enable the Executor/Advisor flow and switch to the configured Executor model; accepts contextMaxChars=N",
|
|
102
256
|
handler: async (args, ctx) => {
|
|
103
257
|
loadConfig(ctx);
|
|
104
258
|
const argumentError = parseArgs(args);
|
|
105
259
|
if (argumentError) {
|
|
106
|
-
if (ctx.hasUI)
|
|
260
|
+
if (ctx.hasUI) {
|
|
261
|
+
ctx.ui.notify(argumentError, "error");
|
|
262
|
+
}
|
|
107
263
|
return;
|
|
108
264
|
}
|
|
109
265
|
const [provider, modelId] = splitRef(executorRef);
|
|
110
266
|
const executor = ctx.modelRegistry.find(provider, modelId);
|
|
111
|
-
if (!executor)
|
|
267
|
+
if (!executor) {
|
|
268
|
+
return ctx.hasUI
|
|
269
|
+
? ctx.ui.notify(`Executor model not found: ${executorRef}`, "error")
|
|
270
|
+
: undefined;
|
|
271
|
+
}
|
|
112
272
|
const [ap, am] = splitRef(advisorRef);
|
|
113
|
-
if (!ctx.modelRegistry.find(ap, am))
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
273
|
+
if (!ctx.modelRegistry.find(ap, am)) {
|
|
274
|
+
return ctx.hasUI
|
|
275
|
+
? ctx.ui.notify(`Advisor model not found: ${advisorRef}`, "error")
|
|
276
|
+
: undefined;
|
|
277
|
+
}
|
|
278
|
+
if (!(await pi.setModel(executor))) {
|
|
279
|
+
return ctx.hasUI
|
|
280
|
+
? ctx.ui.notify(`No API key for Executor ${executorRef}`, "error")
|
|
281
|
+
: undefined;
|
|
282
|
+
}
|
|
283
|
+
if (executorEffortRef) {
|
|
284
|
+
pi.setThinkingLevel(executorEffortRef as any);
|
|
285
|
+
}
|
|
286
|
+
if (!flowEnabled()) {
|
|
287
|
+
pi.setActiveTools([...pi.getActiveTools(), "ask_advisor"]);
|
|
288
|
+
}
|
|
289
|
+
if (ctx.hasUI) {
|
|
290
|
+
ctx.ui.notify(
|
|
291
|
+
`Advisor flow ready — Executor: ${executorRef} (thinking: ${executorEffortRef || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`,
|
|
292
|
+
"info"
|
|
293
|
+
);
|
|
294
|
+
}
|
|
118
295
|
},
|
|
119
296
|
});
|
|
120
297
|
|
|
121
298
|
pi.registerCommand("advisor-models", {
|
|
122
|
-
description:
|
|
299
|
+
description:
|
|
300
|
+
"Select and persist the Executor and Advisor models with reasoning levels",
|
|
123
301
|
handler: async (_args, ctx) => {
|
|
124
|
-
if (!ctx.hasUI)
|
|
125
|
-
|
|
302
|
+
if (!ctx.hasUI) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const refs = ctx.modelRegistry
|
|
306
|
+
.getAvailable()
|
|
307
|
+
.map((m) => `${m.provider}/${m.id}`);
|
|
126
308
|
|
|
127
|
-
const executor = await ctx.ui.custom<string | undefined>(
|
|
128
|
-
|
|
309
|
+
const executor = await ctx.ui.custom<string | undefined>(
|
|
310
|
+
(tui, theme, keybindings, done) =>
|
|
311
|
+
new SearchableModelSelector({
|
|
312
|
+
allOptions: refs,
|
|
313
|
+
keybindings,
|
|
314
|
+
onCancel: () => done(undefined),
|
|
315
|
+
onSelect: done,
|
|
316
|
+
theme,
|
|
317
|
+
title: "Select Executor Model",
|
|
318
|
+
tui,
|
|
319
|
+
})
|
|
129
320
|
);
|
|
130
|
-
if (!executor)
|
|
321
|
+
if (!executor) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
131
324
|
|
|
132
|
-
const executorEffort = await ctx.ui.select(
|
|
133
|
-
|
|
325
|
+
const executorEffort = await ctx.ui.select(
|
|
326
|
+
"Select Executor Reasoning/Thinking Level",
|
|
327
|
+
EFFORT_LEVELS
|
|
328
|
+
);
|
|
329
|
+
if (!executorEffort) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
134
332
|
|
|
135
|
-
const advisor = await ctx.ui.custom<string | undefined>(
|
|
136
|
-
|
|
333
|
+
const advisor = await ctx.ui.custom<string | undefined>(
|
|
334
|
+
(tui, theme, keybindings, done) =>
|
|
335
|
+
new SearchableModelSelector({
|
|
336
|
+
allOptions: refs,
|
|
337
|
+
keybindings,
|
|
338
|
+
onCancel: () => done(undefined),
|
|
339
|
+
onSelect: done,
|
|
340
|
+
theme,
|
|
341
|
+
title: "Select Advisor Model",
|
|
342
|
+
tui,
|
|
343
|
+
})
|
|
137
344
|
);
|
|
138
|
-
if (!advisor)
|
|
345
|
+
if (!advisor) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
139
348
|
|
|
140
|
-
const advisorEffort = await ctx.ui.select(
|
|
141
|
-
|
|
349
|
+
const advisorEffort = await ctx.ui.select(
|
|
350
|
+
"Select Advisor Reasoning/Thinking Level",
|
|
351
|
+
EFFORT_LEVELS
|
|
352
|
+
);
|
|
353
|
+
if (!advisorEffort) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
142
356
|
|
|
143
357
|
setExecutorRef(executor);
|
|
144
358
|
setAdvisorRef(advisor);
|
|
145
|
-
setExecutorEffortRef(
|
|
146
|
-
|
|
359
|
+
setExecutorEffortRef(
|
|
360
|
+
executorEffort === "Default (Model Default)"
|
|
361
|
+
? undefined
|
|
362
|
+
: executorEffort
|
|
363
|
+
);
|
|
364
|
+
setAdvisorEffortRef(
|
|
365
|
+
advisorEffort === "Default (Model Default)" ? undefined : advisorEffort
|
|
366
|
+
);
|
|
147
367
|
|
|
148
368
|
const path = saveConfig(ctx);
|
|
149
|
-
ctx.ui.notify(
|
|
369
|
+
ctx.ui.notify(
|
|
370
|
+
`Saved Executor + Advisor configurations to ${path}`,
|
|
371
|
+
"info"
|
|
372
|
+
);
|
|
150
373
|
},
|
|
151
374
|
});
|
|
152
375
|
|
|
@@ -154,36 +377,49 @@ export const registerCommands = (pi: ExtensionAPI, dependencies: { consult?: Man
|
|
|
154
377
|
description: "Configure Advisor context and reasoning effort",
|
|
155
378
|
handler: async (_args, ctx) => {
|
|
156
379
|
loadConfig(ctx);
|
|
157
|
-
if (!ctx.hasUI)
|
|
380
|
+
if (!ctx.hasUI) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
158
383
|
|
|
159
384
|
const initial: AdvisorSettings = {
|
|
385
|
+
autoLoopGate: advisorAutoLoopGateRef,
|
|
386
|
+
blockOnBlocked: advisorBlockOnBlockedRef,
|
|
387
|
+
collapseResponses: advisorCollapseResponsesRef,
|
|
388
|
+
completionGate: advisorCompletionGateRef,
|
|
160
389
|
contextMaxChars: contextMaxCharsRef,
|
|
390
|
+
customRule: advisorCustomInvocationRef,
|
|
161
391
|
effort: advisorEffortRef,
|
|
162
|
-
planGate: advisorPlanGateRef,
|
|
163
392
|
failureGate: advisorFailureGateRef,
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
customRule: advisorCustomInvocationRef,
|
|
167
|
-
blockOnBlocked: advisorBlockOnBlockedRef,
|
|
168
|
-
autoLoopGate: advisorAutoLoopGateRef,
|
|
393
|
+
failureMode: advisorFailureModeRef,
|
|
394
|
+
herdrIntegration: advisorHerdrIntegrationRef,
|
|
169
395
|
loopThreshold: advisorLoopThresholdRef,
|
|
170
396
|
maxCallsPerSession: advisorMaxCallsPerSessionRef,
|
|
397
|
+
planGate: advisorPlanGateRef,
|
|
171
398
|
sessionSummary: advisorSessionSummaryRef,
|
|
399
|
+
toolResultMaxBytes: advisorToolResultMaxBytesRef,
|
|
400
|
+
toolResultMaxLines: advisorToolResultMaxLinesRef,
|
|
172
401
|
};
|
|
173
|
-
const settings = await ctx.ui.custom<AdvisorSettings | undefined>(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
402
|
+
const settings = await ctx.ui.custom<AdvisorSettings | undefined>(
|
|
403
|
+
(tui, theme, _keybindings, done) =>
|
|
404
|
+
new AdvisorSettingsSelector({
|
|
405
|
+
effortLevels: EFFORT_LEVELS,
|
|
406
|
+
initial,
|
|
407
|
+
onCancel: () => done(undefined),
|
|
408
|
+
onSave: done,
|
|
409
|
+
presets: CONTEXT_PRESETS,
|
|
410
|
+
theme,
|
|
411
|
+
tui,
|
|
412
|
+
})
|
|
183
413
|
);
|
|
184
|
-
if (!settings)
|
|
414
|
+
if (!settings) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
185
417
|
|
|
186
|
-
setAdvisorEffortRef(
|
|
418
|
+
setAdvisorEffortRef(
|
|
419
|
+
settings.effort === "Default (Model Default)"
|
|
420
|
+
? undefined
|
|
421
|
+
: settings.effort
|
|
422
|
+
);
|
|
187
423
|
setContextMaxCharsRef(settings.contextMaxChars);
|
|
188
424
|
setAdvisorPlanGateRef(settings.planGate);
|
|
189
425
|
setAdvisorFailureGateRef(settings.failureGate);
|
|
@@ -195,6 +431,10 @@ export const registerCommands = (pi: ExtensionAPI, dependencies: { consult?: Man
|
|
|
195
431
|
setAdvisorLoopThresholdRef(settings.loopThreshold ?? 3);
|
|
196
432
|
setAdvisorMaxCallsPerSessionRef(settings.maxCallsPerSession);
|
|
197
433
|
setAdvisorSessionSummaryRef(settings.sessionSummary ?? true);
|
|
434
|
+
setAdvisorFailureModeRef(settings.failureMode ?? "block-session");
|
|
435
|
+
setAdvisorHerdrIntegrationRef(settings.herdrIntegration ?? true);
|
|
436
|
+
setAdvisorToolResultMaxLinesRef(settings.toolResultMaxLines ?? 2000);
|
|
437
|
+
setAdvisorToolResultMaxBytesRef(settings.toolResultMaxBytes ?? 50 * 1024);
|
|
198
438
|
const path = saveConfig(ctx);
|
|
199
439
|
ctx.ui.notify(`Saved Advisor settings to ${path}`, "info");
|
|
200
440
|
},
|
|
@@ -203,8 +443,15 @@ export const registerCommands = (pi: ExtensionAPI, dependencies: { consult?: Man
|
|
|
203
443
|
pi.registerCommand("advisor-off", {
|
|
204
444
|
description: "Disable on-demand Advisor calls; keep the current model",
|
|
205
445
|
handler: async (_args, ctx) => {
|
|
206
|
-
pi.setActiveTools(
|
|
207
|
-
|
|
446
|
+
pi.setActiveTools(
|
|
447
|
+
pi.getActiveTools().filter((name) => name !== "ask_advisor")
|
|
448
|
+
);
|
|
449
|
+
if (ctx.hasUI) {
|
|
450
|
+
ctx.ui.notify(
|
|
451
|
+
"Advisor flow disabled. Current model unchanged.",
|
|
452
|
+
"info"
|
|
453
|
+
);
|
|
454
|
+
}
|
|
208
455
|
},
|
|
209
456
|
});
|
|
210
457
|
};
|