@oh-my-pi/pi-coding-agent 17.2.9 → 17.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/CHANGELOG.md +83 -0
- package/dist/{CHANGELOG-8yy8h3bc.md → CHANGELOG-d9xenpn9.md} +83 -0
- package/dist/cli.js +10208 -12596
- package/dist/types/capability/mcp.d.ts +11 -0
- package/dist/types/capability/skill.d.ts +6 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/command-help.d.ts +3 -0
- package/dist/types/commands/share.d.ts +25 -0
- package/dist/types/commit/agentic/index.d.ts +3 -1
- package/dist/types/commit/execute.d.ts +32 -0
- package/dist/types/commit/index.d.ts +2 -1
- package/dist/types/commit/pipeline.d.ts +7 -1
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/model-resolver.d.ts +13 -0
- package/dist/types/config/settings-schema.d.ts +1 -34
- package/dist/types/discovery/agent-plugin-format.d.ts +143 -0
- package/dist/types/discovery/agent-plugins.d.ts +1 -0
- package/dist/types/discovery/contained-path.d.ts +34 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +5 -5
- package/dist/types/extensibility/custom-tools/types.d.ts +3 -3
- package/dist/types/extensibility/extensions/loader.d.ts +9 -2
- package/dist/types/extensibility/extensions/types.d.ts +45 -8
- package/dist/types/extensibility/hooks/types.d.ts +5 -5
- package/dist/types/extensibility/shared-events.d.ts +3 -2
- package/dist/types/extensibility/skills.d.ts +5 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/main.d.ts +1 -1
- package/dist/types/mcp/transports/header-policy.d.ts +45 -0
- package/dist/types/mcp/types.d.ts +15 -0
- package/dist/types/modes/acp/acp-agent.d.ts +1 -1
- package/dist/types/modes/acp/acp-client-bridge.d.ts +1 -1
- package/dist/types/modes/acp/acp-event-mapper.d.ts +1 -1
- package/dist/types/modes/acp/acp-mode.d.ts +1 -1
- package/dist/types/modes/components/agent-hub-projection.d.ts +38 -0
- package/dist/types/modes/components/agent-hub-renderer.d.ts +41 -0
- package/dist/types/modes/components/agent-hub.d.ts +14 -5
- package/dist/types/modes/components/agent-transcript-viewer.d.ts +2 -0
- package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -2
- package/dist/types/modes/components/model-browser.d.ts +9 -1
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +8 -1
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +3 -2
- package/dist/types/registry/agent-registry.d.ts +47 -0
- package/dist/types/registry/persisted-agents.d.ts +3 -1
- package/dist/types/secrets/index.d.ts +23 -1
- package/dist/types/session/agent-session-events.d.ts +2 -2
- package/dist/types/session/agent-session.d.ts +4 -2
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/prewalk.d.ts +3 -1
- package/dist/types/session/session-entries.d.ts +10 -0
- package/dist/types/session/session-loader.d.ts +11 -1
- package/dist/types/session/session-manager.d.ts +9 -1
- package/dist/types/session/session-tools.d.ts +18 -1
- package/dist/types/session/turn-recovery.d.ts +7 -2
- package/dist/types/slash-commands/acp-builtins.d.ts +1 -1
- package/dist/types/slash-commands/available-commands.d.ts +1 -1
- package/dist/types/task/executor.d.ts +6 -0
- package/dist/types/task/index.d.ts +4 -3
- package/dist/types/task/read-only-policy.d.ts +3 -0
- package/dist/types/task/structured-subagent.d.ts +2 -0
- package/dist/types/task/types.d.ts +4 -0
- package/dist/types/tools/bash.d.ts +3 -3
- package/dist/types/tools/browser/launch.d.ts +2 -1
- package/dist/types/tools/browser/tab-worker.d.ts +2 -2
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read.d.ts +1 -5
- package/dist/types/tools/run-scope.d.ts +27 -1
- package/dist/types/tools/shell-tokenize.d.ts +16 -0
- package/dist/types/tools/terminal-output.d.ts +1 -1
- package/dist/types/utils/turndown.d.ts +1 -1
- package/dist/types/vibe/runtime.d.ts +2 -3
- package/dist/types/web/scrapers/readthedocs.d.ts +0 -3
- package/dist/types/web/search/providers/browser-headers.d.ts +2 -3
- package/examples/custom-tools/README.md +1 -1
- package/examples/extensions/README.md +1 -1
- package/examples/extensions/api-demo.ts +5 -6
- package/examples/extensions/chalk-logger.ts +1 -1
- package/examples/extensions/hello.ts +2 -2
- package/examples/extensions/reload-runtime.ts +1 -1
- package/examples/extensions/tools.ts +2 -2
- package/examples/extensions/with-deps/index.ts +1 -1
- package/examples/sdk/06-extensions.ts +1 -1
- package/package.json +15 -31
- package/scripts/bundle-dist.ts +1 -11
- package/scripts/legacy-pi-virtual-module.ts +4 -1
- package/src/advisor/runtime.ts +54 -0
- package/src/capability/mcp.ts +11 -0
- package/src/capability/skill.ts +6 -0
- package/src/cli/agents-cli.ts +1 -1
- package/src/cli/args.ts +24 -2
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/auth-gateway-cli.ts +1 -1
- package/src/cli/bench-cli.ts +1 -1
- package/src/cli/claude-trace-cli.ts +1 -1
- package/src/cli/command-help.ts +4 -0
- package/src/cli/config-cli.ts +1 -1
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/file-processor.ts +1 -1
- package/src/cli/flag-tables.ts +4 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/grep-cli.ts +1 -1
- package/src/cli/grievances-cli.ts +1 -1
- package/src/cli/help-extra.ts +1 -1
- package/src/cli/models-cli.ts +1 -1
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/read-cli.ts +1 -1
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli/shell-cli.ts +1 -1
- package/src/cli/ssh-cli.ts +1 -1
- package/src/cli/stats-cli.ts +1 -1
- package/src/cli/tiny-models-cli.ts +1 -1
- package/src/cli/ttsr-cli.ts +1 -1
- package/src/cli/update-cli.ts +1 -1
- package/src/cli/usage-cli.ts +1 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/cli/worktree-cli.ts +1 -1
- package/src/cli-commands.ts +5 -0
- package/src/commands/commit.ts +16 -3
- package/src/commands/say.ts +1 -1
- package/src/commands/share.ts +71 -0
- package/src/commands/token.ts +1 -1
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/agentic/index.ts +39 -21
- package/src/commit/cli.ts +1 -1
- package/src/commit/execute.ts +56 -0
- package/src/commit/index.ts +2 -1
- package/src/commit/pipeline.ts +20 -7
- package/src/config/model-discovery.ts +1 -1
- package/src/config/model-registry.ts +21 -1
- package/src/config/model-resolver.ts +54 -7
- package/src/config/settings-schema.ts +2 -33
- package/src/config/settings.ts +46 -0
- package/src/discovery/agent-plugin-format.ts +551 -0
- package/src/discovery/agent-plugins.ts +341 -0
- package/src/discovery/agents.ts +4 -2
- package/src/discovery/builtin-rules/ts-no-inline-cast-access.md +5 -4
- package/src/discovery/builtin-rules/ts-no-tiny-functions.md +1 -1
- package/src/discovery/claude-plugins.ts +21 -5
- package/src/discovery/contained-path.ts +78 -0
- package/src/discovery/helpers.ts +23 -9
- package/src/discovery/index.ts +1 -0
- package/src/discovery/omp-plugins.ts +20 -7
- package/src/eval/py/runner.py +38 -1
- package/src/exec/non-interactive-env.ts +1 -0
- package/src/extensibility/custom-commands/loader.ts +4 -4
- package/src/extensibility/custom-commands/types.ts +5 -5
- package/src/extensibility/custom-tools/loader.ts +4 -4
- package/src/extensibility/custom-tools/types.ts +3 -3
- package/src/extensibility/extensions/loader.ts +85 -20
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +51 -8
- package/src/extensibility/hooks/loader.ts +4 -5
- package/src/extensibility/hooks/types.ts +5 -5
- package/src/extensibility/plugins/legacy-pi-compat.ts +53 -0
- package/src/extensibility/plugins/marketplace/manager.ts +2 -1
- package/src/extensibility/shared-events.ts +3 -2
- package/src/extensibility/skills.ts +9 -0
- package/src/index.ts +2 -2
- package/src/internal-urls/memory-protocol.ts +5 -1
- package/src/internal-urls/skill-protocol.ts +14 -0
- package/src/internal-urls/vault-protocol.ts +2 -2
- package/src/launch/client.ts +11 -1
- package/src/launch/protocol.ts +7 -2
- package/src/launch/terminal-output.ts +1 -1
- package/src/main.ts +88 -23
- package/src/markit/converters/docx.ts +1 -1
- package/src/markit/converters/epub.ts +1 -1
- package/src/markit/converters/pptx.ts +1 -1
- package/src/markit/converters/xlsx.ts +1 -1
- package/src/mcp/config.ts +3 -0
- package/src/mcp/manager.ts +12 -9
- package/src/mcp/transports/header-policy.ts +95 -0
- package/src/mcp/transports/http.ts +35 -52
- package/src/mcp/transports/sse.ts +20 -27
- package/src/mcp/types.ts +15 -0
- package/src/modes/acp/acp-agent.ts +20 -9
- package/src/modes/acp/acp-client-bridge.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +1 -1
- package/src/modes/acp/acp-mode.ts +1 -1
- package/src/modes/components/agent-dashboard.ts +2 -0
- package/src/modes/components/agent-hub-projection.ts +248 -0
- package/src/modes/components/agent-hub-renderer.ts +194 -0
- package/src/modes/components/agent-hub.ts +674 -207
- package/src/modes/components/agent-transcript-viewer.ts +3 -0
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/chat-transcript-builder.ts +3 -0
- package/src/modes/components/custom-editor.ts +0 -9
- package/src/modes/components/extensions/inspector-panel.ts +11 -6
- package/src/modes/components/footer.ts +1 -3
- package/src/modes/components/model-browser.ts +11 -3
- package/src/modes/components/model-hub.ts +4 -1
- package/src/modes/components/status-line/component.ts +1 -0
- package/src/modes/components/status-line/segments.ts +10 -7
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/tool-execution.ts +13 -16
- package/src/modes/components/tree-selector.ts +62 -3
- package/src/modes/controllers/command-controller.ts +4 -1
- package/src/modes/controllers/event-controller.ts +44 -20
- package/src/modes/controllers/extension-ui-controller.ts +2 -2
- package/src/modes/controllers/input-controller.ts +20 -2
- package/src/modes/controllers/mcp-command-controller.ts +81 -20
- package/src/modes/controllers/selector-controller.ts +41 -49
- package/src/modes/controllers/streaming-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +13 -2
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -1
- package/src/modes/theme/theme.ts +2 -2
- package/src/modes/utils/transcript-render-helpers.ts +4 -2
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/prompts/tools/computer.md +1 -1
- package/src/registry/agent-lifecycle.ts +14 -7
- package/src/registry/agent-registry.ts +65 -2
- package/src/registry/persisted-agents.ts +341 -16
- package/src/sdk.ts +6 -49
- package/src/secrets/index.ts +52 -1
- package/src/session/agent-session-events.ts +2 -2
- package/src/session/agent-session.ts +54 -16
- package/src/session/messages.ts +1 -0
- package/src/session/prewalk.ts +57 -17
- package/src/session/session-context.ts +3 -5
- package/src/session/session-entries.ts +10 -0
- package/src/session/session-handoff.ts +5 -1
- package/src/session/session-listing.ts +1 -1
- package/src/session/session-loader.ts +74 -8
- package/src/session/session-manager.ts +22 -2
- package/src/session/session-paths.ts +57 -9
- package/src/session/session-tools.ts +65 -4
- package/src/session/todo-tracker.ts +11 -1
- package/src/session/turn-recovery.ts +96 -74
- package/src/slash-commands/acp-builtins.ts +1 -1
- package/src/slash-commands/available-commands.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +12 -8
- package/src/task/executor.ts +70 -20
- package/src/task/index.ts +30 -34
- package/src/task/isolation-runner.ts +24 -11
- package/src/task/persisted-revive.ts +12 -5
- package/src/task/read-only-policy.ts +27 -0
- package/src/task/structured-subagent.ts +14 -4
- package/src/task/types.ts +4 -0
- package/src/tools/auto-generated-guard.ts +1 -1
- package/src/tools/bash-interactive.ts +4 -4
- package/src/tools/bash-skill-urls.ts +15 -0
- package/src/tools/bash.ts +16 -17
- package/src/tools/browser/cmux/cmux-tab.ts +66 -18
- package/src/tools/browser/launch.ts +41 -12
- package/src/tools/browser/readable.ts +9 -9
- package/src/tools/browser/tab-supervisor.ts +12 -3
- package/src/tools/browser/tab-worker-entry.ts +1 -1
- package/src/tools/browser/tab-worker.ts +101 -12
- package/src/tools/debug.ts +1 -1
- package/src/tools/fetch.ts +1 -1
- package/src/tools/jtd-to-json-schema.ts +123 -21
- package/src/tools/path-utils.ts +9 -2
- package/src/tools/read.ts +21 -9
- package/src/tools/run-scope.ts +290 -4
- package/src/tools/shell-tokenize.ts +98 -0
- package/src/tools/terminal-output.ts +1 -1
- package/src/tools/todo.ts +1 -1
- package/src/utils/clipboard.ts +10 -2
- package/src/utils/external-editor.ts +4 -2
- package/src/utils/jj.ts +1 -1
- package/src/utils/turndown.ts +1 -2
- package/src/vibe/runtime.ts +5 -5
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +2 -1
- package/src/web/scrapers/twitter.ts +2 -2
- package/src/web/scrapers/types.ts +1 -1
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/search/providers/browser-headers.ts +12 -39
- package/src/web/search/providers/codex.ts +3 -26
- package/src/web/search/providers/ecosia.ts +1 -1
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/google.ts +1 -1
- package/src/web/search/providers/mojeek.ts +1 -1
- package/src/web/search/providers/startpage.ts +1 -1
- package/src/markit/converters/mammoth.d.ts +0 -24
|
@@ -3,7 +3,7 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
|
|
5
5
|
import { postmortem, Snowflake, untilAborted, withTimeout } from "@oh-my-pi/pi-utils";
|
|
6
|
-
import type { HTMLElement } from "
|
|
6
|
+
import type { HTMLElement } from "@oh-my-pi/pi-utils/dom";
|
|
7
7
|
import type {
|
|
8
8
|
Browser,
|
|
9
9
|
CDPSession,
|
|
@@ -23,10 +23,15 @@ import { formatScreenshot } from "../render-utils";
|
|
|
23
23
|
import {
|
|
24
24
|
bindRunFacade,
|
|
25
25
|
CELL_BUDGET_SLACK_MS,
|
|
26
|
+
installBrowserWorkerRejectionGuard,
|
|
27
|
+
isBrowserRunOwnedRejection,
|
|
28
|
+
markBrowserRunRejection,
|
|
26
29
|
markHandled,
|
|
30
|
+
observeBrowserRunPromise,
|
|
27
31
|
resolvePredicateTimeout,
|
|
28
32
|
type WaitPredicateOptions,
|
|
29
33
|
waitForRun,
|
|
34
|
+
withBrowserPromiseCombinatorTracking,
|
|
30
35
|
} from "../run-scope";
|
|
31
36
|
import { ToolAbortError, ToolError, throwIfAborted } from "../tool-errors";
|
|
32
37
|
import {
|
|
@@ -44,6 +49,7 @@ import {
|
|
|
44
49
|
loadPuppeteerInWorker,
|
|
45
50
|
} from "./launch";
|
|
46
51
|
import { extractReadableFromHtml, type ReadableFormat } from "./readable";
|
|
52
|
+
|
|
47
53
|
import { cloneSafe, RunOutput } from "./run-output";
|
|
48
54
|
import type {
|
|
49
55
|
Observation,
|
|
@@ -701,6 +707,9 @@ interface ActiveRun {
|
|
|
701
707
|
output: RunOutput;
|
|
702
708
|
screenshots: ScreenshotResult[];
|
|
703
709
|
pendingTools: Map<string, { resolve(value: unknown): void; reject(error: Error): void }>;
|
|
710
|
+
rejectionOwner: object;
|
|
711
|
+
floatingRejections: unknown[];
|
|
712
|
+
floatingFailure: { promise: Promise<never>; reject(reason?: unknown): void };
|
|
704
713
|
/** Helper invocations currently awaiting the page/network, keyed by op id. */
|
|
705
714
|
inflight: Map<number, InflightOp>;
|
|
706
715
|
opCounter: number;
|
|
@@ -748,17 +757,75 @@ export class WorkerCore {
|
|
|
748
757
|
#active: ActiveRun | null = null;
|
|
749
758
|
#runtime: JsRuntime | null = null;
|
|
750
759
|
#unsub: () => void;
|
|
760
|
+
#isolated: boolean;
|
|
761
|
+
#uninstallRejectionGuard: () => void;
|
|
751
762
|
#mode?: WorkerInitPayload["mode"];
|
|
752
763
|
#activateForScreenshot = true;
|
|
753
764
|
#dialogPolicy?: DialogPolicy;
|
|
754
765
|
#dialogHandler?: (dialog: Dialog) => void;
|
|
755
766
|
#openDialog?: OpenDialogInfo;
|
|
756
767
|
|
|
757
|
-
constructor(transport: Transport) {
|
|
768
|
+
constructor(transport: Transport, isolated: boolean) {
|
|
758
769
|
this.#transport = transport;
|
|
770
|
+
this.#isolated = isolated;
|
|
759
771
|
this.#unsub = this.#transport.onMessage(msg => {
|
|
760
772
|
void this.#handleMessage(msg as WorkerInbound);
|
|
761
773
|
});
|
|
774
|
+
this.#uninstallRejectionGuard = this.#installRejectionGuard();
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
#installRejectionGuard(): () => void {
|
|
778
|
+
if (!this.#isolated) {
|
|
779
|
+
return postmortem.interceptUnhandledRejections(reason => this.#consumeUnhandledRejection(reason));
|
|
780
|
+
}
|
|
781
|
+
return installBrowserWorkerRejectionGuard(reason => this.#consumeUnhandledRejection(reason));
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
#consumeUnhandledRejection(reason: unknown): boolean {
|
|
785
|
+
const active = this.#active;
|
|
786
|
+
if (!active) return false;
|
|
787
|
+
if (!isBrowserRunOwnedRejection(reason, active.rejectionOwner, `browser-run-${active.id}.js`)) return false;
|
|
788
|
+
this.#recordFloatingRejection(active, reason);
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
#recordFloatingRejection(active: ActiveRun, reason: unknown): void {
|
|
793
|
+
if (postmortem.isExpectedCleanupError(reason)) return;
|
|
794
|
+
if (this.#active !== active) {
|
|
795
|
+
this.#log("warn", "Unhandled rejection after browser run ended", {
|
|
796
|
+
runId: active.id,
|
|
797
|
+
error: reason instanceof Error ? reason.message : String(reason),
|
|
798
|
+
});
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
const isFirst = active.floatingRejections.length === 0;
|
|
802
|
+
active.floatingRejections.push(reason);
|
|
803
|
+
if (isFirst) active.floatingFailure.reject(this.#floatingRejectionError(reason));
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
#floatingRejectionError(reason: unknown): Error {
|
|
807
|
+
const message = reason instanceof Error ? reason.message : String(reason);
|
|
808
|
+
const error = new Error(`Unhandled rejection (missing await?): ${message}`, { cause: reason });
|
|
809
|
+
if (reason instanceof Error) error.name = reason.name;
|
|
810
|
+
return error;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
#foldFloatingRejections(active: ActiveRun, failure: { error: unknown } | undefined): { error: unknown } | undefined {
|
|
814
|
+
const rejections = active.floatingRejections;
|
|
815
|
+
if (rejections.length === 0) return failure;
|
|
816
|
+
let reported = rejections;
|
|
817
|
+
if (!failure) {
|
|
818
|
+
failure = { error: this.#floatingRejectionError(rejections[0]) };
|
|
819
|
+
reported = rejections.slice(1);
|
|
820
|
+
} else if (failure.error instanceof Error && failure.error.cause === rejections[0]) {
|
|
821
|
+
reported = rejections.slice(1);
|
|
822
|
+
}
|
|
823
|
+
for (const reason of reported) {
|
|
824
|
+
this.#log("warn", "Additional unhandled browser-run rejection", {
|
|
825
|
+
error: reason instanceof Error ? reason.message : String(reason),
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
return failure;
|
|
762
829
|
}
|
|
763
830
|
|
|
764
831
|
nextElementId(): number {
|
|
@@ -973,6 +1040,7 @@ export class WorkerCore {
|
|
|
973
1040
|
const signal = AbortSignal.any([timeoutSignal, ac.signal, runAc.signal]);
|
|
974
1041
|
const output = new RunOutput();
|
|
975
1042
|
const screenshots: ScreenshotResult[] = [];
|
|
1043
|
+
const floatingFailure = Promise.withResolvers<never>();
|
|
976
1044
|
const active: ActiveRun = {
|
|
977
1045
|
id: msg.id,
|
|
978
1046
|
ac,
|
|
@@ -980,6 +1048,9 @@ export class WorkerCore {
|
|
|
980
1048
|
output,
|
|
981
1049
|
screenshots,
|
|
982
1050
|
pendingTools: new Map(),
|
|
1051
|
+
rejectionOwner: {},
|
|
1052
|
+
floatingRejections: [],
|
|
1053
|
+
floatingFailure,
|
|
983
1054
|
inflight: new Map(),
|
|
984
1055
|
opCounter: 0,
|
|
985
1056
|
};
|
|
@@ -995,10 +1066,11 @@ export class WorkerCore {
|
|
|
995
1066
|
const tabApi = this.#createTabApi(msg.name, msg.timeoutMs, signal, msg.session, output, screenshots, active);
|
|
996
1067
|
const runtime = this.#ensureRuntime(msg.session);
|
|
997
1068
|
runtime.setCwd(msg.session.cwd);
|
|
1069
|
+
const onFloatingRejection = (reason: unknown): void => this.#recordFloatingRejection(active, reason);
|
|
998
1070
|
runtime.setRunScope({
|
|
999
|
-
page: bindRunFacade(runPage.page, signal),
|
|
1000
|
-
browser: bindRunFacade(browser, signal),
|
|
1001
|
-
tab: bindRunFacade(tabApi, signal),
|
|
1071
|
+
page: bindRunFacade(runPage.page, signal, active.rejectionOwner, onFloatingRejection),
|
|
1072
|
+
browser: bindRunFacade(browser, signal, active.rejectionOwner, onFloatingRejection),
|
|
1073
|
+
tab: bindRunFacade(tabApi, signal, active.rejectionOwner, onFloatingRejection),
|
|
1002
1074
|
assert: (cond: unknown, text?: string): void => {
|
|
1003
1075
|
if (!cond) throw new ToolError(text ?? "Assertion failed");
|
|
1004
1076
|
},
|
|
@@ -1010,10 +1082,12 @@ export class WorkerCore {
|
|
|
1010
1082
|
typeof msOrPredicate === "number"
|
|
1011
1083
|
? undefined
|
|
1012
1084
|
: { timeout: resolvePredicateTimeout(msg.timeoutMs, opts?.timeout), interval: opts?.interval };
|
|
1013
|
-
return
|
|
1085
|
+
return observeBrowserRunPromise(
|
|
1014
1086
|
this.#runOp(active, label, signal, Number.POSITIVE_INFINITY, sig =>
|
|
1015
1087
|
waitForRun(msOrPredicate, sig, resolved),
|
|
1016
1088
|
),
|
|
1089
|
+
active.rejectionOwner,
|
|
1090
|
+
onFloatingRejection,
|
|
1017
1091
|
);
|
|
1018
1092
|
},
|
|
1019
1093
|
});
|
|
@@ -1051,10 +1125,19 @@ export class WorkerCore {
|
|
|
1051
1125
|
try {
|
|
1052
1126
|
const hooks = this.#hooksForActiveRun();
|
|
1053
1127
|
if (!hooks) throw new ToolError("Browser runtime started without an active run");
|
|
1054
|
-
returnValue = await
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1128
|
+
returnValue = await withBrowserPromiseCombinatorTracking(
|
|
1129
|
+
active.rejectionOwner,
|
|
1130
|
+
onFloatingRejection,
|
|
1131
|
+
async () =>
|
|
1132
|
+
await Promise.race([
|
|
1133
|
+
runtime.run(msg.code, `browser-run-${msg.id}.js`, hooks, {
|
|
1134
|
+
runId: msg.id,
|
|
1135
|
+
cwd: msg.session.cwd,
|
|
1136
|
+
}),
|
|
1137
|
+
cancelRejection,
|
|
1138
|
+
floatingFailure.promise,
|
|
1139
|
+
]),
|
|
1140
|
+
);
|
|
1058
1141
|
completed = true;
|
|
1059
1142
|
} finally {
|
|
1060
1143
|
signal.removeEventListener("abort", onCancel);
|
|
@@ -1063,11 +1146,13 @@ export class WorkerCore {
|
|
|
1063
1146
|
failure = { error };
|
|
1064
1147
|
} finally {
|
|
1065
1148
|
runAc.abort(postmortem.markExpectedCleanupError(new ToolAbortError("Browser run ended")));
|
|
1149
|
+
await Bun.sleep(0);
|
|
1066
1150
|
try {
|
|
1067
1151
|
await runPage?.cleanup();
|
|
1068
1152
|
} catch (error) {
|
|
1069
1153
|
failure = { error };
|
|
1070
1154
|
}
|
|
1155
|
+
failure = this.#foldFloatingRejections(active, failure);
|
|
1071
1156
|
if (this.#active?.id === msg.id) this.#active = null;
|
|
1072
1157
|
}
|
|
1073
1158
|
if (failure) {
|
|
@@ -1182,9 +1267,12 @@ export class WorkerCore {
|
|
|
1182
1267
|
(opTimeout?.aborted || (err instanceof Error && err.name === "TimeoutError"))
|
|
1183
1268
|
) {
|
|
1184
1269
|
const hint = selector ? await this.#selectorTimeoutHint(selector) : "";
|
|
1185
|
-
throw
|
|
1270
|
+
throw markBrowserRunRejection(
|
|
1271
|
+
new ToolError(`${label} timed out after ${perOpTimeoutMs}ms${hint}`),
|
|
1272
|
+
active.rejectionOwner,
|
|
1273
|
+
);
|
|
1186
1274
|
}
|
|
1187
|
-
throw err;
|
|
1275
|
+
throw markBrowserRunRejection(err, active.rejectionOwner);
|
|
1188
1276
|
} finally {
|
|
1189
1277
|
earlyAc.abort();
|
|
1190
1278
|
active.inflight.delete(opId);
|
|
@@ -1868,6 +1956,7 @@ export class WorkerCore {
|
|
|
1868
1956
|
|
|
1869
1957
|
async #close(): Promise<void> {
|
|
1870
1958
|
this.#unsub();
|
|
1959
|
+
this.#uninstallRejectionGuard();
|
|
1871
1960
|
this.#clearElementCache();
|
|
1872
1961
|
const page = this.#page;
|
|
1873
1962
|
if (this.#dialogHandler && page && !page.isClosed()) page.off("dialog", this.#dialogHandler);
|
package/src/tools/debug.ts
CHANGED
|
@@ -505,7 +505,7 @@ const ADAPTER_UNAVAILABLE_MESSAGES: Readonly<Record<string, string>> = {
|
|
|
505
505
|
dlv: "adapter 'dlv' is not available: install with 'go install github.com/go-delve/delve/cmd/dlv@latest'",
|
|
506
506
|
rdbg: "adapter 'rdbg' is not available: install with 'gem install debug'",
|
|
507
507
|
"js-debug-adapter":
|
|
508
|
-
"adapter 'js-debug-adapter' is not available:
|
|
508
|
+
"adapter 'js-debug-adapter' is not available: download it from https://github.com/microsoft/vscode-js-debug",
|
|
509
509
|
};
|
|
510
510
|
|
|
511
511
|
const ADAPTER_CANONICAL_COMMANDS: Readonly<Record<string, string>> = {
|
package/src/tools/fetch.ts
CHANGED
|
@@ -516,7 +516,7 @@ function cleanFeedText(text: string): string {
|
|
|
516
516
|
* Parse RSS/Atom feed to markdown
|
|
517
517
|
*/
|
|
518
518
|
async function parseFeedToMarkdown(content: string, maxItems = 10): Promise<string> {
|
|
519
|
-
const { parseHTML } = await import("
|
|
519
|
+
const { parseHTML } = await import("@oh-my-pi/pi-utils/dom");
|
|
520
520
|
try {
|
|
521
521
|
const doc = parseHTML(content).document;
|
|
522
522
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @see https://datatracker.ietf.org/doc/html/rfc8927
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import { isRecord } from "@oh-my-pi/pi-utils";
|
|
11
12
|
import type { JTDPrimitive } from "./jtd-utils.js";
|
|
12
13
|
import {
|
|
13
14
|
isJTDDiscriminator,
|
|
@@ -134,6 +135,18 @@ function convertSchema(schema: unknown): unknown {
|
|
|
134
135
|
return {};
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
const jtdOnlyPrimitiveTypes: Record<string, true> = {
|
|
139
|
+
timestamp: true,
|
|
140
|
+
float32: true,
|
|
141
|
+
float64: true,
|
|
142
|
+
int8: true,
|
|
143
|
+
uint8: true,
|
|
144
|
+
int16: true,
|
|
145
|
+
uint16: true,
|
|
146
|
+
int32: true,
|
|
147
|
+
uint32: true,
|
|
148
|
+
};
|
|
149
|
+
|
|
137
150
|
/**
|
|
138
151
|
* Detect if a schema is JTD format (vs JSON Schema).
|
|
139
152
|
*
|
|
@@ -155,11 +168,8 @@ export function isJTDSchema(schema: unknown): boolean {
|
|
|
155
168
|
if ("ref" in obj) return true;
|
|
156
169
|
|
|
157
170
|
// JTD type primitives (JSON Schema doesn't have int32, float64, etc.)
|
|
158
|
-
if (
|
|
159
|
-
|
|
160
|
-
if (jtdPrimitives.includes(obj.type as string)) {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
171
|
+
if (typeof obj.type === "string" && Object.hasOwn(jtdOnlyPrimitiveTypes, obj.type)) {
|
|
172
|
+
return true;
|
|
163
173
|
}
|
|
164
174
|
|
|
165
175
|
// JTD properties form without type: "object" (JSON Schema requires it)
|
|
@@ -170,36 +180,128 @@ export function isJTDSchema(schema: unknown): boolean {
|
|
|
170
180
|
return false;
|
|
171
181
|
}
|
|
172
182
|
|
|
173
|
-
function
|
|
174
|
-
if (schema
|
|
175
|
-
|
|
183
|
+
function isUnambiguousJTDSchema(schema: unknown): boolean {
|
|
184
|
+
if (!isRecord(schema)) return false;
|
|
185
|
+
|
|
186
|
+
if (isRecord(schema.elements) || isRecord(schema.values) || isRecord(schema.optionalProperties)) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
if (typeof schema.ref === "string") return true;
|
|
190
|
+
if (typeof schema.type === "string" && Object.hasOwn(jtdOnlyPrimitiveTypes, schema.type)) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (typeof schema.discriminator !== "string" || !isRecord(schema.mapping)) {
|
|
194
|
+
return false;
|
|
176
195
|
}
|
|
177
196
|
|
|
178
|
-
|
|
179
|
-
|
|
197
|
+
for (const key in schema.mapping) {
|
|
198
|
+
if (!Object.hasOwn(schema.mapping, key)) continue;
|
|
199
|
+
const mapping = schema.mapping[key];
|
|
200
|
+
if (!isRecord(mapping)) return false;
|
|
201
|
+
|
|
202
|
+
let hasSchemaProperties = false;
|
|
203
|
+
if (Object.hasOwn(mapping, "properties")) {
|
|
204
|
+
if (!isRecord(mapping.properties)) return false;
|
|
205
|
+
hasSchemaProperties = true;
|
|
206
|
+
}
|
|
207
|
+
if (Object.hasOwn(mapping, "optionalProperties")) {
|
|
208
|
+
if (!isRecord(mapping.optionalProperties)) return false;
|
|
209
|
+
hasSchemaProperties = true;
|
|
210
|
+
}
|
|
211
|
+
if (!hasSchemaProperties) return false;
|
|
180
212
|
}
|
|
181
213
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function normalizeJsonSchemaArray(value: unknown): unknown {
|
|
218
|
+
if (!Array.isArray(value)) return value;
|
|
219
|
+
|
|
220
|
+
let normalized: unknown[] | undefined;
|
|
221
|
+
for (let index = 0; index < value.length; index++) {
|
|
222
|
+
const item = value[index];
|
|
223
|
+
const converted = normalizeJsonSchemaNode(item);
|
|
224
|
+
if (converted === item) continue;
|
|
225
|
+
normalized ??= value.slice();
|
|
226
|
+
normalized[index] = converted;
|
|
227
|
+
}
|
|
228
|
+
return normalized ?? value;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function normalizeJsonSchemaMap(value: unknown): unknown {
|
|
232
|
+
if (!isRecord(value)) return value;
|
|
233
|
+
|
|
234
|
+
let normalized: Record<string, unknown> | undefined;
|
|
235
|
+
for (const key in value) {
|
|
236
|
+
if (!Object.hasOwn(value, key)) continue;
|
|
237
|
+
const item = value[key];
|
|
238
|
+
const converted = normalizeJsonSchemaNode(item);
|
|
239
|
+
if (converted === item) continue;
|
|
240
|
+
normalized ??= { ...value };
|
|
241
|
+
normalized[key] = converted;
|
|
188
242
|
}
|
|
243
|
+
return normalized ?? value;
|
|
244
|
+
}
|
|
189
245
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
246
|
+
function normalizeJsonSchemaNode(schema: unknown): unknown {
|
|
247
|
+
if (!isRecord(schema)) return schema;
|
|
248
|
+
if (isUnambiguousJTDSchema(schema)) return convertSchema(schema);
|
|
249
|
+
|
|
250
|
+
let normalized: Record<string, unknown> | undefined;
|
|
251
|
+
for (const key in schema) {
|
|
252
|
+
if (!Object.hasOwn(schema, key)) continue;
|
|
253
|
+
|
|
254
|
+
const value = schema[key];
|
|
255
|
+
let converted: unknown;
|
|
256
|
+
switch (key) {
|
|
257
|
+
case "not":
|
|
258
|
+
case "if":
|
|
259
|
+
case "then":
|
|
260
|
+
case "else":
|
|
261
|
+
case "items":
|
|
262
|
+
case "contains":
|
|
263
|
+
case "propertyNames":
|
|
264
|
+
case "additionalProperties":
|
|
265
|
+
case "unevaluatedProperties":
|
|
266
|
+
case "unevaluatedItems":
|
|
267
|
+
case "contentSchema":
|
|
268
|
+
converted = normalizeJsonSchemaNode(value);
|
|
269
|
+
break;
|
|
270
|
+
case "allOf":
|
|
271
|
+
case "anyOf":
|
|
272
|
+
case "oneOf":
|
|
273
|
+
case "prefixItems":
|
|
274
|
+
converted = normalizeJsonSchemaArray(value);
|
|
275
|
+
break;
|
|
276
|
+
case "properties":
|
|
277
|
+
case "patternProperties":
|
|
278
|
+
case "$defs":
|
|
279
|
+
case "definitions":
|
|
280
|
+
case "dependentSchemas":
|
|
281
|
+
converted = normalizeJsonSchemaMap(value);
|
|
282
|
+
break;
|
|
283
|
+
default:
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (converted === value) continue;
|
|
288
|
+
normalized ??= { ...schema };
|
|
289
|
+
normalized[key] = converted;
|
|
193
290
|
}
|
|
194
291
|
|
|
195
|
-
return normalized;
|
|
292
|
+
return normalized ?? schema;
|
|
196
293
|
}
|
|
294
|
+
|
|
197
295
|
/**
|
|
198
296
|
* Convert JTD schema to JSON Schema.
|
|
199
297
|
* If already JSON Schema, returns as-is.
|
|
200
298
|
*/
|
|
201
299
|
export function jtdToJsonSchema(schema: unknown): unknown {
|
|
202
|
-
|
|
300
|
+
if (isJTDSchema(schema)) {
|
|
301
|
+
// convertSchema is recursive; re-walking its JSON Schema output caused #1345.
|
|
302
|
+
return convertSchema(schema);
|
|
303
|
+
}
|
|
304
|
+
return normalizeJsonSchemaNode(schema);
|
|
203
305
|
}
|
|
204
306
|
|
|
205
307
|
/**
|
package/src/tools/path-utils.ts
CHANGED
|
@@ -816,10 +816,18 @@ async function tryDelimitedPathSplit(
|
|
|
816
816
|
export async function splitDelimitedPathEntry(
|
|
817
817
|
entry: string,
|
|
818
818
|
cwd: string,
|
|
819
|
-
options: {
|
|
819
|
+
options: {
|
|
820
|
+
splitter?: PathEntrySplitter;
|
|
821
|
+
routedUrlPredicate?: (entry: string) => boolean;
|
|
822
|
+
} = {},
|
|
820
823
|
): Promise<string[] | null> {
|
|
821
824
|
const normalizedEntry = normalizePathLikeInput(entry);
|
|
822
825
|
if (!hasTopLevelPathDelimiter(normalizedEntry)) return null;
|
|
826
|
+
const splitter = options.splitter ?? parseSearchPath;
|
|
827
|
+
if (options.routedUrlPredicate?.(normalizedEntry)) {
|
|
828
|
+
const parts = await tryDelimitedPathSplit(normalizedEntry, cwd, splitter, "semicolon", "none");
|
|
829
|
+
return parts?.every(options.routedUrlPredicate) ? parts : null;
|
|
830
|
+
}
|
|
823
831
|
if (isInternalUrlPath(normalizedEntry)) return null;
|
|
824
832
|
// A real POSIX file may contain the delimiter and a selector-shaped tail
|
|
825
833
|
// (`a;b:1-2`, `a b:1-2`). Preserve the raw entry whenever the full literal
|
|
@@ -827,7 +835,6 @@ export async function splitDelimitedPathEntry(
|
|
|
827
835
|
// splitters see it before delimiter expansion peels or splits (issue #4618
|
|
828
836
|
// reviewer feedback: delimited expansion ran before the literal check).
|
|
829
837
|
if ((await probeLiteralPathExists(normalizedEntry, cwd)) !== "missing") return null;
|
|
830
|
-
const splitter = options.splitter ?? parseSearchPath;
|
|
831
838
|
const peeledEntry = splitPathAndSel(normalizedEntry).path;
|
|
832
839
|
if (!hasGlobPathChars(peeledEntry) && (await delimitedPathPartResolves(normalizedEntry, cwd, splitter))) {
|
|
833
840
|
return null;
|
package/src/tools/read.ts
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
readImageMetadata,
|
|
27
27
|
untilAborted,
|
|
28
28
|
} from "@oh-my-pi/pi-utils";
|
|
29
|
-
import { LRUCache } from "
|
|
29
|
+
import { LRUCache } from "@oh-my-pi/pi-utils/lru";
|
|
30
30
|
import {
|
|
31
31
|
canonicalSnapshotKey,
|
|
32
32
|
getFileSnapshotStore,
|
|
@@ -721,6 +721,10 @@ const readSchema = type({
|
|
|
721
721
|
),
|
|
722
722
|
});
|
|
723
723
|
|
|
724
|
+
const readSchemaWithoutMemory = type({
|
|
725
|
+
path: type("string").describe("Local path, internal URI (e.g. skill://), or URL. Inline selectors are supported."),
|
|
726
|
+
});
|
|
727
|
+
|
|
724
728
|
export type ReadToolInput = typeof readSchema.infer;
|
|
725
729
|
|
|
726
730
|
export interface ReadToolDetails {
|
|
@@ -866,7 +870,9 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
866
870
|
readonly label = "Read";
|
|
867
871
|
readonly loadMode = "essential";
|
|
868
872
|
description: string;
|
|
869
|
-
|
|
873
|
+
get parameters(): typeof readSchema {
|
|
874
|
+
return this.session.settings.get("memory.backend") === "off" ? readSchemaWithoutMemory : readSchema;
|
|
875
|
+
}
|
|
870
876
|
readonly strict = true;
|
|
871
877
|
|
|
872
878
|
readonly #autoResizeImages: boolean;
|
|
@@ -962,8 +968,9 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
962
968
|
async #tryReadDelimitedPaths(
|
|
963
969
|
readPath: string,
|
|
964
970
|
signal?: AbortSignal,
|
|
971
|
+
routedUrlPredicate?: (entry: string) => boolean,
|
|
965
972
|
): Promise<AgentToolResult<ReadToolDetails> | null> {
|
|
966
|
-
const parts = await splitDelimitedPathEntry(readPath, this.session.cwd);
|
|
973
|
+
const parts = await splitDelimitedPathEntry(readPath, this.session.cwd, { routedUrlPredicate });
|
|
967
974
|
if (!parts) return null;
|
|
968
975
|
|
|
969
976
|
const notice = `Note: interpreted as ${parts.length} paths: ${parts.join(", ")}`;
|
|
@@ -2306,9 +2313,13 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
2306
2313
|
}
|
|
2307
2314
|
|
|
2308
2315
|
// Handle native OMP URLs and custom-scheme resources advertised by MCP servers.
|
|
2309
|
-
// Use the internal-URL-aware splitter so malformed selectors are peeled
|
|
2310
|
-
// off the URL and surfaced via parseSel rather than confusing handlers.
|
|
2311
2316
|
const internalRouter = InternalUrlRouter.instance();
|
|
2317
|
+
const delimitedInternalResult = internalRouter.canResolve(readPath)
|
|
2318
|
+
? await this.#tryReadDelimitedPaths(readPath, signal, entry => internalRouter.canResolve(entry))
|
|
2319
|
+
: null;
|
|
2320
|
+
if (delimitedInternalResult) return delimitedInternalResult;
|
|
2321
|
+
|
|
2322
|
+
// Peel malformed selectors through the internal-URL-aware parser before routing.
|
|
2312
2323
|
let promotedSelector: string | undefined;
|
|
2313
2324
|
if (internalRouter.canResolve(readPath)) {
|
|
2314
2325
|
const internalTarget = splitInternalUrlSel(readPath);
|
|
@@ -2486,6 +2497,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
2486
2497
|
const imageMetadata = await readImageMetadata(absolutePath);
|
|
2487
2498
|
const mimeType = imageMetadata?.mimeType;
|
|
2488
2499
|
const ext = path.extname(absolutePath).toLowerCase();
|
|
2500
|
+
const resolvedDisplayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
|
|
2489
2501
|
const shouldConvertWithMarkit = CONVERTIBLE_EXTENSIONS.has(ext);
|
|
2490
2502
|
|
|
2491
2503
|
// Profiler reports (macOS `sample` call trees, V8 `.cpuprofile` JSON):
|
|
@@ -2530,7 +2542,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
2530
2542
|
fileSize,
|
|
2531
2543
|
}));
|
|
2532
2544
|
} else if (isNotebookPath(absolutePath) && !isRawSelector(parsed)) {
|
|
2533
|
-
const notebookText = await readEditableNotebookText(absolutePath,
|
|
2545
|
+
const notebookText = await readEditableNotebookText(absolutePath, resolvedDisplayPath);
|
|
2534
2546
|
if (isMultiRange(parsed) && parsed.kind === "lines") {
|
|
2535
2547
|
return this.#buildInMemoryMultiRangeResult(notebookText, parsed.ranges, {
|
|
2536
2548
|
details: { resolvedPath: absolutePath },
|
|
@@ -2549,7 +2561,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
2549
2561
|
const result = await convertFileWithMarkit(absolutePath, signal);
|
|
2550
2562
|
if (result.ok) {
|
|
2551
2563
|
const renderedContent =
|
|
2552
|
-
ext === ".pdf" ? rewritePdfImagePlaceholders(result.content,
|
|
2564
|
+
ext === ".pdf" ? rewritePdfImagePlaceholders(result.content, resolvedDisplayPath) : result.content;
|
|
2553
2565
|
// Route the converted markdown through the in-memory text builder
|
|
2554
2566
|
// so line-range selectors (`file.pdf:50-100`, `:5-16,40-80`) and
|
|
2555
2567
|
// raw mode apply against the converted output. Without this,
|
|
@@ -2592,7 +2604,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
2592
2604
|
return toolResult<ReadToolDetails>({ resolvedPath: absolutePath, suffixResolution })
|
|
2593
2605
|
.text(
|
|
2594
2606
|
prependSuffixResolutionNotice(
|
|
2595
|
-
`[Cannot read binary file '${
|
|
2607
|
+
`[Cannot read binary file '${resolvedDisplayPath}' (${formatBytes(fileSize)}); not valid UTF-8 text. Use ':raw' to read bytes verbatim.]`,
|
|
2596
2608
|
suffixResolution,
|
|
2597
2609
|
),
|
|
2598
2610
|
)
|
|
@@ -2609,7 +2621,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
2609
2621
|
if (summary?.parsed && summary.elided) {
|
|
2610
2622
|
const renderedSummary = this.#renderSummary(summary);
|
|
2611
2623
|
const footer = formatSummaryElisionFooter(
|
|
2612
|
-
|
|
2624
|
+
resolvedDisplayPath,
|
|
2613
2625
|
renderedSummary.elidedRanges,
|
|
2614
2626
|
renderedSummary.elidedLines,
|
|
2615
2627
|
);
|