pi-advisor-flow 0.5.6 → 0.7.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +1 -0
  3. package/dist/index.js +3160 -1255
  4. package/extensions/index.ts +9 -9
  5. package/package.json +12 -8
  6. package/src/{untracked.ts → attachments.ts} +2 -5
  7. package/src/commands/activation-preparation.ts +6 -6
  8. package/src/commands/activation.ts +7 -7
  9. package/src/commands/lifecycle.ts +5 -5
  10. package/src/commands/manual-command.ts +13 -9
  11. package/src/commands/manual-consultation.ts +24 -10
  12. package/src/commands/manual-progress.ts +3 -3
  13. package/src/commands/model-commands.ts +6 -6
  14. package/src/commands/model-options.ts +4 -4
  15. package/src/commands/model-picker.ts +2 -2
  16. package/src/commands/registration.ts +8 -8
  17. package/src/commands/renderers.ts +5 -5
  18. package/src/commands/runtime.ts +8 -8
  19. package/src/commands/settings-commands.ts +8 -8
  20. package/src/commands/settings-persistence.ts +52 -4
  21. package/src/commands/types.ts +6 -13
  22. package/src/commands.ts +2 -2
  23. package/src/config/args.ts +3 -3
  24. package/src/config/defaults.ts +78 -3
  25. package/src/config/schema.ts +434 -0
  26. package/src/config/state.ts +71 -2
  27. package/src/config/storage.ts +27 -119
  28. package/src/config/types.ts +30 -1
  29. package/src/config/validation.ts +61 -181
  30. package/src/config.ts +7 -7
  31. package/src/content-utils.ts +30 -0
  32. package/src/conversation.ts +13 -168
  33. package/src/git.ts +4 -18
  34. package/src/herdr.ts +6 -8
  35. package/src/jev/client.ts +348 -0
  36. package/src/jev/key-store.ts +252 -0
  37. package/src/jev/ledger.ts +234 -0
  38. package/src/jev/questions.ts +119 -0
  39. package/src/jev/state.ts +47 -0
  40. package/src/jev/transport.ts +58 -0
  41. package/src/model-stream.ts +5 -8
  42. package/src/outcomes.ts +3 -2
  43. package/src/pi-settings.ts +59 -0
  44. package/src/preferences.ts +2 -2
  45. package/src/redaction.ts +50 -0
  46. package/src/scout-context.ts +121 -485
  47. package/src/scout-curation.ts +84 -0
  48. package/src/scout-groups.ts +485 -0
  49. package/src/scout-protocol.ts +122 -0
  50. package/src/scout-reconstruct.ts +44 -0
  51. package/src/scout-types.ts +66 -0
  52. package/src/scout.ts +53 -63
  53. package/src/session-state.ts +215 -78
  54. package/src/tool-result-cap.ts +88 -0
  55. package/src/tools/consult-context.ts +155 -0
  56. package/src/tools/consultation.ts +71 -220
  57. package/src/tools/gate-policy.ts +5 -5
  58. package/src/tools/gate-protocol.ts +2 -2
  59. package/src/tools/jev-filter.ts +202 -0
  60. package/src/tools/jev-turn-gate.ts +183 -0
  61. package/src/tools/loop-gate.ts +71 -61
  62. package/src/tools/outage-notifier.ts +30 -0
  63. package/src/tools/prompts.ts +4 -7
  64. package/src/tools/register-ask-advisor.ts +46 -15
  65. package/src/tools/register-lifecycle.ts +7 -7
  66. package/src/tools/register-outcome.ts +5 -5
  67. package/src/tools/register-renderers.ts +63 -5
  68. package/src/tools/registration.ts +27 -10
  69. package/src/tools/render-advisor-result.ts +54 -22
  70. package/src/tools/render-common.ts +25 -13
  71. package/src/tools/scout-status.ts +5 -5
  72. package/src/tools/session.ts +1 -1
  73. package/src/tools/types.ts +17 -7
  74. package/src/tools.ts +9 -9
  75. package/src/ui/jev-setup-submenu.ts +344 -0
  76. package/src/ui/manual-dialog-render.ts +2 -2
  77. package/src/ui/manual-dialog.ts +4 -9
  78. package/src/ui/masked-input.ts +68 -0
  79. package/src/ui/model-selector.ts +1 -1
  80. package/src/ui/settings-formatting.ts +2 -2
  81. package/src/ui/settings-items.ts +166 -5
  82. package/src/ui/settings-mutations.ts +37 -2
  83. package/src/ui/settings-selector.ts +5 -5
  84. package/src/ui/text-setting-submenu.ts +1 -1
  85. package/src/ui/types.ts +13 -2
  86. package/src/ui.ts +4 -4
  87. package/src/usage.ts +4 -7
@@ -10,6 +10,17 @@ import {
10
10
  setAdvisorGitContextMaxCharsRef,
11
11
  setAdvisorGitContextRef,
12
12
  setAdvisorHerdrIntegrationRef,
13
+ setAdvisorJevDigestMaxCharsRef,
14
+ setAdvisorJevFilterEnabledRef,
15
+ setAdvisorJevFilterNoulMarginRef,
16
+ setAdvisorJevFilterOverrideWindowRef,
17
+ setAdvisorJevFilterSkipConfidenceRef,
18
+ setAdvisorJevModelRef,
19
+ setAdvisorJevPricePerMtokRef,
20
+ setAdvisorJevTimeoutMsRef,
21
+ setAdvisorJevTransportRef,
22
+ setAdvisorJevTurnGateEveryTurnsRef,
23
+ setAdvisorJevTurnGateNoulThresholdRef,
13
24
  setAdvisorLoopThresholdRef,
14
25
  setAdvisorMaxCallsPerSessionRef,
15
26
  setAdvisorOutcomeLoggingRef,
@@ -31,14 +42,24 @@ import {
31
42
  setShowUsageDetailsRef,
32
43
  setShowUsageFooterRef,
33
44
  setSimpleModeRef,
34
- } from "./state.js";
35
- import type { AdvisorConfig } from "./types.js";
45
+ } from "./state.ts";
46
+ import type { AdvisorConfig } from "./types.ts";
36
47
  import {
37
48
  DEFAULT_ADVISOR_GIT_CONTEXT_MAX_CHARS,
38
49
  DEFAULT_ADVISOR_TOOL_RESULT_MAX_BYTES,
39
50
  DEFAULT_ADVISOR_TOOL_RESULT_MAX_LINES,
40
51
  DEFAULT_CONTEXT_MAX_CHARS,
41
- } from "./types.js";
52
+ DEFAULT_JEV_DIGEST_MAX_CHARS,
53
+ DEFAULT_JEV_FILTER_NOUL_MARGIN,
54
+ DEFAULT_JEV_FILTER_OVERRIDE_WINDOW,
55
+ DEFAULT_JEV_FILTER_SKIP_CONFIDENCE,
56
+ DEFAULT_JEV_MODEL,
57
+ DEFAULT_JEV_PRICE_PER_MTOK,
58
+ DEFAULT_JEV_TIMEOUT_MS,
59
+ DEFAULT_JEV_TRANSPORT,
60
+ DEFAULT_JEV_TURN_GATE_EVERY_TURNS,
61
+ DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD,
62
+ } from "./types.ts";
42
63
 
43
64
  export const resetDefaults = () => {
44
65
  setExecutorRef("");
@@ -61,6 +82,17 @@ export const resetDefaults = () => {
61
82
  setAlwaysOnRef(false);
62
83
  setAdvisorFailureModeRef("block-session");
63
84
  setAdvisorHerdrIntegrationRef(true);
85
+ setAdvisorJevModelRef(DEFAULT_JEV_MODEL);
86
+ setAdvisorJevFilterEnabledRef(false);
87
+ setAdvisorJevFilterSkipConfidenceRef(DEFAULT_JEV_FILTER_SKIP_CONFIDENCE);
88
+ setAdvisorJevFilterNoulMarginRef(DEFAULT_JEV_FILTER_NOUL_MARGIN);
89
+ setAdvisorJevFilterOverrideWindowRef(DEFAULT_JEV_FILTER_OVERRIDE_WINDOW);
90
+ setAdvisorJevTimeoutMsRef(DEFAULT_JEV_TIMEOUT_MS);
91
+ setAdvisorJevDigestMaxCharsRef(DEFAULT_JEV_DIGEST_MAX_CHARS);
92
+ setAdvisorJevPricePerMtokRef(DEFAULT_JEV_PRICE_PER_MTOK);
93
+ setAdvisorJevTransportRef(DEFAULT_JEV_TRANSPORT);
94
+ setAdvisorJevTurnGateEveryTurnsRef(DEFAULT_JEV_TURN_GATE_EVERY_TURNS);
95
+ setAdvisorJevTurnGateNoulThresholdRef(DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD);
64
96
  setAdvisorToolResultMaxLinesRef(DEFAULT_ADVISOR_TOOL_RESULT_MAX_LINES);
65
97
  setAdvisorToolResultMaxBytesRef(DEFAULT_ADVISOR_TOOL_RESULT_MAX_BYTES);
66
98
  setAdvisorRedactSecretsRef(false);
@@ -150,6 +182,49 @@ export const applyConfig = (config: AdvisorConfig) => {
150
182
  "advisorHerdrIntegration",
151
183
  setAdvisorHerdrIntegrationRef
152
184
  );
185
+ applyOptionalConfig(
186
+ config,
187
+ "advisorJevFilterEnabled",
188
+ setAdvisorJevFilterEnabledRef
189
+ );
190
+ applyOptionalConfig(
191
+ config,
192
+ "advisorJevFilterSkipConfidence",
193
+ setAdvisorJevFilterSkipConfidenceRef
194
+ );
195
+ applyOptionalConfig(
196
+ config,
197
+ "advisorJevFilterNoulMargin",
198
+ setAdvisorJevFilterNoulMarginRef
199
+ );
200
+ applyOptionalConfig(
201
+ config,
202
+ "advisorJevFilterOverrideWindow",
203
+ setAdvisorJevFilterOverrideWindowRef
204
+ );
205
+ applyNonEmptyStringConfig(config.advisorJevModel, setAdvisorJevModelRef);
206
+ applyOptionalConfig(config, "advisorJevTimeoutMs", setAdvisorJevTimeoutMsRef);
207
+ applyOptionalConfig(
208
+ config,
209
+ "advisorJevDigestMaxChars",
210
+ setAdvisorJevDigestMaxCharsRef
211
+ );
212
+ applyOptionalConfig(
213
+ config,
214
+ "advisorJevPricePerMtok",
215
+ setAdvisorJevPricePerMtokRef
216
+ );
217
+ applyOptionalConfig(config, "advisorJevTransport", setAdvisorJevTransportRef);
218
+ applyOptionalConfig(
219
+ config,
220
+ "advisorJevTurnGateEveryTurns",
221
+ setAdvisorJevTurnGateEveryTurnsRef
222
+ );
223
+ applyOptionalConfig(
224
+ config,
225
+ "advisorJevTurnGateNoulThreshold",
226
+ setAdvisorJevTurnGateNoulThresholdRef
227
+ );
153
228
  applyOptionalConfig(
154
229
  config,
155
230
  "advisorToolResultMaxLines",
@@ -0,0 +1,434 @@
1
+ import { GIT_CONTEXT_LEVELS, isValidGitContextLevel } from "../git.ts";
2
+ import {
3
+ advisorAutoLoopGateRef,
4
+ advisorBlockOnBlockedRef,
5
+ advisorCollapseResponsesRef,
6
+ advisorCompletionGateRef,
7
+ advisorCustomInvocationRef,
8
+ advisorEffortRef,
9
+ advisorFailureGateRef,
10
+ advisorFailureModeRef,
11
+ advisorGitContextMaxCharsRef,
12
+ advisorGitContextRef,
13
+ advisorHerdrIntegrationRef,
14
+ advisorJevDigestMaxCharsRef,
15
+ advisorJevFilterEnabledRef,
16
+ advisorJevFilterNoulMarginRef,
17
+ advisorJevFilterOverrideWindowRef,
18
+ advisorJevFilterSkipConfidenceRef,
19
+ advisorJevModelRef,
20
+ advisorJevPricePerMtokRef,
21
+ advisorJevTimeoutMsRef,
22
+ advisorJevTransportRef,
23
+ advisorJevTurnGateEveryTurnsRef,
24
+ advisorJevTurnGateNoulThresholdRef,
25
+ advisorLoopThresholdRef,
26
+ advisorMaxCallsPerSessionRef,
27
+ advisorOutcomeLoggingRef,
28
+ advisorPlanGateRef,
29
+ advisorRedactSecretsRef,
30
+ advisorRef,
31
+ advisorScoutEnabledRef,
32
+ advisorSessionSummaryRef,
33
+ advisorToolPoliciesRef,
34
+ advisorToolResultMaxBytesRef,
35
+ advisorToolResultMaxLinesRef,
36
+ advisorTrackedFileContentRef,
37
+ advisorUntrackedContentRef,
38
+ alwaysOnRef,
39
+ contextMaxCharsRef,
40
+ executorEffortRef,
41
+ executorRef,
42
+ showUsageDetailsRef,
43
+ showUsageFooterRef,
44
+ simpleModeRef,
45
+ } from "./state.ts";
46
+ import {
47
+ ADVISOR_TOOL_POLICIES,
48
+ type AdvisorConfig,
49
+ GATE_FAILURE_MODES,
50
+ JEV_TRANSPORTS,
51
+ type JevTransport,
52
+ MAX_CONTEXT_MAX_CHARS,
53
+ } from "./types.ts";
54
+
55
+ /** An empty ref means no model has been selected yet. */
56
+ const configuredModelRef = (value: string | undefined): string | undefined =>
57
+ value?.trim() || undefined;
58
+
59
+ export const isValidAdvisorToolPolicies = (
60
+ value: unknown
61
+ ): value is Record<string, (typeof ADVISOR_TOOL_POLICIES)[number]> => {
62
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
63
+ return false;
64
+ }
65
+ return Object.entries(value).every(
66
+ ([toolName, policy]) =>
67
+ toolName.trim().length > 0 &&
68
+ typeof policy === "string" &&
69
+ ADVISOR_TOOL_POLICIES.includes(
70
+ policy as (typeof ADVISOR_TOOL_POLICIES)[number]
71
+ )
72
+ );
73
+ };
74
+
75
+ const nonNegativeSafeInteger = (value: unknown): value is number =>
76
+ typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
77
+
78
+ export const isValidContextMaxChars = (value: unknown): value is number =>
79
+ typeof value === "number" &&
80
+ Number.isSafeInteger(value) &&
81
+ value >= 0 &&
82
+ value <= MAX_CONTEXT_MAX_CHARS;
83
+
84
+ export const isValidLoopThreshold = (value: unknown): value is number =>
85
+ typeof value === "number" && Number.isSafeInteger(value) && value >= 2;
86
+
87
+ export const isValidMaxCallsPerSession = (value: unknown): value is number =>
88
+ nonNegativeSafeInteger(value);
89
+
90
+ export const isValidGateFailureMode = (
91
+ value: unknown
92
+ ): value is (typeof GATE_FAILURE_MODES)[number] =>
93
+ typeof value === "string" &&
94
+ GATE_FAILURE_MODES.includes(value as (typeof GATE_FAILURE_MODES)[number]);
95
+
96
+ export const isValidToolResultMaxLines = (value: unknown): value is number =>
97
+ nonNegativeSafeInteger(value);
98
+
99
+ export const isValidToolResultMaxBytes = (value: unknown): value is number =>
100
+ nonNegativeSafeInteger(value);
101
+
102
+ export const isValidJevTimeoutMs = (value: unknown): value is number =>
103
+ typeof value === "number" && Number.isSafeInteger(value) && value >= 1;
104
+
105
+ export const isValidJevDigestMaxChars = (value: unknown): value is number =>
106
+ nonNegativeSafeInteger(value);
107
+
108
+ export const isValidJevPricePerMtok = (value: unknown): value is number =>
109
+ typeof value === "number" && Number.isFinite(value) && value > 0;
110
+
111
+ export const isValidJevSkipConfidence = (value: unknown): value is number =>
112
+ typeof value === "number" &&
113
+ Number.isFinite(value) &&
114
+ value >= 0.5 &&
115
+ value <= 1;
116
+
117
+ export const isValidJevNoulMargin = (value: unknown): value is number =>
118
+ typeof value === "number" &&
119
+ Number.isFinite(value) &&
120
+ value >= 0 &&
121
+ value <= 0.5;
122
+
123
+ export const isValidJevTransport = (value: unknown): value is JevTransport =>
124
+ typeof value === "string" && JEV_TRANSPORTS.includes(value as JevTransport);
125
+
126
+ /** One declarative entry per AdvisorConfig key: JSON type, persistence, and
127
+ * the live runtime value behind it. Validation and storage derive from this
128
+ * table; adding a setting means adding exactly one entry here. */
129
+ export interface ConfigKeySchema {
130
+ /** Human-readable accepted-value phrase for error messages. */
131
+ accepted: string;
132
+ /** Live runtime value captured by saveConfig. */
133
+ current: () => unknown;
134
+ /** Included in the state captured and diffed by saveConfig. */
135
+ persisted: boolean;
136
+ /** JSON value type used for the base type check. */
137
+ type: "string" | "boolean" | "number" | "enum" | "object";
138
+ /** Type beyond the JSON type, for enum and object keys. */
139
+ validate?: (value: unknown) => boolean;
140
+ }
141
+
142
+ export const CONFIG_SCHEMA = {
143
+ advisor: {
144
+ accepted: "a provider/model string",
145
+ current: () => configuredModelRef(advisorRef),
146
+ persisted: true,
147
+ type: "string",
148
+ },
149
+ advisorAutoLoopGate: {
150
+ accepted: "true or false",
151
+ current: () => advisorAutoLoopGateRef,
152
+ persisted: true,
153
+ type: "boolean",
154
+ },
155
+ advisorBlockOnBlocked: {
156
+ accepted: "true or false",
157
+ current: () => advisorBlockOnBlockedRef,
158
+ persisted: true,
159
+ type: "boolean",
160
+ },
161
+ advisorCollapseResponses: {
162
+ accepted: "true or false",
163
+ current: () => advisorCollapseResponsesRef,
164
+ persisted: true,
165
+ type: "boolean",
166
+ },
167
+ advisorCompletionGate: {
168
+ accepted: "true or false",
169
+ current: () => advisorCompletionGateRef,
170
+ persisted: true,
171
+ type: "boolean",
172
+ },
173
+ advisorCustomInvocation: {
174
+ accepted: "a string",
175
+ current: () => advisorCustomInvocationRef,
176
+ persisted: true,
177
+ type: "string",
178
+ },
179
+ advisorEffort: {
180
+ accepted: "a string",
181
+ current: () => advisorEffortRef,
182
+ persisted: true,
183
+ type: "string",
184
+ },
185
+ advisorFailureGate: {
186
+ accepted: "true or false",
187
+ current: () => advisorFailureGateRef,
188
+ persisted: true,
189
+ type: "boolean",
190
+ },
191
+ advisorGitContext: {
192
+ accepted: GIT_CONTEXT_LEVELS.join(", "),
193
+ current: () => advisorGitContextRef,
194
+ persisted: true,
195
+ type: "enum",
196
+ validate: isValidGitContextLevel,
197
+ },
198
+ advisorGitContextMaxChars: {
199
+ accepted: "a non-negative safe integer",
200
+ current: () => advisorGitContextMaxCharsRef,
201
+ persisted: true,
202
+ type: "number",
203
+ validate: nonNegativeSafeInteger,
204
+ },
205
+ advisorHerdrIntegration: {
206
+ accepted: "true or false",
207
+ current: () => advisorHerdrIntegrationRef,
208
+ persisted: true,
209
+ type: "boolean",
210
+ },
211
+ advisorJevDigestMaxChars: {
212
+ accepted: "a non-negative safe integer",
213
+ current: () => advisorJevDigestMaxCharsRef,
214
+ persisted: true,
215
+ type: "number",
216
+ validate: isValidJevDigestMaxChars,
217
+ },
218
+ advisorJevFilterEnabled: {
219
+ accepted: "true or false",
220
+ current: () => advisorJevFilterEnabledRef,
221
+ persisted: true,
222
+ type: "boolean",
223
+ },
224
+ advisorJevFilterNoulMargin: {
225
+ accepted: "a number from 0 through 0.5",
226
+ current: () => advisorJevFilterNoulMarginRef,
227
+ persisted: true,
228
+ type: "number",
229
+ validate: isValidJevNoulMargin,
230
+ },
231
+ advisorJevFilterOverrideWindow: {
232
+ accepted: "a non-negative safe integer",
233
+ current: () => advisorJevFilterOverrideWindowRef,
234
+ persisted: true,
235
+ type: "number",
236
+ validate: nonNegativeSafeInteger,
237
+ },
238
+ advisorJevFilterSkipConfidence: {
239
+ accepted: "a number between 0.5 and 1 inclusive",
240
+ current: () => advisorJevFilterSkipConfidenceRef,
241
+ persisted: true,
242
+ type: "number",
243
+ validate: isValidJevSkipConfidence,
244
+ },
245
+ advisorJevModel: {
246
+ accepted: "a non-empty string",
247
+ current: () => advisorJevModelRef,
248
+ persisted: true,
249
+ type: "string",
250
+ },
251
+ advisorJevPricePerMtok: {
252
+ accepted: "a positive number",
253
+ current: () => advisorJevPricePerMtokRef,
254
+ persisted: true,
255
+ type: "number",
256
+ validate: isValidJevPricePerMtok,
257
+ },
258
+ advisorJevTimeoutMs: {
259
+ accepted: "a positive safe integer",
260
+ current: () => advisorJevTimeoutMsRef,
261
+ persisted: true,
262
+ type: "number",
263
+ validate: isValidJevTimeoutMs,
264
+ },
265
+ advisorJevTransport: {
266
+ accepted: JEV_TRANSPORTS.join(", "),
267
+ current: () => advisorJevTransportRef,
268
+ persisted: true,
269
+ type: "enum",
270
+ validate: isValidJevTransport,
271
+ },
272
+ advisorJevTurnGateEveryTurns: {
273
+ accepted: "a non-negative safe integer (0 disables the turn gate)",
274
+ current: () => advisorJevTurnGateEveryTurnsRef,
275
+ persisted: true,
276
+ type: "number",
277
+ validate: nonNegativeSafeInteger,
278
+ },
279
+ advisorJevTurnGateNoulThreshold: {
280
+ accepted: "a number between 0.5 and 1 inclusive",
281
+ current: () => advisorJevTurnGateNoulThresholdRef,
282
+ persisted: true,
283
+ type: "number",
284
+ validate: isValidJevSkipConfidence,
285
+ },
286
+ advisorLoopThreshold: {
287
+ accepted: "a safe integer of at least 2",
288
+ current: () => advisorLoopThresholdRef,
289
+ persisted: true,
290
+ type: "number",
291
+ validate: isValidLoopThreshold,
292
+ },
293
+ advisorMaxCallsPerSession: {
294
+ accepted: "a non-negative safe integer",
295
+ current: () => advisorMaxCallsPerSessionRef,
296
+ persisted: true,
297
+ type: "number",
298
+ validate: isValidMaxCallsPerSession,
299
+ },
300
+ advisorOutcomeLogging: {
301
+ accepted: "true or false",
302
+ current: () => advisorOutcomeLoggingRef,
303
+ persisted: false,
304
+ type: "boolean",
305
+ },
306
+ advisorPlanGate: {
307
+ accepted: "true or false",
308
+ current: () => advisorPlanGateRef,
309
+ persisted: true,
310
+ type: "boolean",
311
+ },
312
+ advisorRedactSecrets: {
313
+ accepted: "true or false",
314
+ current: () => advisorRedactSecretsRef,
315
+ persisted: true,
316
+ type: "boolean",
317
+ },
318
+ advisorScoutEnabled: {
319
+ accepted: "true or false",
320
+ current: () => advisorScoutEnabledRef,
321
+ persisted: true,
322
+ type: "boolean",
323
+ },
324
+ advisorSessionSummary: {
325
+ accepted: "true or false",
326
+ current: () => advisorSessionSummaryRef,
327
+ persisted: true,
328
+ type: "boolean",
329
+ },
330
+ advisorToolPolicies: {
331
+ accepted:
332
+ "a JSON object with non-empty tool names and full, summary, or exclude values",
333
+ current: () => ({ ...advisorToolPoliciesRef }),
334
+ persisted: true,
335
+ type: "object",
336
+ validate: isValidAdvisorToolPolicies,
337
+ },
338
+ advisorToolResultMaxBytes: {
339
+ accepted: "a non-negative safe integer",
340
+ current: () => advisorToolResultMaxBytesRef,
341
+ persisted: true,
342
+ type: "number",
343
+ validate: isValidToolResultMaxBytes,
344
+ },
345
+ advisorToolResultMaxLines: {
346
+ accepted: "a non-negative safe integer",
347
+ current: () => advisorToolResultMaxLinesRef,
348
+ persisted: true,
349
+ type: "number",
350
+ validate: isValidToolResultMaxLines,
351
+ },
352
+ advisorTrackedFileContent: {
353
+ accepted: "true or false",
354
+ current: () => advisorTrackedFileContentRef,
355
+ persisted: true,
356
+ type: "boolean",
357
+ },
358
+ advisorUntrackedContent: {
359
+ accepted: "true or false",
360
+ current: () => advisorUntrackedContentRef,
361
+ persisted: true,
362
+ type: "boolean",
363
+ },
364
+ alwaysOn: {
365
+ accepted: "true or false",
366
+ current: () => alwaysOnRef,
367
+ persisted: true,
368
+ type: "boolean",
369
+ },
370
+ contextMaxChars: {
371
+ accepted: `a safe integer from 0 through ${MAX_CONTEXT_MAX_CHARS}`,
372
+ current: () => contextMaxCharsRef,
373
+ persisted: true,
374
+ type: "number",
375
+ validate: isValidContextMaxChars,
376
+ },
377
+ executor: {
378
+ accepted: "a provider/model string",
379
+ current: () => configuredModelRef(executorRef),
380
+ persisted: true,
381
+ type: "string",
382
+ },
383
+ executorEffort: {
384
+ accepted: "a string",
385
+ current: () => executorEffortRef,
386
+ persisted: true,
387
+ type: "string",
388
+ },
389
+ gateFailureMode: {
390
+ accepted: GATE_FAILURE_MODES.join(", "),
391
+ current: () => advisorFailureModeRef,
392
+ persisted: true,
393
+ type: "enum",
394
+ validate: isValidGateFailureMode,
395
+ },
396
+ showUsageDetails: {
397
+ accepted: "true or false",
398
+ current: () => showUsageDetailsRef,
399
+ persisted: true,
400
+ type: "boolean",
401
+ },
402
+ showUsageFooter: {
403
+ accepted: "true or false",
404
+ current: () => showUsageFooterRef,
405
+ persisted: true,
406
+ type: "boolean",
407
+ },
408
+ simpleMode: {
409
+ accepted: "true or false",
410
+ current: () => simpleModeRef,
411
+ persisted: true,
412
+ type: "boolean",
413
+ },
414
+ } as const satisfies Record<keyof AdvisorConfig, ConfigKeySchema>;
415
+
416
+ export type ConfigKey = keyof typeof CONFIG_SCHEMA;
417
+
418
+ /** Keys saveConfig captures, diffs, and writes to advisor.json. */
419
+ export type PersistedConfigKey = {
420
+ [Key in ConfigKey]: (typeof CONFIG_SCHEMA)[Key]["persisted"] extends true
421
+ ? Key
422
+ : never;
423
+ }[ConfigKey];
424
+
425
+ export const SAVED_CONFIG_KEYS = (
426
+ Object.keys(CONFIG_SCHEMA) as ConfigKey[]
427
+ ).filter(
428
+ (key) => CONFIG_SCHEMA[key].persisted
429
+ ) as readonly PersistedConfigKey[];
430
+
431
+ /** Widened per-key view for consumers that index by dynamic key. */
432
+ const SCHEMA_BY_KEY: Record<ConfigKey, ConfigKeySchema> = CONFIG_SCHEMA;
433
+
434
+ export { configuredModelRef, SCHEMA_BY_KEY };
@@ -1,12 +1,23 @@
1
- import type { GitContextLevel } from "../git.js";
1
+ import type { GitContextLevel } from "../git.ts";
2
2
  import {
3
3
  type AdvisorToolPolicies,
4
4
  DEFAULT_ADVISOR_GIT_CONTEXT_MAX_CHARS,
5
5
  DEFAULT_ADVISOR_TOOL_RESULT_MAX_BYTES,
6
6
  DEFAULT_ADVISOR_TOOL_RESULT_MAX_LINES,
7
7
  DEFAULT_CONTEXT_MAX_CHARS,
8
+ DEFAULT_JEV_DIGEST_MAX_CHARS,
9
+ DEFAULT_JEV_FILTER_NOUL_MARGIN,
10
+ DEFAULT_JEV_FILTER_OVERRIDE_WINDOW,
11
+ DEFAULT_JEV_FILTER_SKIP_CONFIDENCE,
12
+ DEFAULT_JEV_MODEL,
13
+ DEFAULT_JEV_PRICE_PER_MTOK,
14
+ DEFAULT_JEV_TIMEOUT_MS,
15
+ DEFAULT_JEV_TRANSPORT,
16
+ DEFAULT_JEV_TURN_GATE_EVERY_TURNS,
17
+ DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD,
8
18
  type GateFailureMode,
9
- } from "./types.js";
19
+ type JevTransport,
20
+ } from "./types.ts";
10
21
 
11
22
  // An empty ref means no model has been selected yet.
12
23
  export let executorRef = "";
@@ -30,6 +41,20 @@ export let simpleModeRef = false;
30
41
  export let alwaysOnRef = false;
31
42
  export let advisorFailureModeRef: GateFailureMode = "block-session";
32
43
  export let advisorHerdrIntegrationRef = true;
44
+ export let advisorJevFilterEnabledRef = false;
45
+ export let advisorJevFilterSkipConfidenceRef =
46
+ DEFAULT_JEV_FILTER_SKIP_CONFIDENCE;
47
+ export let advisorJevFilterNoulMarginRef = DEFAULT_JEV_FILTER_NOUL_MARGIN;
48
+ export let advisorJevFilterOverrideWindowRef =
49
+ DEFAULT_JEV_FILTER_OVERRIDE_WINDOW;
50
+ export let advisorJevModelRef = DEFAULT_JEV_MODEL;
51
+ export let advisorJevTimeoutMsRef = DEFAULT_JEV_TIMEOUT_MS;
52
+ export let advisorJevDigestMaxCharsRef = DEFAULT_JEV_DIGEST_MAX_CHARS;
53
+ export let advisorJevPricePerMtokRef = DEFAULT_JEV_PRICE_PER_MTOK;
54
+ export let advisorJevTransportRef: JevTransport = DEFAULT_JEV_TRANSPORT;
55
+ export let advisorJevTurnGateEveryTurnsRef = DEFAULT_JEV_TURN_GATE_EVERY_TURNS;
56
+ export let advisorJevTurnGateNoulThresholdRef =
57
+ DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD;
33
58
  export let advisorToolResultMaxLinesRef = DEFAULT_ADVISOR_TOOL_RESULT_MAX_LINES;
34
59
  export let advisorToolResultMaxBytesRef = DEFAULT_ADVISOR_TOOL_RESULT_MAX_BYTES;
35
60
  export let advisorRedactSecretsRef = false;
@@ -117,6 +142,39 @@ export const setAdvisorFailureModeRef = (value: GateFailureMode) => {
117
142
  export const setAdvisorHerdrIntegrationRef = (enabled: boolean) => {
118
143
  advisorHerdrIntegrationRef = enabled;
119
144
  };
145
+ export const setAdvisorJevFilterEnabledRef = (enabled: boolean) => {
146
+ advisorJevFilterEnabledRef = enabled;
147
+ };
148
+ export const setAdvisorJevFilterSkipConfidenceRef = (value: number) => {
149
+ advisorJevFilterSkipConfidenceRef = value;
150
+ };
151
+ export const setAdvisorJevFilterNoulMarginRef = (value: number) => {
152
+ advisorJevFilterNoulMarginRef = value;
153
+ };
154
+ export const setAdvisorJevFilterOverrideWindowRef = (value: number) => {
155
+ advisorJevFilterOverrideWindowRef = value;
156
+ };
157
+ export const setAdvisorJevModelRef = (model: string | undefined) => {
158
+ advisorJevModelRef = model?.trim() || DEFAULT_JEV_MODEL;
159
+ };
160
+ export const setAdvisorJevTimeoutMsRef = (value: number) => {
161
+ advisorJevTimeoutMsRef = value;
162
+ };
163
+ export const setAdvisorJevDigestMaxCharsRef = (value: number) => {
164
+ advisorJevDigestMaxCharsRef = value;
165
+ };
166
+ export const setAdvisorJevPricePerMtokRef = (value: number) => {
167
+ advisorJevPricePerMtokRef = value;
168
+ };
169
+ export const setAdvisorJevTransportRef = (value: JevTransport) => {
170
+ advisorJevTransportRef = value;
171
+ };
172
+ export const setAdvisorJevTurnGateEveryTurnsRef = (value: number) => {
173
+ advisorJevTurnGateEveryTurnsRef = value;
174
+ };
175
+ export const setAdvisorJevTurnGateNoulThresholdRef = (value: number) => {
176
+ advisorJevTurnGateNoulThresholdRef = value;
177
+ };
120
178
  export const setAdvisorToolResultMaxLinesRef = (value: number) => {
121
179
  advisorToolResultMaxLinesRef = value;
122
180
  };
@@ -172,6 +230,17 @@ export const getAdvisorSettings = () => ({
172
230
  gitContext: advisorGitContextRef,
173
231
  gitContextMaxChars: advisorGitContextMaxCharsRef,
174
232
  herdrIntegration: advisorHerdrIntegrationRef,
233
+ jevDigestMaxChars: advisorJevDigestMaxCharsRef,
234
+ jevFilterEnabled: advisorJevFilterEnabledRef,
235
+ jevFilterNoulMargin: advisorJevFilterNoulMarginRef,
236
+ jevFilterOverrideWindow: advisorJevFilterOverrideWindowRef,
237
+ jevFilterSkipConfidence: advisorJevFilterSkipConfidenceRef,
238
+ jevModel: advisorJevModelRef,
239
+ jevPricePerMtok: advisorJevPricePerMtokRef,
240
+ jevTimeoutMs: advisorJevTimeoutMsRef,
241
+ jevTransport: advisorJevTransportRef,
242
+ jevTurnGateEveryTurns: advisorJevTurnGateEveryTurnsRef,
243
+ jevTurnGateNoulThreshold: advisorJevTurnGateNoulThresholdRef,
175
244
  loopThreshold: advisorLoopThresholdRef,
176
245
  maxCallsPerSession: advisorMaxCallsPerSessionRef,
177
246
  outcomeLogging: advisorOutcomeLoggingRef,