UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

96 lines (95 loc) • 3.88 kB
import { j as writeExternalFileWithinRoot } from "../../fs-safe-BUXBSN-4.mjs"; import { i as resolveExistingPathsWithinRoot } from "../../security-runtime-Cl_Gnohk.mjs"; import { t as createBrowserToolDefinition } from "../../browser-tool-description-CRHph32o.mjs"; import { i as resolveBrowserConfig } from "../../config-DQZ6ubGi.mjs"; import "../../paths-DxRACgE0.mjs"; import { x as closePlaywrightBrowserConnection } from "../../pw-tools-core.interactions.navigation-Y_1O7pC7.mjs"; import { n as stopBrowserBridgeServer, t as startBrowserBridgeServer } from "../../bridge-server-CghCLLNy.mjs"; import { i as createBrowserTool, t as browserHandlers } from "../../browser-request-BAhkzthg.mjs"; import path from "node:path"; import { chmod, copyFile } from "node:fs/promises"; import { randomBytes } from "node:crypto"; //#region extensions/browser/src/attached-browser-tool-runtime.ts /** * The bridge owns only authenticated Browser HTTP ingress. Chrome remains owned * by the caller and survives bridge disposal. */ const ATTACHED_PROFILE_NAME = "worker"; async function persistAttachedScreenshot(params) { const extension = params.type === "jpeg" ? "jpg" : "png"; const fileName = `screenshot-${randomBytes(8).toString("hex")}.${extension}`; return (await writeExternalFileWithinRoot({ rootDir: params.workspaceDir, path: path.join(".artifacts", "cloud-worker-browser", fileName), fallbackFileName: fileName, write: async (stagedPath) => { await copyFile(params.sourcePath, stagedPath); await chmod(stagedPath, 384); } })).path; } function normalizeAttachedCdpUrl(raw) { const parsed = URL.parse(raw); const port = Number(parsed?.port); if (!parsed || parsed.protocol !== "http:" || parsed.hostname !== "127.0.0.1" || parsed.username !== "" || parsed.password !== "" || parsed.port === "" || !Number.isInteger(port) || port < 1 || port > 65535 || parsed.pathname !== "/" || parsed.search !== "" || parsed.hash !== "") throw new Error("Attached Browser CDP URL must be a loopback HTTP URL with an explicit port."); return parsed.toString().replace(/\/$/u, ""); } /** Create a normal Browser agent tool pinned to one raw, attach-only CDP profile. */ async function createAttachedBrowserToolRuntime(params) { const cdpUrl = normalizeAttachedCdpUrl(params.cdpUrl); const resolved = resolveBrowserConfig({ enabled: true, attachOnly: true, cdpUrl, defaultProfile: ATTACHED_PROFILE_NAME, profiles: { [ATTACHED_PROFILE_NAME]: { driver: "openclaw", attachOnly: true, cdpUrl } } }); resolved.profiles = { [ATTACHED_PROFILE_NAME]: { driver: "openclaw", attachOnly: true, cdpUrl } }; resolved.extensionRelayPorts = {}; resolved.extensionRelayInternalTokens = {}; const bridge = await startBrowserBridgeServer({ resolved, host: "127.0.0.1", port: 0, authToken: randomBytes(32).toString("base64url"), onEnsureAttachTarget: async () => await params.ensureAttachTarget() }); const dispose = async () => { try { await stopBrowserBridgeServer(bridge.server); } finally { await closePlaywrightBrowserConnection({ cdpUrl }); } }; try { return { tool: createBrowserTool({ sandboxBridgeUrl: bridge.baseUrl, allowHostControl: false, ...params.agentSessionKey !== void 0 ? { agentSessionKey: params.agentSessionKey } : {}, ...params.agentDir !== void 0 ? { agentDir: params.agentDir } : {}, ...params.workspaceDir !== void 0 ? { workspaceDir: params.workspaceDir } : {}, screenshotResultMode: "path", persistScreenshot: async ({ sourcePath, type }) => await persistAttachedScreenshot({ sourcePath, workspaceDir: params.workspaceDir, type }) }), dispose }; } catch (error) { await dispose(); throw error; } } //#endregion export { browserHandlers, createAttachedBrowserToolRuntime, createBrowserToolDefinition, resolveExistingPathsWithinRoot };