@oh-my-pi/pi-coding-agent 15.9.67 → 15.10.1
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 +136 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/dry-balance-cli.d.ts +15 -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/commit/analysis/conventional.d.ts +2 -2
- package/dist/types/commit/analysis/summary.d.ts +2 -2
- package/dist/types/commit/changelog/generate.d.ts +2 -2
- package/dist/types/commit/changelog/index.d.ts +2 -2
- package/dist/types/commit/map-reduce/index.d.ts +3 -3
- package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
- package/dist/types/commit/model-selection.d.ts +10 -4
- package/dist/types/config/api-key-resolver.d.ts +34 -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 +25 -2
- package/dist/types/config/settings-schema.d.ts +41 -6
- package/dist/types/dap/config.d.ts +14 -1
- package/dist/types/dap/types.d.ts +10 -0
- package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
- package/dist/types/lsp/types.d.ts +10 -0
- package/dist/types/lsp/utils.d.ts +3 -2
- 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/chat-block.d.ts +64 -0
- package/dist/types/modes/components/custom-editor.d.ts +5 -1
- package/dist/types/modes/components/overlay-box.d.ts +17 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +59 -0
- package/dist/types/modes/components/plan-toc.d.ts +41 -0
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +18 -0
- package/dist/types/modes/components/transcript-container.d.ts +11 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +0 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
- package/dist/types/modes/controllers/input-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
- package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
- package/dist/types/modes/index.d.ts +5 -4
- package/dist/types/modes/interactive-mode.d.ts +16 -6
- 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/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +19 -6
- package/dist/types/modes/utils/copy-targets.d.ts +21 -1
- package/dist/types/plan-mode/approved-plan.d.ts +27 -8
- package/dist/types/plan-mode/plan-protection.d.ts +4 -4
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +21 -0
- package/dist/types/session/messages.d.ts +12 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/slash-commands/types.d.ts +4 -6
- package/dist/types/task/executor.d.ts +14 -0
- package/dist/types/task/index.d.ts +1 -0
- package/dist/types/task/render.d.ts +3 -2
- package/dist/types/telemetry-export.d.ts +1 -1
- package/dist/types/tools/archive-reader.d.ts +5 -0
- package/dist/types/tools/ast-edit.d.ts +3 -0
- package/dist/types/tools/ast-grep.d.ts +3 -0
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/eval-render.d.ts +1 -8
- package/dist/types/tools/fetch.d.ts +15 -7
- package/dist/types/tools/find.d.ts +8 -4
- package/dist/types/tools/grouped-file-output.d.ts +95 -12
- package/dist/types/tools/memory-render.d.ts +4 -1
- package/dist/types/tools/plan-mode-guard.d.ts +8 -9
- package/dist/types/tools/render-utils.d.ts +13 -9
- package/dist/types/tools/renderers.d.ts +16 -2
- package/dist/types/tools/search.d.ts +5 -1
- package/dist/types/tools/sqlite-reader.d.ts +1 -0
- package/dist/types/tools/todo.d.ts +3 -2
- package/dist/types/tools/write.d.ts +5 -0
- package/dist/types/tui/output-block.d.ts +16 -4
- package/dist/types/tui/status-line.d.ts +3 -0
- package/dist/types/utils/enhanced-paste.d.ts +20 -0
- package/dist/types/web/scrapers/github.d.ts +22 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -1
- 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/auto-thinking/classifier.ts +5 -1
- package/src/cli/args.ts +2 -2
- package/src/cli/dry-balance-cli.ts +52 -17
- package/src/cli/gallery-cli.ts +226 -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 +250 -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/commit/analysis/conventional.ts +2 -2
- package/src/commit/analysis/summary.ts +2 -2
- package/src/commit/changelog/generate.ts +2 -2
- package/src/commit/changelog/index.ts +2 -2
- package/src/commit/map-reduce/index.ts +3 -3
- package/src/commit/map-reduce/map-phase.ts +2 -2
- package/src/commit/map-reduce/reduce-phase.ts +2 -2
- package/src/commit/model-selection.ts +33 -9
- package/src/commit/pipeline.ts +4 -4
- package/src/config/api-key-resolver.ts +58 -0
- 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 +41 -18
- package/src/config/settings-schema.ts +28 -5
- package/src/config/settings.ts +31 -2
- package/src/dap/client.ts +14 -16
- package/src/dap/config.ts +41 -2
- package/src/dap/defaults.json +1 -0
- package/src/dap/session.ts +1 -0
- package/src/dap/types.ts +10 -0
- package/src/debug/index.ts +40 -54
- package/src/edit/renderer.ts +111 -119
- package/src/eval/__tests__/agent-bridge.test.ts +75 -32
- package/src/eval/__tests__/llm-bridge.test.ts +90 -31
- package/src/eval/agent-bridge.ts +34 -7
- package/src/eval/llm-bridge.ts +8 -3
- 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 +37 -27
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/lsp/client.ts +104 -55
- package/src/lsp/types.ts +10 -0
- package/src/lsp/utils.ts +3 -2
- package/src/main.ts +53 -56
- package/src/memories/index.ts +12 -5
- 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/mnemopi/backend.ts +5 -1
- package/src/modes/acp/acp-agent.ts +33 -26
- package/src/modes/components/assistant-message.ts +2 -9
- package/src/modes/components/chat-block.ts +111 -0
- package/src/modes/components/copy-selector.ts +1 -44
- package/src/modes/components/custom-editor.ts +33 -1
- package/src/modes/components/custom-message.ts +1 -3
- package/src/modes/components/execution-shared.ts +1 -2
- package/src/modes/components/hook-message.ts +1 -3
- package/src/modes/components/overlay-box.ts +108 -0
- package/src/modes/components/plan-review-overlay.ts +799 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/read-tool-group.ts +20 -4
- package/src/modes/components/skill-message.ts +0 -1
- package/src/modes/components/status-line.ts +3 -5
- package/src/modes/components/tips.txt +1 -0
- package/src/modes/components/todo-reminder.ts +0 -2
- package/src/modes/components/tool-execution.ts +115 -90
- package/src/modes/components/transcript-container.ts +84 -24
- package/src/modes/components/user-message.ts +1 -2
- package/src/modes/controllers/command-controller-shared.ts +7 -6
- package/src/modes/controllers/command-controller.ts +70 -57
- package/src/modes/controllers/event-controller.ts +41 -40
- package/src/modes/controllers/extension-ui-controller.ts +10 -73
- package/src/modes/controllers/input-controller.ts +135 -122
- package/src/modes/controllers/mcp-command-controller.ts +69 -60
- package/src/modes/controllers/selector-controller.ts +25 -27
- package/src/modes/controllers/streaming-reveal.ts +212 -0
- package/src/modes/controllers/tan-command-controller.ts +173 -0
- package/src/modes/index.ts +5 -4
- package/src/modes/interactive-mode.ts +171 -82
- 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/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/theme/theme-schema.json +1 -1
- package/src/modes/theme/theme.ts +8 -4
- package/src/modes/types.ts +19 -8
- package/src/modes/utils/context-usage.ts +10 -6
- package/src/modes/utils/copy-targets.ts +133 -27
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +44 -46
- package/src/plan-mode/approved-plan.ts +66 -43
- package/src/plan-mode/plan-protection.ts +4 -4
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/plan-mode-active.md +67 -58
- package/src/prompts/system/plan-mode-approved.md +1 -1
- package/src/sdk.ts +32 -60
- package/src/session/agent-session.ts +89 -13
- package/src/session/messages.ts +26 -0
- package/src/session/session-manager.ts +13 -5
- package/src/slash-commands/builtin-registry.ts +37 -10
- package/src/slash-commands/helpers/usage-report.ts +2 -0
- package/src/slash-commands/types.ts +4 -6
- package/src/task/executor.ts +25 -4
- package/src/task/index.ts +4 -0
- package/src/task/render.ts +212 -148
- package/src/telemetry-export.ts +25 -7
- package/src/tools/archive-reader.ts +64 -0
- package/src/tools/ask.ts +119 -164
- package/src/tools/ast-edit.ts +98 -71
- package/src/tools/ast-grep.ts +37 -43
- package/src/tools/bash.ts +50 -6
- package/src/tools/debug.ts +20 -8
- 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 +391 -91
- package/src/tools/find.ts +44 -30
- package/src/tools/gh-renderer.ts +81 -42
- package/src/tools/grouped-file-output.ts +272 -48
- package/src/tools/image-gen.ts +150 -103
- package/src/tools/inspect-image-renderer.ts +63 -41
- package/src/tools/inspect-image.ts +8 -1
- package/src/tools/job.ts +3 -4
- package/src/tools/memory-render.ts +4 -1
- package/src/tools/plan-mode-guard.ts +21 -39
- package/src/tools/read.ts +23 -16
- package/src/tools/render-utils.ts +38 -40
- package/src/tools/renderers.ts +16 -1
- package/src/tools/report-tool-issue.ts +1 -1
- package/src/tools/resolve.ts +14 -0
- package/src/tools/search-tool-bm25.ts +36 -23
- package/src/tools/search.ts +189 -95
- package/src/tools/sqlite-reader.ts +9 -12
- package/src/tools/todo.ts +138 -59
- package/src/tools/write.ts +100 -60
- package/src/tui/output-block.ts +60 -13
- package/src/tui/status-line.ts +5 -1
- package/src/utils/commit-message-generator.ts +9 -1
- package/src/utils/enhanced-paste.ts +202 -0
- package/src/utils/title-generator.ts +2 -1
- package/src/web/scrapers/github.ts +255 -3
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/providers/anthropic.ts +25 -19
- package/src/web/search/providers/exa.ts +11 -3
- package/src/web/search/providers/kimi.ts +28 -17
- package/src/web/search/providers/parallel.ts +35 -24
- package/src/web/search/providers/perplexity.ts +199 -51
- package/src/web/search/providers/synthetic.ts +8 -6
- package/src/web/search/providers/tavily.ts +9 -8
- package/src/web/search/providers/zai.ts +8 -6
- 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
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun `--preload` shim for the omp dev launcher (`scripts/dev-launch`).
|
|
3
|
+
*
|
|
4
|
+
* The launcher starts Bun from an empty, bunfig-free directory so a foreign
|
|
5
|
+
* project's `bunfig.toml` `preload` cannot run inside the omp CLI: Bun reads
|
|
6
|
+
* `bunfig.toml` from the *current working directory* on startup and evaluates
|
|
7
|
+
* its `preload` entries before the entrypoint, so a bun-shebang bin inherits
|
|
8
|
+
* whatever `preload` the directory you launched from declares (and crashes if
|
|
9
|
+
* that preload can't resolve). This shim is loaded before the entrypoint's
|
|
10
|
+
* imports run, so it restores the user's real working directory in time for
|
|
11
|
+
* import-time snapshots (e.g. `getProjectDir()` in `@oh-my-pi/pi-utils/dirs`).
|
|
12
|
+
*/
|
|
13
|
+
const launchCwd = process.env.OMP_LAUNCH_CWD;
|
|
14
|
+
if (launchCwd) {
|
|
15
|
+
delete process.env.OMP_LAUNCH_CWD;
|
|
16
|
+
try {
|
|
17
|
+
process.chdir(launchCwd);
|
|
18
|
+
} catch {}
|
|
19
|
+
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { type AssistantMessage, completeSimple, Effort, type Model } from "@oh-my-pi/pi-ai";
|
|
17
17
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
18
|
+
|
|
18
19
|
import type { ModelRegistry } from "../config/model-registry";
|
|
19
20
|
import { resolveRoleSelection } from "../config/model-resolver";
|
|
20
21
|
import type { Settings } from "../config/settings";
|
|
@@ -82,7 +83,10 @@ async function classifyOnline(input: string, deps: ClassifyDifficultyDeps): Prom
|
|
|
82
83
|
messages: [{ role: "user", content: input, timestamp: Date.now() }],
|
|
83
84
|
},
|
|
84
85
|
{
|
|
85
|
-
apiKey,
|
|
86
|
+
apiKey: deps.registry.resolver(model.provider, {
|
|
87
|
+
sessionId: deps.sessionId,
|
|
88
|
+
baseUrl: model.baseUrl,
|
|
89
|
+
}),
|
|
86
90
|
maxTokens,
|
|
87
91
|
disableReasoning: true,
|
|
88
92
|
metadata,
|
package/src/cli/args.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI argument parsing and help display
|
|
3
3
|
*/
|
|
4
|
-
import { type Effort, THINKING_EFFORTS } from "@oh-my-pi/pi-ai";
|
|
4
|
+
import { type Effort, THINKING_EFFORTS } from "@oh-my-pi/pi-ai/effort";
|
|
5
5
|
import { APP_NAME, CONFIG_DIR_NAME, logger } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
import { parseEffort } from "../thinking";
|
|
@@ -284,7 +284,7 @@ export function getExtraHelpText(): string {
|
|
|
284
284
|
${chalk.dim("# Search & Tools")}
|
|
285
285
|
EXA_API_KEY - Exa web search
|
|
286
286
|
BRAVE_API_KEY - Brave web search
|
|
287
|
-
PERPLEXITY_API_KEY - Perplexity web search (
|
|
287
|
+
PERPLEXITY_API_KEY - Perplexity web search API key (optional; anonymous fallback)
|
|
288
288
|
PERPLEXITY_COOKIES - Perplexity web search (session cookie)
|
|
289
289
|
TAVILY_API_KEY - Tavily web search
|
|
290
290
|
ANTHROPIC_SEARCH_API_KEY - Anthropic web search (override; isolates search from main ANTHROPIC_API_KEY)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Api,
|
|
3
|
+
ApiKeyResolver,
|
|
3
4
|
AssistantMessage,
|
|
4
5
|
AssistantMessageEvent,
|
|
5
6
|
AssistantMessageEventStream,
|
|
7
|
+
AuthCredentialSnapshotEntry,
|
|
6
8
|
Context,
|
|
7
9
|
Model,
|
|
8
10
|
OAuthAccess,
|
|
@@ -59,6 +61,12 @@ export interface DryBalanceAuthStorage {
|
|
|
59
61
|
options?: DryBalanceAuthOptions,
|
|
60
62
|
): Promise<OAuthAccess | undefined>;
|
|
61
63
|
getOAuthAccesses?(provider: string, options?: DryBalanceAuthOptions): Promise<OAuthAccessResolution[]>;
|
|
64
|
+
/**
|
|
65
|
+
* Force-refresh a single credential by id (step (b) of the auth-retry
|
|
66
|
+
* policy). The bench re-mints the failing account's token in place on a
|
|
67
|
+
* 401 rather than rotating accounts — it is measuring each account.
|
|
68
|
+
*/
|
|
69
|
+
forceRefreshCredentialById?(id: number, signal?: AbortSignal): Promise<AuthCredentialSnapshotEntry>;
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
export interface DryBalanceModelRegistry {
|
|
@@ -152,6 +160,8 @@ export interface DryBalanceDependencies {
|
|
|
152
160
|
now?: () => number;
|
|
153
161
|
stdoutIsTTY?: boolean;
|
|
154
162
|
stderrIsTTY?: boolean;
|
|
163
|
+
stdoutColumns?: number;
|
|
164
|
+
stderrColumns?: number;
|
|
155
165
|
}
|
|
156
166
|
|
|
157
167
|
type DryBalanceAttemptResult =
|
|
@@ -181,6 +191,7 @@ type DryBalanceBenchTarget =
|
|
|
181
191
|
ok: true;
|
|
182
192
|
account: string;
|
|
183
193
|
accessToken: string;
|
|
194
|
+
credentialId?: number;
|
|
184
195
|
}
|
|
185
196
|
| {
|
|
186
197
|
ok: false;
|
|
@@ -310,10 +321,11 @@ function renderBenchStatusLine(
|
|
|
310
321
|
}
|
|
311
322
|
}
|
|
312
323
|
|
|
313
|
-
function createBenchProgressSink(
|
|
324
|
+
export function createBenchProgressSink(
|
|
314
325
|
total: number,
|
|
315
326
|
write: (text: string) => void,
|
|
316
327
|
interactive: boolean,
|
|
328
|
+
columns: number,
|
|
317
329
|
): DryBalanceBenchProgressSink {
|
|
318
330
|
const statuses: DryBalanceBenchProgressStatus[] = Array.from({ length: total }, () => ({ state: "waiting" }));
|
|
319
331
|
if (!interactive) {
|
|
@@ -333,13 +345,21 @@ function createBenchProgressSink(
|
|
|
333
345
|
let frame = 0;
|
|
334
346
|
let lineCount = 0;
|
|
335
347
|
let timer: NodeJS.Timeout | undefined;
|
|
348
|
+
const width = Number.isFinite(columns) && columns > 0 ? Math.trunc(columns) : 80;
|
|
336
349
|
const render = (): void => {
|
|
337
350
|
const lines = [
|
|
338
351
|
chalk.bold("bench requests"),
|
|
339
352
|
...statuses.map((status, index) => renderBenchStatusLine(status, index, total, frame)),
|
|
340
353
|
];
|
|
341
|
-
|
|
342
|
-
|
|
354
|
+
// Anchor every redraw at column 0 and terminate each row with CRLF: a
|
|
355
|
+
// bare `\n` only returns to column 0 when the tty performs ONLCR
|
|
356
|
+
// translation, which is off whenever the terminal is in raw mode — there
|
|
357
|
+
// the old column-preserving cursor-up staircased each frame into
|
|
358
|
+
// scrollback. Cap each line to the terminal width so a wrapped row never
|
|
359
|
+
// desyncs the `\x1b[<n>A` cursor-up from the logical line count.
|
|
360
|
+
const move = lineCount > 0 ? `\x1b[${lineCount}A` : "";
|
|
361
|
+
const body = lines.map(line => `\x1b[2K${truncateToWidth(line, width)}`).join("\r\n");
|
|
362
|
+
write(`${move}\r${body}\r\n`);
|
|
343
363
|
lineCount = lines.length;
|
|
344
364
|
};
|
|
345
365
|
render();
|
|
@@ -370,13 +390,23 @@ function createBenchProgressSink(
|
|
|
370
390
|
async function runBenchRequest(
|
|
371
391
|
model: Model<Api>,
|
|
372
392
|
sessionId: string,
|
|
373
|
-
|
|
374
|
-
|
|
393
|
+
target: Extract<DryBalanceBenchTarget, { ok: true }>,
|
|
394
|
+
authStorage: DryBalanceAuthStorage,
|
|
375
395
|
streamFn: DryBalanceStreamSimple,
|
|
376
396
|
now: () => number,
|
|
377
397
|
): Promise<DryBalanceBenchResult> {
|
|
398
|
+
const { account, accessToken, credentialId } = target;
|
|
378
399
|
const startedAt = now();
|
|
379
400
|
let firstTokenAt: number | undefined;
|
|
401
|
+
// Re-mint the cached token on a 401: a peer/broker may have rotated it out
|
|
402
|
+
// from under our snapshot (Anthropic rotates refresh tokens on every use).
|
|
403
|
+
// The bench measures one account, so the switch step intentionally declines.
|
|
404
|
+
const apiKey: ApiKeyResolver = async ({ lastChance, error }) => {
|
|
405
|
+
if (error === undefined) return accessToken;
|
|
406
|
+
if (lastChance || credentialId === undefined || !authStorage.forceRefreshCredentialById) return undefined;
|
|
407
|
+
const refreshed = await authStorage.forceRefreshCredentialById(credentialId);
|
|
408
|
+
return refreshed.credential.type === "oauth" ? refreshed.credential.access : undefined;
|
|
409
|
+
};
|
|
380
410
|
try {
|
|
381
411
|
const context: Context = {
|
|
382
412
|
messages: [
|
|
@@ -389,7 +419,7 @@ async function runBenchRequest(
|
|
|
389
419
|
],
|
|
390
420
|
};
|
|
391
421
|
const stream = streamFn(model, context, {
|
|
392
|
-
apiKey
|
|
422
|
+
apiKey,
|
|
393
423
|
sessionId,
|
|
394
424
|
maxTokens: resolveBenchMaxTokens(model),
|
|
395
425
|
temperature: 0.2,
|
|
@@ -454,7 +484,7 @@ async function resolveBenchTargets(
|
|
|
454
484
|
seen.add(key);
|
|
455
485
|
const account = extractAccount(entry);
|
|
456
486
|
if (entry.ok) {
|
|
457
|
-
targets.push({ ok: true, account, accessToken: entry.accessToken });
|
|
487
|
+
targets.push({ ok: true, account, accessToken: entry.accessToken, credentialId: entry.credentialId });
|
|
458
488
|
} else {
|
|
459
489
|
targets.push({ ok: false, account, error: entry.error });
|
|
460
490
|
}
|
|
@@ -465,6 +495,7 @@ async function resolveBenchTargets(
|
|
|
465
495
|
async function runBenchTargets(
|
|
466
496
|
model: Model<Api>,
|
|
467
497
|
targets: DryBalanceBenchTarget[],
|
|
498
|
+
authStorage: DryBalanceAuthStorage,
|
|
468
499
|
randomSessionId: () => string,
|
|
469
500
|
progress: DryBalanceBenchProgressSink | undefined,
|
|
470
501
|
streamFn: DryBalanceStreamSimple,
|
|
@@ -482,14 +513,7 @@ async function runBenchTargets(
|
|
|
482
513
|
return result;
|
|
483
514
|
}
|
|
484
515
|
progress?.markRunning(index, target.account);
|
|
485
|
-
const result = await runBenchRequest(
|
|
486
|
-
model,
|
|
487
|
-
randomSessionId(),
|
|
488
|
-
target.account,
|
|
489
|
-
target.accessToken,
|
|
490
|
-
streamFn,
|
|
491
|
-
now,
|
|
492
|
-
);
|
|
516
|
+
const result = await runBenchRequest(model, randomSessionId(), target, authStorage, streamFn, now);
|
|
493
517
|
progress?.complete(index, result);
|
|
494
518
|
return result;
|
|
495
519
|
}),
|
|
@@ -792,8 +816,19 @@ export async function runDryBalanceCommand(
|
|
|
792
816
|
const progressInteractive = command.flags.json
|
|
793
817
|
? (deps.stderrIsTTY ?? process.stderr.isTTY === true)
|
|
794
818
|
: (deps.stdoutIsTTY ?? process.stdout.isTTY === true);
|
|
795
|
-
|
|
796
|
-
|
|
819
|
+
const progressColumns = command.flags.json
|
|
820
|
+
? (deps.stderrColumns ?? process.stderr.columns ?? 80)
|
|
821
|
+
: (deps.stdoutColumns ?? process.stdout.columns ?? 80);
|
|
822
|
+
progress = createBenchProgressSink(targets.length, progressWrite, progressInteractive, progressColumns);
|
|
823
|
+
benchResults = await runBenchTargets(
|
|
824
|
+
model,
|
|
825
|
+
targets,
|
|
826
|
+
runtime.modelRegistry.authStorage,
|
|
827
|
+
randomSessionId,
|
|
828
|
+
progress,
|
|
829
|
+
streamFn,
|
|
830
|
+
now,
|
|
831
|
+
);
|
|
797
832
|
results = targets.map(target =>
|
|
798
833
|
target.ok ? { ok: true, account: target.account } : { ok: false, reason: target.error },
|
|
799
834
|
);
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omp gallery` — render every built-in tool's renderer across its lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* For each tool with a registered renderer, the gallery drives a real
|
|
5
|
+
* {@link ToolExecutionComponent} through four states — streaming arguments,
|
|
6
|
+
* arguments complete (in progress), success, and failure — and prints the
|
|
7
|
+
* rendered output to stdout. It exists for visual QA of tool renderers without
|
|
8
|
+
* having to provoke each state through a live agent session.
|
|
9
|
+
*/
|
|
10
|
+
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
11
|
+
import type { TUI } from "@oh-my-pi/pi-tui";
|
|
12
|
+
import { getProjectDir } from "@oh-my-pi/pi-utils";
|
|
13
|
+
import { Settings } from "../config/settings";
|
|
14
|
+
import { ToolExecutionComponent } from "../modes/components/tool-execution";
|
|
15
|
+
import { initTheme, theme } from "../modes/theme/theme";
|
|
16
|
+
import { toolRenderers } from "../tools/renderers";
|
|
17
|
+
import { type GalleryFixture, type GalleryResult, galleryFixtures } from "./gallery-fixtures";
|
|
18
|
+
import { captureGalleryScreenshots } from "./gallery-screenshot";
|
|
19
|
+
|
|
20
|
+
/** Lifecycle states the gallery renders, in display order. */
|
|
21
|
+
export const GALLERY_STATES = ["streaming", "progress", "success", "error"] as const;
|
|
22
|
+
export type GalleryState = (typeof GALLERY_STATES)[number];
|
|
23
|
+
|
|
24
|
+
const STATE_LABELS: Record<GalleryState, string> = {
|
|
25
|
+
streaming: "streaming args",
|
|
26
|
+
progress: "in progress",
|
|
27
|
+
success: "done",
|
|
28
|
+
error: "failed",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export interface GalleryCommandArgs {
|
|
32
|
+
/** Render width in columns (defaults to terminal width, clamped). */
|
|
33
|
+
width?: number;
|
|
34
|
+
/** Restrict to a single tool name. */
|
|
35
|
+
tool?: string;
|
|
36
|
+
/** Restrict to specific lifecycle states. */
|
|
37
|
+
states?: GalleryState[];
|
|
38
|
+
/** Render the expanded variant of each renderer. */
|
|
39
|
+
expanded?: boolean;
|
|
40
|
+
/** Strip ANSI styling from the output (useful when redirecting to a file). */
|
|
41
|
+
plain?: boolean;
|
|
42
|
+
/** Capture the rendered gallery as PNG screenshot(s) via VHS instead of printing ANSI. */
|
|
43
|
+
screenshot?: boolean;
|
|
44
|
+
/** Screenshot output path (single image) or base path (suffixed when split across images). */
|
|
45
|
+
out?: string;
|
|
46
|
+
/** Font family for screenshots (must be installed; Nerd Font recommended for icon glyphs). */
|
|
47
|
+
font?: string;
|
|
48
|
+
/** Font size in points for screenshots. */
|
|
49
|
+
fontSize?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** One tool's rendered lifecycle, as ANSI lines: a leading blank, the section rule, then each state. */
|
|
53
|
+
export interface GallerySection {
|
|
54
|
+
heading: string;
|
|
55
|
+
lines: string[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const GENERIC_ERROR: GalleryResult = {
|
|
59
|
+
content: [{ type: "text", text: "Error: operation failed" }],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Build the fake `AgentTool` the component needs for its label, edit mode, and —
|
|
65
|
+
* for `customRendered` fixtures — the renderer functions that route it through
|
|
66
|
+
* the same custom-tool branch production uses (see {@link GalleryFixture}).
|
|
67
|
+
*/
|
|
68
|
+
function fakeToolFor(name: string, fixture: GalleryFixture | undefined): AgentTool | undefined {
|
|
69
|
+
if (!fixture?.label && !fixture?.editMode && !fixture?.customRendered) return undefined;
|
|
70
|
+
const tool: Record<string, unknown> = { name, label: fixture.label ?? name, mode: fixture.editMode };
|
|
71
|
+
if (fixture.customRendered) {
|
|
72
|
+
const renderer = toolRenderers[name] as
|
|
73
|
+
| { renderCall?: unknown; renderResult?: unknown; mergeCallAndResult?: unknown; inline?: unknown }
|
|
74
|
+
| undefined;
|
|
75
|
+
if (renderer) {
|
|
76
|
+
tool.renderCall = renderer.renderCall;
|
|
77
|
+
tool.renderResult = renderer.renderResult;
|
|
78
|
+
tool.mergeCallAndResult = renderer.mergeCallAndResult;
|
|
79
|
+
tool.inline = renderer.inline;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return tool as unknown as AgentTool;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** The curated fixture for a tool, or a generic one for registry tools lacking sample data. */
|
|
86
|
+
export function resolveFixture(name: string): GalleryFixture {
|
|
87
|
+
return (
|
|
88
|
+
galleryFixtures[name] ??
|
|
89
|
+
({
|
|
90
|
+
args: { note: `sample ${name} call` },
|
|
91
|
+
result: { content: [{ type: "text", text: `${name} completed` }] },
|
|
92
|
+
} satisfies GalleryFixture)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Render a single tool/state pair to lines. Builds a fresh component, drives it
|
|
98
|
+
* to the requested state, settles any async edit preview, then snapshots the
|
|
99
|
+
* render and stops all animation timers.
|
|
100
|
+
*/
|
|
101
|
+
export async function renderGalleryState(
|
|
102
|
+
name: string,
|
|
103
|
+
fixture: GalleryFixture,
|
|
104
|
+
state: GalleryState,
|
|
105
|
+
width: number,
|
|
106
|
+
expanded = false,
|
|
107
|
+
): Promise<string[]> {
|
|
108
|
+
const tool = fakeToolFor(name, fixture);
|
|
109
|
+
const streamingArgs = state === "streaming" ? (fixture.streamingArgs ?? fixture.args) : fixture.args;
|
|
110
|
+
// The component only calls `requestRender` during a static render;
|
|
111
|
+
// `imageBudget` is consulted solely when images render, which the gallery
|
|
112
|
+
// disables. A cast avoids constructing a real terminal.
|
|
113
|
+
const ui = { requestRender() {} } as unknown as TUI;
|
|
114
|
+
const component = new ToolExecutionComponent(name, streamingArgs, { showImages: false }, tool, ui, getProjectDir());
|
|
115
|
+
component.setExpanded(expanded);
|
|
116
|
+
|
|
117
|
+
if (state !== "streaming") {
|
|
118
|
+
component.setArgsComplete();
|
|
119
|
+
}
|
|
120
|
+
if (state === "success") {
|
|
121
|
+
component.updateResult(fixture.result, false);
|
|
122
|
+
} else if (state === "error") {
|
|
123
|
+
component.updateResult(fixture.errorResult ?? GENERIC_ERROR, false);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Edit-like renderers compute their diff preview off the render path; wait
|
|
127
|
+
// for it to settle so the snapshot is deterministic instead of racing a tick.
|
|
128
|
+
await component.whenPreviewSettled();
|
|
129
|
+
|
|
130
|
+
const lines = component.render(width);
|
|
131
|
+
component.stopAnimation();
|
|
132
|
+
return lines;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function resolveWidth(requested: number | undefined): number {
|
|
136
|
+
const fallback = process.stdout.columns ?? 100;
|
|
137
|
+
const width = requested ?? fallback;
|
|
138
|
+
return Math.max(40, Math.min(200, width));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function sectionRule(label: string, width: number): string {
|
|
142
|
+
const prefix = `── ${label} `;
|
|
143
|
+
const fill = Math.max(0, width - prefix.length);
|
|
144
|
+
return theme.fg("accent", theme.bold(`${prefix}${"─".repeat(fill)}`));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Render each requested tool's lifecycle into ANSI section blocks. The block
|
|
149
|
+
* layout (leading blank, section rule, then a blank + dim label + body per
|
|
150
|
+
* state) is shared by the stdout and screenshot paths so both stay identical.
|
|
151
|
+
*/
|
|
152
|
+
async function renderGallerySections(
|
|
153
|
+
names: string[],
|
|
154
|
+
states: GalleryState[],
|
|
155
|
+
width: number,
|
|
156
|
+
expanded: boolean,
|
|
157
|
+
): Promise<GallerySection[]> {
|
|
158
|
+
const sections: GallerySection[] = [];
|
|
159
|
+
for (const name of names) {
|
|
160
|
+
const fixture = resolveFixture(name);
|
|
161
|
+
const heading = fixture.label && fixture.label !== name ? `${name} — ${fixture.label}` : name;
|
|
162
|
+
const lines: string[] = ["", sectionRule(heading, width)];
|
|
163
|
+
for (const state of states) {
|
|
164
|
+
lines.push("", theme.fg("dim", ` · ${STATE_LABELS[state]}`));
|
|
165
|
+
try {
|
|
166
|
+
for (const line of await renderGalleryState(name, fixture, state, width, expanded)) lines.push(line);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
lines.push(theme.fg("error", ` render failed: ${String(err)}`));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
sections.push({ heading, lines });
|
|
172
|
+
}
|
|
173
|
+
return sections;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Render the gallery. Iterates the renderer registry (or a single tool),
|
|
178
|
+
* printing each requested lifecycle state under a labeled section — or, with
|
|
179
|
+
* `screenshot`, capturing the rendered output as PNG(s) via VHS.
|
|
180
|
+
*/
|
|
181
|
+
export async function runGalleryCommand(args: GalleryCommandArgs): Promise<void> {
|
|
182
|
+
const settingsInstance = await Settings.init();
|
|
183
|
+
// Screenshots must carry exact theme RGB regardless of how the invoking
|
|
184
|
+
// terminal advertises its color support, so force truecolor before the theme
|
|
185
|
+
// (and therefore every SGR escape it emits) is built.
|
|
186
|
+
if (args.screenshot) process.env.COLORTERM = "truecolor";
|
|
187
|
+
await initTheme(
|
|
188
|
+
false,
|
|
189
|
+
settingsInstance.get("symbolPreset"),
|
|
190
|
+
settingsInstance.get("colorBlindMode"),
|
|
191
|
+
settingsInstance.get("theme.dark"),
|
|
192
|
+
settingsInstance.get("theme.light"),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const width = resolveWidth(args.width);
|
|
196
|
+
const expanded = args.expanded ?? false;
|
|
197
|
+
const states = args.states && args.states.length > 0 ? args.states : [...GALLERY_STATES];
|
|
198
|
+
|
|
199
|
+
// Renderer-registry tools plus fixture-only tools (no dedicated renderer,
|
|
200
|
+
// e.g. `report_tool_issue` / custom extension tools) so the gallery covers
|
|
201
|
+
// the generic fallback + custom-tool branches too.
|
|
202
|
+
const allNames = Array.from(new Set([...Object.keys(toolRenderers), ...Object.keys(galleryFixtures)])).sort();
|
|
203
|
+
const names = args.tool ? allNames.filter(name => name === args.tool) : allNames;
|
|
204
|
+
if (args.tool && names.length === 0) {
|
|
205
|
+
process.stdout.write(`Unknown tool '${args.tool}'. Known tools: ${allNames.join(", ")}\n`);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const sections = await renderGallerySections(names, states, width, expanded);
|
|
210
|
+
|
|
211
|
+
if (args.screenshot) {
|
|
212
|
+
const paths = await captureGalleryScreenshots(sections, {
|
|
213
|
+
width,
|
|
214
|
+
font: args.font,
|
|
215
|
+
fontSize: args.fontSize,
|
|
216
|
+
out: args.out,
|
|
217
|
+
});
|
|
218
|
+
process.stdout.write(`${paths.join("\n")}\n`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const lines = sections.flatMap(section => section.lines);
|
|
223
|
+
lines.push("");
|
|
224
|
+
const text = lines.map(line => (args.plain ? Bun.stripANSI(line) : line)).join("\n");
|
|
225
|
+
process.stdout.write(`${text}\n`);
|
|
226
|
+
}
|