@oh-my-pi/pi-coding-agent 17.2.4 → 17.2.6
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 +69 -0
- package/dist/{CHANGELOG-bpmhv26t.md → CHANGELOG-gs76k6wc.md} +69 -0
- package/dist/cli.js +4438 -3962
- package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
- package/dist/types/cli/args.d.ts +4 -1
- package/dist/types/cli/browser-relay-cli.d.ts +15 -0
- package/dist/types/cli/command-help.d.ts +99 -0
- package/dist/types/cli/gc-cli.d.ts +1 -0
- package/dist/types/cli/help-extra.d.ts +2 -0
- package/dist/types/cli/thinking-levels.d.ts +5 -0
- package/dist/types/cli/update-cli.d.ts +13 -0
- package/dist/types/commands/browser-relay.d.ts +38 -0
- package/dist/types/commands/commit.d.ts +3 -0
- package/dist/types/commands/complete.d.ts +1 -1
- package/dist/types/commands/completions.d.ts +6 -0
- package/dist/types/commands/grep.d.ts +3 -0
- package/dist/types/commands/join.d.ts +4 -0
- package/dist/types/commands/launch-help.d.ts +171 -0
- package/dist/types/commands/launch.d.ts +5 -1
- package/dist/types/commands/models.d.ts +3 -0
- package/dist/types/commands/say.d.ts +10 -0
- package/dist/types/commands/worktree.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/model-discovery.d.ts +2 -2
- package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/models-config.d.ts +1 -0
- package/dist/types/config/service-tier.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +69 -21
- package/dist/types/cursor-bridge-tools.d.ts +1 -1
- package/dist/types/cursor.d.ts +7 -4
- package/dist/types/edit/index.d.ts +3 -3
- package/dist/types/edit/modes/replace.d.ts +22 -15
- package/dist/types/edit/renderer.d.ts +1 -1
- package/dist/types/eval/py/kernel.d.ts +3 -1
- package/dist/types/eval/py/spawn-options.d.ts +12 -16
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
- package/dist/types/launch/broker.d.ts +1 -1
- package/dist/types/launch/client.d.ts +15 -4
- package/dist/types/launch/ensure.d.ts +8 -0
- package/dist/types/launch/paths.d.ts +1 -1
- package/dist/types/launch/protocol.d.ts +19 -2
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/lsp/mux/daemon.d.ts +15 -0
- package/dist/types/lsp/mux/protocol.d.ts +57 -0
- package/dist/types/lsp/mux/server.d.ts +18 -0
- package/dist/types/lsp/types.d.ts +22 -2
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mnemopi/embed-client.d.ts +1 -1
- package/dist/types/mnemopi/state.d.ts +0 -23
- package/dist/types/modes/components/assistant-message.d.ts +2 -0
- package/dist/types/modes/components/btw-panel.d.ts +3 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +2 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +5 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/modes/workflow.d.ts +2 -1
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/security/contracts/schemas.d.ts +405 -403
- package/dist/types/session/agent-session-types.d.ts +8 -1
- package/dist/types/session/agent-session.d.ts +26 -2
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/launch-completion.d.ts +10 -0
- package/dist/types/session/session-advisors.d.ts +1 -1
- package/dist/types/session/session-context.d.ts +2 -1
- package/dist/types/session/session-entries.d.ts +15 -1
- package/dist/types/session/session-maintenance.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +23 -11
- package/dist/types/session/session-stats.d.ts +10 -0
- package/dist/types/session/session-storage.d.ts +15 -3
- package/dist/types/session/yield-queue.d.ts +6 -1
- package/dist/types/system-prompt.d.ts +4 -1
- package/dist/types/task/index.d.ts +2 -1
- package/dist/types/task/spawn-policy.d.ts +5 -0
- package/dist/types/thinking.d.ts +1 -7
- package/dist/types/tools/ast-grep.d.ts +1 -1
- package/dist/types/tools/browser/registry.d.ts +2 -1
- package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
- package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
- package/dist/types/tools/browser/relay/kind.d.ts +19 -0
- package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
- package/dist/types/tools/browser/relay/server.d.ts +35 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -0
- package/dist/types/tools/computer/exposure.d.ts +9 -7
- package/dist/types/tools/computer/protocol.d.ts +70 -17
- package/dist/types/tools/computer/supervisor.d.ts +23 -10
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +42 -7
- package/dist/types/tools/computer-renderer.d.ts +7 -5
- package/dist/types/tools/computer.d.ts +25 -44
- package/dist/types/tools/context.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +1 -1
- package/dist/types/tools/grep.d.ts +1 -1
- package/dist/types/tools/index.d.ts +9 -0
- package/dist/types/tools/render-utils.d.ts +2 -0
- package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
- package/dist/types/tools/tool-timeouts.d.ts +5 -0
- package/dist/types/tools/xdev.d.ts +8 -0
- package/dist/types/utils/clipboard.d.ts +2 -2
- package/dist/types/web/kagi.d.ts +1 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/providers/anthropic.d.ts +1 -0
- package/dist/types/web/search/providers/base.d.ts +2 -0
- package/dist/types/web/search/providers/brave.d.ts +1 -0
- package/dist/types/web/search/providers/browser-page.d.ts +1 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -0
- package/dist/types/web/search/providers/exa.d.ts +1 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
- package/dist/types/web/search/providers/gemini.d.ts +1 -0
- package/dist/types/web/search/providers/jina.d.ts +1 -0
- package/dist/types/web/search/providers/kagi.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -0
- package/dist/types/web/search/providers/parallel.d.ts +1 -0
- package/dist/types/web/search/providers/perplexity.d.ts +1 -0
- package/dist/types/web/search/providers/searxng.d.ts +1 -0
- package/dist/types/web/search/providers/tavily.d.ts +1 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
- package/dist/types/web/search/providers/utils.d.ts +6 -9
- package/dist/types/web/search/providers/zai.d.ts +1 -0
- package/dist/types/web/search/types.d.ts +4 -0
- package/package.json +12 -12
- package/src/cli/args.ts +7 -87
- package/src/cli/browser-relay-cli.ts +119 -0
- package/src/cli/command-help.ts +103 -0
- package/src/cli/completion-gen.ts +5 -5
- package/src/cli/flag-tables.ts +9 -0
- package/src/cli/gc-cli.ts +641 -21
- package/src/cli/help-extra.ts +89 -0
- package/src/cli/setup-cli.ts +13 -21
- package/src/cli/thinking-levels.ts +7 -0
- package/src/cli/update-cli.ts +26 -7
- package/src/cli-commands.ts +170 -33
- package/src/cli.ts +17 -5
- package/src/commands/acp.ts +3 -1
- package/src/commands/agents.ts +3 -2
- package/src/commands/auth-broker.ts +3 -2
- package/src/commands/auth-gateway.ts +3 -2
- package/src/commands/bench.ts +2 -3
- package/src/commands/browser-relay.ts +53 -0
- package/src/commands/cleanse.ts +2 -2
- package/src/commands/commit.ts +3 -2
- package/src/commands/complete.ts +2 -1
- package/src/commands/completions.ts +3 -2
- package/src/commands/config.ts +3 -2
- package/src/commands/dry-balance.ts +2 -2
- package/src/commands/gallery.ts +3 -2
- package/src/commands/gc.ts +3 -2
- package/src/commands/grep.ts +3 -2
- package/src/commands/grievances.ts +3 -2
- package/src/commands/install.ts +2 -2
- package/src/commands/join.ts +3 -2
- package/src/commands/launch-help.ts +116 -0
- package/src/commands/launch.ts +7 -191
- package/src/commands/models.ts +3 -2
- package/src/commands/plugin.ts +3 -2
- package/src/commands/read.ts +3 -2
- package/src/commands/say.ts +3 -2
- package/src/commands/setup.ts +3 -2
- package/src/commands/shell.ts +3 -2
- package/src/commands/ssh.ts +3 -2
- package/src/commands/stats.ts +3 -2
- package/src/commands/tiny-models.ts +2 -2
- package/src/commands/token.ts +2 -2
- package/src/commands/ttsr.ts +2 -2
- package/src/commands/update.ts +3 -2
- package/src/commands/usage.ts +3 -2
- package/src/commands/web-search.ts +3 -2
- package/src/commands/worktree.ts +3 -2
- package/src/config/keybindings.ts +5 -0
- package/src/config/model-discovery.ts +44 -27
- package/src/config/model-registry.ts +19 -13
- package/src/config/models-config-schema-bundle.ts +9 -0
- package/src/config/resolve-config-value.ts +2 -1
- package/src/config/service-tier.ts +5 -0
- package/src/config/settings-schema.ts +72 -20
- package/src/config/settings.ts +1 -1
- package/src/cursor-bridge-tools.ts +1 -1
- package/src/cursor.ts +10 -14
- package/src/edit/diff.ts +17 -8
- package/src/edit/index.ts +20 -7
- package/src/edit/modes/replace.ts +93 -40
- package/src/edit/renderer.ts +1 -1
- package/src/edit/streaming.ts +14 -17
- package/src/eval/py/kernel.ts +2 -1
- package/src/eval/py/spawn-options.ts +24 -29
- package/src/export/html/index.ts +10 -3
- package/src/export/html/template.js +8 -26
- package/src/export/share.ts +4 -0
- package/src/extensibility/extensions/wrapper.ts +1 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
- package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
- package/src/extensibility/skills.ts +11 -0
- package/src/extensibility/utils.ts +10 -2
- package/src/launch/broker.ts +223 -7
- package/src/launch/client.ts +192 -21
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +1 -1
- package/src/launch/protocol.ts +54 -2
- package/src/lsp/client.ts +23 -2
- package/src/lsp/index.ts +8 -0
- package/src/lsp/mux/daemon.ts +348 -0
- package/src/lsp/mux/protocol.ts +96 -0
- package/src/lsp/mux/server.ts +797 -0
- package/src/lsp/types.ts +28 -2
- package/src/main.ts +20 -8
- package/src/mcp/config-writer.ts +1 -1
- package/src/mcp/oauth-flow.ts +11 -1
- package/src/mnemopi/embed-client.ts +49 -2
- package/src/mnemopi/state.ts +57 -23
- package/src/modes/components/assistant-message.ts +11 -0
- package/src/modes/components/btw-panel.ts +41 -4
- package/src/modes/components/chat-transcript-builder.ts +4 -0
- package/src/modes/components/custom-editor.ts +9 -0
- package/src/modes/components/read-tool-group.ts +10 -0
- package/src/modes/components/status-line/component.ts +1 -1
- package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
- package/src/modes/components/tool-execution.ts +8 -0
- package/src/modes/components/tree-selector.ts +46 -48
- package/src/modes/controllers/btw-controller.ts +55 -7
- package/src/modes/controllers/command-controller.ts +31 -0
- package/src/modes/controllers/event-controller.ts +17 -0
- package/src/modes/controllers/input-controller.ts +63 -8
- package/src/modes/controllers/mcp-command-controller.ts +11 -5
- package/src/modes/controllers/selector-controller.ts +20 -0
- package/src/modes/interactive-mode.ts +18 -2
- package/src/modes/types.ts +9 -1
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/interactive-context-helpers.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +6 -10
- package/src/modes/workflow.ts +8 -2
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/session/launch-completion.md +1 -0
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +26 -52
- package/src/prompts/system/workflow-notice.md +3 -3
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/computer.md +21 -21
- package/src/prompts/tools/glob.md +1 -1
- package/src/prompts/tools/grep.md +1 -1
- package/src/prompts/tools/replace.md +5 -4
- package/src/prompts/tools/task.md +4 -4
- package/src/sdk.ts +49 -6
- package/src/secrets/index.ts +1 -1
- package/src/security/contracts/schemas.ts +205 -183
- package/src/security/contracts/validation.ts +5 -1
- package/src/security/store.ts +2 -2
- package/src/session/agent-session-types.ts +9 -1
- package/src/session/agent-session.ts +204 -15
- package/src/session/indexed-session-storage.ts +9 -0
- package/src/session/launch-completion.ts +37 -0
- package/src/session/prewalk.ts +24 -2
- package/src/session/session-advisors.ts +2 -2
- package/src/session/session-context.ts +42 -12
- package/src/session/session-dump-format.ts +1 -1
- package/src/session/session-entries.ts +17 -1
- package/src/session/session-maintenance.ts +38 -4
- package/src/session/session-manager.ts +123 -67
- package/src/session/session-paths.ts +118 -55
- package/src/session/session-stats.ts +48 -3
- package/src/session/session-storage.ts +30 -22
- package/src/session/stream-guards.ts +1 -1
- package/src/session/yield-queue.ts +121 -16
- package/src/slash-commands/builtin-registry.ts +37 -24
- package/src/system-prompt.ts +8 -3
- package/src/task/index.ts +23 -8
- package/src/task/spawn-policy.ts +14 -0
- package/src/thinking.ts +2 -8
- package/src/tools/ast-grep.ts +10 -4
- package/src/tools/browser/cmux/cmux-tab.ts +97 -14
- package/src/tools/browser/cmux/rpc.ts +2 -8
- package/src/tools/browser/registry.ts +53 -2
- package/src/tools/browser/relay/bridge.ts +945 -0
- package/src/tools/browser/relay/daemon.ts +117 -0
- package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
- package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
- package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
- package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
- package/src/tools/browser/relay/kind.ts +41 -0
- package/src/tools/browser/relay/protocol.ts +54 -0
- package/src/tools/browser/relay/server.ts +141 -0
- package/src/tools/browser/render.ts +4 -1
- package/src/tools/browser/shared-daemon.ts +7 -58
- package/src/tools/browser/tab-supervisor.ts +5 -4
- package/src/tools/browser/tab-worker.ts +33 -12
- package/src/tools/browser.ts +26 -1
- package/src/tools/computer/exposure.ts +11 -35
- package/src/tools/computer/protocol.ts +51 -10
- package/src/tools/computer/supervisor.ts +227 -124
- package/src/tools/computer/worker-entry.ts +11 -6
- package/src/tools/computer/worker.ts +695 -81
- package/src/tools/computer-renderer.ts +104 -65
- package/src/tools/computer.ts +134 -428
- package/src/tools/context.ts +3 -0
- package/src/tools/glob.ts +9 -2
- package/src/tools/grep.ts +12 -6
- package/src/tools/hub/launch.ts +122 -6
- package/src/tools/index.ts +9 -0
- package/src/tools/inspect-image.ts +32 -6
- package/src/tools/render-utils.ts +2 -0
- package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/xdev.ts +29 -2
- package/src/utils/clipboard.ts +40 -14
- package/src/utils/command-args.ts +26 -28
- package/src/utils/tool-choice.ts +0 -13
- package/src/web/kagi.ts +2 -1
- package/src/web/search/index.ts +18 -2
- package/src/web/search/providers/anthropic.ts +4 -1
- package/src/web/search/providers/base.ts +2 -0
- package/src/web/search/providers/brave.ts +3 -1
- package/src/web/search/providers/browser-page.ts +6 -4
- package/src/web/search/providers/codex.ts +4 -1
- package/src/web/search/providers/duckduckgo.ts +2 -1
- package/src/web/search/providers/ecosia.ts +2 -1
- package/src/web/search/providers/exa.ts +4 -2
- package/src/web/search/providers/firecrawl.ts +3 -1
- package/src/web/search/providers/gemini.ts +8 -2
- package/src/web/search/providers/google.ts +2 -1
- package/src/web/search/providers/jina.ts +12 -2
- package/src/web/search/providers/kagi.ts +3 -0
- package/src/web/search/providers/kimi.ts +5 -1
- package/src/web/search/providers/mojeek.ts +2 -1
- package/src/web/search/providers/parallel.ts +5 -1
- package/src/web/search/providers/perplexity.ts +6 -3
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/searxng.ts +11 -5
- package/src/web/search/providers/startpage.ts +10 -4
- package/src/web/search/providers/synthetic.ts +11 -5
- package/src/web/search/providers/tavily.ts +3 -1
- package/src/web/search/providers/tinyfish.ts +3 -1
- package/src/web/search/providers/utils.ts +12 -10
- package/src/web/search/providers/xai.ts +2 -2
- package/src/web/search/providers/zai.ts +18 -3
- package/src/web/search/types.ts +6 -0
- package/dist/types/config/file-lock.d.ts +0 -29
- package/src/config/file-lock.ts +0 -164
|
@@ -24,7 +24,7 @@ interface BrowserRenderArgs {
|
|
|
24
24
|
code?: string;
|
|
25
25
|
all?: boolean;
|
|
26
26
|
kill?: boolean;
|
|
27
|
-
app?: { path?: string; cdp_url?: string; target?: string; cmux?: boolean; surface?: string };
|
|
27
|
+
app?: { path?: string; cdp_url?: string; relay?: boolean; target?: string; cmux?: boolean; surface?: string };
|
|
28
28
|
viewport?: { width: number; height: number; scale?: number };
|
|
29
29
|
timeout?: number;
|
|
30
30
|
}
|
|
@@ -39,6 +39,7 @@ function describeBrowser(args: BrowserRenderArgs, details: BrowserToolDetails |
|
|
|
39
39
|
if (cdpUrl) return `connected ${cdpUrl}`;
|
|
40
40
|
const appPath = typeof args.app?.path === "string" ? args.app.path : "";
|
|
41
41
|
if (appPath) return `spawned ${shortenPath(appPath)}`;
|
|
42
|
+
if (args.app?.relay) return "relay";
|
|
42
43
|
if (args.app?.cmux !== false && (args.app?.cmux === true || args.app?.surface)) {
|
|
43
44
|
return args.app.surface ? `cmux ${args.app.surface}` : "cmux";
|
|
44
45
|
}
|
|
@@ -49,6 +50,8 @@ function describeBrowser(args: BrowserRenderArgs, details: BrowserToolDetails |
|
|
|
49
50
|
return "spawned";
|
|
50
51
|
case "connected":
|
|
51
52
|
return "connected";
|
|
53
|
+
case "relay":
|
|
54
|
+
return "relay";
|
|
52
55
|
case "cmux":
|
|
53
56
|
return "cmux";
|
|
54
57
|
default:
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
import * as fs from "node:fs/promises";
|
|
12
12
|
import * as path from "node:path";
|
|
13
13
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
14
|
-
import {
|
|
14
|
+
import { daemonClientForProject } from "../../launch/client";
|
|
15
|
+
import { describeQuietly, stopQuietly, waitReady } from "../../launch/ensure";
|
|
15
16
|
import { daemonRuntimeDir } from "../../launch/paths";
|
|
16
17
|
import type { DaemonSnapshot } from "../../launch/protocol";
|
|
17
18
|
import { throwIfAborted } from "../tool-errors";
|
|
@@ -20,7 +21,6 @@ import { resolveSharedBrowserLaunchSpec } from "./launch";
|
|
|
20
21
|
/** Chrome prints this on stderr once the CDP listener is up; the broker's ready probe captures the line. */
|
|
21
22
|
const READY_LOG_PATTERN = String.raw`DevTools listening on ws://\S+`;
|
|
22
23
|
const READY_TIMEOUT_MS = 30_000;
|
|
23
|
-
const STOP_TIMEOUT_MS = 5_000;
|
|
24
24
|
const PROBE_TIMEOUT_MS = 1_500;
|
|
25
25
|
/** describe→start rounds before giving up; bounds cross-process start races and wedged-Chrome replacement. */
|
|
26
26
|
const ENSURE_ATTEMPTS = 3;
|
|
@@ -59,58 +59,6 @@ async function probeEndpoint(wsEndpoint: string): Promise<boolean> {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
/** Snapshot the daemon, treating "unknown daemon" as absent. */
|
|
63
|
-
async function describeQuietly(
|
|
64
|
-
client: DaemonBrokerClient,
|
|
65
|
-
name: string,
|
|
66
|
-
signal?: AbortSignal,
|
|
67
|
-
): Promise<DaemonSnapshot | undefined> {
|
|
68
|
-
try {
|
|
69
|
-
const result = await client.request({ op: "describe", name }, signal);
|
|
70
|
-
return result.op === "describe" ? result.daemon : undefined;
|
|
71
|
-
} catch (error) {
|
|
72
|
-
throwIfAborted(signal);
|
|
73
|
-
logger.debug("Shared browser describe failed", {
|
|
74
|
-
name,
|
|
75
|
-
error: error instanceof Error ? error.message : String(error),
|
|
76
|
-
});
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** Block until the daemon reports ready; undefined on timeout or pre-ready exit. */
|
|
82
|
-
async function waitReady(
|
|
83
|
-
client: DaemonBrokerClient,
|
|
84
|
-
name: string,
|
|
85
|
-
signal?: AbortSignal,
|
|
86
|
-
): Promise<DaemonSnapshot | undefined> {
|
|
87
|
-
try {
|
|
88
|
-
const result = await client.request({ op: "wait", name, for: "ready", timeoutMs: READY_TIMEOUT_MS }, signal);
|
|
89
|
-
if (result.op !== "wait" || result.timedOut) return undefined;
|
|
90
|
-
return result.daemon;
|
|
91
|
-
} catch (error) {
|
|
92
|
-
throwIfAborted(signal);
|
|
93
|
-
logger.debug("Shared browser ready wait failed", {
|
|
94
|
-
name,
|
|
95
|
-
error: error instanceof Error ? error.message : String(error),
|
|
96
|
-
});
|
|
97
|
-
return undefined;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** Best-effort stop before replacing a wedged or endpoint-less daemon. */
|
|
102
|
-
async function stopQuietly(client: DaemonBrokerClient, name: string, signal?: AbortSignal): Promise<void> {
|
|
103
|
-
try {
|
|
104
|
-
await client.request({ op: "stop", name, timeoutMs: STOP_TIMEOUT_MS }, signal);
|
|
105
|
-
} catch (error) {
|
|
106
|
-
throwIfAborted(signal);
|
|
107
|
-
logger.debug("Shared browser stop failed", {
|
|
108
|
-
name,
|
|
109
|
-
error: error instanceof Error ? error.message : String(error),
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
62
|
/**
|
|
115
63
|
* Ensure the project-shared automation Chromium is running and reachable,
|
|
116
64
|
* launching it under the daemon broker when needed. Idempotent across
|
|
@@ -139,16 +87,17 @@ export async function ensureSharedBrowser(opts: {
|
|
|
139
87
|
await fs.mkdir(userDataDir, { recursive: true });
|
|
140
88
|
for (let attempt = 0; attempt < ENSURE_ATTEMPTS; attempt++) {
|
|
141
89
|
throwIfAborted(opts.signal);
|
|
142
|
-
const existing = await describeQuietly(client, name, opts.signal);
|
|
90
|
+
const existing = await describeQuietly(client, name, "Shared browser", opts.signal);
|
|
143
91
|
if (existing && existing.state !== "exited" && existing.state !== "failed") {
|
|
144
|
-
const settled =
|
|
92
|
+
const settled =
|
|
93
|
+
existing.readyAt !== undefined ? existing : await waitReady(client, name, "Shared browser", opts.signal);
|
|
145
94
|
const wsEndpoint = wsEndpointOf(settled);
|
|
146
95
|
if (wsEndpoint && (await probeEndpoint(wsEndpoint))) {
|
|
147
96
|
return { wsEndpoint, daemonName: name, projectDir: client.projectDir };
|
|
148
97
|
}
|
|
149
98
|
// Live record but unreachable Chrome (wedged, or readiness never
|
|
150
99
|
// matched): replace it rather than handing out a dead endpoint.
|
|
151
|
-
await stopQuietly(client, name, opts.signal);
|
|
100
|
+
await stopQuietly(client, name, "Shared browser", opts.signal);
|
|
152
101
|
continue;
|
|
153
102
|
}
|
|
154
103
|
try {
|
|
@@ -175,7 +124,7 @@ export async function ensureSharedBrowser(opts: {
|
|
|
175
124
|
if (wsEndpoint && (await probeEndpoint(wsEndpoint))) {
|
|
176
125
|
return { wsEndpoint, daemonName: name, projectDir: client.projectDir };
|
|
177
126
|
}
|
|
178
|
-
await stopQuietly(client, name, opts.signal);
|
|
127
|
+
await stopQuietly(client, name, "Shared browser", opts.signal);
|
|
179
128
|
} catch (error) {
|
|
180
129
|
throwIfAborted(opts.signal);
|
|
181
130
|
// Lost a cross-process start race ("already starting/ready"); the next
|
|
@@ -698,10 +698,11 @@ async function buildInitPayload(browser: PuppeteerBrowserHandle, opts: AcquireTa
|
|
|
698
698
|
timeoutMs: opts.timeoutMs,
|
|
699
699
|
};
|
|
700
700
|
}
|
|
701
|
-
//
|
|
702
|
-
// visible tab and avoid raising it before screenshots. An explicit
|
|
703
|
-
// be backgrounded, so retain activation
|
|
704
|
-
const
|
|
701
|
+
// Connected and relay browsers are user-driven. When no target is requested,
|
|
702
|
+
// adopt the visible tab and avoid raising it before screenshots. An explicit
|
|
703
|
+
// target may be backgrounded, so retain activation for target-correct pixels.
|
|
704
|
+
const userDriven = browser.kind.kind === "connected" || browser.kind.kind === "relay";
|
|
705
|
+
const activateForScreenshot = !userDriven || !shouldPreserveConnectedBrowserFocus(opts.target);
|
|
705
706
|
const page = await pickElectronTarget(browser.browser, {
|
|
706
707
|
matcher: opts.target,
|
|
707
708
|
preferVisible: !activateForScreenshot,
|
|
@@ -20,6 +20,14 @@ import { JsRuntime, type RuntimeHooks } from "../../eval/js/shared/runtime";
|
|
|
20
20
|
import { resizeImage } from "../../utils/image-resize";
|
|
21
21
|
import { resolveToCwd } from "../path-utils";
|
|
22
22
|
import { formatScreenshot } from "../render-utils";
|
|
23
|
+
import {
|
|
24
|
+
bindRunFacade,
|
|
25
|
+
CELL_BUDGET_SLACK_MS,
|
|
26
|
+
markHandled,
|
|
27
|
+
resolvePredicateTimeout,
|
|
28
|
+
type WaitPredicateOptions,
|
|
29
|
+
waitForRun,
|
|
30
|
+
} from "../run-scope";
|
|
23
31
|
import { ToolAbortError, ToolError, throwIfAborted } from "../tool-errors";
|
|
24
32
|
import {
|
|
25
33
|
type AriaSnapshotOptions,
|
|
@@ -36,14 +44,6 @@ import {
|
|
|
36
44
|
loadPuppeteerInWorker,
|
|
37
45
|
} from "./launch";
|
|
38
46
|
import { extractReadableFromHtml, type ReadableFormat } from "./readable";
|
|
39
|
-
import {
|
|
40
|
-
bindBrowserRunFacade,
|
|
41
|
-
CELL_BUDGET_SLACK_MS,
|
|
42
|
-
markHandled,
|
|
43
|
-
resolvePredicateTimeout,
|
|
44
|
-
type WaitPredicateOptions,
|
|
45
|
-
waitForBrowserRun,
|
|
46
|
-
} from "./run-cancellation";
|
|
47
47
|
import { cloneSafe, RunOutput } from "./run-output";
|
|
48
48
|
import type {
|
|
49
49
|
Observation,
|
|
@@ -827,6 +827,7 @@ export class WorkerCore {
|
|
|
827
827
|
const page = await target.page();
|
|
828
828
|
if (!page) throw new ToolError(`Target ${payload.targetId} is no longer available on the attached browser`);
|
|
829
829
|
this.#page = page;
|
|
830
|
+
await this.#claimRelayTarget(page);
|
|
830
831
|
this.#observeDialogs();
|
|
831
832
|
if (payload.dialogs) this.#applyDialogPolicy(payload.dialogs);
|
|
832
833
|
if (payload.url) {
|
|
@@ -853,6 +854,26 @@ export class WorkerCore {
|
|
|
853
854
|
throw new ToolError(`Target ${targetId} is no longer available on the attached browser`);
|
|
854
855
|
}
|
|
855
856
|
|
|
857
|
+
/**
|
|
858
|
+
* Tell the omp browser relay this worker drives the adopted page, so the
|
|
859
|
+
* relay adds it to the per-window "omp" tab group. Best-effort: plain CDP
|
|
860
|
+
* backends (real Chrome, cmux) reject the relay-private method.
|
|
861
|
+
*/
|
|
862
|
+
async #claimRelayTarget(page: Page): Promise<void> {
|
|
863
|
+
let session: CDPSession | undefined;
|
|
864
|
+
try {
|
|
865
|
+
session = await page.createCDPSession();
|
|
866
|
+
// Puppeteer's protocol map cannot express the relay-private method; the
|
|
867
|
+
// send signature is otherwise identical.
|
|
868
|
+
const raw = session as unknown as { send(method: string): Promise<unknown> };
|
|
869
|
+
await raw.send("OMP.claimTarget");
|
|
870
|
+
} catch {
|
|
871
|
+
// Not the omp relay; nothing to claim.
|
|
872
|
+
} finally {
|
|
873
|
+
await session?.detach().catch(() => undefined);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
856
877
|
/**
|
|
857
878
|
* Best-effort unblocking of a wedged target during post-timeout recovery: dismiss any
|
|
858
879
|
* open JS dialog and stop a pending navigation over a raw CDP session (created on the
|
|
@@ -975,9 +996,9 @@ export class WorkerCore {
|
|
|
975
996
|
const runtime = this.#ensureRuntime(msg.session);
|
|
976
997
|
runtime.setCwd(msg.session.cwd);
|
|
977
998
|
runtime.setRunScope({
|
|
978
|
-
page:
|
|
979
|
-
browser:
|
|
980
|
-
tab:
|
|
999
|
+
page: bindRunFacade(runPage.page, signal),
|
|
1000
|
+
browser: bindRunFacade(browser, signal),
|
|
1001
|
+
tab: bindRunFacade(tabApi, signal),
|
|
981
1002
|
assert: (cond: unknown, text?: string): void => {
|
|
982
1003
|
if (!cond) throw new ToolError(text ?? "Assertion failed");
|
|
983
1004
|
},
|
|
@@ -991,7 +1012,7 @@ export class WorkerCore {
|
|
|
991
1012
|
: { timeout: resolvePredicateTimeout(msg.timeoutMs, opts?.timeout), interval: opts?.interval };
|
|
992
1013
|
return markHandled(
|
|
993
1014
|
this.#runOp(active, label, signal, Number.POSITIVE_INFINITY, sig =>
|
|
994
|
-
|
|
1015
|
+
waitForRun(msOrPredicate, sig, resolved),
|
|
995
1016
|
),
|
|
996
1017
|
);
|
|
997
1018
|
},
|
package/src/tools/browser.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
holdBrowser,
|
|
16
16
|
releaseBrowser,
|
|
17
17
|
} from "./browser/registry";
|
|
18
|
+
import { resolveRelayKind } from "./browser/relay/kind";
|
|
18
19
|
import type { Observation, ScreenshotResult } from "./browser/tab-protocol";
|
|
19
20
|
import {
|
|
20
21
|
type AcquireTabResult,
|
|
@@ -39,6 +40,7 @@ export {
|
|
|
39
40
|
export { cmuxSnapshotToObservation, mapWaitUntil, resolveCmuxKind, serializeEval } from "./browser/cmux/rpc";
|
|
40
41
|
export { CmuxSocketClient } from "./browser/cmux/socket-client";
|
|
41
42
|
export { extractReadableFromHtml, type ReadableFormat, type ReadableResult } from "./browser/readable";
|
|
43
|
+
export { DEFAULT_RELAY_URL, type RelayKind, resolveRelayKind } from "./browser/relay/kind";
|
|
42
44
|
export type { Observation, ObservationEntry } from "./browser/tab-protocol";
|
|
43
45
|
|
|
44
46
|
const DEFAULT_TAB_NAME = "main";
|
|
@@ -46,6 +48,7 @@ const DEFAULT_TAB_NAME = "main";
|
|
|
46
48
|
const appSchema = type({
|
|
47
49
|
"path?": type("string").describe("binary path to spawn"),
|
|
48
50
|
"cdp_url?": type("string").describe("existing cdp endpoint"),
|
|
51
|
+
"relay?": type("boolean").describe("drive the user's own tabs via the omp browser relay"),
|
|
49
52
|
"args?": type("string[]").describe("extra cli args"),
|
|
50
53
|
"target?": type("string").describe("substring to pick a window"),
|
|
51
54
|
});
|
|
@@ -95,7 +98,24 @@ function resolveBrowserKind(params: BrowserParams, session: ToolSession): Browse
|
|
|
95
98
|
const exe = resolveToCwd(app.path, session.cwd);
|
|
96
99
|
return { kind: "spawned", path: exe };
|
|
97
100
|
}
|
|
98
|
-
|
|
101
|
+
const relayUrl = session.settings.get("browser.relayUrl") as string | undefined;
|
|
102
|
+
// Explicit app.relay wins over every setting; PI_BROWSER_RELAY stays the
|
|
103
|
+
// final kill switch (a relay that is down would otherwise brick the tool).
|
|
104
|
+
if (app?.relay) {
|
|
105
|
+
const relayKind = resolveRelayKind({ settingEnabled: true, url: relayUrl });
|
|
106
|
+
if (relayKind) return relayKind;
|
|
107
|
+
}
|
|
108
|
+
// Relay before cdpUrl among settings: enabling the opt-out-by-default relay
|
|
109
|
+
// is a deliberate mode selection, while cdpUrl is a standing fallback
|
|
110
|
+
// endpoint. A configured endpoint is a default, not an override: explicit
|
|
111
|
+
// app options win.
|
|
112
|
+
if (app?.relay !== false) {
|
|
113
|
+
const relayKind = resolveRelayKind({
|
|
114
|
+
settingEnabled: session.settings.get("browser.relay") as boolean | undefined,
|
|
115
|
+
url: relayUrl,
|
|
116
|
+
});
|
|
117
|
+
if (relayKind) return relayKind;
|
|
118
|
+
}
|
|
99
119
|
const configuredCdpUrl = (session.settings.get("browser.cdpUrl") as string | undefined)?.trim();
|
|
100
120
|
if (configuredCdpUrl) {
|
|
101
121
|
return { kind: "connected", cdpUrl: configuredCdpUrl.replace(/\/+$/, "") };
|
|
@@ -427,6 +447,8 @@ function describeBrowser(handle: BrowserHandle): string {
|
|
|
427
447
|
return `spawned ${handle.kind.path} (pid ${handle.pid ?? "?"})`;
|
|
428
448
|
case "connected":
|
|
429
449
|
return `connected ${handle.cdpUrl ?? handle.kind.cdpUrl}`;
|
|
450
|
+
case "relay":
|
|
451
|
+
return `relay ${handle.cdpUrl ?? handle.kind.cdpUrl}`;
|
|
430
452
|
}
|
|
431
453
|
}
|
|
432
454
|
|
|
@@ -438,6 +460,8 @@ function describeKind(kind: BrowserKind): string {
|
|
|
438
460
|
return `spawned:${kind.path}`;
|
|
439
461
|
case "connected":
|
|
440
462
|
return `connected:${kind.cdpUrl}`;
|
|
463
|
+
case "relay":
|
|
464
|
+
return `relay:${kind.cdpUrl}`;
|
|
441
465
|
case "cmux":
|
|
442
466
|
return `cmux:${kind.surface ?? "split"}`;
|
|
443
467
|
}
|
|
@@ -448,6 +472,7 @@ function sameBrowserKind(a: BrowserKind, b: BrowserKind): boolean {
|
|
|
448
472
|
if (a.kind === "headless" && b.kind === "headless") return a.headless === b.headless;
|
|
449
473
|
if (a.kind === "spawned" && b.kind === "spawned") return a.path === b.path;
|
|
450
474
|
if (a.kind === "connected" && b.kind === "connected") return a.cdpUrl === b.cdpUrl;
|
|
475
|
+
if (a.kind === "relay" && b.kind === "relay") return a.cdpUrl === b.cdpUrl;
|
|
451
476
|
if (a.kind === "cmux" && b.kind === "cmux") return a.socketPath === b.socketPath;
|
|
452
477
|
return false;
|
|
453
478
|
}
|
|
@@ -1,38 +1,14 @@
|
|
|
1
1
|
import type { Model } from "@oh-my-pi/pi-ai";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
url.protocol === "https:" &&
|
|
15
|
-
(url.hostname.endsWith(".openai.azure.com") || url.hostname === "models.inference.ai.azure.com")
|
|
16
|
-
);
|
|
17
|
-
} catch {
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Match the provider transport's effective Computer Use tool representation. */
|
|
23
|
-
export function computerExposureMode(
|
|
24
|
-
model: Model | undefined,
|
|
25
|
-
options?: ComputerExposureOptions,
|
|
26
|
-
): ComputerExposureMode {
|
|
27
|
-
if (!model) return "unavailable";
|
|
28
|
-
if (model.supportsComputerUse !== true) return "function";
|
|
29
|
-
if (model.api !== "azure-openai-responses" || model.supportsComputerUseConfig !== undefined) return "native";
|
|
30
|
-
const baseUrl =
|
|
31
|
-
options?.azureBaseUrl?.trim() ||
|
|
32
|
-
process.env.AZURE_OPENAI_BASE_URL?.trim() ||
|
|
33
|
-
(options?.azureResourceName || process.env.AZURE_OPENAI_RESOURCE_NAME
|
|
34
|
-
? `https://${options?.azureResourceName || process.env.AZURE_OPENAI_RESOURCE_NAME}.openai.azure.com/openai/v1`
|
|
35
|
-
: undefined) ||
|
|
36
|
-
model.baseUrl;
|
|
37
|
-
return baseUrl && isFirstPartyAzureEndpoint(baseUrl) ? "native" : "function";
|
|
3
|
+
/** How the computer tool is represented to the active model. */
|
|
4
|
+
export type ComputerExposureMode = "function" | "unavailable";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Report the computer tool's callable representation.
|
|
8
|
+
*
|
|
9
|
+
* Window selection is part of the tool's JSON schema, so even models with
|
|
10
|
+
* provider-native Computer Use support receive it as a function.
|
|
11
|
+
*/
|
|
12
|
+
export function computerExposureMode(model: Model | undefined): ComputerExposureMode {
|
|
13
|
+
return model ? "function" : "unavailable";
|
|
38
14
|
}
|
|
@@ -1,26 +1,67 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import type { DesktopCapabilities } from "@oh-my-pi/pi-natives";
|
|
2
3
|
|
|
4
|
+
/** Hidden CLI selector that re-enters the computer worker host. */
|
|
3
5
|
export const COMPUTER_WORKER_ARG = "__omp_worker_computer";
|
|
4
6
|
|
|
7
|
+
/** Frozen run settings transferred from the tool session to the worker. */
|
|
8
|
+
export interface ComputerSessionSnapshot {
|
|
9
|
+
cwd: string;
|
|
10
|
+
sessionId: string;
|
|
11
|
+
captureMaxWidth: number;
|
|
12
|
+
captureMaxHeight: number;
|
|
13
|
+
display: string;
|
|
14
|
+
readOnly: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Reply envelope for a session tool invoked by desktop JavaScript. */
|
|
18
|
+
export type ToolReply = { ok: true; value: unknown } | { ok: false; error: RunErrorPayload };
|
|
19
|
+
|
|
20
|
+
/** Commands accepted by the persistent computer worker. */
|
|
5
21
|
export type ComputerWorkerInbound =
|
|
6
22
|
| { type: "ping"; id: string }
|
|
7
|
-
| { type: "
|
|
8
|
-
| { type: "
|
|
23
|
+
| { type: "run"; id: string; code: string; timeoutMs: number; session: ComputerSessionSnapshot }
|
|
24
|
+
| { type: "abort"; id: string }
|
|
25
|
+
| { type: "tool-reply"; id: string; reply: ToolReply }
|
|
9
26
|
| { type: "close" };
|
|
10
27
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
28
|
+
/** Successful computer run output returned to the tool supervisor. */
|
|
29
|
+
export interface ComputerRunOk {
|
|
30
|
+
displays: Array<TextContent | ImageContent>;
|
|
31
|
+
returnValue: unknown;
|
|
32
|
+
screenshots: ComputerScreenshot[];
|
|
33
|
+
capabilities?: DesktopCapabilities;
|
|
34
|
+
}
|
|
17
35
|
|
|
18
|
-
|
|
36
|
+
/** Full-resolution screenshot emitted during one computer run. */
|
|
37
|
+
export interface ComputerScreenshot {
|
|
38
|
+
path: string;
|
|
39
|
+
width: number;
|
|
40
|
+
height: number;
|
|
41
|
+
sourceWidth?: number;
|
|
42
|
+
sourceHeight?: number;
|
|
43
|
+
target: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Clone-safe error metadata returned across the worker boundary. */
|
|
47
|
+
export interface RunErrorPayload {
|
|
19
48
|
name: string;
|
|
20
49
|
message: string;
|
|
21
50
|
stack?: string;
|
|
51
|
+
isToolError: boolean;
|
|
52
|
+
isAbort: boolean;
|
|
22
53
|
}
|
|
23
54
|
|
|
55
|
+
/** Events emitted by the persistent computer worker. */
|
|
56
|
+
export type ComputerWorkerOutbound =
|
|
57
|
+
| { type: "ready" }
|
|
58
|
+
| { type: "pong"; id: string }
|
|
59
|
+
| { type: "result"; id: string; ok: true; payload: ComputerRunOk }
|
|
60
|
+
| { type: "result"; id: string; ok: false; error: RunErrorPayload }
|
|
61
|
+
| { type: "tool-call"; id: string; runId: string; name: string; args: unknown }
|
|
62
|
+
| { type: "closed" };
|
|
63
|
+
|
|
64
|
+
/** Transport used by the worker core in Bun workers and tests. */
|
|
24
65
|
export interface ComputerWorkerTransport {
|
|
25
66
|
send(message: ComputerWorkerOutbound, transfer?: Bun.Transferable[]): void;
|
|
26
67
|
onMessage(handler: (message: ComputerWorkerInbound) => void): () => void;
|