UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

166 lines (165 loc) • 7.4 kB
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { a as getTrackedWorkerPoolSnapshot } from "./worker-cpu-EKuz4_X-.mjs"; import { t as ErrorCodes } from "./gateway-error-details-DIefe7Zy.mjs"; import { f as errorShape } from "./error-codes-DI20vDEB.mjs"; import { t as lazyCompile } from "./protocol-validator-C_V-gGjM.mjs"; import { c as normalizeDiagnosticStabilityQuery, t as getDiagnosticStabilitySnapshot } from "./diagnostic-stability-COzLr3q8.mjs"; import { n as SUBAGENT_LANE_PREFIX, r as SWARM_LANE_PREFIX, t as STATIC_COMMAND_LANES } from "./lanes-D7a4ntDu.mjs"; import { a as getCommandLaneSnapshot, g as getQueueState, u as listCommandLaneTotals } from "./command-queue-sWcl2dHN.mjs"; import { n as getBackgroundWorkSnapshot, r as isBackgroundWorkLane } from "./background-work-e4eP0NpZ.mjs"; import { Type } from "typebox"; //#region packages/gateway-protocol/src/schema/diagnostics.ts /** Integer inputs are clamped by the capture owner to safe sampling bounds. */ const DiagnosticsHeapProfileParamsSchema = Type.Object({ durationMs: Type.Optional(Type.Integer({ minimum: 1, maximum: Number.MAX_SAFE_INTEGER })), samplingIntervalBytes: Type.Optional(Type.Integer({ minimum: 1, maximum: Number.MAX_SAFE_INTEGER })), includeObjectsCollectedByMajorGC: Type.Optional(Type.Boolean()), includeObjectsCollectedByMinorGC: Type.Optional(Type.Boolean()) }, { additionalProperties: false }); const validateDiagnosticsHeapProfileParams = /* @__PURE__ */ lazyCompile(DiagnosticsHeapProfileParamsSchema); const DiagnosticsHeapSnapshotParamsSchema = Type.Object({ reason: Type.Optional(Type.String({ maxLength: 256 })) }, { additionalProperties: false }); const validateDiagnosticsHeapSnapshotParams = /* @__PURE__ */ lazyCompile(DiagnosticsHeapSnapshotParamsSchema); //#endregion //#region src/process/command-lane-diagnostics.ts const STATIC_COMMAND_LANE_SET = new Set(STATIC_COMMAND_LANES); const MAX_SWARM_LANE_SNAPSHOTS = 32; function getSubagentLaneSnapshot() { const snapshot = { ...getCommandLaneSnapshot("subagent"), concurrencyScope: "session", saturatedLaneCount: 0 }; for (const state of getQueueState().lanes.values()) { if (!state.lane.startsWith(SUBAGENT_LANE_PREFIX) || state.lane.startsWith(SWARM_LANE_PREFIX)) continue; const activeCount = state.activeTaskIds.size; snapshot.activeCount += activeCount; snapshot.queuedCount += state.queue.length; snapshot.draining ||= state.draining; snapshot.generation = Math.max(snapshot.generation, state.generation); if (activeCount >= state.maxConcurrent) { snapshot.saturatedLaneCount = (snapshot.saturatedLaneCount ?? 0) + 1; snapshot.blockedBy = "lane"; } } return snapshot; } function getCommandLaneDiagnostics() { const lanes = [...STATIC_COMMAND_LANES].toSorted().map((lane) => { if (lane === "background") return getBackgroundWorkSnapshot(); if (lane === "subagent") return getSubagentLaneSnapshot(); return getCommandLaneSnapshot(lane); }).filter((lane) => lane.maxConcurrent > 0 || lane.activeCount > 0 || lane.queuedCount > 0); const dynamic = { laneCount: 0, activeCount: 0, queuedCount: 0, queuedLaneCount: 0 }; let swarmSnapshots = 0; for (const totals of listCommandLaneTotals()) { if (totals.lane.startsWith(SWARM_LANE_PREFIX)) { if (swarmSnapshots < MAX_SWARM_LANE_SNAPSHOTS) { lanes.push(getCommandLaneSnapshot(totals.lane)); swarmSnapshots += 1; continue; } } else if (STATIC_COMMAND_LANE_SET.has(totals.lane) || isBackgroundWorkLane(totals.lane) || totals.lane.startsWith(SUBAGENT_LANE_PREFIX)) continue; dynamic.laneCount += 1; dynamic.activeCount += totals.activeCount; dynamic.queuedCount += totals.queuedCount; if (totals.queuedCount > 0) dynamic.queuedLaneCount += 1; } return { lanes, dynamic: dynamic.laneCount > 0 ? dynamic : null }; } //#endregion //#region src/gateway/server-methods/diagnostics.ts async function captureProfile({ client, signal, context, respond, hasCurrentClientAuthority }, label, capture) { const lifetime = AbortSignal.any([ signal, client?.connectionSignal, context.requestEntryLifetime?.signal ].filter((value) => value !== void 0)); const hasAuthority = () => !client?.invalidated && (hasCurrentClientAuthority?.() ?? true); const outcome = await capture({ signal: lifetime, hasAuthority }); if (lifetime.aborted || !hasAuthority()) return; if (outcome.status === "complete") respond(true, outcome.result, void 0); else { const message = outcome.reason === "tracing-active" ? `${label} unavailable: stop active Node tracing, including non-CPU categories, before requesting a profile` : `${label} unavailable: ${outcome.reason}`; respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, message, { details: { reason: outcome.reason, cleanupFailed: outcome.cleanupFailed } })); } } /** Gateway handlers for bounded runtime diagnostics. */ const diagnosticsHandlers = { "diagnostics.cpuProfile": async (options) => { const { req, respond } = options; if (req.params !== void 0 && (!isRecord(req.params) || Object.keys(req.params).length > 0)) { respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "diagnostics.cpuProfile accepts only empty params")); return; } await captureProfile(options, "CPU profile", async (authority) => { const { captureDiagnosticCpuProfile } = await import("./diagnostic-cpu-profile-AGPkpmwQ.mjs"); return captureDiagnosticCpuProfile(authority); }); }, "diagnostics.heapProfile": async (options) => { const { req, respond } = options; const params = req.params === void 0 ? {} : req.params; if (!validateDiagnosticsHeapProfileParams(params)) { respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "diagnostics.heapProfile accepts only positive integer durationMs and samplingIntervalBytes, and boolean includeObjectsCollectedByMajorGC and includeObjectsCollectedByMinorGC")); return; } await captureProfile(options, "Heap profile", async (authority) => { const { captureDiagnosticHeapProfile } = await import("./diagnostic-heap-profile-DpQc9tTI.mjs"); return captureDiagnosticHeapProfile({ ...params, ...authority }); }); }, "diagnostics.heapSnapshot": async (options) => { const params = options.req.params === void 0 ? {} : options.req.params; if (!validateDiagnosticsHeapSnapshotParams(params)) { options.respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "diagnostics.heapSnapshot accepts only an optional reason string (at most 256 characters)")); return; } await captureProfile(options, "Heap snapshot", async (authority) => { const { captureDiagnosticHeapSnapshot } = await import("./diagnostic-heap-snapshot-DY6Encyf.mjs"); return captureDiagnosticHeapSnapshot({ ...params, ...authority }); }); }, "diagnostics.lanes": ({ respond }) => { respond(true, { ts: Date.now(), ...getCommandLaneDiagnostics(), ...getTrackedWorkerPoolSnapshot() }, void 0); }, "diagnostics.stability": async ({ params, respond }) => { try { const query = normalizeDiagnosticStabilityQuery(params); respond(true, getDiagnosticStabilitySnapshot(query), void 0); } catch (err) { respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, err instanceof Error ? err.message : "invalid diagnostics.stability params")); } } }; //#endregion export { diagnosticsHandlers };