openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
156 lines (155 loc) • 7.57 kB
JavaScript
import "./src-SskUVPJG.mjs";
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { t as stableStringify } from "./stable-stringify-CkQ0IEj1.mjs";
import { ni as NEVER } from "./json-schema-processors-C6KO_BFy.mjs";
import { Et as _enum, Jn as string, Kt as custom, or as union, tr as transform, xn as literal } from "./schemas-BOYIvvln.mjs";
import { a as parseWorkerLaunchPlan } from "./launch-descriptor-Cjab1Wps.mjs";
import { i as workerProtocolObject, r as workerProtocolIdentifier, t as WorkerGatewayNamespace } from "./protocol-record-BIYtFogM.mjs";
import { createHash } from "node:crypto";
//#region src/worker/node-supervisor-protocol.ts
const NODE_WORKER_SUPERVISOR_CONTROL_REQUEST_MAX_BYTES = 4096;
const NODE_WORKER_STATUS_WAIT_MAX_MS = 2e4;
const NODE_WORKER_RESULT_JSON_MAX_BYTES = 65536;
const NODE_WORKER_ERROR_TEXT_MAX_BYTES = 4096;
const NODE_WORKER_CONNECTION_FAILURE_CAUSE_MAX_BYTES = 65536;
const NODE_WORKER_CONNECTION_FAILURE_MESSAGE_TYPE = "openclaw-worker-connection-failure-v1";
function isNonNegativeInteger(value) {
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
}
function isPlanHash(value) {
return typeof value === "string" && /^[a-f0-9]{64}$/u.test(value);
}
const nonNegativeInteger = (label) => custom(isNonNegativeInteger, { error: `INVALID_REQUEST: ${label} must be a non-negative safe integer` });
const IdentityShape = {
launchId: workerProtocolIdentifier("launchId"),
planHash: custom(isPlanHash, { error: "INVALID_REQUEST: planHash must be 64 lowercase hexadecimal characters" }),
environmentId: workerProtocolIdentifier("environmentId"),
sessionId: workerProtocolIdentifier("sessionId"),
ownerEpoch: nonNegativeInteger("ownerEpoch"),
placementGeneration: nonNegativeInteger("placementGeneration"),
runId: workerProtocolIdentifier("runId")
};
const Identity = workerProtocolObject(IdentityShape);
const EnvironmentStop = workerProtocolObject({
gatewayNamespace: WorkerGatewayNamespace,
environmentId: IdentityShape.environmentId,
sessionId: IdentityShape.sessionId,
ownerEpoch: IdentityShape.ownerEpoch
});
const LaunchInput = workerProtocolObject({
environmentSession: literal(1, { error: "INVALID_REQUEST: node worker environment lifetime support required" }),
sessionKey: workerProtocolIdentifier("sessionKey", 1024).optional(),
idleRetention: literal(true, { error: "INVALID_REQUEST: idleRetention must be true" }).optional(),
launchId: IdentityShape.launchId,
gatewayNamespace: WorkerGatewayNamespace,
expectedBundleHash: custom(isPlanHash, { error: "INVALID_REQUEST: expectedBundleHash must be 64 lowercase hexadecimal characters" }),
descriptor: transform((value, context) => {
try {
return parseWorkerLaunchPlan(value);
} catch {
context.addIssue({
code: "custom",
message: "INVALID_REQUEST: invalid worker launch descriptor"
});
return NEVER;
}
}),
placementGeneration: IdentityShape.placementGeneration
});
const Lookup = workerProtocolObject({
launchId: IdentityShape.launchId,
waitMs: custom((value) => isNonNegativeInteger(value) && value >= 1 && value <= 2e4, { error: "INVALID_REQUEST: waitMs must be an integer between 1 and 20000" }).optional()
});
const Receipt = union([
workerProtocolObject({
...IdentityShape,
state: _enum(["pending", "running"])
}),
workerProtocolObject({
...IdentityShape,
state: literal("completed"),
resultJson: custom(isBoundedResultJson)
}),
workerProtocolObject({
...IdentityShape,
state: _enum([
"failed",
"interrupted",
"cancelled"
]),
errorText: custom(isBoundedErrorText)
})
]);
const ConnectionFailure = workerProtocolObject({
type: literal(NODE_WORKER_CONNECTION_FAILURE_MESSAGE_TYPE),
cause: string().min(1).refine((value) => Buffer.byteLength(value, "utf8") <= NODE_WORKER_CONNECTION_FAILURE_CAUSE_MAX_BYTES).nullable()
});
function parseRequest(schema, value, operation) {
const parsed = schema.safeParse(value);
if (!parsed.success) {
const issue = parsed.error.issues[0];
throw new Error(issue?.path.length ? issue.message : `INVALID_REQUEST: invalid node worker ${operation} request`);
}
return parsed.data;
}
function decodeRequest(raw) {
if (!raw) throw new Error("INVALID_REQUEST: paramsJSON required");
try {
return JSON.parse(raw);
} catch {
throw new Error("INVALID_REQUEST: paramsJSON malformed JSON");
}
}
function parseNodeWorkerLaunchInput(raw) {
return validateNodeWorkerLaunchInput(decodeRequest(raw));
}
function validateNodeWorkerLaunchInput(value) {
const input = parseRequest(LaunchInput, value, "launch");
if (input.descriptor.assignment.turnId !== input.launchId) throw new Error("INVALID_REQUEST: launchId must match descriptor assignment turnId");
if (input.descriptor.admission.handshake.bundleHash !== input.expectedBundleHash) throw new Error("INVALID_REQUEST: descriptor bundle hash does not match expectedBundleHash");
if (input.sessionKey === void 0) delete input.sessionKey;
return input;
}
function parseNodeWorkerLookupInput(raw) {
return parseRequest(Lookup, decodeRequest(raw), "lookup");
}
function parseNodeWorkerCancelInput(raw) {
if (!raw || Buffer.byteLength(raw, "utf8") > NODE_WORKER_SUPERVISOR_CONTROL_REQUEST_MAX_BYTES) throw new Error("INVALID_REQUEST: invalid node worker cancel request");
return parseRequest(Identity, decodeRequest(raw), "cancel");
}
function parseNodeWorkerEnvironmentStopInput(raw) {
if (!raw || Buffer.byteLength(raw, "utf8") > NODE_WORKER_SUPERVISOR_CONTROL_REQUEST_MAX_BYTES) throw new Error("INVALID_REQUEST: invalid node worker environment stop request");
return parseRequest(EnvironmentStop, decodeRequest(raw), "environment stop");
}
function nodeWorkerPlanHash(input) {
return createHash("sha256").update(stableStringify({
expectedBundleHash: input.expectedBundleHash,
descriptor: input.descriptor,
gatewayNamespace: input.gatewayNamespace,
placementGeneration: input.placementGeneration,
...input.sessionKey === void 0 ? {} : { sessionKey: input.sessionKey },
...input.idleRetention ? { idleRetention: true } : {}
})).digest("hex");
}
function isBoundedResultJson(value) {
if (typeof value !== "string" || value.length === 0 || Buffer.byteLength(value, "utf8") > NODE_WORKER_RESULT_JSON_MAX_BYTES) return false;
try {
return isRecord(JSON.parse(value));
} catch {
return false;
}
}
function isBoundedErrorText(value) {
return typeof value === "string" && value.length > 0 && Buffer.byteLength(value, "utf8") <= NODE_WORKER_ERROR_TEXT_MAX_BYTES && !/[\r\n]/u.test(value);
}
function parseNodeWorkerConnectionFailureMessage(value) {
return ConnectionFailure.safeParse(value).data ?? null;
}
function parseNodeWorkerSupervisorReceipt(value) {
return Receipt.safeParse(value).data ?? null;
}
function nodeWorkerTurnMatchesIdentity(receipt, expected) {
return receipt.launchId === expected.launchId && receipt.planHash === expected.planHash && receipt.environmentId === expected.environmentId && receipt.sessionId === expected.sessionId && receipt.ownerEpoch === expected.ownerEpoch && receipt.placementGeneration === expected.placementGeneration && receipt.runId === expected.runId;
}
//#endregion
export { parseNodeWorkerCancelInput as a, parseNodeWorkerLaunchInput as c, validateNodeWorkerLaunchInput as d, nodeWorkerTurnMatchesIdentity as i, parseNodeWorkerLookupInput as l, NODE_WORKER_STATUS_WAIT_MAX_MS as n, parseNodeWorkerConnectionFailureMessage as o, nodeWorkerPlanHash as r, parseNodeWorkerEnvironmentStopInput as s, NODE_WORKER_CONNECTION_FAILURE_MESSAGE_TYPE as t, parseNodeWorkerSupervisorReceipt as u };