UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

233 lines (232 loc) • 8.61 kB
import { a as asOptionalRecord, u as readStringField } from "./record-coerce-TIsquoVR.mjs"; import { s as isLoopbackHost } from "./net-BD0odJBF.mjs"; import "./string-coerce-runtime-B1b8UNzb.mjs"; import "./ssrf-runtime-DDaKW8yK.mjs"; import { f as DEFAULT_OPENCLAW_BROWSER_COLOR } from "./constants-C-i9f6FL.mjs"; //#region extensions/browser/src/browser/engines/chromium.ts const chromiumEngine = { descriptor: { id: "chromium", label: "Chromium", launchMode: "managed-or-attach", sessionScope: "browser", screenshotFidelity: "rendered" }, requiresDedicatedEndpoint: false, canReconnectForSafeReads: true, supportsRequest: () => true, capabilities(profile) { const usesChromeMcp = profile.driver === "existing-session"; const usesExtension = profile.driver === "extension"; const isRemote = !usesChromeMcp && !usesExtension && !profile.cdpIsLoopback; const localManaged = !usesChromeMcp && !usesExtension && !isRemote; return { supportsBatchActions: profile.driver !== "existing-session", supportsDownloads: profile.driver !== "existing-session", supportsPdf: profile.driver !== "existing-session", supportsRequests: profile.driver !== "existing-session", supportsErrors: profile.driver !== "existing-session", supportsPageText: profile.driver !== "existing-session", supportsEmulation: profile.driver !== "existing-session", supportsScreenshots: true, supportsVisualActions: true, supportsUploads: true, supportsDialogs: true, supportsStorage: true, supportsScreencast: profile.driver !== "existing-session", supportsConsole: true, supportsMultipleTabs: true, supportsNativeSnapshots: true, requiresCompleteTargetEnumeration: profile.driver === "extension", mode: usesChromeMcp ? "local-existing-session" : usesExtension ? "local-extension" : isRemote ? "remote-cdp" : "local-managed", isRemote, browserFilesystemLocal: usesExtension || localManaged && !profile.attachOnly, usesChromeMcp, usesPersistentPlaywright: usesExtension || isRemote, supportsPerTabWs: localManaged, supportsJsonTabEndpoints: localManaged, supportsReset: localManaged, supportsManagedTabLimit: localManaged }; } }; //#endregion //#region extensions/browser/src/browser/engines/lightpanda-cdp.ts const MAX_PENDING_TARGET_COMMANDS = 4096; const MAX_ATTACHED_PAGE_SESSIONS = 4096; const ROOT_REPLIES = /* @__PURE__ */ new Set([ "Target.getTargetInfo", "Target.getTargets", "Target.getBrowserContexts" ]); /** Normalize the session-routing omissions observed in Lightpanda 0.4.1. */ function createLightpandaCdpNormalizer() { const pendingSessions = /* @__PURE__ */ new Map(); const targetBySession = /* @__PURE__ */ new Map(); return { send(message) { const command = asOptionalRecord(message); const method = readStringField(command, "method"); const sessionId = readStringField(command, "sessionId"); if (!command || !sessionId || !ROOT_REPLIES.has(method ?? "")) return message; if (typeof command.id === "number") { if (pendingSessions.size >= MAX_PENDING_TARGET_COMMANDS) throw new Error("Lightpanda has too many unanswered target commands; reconnect."); pendingSessions.set(command.id, sessionId); } const params = asOptionalRecord(command.params); const targetId = targetBySession.get(sessionId); if (method === "Target.getTargetInfo" && !readStringField(params, "targetId") && targetId) return { ...command, params: { ...params, targetId } }; return message; }, receive(message) { const params = asOptionalRecord(message.params); const sessionId = readStringField(params, "sessionId"); if (message.method === "Target.attachedToTarget" && sessionId) { const target = asOptionalRecord(params?.targetInfo); const targetId = readStringField(target, "targetId"); if (sessionId === "STARTUP" && targetId === "TID-STARTUP" && readStringField(target, "browserContextId") === "BID-STARTUP") return; if (readStringField(target, "type") === "page" && targetId) { if (targetBySession.size >= MAX_ATTACHED_PAGE_SESSIONS) throw new Error("Lightpanda has too many attached page sessions; reconnect."); targetBySession.set(sessionId, targetId); } } else if (message.method === "Target.detachedFromTarget" && sessionId) targetBySession.delete(sessionId); if (typeof message.id === "number") { const expectedSessionId = pendingSessions.get(message.id); pendingSessions.delete(message.id); if (expectedSessionId && !readStringField(message, "sessionId")) return { ...message, sessionId: expectedSessionId }; } return message; }, clear() { pendingSessions.clear(); targetBySession.clear(); } }; } //#endregion //#region extensions/browser/src/browser/engines/lightpanda.ts const SEMANTIC_ROUTES = /* @__PURE__ */ new Set([ "/", "/doctor", "/start", "/stop", "/tabs", "/tabs/open", "/tabs/focus", "/tabs/:targetId", "/tabs/action", "/navigate", "/text", "/snapshot", "/act" ]); const SEMANTIC_ACT_KINDS = /* @__PURE__ */ new Set([ "click", "type", "press", "select", "fill", "wait", "evaluate", "close" ]); //#endregion //#region extensions/browser/src/browser/engines/registry.ts const engines = { chromium: chromiumEngine, lightpanda: { descriptor: { id: "lightpanda", label: "Lightpanda", launchMode: "attach-only", sessionScope: "connection", screenshotFidelity: "none" }, requiresDedicatedEndpoint: true, canReconnectForSafeReads: false, maxPagesPerConnection: 1, defaultSnapshotRefs: "aria", createCdpNormalizer: createLightpandaCdpNormalizer, supportsRequest({ path, actionKind, actionSelector, snapshot }) { if (!SEMANTIC_ROUTES.has(path)) return false; if (path === "/act") return !actionSelector && (actionKind === void 0 || SEMANTIC_ACT_KINDS.has(actionKind)); return !snapshot || !(snapshot.labels || snapshot.format === "aria" || snapshot.refs === "role" || snapshot.selector || snapshot.frame); }, capabilities(profile) { return { mode: "lightweight-cdp", isRemote: !profile.cdpIsLoopback, browserFilesystemLocal: false, usesChromeMcp: false, usesPersistentPlaywright: true, supportsPerTabWs: false, supportsJsonTabEndpoints: false, supportsReset: false, supportsManagedTabLimit: false, supportsBatchActions: false, supportsDownloads: false, supportsPdf: false, supportsRequests: false, supportsErrors: false, supportsPageText: true, supportsEmulation: false, supportsScreenshots: false, supportsVisualActions: false, supportsUploads: false, supportsDialogs: false, supportsStorage: false, supportsScreencast: false, supportsConsole: false, supportsMultipleTabs: false, supportsNativeSnapshots: false, requiresCompleteTargetEnumeration: false }; }, resolveExternalProfile(profileName, profile) { const endpoint = profile.cdpUrl ? URL.parse(profile.cdpUrl) : null; if (!endpoint || !["ws:", "wss:"].includes(endpoint.protocol)) throw new Error(`browser.profiles.${profileName}.cdpUrl must be an explicit ws:// or wss:// Lightpanda endpoint.`); if (profile.attachOnly !== true) throw new Error(`browser.profiles.${profileName} requires attachOnly: true for Lightpanda.`); if (profile.driver !== void 0 && profile.driver !== "openclaw") throw new Error(`browser.profiles.${profileName} requires the default CDP driver for Lightpanda.`); for (const key of [ "cdpPort", "userDataDir", "mcpCommand", "mcpArgs", "headless", "executablePath" ]) if (profile[key] !== void 0) throw new Error(`browser.profiles.${profileName}.${key} is not supported by Lightpanda.`); return { name: profileName, engine: "lightpanda", cdpUrl: endpoint.toString(), cdpHost: endpoint.hostname, cdpPort: Number(endpoint.port || (endpoint.protocol === "wss:" ? 443 : 80)), cdpIsLoopback: isLoopbackHost(endpoint.hostname), color: DEFAULT_OPENCLAW_BROWSER_COLOR, driver: "openclaw", headless: true, headlessSource: "default", attachOnly: true }; } } }; function resolveBrowserEngine(id = "chromium") { if (!Object.hasOwn(engines, id)) throw new Error(`Unknown browser engine "${id}". Select chromium or lightpanda.`); return engines[id]; } /** The same registered implementations drive status discovery and execution. */ function listBrowserEngines() { return Object.values(engines).map(({ descriptor }) => Object.assign({}, descriptor)); } //#endregion export { resolveBrowserEngine as n, listBrowserEngines as t };