UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

89 lines (88 loc) 4.91 kB
import { t as parseNodeOptionsEnvVar } from "./node-options-W869vrJq.js"; import { n as resolveServiceEntrypointIndex } from "./service-layout-bTjykwbW.js"; import { a as resolveManagedGatewayServiceCommand, r as hasGatewayServiceEnvironmentOverride } from "./service-types-CK8rxZ9x.js"; import os from "node:os"; //#region src/daemon/gateway-heap.ts /** Adaptive Node heap policy for the managed Gateway service. */ const MEBIBYTE_BYTES = 1048576; const GATEWAY_HEAP_FLOOR_MIB = 2048; const GATEWAY_HEAP_CAP_MIB = 8192; function readAvailableMemory(params) { const constrainedMemoryBytes = params.constrainedMemoryBytes ?? process.constrainedMemory(); const physicalMemoryBytes = params.physicalMemoryBytes ?? os.totalmem(); const validPhysical = Number.isSafeInteger(physicalMemoryBytes) && physicalMemoryBytes > 0; if (Number.isSafeInteger(constrainedMemoryBytes) && constrainedMemoryBytes > 0 && (!validPhysical || constrainedMemoryBytes <= physicalMemoryBytes)) return { bytes: constrainedMemoryBytes, source: "constrained" }; return { bytes: validPhysical ? physicalMemoryBytes : null, source: validPhysical ? "physical" : "unknown" }; } function resolveGatewayHeapLimit(params = {}) { const memory = readAvailableMemory(params); if (memory.bytes === null || memory.bytes < 2 * MEBIBYTE_BYTES) return { maxOldSpaceSizeMiB: null, availableMemoryMiB: null, memorySource: "unknown", floorMiB: GATEWAY_HEAP_FLOOR_MIB, capMiB: GATEWAY_HEAP_CAP_MIB, headroomCapMiB: null }; const availableMemoryMiB = Math.floor(memory.bytes / MEBIBYTE_BYTES); const halfMemoryMiB = Math.floor(availableMemoryMiB / 2); const capMiB = Math.max(GATEWAY_HEAP_CAP_MIB, Math.floor(availableMemoryMiB / 4)); const headroomCapMiB = Math.floor(availableMemoryMiB * .75); return { maxOldSpaceSizeMiB: Math.min(capMiB, Math.max(GATEWAY_HEAP_FLOOR_MIB, halfMemoryMiB), headroomCapMiB), availableMemoryMiB, memorySource: memory.source, floorMiB: GATEWAY_HEAP_FLOOR_MIB, capMiB, headroomCapMiB }; } function parseHeapControls(tokens) { const controls = /* @__PURE__ */ new Map(); for (let index = 0; index < tokens.length; index += 1) { const token = tokens[index] ?? ""; if (token === "--") break; const match = /^(--max(?:[-_]old[-_]space[-_]size(?:[-_]percentage)?|[-_]heap[-_]size))(?:=(.*))?$/u.exec(token); if (!match) continue; const flag = (match[1] ?? "").replaceAll("_", "-"); const rawValue = match[2] ?? tokens[++index] ?? ""; const value = Number(rawValue); if (flag.endsWith("-percentage") ? Number.isFinite(value) && value > 0 && value <= 100 : /^\+?\d+$/u.test(rawValue) && Number.isSafeInteger(value) && value >= 0) controls.set(flag, value); } return Array.from(controls, ([flag, value]) => `${flag}=${value}`); } function resolveGatewayHeapNodeOptions(existingNodeOptions, runtime = "node") { const controls = parseHeapControls(parseNodeOptionsEnvVar(existingNodeOptions) ?? []).join(" "); if (controls || runtime !== "bun") return controls; const limit = resolveGatewayHeapLimit().maxOldSpaceSizeMiB; return limit === null ? "" : `--max-old-space-size=${Math.min(GATEWAY_HEAP_CAP_MIB, limit)}`; } function readServiceHeapExecArgv(programArguments) { const entrypointIndex = resolveServiceEntrypointIndex(programArguments); return parseHeapControls(programArguments.slice(1, entrypointIndex ?? 1)); } function resolveGatewayHeapExecArgv(existingCommand) { const managed = resolveManagedGatewayServiceCommand(existingCommand); const existing = readServiceHeapExecArgv(managed?.programArguments ?? []); if (existing.length || resolveGatewayHeapNodeOptions(managed?.environment?.NODE_OPTIONS) || hasGatewayServiceEnvironmentOverride(existingCommand, ["NODE_OPTIONS"])) return existing; const limit = resolveGatewayHeapLimit().maxOldSpaceSizeMiB; return limit === null ? [] : [`--max-old-space-size=${limit}`]; } function inspectGatewayHeapLimit(nodeOptions, memory = {}, programArguments = []) { return { ...resolveGatewayHeapLimit(memory), nodeOptions: resolveGatewayHeapNodeOptions(nodeOptions), execArgv: readServiceHeapExecArgv(programArguments) }; } function formatGatewayHeapLimitReport(report) { return `${[report.nodeOptions ? `service NODE_OPTIONS: ${report.nodeOptions}` : "", report.execArgv.length ? `service argv: ${report.execArgv.join(" ")}` : ""].filter(Boolean).join("; ") || "no service heap control"}; installer recommendation: ${report.maxOldSpaceSizeMiB === null ? "unavailable (unknown capacity; use Node default)" : `${report.maxOldSpaceSizeMiB} MiB old space (${report.availableMemoryMiB} MiB ${report.memorySource} capacity; adaptive cap ${report.capMiB} MiB; native headroom cap ${report.headroomCapMiB} MiB)`}; runtime V8 ceiling: not measured`; } //#endregion export { resolveGatewayHeapNodeOptions as i, inspectGatewayHeapLimit as n, resolveGatewayHeapExecArgv as r, formatGatewayHeapLimitReport as t };