pi-advisor-flow 0.9.2-dev.4 → 0.10.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 +11 -0
- package/README.md +16 -7
- package/dist/index.js +938 -287
- package/package.json +2 -2
- package/src/commands/activation-preparation.ts +4 -0
- package/src/commands/manual-consultation.ts +20 -3
- package/src/commands/model-commands.ts +5 -1
- package/src/commands/model-picker.ts +44 -2
- package/src/commands/outcome-stats.ts +98 -0
- package/src/commands/registration.ts +2 -0
- package/src/commands/renderers.ts +51 -0
- package/src/commands/runtime.ts +9 -1
- package/src/commands/settings-persistence.ts +4 -0
- package/src/commands/types.ts +5 -2
- package/src/config/defaults.ts +13 -0
- package/src/config/schema.ts +14 -0
- package/src/config/state.ts +10 -0
- package/src/config/types.ts +2 -0
- package/src/config.ts +4 -0
- package/src/follow-up.ts +85 -0
- package/src/outcome-stats.ts +154 -0
- package/src/outcomes.ts +8 -1
- package/src/preferences.ts +90 -12
- package/src/session-state.ts +33 -0
- package/src/tools/consult-context.ts +12 -1
- package/src/tools/consultation.ts +344 -47
- package/src/tools/jev-turn-gate.ts +2 -0
- package/src/tools/loop-gate.ts +2 -0
- package/src/tools/model-access.ts +7 -3
- package/src/tools/prompts.ts +28 -2
- package/src/tools/register-ask-advisor.ts +110 -23
- package/src/tools/register-lifecycle.ts +11 -0
- package/src/tools/register-renderers.ts +40 -6
- package/src/tools/render-advisor-result.ts +6 -0
- package/src/tools/render-common.ts +6 -2
- package/src/tools/types.ts +5 -0
- package/src/ui/settings-items.ts +43 -0
- package/src/ui/settings-mutations.ts +9 -0
- package/src/ui/settings-selector.ts +9 -0
- package/src/ui/types.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-advisor-flow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Advanced Executor/Advisor flow for Pi, fully configurable and extendable.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"advisor",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@earendil-works/pi-coding-agent": "1.0.0",
|
|
56
56
|
"@earendil-works/pi-tui": "1.0.0",
|
|
57
57
|
"@oxlint/plugins": "1.86.0",
|
|
58
|
-
"@types/node": "^26.6.
|
|
58
|
+
"@types/node": "^26.6.4",
|
|
59
59
|
"@typesafe-ai/sdk": "^0.6.0",
|
|
60
60
|
"bun-types": "1.4.2",
|
|
61
61
|
"husky": "^9.1.7",
|
|
@@ -2,11 +2,13 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
advisorEffortRef,
|
|
5
|
+
advisorFallbackModelRef,
|
|
5
6
|
advisorRef,
|
|
6
7
|
executorEffortRef,
|
|
7
8
|
executorRef,
|
|
8
9
|
getPersistedModelRefs,
|
|
9
10
|
setAdvisorEffortRef,
|
|
11
|
+
setAdvisorFallbackModelRef,
|
|
10
12
|
setAdvisorRef,
|
|
11
13
|
setExecutorEffortRef,
|
|
12
14
|
setExecutorRef,
|
|
@@ -99,6 +101,7 @@ export const prepareActivationModels = async (
|
|
|
99
101
|
const selection = await selectAdvisorModels(ctx, {
|
|
100
102
|
advisor: advisorOverride || persisted.advisor ? advisorRef : "",
|
|
101
103
|
advisorEffort: advisorEffortRef,
|
|
104
|
+
advisorFallbackModel: advisorFallbackModelRef,
|
|
102
105
|
executor:
|
|
103
106
|
executorOverride || plan.pendingExecutor || persisted.executor
|
|
104
107
|
? executorRef
|
|
@@ -111,6 +114,7 @@ export const prepareActivationModels = async (
|
|
|
111
114
|
return;
|
|
112
115
|
}
|
|
113
116
|
setAdvisorRef(selection.advisor);
|
|
117
|
+
setAdvisorFallbackModelRef(selection.advisorFallbackModel);
|
|
114
118
|
setAdvisorEffortRef(selection.advisorEffort);
|
|
115
119
|
setExecutorRef(selection.executor);
|
|
116
120
|
setExecutorEffortRef(selection.executorEffort);
|
|
@@ -14,7 +14,11 @@ import { notify } from "./runtime.ts";
|
|
|
14
14
|
import type { CommandRuntime, ManualAdvisorProgressState } from "./types.ts";
|
|
15
15
|
|
|
16
16
|
interface ManualResultDetails {
|
|
17
|
+
adviceId?: string;
|
|
17
18
|
advisor: string;
|
|
19
|
+
agentRulesBytes?: number;
|
|
20
|
+
followUp?: boolean;
|
|
21
|
+
preferenceBytes?: number;
|
|
18
22
|
question?: string;
|
|
19
23
|
text: string;
|
|
20
24
|
usage?: AdvisorUsageSnapshot;
|
|
@@ -48,7 +52,15 @@ export const startManualConsultation = async (
|
|
|
48
52
|
const finishHerdrActivity = runtime.herdrActivity.start();
|
|
49
53
|
let scoutDetails: ScoutToolDetails | undefined;
|
|
50
54
|
try {
|
|
51
|
-
const {
|
|
55
|
+
const {
|
|
56
|
+
adviceId,
|
|
57
|
+
agentRulesBytes,
|
|
58
|
+
followUp,
|
|
59
|
+
markdown,
|
|
60
|
+
model,
|
|
61
|
+
preferenceBytes,
|
|
62
|
+
usage,
|
|
63
|
+
} = await runtime.requestAdvisor(
|
|
52
64
|
ctx,
|
|
53
65
|
question,
|
|
54
66
|
controller.signal,
|
|
@@ -84,8 +96,9 @@ export const startManualConsultation = async (
|
|
|
84
96
|
runtime.advisorSessionState.recordInvocation({
|
|
85
97
|
cost: advisorUsageCost(usage),
|
|
86
98
|
executionEffect: "continued",
|
|
99
|
+
followUp,
|
|
87
100
|
kind: "markdown",
|
|
88
|
-
model: advisorRef,
|
|
101
|
+
model: model ?? advisorRef,
|
|
89
102
|
trigger: "manual",
|
|
90
103
|
usage,
|
|
91
104
|
});
|
|
@@ -102,7 +115,11 @@ export const startManualConsultation = async (
|
|
|
102
115
|
}
|
|
103
116
|
runtime.updateAdvisorUsageStatus(ctx);
|
|
104
117
|
const details: ManualResultDetails = {
|
|
105
|
-
|
|
118
|
+
adviceId,
|
|
119
|
+
advisor: model ?? advisorRef,
|
|
120
|
+
agentRulesBytes,
|
|
121
|
+
followUp,
|
|
122
|
+
preferenceBytes,
|
|
106
123
|
question,
|
|
107
124
|
text: markdown,
|
|
108
125
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
advisorEffortRef,
|
|
3
|
+
advisorFallbackModelRef,
|
|
3
4
|
advisorRef,
|
|
4
5
|
executorEffortRef,
|
|
5
6
|
executorRef,
|
|
6
7
|
getPersistedModelRefs,
|
|
7
8
|
setAdvisorEffortRef,
|
|
9
|
+
setAdvisorFallbackModelRef,
|
|
8
10
|
setAdvisorRef,
|
|
9
11
|
setExecutorEffortRef,
|
|
10
12
|
setExecutorRef,
|
|
@@ -24,7 +26,7 @@ export const registerModelCommands = (runtime: CommandRuntime) => {
|
|
|
24
26
|
|
|
25
27
|
runtime.pi.registerCommand("advisor-models", {
|
|
26
28
|
description:
|
|
27
|
-
"Select and persist the Executor and
|
|
29
|
+
"Select and persist the Executor, Advisor, and optional fallback models with reasoning levels",
|
|
28
30
|
handler: async (_args, ctx) => {
|
|
29
31
|
if (!(loadCommandConfig(ctx) && ctx.hasUI)) {
|
|
30
32
|
return;
|
|
@@ -36,6 +38,7 @@ export const registerModelCommands = (runtime: CommandRuntime) => {
|
|
|
36
38
|
const selection = await selectAdvisorModels(ctx, {
|
|
37
39
|
advisor: persisted.advisor ? advisorRef : "",
|
|
38
40
|
advisorEffort: advisorEffortRef,
|
|
41
|
+
advisorFallbackModel: advisorFallbackModelRef,
|
|
39
42
|
executor:
|
|
40
43
|
runtime.pendingExecutorModelRef ??
|
|
41
44
|
(persisted.executor ? executorRef : ""),
|
|
@@ -49,6 +52,7 @@ export const registerModelCommands = (runtime: CommandRuntime) => {
|
|
|
49
52
|
|
|
50
53
|
setExecutorRef(selection.executor);
|
|
51
54
|
setAdvisorRef(selection.advisor);
|
|
55
|
+
setAdvisorFallbackModelRef(selection.advisorFallbackModel);
|
|
52
56
|
setExecutorEffortRef(selection.executorEffort);
|
|
53
57
|
setAdvisorEffortRef(selection.advisorEffort);
|
|
54
58
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
|
|
3
3
|
import { SearchableModelSelector } from "../ui/model-selector.ts";
|
|
4
|
+
import { FALLBACK_ADVISOR_MODEL_DISABLED } from "../ui/types.ts";
|
|
4
5
|
import {
|
|
5
6
|
effortChoices,
|
|
6
7
|
getAvailableModelRefs,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
export interface AdvisorModelSelection {
|
|
11
12
|
advisor: string;
|
|
12
13
|
advisorEffort: string | undefined;
|
|
14
|
+
advisorFallbackModel: string | undefined;
|
|
13
15
|
executor: string;
|
|
14
16
|
executorEffort: string | undefined;
|
|
15
17
|
}
|
|
@@ -17,6 +19,7 @@ export interface AdvisorModelSelection {
|
|
|
17
19
|
export interface AdvisorModelPickerOptions {
|
|
18
20
|
advisor: string | undefined;
|
|
19
21
|
advisorEffort: string | undefined;
|
|
22
|
+
advisorFallbackModel: string | undefined;
|
|
20
23
|
executor: string | undefined;
|
|
21
24
|
executorEffort: string | undefined;
|
|
22
25
|
selectAdvisor: boolean;
|
|
@@ -46,7 +49,13 @@ export const selectAdvisorModels = async (
|
|
|
46
49
|
)
|
|
47
50
|
),
|
|
48
51
|
];
|
|
49
|
-
let {
|
|
52
|
+
let {
|
|
53
|
+
advisor,
|
|
54
|
+
advisorEffort,
|
|
55
|
+
advisorFallbackModel,
|
|
56
|
+
executor,
|
|
57
|
+
executorEffort,
|
|
58
|
+
} = options;
|
|
50
59
|
|
|
51
60
|
if (options.selectExecutor) {
|
|
52
61
|
const selectedExecutor = await ctx.ui.custom<string | undefined>(
|
|
@@ -104,8 +113,41 @@ export const selectAdvisorModels = async (
|
|
|
104
113
|
advisorEffort = selectedEffort(selectedAdvisorEffort);
|
|
105
114
|
}
|
|
106
115
|
|
|
116
|
+
const selectedFallback = await ctx.ui.custom<string | undefined>(
|
|
117
|
+
(tui, theme, keybindings, done) =>
|
|
118
|
+
new SearchableModelSelector({
|
|
119
|
+
allOptions: [
|
|
120
|
+
FALLBACK_ADVISOR_MODEL_DISABLED,
|
|
121
|
+
...new Set([
|
|
122
|
+
...allOptions,
|
|
123
|
+
...(refs || !advisorFallbackModel ? [] : [advisorFallbackModel]),
|
|
124
|
+
]),
|
|
125
|
+
],
|
|
126
|
+
currentOption: advisorFallbackModel ?? FALLBACK_ADVISOR_MODEL_DISABLED,
|
|
127
|
+
keybindings,
|
|
128
|
+
onCancel: () => done(undefined),
|
|
129
|
+
onSelect: done,
|
|
130
|
+
theme,
|
|
131
|
+
title: "Select Fallback Advisor Model (optional)",
|
|
132
|
+
tui,
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
if (selectedFallback === undefined) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
advisorFallbackModel =
|
|
139
|
+
selectedFallback === FALLBACK_ADVISOR_MODEL_DISABLED
|
|
140
|
+
? undefined
|
|
141
|
+
: selectedFallback;
|
|
142
|
+
|
|
107
143
|
if (!(advisor && executor)) {
|
|
108
144
|
return undefined;
|
|
109
145
|
}
|
|
110
|
-
return {
|
|
146
|
+
return {
|
|
147
|
+
advisor,
|
|
148
|
+
advisorEffort,
|
|
149
|
+
advisorFallbackModel,
|
|
150
|
+
executor,
|
|
151
|
+
executorEffort,
|
|
152
|
+
};
|
|
111
153
|
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { aggregateOutcomeRecords, readOutcomeLog } from "../outcome-stats.ts";
|
|
2
|
+
import type { OutcomeStats } from "../outcome-stats.ts";
|
|
3
|
+
import { OUTCOME_LOG_MAX_BYTES } from "../outcomes.ts";
|
|
4
|
+
import type { CommandRuntime } from "./types.ts";
|
|
5
|
+
|
|
6
|
+
export interface AdvisorStatsDetails {
|
|
7
|
+
error?: string;
|
|
8
|
+
malformedLines: number;
|
|
9
|
+
stats?: OutcomeStats;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const percent = (rate: number | undefined) =>
|
|
13
|
+
rate === undefined ? "n/a" : `${(rate * 100).toFixed(1)}%`;
|
|
14
|
+
|
|
15
|
+
const validatedCount = (value: { failed: number; passed: number }) =>
|
|
16
|
+
value.failed + value.passed;
|
|
17
|
+
|
|
18
|
+
const timestamp = (value: string | undefined) =>
|
|
19
|
+
value ? new Date(value).toLocaleString() : "n/a";
|
|
20
|
+
|
|
21
|
+
export const formatAdvisorStats = ({
|
|
22
|
+
error,
|
|
23
|
+
malformedLines,
|
|
24
|
+
stats,
|
|
25
|
+
}: AdvisorStatsDetails): string => {
|
|
26
|
+
if (error) {
|
|
27
|
+
return `**Could not read Advisor outcomes.**\n\n${error}`;
|
|
28
|
+
}
|
|
29
|
+
if (!stats || stats.total === 0) {
|
|
30
|
+
const ignored = malformedLines
|
|
31
|
+
? `\n\nIgnored ${malformedLines} malformed ledger line${malformedLines === 1 ? "" : "s"}.`
|
|
32
|
+
: "";
|
|
33
|
+
return `**No Advisor outcomes recorded yet.**\n\nEnable outcome logging and record an outcome after an Advisor response to build this report.${ignored}`;
|
|
34
|
+
}
|
|
35
|
+
const { validationByAdoption } = stats;
|
|
36
|
+
const { followed } = validationByAdoption;
|
|
37
|
+
const notFollowed = validationByAdoption["not-followed"];
|
|
38
|
+
const triggerLines = Object.entries(stats.byTrigger).map(
|
|
39
|
+
([trigger, count]) => `- ${trigger}: ${count}`
|
|
40
|
+
);
|
|
41
|
+
const adoptionLines = Object.entries(stats.adoption).map(
|
|
42
|
+
([adoption, count]) => `- ${adoption}: ${count}`
|
|
43
|
+
);
|
|
44
|
+
const validationLines = [
|
|
45
|
+
`- followed: ${percent(followed.passRate)} passed (${followed.passed}/${validatedCount(followed)})`,
|
|
46
|
+
`- not-followed: ${percent(notFollowed.passRate)} passed (${notFollowed.passed}/${validatedCount(notFollowed)})`,
|
|
47
|
+
];
|
|
48
|
+
const ignored = malformedLines
|
|
49
|
+
? `\n\nIgnored ${malformedLines} malformed ledger line${malformedLines === 1 ? "" : "s"}.`
|
|
50
|
+
: "";
|
|
51
|
+
return [
|
|
52
|
+
`**${stats.total} Advisor outcome${stats.total === 1 ? "" : "s"}**`,
|
|
53
|
+
"",
|
|
54
|
+
"**By trigger**",
|
|
55
|
+
...triggerLines,
|
|
56
|
+
"",
|
|
57
|
+
"**Adoption**",
|
|
58
|
+
...adoptionLines,
|
|
59
|
+
"",
|
|
60
|
+
"**Validation passed rate (passed / passed + failed)**",
|
|
61
|
+
...validationLines,
|
|
62
|
+
"",
|
|
63
|
+
`Distinct advices seen: ${stats.distinctAdvices}`,
|
|
64
|
+
`Time window: ${timestamp(stats.firstTimestamp)} → ${timestamp(stats.lastTimestamp)}`,
|
|
65
|
+
`Ledger window: capped at ${OUTCOME_LOG_MAX_BYTES / (1024 * 1024)} MiB and rewritten on overflow; this report covers only retained records.${ignored}`,
|
|
66
|
+
].join("\n");
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const readAdvisorStats = async (): Promise<AdvisorStatsDetails> => {
|
|
70
|
+
try {
|
|
71
|
+
const log = await readOutcomeLog();
|
|
72
|
+
const stats = aggregateOutcomeRecords(log.records, log.malformedLines);
|
|
73
|
+
return { malformedLines: log.malformedLines, stats };
|
|
74
|
+
} catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
error: error instanceof Error ? error.message : String(error),
|
|
77
|
+
malformedLines: 0,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const registerOutcomeStatsCommand = (runtime: CommandRuntime) => {
|
|
83
|
+
runtime.pi.registerCommand("advisor-stats", {
|
|
84
|
+
description: "Show retained Advisor outcome adoption and validation stats",
|
|
85
|
+
handler: async (_args, _ctx) => {
|
|
86
|
+
const details = await readAdvisorStats();
|
|
87
|
+
runtime.pi.sendMessage(
|
|
88
|
+
{
|
|
89
|
+
content: [],
|
|
90
|
+
customType: "advisor-stats-result",
|
|
91
|
+
details,
|
|
92
|
+
display: true,
|
|
93
|
+
},
|
|
94
|
+
{ deliverAs: "steer", triggerTurn: false }
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
};
|
|
@@ -7,6 +7,7 @@ import { activateAdvisor } from "./activation.ts";
|
|
|
7
7
|
import { registerCommandLifecycle } from "./lifecycle.ts";
|
|
8
8
|
import { registerManualCommand } from "./manual-command.ts";
|
|
9
9
|
import { registerModelCommands } from "./model-commands.ts";
|
|
10
|
+
import { registerOutcomeStatsCommand } from "./outcome-stats.ts";
|
|
10
11
|
import { registerCommandRenderers } from "./renderers.ts";
|
|
11
12
|
import { createCommandRuntime } from "./runtime.ts";
|
|
12
13
|
import { registerSettingsCommands } from "./settings-commands.ts";
|
|
@@ -24,5 +25,6 @@ export const registerCommands = (
|
|
|
24
25
|
registerCommandLifecycle(runtime, activate);
|
|
25
26
|
registerManualCommand(runtime);
|
|
26
27
|
registerModelCommands(runtime);
|
|
28
|
+
registerOutcomeStatsCommand(runtime);
|
|
27
29
|
registerSettingsCommands(runtime);
|
|
28
30
|
};
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
} from "../tools/render-common.ts";
|
|
16
16
|
import { formatAdvisorUsage } from "../usage.ts";
|
|
17
17
|
import { ManualAdvisorProgressComponent } from "./manual-progress.ts";
|
|
18
|
+
import { formatAdvisorStats } from "./outcome-stats.ts";
|
|
19
|
+
import type { AdvisorStatsDetails } from "./outcome-stats.ts";
|
|
18
20
|
import type { CommandRuntime } from "./types.ts";
|
|
19
21
|
|
|
20
22
|
interface ManualCallEntryDetails {
|
|
@@ -24,10 +26,22 @@ interface ManualCallEntryDetails {
|
|
|
24
26
|
|
|
25
27
|
interface ManualResultDetails {
|
|
26
28
|
advisor?: string;
|
|
29
|
+
agentRulesBytes?: number;
|
|
30
|
+
preferenceBytes?: number;
|
|
27
31
|
text?: string;
|
|
28
32
|
usage?: unknown;
|
|
29
33
|
}
|
|
30
34
|
|
|
35
|
+
const formatByteSize = (bytes: number) => {
|
|
36
|
+
if (bytes >= 1024 * 1024) {
|
|
37
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
38
|
+
}
|
|
39
|
+
if (bytes >= 1024) {
|
|
40
|
+
return `${Math.round(bytes / 1024)} KiB`;
|
|
41
|
+
}
|
|
42
|
+
return `${bytes} B`;
|
|
43
|
+
};
|
|
44
|
+
|
|
31
45
|
const manualCallRenderer =
|
|
32
46
|
(runtime: CommandRuntime): EntryRenderer<ManualCallEntryDetails> =>
|
|
33
47
|
(entry, { expanded }, theme) => {
|
|
@@ -70,12 +84,45 @@ const manualResultRenderer: MessageRenderer<ManualResultDetails> = (
|
|
|
70
84
|
box.addChild(new Text(theme.fg("dim", ` Usage: ${usage}`), 0, 0));
|
|
71
85
|
}
|
|
72
86
|
}
|
|
87
|
+
const attachments = [
|
|
88
|
+
details?.agentRulesBytes
|
|
89
|
+
? `AGENTS.md rules attached · ${formatByteSize(details.agentRulesBytes)}`
|
|
90
|
+
: undefined,
|
|
91
|
+
details?.preferenceBytes
|
|
92
|
+
? `Project preferences attached · ${formatByteSize(details.preferenceBytes)}`
|
|
93
|
+
: undefined,
|
|
94
|
+
].filter((value): value is string => value !== undefined);
|
|
95
|
+
if (attachments.length) {
|
|
96
|
+
box.addChild(
|
|
97
|
+
new Text(theme.fg("dim", ` ${attachments.join(" · ")}`), 0, 0)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
73
100
|
box.addChild(
|
|
74
101
|
new Markdown(adviceForDisplay(advice, expanded), 0, 0, getMarkdownTheme())
|
|
75
102
|
);
|
|
76
103
|
return box;
|
|
77
104
|
};
|
|
78
105
|
|
|
106
|
+
const outcomeStatsRenderer: MessageRenderer<AdvisorStatsDetails> = (
|
|
107
|
+
message,
|
|
108
|
+
_options,
|
|
109
|
+
theme
|
|
110
|
+
) => {
|
|
111
|
+
const box = new Box(1, 1, (text) => theme.bg("customMessageBg", text));
|
|
112
|
+
box.addChild(
|
|
113
|
+
new Text(theme.fg("accent", theme.bold("◆ ADVISOR · OUTCOME STATS")), 0, 0)
|
|
114
|
+
);
|
|
115
|
+
box.addChild(
|
|
116
|
+
new Markdown(
|
|
117
|
+
formatAdvisorStats(message.details ?? { malformedLines: 0 }),
|
|
118
|
+
0,
|
|
119
|
+
0,
|
|
120
|
+
getMarkdownTheme()
|
|
121
|
+
)
|
|
122
|
+
);
|
|
123
|
+
return box;
|
|
124
|
+
};
|
|
125
|
+
|
|
79
126
|
export const registerCommandRenderers = (runtime: CommandRuntime) => {
|
|
80
127
|
runtime.pi.registerEntryRenderer?.(
|
|
81
128
|
"advisor-manual-call",
|
|
@@ -85,4 +132,8 @@ export const registerCommandRenderers = (runtime: CommandRuntime) => {
|
|
|
85
132
|
"advisor-manual-result",
|
|
86
133
|
manualResultRenderer
|
|
87
134
|
);
|
|
135
|
+
runtime.pi.registerMessageRenderer?.(
|
|
136
|
+
"advisor-stats-result",
|
|
137
|
+
outcomeStatsRenderer
|
|
138
|
+
);
|
|
88
139
|
};
|
package/src/commands/runtime.ts
CHANGED
|
@@ -77,7 +77,15 @@ class CommandRuntime implements CommandRuntimeContract {
|
|
|
77
77
|
undefined,
|
|
78
78
|
undefined,
|
|
79
79
|
undefined,
|
|
80
|
-
onScout
|
|
80
|
+
onScout,
|
|
81
|
+
undefined,
|
|
82
|
+
undefined,
|
|
83
|
+
(adviceId, payload, replacesAdviceId) =>
|
|
84
|
+
this.advisorSessionState.captureFollowUp(
|
|
85
|
+
adviceId,
|
|
86
|
+
payload,
|
|
87
|
+
replacesAdviceId
|
|
88
|
+
)
|
|
81
89
|
));
|
|
82
90
|
}
|
|
83
91
|
|
|
@@ -3,6 +3,7 @@ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
3
3
|
import {
|
|
4
4
|
getAdvisorSettings,
|
|
5
5
|
getPersistedModelRefs,
|
|
6
|
+
setAdvisorAgentsMdContextRef,
|
|
6
7
|
setAdvisorAutoLoopGateRef,
|
|
7
8
|
setAdvisorBlockOnBlockedRef,
|
|
8
9
|
setAdvisorCollapseResponsesRef,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
setAdvisorCustomInvocationRef,
|
|
11
12
|
setAdvisorDisableSameModelRef,
|
|
12
13
|
setAdvisorEffortRef,
|
|
14
|
+
setAdvisorFallbackModelRef,
|
|
13
15
|
setAdvisorFailureGateRef,
|
|
14
16
|
setAdvisorFailureModeRef,
|
|
15
17
|
setAdvisorGitContextMaxCharsRef,
|
|
@@ -68,6 +70,7 @@ const applySessionSettings = (settings: AdvisorSettings) => {
|
|
|
68
70
|
);
|
|
69
71
|
setContextMaxCharsRef(settings.contextMaxChars);
|
|
70
72
|
setAdvisorPlanGateRef(settings.planGate);
|
|
73
|
+
setAdvisorFallbackModelRef(settings.fallbackModel);
|
|
71
74
|
setAdvisorFailureGateRef(settings.failureGate);
|
|
72
75
|
setAdvisorCompletionGateRef(settings.completionGate);
|
|
73
76
|
setAdvisorDisableSameModelRef(settings.disableSameModel ?? true);
|
|
@@ -126,6 +129,7 @@ const applyDisclosureSettings = (settings: AdvisorSettings) => {
|
|
|
126
129
|
setAdvisorGitContextRef(settings.gitContext ?? "summary");
|
|
127
130
|
setAdvisorGitContextMaxCharsRef(settings.gitContextMaxChars ?? 20_000);
|
|
128
131
|
setAdvisorToolPoliciesRef(settings.toolPolicies ?? {});
|
|
132
|
+
setAdvisorAgentsMdContextRef(settings.agentsMdContext ?? true);
|
|
129
133
|
setAdvisorTrackedFileContentRef(settings.trackedFileContent ?? false);
|
|
130
134
|
setAdvisorUntrackedContentRef(settings.untrackedContent ?? false);
|
|
131
135
|
setAdvisorOutcomeLoggingRef(settings.outcomeLogging ?? false);
|
package/src/commands/types.ts
CHANGED
|
@@ -19,10 +19,13 @@ export type ManualConsult = (
|
|
|
19
19
|
gitContext?: GitContextLevel
|
|
20
20
|
) => Promise<{
|
|
21
21
|
adviceId?: string;
|
|
22
|
-
|
|
23
|
-
thinkingText: string;
|
|
22
|
+
agentRulesBytes?: number;
|
|
24
23
|
draftBytes?: number;
|
|
24
|
+
followUp?: boolean;
|
|
25
|
+
markdown: string;
|
|
26
|
+
model?: string;
|
|
25
27
|
preferenceBytes?: number;
|
|
28
|
+
thinkingText: string;
|
|
26
29
|
usage?: unknown;
|
|
27
30
|
}>;
|
|
28
31
|
|
package/src/config/defaults.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
setAdvisorAgentsMdContextRef,
|
|
2
3
|
setAdvisorAutoLoopGateRef,
|
|
3
4
|
setAdvisorBlockOnBlockedRef,
|
|
4
5
|
setAdvisorCollapseResponsesRef,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
setAdvisorPlanGateRef,
|
|
30
31
|
setAdvisorRedactSecretsRef,
|
|
31
32
|
setAdvisorRef,
|
|
33
|
+
setAdvisorFallbackModelRef,
|
|
32
34
|
setAdvisorScoutEnabledRef,
|
|
33
35
|
setAdvisorScoutTimeoutMsRef,
|
|
34
36
|
setAdvisorSessionSummaryRef,
|
|
@@ -68,6 +70,8 @@ import {
|
|
|
68
70
|
export const resetDefaults = () => {
|
|
69
71
|
setExecutorRef("");
|
|
70
72
|
setAdvisorRef("");
|
|
73
|
+
setAdvisorFallbackModelRef(undefined);
|
|
74
|
+
setAdvisorAgentsMdContextRef(true);
|
|
71
75
|
setPersistedModelRefs(undefined, undefined);
|
|
72
76
|
setExecutorEffortRef(undefined);
|
|
73
77
|
setAdvisorEffortRef(undefined);
|
|
@@ -137,8 +141,17 @@ const applyNonEmptyStringConfig = (
|
|
|
137
141
|
export const applyConfig = (config: AdvisorConfig) => {
|
|
138
142
|
applyNonEmptyStringConfig(config.executor, setExecutorRef);
|
|
139
143
|
applyNonEmptyStringConfig(config.advisor, setAdvisorRef);
|
|
144
|
+
applyNonEmptyStringConfig(
|
|
145
|
+
config.advisorFallbackModel,
|
|
146
|
+
setAdvisorFallbackModelRef
|
|
147
|
+
);
|
|
140
148
|
applyNonEmptyStringConfig(config.executorEffort, setExecutorEffortRef);
|
|
141
149
|
applyNonEmptyStringConfig(config.advisorEffort, setAdvisorEffortRef);
|
|
150
|
+
applyOptionalConfig(
|
|
151
|
+
config,
|
|
152
|
+
"advisorAgentsMdContext",
|
|
153
|
+
setAdvisorAgentsMdContextRef
|
|
154
|
+
);
|
|
142
155
|
applyOptionalConfig(config, "contextMaxChars", setContextMaxCharsRef);
|
|
143
156
|
applyOptionalConfig(config, "advisorPlanGate", setAdvisorPlanGateRef);
|
|
144
157
|
applyOptionalConfig(config, "advisorFailureGate", setAdvisorFailureGateRef);
|
package/src/config/schema.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { isString } from "../content-utils.ts";
|
|
|
2
2
|
import type { JsonValue } from "../content-utils.ts";
|
|
3
3
|
import { GIT_CONTEXT_LEVELS, isValidGitContextLevel } from "../git.ts";
|
|
4
4
|
import {
|
|
5
|
+
advisorAgentsMdContextRef,
|
|
5
6
|
advisorAutoLoopGateRef,
|
|
6
7
|
advisorBlockOnBlockedRef,
|
|
7
8
|
advisorCollapseResponsesRef,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
advisorCustomInvocationRef,
|
|
10
11
|
advisorDisableSameModelRef,
|
|
11
12
|
advisorEffortRef,
|
|
13
|
+
advisorFallbackModelRef,
|
|
12
14
|
advisorFailureGateRef,
|
|
13
15
|
advisorFailureModeRef,
|
|
14
16
|
advisorGitContextMaxCharsRef,
|
|
@@ -171,6 +173,12 @@ export const CONFIG_SCHEMA = {
|
|
|
171
173
|
persisted: true,
|
|
172
174
|
type: "string",
|
|
173
175
|
},
|
|
176
|
+
advisorAgentsMdContext: {
|
|
177
|
+
accepted: "true or false",
|
|
178
|
+
current: () => advisorAgentsMdContextRef,
|
|
179
|
+
persisted: true,
|
|
180
|
+
type: "boolean",
|
|
181
|
+
},
|
|
174
182
|
advisorAutoLoopGate: {
|
|
175
183
|
accepted: "true or false",
|
|
176
184
|
current: () => advisorAutoLoopGateRef,
|
|
@@ -219,6 +227,12 @@ export const CONFIG_SCHEMA = {
|
|
|
219
227
|
persisted: true,
|
|
220
228
|
type: "boolean",
|
|
221
229
|
},
|
|
230
|
+
advisorFallbackModel: {
|
|
231
|
+
accepted: "a provider/model string",
|
|
232
|
+
current: () => configuredModelRef(advisorFallbackModelRef),
|
|
233
|
+
persisted: true,
|
|
234
|
+
type: "string",
|
|
235
|
+
},
|
|
222
236
|
advisorGitContext: {
|
|
223
237
|
accepted: GIT_CONTEXT_LEVELS.join(", "),
|
|
224
238
|
current: () => advisorGitContextRef,
|
package/src/config/state.ts
CHANGED
|
@@ -25,6 +25,8 @@ import type {
|
|
|
25
25
|
// An empty ref means no model has been selected yet.
|
|
26
26
|
export let executorRef = "";
|
|
27
27
|
export let advisorRef = "";
|
|
28
|
+
export let advisorFallbackModelRef: string | undefined;
|
|
29
|
+
export let advisorAgentsMdContextRef = true;
|
|
28
30
|
let persistedExecutorRef: string | undefined;
|
|
29
31
|
let persistedAdvisorRef: string | undefined;
|
|
30
32
|
export let executorEffortRef: string | undefined;
|
|
@@ -80,6 +82,12 @@ export const setExecutorRef = (ref: string) => {
|
|
|
80
82
|
export const setAdvisorRef = (ref: string) => {
|
|
81
83
|
advisorRef = ref;
|
|
82
84
|
};
|
|
85
|
+
export const setAdvisorFallbackModelRef = (ref: string | undefined) => {
|
|
86
|
+
advisorFallbackModelRef = ref?.trim() || undefined;
|
|
87
|
+
};
|
|
88
|
+
export const setAdvisorAgentsMdContextRef = (enabled: boolean) => {
|
|
89
|
+
advisorAgentsMdContextRef = enabled;
|
|
90
|
+
};
|
|
83
91
|
/** Returns model refs explicitly persisted in the global Advisor config. */
|
|
84
92
|
export const getPersistedModelRefs = () => ({
|
|
85
93
|
advisor: persistedAdvisorRef,
|
|
@@ -234,6 +242,7 @@ export const setShowUsageFooterRef = (enabled: boolean) => {
|
|
|
234
242
|
* imported mutable bindings, which can be snapshotted by extension loaders.
|
|
235
243
|
*/
|
|
236
244
|
export const getAdvisorSettings = () => ({
|
|
245
|
+
agentsMdContext: advisorAgentsMdContextRef,
|
|
237
246
|
alwaysOn: alwaysOnRef,
|
|
238
247
|
autoLoopGate: advisorAutoLoopGateRef,
|
|
239
248
|
blockOnBlocked: advisorBlockOnBlockedRef,
|
|
@@ -245,6 +254,7 @@ export const getAdvisorSettings = () => ({
|
|
|
245
254
|
effort: advisorEffortRef,
|
|
246
255
|
failureGate: advisorFailureGateRef,
|
|
247
256
|
failureMode: advisorFailureModeRef,
|
|
257
|
+
fallbackModel: advisorFallbackModelRef,
|
|
248
258
|
gitContext: advisorGitContextRef,
|
|
249
259
|
gitContextMaxChars: advisorGitContextMaxCharsRef,
|
|
250
260
|
herdrIntegration: advisorHerdrIntegrationRef,
|
package/src/config/types.ts
CHANGED
|
@@ -60,6 +60,8 @@ export const GATE_FAILURE_MODES: GateFailureMode[] = [
|
|
|
60
60
|
|
|
61
61
|
export interface AdvisorConfig {
|
|
62
62
|
advisor?: string;
|
|
63
|
+
advisorFallbackModel?: string;
|
|
64
|
+
advisorAgentsMdContext?: boolean;
|
|
63
65
|
advisorAutoLoopGate?: boolean;
|
|
64
66
|
advisorBlockOnBlocked?: boolean;
|
|
65
67
|
advisorCollapseResponses?: boolean;
|
package/src/config.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// biome-ignore lint/performance/noBarrelFile: this facade intentionally preserves the public config module contract.
|
|
2
2
|
export { parseArgs } from "./config/args.ts";
|
|
3
3
|
export {
|
|
4
|
+
advisorAgentsMdContextRef,
|
|
4
5
|
advisorAutoLoopGateRef,
|
|
5
6
|
advisorBlockOnBlockedRef,
|
|
6
7
|
advisorCollapseResponsesRef,
|
|
7
8
|
advisorCompletionGateRef,
|
|
8
9
|
advisorCustomInvocationRef,
|
|
9
10
|
advisorEffortRef,
|
|
11
|
+
advisorFallbackModelRef,
|
|
10
12
|
advisorFailureGateRef,
|
|
11
13
|
advisorFailureModeRef,
|
|
12
14
|
advisorGitContextMaxCharsRef,
|
|
@@ -34,12 +36,14 @@ export {
|
|
|
34
36
|
getAdvisorSettings,
|
|
35
37
|
getPersistedModelRefs,
|
|
36
38
|
isSimpleMode,
|
|
39
|
+
setAdvisorAgentsMdContextRef,
|
|
37
40
|
setAdvisorAutoLoopGateRef,
|
|
38
41
|
setAdvisorBlockOnBlockedRef,
|
|
39
42
|
setAdvisorCollapseResponsesRef,
|
|
40
43
|
setAdvisorCompletionGateRef,
|
|
41
44
|
setAdvisorCustomInvocationRef,
|
|
42
45
|
setAdvisorEffortRef,
|
|
46
|
+
setAdvisorFallbackModelRef,
|
|
43
47
|
setAdvisorFailureGateRef,
|
|
44
48
|
setAdvisorFailureModeRef,
|
|
45
49
|
setAdvisorGitContextMaxCharsRef,
|