@oh-my-pi/pi-coding-agent 15.9.67 → 15.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 +63 -1
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/gallery-cli.d.ts +43 -0
- package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
- package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +44 -0
- package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
- package/dist/types/cli/gallery-screenshot.d.ts +35 -0
- package/dist/types/commands/gallery.d.ts +47 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-id-affixes.d.ts +2 -0
- package/dist/types/config/model-registry.d.ts +8 -1
- package/dist/types/config/settings-schema.d.ts +32 -6
- package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
- package/dist/types/lsp/types.d.ts +10 -0
- package/dist/types/main.d.ts +3 -2
- package/dist/types/memory-backend/index.d.ts +2 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +1 -1
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/tool-execution.d.ts +18 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/index.d.ts +5 -4
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/setup-version.d.ts +11 -0
- package/dist/types/modes/setup-wizard/index.d.ts +2 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +2 -1
- package/dist/types/modes/types.d.ts +1 -1
- package/dist/types/sdk.d.ts +1 -1
- package/dist/types/task/executor.d.ts +7 -0
- package/dist/types/telemetry-export.d.ts +1 -1
- package/dist/types/tools/eval-render.d.ts +1 -8
- package/dist/types/tools/fetch.d.ts +15 -7
- package/dist/types/tools/render-utils.d.ts +8 -0
- package/dist/types/tools/renderers.d.ts +16 -2
- package/dist/types/tools/search.d.ts +1 -1
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/web/scrapers/github.d.ts +22 -0
- package/dist/types/web/search/providers/perplexity.d.ts +8 -1
- package/dist/types/web/search/types.d.ts +1 -1
- package/package.json +9 -9
- package/scripts/dev-launch +42 -0
- package/scripts/dev-launch-preload.ts +19 -0
- package/src/cli/args.ts +2 -2
- package/src/cli/gallery-cli.ts +223 -0
- package/src/cli/gallery-fixtures/agentic.ts +292 -0
- package/src/cli/gallery-fixtures/codeintel.ts +188 -0
- package/src/cli/gallery-fixtures/edit.ts +194 -0
- package/src/cli/gallery-fixtures/fs.ts +153 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +49 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +221 -0
- package/src/cli/gallery-fixtures/search.ts +213 -0
- package/src/cli/gallery-fixtures/shell.ts +167 -0
- package/src/cli/gallery-fixtures/types.ts +41 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli-commands.ts +1 -0
- package/src/commands/gallery.ts +52 -0
- package/src/commands/launch.ts +1 -1
- package/src/config/keybindings.ts +15 -6
- package/src/config/model-equivalence.ts +35 -12
- package/src/config/model-id-affixes.ts +39 -22
- package/src/config/model-registry.ts +16 -16
- package/src/config/settings-schema.ts +18 -5
- package/src/config/settings.ts +11 -0
- package/src/dap/client.ts +14 -16
- package/src/edit/renderer.ts +36 -48
- package/src/eval/__tests__/agent-bridge.test.ts +75 -32
- package/src/eval/agent-bridge.ts +34 -7
- package/src/extensibility/extensions/runner.ts +1 -0
- package/src/extensibility/plugins/doctor.ts +0 -1
- package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
- package/src/goals/tools/goal-tool.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +5 -5
- package/src/lsp/client.ts +104 -55
- package/src/lsp/types.ts +10 -0
- package/src/main.ts +44 -49
- package/src/memory-backend/index.ts +13 -1
- package/src/memory-backend/resolve.ts +3 -5
- package/src/memory-backend/types.ts +1 -1
- package/src/modes/components/custom-editor.ts +10 -1
- package/src/modes/components/status-line.ts +3 -5
- package/src/modes/components/tool-execution.ts +61 -16
- package/src/modes/controllers/command-controller.ts +13 -2
- package/src/modes/controllers/input-controller.ts +11 -3
- package/src/modes/controllers/selector-controller.ts +2 -2
- package/src/modes/index.ts +5 -4
- package/src/modes/interactive-mode.ts +17 -3
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +3 -2
- package/src/modes/setup-wizard/scenes/web-search.ts +3 -2
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/context-usage.ts +10 -6
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/sdk.ts +21 -23
- package/src/session/agent-session.ts +7 -7
- package/src/slash-commands/builtin-registry.ts +1 -1
- package/src/slash-commands/helpers/usage-report.ts +2 -0
- package/src/task/executor.ts +20 -2
- package/src/task/render.ts +1 -2
- package/src/telemetry-export.ts +25 -7
- package/src/tools/eval-backends.ts +6 -17
- package/src/tools/eval-render.ts +21 -18
- package/src/tools/eval.ts +5 -4
- package/src/tools/fetch.ts +94 -84
- package/src/tools/render-utils.ts +17 -3
- package/src/tools/renderers.ts +16 -1
- package/src/tools/report-tool-issue.ts +1 -1
- package/src/tools/search.ts +173 -81
- package/src/tools/todo.ts +20 -7
- package/src/tools/write.ts +22 -1
- package/src/web/scrapers/github.ts +255 -3
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/providers/perplexity.ts +199 -51
- package/src/web/search/render.ts +39 -54
- package/src/web/search/types.ts +5 -1
- package/dist/types/eval/__tests__/shared-executors.test.d.ts +0 -1
- package/src/eval/__tests__/shared-executors.test.ts +0 -609
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
renderJsonTreeLines,
|
|
32
32
|
} from "../../tools/json-tree";
|
|
33
33
|
import { formatExpandHint, replaceTabs, resolveImageOptions, truncateToWidth } from "../../tools/render-utils";
|
|
34
|
-
import { toolRenderers } from "../../tools/renderers";
|
|
34
|
+
import { type ToolRenderer, toolRenderers } from "../../tools/renderers";
|
|
35
35
|
import { TODO_STRIKE_TOTAL_FRAMES } from "../../tools/todo";
|
|
36
36
|
import { isFramedBlockComponent, renderStatusLine } from "../../tui";
|
|
37
37
|
import { sanitizeWithOptionalSixelPassthrough } from "../../utils/sixel";
|
|
@@ -51,6 +51,12 @@ function addBoxChild(box: Box, component: unknown): boolean {
|
|
|
51
51
|
return isFramedBlockComponent(child);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
function setBoxPaddingForFramedBlock(box: Box, hasFramedBlock: boolean): void {
|
|
55
|
+
const padding = hasFramedBlock ? 0 : 1;
|
|
56
|
+
box.setPaddingX(padding);
|
|
57
|
+
box.setPaddingY(padding);
|
|
58
|
+
}
|
|
59
|
+
|
|
54
60
|
/**
|
|
55
61
|
* Drop trailing removal/hunk-header lines that appear in a streaming diff
|
|
56
62
|
* before the matching `+added` lines have arrived. Without this, a partial
|
|
@@ -524,6 +530,39 @@ export class ToolExecutionComponent extends Container {
|
|
|
524
530
|
return (this.#result.details as { async?: { state?: string } } | undefined)?.async?.state === "running";
|
|
525
531
|
}
|
|
526
532
|
|
|
533
|
+
/**
|
|
534
|
+
* While a tool's preview is still streaming, a block whose preview is
|
|
535
|
+
* append-only (rows only grow at the bottom, never re-layout) lets the
|
|
536
|
+
* renderer commit the scrolled-off head of an over-tall preview to native
|
|
537
|
+
* scrollback instead of dropping it — the same anti-yank path a streaming
|
|
538
|
+
* assistant reply uses (see {@link TranscriptContainer} +
|
|
539
|
+
* `NativeScrollbackLiveRegion`). Covers both phases: a pre-result call preview
|
|
540
|
+
* (a `write` whose content streams in) and a partial-result preview that
|
|
541
|
+
* streams output below fixed input (an `eval`/`bash` whose stdout grows under
|
|
542
|
+
* its code cell). Gated on {@link isTranscriptBlockFinalized} so the boundary
|
|
543
|
+
* closes the instant the block reaches a terminal state — a final result that
|
|
544
|
+
* may collapse to a compact view, a backgrounded async tool, or a seal — and
|
|
545
|
+
* the renderer decides whether its current preview shape qualifies via
|
|
546
|
+
* `isStreamingPreviewAppendOnly` (typically: only the expanded full view,
|
|
547
|
+
* which is top-anchored; the collapsed tail window re-layouts but is bounded
|
|
548
|
+
* so it never overflows anyway).
|
|
549
|
+
*/
|
|
550
|
+
isTranscriptBlockAppendOnly(): boolean {
|
|
551
|
+
// A finalized block's preview can collapse/re-layout; only a live,
|
|
552
|
+
// still-streaming block is a candidate.
|
|
553
|
+
if (this.isTranscriptBlockFinalized()) return false;
|
|
554
|
+
const predicate =
|
|
555
|
+
(this.#tool as { isStreamingPreviewAppendOnly?: ToolRenderer["isStreamingPreviewAppendOnly"] } | undefined)
|
|
556
|
+
?.isStreamingPreviewAppendOnly ?? toolRenderers[this.#toolName]?.isStreamingPreviewAppendOnly;
|
|
557
|
+
if (!predicate) return false;
|
|
558
|
+
try {
|
|
559
|
+
return predicate(this.#getCallArgsForRender(), this.#renderState, this.#result);
|
|
560
|
+
} catch (err) {
|
|
561
|
+
logger.warn("Tool append-only predicate failed", { tool: this.#toolName, error: String(err) });
|
|
562
|
+
return false;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
527
566
|
/**
|
|
528
567
|
* Mark the tool terminal even though no result arrived (the turn aborted or
|
|
529
568
|
* abandoned it) and stop animating, so it can freeze and stops pinning the
|
|
@@ -595,22 +634,28 @@ export class ToolExecutionComponent extends Container {
|
|
|
595
634
|
// call preview once result lines exist.
|
|
596
635
|
this.#renderState.renderContext = this.#buildRenderContext();
|
|
597
636
|
|
|
598
|
-
// Render call component
|
|
637
|
+
// Render call component. The fallback label only stands in for a
|
|
638
|
+
// missing `renderCall`; when the call is intentionally suppressed
|
|
639
|
+
// (mergeCallAndResult once a result exists) we render nothing here so
|
|
640
|
+
// the result component isn't preceded by a redundant tool-name line.
|
|
599
641
|
const shouldRenderCall = !this.#result || !mergeCallAndResult;
|
|
600
|
-
if (shouldRenderCall
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
642
|
+
if (shouldRenderCall) {
|
|
643
|
+
if (tool.renderCall) {
|
|
644
|
+
try {
|
|
645
|
+
const callComponent = tool.renderCall(this.#getCallArgsForRender(), this.#renderState, theme);
|
|
646
|
+
if (callComponent) {
|
|
647
|
+
contentBoxHasFramedBlock =
|
|
648
|
+
addBoxChild(this.#contentBox, callComponent) || contentBoxHasFramedBlock;
|
|
649
|
+
}
|
|
650
|
+
} catch (err) {
|
|
651
|
+
logger.warn("Tool renderer failed", { tool: this.#toolName, error: String(err) });
|
|
652
|
+
// Fall back to default on error
|
|
653
|
+
addBoxChild(this.#contentBox, new Text(theme.fg("toolTitle", theme.bold(this.#toolLabel)), 0, 0));
|
|
605
654
|
}
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// Fall back to default on error
|
|
655
|
+
} else {
|
|
656
|
+
// No custom renderCall, show tool name
|
|
609
657
|
addBoxChild(this.#contentBox, new Text(theme.fg("toolTitle", theme.bold(this.#toolLabel)), 0, 0));
|
|
610
658
|
}
|
|
611
|
-
} else {
|
|
612
|
-
// No custom renderCall, show tool name
|
|
613
|
-
addBoxChild(this.#contentBox, new Text(theme.fg("toolTitle", theme.bold(this.#toolLabel)), 0, 0));
|
|
614
659
|
}
|
|
615
660
|
|
|
616
661
|
// Render result component if we have a result
|
|
@@ -650,7 +695,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
650
695
|
addBoxChild(this.#contentBox, new Text(theme.fg("toolOutput", replaceTabs(output)), 0, 0));
|
|
651
696
|
}
|
|
652
697
|
}
|
|
653
|
-
this.#contentBox
|
|
698
|
+
setBoxPaddingForFramedBlock(this.#contentBox, contentBoxHasFramedBlock);
|
|
654
699
|
} else if (this.#toolName in toolRenderers) {
|
|
655
700
|
// Built-in tools with renderers
|
|
656
701
|
const renderer = toolRenderers[this.#toolName];
|
|
@@ -693,7 +738,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
693
738
|
);
|
|
694
739
|
if (resultComponent) {
|
|
695
740
|
const fileBoxHasFramedBlock = addBoxChild(fileBox, resultComponent);
|
|
696
|
-
fileBox
|
|
741
|
+
setBoxPaddingForFramedBlock(fileBox, fileBoxHasFramedBlock);
|
|
697
742
|
}
|
|
698
743
|
} catch (err) {
|
|
699
744
|
logger.warn("Tool renderer failed", { tool: this.#toolName, error: String(err) });
|
|
@@ -776,7 +821,7 @@ export class ToolExecutionComponent extends Container {
|
|
|
776
821
|
}
|
|
777
822
|
}
|
|
778
823
|
}
|
|
779
|
-
this.#contentBox
|
|
824
|
+
setBoxPaddingForFramedBlock(this.#contentBox, contentBoxHasFramedBlock);
|
|
780
825
|
}
|
|
781
826
|
} else {
|
|
782
827
|
// Other built-in tools: use Text directly with caching
|
|
@@ -13,7 +13,6 @@ import { Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@oh-my-pi
|
|
|
13
13
|
import { formatDuration, Snowflake } from "@oh-my-pi/pi-utils";
|
|
14
14
|
import { $ } from "bun";
|
|
15
15
|
import { shouldEnableAppendOnlyContext } from "../../config/append-only-context-mode";
|
|
16
|
-
import { loadCustomShare } from "../../export/custom-share";
|
|
17
16
|
import type { CompactOptions } from "../../extensibility/extensions/types";
|
|
18
17
|
import {
|
|
19
18
|
diffMentalModelContent,
|
|
@@ -131,6 +130,7 @@ export class CommandController {
|
|
|
131
130
|
}
|
|
132
131
|
|
|
133
132
|
try {
|
|
133
|
+
const { loadCustomShare } = await import("../../export/custom-share");
|
|
134
134
|
const customShare = await loadCustomShare();
|
|
135
135
|
if (customShare) {
|
|
136
136
|
const loader = new BorderedLoader(this.ctx.ui, theme, "Sharing...");
|
|
@@ -465,7 +465,7 @@ export class CommandController {
|
|
|
465
465
|
const argumentText = text.slice(7).trim();
|
|
466
466
|
const action = argumentText.split(/\s+/, 1)[0]?.toLowerCase() || "view";
|
|
467
467
|
const agentDir = this.ctx.settings.getAgentDir();
|
|
468
|
-
const backend = resolveMemoryBackend(this.ctx.settings);
|
|
468
|
+
const backend = await resolveMemoryBackend(this.ctx.settings);
|
|
469
469
|
|
|
470
470
|
if (action === "view") {
|
|
471
471
|
const payload = await backend.buildDeveloperInstructions(agentDir, this.ctx.settings, this.ctx.session);
|
|
@@ -1272,6 +1272,8 @@ function formatAccountLabel(limit: UsageLimit, report: UsageReport, index: numbe
|
|
|
1272
1272
|
if (email) return email;
|
|
1273
1273
|
const accountId = (report.metadata?.accountId as string | undefined) ?? limit.scope.accountId;
|
|
1274
1274
|
if (accountId) return accountId;
|
|
1275
|
+
const projectId = (report.metadata?.projectId as string | undefined) ?? limit.scope.projectId;
|
|
1276
|
+
if (projectId) return projectId;
|
|
1275
1277
|
return `account ${index + 1}`;
|
|
1276
1278
|
}
|
|
1277
1279
|
|
|
@@ -1280,6 +1282,8 @@ function formatUnlimitedReportLabel(report: UsageReport, index: number): string
|
|
|
1280
1282
|
if (email) return email;
|
|
1281
1283
|
const accountId = report.metadata?.accountId as string | undefined;
|
|
1282
1284
|
if (accountId) return accountId;
|
|
1285
|
+
const projectId = report.metadata?.projectId as string | undefined;
|
|
1286
|
+
if (projectId) return projectId;
|
|
1283
1287
|
return `account ${index + 1}`;
|
|
1284
1288
|
}
|
|
1285
1289
|
|
|
@@ -1365,6 +1369,13 @@ function formatAggregateAmount(limits: UsageLimit[]): string {
|
|
|
1365
1369
|
return `${formatNumber(remainingPct)}% free`;
|
|
1366
1370
|
}
|
|
1367
1371
|
|
|
1372
|
+
// Count unique accounts from limit scopes — not limits.length.
|
|
1373
|
+
const uniqueAccountIds = new Set(
|
|
1374
|
+
limits.map(limit => limit.scope.accountId).filter((id): id is string => typeof id === "string" && id.length > 0),
|
|
1375
|
+
);
|
|
1376
|
+
if (uniqueAccountIds.size > 0) return `${uniqueAccountIds.size} ${uniqueAccountIds.size === 1 ? "acct" : "accts"}`;
|
|
1377
|
+
// No account IDs available — keep the pre-existing fallback so providers
|
|
1378
|
+
// that don't populate scope.accountId still show a summary.
|
|
1368
1379
|
return `${limits.length} accts`;
|
|
1369
1380
|
}
|
|
1370
1381
|
|
|
@@ -144,6 +144,8 @@ export class InputController {
|
|
|
144
144
|
this.ctx.editor.setActionKeys("app.clear", this.ctx.keybindings.getKeys("app.clear"));
|
|
145
145
|
this.ctx.editor.onClear = () => this.handleCtrlC();
|
|
146
146
|
this.ctx.editor.setActionKeys("app.exit", this.ctx.keybindings.getKeys("app.exit"));
|
|
147
|
+
this.ctx.editor.setActionKeys("app.display.reset", this.ctx.keybindings.getKeys("app.display.reset"));
|
|
148
|
+
this.ctx.editor.onDisplayReset = () => this.ctx.ui.resetDisplay();
|
|
147
149
|
this.ctx.editor.onExit = () => this.handleCtrlD();
|
|
148
150
|
this.ctx.editor.setActionKeys("app.suspend", this.ctx.keybindings.getKeys("app.suspend"));
|
|
149
151
|
this.ctx.editor.onSuspend = () => this.handleCtrlZ();
|
|
@@ -188,11 +190,9 @@ export class InputController {
|
|
|
188
190
|
this.ctx.editor.onExpandTools = () => this.toggleToolOutputExpansion();
|
|
189
191
|
this.ctx.editor.setActionKeys("app.message.dequeue", this.ctx.keybindings.getKeys("app.message.dequeue"));
|
|
190
192
|
this.ctx.editor.onDequeue = () => this.handleDequeue();
|
|
191
|
-
|
|
192
193
|
this.ctx.editor.clearCustomKeyHandlers();
|
|
193
194
|
// Wire up extension shortcuts
|
|
194
195
|
this.registerExtensionShortcuts();
|
|
195
|
-
|
|
196
196
|
const planModeKeys = this.ctx.keybindings.getKeys("app.plan.toggle");
|
|
197
197
|
for (const key of planModeKeys) {
|
|
198
198
|
this.ctx.editor.setCustomKeyHandler(key, () => void this.ctx.handlePlanModeCommand());
|
|
@@ -846,7 +846,15 @@ export class InputController {
|
|
|
846
846
|
child.setExpanded(expanded);
|
|
847
847
|
}
|
|
848
848
|
}
|
|
849
|
-
|
|
849
|
+
// Toggling expansion mutates every block, but on ED3-risk terminals the
|
|
850
|
+
// transcript freezes a snapshot of each block once it scrolls past the live
|
|
851
|
+
// region (committed native scrollback is immutable there). A plain repaint
|
|
852
|
+
// replays those stale snapshots, so the toggle appears to do nothing above
|
|
853
|
+
// the live block. resetDisplay() invalidates the snapshots and forces a
|
|
854
|
+
// full clear + replay — the keyboard-accessible resize-reset equivalent —
|
|
855
|
+
// which is the only path that re-emits the whole transcript at its new
|
|
856
|
+
// heights.
|
|
857
|
+
this.ctx.ui.resetDisplay();
|
|
850
858
|
}
|
|
851
859
|
|
|
852
860
|
toggleThinkingBlockVisibility(): void {
|
|
@@ -7,7 +7,6 @@ import { getAgentDbPath, getProjectDir, normalizePathForComparison } from "@oh-m
|
|
|
7
7
|
import { getRoleInfo } from "../../config/model-registry";
|
|
8
8
|
import { formatModelSelectorValue } from "../../config/model-resolver";
|
|
9
9
|
import { settings } from "../../config/settings";
|
|
10
|
-
import { DebugSelectorComponent } from "../../debug";
|
|
11
10
|
import { disableProvider, enableProvider } from "../../discovery";
|
|
12
11
|
import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../../discovery/helpers";
|
|
13
12
|
import {
|
|
@@ -1080,7 +1079,8 @@ export class SelectorController {
|
|
|
1080
1079
|
});
|
|
1081
1080
|
}
|
|
1082
1081
|
|
|
1083
|
-
showDebugSelector(): void {
|
|
1082
|
+
async showDebugSelector(): Promise<void> {
|
|
1083
|
+
const { DebugSelectorComponent } = await import("../../debug");
|
|
1084
1084
|
this.showSelector(done => {
|
|
1085
1085
|
const selector = new DebugSelectorComponent(this.ctx, done);
|
|
1086
1086
|
return { component: selector, focus: selector };
|
package/src/modes/index.ts
CHANGED
|
@@ -2,11 +2,13 @@ import { emergencyTerminalRestore } from "@oh-my-pi/pi-tui";
|
|
|
2
2
|
import { postmortem } from "@oh-my-pi/pi-utils";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Interactive mode and embeddable RPC client exports for the coding agent.
|
|
6
|
+
*
|
|
7
|
+
* Branch-specific runners live in their concrete modules so importing this
|
|
8
|
+
* barrel does not pull print, RPC server, or ACP server mode into the normal
|
|
9
|
+
* TUI graph.
|
|
6
10
|
*/
|
|
7
|
-
export { runAcpMode } from "./acp";
|
|
8
11
|
export { InteractiveMode, type InteractiveModeOptions } from "./interactive-mode";
|
|
9
|
-
export { type PrintModeOptions, runPrintMode } from "./print-mode";
|
|
10
12
|
export {
|
|
11
13
|
defineRpcClientTool,
|
|
12
14
|
type ModelInfo,
|
|
@@ -17,7 +19,6 @@ export {
|
|
|
17
19
|
type RpcClientToolResult,
|
|
18
20
|
type RpcEventListener,
|
|
19
21
|
} from "./rpc/rpc-client";
|
|
20
|
-
export { runRpcMode } from "./rpc/rpc-mode";
|
|
21
22
|
export type {
|
|
22
23
|
RpcCommand,
|
|
23
24
|
RpcHostToolCallRequest,
|
|
@@ -250,6 +250,20 @@ export interface InteractiveModeOptions {
|
|
|
250
250
|
initialMessages?: string[];
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Plan-review preview block. Once rendered it is static (a one-shot Markdown of
|
|
255
|
+
* the plan file), so even while it sits as the live bottom block beneath the
|
|
256
|
+
* approval selector its scrolled-off head is safe to commit to native
|
|
257
|
+
* scrollback. Reporting append-only lets an over-tall plan + selector commit the
|
|
258
|
+
* plan's head instead of clipping it — without this a plain {@link Container} is
|
|
259
|
+
* deferred and a long plan is cut off the top on ED3-risk terminals.
|
|
260
|
+
*/
|
|
261
|
+
class PlanReviewBlock extends Container {
|
|
262
|
+
isTranscriptBlockAppendOnly(): boolean {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
253
267
|
export class InteractiveMode implements InteractiveModeContext {
|
|
254
268
|
session: AgentSession;
|
|
255
269
|
sessionManager: SessionManager;
|
|
@@ -1680,7 +1694,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1680
1694
|
#renderPlanPreview(planContent: string, options?: { append?: boolean }): void {
|
|
1681
1695
|
const existingContainer = this.#planReviewContainer;
|
|
1682
1696
|
const replaceExisting = options?.append !== true && existingContainer !== undefined;
|
|
1683
|
-
const planReviewContainer = replaceExisting ? existingContainer : new
|
|
1697
|
+
const planReviewContainer = replaceExisting ? existingContainer : new PlanReviewBlock();
|
|
1684
1698
|
planReviewContainer.clear();
|
|
1685
1699
|
planReviewContainer.addChild(new Spacer(1));
|
|
1686
1700
|
planReviewContainer.addChild(new DynamicBorder());
|
|
@@ -2844,8 +2858,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2844
2858
|
}
|
|
2845
2859
|
}
|
|
2846
2860
|
|
|
2847
|
-
showDebugSelector(): void {
|
|
2848
|
-
this.#selectorController.showDebugSelector();
|
|
2861
|
+
async showDebugSelector(): Promise<void> {
|
|
2862
|
+
await this.#selectorController.showDebugSelector();
|
|
2849
2863
|
}
|
|
2850
2864
|
|
|
2851
2865
|
showSessionObserver(): void {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup version the wizard advances a fresh install to. Bump it whenever a new
|
|
3
|
+
* setup scene lands (or an existing scene raises its `minVersion`).
|
|
4
|
+
*
|
|
5
|
+
* Kept in its own dependency-free module so the cold-launch gate in `main.ts`
|
|
6
|
+
* can answer "is the stored setup version stale?" without statically importing
|
|
7
|
+
* the full wizard — every scene (sign-in/OAuth, web search, theme previews) plus
|
|
8
|
+
* the overlay component and their TUI deps. MUST equal `max(scene.minVersion)`
|
|
9
|
+
* across `ALL_SCENES`; the `setup-wizard` barrel and test suite guard it.
|
|
10
|
+
*/
|
|
11
|
+
export const CURRENT_SETUP_VERSION = 1;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Settings } from "../../config/settings";
|
|
2
|
+
import { CURRENT_SETUP_VERSION } from "../setup-version";
|
|
2
3
|
import type { InteractiveModeContext } from "../types";
|
|
3
4
|
import { glyphSetupScene } from "./scenes/glyph";
|
|
4
5
|
import { providersSetupScene } from "./scenes/providers";
|
|
@@ -8,14 +9,14 @@ import { SetupWizardComponent } from "./wizard-overlay";
|
|
|
8
9
|
|
|
9
10
|
export type { SetupScene, SetupSceneController, SetupSceneHost, SetupSceneResult } from "./scenes/types";
|
|
10
11
|
|
|
12
|
+
export { CURRENT_SETUP_VERSION };
|
|
13
|
+
|
|
11
14
|
export const ALL_SCENES = [
|
|
12
15
|
providersSetupScene,
|
|
13
16
|
glyphSetupScene,
|
|
14
17
|
themeSetupScene,
|
|
15
18
|
] as const satisfies readonly SetupScene[];
|
|
16
19
|
|
|
17
|
-
export const CURRENT_SETUP_VERSION = ALL_SCENES.reduce((max, scene) => Math.max(max, scene.minVersion), 0);
|
|
18
|
-
|
|
19
20
|
export interface SetupSceneSelectionOptions {
|
|
20
21
|
resuming?: boolean;
|
|
21
22
|
isTTY?: boolean;
|
|
@@ -19,7 +19,8 @@ type Availability = "checking" | boolean;
|
|
|
19
19
|
/**
|
|
20
20
|
* "Web search" panel: picks the provider the web_search tool should prefer and
|
|
21
21
|
* reports whether the highlighted provider is ready to use given current
|
|
22
|
-
* credentials (env keys or OAuth sign-ins from the Sign in tab)
|
|
22
|
+
* credentials (env keys or OAuth sign-ins from the Sign in tab) or an
|
|
23
|
+
* unauthenticated fallback.
|
|
23
24
|
*/
|
|
24
25
|
export class WebSearchTab implements SetupTab {
|
|
25
26
|
readonly id = "web-search";
|
|
@@ -91,7 +92,7 @@ export class WebSearchTab implements SetupTab {
|
|
|
91
92
|
let ready = false;
|
|
92
93
|
try {
|
|
93
94
|
const provider = await getSearchProvider(id);
|
|
94
|
-
ready = await provider.
|
|
95
|
+
ready = await provider.isExplicitlyAvailable(this.host.ctx.session.modelRegistry.authStorage);
|
|
95
96
|
} catch {
|
|
96
97
|
ready = false;
|
|
97
98
|
}
|
package/src/modes/types.ts
CHANGED
|
@@ -269,7 +269,7 @@ export interface InteractiveModeContext {
|
|
|
269
269
|
handleSessionDeleteCommand(): Promise<void>;
|
|
270
270
|
showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
|
|
271
271
|
showHookConfirm(title: string, message: string): Promise<boolean>;
|
|
272
|
-
showDebugSelector(): void
|
|
272
|
+
showDebugSelector(): Promise<void>;
|
|
273
273
|
showSessionObserver(): void;
|
|
274
274
|
resetObserverRegistry(): void;
|
|
275
275
|
|
|
@@ -37,6 +37,9 @@ export interface ContextBreakdown {
|
|
|
37
37
|
freeTokens: number;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
const EMPTY_STRING_PARTS: readonly string[] = [];
|
|
41
|
+
const EMPTY_TOOLS: ReadonlyArray<Pick<Tool, "name" | "description" | "parameters">> = [];
|
|
42
|
+
|
|
40
43
|
export function estimateSkillsTokens(skills: readonly Skill[]): number {
|
|
41
44
|
const fragments: string[] = [];
|
|
42
45
|
for (const skill of skills) {
|
|
@@ -75,15 +78,16 @@ export function estimateToolSchemaTokens(
|
|
|
75
78
|
* messages walked incrementally as new entries append.
|
|
76
79
|
*/
|
|
77
80
|
export function computeNonMessageTokens(session: AgentSession): number {
|
|
78
|
-
const
|
|
79
|
-
|
|
81
|
+
const systemPromptParts = session.systemPrompt ?? EMPTY_STRING_PARTS;
|
|
82
|
+
const tools = session.agent?.state?.tools ?? EMPTY_TOOLS;
|
|
83
|
+
return countTokens(systemPromptParts) + estimateToolSchemaTokens(tools);
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
/**
|
|
83
|
-
* Shared helper for the four non-message token totals
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
+
* Shared helper for the four non-message token totals used by
|
|
88
|
+
* `computeContextBreakdown` (/context panel). Keep this category split stable:
|
|
89
|
+
* the status-line fast path intentionally uses the equivalent collapsed total
|
|
90
|
+
* in `computeNonMessageTokens`.
|
|
87
91
|
*/
|
|
88
92
|
function computeNonMessageBreakdown(session: AgentSession): {
|
|
89
93
|
skillsTokens: number;
|
|
@@ -37,6 +37,7 @@ export function buildHotkeysMarkdown(bindings: HotkeysMarkdownBindings): string
|
|
|
37
37
|
`| \`${appKey(bindings, "app.clear")}\` | Clear editor (first) / exit (second) |`,
|
|
38
38
|
`| \`${appKey(bindings, "app.exit")}\` | Exit (when editor is empty) |`,
|
|
39
39
|
`| \`${appKey(bindings, "app.suspend")}\` | Suspend to background |`,
|
|
40
|
+
`| \`${appKey(bindings, "app.display.reset")}\` | Reset terminal display |`,
|
|
40
41
|
`| \`${appKey(bindings, "app.thinking.cycle")}\` | Cycle thinking level |`,
|
|
41
42
|
`| \`${appKey(bindings, "app.model.cycleForward")}\` | Cycle role models (slow/default/smol) |`,
|
|
42
43
|
`| \`${appKey(bindings, "app.model.cycleBackward")}\` | Cycle role models (backward) |`,
|
package/src/sdk.ts
CHANGED
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
} from "@oh-my-pi/pi-utils";
|
|
37
37
|
import chalk from "chalk";
|
|
38
38
|
import { type AsyncJob, AsyncJobManager, isBackgroundJobSupportEnabled } from "./async";
|
|
39
|
-
import { createAutoresearchExtension } from "./autoresearch";
|
|
40
39
|
import { loadCapability } from "./capability";
|
|
41
40
|
import { type Rule, ruleCapability, setActiveRules } from "./capability/rule";
|
|
42
41
|
import { bucketRules } from "./capability/rule-buckets";
|
|
@@ -57,7 +56,6 @@ import { resolveConfigValue } from "./config/resolve-config-value";
|
|
|
57
56
|
import { initializeWithSettings } from "./discovery";
|
|
58
57
|
import { disposeAllKernelSessions, disposeKernelSessionsByOwner } from "./eval/py/executor";
|
|
59
58
|
import { defaultEvalSessionId } from "./eval/session-id";
|
|
60
|
-
import { TtsrManager } from "./export/ttsr";
|
|
61
59
|
import {
|
|
62
60
|
type CustomCommandsLoadResult,
|
|
63
61
|
type LoadedCustomCommand,
|
|
@@ -90,7 +88,7 @@ import { LocalProtocolHandler, type LocalProtocolOptions } from "./internal-urls
|
|
|
90
88
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "./lsp/startup-events";
|
|
91
89
|
import { discoverAndLoadMCPTools, MCPManager, type MCPToolsLoadResult } from "./mcp";
|
|
92
90
|
import { resolveMemoryBackend } from "./memory-backend";
|
|
93
|
-
import {
|
|
91
|
+
import type { MnemopiSessionState } from "./mnemopi/state";
|
|
94
92
|
import asyncResultTemplate from "./prompts/tools/async-result.md" with { type: "text" };
|
|
95
93
|
import { AgentRegistry, MAIN_AGENT_ID } from "./registry/agent-registry";
|
|
96
94
|
import {
|
|
@@ -1150,6 +1148,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1150
1148
|
|
|
1151
1149
|
// Discover rules and bucket them in one pass to avoid repeated scans over large rule sets.
|
|
1152
1150
|
const { ttsrManager, rulebookRules, alwaysApplyRules } = await logger.time("discoverTtsrRules", async () => {
|
|
1151
|
+
const { TtsrManager } = await import("./export/ttsr");
|
|
1153
1152
|
const ttsrSettings = settings.getGroup("ttsr");
|
|
1154
1153
|
const ttsrManager = new TtsrManager(ttsrSettings);
|
|
1155
1154
|
const rulesResult =
|
|
@@ -1295,7 +1294,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1295
1294
|
session ? session.trackEvalExecution(execution, abortController) : execution,
|
|
1296
1295
|
getSessionId: () => sessionManager.getSessionId?.() ?? null,
|
|
1297
1296
|
getHindsightSessionState: () => session?.getHindsightSessionState(),
|
|
1298
|
-
getMnemopiSessionState: () => getMnemopiSessionState(
|
|
1297
|
+
getMnemopiSessionState: () => session?.getMnemopiSessionState(),
|
|
1299
1298
|
getAgentId: () => resolvedAgentId,
|
|
1300
1299
|
getToolByName: name => session?.getToolByName(name),
|
|
1301
1300
|
agentRegistry,
|
|
@@ -1472,7 +1471,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1472
1471
|
}
|
|
1473
1472
|
|
|
1474
1473
|
const inlineExtensions: ExtensionFactory[] = options.extensions ? [...options.extensions] : [];
|
|
1475
|
-
inlineExtensions.push(createAutoresearchExtension);
|
|
1474
|
+
inlineExtensions.push((await import("./autoresearch")).createAutoresearchExtension);
|
|
1476
1475
|
if (customTools.length > 0) {
|
|
1477
1476
|
inlineExtensions.push(createCustomToolsExtension(customTools));
|
|
1478
1477
|
}
|
|
@@ -1607,9 +1606,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1607
1606
|
// `ExtensionToolWrapper` installed below is the only place the per-tool approval gate runs.
|
|
1608
1607
|
// A conditional runner means the approval system silently disappears for users with no
|
|
1609
1608
|
// extensions, contradicting non-yolo `tools.approvalMode` settings without feedback.
|
|
1610
|
-
// (
|
|
1611
|
-
// is unreachable;
|
|
1612
|
-
//
|
|
1609
|
+
// (The builtin autoresearch extension is unconditionally loaded above, so this scenario
|
|
1610
|
+
// is unreachable; unconditional runner construction keeps that invariant explicit and
|
|
1611
|
+
// prevents future optional extensions from silently re-opening the hole.)
|
|
1613
1612
|
const extensionRunner: ExtensionRunner = new ExtensionRunner(
|
|
1614
1613
|
extensionsResult.extensions,
|
|
1615
1614
|
extensionsResult.runtime,
|
|
@@ -1723,7 +1722,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1723
1722
|
|
|
1724
1723
|
const repeatToolDescriptions = settings.get("repeatToolDescriptions");
|
|
1725
1724
|
const eagerTasks = settings.get("task.eager");
|
|
1726
|
-
const intentField = settings.get("tools.intentTracing")
|
|
1725
|
+
const intentField = $flag("PI_INTENT_TRACING", settings.get("tools.intentTracing")) ? INTENT_FIELD : undefined;
|
|
1727
1726
|
const rebuildSystemPrompt = async (
|
|
1728
1727
|
toolNames: string[],
|
|
1729
1728
|
tools: Map<string, AgentTool>,
|
|
@@ -1749,7 +1748,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1749
1748
|
const promptTools = buildSystemPromptToolMetadata(tools, {
|
|
1750
1749
|
search_tool_bm25: { description: renderSearchToolBm25Description(discoverableToolsForDesc) },
|
|
1751
1750
|
});
|
|
1752
|
-
const memoryBackend = resolveMemoryBackend(settings);
|
|
1751
|
+
const memoryBackend = await resolveMemoryBackend(settings);
|
|
1753
1752
|
const memoryInstructions = await memoryBackend.buildDeveloperInstructions(agentDir, settings, session);
|
|
1754
1753
|
|
|
1755
1754
|
// Build combined append prompt: memory instructions + MCP server instructions
|
|
@@ -2267,19 +2266,18 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2267
2266
|
}
|
|
2268
2267
|
}
|
|
2269
2268
|
|
|
2270
|
-
logger.time("startMemoryStartupTask", () =>
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
);
|
|
2269
|
+
logger.time("startMemoryStartupTask", async () => {
|
|
2270
|
+
const memoryBackend = await resolveMemoryBackend(settings);
|
|
2271
|
+
await memoryBackend.start({
|
|
2272
|
+
session,
|
|
2273
|
+
settings,
|
|
2274
|
+
modelRegistry,
|
|
2275
|
+
agentDir,
|
|
2276
|
+
taskDepth,
|
|
2277
|
+
parentHindsightSessionState: options.parentHindsightSessionState,
|
|
2278
|
+
parentMnemopiSessionState: options.parentMnemopiSessionState,
|
|
2279
|
+
});
|
|
2280
|
+
});
|
|
2283
2281
|
|
|
2284
2282
|
// Wire MCP manager callbacks to session for reactive tool updates.
|
|
2285
2283
|
// Skip when reusing a parent's manager — the parent owns the callbacks.
|
|
@@ -128,7 +128,6 @@ import {
|
|
|
128
128
|
} from "../eval/py/executor";
|
|
129
129
|
import { defaultEvalSessionId } from "../eval/session-id";
|
|
130
130
|
import { type BashResult, executeBash as executeBashCommand } from "../exec/bash-executor";
|
|
131
|
-
import { exportSessionToHtml } from "../export/html";
|
|
132
131
|
import type { TtsrManager, TtsrMatchContext } from "../export/ttsr";
|
|
133
132
|
import type { LoadedCustomCommand } from "../extensibility/custom-commands";
|
|
134
133
|
import type { CustomTool, CustomToolContext } from "../extensibility/custom-tools/types";
|
|
@@ -2967,14 +2966,14 @@ export class AgentSession {
|
|
|
2967
2966
|
}
|
|
2968
2967
|
|
|
2969
2968
|
#rekeyHindsightMemoryForCurrentSessionId(): void {
|
|
2970
|
-
if (
|
|
2969
|
+
if (this.settings.get("memory.backend") !== "hindsight") return;
|
|
2971
2970
|
const sid = this.agent.sessionId;
|
|
2972
2971
|
if (!sid) return;
|
|
2973
2972
|
this.getHindsightSessionState()?.setSessionId(sid);
|
|
2974
2973
|
}
|
|
2975
2974
|
|
|
2976
2975
|
#rekeyMnemopiMemoryForCurrentSessionId(): void {
|
|
2977
|
-
if (
|
|
2976
|
+
if (this.settings.get("memory.backend") !== "mnemopi") return;
|
|
2978
2977
|
const sid = this.agent.sessionId;
|
|
2979
2978
|
if (!sid) return;
|
|
2980
2979
|
this.getMnemopiSessionState()?.setSessionId(sid);
|
|
@@ -2982,14 +2981,14 @@ export class AgentSession {
|
|
|
2982
2981
|
|
|
2983
2982
|
/** New session file: reset auto-recall / retain-threshold counters for the new transcript. */
|
|
2984
2983
|
#resetHindsightConversationTrackingIfHindsight(): void {
|
|
2985
|
-
if (
|
|
2984
|
+
if (this.settings.get("memory.backend") !== "hindsight") return;
|
|
2986
2985
|
const state = this.getHindsightSessionState();
|
|
2987
2986
|
if (!state || state.aliasOf) return;
|
|
2988
2987
|
state.resetConversationTracking();
|
|
2989
2988
|
}
|
|
2990
2989
|
|
|
2991
2990
|
#resetMnemopiConversationTrackingIfMnemopi(): void {
|
|
2992
|
-
if (
|
|
2991
|
+
if (this.settings.get("memory.backend") !== "mnemopi") return;
|
|
2993
2992
|
const state = this.getMnemopiSessionState();
|
|
2994
2993
|
if (!state || state.aliasOf) return;
|
|
2995
2994
|
state.resetConversationTracking();
|
|
@@ -3670,7 +3669,7 @@ export class AgentSession {
|
|
|
3670
3669
|
}
|
|
3671
3670
|
|
|
3672
3671
|
async #buildSystemPromptForAgentStart(promptText: string): Promise<string[]> {
|
|
3673
|
-
const backend = resolveMemoryBackend(this.settings);
|
|
3672
|
+
const backend = await resolveMemoryBackend(this.settings);
|
|
3674
3673
|
if (!backend.beforeAgentStartPrompt) return this.#baseSystemPrompt;
|
|
3675
3674
|
|
|
3676
3675
|
try {
|
|
@@ -6096,7 +6095,7 @@ export class AgentSession {
|
|
|
6096
6095
|
messagesToSummarize: AgentMessage[];
|
|
6097
6096
|
turnPrefixMessages: AgentMessage[];
|
|
6098
6097
|
}): Promise<string | undefined> {
|
|
6099
|
-
const backend = resolveMemoryBackend(this.settings);
|
|
6098
|
+
const backend = await resolveMemoryBackend(this.settings);
|
|
6100
6099
|
if (!backend.preCompactionContext) return undefined;
|
|
6101
6100
|
const messages = preparation.messagesToSummarize.concat(preparation.turnPrefixMessages);
|
|
6102
6101
|
try {
|
|
@@ -9588,6 +9587,7 @@ export class AgentSession {
|
|
|
9588
9587
|
*/
|
|
9589
9588
|
async exportToHtml(outputPath?: string): Promise<string> {
|
|
9590
9589
|
const themeName = getCurrentThemeName();
|
|
9590
|
+
const { exportSessionToHtml } = await import("../export/html");
|
|
9591
9591
|
return exportSessionToHtml(this.sessionManager, this.state, { outputPath, themeName });
|
|
9592
9592
|
}
|
|
9593
9593
|
|
|
@@ -934,7 +934,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
934
934
|
allowArgs: true,
|
|
935
935
|
handle: async (command, runtime) => {
|
|
936
936
|
const verb = (command.args.trim().split(/\s+/)[0] ?? "").toLowerCase() || "view";
|
|
937
|
-
const backend = resolveMemoryBackend(runtime.settings);
|
|
937
|
+
const backend = await resolveMemoryBackend(runtime.settings);
|
|
938
938
|
switch (verb) {
|
|
939
939
|
case "view": {
|
|
940
940
|
const payload = await backend.buildDeveloperInstructions(
|
|
@@ -26,6 +26,8 @@ function formatUsageReportAccount(report: UsageReport, limit: UsageLimit, index:
|
|
|
26
26
|
if (typeof email === "string" && email) return email;
|
|
27
27
|
const accountId = report.metadata?.accountId ?? limit.scope.accountId;
|
|
28
28
|
if (typeof accountId === "string" && accountId) return accountId;
|
|
29
|
+
const projectId = report.metadata?.projectId ?? limit.scope.projectId;
|
|
30
|
+
if (typeof projectId === "string" && projectId) return projectId;
|
|
29
31
|
return `account ${index + 1}`;
|
|
30
32
|
}
|
|
31
33
|
|