pi-advisor-flow 0.6.0 → 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.
- package/CHANGELOG.md +16 -0
- package/README.md +1 -0
- package/dist/index.js +1816 -154
- package/package.json +11 -9
- package/src/commands/manual-consultation.ts +16 -2
- package/src/commands/settings-persistence.ts +48 -0
- package/src/commands/types.ts +1 -0
- package/src/config/defaults.ts +75 -0
- package/src/config/schema.ts +112 -0
- package/src/config/state.ts +69 -0
- package/src/config/storage.ts +7 -2
- package/src/config/types.ts +29 -0
- package/src/jev/client.ts +348 -0
- package/src/jev/key-store.ts +252 -0
- package/src/jev/ledger.ts +234 -0
- package/src/jev/questions.ts +119 -0
- package/src/jev/state.ts +47 -0
- package/src/jev/transport.ts +58 -0
- package/src/outcomes.ts +5 -1
- package/src/session-state.ts +99 -5
- package/src/tools/jev-filter.ts +202 -0
- package/src/tools/jev-turn-gate.ts +183 -0
- package/src/tools/loop-gate.ts +1 -0
- package/src/tools/outage-notifier.ts +30 -0
- package/src/tools/register-ask-advisor.ts +37 -1
- package/src/tools/register-renderers.ts +58 -0
- package/src/tools/registration.ts +17 -0
- package/src/tools/render-advisor-result.ts +43 -14
- package/src/tools/types.ts +10 -0
- package/src/ui/jev-setup-submenu.ts +344 -0
- package/src/ui/masked-input.ts +68 -0
- package/src/ui/settings-items.ts +162 -1
- package/src/ui/settings-mutations.ts +35 -0
- package/src/ui/types.ts +11 -0
- package/src/usage.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-advisor-flow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Advanced Executor/Advisor flow for Pi, fully configurable and extendable.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"pi-coding-agent",
|
|
9
9
|
"advisor",
|
|
10
10
|
"pi-advisor",
|
|
11
|
-
"herdr"
|
|
11
|
+
"herdr",
|
|
12
|
+
"jev"
|
|
12
13
|
],
|
|
13
14
|
"homepage": "https://github.com/philipbrembeck/pi-advisor",
|
|
14
15
|
"repository": {
|
|
@@ -62,18 +63,19 @@
|
|
|
62
63
|
"undici": "8.9.0"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"@biomejs/biome": "2.5.
|
|
66
|
+
"@biomejs/biome": "2.5.13",
|
|
66
67
|
"@earendil-works/pi-ai": "^0.85.1",
|
|
67
68
|
"@earendil-works/pi-coding-agent": "^0.85.1",
|
|
68
69
|
"@earendil-works/pi-tui": "^0.85.1",
|
|
69
|
-
"@types/node": "^26.
|
|
70
|
-
"
|
|
70
|
+
"@types/node": "^26.6.2",
|
|
71
|
+
"@typesafe-ai/sdk": "^0.6.0",
|
|
72
|
+
"bun-types": "1.4.2",
|
|
71
73
|
"husky": "^9.1.7",
|
|
72
|
-
"knip": "^6.
|
|
73
|
-
"lint-staged": "^17.
|
|
74
|
-
"typebox": "^1.3.
|
|
74
|
+
"knip": "^6.37.0",
|
|
75
|
+
"lint-staged": "^17.5.1",
|
|
76
|
+
"typebox": "^1.3.34",
|
|
75
77
|
"typescript": "^7.0.2",
|
|
76
|
-
"ultracite": "7.
|
|
78
|
+
"ultracite": "7.12.0"
|
|
77
79
|
},
|
|
78
80
|
"peerDependencies": {
|
|
79
81
|
"@earendil-works/pi-ai": "^0.84.1 || ^0.85.1",
|
|
@@ -2,6 +2,7 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
import { advisorRef } from "../config/state.ts";
|
|
3
3
|
import type { GitContextLevel } from "../git.ts";
|
|
4
4
|
import { herdrAdvisorActivity, notifyHerdrAdvisorFailure } from "../herdr.ts";
|
|
5
|
+
import { normalizeScreeningQuestion } from "../tools/jev-filter.ts";
|
|
5
6
|
import { appendScoutLifecycleEntry } from "../tools/scout-status.ts";
|
|
6
7
|
import type { ScoutToolDetails } from "../tools/types.ts";
|
|
7
8
|
import { advisorUsageCost, snapshotAdvisorUsage } from "../usage.ts";
|
|
@@ -63,11 +64,12 @@ export const startManualConsultation = (
|
|
|
63
64
|
},
|
|
64
65
|
gitContext
|
|
65
66
|
)
|
|
66
|
-
.then(({ markdown, usage }) => {
|
|
67
|
+
.then(({ adviceId, markdown, usage }) => {
|
|
67
68
|
if (controller.signal.aborted) {
|
|
68
69
|
return;
|
|
69
70
|
}
|
|
70
71
|
progress.phase = "complete";
|
|
72
|
+
runtime.advisorSessionState.resetTurnsSinceConsultation();
|
|
71
73
|
runtime.advisorSessionState.recordInvocation({
|
|
72
74
|
cost: advisorUsageCost(usage),
|
|
73
75
|
executionEffect: "continued",
|
|
@@ -76,11 +78,22 @@ export const startManualConsultation = (
|
|
|
76
78
|
trigger: "manual",
|
|
77
79
|
usage,
|
|
78
80
|
});
|
|
81
|
+
if (typeof adviceId === "string") {
|
|
82
|
+
// Registering the manual question lets an identical later ask_advisor
|
|
83
|
+
// hit repeat detection instead of re-consulting.
|
|
84
|
+
runtime.advisorSessionState.issueAdvice(
|
|
85
|
+
adviceId,
|
|
86
|
+
markdown,
|
|
87
|
+
"manual",
|
|
88
|
+
false,
|
|
89
|
+
normalizeScreeningQuestion(question)
|
|
90
|
+
);
|
|
91
|
+
}
|
|
79
92
|
runtime.updateAdvisorUsageStatus(ctx);
|
|
80
93
|
const normalizedUsage = snapshotAdvisorUsage(usage);
|
|
81
94
|
runtime.pi.sendMessage(
|
|
82
95
|
{
|
|
83
|
-
content: `Manual Advisor consultation${question ? ` (${question})` : ""}:\n\n${markdown}`,
|
|
96
|
+
content: `Manual Advisor consultation${question ? ` (${question})` : ""} — for your awareness; no action or follow-up consultation is needed unless the user asks:\n\n${markdown}`,
|
|
84
97
|
customType: "advisor-manual-result",
|
|
85
98
|
details: {
|
|
86
99
|
advisor: advisorRef,
|
|
@@ -104,6 +117,7 @@ export const startManualConsultation = (
|
|
|
104
117
|
}
|
|
105
118
|
progress.phase = "error";
|
|
106
119
|
const message = error instanceof Error ? error.message : String(error);
|
|
120
|
+
runtime.advisorSessionState.resetTurnsSinceConsultation();
|
|
107
121
|
runtime.advisorSessionState.recordInvocation({
|
|
108
122
|
executionEffect: "continued",
|
|
109
123
|
failure: "provider-error",
|
|
@@ -12,6 +12,17 @@ import {
|
|
|
12
12
|
setAdvisorGitContextMaxCharsRef,
|
|
13
13
|
setAdvisorGitContextRef,
|
|
14
14
|
setAdvisorHerdrIntegrationRef,
|
|
15
|
+
setAdvisorJevDigestMaxCharsRef,
|
|
16
|
+
setAdvisorJevFilterEnabledRef,
|
|
17
|
+
setAdvisorJevFilterNoulMarginRef,
|
|
18
|
+
setAdvisorJevFilterOverrideWindowRef,
|
|
19
|
+
setAdvisorJevFilterSkipConfidenceRef,
|
|
20
|
+
setAdvisorJevModelRef,
|
|
21
|
+
setAdvisorJevPricePerMtokRef,
|
|
22
|
+
setAdvisorJevTimeoutMsRef,
|
|
23
|
+
setAdvisorJevTransportRef,
|
|
24
|
+
setAdvisorJevTurnGateEveryTurnsRef,
|
|
25
|
+
setAdvisorJevTurnGateNoulThresholdRef,
|
|
15
26
|
setAdvisorLoopThresholdRef,
|
|
16
27
|
setAdvisorMaxCallsPerSessionRef,
|
|
17
28
|
setAdvisorOutcomeLoggingRef,
|
|
@@ -31,6 +42,18 @@ import {
|
|
|
31
42
|
setSimpleModeRef,
|
|
32
43
|
} from "../config/state.ts";
|
|
33
44
|
import { saveConfig, saveGlobalOutcomeLogging } from "../config/storage.ts";
|
|
45
|
+
import {
|
|
46
|
+
DEFAULT_JEV_DIGEST_MAX_CHARS,
|
|
47
|
+
DEFAULT_JEV_FILTER_NOUL_MARGIN,
|
|
48
|
+
DEFAULT_JEV_FILTER_OVERRIDE_WINDOW,
|
|
49
|
+
DEFAULT_JEV_FILTER_SKIP_CONFIDENCE,
|
|
50
|
+
DEFAULT_JEV_MODEL,
|
|
51
|
+
DEFAULT_JEV_PRICE_PER_MTOK,
|
|
52
|
+
DEFAULT_JEV_TIMEOUT_MS,
|
|
53
|
+
DEFAULT_JEV_TRANSPORT,
|
|
54
|
+
DEFAULT_JEV_TURN_GATE_EVERY_TURNS,
|
|
55
|
+
DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD,
|
|
56
|
+
} from "../config/types.ts";
|
|
34
57
|
import type { AdvisorSettings } from "../ui/types.ts";
|
|
35
58
|
|
|
36
59
|
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: one settings form maps every persisted control.
|
|
@@ -56,6 +79,31 @@ const applyAdvisorSettings = (settings: AdvisorSettings) => {
|
|
|
56
79
|
setAlwaysOnRef(settings.alwaysOn ?? false);
|
|
57
80
|
setAdvisorFailureModeRef(settings.failureMode ?? "block-session");
|
|
58
81
|
setAdvisorHerdrIntegrationRef(settings.herdrIntegration ?? true);
|
|
82
|
+
setAdvisorJevFilterEnabledRef(settings.jevFilterEnabled ?? false);
|
|
83
|
+
setAdvisorJevFilterSkipConfidenceRef(
|
|
84
|
+
settings.jevFilterSkipConfidence ?? DEFAULT_JEV_FILTER_SKIP_CONFIDENCE
|
|
85
|
+
);
|
|
86
|
+
setAdvisorJevFilterNoulMarginRef(
|
|
87
|
+
settings.jevFilterNoulMargin ?? DEFAULT_JEV_FILTER_NOUL_MARGIN
|
|
88
|
+
);
|
|
89
|
+
setAdvisorJevFilterOverrideWindowRef(
|
|
90
|
+
settings.jevFilterOverrideWindow ?? DEFAULT_JEV_FILTER_OVERRIDE_WINDOW
|
|
91
|
+
);
|
|
92
|
+
setAdvisorJevModelRef(settings.jevModel ?? DEFAULT_JEV_MODEL);
|
|
93
|
+
setAdvisorJevTimeoutMsRef(settings.jevTimeoutMs ?? DEFAULT_JEV_TIMEOUT_MS);
|
|
94
|
+
setAdvisorJevDigestMaxCharsRef(
|
|
95
|
+
settings.jevDigestMaxChars ?? DEFAULT_JEV_DIGEST_MAX_CHARS
|
|
96
|
+
);
|
|
97
|
+
setAdvisorJevPricePerMtokRef(
|
|
98
|
+
settings.jevPricePerMtok ?? DEFAULT_JEV_PRICE_PER_MTOK
|
|
99
|
+
);
|
|
100
|
+
setAdvisorJevTransportRef(settings.jevTransport ?? DEFAULT_JEV_TRANSPORT);
|
|
101
|
+
setAdvisorJevTurnGateEveryTurnsRef(
|
|
102
|
+
settings.jevTurnGateEveryTurns ?? DEFAULT_JEV_TURN_GATE_EVERY_TURNS
|
|
103
|
+
);
|
|
104
|
+
setAdvisorJevTurnGateNoulThresholdRef(
|
|
105
|
+
settings.jevTurnGateNoulThreshold ?? DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD
|
|
106
|
+
);
|
|
59
107
|
setAdvisorToolResultMaxLinesRef(settings.toolResultMaxLines ?? 2000);
|
|
60
108
|
setAdvisorToolResultMaxBytesRef(settings.toolResultMaxBytes ?? 50 * 1024);
|
|
61
109
|
setAdvisorRedactSecretsRef(settings.redactSecrets ?? false);
|
package/src/commands/types.ts
CHANGED
package/src/config/defaults.ts
CHANGED
|
@@ -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,
|
|
@@ -38,6 +49,16 @@ import {
|
|
|
38
49
|
DEFAULT_ADVISOR_TOOL_RESULT_MAX_BYTES,
|
|
39
50
|
DEFAULT_ADVISOR_TOOL_RESULT_MAX_LINES,
|
|
40
51
|
DEFAULT_CONTEXT_MAX_CHARS,
|
|
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,
|
|
41
62
|
} from "./types.ts";
|
|
42
63
|
|
|
43
64
|
export const resetDefaults = () => {
|
|
@@ -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",
|
package/src/config/schema.ts
CHANGED
|
@@ -11,6 +11,17 @@ import {
|
|
|
11
11
|
advisorGitContextMaxCharsRef,
|
|
12
12
|
advisorGitContextRef,
|
|
13
13
|
advisorHerdrIntegrationRef,
|
|
14
|
+
advisorJevDigestMaxCharsRef,
|
|
15
|
+
advisorJevFilterEnabledRef,
|
|
16
|
+
advisorJevFilterNoulMarginRef,
|
|
17
|
+
advisorJevFilterOverrideWindowRef,
|
|
18
|
+
advisorJevFilterSkipConfidenceRef,
|
|
19
|
+
advisorJevModelRef,
|
|
20
|
+
advisorJevPricePerMtokRef,
|
|
21
|
+
advisorJevTimeoutMsRef,
|
|
22
|
+
advisorJevTransportRef,
|
|
23
|
+
advisorJevTurnGateEveryTurnsRef,
|
|
24
|
+
advisorJevTurnGateNoulThresholdRef,
|
|
14
25
|
advisorLoopThresholdRef,
|
|
15
26
|
advisorMaxCallsPerSessionRef,
|
|
16
27
|
advisorOutcomeLoggingRef,
|
|
@@ -36,6 +47,8 @@ import {
|
|
|
36
47
|
ADVISOR_TOOL_POLICIES,
|
|
37
48
|
type AdvisorConfig,
|
|
38
49
|
GATE_FAILURE_MODES,
|
|
50
|
+
JEV_TRANSPORTS,
|
|
51
|
+
type JevTransport,
|
|
39
52
|
MAX_CONTEXT_MAX_CHARS,
|
|
40
53
|
} from "./types.ts";
|
|
41
54
|
|
|
@@ -86,6 +99,30 @@ export const isValidToolResultMaxLines = (value: unknown): value is number =>
|
|
|
86
99
|
export const isValidToolResultMaxBytes = (value: unknown): value is number =>
|
|
87
100
|
nonNegativeSafeInteger(value);
|
|
88
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
|
+
|
|
89
126
|
/** One declarative entry per AdvisorConfig key: JSON type, persistence, and
|
|
90
127
|
* the live runtime value behind it. Validation and storage derive from this
|
|
91
128
|
* table; adding a setting means adding exactly one entry here. */
|
|
@@ -171,6 +208,81 @@ export const CONFIG_SCHEMA = {
|
|
|
171
208
|
persisted: true,
|
|
172
209
|
type: "boolean",
|
|
173
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
|
+
},
|
|
174
286
|
advisorLoopThreshold: {
|
|
175
287
|
accepted: "a safe integer of at least 2",
|
|
176
288
|
current: () => advisorLoopThresholdRef,
|
package/src/config/state.ts
CHANGED
|
@@ -5,7 +5,18 @@ import {
|
|
|
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,
|
|
19
|
+
type JevTransport,
|
|
9
20
|
} from "./types.ts";
|
|
10
21
|
|
|
11
22
|
// An empty ref means no model has been selected yet.
|
|
@@ -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,
|
package/src/config/storage.ts
CHANGED
|
@@ -36,7 +36,12 @@ const currentConfigState = (): ConfigState =>
|
|
|
36
36
|
const sameConfigValue = <Value>(left: Value, right: Value) =>
|
|
37
37
|
JSON.stringify(left) === JSON.stringify(right);
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
/** Keys advisor.json may hold that are not AdvisorConfig settings but are
|
|
40
|
+
* still legitimate (hand-placed secrets). They stay out of CONFIG_SCHEMA, are
|
|
41
|
+
* preserved like any unknown key, and never trigger the typo warning. */
|
|
42
|
+
const RESERVED_ADVISOR_JSON_KEYS = new Set(["typesafe_api_key"]);
|
|
43
|
+
|
|
44
|
+
export const readExistingConfig = (path: string): Record<string, unknown> => {
|
|
40
45
|
try {
|
|
41
46
|
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
42
47
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
@@ -139,7 +144,7 @@ export const loadConfig = (_ctx: ExtensionContext) => {
|
|
|
139
144
|
applyConfig(globalConfig);
|
|
140
145
|
const unknownKeys = unknownConfigKeys(
|
|
141
146
|
globalConfig as Record<string, unknown>
|
|
142
|
-
);
|
|
147
|
+
).filter((key) => !RESERVED_ADVISOR_JSON_KEYS.has(key));
|
|
143
148
|
const warningIdentity = `${global}:${configIdentity(global)}`;
|
|
144
149
|
if (
|
|
145
150
|
unknownKeys.length > 0 &&
|
package/src/config/types.ts
CHANGED
|
@@ -9,6 +9,24 @@ export const MAX_CONTEXT_MAX_CHARS = Number.MAX_SAFE_INTEGER;
|
|
|
9
9
|
export const DEFAULT_ADVISOR_TOOL_RESULT_MAX_LINES = DEFAULT_MAX_LINES;
|
|
10
10
|
export const DEFAULT_ADVISOR_TOOL_RESULT_MAX_BYTES = DEFAULT_MAX_BYTES;
|
|
11
11
|
export const DEFAULT_ADVISOR_GIT_CONTEXT_MAX_CHARS = 20_000;
|
|
12
|
+
export const DEFAULT_JEV_MODEL = "jev-latest";
|
|
13
|
+
// Provisional: the latency benchmark was dropped from scope; revisit if live
|
|
14
|
+
// measurements suggest a different bound.
|
|
15
|
+
export const DEFAULT_JEV_TIMEOUT_MS = 8000;
|
|
16
|
+
export const DEFAULT_JEV_DIGEST_MAX_CHARS = 4000;
|
|
17
|
+
export const DEFAULT_JEV_PRICE_PER_MTOK = 0.042;
|
|
18
|
+
export const DEFAULT_JEV_FILTER_SKIP_CONFIDENCE = 0.85;
|
|
19
|
+
export const DEFAULT_JEV_FILTER_NOUL_MARGIN = 0.35;
|
|
20
|
+
export const DEFAULT_JEV_FILTER_OVERRIDE_WINDOW = 10;
|
|
21
|
+
export const DEFAULT_JEV_TURN_GATE_EVERY_TURNS = 0;
|
|
22
|
+
export const DEFAULT_JEV_TURN_GATE_NOUL_THRESHOLD = 0.8;
|
|
23
|
+
export type JevTransport = "auto" | "typesafe" | "openrouter";
|
|
24
|
+
export const DEFAULT_JEV_TRANSPORT: JevTransport = "auto";
|
|
25
|
+
export const JEV_TRANSPORTS: JevTransport[] = [
|
|
26
|
+
"auto",
|
|
27
|
+
"typesafe",
|
|
28
|
+
"openrouter",
|
|
29
|
+
];
|
|
12
30
|
|
|
13
31
|
export type AdvisorToolPolicy = "full" | "summary" | "exclude";
|
|
14
32
|
export type AdvisorToolPolicies = Record<string, AdvisorToolPolicy>;
|
|
@@ -40,6 +58,17 @@ export interface AdvisorConfig {
|
|
|
40
58
|
advisorGitContext?: GitContextLevel;
|
|
41
59
|
advisorGitContextMaxChars?: number;
|
|
42
60
|
advisorHerdrIntegration?: boolean;
|
|
61
|
+
advisorJevDigestMaxChars?: number;
|
|
62
|
+
advisorJevFilterEnabled?: boolean;
|
|
63
|
+
advisorJevFilterNoulMargin?: number;
|
|
64
|
+
advisorJevFilterOverrideWindow?: number;
|
|
65
|
+
advisorJevFilterSkipConfidence?: number;
|
|
66
|
+
advisorJevModel?: string;
|
|
67
|
+
advisorJevPricePerMtok?: number;
|
|
68
|
+
advisorJevTimeoutMs?: number;
|
|
69
|
+
advisorJevTransport?: JevTransport;
|
|
70
|
+
advisorJevTurnGateEveryTurns?: number;
|
|
71
|
+
advisorJevTurnGateNoulThreshold?: number;
|
|
43
72
|
advisorLoopThreshold?: number;
|
|
44
73
|
advisorMaxCallsPerSession?: number;
|
|
45
74
|
advisorOutcomeLogging?: boolean;
|