pi-advisor-flow 0.1.9 → 0.2.1
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 +26 -1
- package/package.json +33 -21
- package/src/commands.ts +396 -123
- package/src/config.ts +405 -99
- package/src/conversation.ts +217 -47
- package/src/herdr.ts +142 -30
- package/src/session-state.ts +190 -41
- package/src/tools.ts +804 -199
- package/src/ui.ts +376 -106
package/src/ui.ts
CHANGED
|
@@ -1,35 +1,60 @@
|
|
|
1
|
-
import { Input, Key, matchesKey, fuzzyFilter, truncateToWidth, type Component, type Focusable } from "@earendil-works/pi-tui";
|
|
2
|
-
import { Box, Text } from "@earendil-works/pi-tui";
|
|
3
1
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import {
|
|
3
|
+
type Component,
|
|
4
|
+
type Focusable,
|
|
5
|
+
fuzzyFilter,
|
|
6
|
+
Input,
|
|
7
|
+
Key,
|
|
8
|
+
type Keybindings,
|
|
9
|
+
type KeybindingsManager,
|
|
10
|
+
matchesKey,
|
|
11
|
+
truncateToWidth,
|
|
12
|
+
} from "@earendil-works/pi-tui";
|
|
13
|
+
|
|
14
|
+
interface RenderRequester {
|
|
15
|
+
requestRender: () => void;
|
|
16
|
+
}
|
|
17
|
+
interface SearchableModelSelectorOptions {
|
|
18
|
+
allOptions: string[];
|
|
19
|
+
keybindings: KeybindingsManager;
|
|
20
|
+
onCancel: () => void;
|
|
21
|
+
onSelect: (value: string) => void;
|
|
22
|
+
theme: Theme;
|
|
23
|
+
title: string;
|
|
24
|
+
tui: RenderRequester;
|
|
25
|
+
}
|
|
26
|
+
interface AdvisorSettingsSelectorOptions {
|
|
27
|
+
effortLevels: string[];
|
|
28
|
+
initial: AdvisorSettings;
|
|
29
|
+
onCancel: () => void;
|
|
30
|
+
onSave: (settings: AdvisorSettings) => void;
|
|
31
|
+
presets: ContextPreset[];
|
|
32
|
+
theme: Theme;
|
|
33
|
+
tui: RenderRequester;
|
|
34
|
+
}
|
|
4
35
|
|
|
5
36
|
export class SearchableModelSelector implements Component, Focusable {
|
|
6
|
-
private tui:
|
|
7
|
-
private searchInput: Input;
|
|
8
|
-
private allOptions: string[];
|
|
37
|
+
private readonly tui: RenderRequester;
|
|
38
|
+
private readonly searchInput: Input;
|
|
39
|
+
private readonly allOptions: string[];
|
|
9
40
|
private filteredOptions: string[];
|
|
10
41
|
private selectedIndex = 0;
|
|
11
|
-
private title: string;
|
|
12
|
-
private onSelect: (value: string) => void;
|
|
13
|
-
private onCancel: () => void;
|
|
14
|
-
private theme: Theme;
|
|
15
|
-
private keybindings:
|
|
42
|
+
private readonly title: string;
|
|
43
|
+
private readonly onSelect: (value: string) => void;
|
|
44
|
+
private readonly onCancel: () => void;
|
|
45
|
+
private readonly theme: Theme;
|
|
46
|
+
private readonly keybindings: KeybindingsManager;
|
|
16
47
|
private _focused = false;
|
|
17
48
|
|
|
18
|
-
|
|
19
|
-
|
|
49
|
+
get focused(): boolean {
|
|
50
|
+
return this._focused;
|
|
51
|
+
}
|
|
52
|
+
set focused(val: boolean) {
|
|
20
53
|
this._focused = val;
|
|
21
54
|
this.searchInput.focused = val;
|
|
22
55
|
}
|
|
23
56
|
|
|
24
|
-
constructor(options: {
|
|
25
|
-
tui: any;
|
|
26
|
-
title: string;
|
|
27
|
-
allOptions: string[];
|
|
28
|
-
theme: Theme;
|
|
29
|
-
keybindings: any;
|
|
30
|
-
onSelect: (value: string) => void;
|
|
31
|
-
onCancel: () => void;
|
|
32
|
-
}) {
|
|
57
|
+
constructor(options: SearchableModelSelectorOptions) {
|
|
33
58
|
this.tui = options.tui;
|
|
34
59
|
this.title = options.title;
|
|
35
60
|
this.allOptions = options.allOptions;
|
|
@@ -41,103 +66,177 @@ export class SearchableModelSelector implements Component, Focusable {
|
|
|
41
66
|
this.filteredOptions = this.allOptions;
|
|
42
67
|
}
|
|
43
68
|
|
|
44
|
-
invalidate(): void {
|
|
69
|
+
invalidate(): void {
|
|
70
|
+
this.searchInput.invalidate();
|
|
71
|
+
}
|
|
45
72
|
|
|
46
73
|
render(width: number): string[] {
|
|
47
74
|
const lines: string[] = ["═".repeat(width)];
|
|
48
75
|
lines.push(` ${this.theme.fg("accent", this.theme.bold(this.title))}`);
|
|
49
76
|
const inputLines = this.searchInput.render(width - 12);
|
|
50
|
-
lines.push(
|
|
77
|
+
lines.push(
|
|
78
|
+
` ${this.theme.fg("accent", "Search: ")}${inputLines[0] || ""}`
|
|
79
|
+
);
|
|
51
80
|
lines.push("");
|
|
52
81
|
|
|
53
82
|
const query = this.searchInput.getValue().trim();
|
|
54
|
-
this.filteredOptions = query
|
|
55
|
-
|
|
83
|
+
this.filteredOptions = query
|
|
84
|
+
? fuzzyFilter(this.allOptions, query, (item) => item)
|
|
85
|
+
: this.allOptions;
|
|
86
|
+
this.selectedIndex = Math.min(
|
|
87
|
+
this.selectedIndex,
|
|
88
|
+
Math.max(0, this.filteredOptions.length - 1)
|
|
89
|
+
);
|
|
56
90
|
|
|
57
91
|
const maxVisible = 10;
|
|
58
92
|
const total = this.filteredOptions.length;
|
|
59
93
|
if (total === 0) {
|
|
60
|
-
lines.push(
|
|
94
|
+
lines.push(` ${this.theme.fg("muted", "No matching models found.")}`);
|
|
61
95
|
} else {
|
|
62
|
-
const startIndex = Math.max(
|
|
96
|
+
const startIndex = Math.max(
|
|
97
|
+
0,
|
|
98
|
+
Math.min(
|
|
99
|
+
this.selectedIndex - Math.floor(maxVisible / 2),
|
|
100
|
+
total - maxVisible
|
|
101
|
+
)
|
|
102
|
+
);
|
|
63
103
|
const endIndex = Math.min(startIndex + maxVisible, total);
|
|
64
|
-
for (let i = startIndex; i < endIndex; i
|
|
104
|
+
for (let i = startIndex; i < endIndex; i += 1) {
|
|
65
105
|
const item = this.filteredOptions[i];
|
|
66
|
-
if (i === this.selectedIndex)
|
|
67
|
-
|
|
106
|
+
if (i === this.selectedIndex) {
|
|
107
|
+
lines.push(
|
|
108
|
+
` ${this.theme.fg("accent", "→ ")}${this.theme.fg("accent", item)}`
|
|
109
|
+
);
|
|
110
|
+
} else {
|
|
111
|
+
lines.push(` ${this.theme.fg("text", item)}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (total > maxVisible) {
|
|
115
|
+
lines.push(
|
|
116
|
+
" " +
|
|
117
|
+
this.theme.fg("muted", ` (${this.selectedIndex + 1}/${total})`)
|
|
118
|
+
);
|
|
68
119
|
}
|
|
69
|
-
if (total > maxVisible) lines.push(" " + this.theme.fg("muted", ` (${this.selectedIndex + 1}/${total})`));
|
|
70
120
|
}
|
|
71
121
|
lines.push("");
|
|
72
|
-
lines.push(
|
|
122
|
+
lines.push(
|
|
123
|
+
` ${this.theme.fg("muted", "Type to search · ↑↓: navigate · Enter: select · Esc: cancel")}`
|
|
124
|
+
);
|
|
73
125
|
lines.push("═".repeat(width));
|
|
74
126
|
return lines;
|
|
75
127
|
}
|
|
76
128
|
|
|
77
129
|
handleInput(keyData: string): void {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
130
|
+
if (this.matchesAction(keyData, "tui.select.up", "\u001b[A")) {
|
|
131
|
+
this.moveSelection(-1);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (this.matchesAction(keyData, "tui.select.down", "\u001b[B")) {
|
|
135
|
+
this.moveSelection(1);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (
|
|
139
|
+
this.matchesAction(keyData, "tui.select.confirm", "\n") ||
|
|
140
|
+
keyData === "\r"
|
|
141
|
+
) {
|
|
142
|
+
if (this.filteredOptions.length > 0) {
|
|
143
|
+
this.onSelect(this.filteredOptions[this.selectedIndex]);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (this.matchesAction(keyData, "tui.select.cancel", "\u001b")) {
|
|
88
148
|
this.onCancel();
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
this.searchInput.handleInput(keyData);
|
|
152
|
+
this.selectedIndex = 0;
|
|
153
|
+
this.tui.requestRender();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private matchesAction(
|
|
157
|
+
keyData: string,
|
|
158
|
+
action: keyof Keybindings,
|
|
159
|
+
fallback: string
|
|
160
|
+
) {
|
|
161
|
+
return this.keybindings.matches(keyData, action) || keyData === fallback;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private moveSelection(direction: -1 | 1) {
|
|
165
|
+
if (this.filteredOptions.length > 0) {
|
|
166
|
+
const lastIndex = this.filteredOptions.length - 1;
|
|
167
|
+
const nextIndex = this.selectedIndex + direction;
|
|
168
|
+
if (nextIndex < 0) {
|
|
169
|
+
this.selectedIndex = lastIndex;
|
|
170
|
+
} else if (nextIndex > lastIndex) {
|
|
171
|
+
this.selectedIndex = 0;
|
|
172
|
+
} else {
|
|
173
|
+
this.selectedIndex = nextIndex;
|
|
174
|
+
}
|
|
93
175
|
}
|
|
176
|
+
this.tui.requestRender();
|
|
94
177
|
}
|
|
95
178
|
}
|
|
96
179
|
|
|
97
|
-
export
|
|
180
|
+
export interface ContextPreset {
|
|
181
|
+
description: string;
|
|
182
|
+
label: string;
|
|
183
|
+
value: number;
|
|
184
|
+
}
|
|
98
185
|
|
|
99
|
-
export
|
|
186
|
+
export interface AdvisorSettings {
|
|
187
|
+
autoLoopGate?: boolean;
|
|
188
|
+
blockOnBlocked?: boolean;
|
|
189
|
+
collapseResponses: boolean;
|
|
190
|
+
completionGate: boolean;
|
|
100
191
|
contextMaxChars: number;
|
|
192
|
+
customRule?: string;
|
|
101
193
|
effort?: string;
|
|
102
|
-
planGate: boolean;
|
|
103
194
|
failureGate: boolean;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
customRule?: string;
|
|
107
|
-
blockOnBlocked?: boolean;
|
|
108
|
-
autoLoopGate?: boolean;
|
|
195
|
+
failureMode?: "block-session" | "block-tool" | "warn-and-continue";
|
|
196
|
+
herdrIntegration?: boolean;
|
|
109
197
|
loopThreshold?: number;
|
|
110
198
|
maxCallsPerSession?: number;
|
|
199
|
+
planGate: boolean;
|
|
111
200
|
sessionSummary?: boolean;
|
|
112
|
-
|
|
201
|
+
toolResultMaxBytes?: number;
|
|
202
|
+
toolResultMaxLines?: number;
|
|
203
|
+
}
|
|
113
204
|
|
|
114
205
|
export class AdvisorSettingsSelector implements Component, Focusable {
|
|
115
|
-
private selectedRow
|
|
206
|
+
private selectedRow: number;
|
|
116
207
|
private contextIndex: number;
|
|
117
208
|
private effortIndex: number;
|
|
118
|
-
private settings: AdvisorSettings;
|
|
119
|
-
private customInput = new Input();
|
|
120
|
-
private editingCustom
|
|
209
|
+
private readonly settings: AdvisorSettings;
|
|
210
|
+
private readonly customInput = new Input();
|
|
211
|
+
private editingCustom: boolean;
|
|
121
212
|
private _focused = false;
|
|
213
|
+
private readonly options: AdvisorSettingsSelectorOptions;
|
|
122
214
|
|
|
123
|
-
|
|
124
|
-
|
|
215
|
+
get focused(): boolean {
|
|
216
|
+
return this._focused;
|
|
217
|
+
}
|
|
218
|
+
set focused(value: boolean) {
|
|
125
219
|
this._focused = value;
|
|
126
220
|
this.customInput.focused = value && this.editingCustom;
|
|
127
221
|
}
|
|
128
222
|
|
|
129
|
-
constructor(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
effortLevels: string[];
|
|
134
|
-
initial: AdvisorSettings;
|
|
135
|
-
onSave: (settings: AdvisorSettings) => void;
|
|
136
|
-
onCancel: () => void;
|
|
137
|
-
}) {
|
|
223
|
+
constructor(options: AdvisorSettingsSelectorOptions) {
|
|
224
|
+
this.selectedRow = 0;
|
|
225
|
+
this.editingCustom = false;
|
|
226
|
+
this.options = options;
|
|
138
227
|
this.settings = { ...options.initial };
|
|
139
|
-
this.contextIndex = Math.max(
|
|
140
|
-
|
|
228
|
+
this.contextIndex = Math.max(
|
|
229
|
+
0,
|
|
230
|
+
options.presets.findIndex(
|
|
231
|
+
(preset) => preset.value === this.settings.contextMaxChars
|
|
232
|
+
)
|
|
233
|
+
);
|
|
234
|
+
this.effortIndex = Math.max(
|
|
235
|
+
0,
|
|
236
|
+
options.effortLevels.indexOf(
|
|
237
|
+
this.settings.effort || "Default (Model Default)"
|
|
238
|
+
)
|
|
239
|
+
);
|
|
141
240
|
this.customInput.onSubmit = (value) => {
|
|
142
241
|
this.settings.customRule = value.trim() || undefined;
|
|
143
242
|
this.editingCustom = false;
|
|
@@ -151,46 +250,124 @@ export class AdvisorSettingsSelector implements Component, Focusable {
|
|
|
151
250
|
};
|
|
152
251
|
}
|
|
153
252
|
|
|
154
|
-
invalidate(): void {
|
|
253
|
+
invalidate(): void {
|
|
254
|
+
this.options.tui.requestRender();
|
|
255
|
+
}
|
|
155
256
|
|
|
156
|
-
private currentContext() {
|
|
257
|
+
private currentContext(): ContextPreset {
|
|
258
|
+
const preset = this.options.presets.find(
|
|
259
|
+
(item) => item.value === this.settings.contextMaxChars
|
|
260
|
+
);
|
|
261
|
+
return (
|
|
262
|
+
preset ?? {
|
|
263
|
+
description: "Current custom context limit",
|
|
264
|
+
label: String(this.settings.contextMaxChars),
|
|
265
|
+
value: this.settings.contextMaxChars,
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
private currentEffort() {
|
|
270
|
+
return this.settings.effort || "Default (Model Default)";
|
|
271
|
+
}
|
|
157
272
|
private row(label: string, value: string, index: number) {
|
|
158
273
|
const { theme } = this.options;
|
|
159
274
|
const prefix = index === this.selectedRow ? theme.fg("accent", "›") : " ";
|
|
160
275
|
const text = `${prefix} ${label.padEnd(28)} ${value}`;
|
|
161
|
-
return index === this.selectedRow
|
|
276
|
+
return index === this.selectedRow
|
|
277
|
+
? theme.fg("accent", theme.bold(text))
|
|
278
|
+
: theme.fg("text", text);
|
|
162
279
|
}
|
|
163
280
|
|
|
164
281
|
render(width: number): string[] {
|
|
165
282
|
const { theme, presets } = this.options;
|
|
166
283
|
const trackWidth = Math.max(24, Math.min(60, width - 4));
|
|
167
|
-
const positions = presets.map((_, index) =>
|
|
284
|
+
const positions = presets.map((_, index) =>
|
|
285
|
+
Math.round((index * (trackWidth - 1)) / Math.max(1, presets.length - 1))
|
|
286
|
+
);
|
|
168
287
|
const track = Array.from({ length: trackWidth }, () => "─");
|
|
169
288
|
track[positions[this.contextIndex]] = "▲";
|
|
170
289
|
const labels = Array.from({ length: trackWidth }, () => " ");
|
|
171
|
-
for (let index = 0; index < presets.length; index
|
|
172
|
-
const label = presets[index]
|
|
173
|
-
const start = Math.max(
|
|
174
|
-
|
|
290
|
+
for (let index = 0; index < presets.length; index += 1) {
|
|
291
|
+
const { label } = presets[index];
|
|
292
|
+
const start = Math.max(
|
|
293
|
+
0,
|
|
294
|
+
Math.min(
|
|
295
|
+
trackWidth - label.length,
|
|
296
|
+
positions[index] - Math.floor(label.length / 2)
|
|
297
|
+
)
|
|
298
|
+
);
|
|
299
|
+
for (let char = 0; char < label.length; char += 1) {
|
|
300
|
+
labels[start + char] = label[char];
|
|
301
|
+
}
|
|
175
302
|
}
|
|
176
303
|
const heading = `Recent history${" ".repeat(Math.max(1, trackWidth - "Recent history".length - "Full branch".length))}Full branch`;
|
|
177
|
-
const onOff = (value: boolean) => value ? "On" : "Off";
|
|
304
|
+
const onOff = (value: boolean) => (value ? "On" : "Off");
|
|
178
305
|
const rows = [
|
|
179
306
|
this.row("Context window", this.currentContext().label, 0),
|
|
180
|
-
this.row("Advisor reasoning", this.
|
|
307
|
+
this.row("Advisor reasoning", this.currentEffort(), 1),
|
|
181
308
|
this.row("Plan gate", onOff(this.settings.planGate), 2),
|
|
182
309
|
this.row("Failure gate", onOff(this.settings.failureGate), 3),
|
|
183
310
|
this.row("Completion gate", onOff(this.settings.completionGate), 4),
|
|
184
|
-
this.row(
|
|
311
|
+
this.row(
|
|
312
|
+
"Collapse long responses",
|
|
313
|
+
onOff(this.settings.collapseResponses),
|
|
314
|
+
5
|
|
315
|
+
),
|
|
185
316
|
this.row("Custom invocation", this.settings.customRule || "None", 6),
|
|
186
|
-
this.row(
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
317
|
+
this.row(
|
|
318
|
+
"Block on critical advice",
|
|
319
|
+
onOff(this.settings.blockOnBlocked ?? true),
|
|
320
|
+
7
|
|
321
|
+
),
|
|
322
|
+
this.row(
|
|
323
|
+
"Automatic loop gate",
|
|
324
|
+
onOff(this.settings.autoLoopGate ?? true),
|
|
325
|
+
8
|
|
326
|
+
),
|
|
327
|
+
this.row(
|
|
328
|
+
"Loop threshold",
|
|
329
|
+
`After ${this.settings.loopThreshold ?? 3} repeats`,
|
|
330
|
+
9
|
|
331
|
+
),
|
|
332
|
+
this.row(
|
|
333
|
+
"Max Advisor calls/session",
|
|
334
|
+
this.settings.maxCallsPerSession === undefined
|
|
335
|
+
? "∞"
|
|
336
|
+
: String(this.settings.maxCallsPerSession),
|
|
337
|
+
10
|
|
338
|
+
),
|
|
339
|
+
this.row(
|
|
340
|
+
"Session Advisor Summary",
|
|
341
|
+
onOff(this.settings.sessionSummary ?? true),
|
|
342
|
+
11
|
|
343
|
+
),
|
|
344
|
+
this.row(
|
|
345
|
+
"Gate failure mode",
|
|
346
|
+
this.settings.failureMode ?? "block-session",
|
|
347
|
+
12
|
|
348
|
+
),
|
|
349
|
+
this.row(
|
|
350
|
+
"Herdr integration",
|
|
351
|
+
onOff(this.settings.herdrIntegration ?? true),
|
|
352
|
+
13
|
|
353
|
+
),
|
|
354
|
+
this.row(
|
|
355
|
+
"Tool result lines",
|
|
356
|
+
String(this.settings.toolResultMaxLines ?? 2000),
|
|
357
|
+
14
|
|
358
|
+
),
|
|
359
|
+
this.row(
|
|
360
|
+
"Tool result bytes",
|
|
361
|
+
String(this.settings.toolResultMaxBytes ?? 50 * 1024),
|
|
362
|
+
15
|
|
363
|
+
),
|
|
191
364
|
];
|
|
192
|
-
if (this.editingCustom)
|
|
193
|
-
|
|
365
|
+
if (this.editingCustom) {
|
|
366
|
+
rows.push(
|
|
367
|
+
` ${this.customInput.render(Math.max(10, width - 6))[0] || ""}`
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
rows.push(this.row("Save changes", "", 16));
|
|
194
371
|
return [
|
|
195
372
|
theme.fg("accent", theme.bold(" Advisor settings")),
|
|
196
373
|
"",
|
|
@@ -213,7 +390,7 @@ export class AdvisorSettingsSelector implements Component, Focusable {
|
|
|
213
390
|
if (matchesKey(keyData, Key.up)) {
|
|
214
391
|
this.selectedRow = Math.max(0, this.selectedRow - 1);
|
|
215
392
|
} else if (matchesKey(keyData, Key.down)) {
|
|
216
|
-
this.selectedRow = Math.min(
|
|
393
|
+
this.selectedRow = Math.min(16, this.selectedRow + 1);
|
|
217
394
|
} else if (matchesKey(keyData, Key.left)) {
|
|
218
395
|
this.adjust(-1);
|
|
219
396
|
} else if (matchesKey(keyData, Key.right)) {
|
|
@@ -226,32 +403,125 @@ export class AdvisorSettingsSelector implements Component, Focusable {
|
|
|
226
403
|
tui.requestRender();
|
|
227
404
|
return;
|
|
228
405
|
}
|
|
229
|
-
if (this.selectedRow ===
|
|
406
|
+
if (this.selectedRow === 16) {
|
|
407
|
+
this.options.onSave({
|
|
408
|
+
...this.settings,
|
|
409
|
+
contextMaxChars: this.currentContext().value,
|
|
410
|
+
effort: this.currentEffort(),
|
|
411
|
+
});
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
230
414
|
this.adjust(1);
|
|
231
415
|
} else if (matchesKey(keyData, Key.escape)) {
|
|
232
|
-
|
|
233
|
-
|
|
416
|
+
this.options.onCancel();
|
|
417
|
+
return;
|
|
418
|
+
} else {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
234
421
|
tui.requestRender();
|
|
235
422
|
}
|
|
236
423
|
|
|
237
424
|
private adjust(direction: number) {
|
|
238
425
|
switch (this.selectedRow) {
|
|
239
|
-
case 0:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
426
|
+
case 0:
|
|
427
|
+
this.contextIndex = Math.max(
|
|
428
|
+
0,
|
|
429
|
+
Math.min(
|
|
430
|
+
this.options.presets.length - 1,
|
|
431
|
+
this.contextIndex + direction
|
|
432
|
+
)
|
|
433
|
+
);
|
|
434
|
+
this.settings.contextMaxChars =
|
|
435
|
+
this.options.presets[this.contextIndex].value;
|
|
436
|
+
break;
|
|
437
|
+
case 1:
|
|
438
|
+
this.effortIndex = Math.max(
|
|
439
|
+
0,
|
|
440
|
+
Math.min(
|
|
441
|
+
this.options.effortLevels.length - 1,
|
|
442
|
+
this.effortIndex + direction
|
|
443
|
+
)
|
|
444
|
+
);
|
|
445
|
+
this.settings.effort = this.options.effortLevels[this.effortIndex];
|
|
446
|
+
break;
|
|
447
|
+
case 2:
|
|
448
|
+
this.settings.planGate = !this.settings.planGate;
|
|
449
|
+
break;
|
|
450
|
+
case 3:
|
|
451
|
+
this.settings.failureGate = !this.settings.failureGate;
|
|
452
|
+
break;
|
|
453
|
+
case 4:
|
|
454
|
+
this.settings.completionGate = !this.settings.completionGate;
|
|
455
|
+
break;
|
|
456
|
+
case 5:
|
|
457
|
+
this.settings.collapseResponses = !this.settings.collapseResponses;
|
|
458
|
+
break;
|
|
459
|
+
case 7:
|
|
460
|
+
this.settings.blockOnBlocked = !(this.settings.blockOnBlocked ?? true);
|
|
461
|
+
break;
|
|
462
|
+
case 8:
|
|
463
|
+
this.settings.autoLoopGate = !(this.settings.autoLoopGate ?? true);
|
|
464
|
+
break;
|
|
465
|
+
case 9:
|
|
466
|
+
this.settings.loopThreshold = Math.max(
|
|
467
|
+
2,
|
|
468
|
+
(this.settings.loopThreshold ?? 3) + direction
|
|
469
|
+
);
|
|
470
|
+
break;
|
|
248
471
|
case 10: {
|
|
249
472
|
const values = [undefined, 0, 1, 2, 3, 5, 10, 25, 50];
|
|
250
|
-
const index = Math.max(
|
|
251
|
-
|
|
473
|
+
const index = Math.max(
|
|
474
|
+
0,
|
|
475
|
+
values.indexOf(this.settings.maxCallsPerSession)
|
|
476
|
+
);
|
|
477
|
+
this.settings.maxCallsPerSession =
|
|
478
|
+
values[Math.max(0, Math.min(values.length - 1, index + direction))];
|
|
252
479
|
break;
|
|
253
480
|
}
|
|
254
|
-
case 11:
|
|
481
|
+
case 11:
|
|
482
|
+
this.settings.sessionSummary = !(this.settings.sessionSummary ?? true);
|
|
483
|
+
break;
|
|
484
|
+
case 12: {
|
|
485
|
+
const modes: AdvisorSettings["failureMode"][] = [
|
|
486
|
+
"block-session",
|
|
487
|
+
"block-tool",
|
|
488
|
+
"warn-and-continue",
|
|
489
|
+
];
|
|
490
|
+
const index = Math.max(
|
|
491
|
+
0,
|
|
492
|
+
modes.indexOf(this.settings.failureMode ?? "block-session")
|
|
493
|
+
);
|
|
494
|
+
this.settings.failureMode =
|
|
495
|
+
modes[Math.max(0, Math.min(modes.length - 1, index + direction))];
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
case 13:
|
|
499
|
+
this.settings.herdrIntegration = !(
|
|
500
|
+
this.settings.herdrIntegration ?? true
|
|
501
|
+
);
|
|
502
|
+
break;
|
|
503
|
+
case 14: {
|
|
504
|
+
const values = [0, 500, 1000, 2000, 5000, 10_000];
|
|
505
|
+
const index = Math.max(
|
|
506
|
+
0,
|
|
507
|
+
values.indexOf(this.settings.toolResultMaxLines ?? 2000)
|
|
508
|
+
);
|
|
509
|
+
this.settings.toolResultMaxLines =
|
|
510
|
+
values[Math.max(0, Math.min(values.length - 1, index + direction))];
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
case 15: {
|
|
514
|
+
const values = [0, 10 * 1024, 50 * 1024, 100 * 1024, 500 * 1024];
|
|
515
|
+
const index = Math.max(
|
|
516
|
+
0,
|
|
517
|
+
values.indexOf(this.settings.toolResultMaxBytes ?? 50 * 1024)
|
|
518
|
+
);
|
|
519
|
+
this.settings.toolResultMaxBytes =
|
|
520
|
+
values[Math.max(0, Math.min(values.length - 1, index + direction))];
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
default:
|
|
524
|
+
break;
|
|
255
525
|
}
|
|
256
526
|
}
|
|
257
527
|
}
|