pi-sage 0.2.9 → 0.2.11
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/.pi/extensions/sage/index.ts +96 -16
- package/package.json +1 -1
|
@@ -378,8 +378,10 @@ async function runSettingsWizard(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
378
378
|
ctx.ui.notify(`Saved Sage settings to ${target}`, "info");
|
|
379
379
|
};
|
|
380
380
|
|
|
381
|
+
let rootSelectionIndex = 0;
|
|
382
|
+
|
|
381
383
|
while (true) {
|
|
382
|
-
const
|
|
384
|
+
const rootOptions = [
|
|
383
385
|
`Enabled: ${onOff(draft.enabled)}`,
|
|
384
386
|
`Autonomous mode: ${onOff(draft.autonomousEnabled)}`,
|
|
385
387
|
`Explicit requests bypass soft limits: ${onOff(draft.explicitRequestAlwaysAllowed)}`,
|
|
@@ -401,13 +403,18 @@ async function runSettingsWizard(ctx: ExtensionCommandContext): Promise<void> {
|
|
|
401
403
|
`Cost cap/session: ${draft.maxEstimatedCostPerSession ?? "(none)"}`,
|
|
402
404
|
`Save scope: ${scope}`,
|
|
403
405
|
"Test Sage call"
|
|
404
|
-
]
|
|
406
|
+
];
|
|
407
|
+
|
|
408
|
+
const action = await selectScrollable(ctx, "Sage settings", rootOptions, 10, rootSelectionIndex);
|
|
405
409
|
|
|
406
410
|
if (!action) {
|
|
407
411
|
ctx.ui.notify("Sage settings closed (changes are saved immediately)", "info");
|
|
408
412
|
return;
|
|
409
413
|
}
|
|
410
414
|
|
|
415
|
+
const selectedIndex = rootOptions.indexOf(action);
|
|
416
|
+
if (selectedIndex >= 0) rootSelectionIndex = selectedIndex;
|
|
417
|
+
|
|
411
418
|
if (action === "Test Sage call") {
|
|
412
419
|
await runSettingsTestCall(ctx, draft);
|
|
413
420
|
continue;
|
|
@@ -721,7 +728,8 @@ async function selectScrollable(
|
|
|
721
728
|
ctx: HasUIContext,
|
|
722
729
|
title: string,
|
|
723
730
|
options: string[],
|
|
724
|
-
maxVisible = 10
|
|
731
|
+
maxVisible = 10,
|
|
732
|
+
initialSelectedIndex = 0
|
|
725
733
|
): Promise<string | undefined> {
|
|
726
734
|
if (options.length === 0) return undefined;
|
|
727
735
|
|
|
@@ -744,6 +752,8 @@ async function selectScrollable(
|
|
|
744
752
|
noMatch: (text) => theme.fg("warning", text)
|
|
745
753
|
});
|
|
746
754
|
|
|
755
|
+
selectList.setSelectedIndex(initialSelectedIndex);
|
|
756
|
+
|
|
747
757
|
selectList.onSelect = (item) => done(item.value);
|
|
748
758
|
selectList.onCancel = () => done(undefined);
|
|
749
759
|
container.addChild(selectList);
|
|
@@ -838,19 +848,89 @@ async function runSettingsTestCall(ctx: ExtensionContext, settings: SageSettings
|
|
|
838
848
|
return;
|
|
839
849
|
}
|
|
840
850
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
});
|
|
851
|
+
type TestOutcome = { status: "ok" | "error" | "cancelled"; message: string };
|
|
852
|
+
|
|
853
|
+
const outcome = await ctx.ui.custom<TestOutcome | undefined>((tui, theme, _keybindings, done) => {
|
|
854
|
+
const controller = new AbortController();
|
|
855
|
+
const container = new Container();
|
|
856
|
+
|
|
857
|
+
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
858
|
+
container.addChild(new Text(theme.fg("accent", "Sage test call"), 1, 0));
|
|
859
|
+
container.addChild(new Text(theme.fg("dim", `Model: ${resolvedModel}`), 1, 0));
|
|
860
|
+
container.addChild(new Text("", 0, 0));
|
|
861
|
+
|
|
862
|
+
const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
863
|
+
let spinnerIndex = 0;
|
|
864
|
+
const statusLine = new Text(theme.fg("muted", `${spinnerFrames[spinnerIndex]} Running test...`), 1, 0);
|
|
865
|
+
container.addChild(statusLine);
|
|
850
866
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
867
|
+
container.addChild(new Text("", 0, 0));
|
|
868
|
+
container.addChild(new Text(theme.fg("dim", "Esc to cancel"), 1, 0));
|
|
869
|
+
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
870
|
+
|
|
871
|
+
let finished = false;
|
|
872
|
+
const finish = (result: TestOutcome): void => {
|
|
873
|
+
if (finished) return;
|
|
874
|
+
finished = true;
|
|
875
|
+
clearInterval(spinnerTimer);
|
|
876
|
+
done(result);
|
|
877
|
+
};
|
|
878
|
+
|
|
879
|
+
const spinnerTimer = setInterval(() => {
|
|
880
|
+
if (finished) return;
|
|
881
|
+
spinnerIndex = (spinnerIndex + 1) % spinnerFrames.length;
|
|
882
|
+
statusLine.setText(theme.fg("muted", `${spinnerFrames[spinnerIndex]} Running test...`));
|
|
883
|
+
tui.requestRender();
|
|
884
|
+
}, 120);
|
|
885
|
+
|
|
886
|
+
void (async () => {
|
|
887
|
+
try {
|
|
888
|
+
const result = await runSageSingleShot({
|
|
889
|
+
cwd: ctx.cwd,
|
|
890
|
+
model: resolvedModel,
|
|
891
|
+
reasoningLevel: settings.reasoningLevel,
|
|
892
|
+
timeoutMs: Math.min(settings.timeoutMs, 45_000),
|
|
893
|
+
question: "Reply with 'Sage test OK' and one short sentence.",
|
|
894
|
+
toolPolicy: settings.toolPolicy,
|
|
895
|
+
signal: controller.signal
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
finish({ status: "ok", message: `Sage test succeeded (${result.latencyMs}ms)` });
|
|
899
|
+
} catch (error) {
|
|
900
|
+
if (controller.signal.aborted) {
|
|
901
|
+
finish({ status: "cancelled", message: "Sage test cancelled" });
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
const message = error instanceof Error ? error.message : "Unknown test failure";
|
|
906
|
+
finish({ status: "error", message: `Sage test failed: ${message}` });
|
|
907
|
+
}
|
|
908
|
+
})();
|
|
909
|
+
|
|
910
|
+
return {
|
|
911
|
+
render: (width: number) => container.render(width),
|
|
912
|
+
invalidate: () => container.invalidate(),
|
|
913
|
+
handleInput: (data: string) => {
|
|
914
|
+
if (data === "\u001b") {
|
|
915
|
+
controller.abort();
|
|
916
|
+
finish({ status: "cancelled", message: "Sage test cancelled" });
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
if (!outcome) return;
|
|
924
|
+
|
|
925
|
+
if (outcome.status === "ok") {
|
|
926
|
+
ctx.ui.notify(outcome.message, "info");
|
|
927
|
+
return;
|
|
855
928
|
}
|
|
929
|
+
|
|
930
|
+
if (outcome.status === "cancelled") {
|
|
931
|
+
ctx.ui.notify(outcome.message, "warning");
|
|
932
|
+
return;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
ctx.ui.notify(outcome.message, "error");
|
|
856
936
|
}
|