openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
190 lines (189 loc) • 8.18 kB
JavaScript
import { D as resolveExpiresAtMsFromDurationMs, o as asDateTimestampMs } from "./number-coercion-CLj0HTDM.js";
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import { n as createLazyPromise } from "./lazy-promise-DGqyc4Y4.js";
import { N as normalizeExecutableToken, d as resolveShellWrapperTransportArgv, l as isShellWrapperExecutable, t as POSIX_PARSEABLE_SHELL_WRAPPERS } from "./shell-wrapper-resolution-CIQIf-gP.js";
import { t as markToolDecisionRecorded } from "./agent-tools.before-tool-call.decision-DCAevWx5.js";
import { t as callGatewayTool } from "./gateway-CB9m4Gcq.js";
import { n as DEFAULT_APPROVAL_TIMEOUT_MS, t as DEFAULT_APPROVAL_REQUEST_TIMEOUT_MS } from "./bash-tools.exec-runtime-CbUMPDGW.js";
import { t as isApprovalNotFoundError } from "./approval-errors-Bzw_-cAg.js";
//#region src/agents/bash-tools.exec-approval-request.ts
/**
* Exec approval request client.
* Registers two-phase approval requests with the gateway, waits for decisions,
* and builds host/node payloads with optional command highlighting.
*/
const POSIX_COMMAND_HIGHLIGHT_SHELLS = POSIX_PARSEABLE_SHELL_WRAPPERS;
const loadExecApprovalCommandSpansRuntime = createLazyPromise(() => import("./bash-tools.exec-approval-request.runtime.js"), { cacheRejections: true });
function buildExecApprovalRequestToolParams(params) {
return {
id: params.id,
...params.command ? { command: params.command } : {},
...params.commandArgv ? { commandArgv: params.commandArgv } : {},
systemRunPlan: params.systemRunPlan,
env: params.env,
cwd: params.cwd,
nodeId: params.nodeId,
host: params.host,
security: params.security,
ask: params.ask,
warningText: params.warningText,
commandSpans: params.commandSpans,
...params.unavailableDecisions?.length ? { unavailableDecisions: params.unavailableDecisions } : {},
agentId: params.agentId,
resolvedPath: params.resolvedPath,
sessionKey: params.sessionKey,
sessionId: params.sessionId,
runId: params.runId,
toolCallId: params.toolCallId,
turnSourceChannel: params.turnSourceChannel,
turnSourceTo: params.turnSourceTo,
turnSourceAccountId: params.turnSourceAccountId,
turnSourceThreadId: params.turnSourceThreadId,
approvalReviewerDeviceIds: params.approvalReviewerDeviceIds,
requireDeliveryRoute: params.requireDeliveryRoute,
suppressDelivery: params.suppressDelivery,
deliverToApprovalClientsOnly: params.deliverToApprovalClientsOnly,
timeoutMs: DEFAULT_APPROVAL_TIMEOUT_MS,
twoPhase: true
};
}
function parseDecision(value) {
if (!value || typeof value !== "object") return {
present: false,
value: null
};
if (!Object.hasOwn(value, "decision")) return {
present: false,
value: null
};
const decision = value.decision;
return {
present: true,
value: typeof decision === "string" ? decision : null
};
}
function parseExpiresAtMs(value) {
return asDateTimestampMs(value);
}
function resolveDefaultExecApprovalExpiresAtMs() {
return resolveExpiresAtMsFromDurationMs(DEFAULT_APPROVAL_TIMEOUT_MS) ?? 0;
}
var ExecApprovalRunAbortedError = class extends Error {
constructor() {
super("Exec approval cancelled because its run was aborted");
this.name = "ExecApprovalRunAbortedError";
}
};
function isExecApprovalRunAbortedError(error) {
return error instanceof ExecApprovalRunAbortedError;
}
/** Registers a two-phase exec approval request with the gateway. */
async function registerExecApprovalRequest(params) {
const registrationResult = await callGatewayTool("exec.approval.request", { timeoutMs: DEFAULT_APPROVAL_REQUEST_TIMEOUT_MS }, buildExecApprovalRequestToolParams(params), { expectFinal: false });
markToolDecisionRecorded();
const decision = parseDecision(registrationResult);
const id = normalizeOptionalString(registrationResult?.id) ?? params.id;
const expiresAtMs = parseExpiresAtMs(registrationResult?.expiresAtMs) ?? resolveDefaultExecApprovalExpiresAtMs();
if (decision.present) return {
id,
expiresAtMs,
finalDecision: decision.value
};
return {
id,
expiresAtMs
};
}
/** Uses a pre-resolved decision or waits for the registered approval id. */
async function resolveRegisteredExecApprovalDecision(params) {
if (params.preResolvedDecision !== void 0) return params.preResolvedDecision ?? null;
try {
const decisionResult = await callGatewayTool("exec.approval.waitDecision", { timeoutMs: DEFAULT_APPROVAL_REQUEST_TIMEOUT_MS }, { id: params.approvalId });
if (decisionResult && typeof decisionResult === "object" && decisionResult.terminalReason === "run-aborted") throw new ExecApprovalRunAbortedError();
return parseDecision(decisionResult).value;
} catch (err) {
if (isApprovalNotFoundError(err)) return null;
throw err;
}
}
/** Builds requester identity context for an approval payload. */
function buildExecApprovalRequesterContext(params) {
return {
agentId: params.agentId,
sessionKey: params.sessionKey
};
}
/** Builds originating channel context for approval delivery/routing. */
function buildExecApprovalTurnSourceContext(params) {
return {
turnSourceChannel: params.turnSourceChannel,
turnSourceTo: params.turnSourceTo,
turnSourceAccountId: params.turnSourceAccountId,
turnSourceThreadId: params.turnSourceThreadId
};
}
async function resolveCommandSpans(command) {
if (!command) return;
try {
const { resolveExecApprovalCommandSpans } = await loadExecApprovalCommandSpansRuntime();
return await resolveExecApprovalCommandSpans(command);
} catch {
return;
}
}
function hasUnsupportedShellArgv(argv) {
if (!argv?.length) return false;
const executable = (resolveShellWrapperTransportArgv([...argv]) ?? argv)[0];
if (!executable) return false;
const normalizedExecutable = normalizeExecutableToken(executable);
return isShellWrapperExecutable(normalizedExecutable) && !POSIX_COMMAND_HIGHLIGHT_SHELLS.has(normalizedExecutable);
}
function shouldSkipGeneratedCommandSpans(params) {
if (params.host === "gateway" && process.platform === "win32") return true;
return hasUnsupportedShellArgv(params.commandArgv?.length ? params.commandArgv : params.systemRunPlan?.argv);
}
async function buildHostApprovalDecisionParams(params) {
const commandSpans = params.commandHighlighting === true ? params.commandSpans ?? (shouldSkipGeneratedCommandSpans(params) ? void 0 : await resolveCommandSpans(params.command ?? params.systemRunPlan?.commandText)) : void 0;
return {
id: params.approvalId,
command: params.command,
commandArgv: params.commandArgv,
systemRunPlan: params.systemRunPlan,
env: params.env,
cwd: params.workdir,
nodeId: params.nodeId,
host: params.host,
security: params.security,
ask: params.ask,
warningText: params.warningText,
commandSpans,
unavailableDecisions: params.unavailableDecisions,
...buildExecApprovalRequesterContext({
agentId: params.agentId,
sessionKey: params.sessionKey
}),
resolvedPath: params.resolvedPath,
sessionId: params.sessionId,
runId: params.runId,
toolCallId: params.toolCallId,
requireDeliveryRoute: params.requireDeliveryRoute,
suppressDelivery: params.suppressDelivery === true || params.trigger === "cron" && params.host !== "gateway" ? true : void 0,
deliverToApprovalClientsOnly: params.trigger === "cron" && params.host === "gateway" ? true : void 0,
approvalReviewerDeviceIds: params.approvalReviewerDeviceIds,
...buildExecApprovalTurnSourceContext(params)
};
}
/** Registers a host/node approval request without waiting for a decision. */
async function registerExecApprovalRequestForHost(params) {
return await registerExecApprovalRequest(await buildHostApprovalDecisionParams(params));
}
/** Registers a host/node approval request and wraps failures for exec callers. */
async function registerExecApprovalRequestForHostOrThrow(params) {
try {
return await registerExecApprovalRequestForHost(params);
} catch (err) {
throw new Error(`Exec approval registration failed: ${String(err)}`, { cause: err });
}
}
//#endregion
export { resolveRegisteredExecApprovalDecision as a, registerExecApprovalRequestForHostOrThrow as i, buildExecApprovalTurnSourceContext as n, isExecApprovalRunAbortedError as r, buildExecApprovalRequesterContext as t };