openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
250 lines (249 loc) • 13 kB
JavaScript
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import "./utils-DUAwk2p5.mjs";
import { l as normalizeToolPolicyName, o as expandToolGroups } from "./tool-policy-shared-DSNSYBF4.mjs";
import { r as createToolPolicyMatcher } from "./tool-policy-match-COwlx5YS.mjs";
import { o as expandPolicyWithPluginGroups, r as buildPluginToolGroups } from "./tool-policy-C57wduz9.mjs";
import { i as readCronScheduledToolProjection } from "./exec-tool-target-pinning-CTUpUcAa.mjs";
//#region src/agents/tools/cron-tool-creator-cap.ts
/**
* Closed core-owned vocabulary a CLI backend may project its native tools into.
* Anything else is a backend contract bug and fails closed at capture time so a
* raw harness tool name can never become a persisted cron capability.
*/
const NATIVE_CRON_CREATOR_CAPABILITIES = /* @__PURE__ */ new Set([
"read",
"write",
"edit",
"apply_patch",
"exec",
"process",
"web_search",
"web_fetch"
]);
/** Fails closed on any backend-projected name outside the exact canonical vocabulary. */
function assertNativeCronCreatorCapabilities(names) {
for (const name of names) if (!NATIVE_CRON_CREATOR_CAPABILITIES.has(name)) throw new Error(`cron creator authority rejected non-canonical native capability ${JSON.stringify(name)}`);
}
const CRON_CREATOR_AUTHORITY_RECOVERY_MESSAGE = "Retry from a fresh authenticated direct-local operator turn, or create/edit via the CLI or Gateway with an explicit finite toolsAllow list containing only currently visible tools; no automation changes were saved.";
const INCOMPLETE_CRON_CREATOR_AUTHORITY_MESSAGE = `Configured MCP authority is unavailable because this turn did not capture the complete model-callable tool surface. ${CRON_CREATOR_AUTHORITY_RECOVERY_MESSAGE}`;
/** No capture marker means this runtime has no deferred configured-MCP surface. */
function isCronCreatorToolCaptureComplete(captureRef) {
return captureRef === void 0 || captureRef.value?.source === "final-executable-surface";
}
function assertInheritedCronToolCaptureReady(value, captureRef) {
if ((isRecord(value) && isRecord(value.payload) ? value.payload : void 0)?.toolsAllowIsDefault !== true || isCronCreatorToolCaptureComplete(captureRef)) return;
throw new Error(INCOMPLETE_CRON_CREATOR_AUTHORITY_MESSAGE);
}
function replaceWithEffectiveCronCreatorToolAllowlist(target, tools, toolMeta, options = {}) {
target.length = 0;
const captured = /* @__PURE__ */ new Map();
for (const tool of tools) {
const projection = readCronScheduledToolProjection(tool);
const name = normalizeToolPolicyName(projection ? projection.targetTool : tool.name);
if (!name) continue;
const aliasName = projection ? normalizeToolPolicyName(tool.name) : void 0;
const existing = captured.get(name);
if (existing !== void 0) {
if (aliasName && !existing.aliasName) existing.aliasName = aliasName;
if (existing.execTarget && !projection?.execTarget) delete existing.execTarget;
else if (existing.execTarget?.ask === "always" && projection?.execTarget?.ask !== "always") delete existing.execTarget.ask;
continue;
}
const meta = toolMeta?.(tool);
const pluginId = typeof meta?.pluginId === "string" ? normalizeToolPolicyName(meta.pluginId) : void 0;
captured.set(name, {
name,
...pluginId ? { pluginId } : {},
...aliasName && aliasName !== name ? { aliasName } : {},
...projection?.execTarget ? { execTarget: { ...projection.execTarget } } : {}
});
}
assertNativeCronCreatorCapabilities(options.canonicalToolNames ?? []);
for (const name of options.canonicalToolNames ?? []) {
if (captured.has(name)) continue;
captured.set(name, name === "exec" && options.nativeExecTarget ? {
name,
execTarget: { ...options.nativeExecTarget }
} : { name });
}
target.push(...captured.values());
}
/** Records the creator cap only after every runtime policy and schema quarantine has run. */
function captureFinalEffectiveCronCreatorToolAllowlist(target, captureRef, tools, toolMeta, options = {}) {
replaceWithEffectiveCronCreatorToolAllowlist(target, tools, toolMeta, options);
captureRef.value = {
version: 1,
source: "final-executable-surface"
};
}
function normalizeCronCreatorToolsAllow(values) {
const normalized = [];
const seen = /* @__PURE__ */ new Set();
for (const entry of values) {
const tool = typeof entry === "string" ? { name: entry } : entry;
const name = normalizeToolPolicyName(tool.name);
if (!name || seen.has(name)) continue;
seen.add(name);
const pluginId = typeof tool.pluginId === "string" ? normalizeToolPolicyName(tool.pluginId) : void 0;
const aliasName = typeof tool.aliasName === "string" ? normalizeToolPolicyName(tool.aliasName) : void 0;
const execTarget = tool.execTarget?.host === "gateway" ? {
host: "gateway",
...tool.execTarget.ask === "always" ? { ask: "always" } : {}
} : void 0;
normalized.push({
name,
...pluginId ? { pluginId } : {},
...aliasName && aliasName !== name ? { aliasName } : {},
...execTarget ? { execTarget } : {}
});
}
return normalized;
}
/** Restrict-only exec target present only when the creator's exec grant is host-pinned. */
function resolveCronCreatorExecToolTarget(entries) {
const execEntry = normalizeCronCreatorToolsAllow(entries ?? []).find((tool) => tool.name === "exec");
return execEntry?.execTarget ? { ...execEntry.execTarget } : void 0;
}
function hasCronTriggerScript(value) {
return isRecord(value) && typeof value.script === "string" && value.script.trim().length > 0;
}
function classifyExplicitToolsAllow(payload) {
if (!payload || !Object.hasOwn(payload, "toolsAllow")) return "absent";
if (!Array.isArray(payload.toolsAllow)) return "resolved";
const values = payload.toolsAllow.filter((entry) => typeof entry === "string");
if (values.length === 0) return "empty";
return values.some((entry) => {
const normalized = normalizeToolPolicyName(entry);
return normalized === "*" || normalized.startsWith("group:");
}) ? "resolved" : "finite";
}
function explicitFiniteToolsNeedResolution(payload, creatorToolAllowlist) {
if (classifyExplicitToolsAllow(payload) !== "finite") return false;
const toolsAllow = payload?.toolsAllow;
if (!Array.isArray(toolsAllow)) return false;
const creatorNames = new Set(normalizeCronCreatorToolsAllow(creatorToolAllowlist ?? []).flatMap((tool) => tool.aliasName ? [tool.name, tool.aliasName] : [tool.name]));
return expandToolGroups(toolsAllow.filter((entry) => typeof entry === "string")).some((name) => !creatorNames.has(name));
}
/** Whether an add needs the creator's complete authority rather than an explicit empty cap. */
function cronCreateRequiresCreatorAuthority(value, creatorToolAllowlist) {
if (!isRecord(value)) return false;
const payload = isRecord(value.payload) ? value.payload : void 0;
const explicitToolsAllow = classifyExplicitToolsAllow(payload);
if (explicitToolsAllow === "empty") return false;
if (explicitToolsAllow === "finite") return explicitFiniteToolsNeedResolution(payload, creatorToolAllowlist);
return hasCronTriggerScript(value.trigger) || payload?.kind === "agentTurn" || payload?.kind === "script" || explicitToolsAllow === "resolved";
}
function capCronJobToolsAllow(params) {
const writesToolsAllow = Object.hasOwn(params.payload, "toolsAllow");
if (params.payload.kind !== "agentTurn" && params.payload.kind !== "script" && !hasCronTriggerScript(params.trigger) && !writesToolsAllow) return;
const creatorToolsAllow = normalizeCronCreatorToolsAllow(params.creatorToolAllowlist);
const creatorToolNames = creatorToolsAllow.map((tool) => tool.name);
const requestedRaw = writesToolsAllow ? params.payload.toolsAllow : params.defaultToolsAllow;
if (!Array.isArray(requestedRaw)) {
params.payload.toolsAllow = creatorToolNames;
params.payload.toolsAllowIsDefault = true;
return;
}
const requestedToolsAllow = expandToolGroups(requestedRaw.filter((entry) => typeof entry === "string"));
if (requestedToolsAllow.includes("*")) {
params.payload.toolsAllow = creatorToolNames;
params.payload.toolsAllowIsDefault = true;
return;
}
if (requestedToolsAllow.length === 0 || creatorToolsAllow.length === 0) {
params.payload.toolsAllow = [];
delete params.payload.toolsAllowIsDefault;
return;
}
const pluginGroups = buildPluginToolGroups({
tools: creatorToolsAllow,
toolMeta: (tool) => tool.pluginId ? { pluginId: tool.pluginId } : void 0
});
const requestedPolicy = expandPolicyWithPluginGroups({ allow: requestedToolsAllow }, pluginGroups);
const matches = createToolPolicyMatcher(requestedPolicy);
params.payload.toolsAllow = creatorToolsAllow.filter((tool) => matches(tool.name) || tool.aliasName !== void 0 && matches(tool.aliasName)).map((tool) => tool.name);
delete params.payload.toolsAllowIsDefault;
}
function capCronJobToolsAllowOnCreate(value, creatorToolAllowlist) {
if (!isRecord(value) || !isRecord(value.payload) || !creatorToolAllowlist) return;
capCronJobToolsAllow({
payload: value.payload,
trigger: value.trigger,
creatorToolAllowlist
});
}
function readCronPayloadKind(value) {
return isRecord(value) && typeof value.kind === "string" ? value.kind : void 0;
}
/** Purely derives the agent-tool patch; current job state is requested only when required. */
function planCronJobUpdatePatch(params) {
const patch = structuredClone(params.patch);
const payload = isRecord(patch.payload) ? patch.payload : void 0;
const explicitPayloadKind = readCronPayloadKind(payload);
const explicitToolsAllow = classifyExplicitToolsAllow(payload);
if (payload === void 0 && !Object.hasOwn(patch, "trigger")) return {
kind: "ready",
patch
};
if (explicitPayloadKind !== void 0 && explicitToolsAllow === "absent" && params.creatorAuthorityComplete !== false && !params.creatorToolAllowlist && !Object.hasOwn(patch, "trigger")) return {
kind: "ready",
patch
};
if (params.creatorAuthorityComplete === false && explicitFiniteToolsNeedResolution(payload, params.creatorToolAllowlist)) return { kind: "needs-creator-authority" };
if (params.creatorToolAllowlist && (explicitToolsAllow === "empty" || explicitToolsAllow === "finite") && explicitPayloadKind !== void 0) {
capCronJobToolsAllow({
payload,
trigger: patch.trigger,
creatorToolAllowlist: params.creatorToolAllowlist
});
return {
kind: "ready",
patch
};
}
if (!params.currentJob) return { kind: "needs-current-job" };
const existingPayload = params.currentJob.payload;
const existingPayloadRecord = isRecord(existingPayload) ? existingPayload : void 0;
const existingPayloadKind = readCronPayloadKind(existingPayload);
const payloadKind = explicitPayloadKind ?? existingPayloadKind;
if (payload && payloadKind !== void 0) {
payload.kind = payloadKind;
patch.payload = payload;
}
const trigger = Object.hasOwn(patch, "trigger") ? patch.trigger : params.currentJob.trigger;
const startsToolPayload = explicitPayloadKind !== void 0 && explicitPayloadKind !== existingPayloadKind && (payloadKind === "agentTurn" || payloadKind === "script");
const startsToolTrigger = Object.hasOwn(patch, "trigger") && hasCronTriggerScript(trigger) && !hasCronTriggerScript(params.currentJob.trigger);
const reusesDefaultAuthority = explicitToolsAllow === "absent" && (startsToolPayload || startsToolTrigger) && (existingPayloadRecord?.toolsAllowIsDefault === true || !Array.isArray(existingPayloadRecord?.toolsAllow));
const needsResolvedAuthority = explicitToolsAllow === "resolved" || reusesDefaultAuthority || explicitFiniteToolsNeedResolution(payload, params.creatorToolAllowlist);
if (needsResolvedAuthority && params.creatorAuthorityComplete === false) return { kind: "needs-creator-authority" };
if (!needsResolvedAuthority && (explicitToolsAllow === "empty" || explicitToolsAllow === "finite") && params.creatorToolAllowlist) {
capCronJobToolsAllow({
payload,
trigger,
creatorToolAllowlist: params.creatorToolAllowlist
});
return {
kind: "ready",
patch
};
}
if (!needsResolvedAuthority || !params.creatorToolAllowlist) return {
kind: "ready",
patch
};
const nextPayload = payload ?? {};
if (payloadKind !== void 0) nextPayload.kind = payloadKind;
patch.payload = nextPayload;
capCronJobToolsAllow({
payload: nextPayload,
trigger,
creatorToolAllowlist: params.creatorToolAllowlist,
defaultToolsAllow: existingPayloadRecord && existingPayloadRecord.toolsAllowIsDefault !== true ? existingPayloadRecord.toolsAllow : void 0
});
return {
kind: "ready",
patch
};
}
//#endregion
export { assertNativeCronCreatorCapabilities as a, cronCreateRequiresCreatorAuthority as c, replaceWithEffectiveCronCreatorToolAllowlist as d, resolveCronCreatorExecToolTarget as f, assertInheritedCronToolCaptureReady as i, isCronCreatorToolCaptureComplete as l, INCOMPLETE_CRON_CREATOR_AUTHORITY_MESSAGE as n, capCronJobToolsAllowOnCreate as o, NATIVE_CRON_CREATOR_CAPABILITIES as r, captureFinalEffectiveCronCreatorToolAllowlist as s, CRON_CREATOR_AUTHORITY_RECOVERY_MESSAGE as t, planCronJobUpdatePatch as u };