UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

1,403 lines 70.7 kB
import { R as timestampMsToIsoString, t as MAX_DATE_TIMESTAMP_MS } from "./number-coercion-CLj0HTDM.js";
import { c as isRecord } from "./record-coerce-DItp3I4t.js";
import { o as normalizeLowercaseStringOrEmpty, t as hasNonEmptyString } from "./string-coerce-CIXf7egm.js";
import { i as truncateWithMarker } from "./utf16-slice-D_ngcYKd.js";
import { n as getRuntimeConfig } from "./io.runtime-B9iJRs3w.js";
import "./utils-P__uGsPB.js";
import { O as parseAgentSessionKey } from "./session-key-BnWWjqNc.js";
import { t as parseDurationMs } from "./parse-duration-CuuCHKpt.js";
import { t as isStringOption } from "./string-readers-e58-jh1A.js";
import { r as CRON_TOOL_DISPLAY_SUMMARY } from "./tool-description-presets-1n9mie5B.js";
import { t as AUTOMATIONS_TOOL_NAME } from "./automations-tool-name-DBMZPbPL.js";
import { a as expandToolGroups, c as normalizeToolPolicyName } from "./tool-policy-shared-DIyS0iQC.js";
import { n as createToolPolicyMatcher } from "./tool-policy-match-TnFxBs5z.js";
import { o as expandPolicyWithPluginGroups, r as buildPluginToolGroups } from "./tool-policy-Wi0C45cX.js";
import { _ as resolveSessionAgentId } from "./agent-scope-DbtJyKUL.js";
import "./config-Cs0XXL3x.js";
import "./client-I-RoP1Al.js";
import { t as GatewayClientRequestError } from "./request-error-BSFClQsA.js";
import { m as recordCronNextCheckProposal } from "./agent-run-registry-CKYKdfNd.js";
import { d as readCanonicalCronListPage, f as resolveCronListPageNextOffset } from "./loader-DPiOPJjR.js";
import { a as optionalNonNegativeIntegerSchema, c as stringEnum, i as optionalFiniteNumberSchema, o as optionalPositiveIntegerSchema, s as optionalStringEnum } from "./typebox-BdE5GwKs.js";
import { t as jsonResult } from "./tool-results-BCM3fdVS.js";
import { d as readPositiveIntegerParam, h as readToolStringParam, l as readNonNegativeIntegerParam } from "./common-Bm6UTDDA.js";
import { n as extractTextFromChatContent } from "./chat-content-DNdfeXZh.js";
import { r as normalizeCronJobPatch, t as normalizeCronJobCreate } from "./normalize-Dd-LvsuI.js";
import { t as parseCronPacingBounds } from "./pacing-D3hd6hdq.js";
import { s as setToolTerminalPresentation, u as readCronScheduledToolProjection } from "./agent-tool-metadata-CZvIgxro.js";
import { a as withGatewayToolCallerIdentity, r as getGatewayToolCallerIdentity } from "./gateway-caller-context-BxVUFvkR.js";
import { n as readGatewayCallOptions, t as callGatewayTool } from "./gateway-CB9m4Gcq.js";
import { t as gatewayCallOptionSchemaProperties } from "./gateway-schema-BUGITwui.js";
import { m as resolveMainSessionAlias, p as resolveInternalSessionKey } from "./sessions-helpers-B2gzzr60.js";
import { t as resolveCronCreationDelivery } from "./delivery-context-zUJOeLlg.js";
import { t as assertCronDeliveryInputNonBlankFields } from "./delivery-target-validation-D5dmr1ev.js";
import { t as normalizeHttpWebhookUrl } from "./webhook-url-AutetAqs.js";
import { t as CRON_MANAGEMENT_METHODS } from "./cron-creator-authority-grant-CDgrJQRP.js";
import { r as bindCronManagementGrant } from "./cron-creator-authority-context-CkDgGats.js";
import { Type } from "typebox";
//#region src/agents/tools/cron-tool-canonicalize.ts
/**
* Cron tool argument canonicalization.
*
* Recovers flat or partial model/tool inputs into the structured cron job/patch shape.
*/
const CRON_SCHEDULE_KINDS$1 = [
	"at",
	"every",
	"cron",
	"on-exit",
	"stream"
];
const CRON_PAYLOAD_KINDS$1 = [
	"systemEvent",
	"agentTurn",
	"script",
	"command"
];
const CRON_FLAT_PAYLOAD_KEYS = [
	"message",
	"text",
	"script",
	"model",
	"fallbacks",
	"toolsAllow",
	"thinking",
	"timeoutSeconds",
	"toolBudget",
	"lightContext",
	"allowUnsafeExternalContent"
];
const CRON_FLAT_SCHEDULE_KEYS = [
	"kind",
	"at",
	"atMs",
	"every",
	"everyMs",
	"anchorMs",
	"cron",
	"expr",
	"tz",
	"stagger",
	"staggerMs",
	"exact",
	"command",
	"cwd",
	"mode",
	"match",
	"batchMs",
	"maxBatchBytes"
];
const CRON_RECOVERABLE_OBJECT_KEYS = /* @__PURE__ */ new Set([
	"name",
	"declarationKey",
	"displayName",
	"owner",
	"schedule",
	"pacing",
	"trigger",
	"sessionTarget",
	"wakeMode",
	"payload",
	"delivery",
	"enabled",
	"description",
	"deleteAfterRun",
	"agentId",
	"sessionKey",
	"failureAlert",
	"namePayload",
	"scheduleKind",
	"sessionTargetName",
	...CRON_FLAT_PAYLOAD_KEYS,
	...CRON_FLAT_SCHEDULE_KEYS
]);
function isCronScheduleKind(value) {
	return isStringOption(value, CRON_SCHEDULE_KINDS$1);
}
function isCronPayloadKind(value) {
	return isStringOption(value, CRON_PAYLOAD_KINDS$1);
}
function isStringArrayOrNull(value) {
	return value === null || Array.isArray(value) && value.every((entry) => typeof entry === "string");
}
function moveDefinedField(params) {
	if (params.source[params.from] === void 0) return false;
	params.target[params.to ?? params.from] = params.source[params.from];
	delete params.source[params.from];
	return true;
}
function repairConcatenatedCronToolKeys(value) {
	if (!isRecord(value.payload) && isRecord(value.namePayload)) value.payload = { ...value.namePayload };
	const rawScheduleKind = value.scheduleKind;
	if (!isRecord(value.schedule)) {
		if (isRecord(rawScheduleKind)) value.schedule = { ...rawScheduleKind };
		else if (isCronScheduleKind(rawScheduleKind)) value.schedule = { kind: rawScheduleKind };
	} else if (isCronScheduleKind(rawScheduleKind) && !isCronScheduleKind(value.schedule.kind)) value.schedule = {
		...value.schedule,
		kind: rawScheduleKind
	};
	if (!hasNonEmptyString(value.name) && hasNonEmptyString(value.sessionTargetName)) value.name = value.sessionTargetName;
	delete value.namePayload;
	delete value.scheduleKind;
	delete value.sessionTargetName;
}
function setScheduleAtMs(schedule, value) {
	const atMs = typeof value === "number" ? value : Number(value);
	schedule.at = Number.isFinite(atMs) ? timestampMsToIsoString(Math.floor(atMs)) ?? value : value;
}
function canonicalizeCronToolSchedule(value) {
	const schedule = isRecord(value.schedule) ? { ...value.schedule } : {};
	let hasSchedule = isRecord(value.schedule);
	if (schedule.atMs !== void 0) {
		setScheduleAtMs(schedule, schedule.atMs);
		delete schedule.atMs;
		if (!isCronScheduleKind(schedule.kind)) schedule.kind = "at";
	}
	if (schedule.everyMs === void 0 && schedule.every !== void 0) {
		schedule.everyMs = schedule.every;
		delete schedule.every;
	}
	if (schedule.expr === void 0 && schedule.cron !== void 0) {
		schedule.expr = schedule.cron;
		delete schedule.cron;
	}
	if (schedule.staggerMs === void 0 && schedule.stagger !== void 0) {
		schedule.staggerMs = schedule.stagger;
		delete schedule.stagger;
	}
	if (schedule.exact === true && schedule.staggerMs === void 0) schedule.staggerMs = 0;
	delete schedule.exact;
	if (isCronScheduleKind(value.kind) && !isCronScheduleKind(schedule.kind)) {
		schedule.kind = value.kind;
		delete value.kind;
		hasSchedule = true;
	}
	if (moveDefinedField({
		source: value,
		target: schedule,
		from: "at"
	}) && !isCronScheduleKind(schedule.kind)) schedule.kind = "at";
	if (value.atMs !== void 0) {
		setScheduleAtMs(schedule, value.atMs);
		delete value.atMs;
		if (!isCronScheduleKind(schedule.kind)) schedule.kind = "at";
		hasSchedule = true;
	}
	if ((moveDefinedField({
		source: value,
		target: schedule,
		from: "everyMs"
	}) || moveDefinedField({
		source: value,
		target: schedule,
		from: "every",
		to: "everyMs"
	})) && !isCronScheduleKind(schedule.kind)) schedule.kind = "every";
	if ((moveDefinedField({
		source: value,
		target: schedule,
		from: "cron",
		to: "expr"
	}) || moveDefinedField({
		source: value,
		target: schedule,
		from: "expr"
	})) && !isCronScheduleKind(schedule.kind)) schedule.kind = "cron";
	if (moveDefinedField({
		source: value,
		target: schedule,
		from: "command"
	}) && !isCronScheduleKind(schedule.kind)) schedule.kind = "on-exit";
	for (const key of [
		"anchorMs",
		"tz",
		"staggerMs",
		"cwd",
		"mode",
		"match",
		"batchMs",
		"maxBatchBytes"
	]) hasSchedule = moveDefinedField({
		source: value,
		target: schedule,
		from: key
	}) || hasSchedule;
	hasSchedule = moveDefinedField({
		source: value,
		target: schedule,
		from: "stagger",
		to: "staggerMs"
	}) || hasSchedule;
	if (value.exact === true && schedule.staggerMs === void 0) {
		schedule.staggerMs = 0;
		hasSchedule = true;
	}
	delete value.exact;
	if (!isCronScheduleKind(schedule.kind)) {
		if (schedule.at !== void 0) schedule.kind = "at";
		else if (schedule.everyMs !== void 0) schedule.kind = "every";
		else if (schedule.expr !== void 0) schedule.kind = "cron";
		else if (schedule.command !== void 0) schedule.kind = "on-exit";
	}
	if (hasSchedule || Object.keys(schedule).length > 0) value.schedule = schedule;
}
function canonicalizeCronToolPayload(value) {
	const payload = isRecord(value.payload) ? { ...value.payload } : {};
	let hasPayload = isRecord(value.payload);
	for (const key of CRON_FLAT_PAYLOAD_KEYS) hasPayload = moveDefinedField({
		source: value,
		target: payload,
		from: key
	}) || hasPayload;
	if (isCronPayloadKind(value.kind) && !isCronPayloadKind(payload.kind)) {
		payload.kind = value.kind;
		delete value.kind;
		hasPayload = true;
	}
	if (!isCronPayloadKind(payload.kind)) {
		if (hasNonEmptyString(payload.script)) payload.kind = "script";
		else if (hasNonEmptyString(payload.message) || hasNonEmptyString(payload.model) || payload.model === null || hasNonEmptyString(payload.thinking) || typeof payload.timeoutSeconds === "number" && hasNonEmptyString(payload.text) || typeof payload.lightContext === "boolean" || typeof payload.allowUnsafeExternalContent === "boolean" || payload.fallbacks !== void 0 && isStringArrayOrNull(payload.fallbacks)) payload.kind = "agentTurn";
		else if (hasNonEmptyString(payload.text)) payload.kind = "systemEvent";
	}
	if (hasPayload || Object.keys(payload).length > 0) value.payload = payload;
}
/**
* Normalizes whitespace-padded cron object keys. Some tool-call
* extraction/serialization pipelines can produce keys with trailing spaces
* (e.g. "schedule " instead of "schedule"), which causes strict gateway
* validation to reject the job with "unexpected property" errors.
*
* Only recognized CRON_RECOVERABLE_OBJECT_KEYS are trimmed — arbitrary keys
* (including special ones like "__proto__") are never mutated.
*
* If both the padded and canonical form of a key exist (e.g. "schedule " and
* "schedule"), the padded key is preserved so strict gateway validation
* rejects the ambiguous input rather than silently picking one value.
*/
function repairPaddedCronKeys(value) {
	for (const key of Object.keys(value)) {
		const trimmed = key.trim();
		if (trimmed !== key && CRON_RECOVERABLE_OBJECT_KEYS.has(trimmed)) {
			if (!(trimmed in value)) {
				value[trimmed] = value[key];
				delete value[key];
			}
		}
	}
}
/** Converts model-friendly cron tool shorthands into the nested gateway job/patch shape. */
function canonicalizeCronToolObject(value) {
	const next = { ...isRecord(value.data) ? value.data : isRecord(value.job) ? value.job : value };
	repairPaddedCronKeys(next);
	repairConcatenatedCronToolKeys(next);
	canonicalizeCronToolSchedule(next);
	canonicalizeCronToolPayload(next);
	return next;
}
const CRON_CREATE_NULLABLE_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["agentId", "sessionKey"]);
function deleteNullFields(record, keep) {
	for (const [key, entry] of Object.entries(record)) if (entry === null && !keep?.has(key)) delete record[key];
	else if (isRecord(entry)) deleteNullFields(entry);
}
/**
* Drops null-valued fields from a create job in place. The model-facing job
* schema is shared with update, where null means "clear this field"; on create
* there is nothing to clear, and the strict gateway cron.add contract rejects
* the nulls its update patch accepts.
*/
function stripCronCreateNullClears(value) {
	deleteNullFields(value, CRON_CREATE_NULLABLE_TOP_LEVEL_KEYS);
	return value;
}
/** Detects recovered update patches that contain no meaningful cron fields after normalization. */
function isEmptyRecoveredCronPatch(value) {
	if (!isRecord(value)) return true;
	const keys = Object.keys(value);
	return keys.length === 0 || keys.length === 1 && keys[0] === "payload" && isRecord(value.payload) && Object.keys(value.payload).length === 0;
}
/** Recovers cron job or patch fields that a model flattened beside the action arguments. */
function recoverCronObjectFromFlatParams(params) {
	const value = {};
	let found = false;
	for (const key of Object.keys(params)) if (CRON_RECOVERABLE_OBJECT_KEYS.has(key) && params[key] !== void 0) {
		value[key] = params[key];
		found = true;
	}
	return {
		found,
		value: canonicalizeCronToolObject(value)
	};
}
/** Checks whether a recovered flat object has enough schedule/payload signal to create a job. */
function hasCronCreateSignal(value) {
	return value.schedule !== void 0 || value.at !== void 0 || value.atMs !== void 0 || value.everyMs !== void 0 || value.cron !== void 0 || value.expr !== void 0 || value.payload !== void 0 || value.message !== void 0 || value.text !== void 0;
}
const CRON_ACTIONS = [
	"status",
	"list",
	"get",
	"add",
	"update",
	"remove",
	"run",
	"runs",
	"next_check",
	"wake"
];
const CRON_SCHEDULE_KINDS = [
	"at",
	"every",
	"cron",
	"stream"
];
const CRON_SCHEDULE_KINDS_TRIGGERS_DISABLED = [
	"at",
	"every",
	"cron"
];
const CRON_WAKE_MODES = ["now", "next-heartbeat"];
const CRON_PAYLOAD_KINDS = [
	"systemEvent",
	"agentTurn",
	"script"
];
const CRON_PAYLOAD_KINDS_TRIGGERS_DISABLED = ["systemEvent", "agentTurn"];
const CRON_DELIVERY_MODES = [
	"none",
	"announce",
	"webhook"
];
const CRON_RUN_MODES = ["due", "force"];
function nullableStringSchema(description) {
	return Type.Optional(Type.Union([Type.String(), Type.Null()], { description }));
}
function nullableStringArraySchema(description) {
	return Type.Optional(Type.Union([Type.Array(Type.String()), Type.Null()], { description }));
}
function deliveryStringSchema(description) {
	return nullableStringSchema(`${description}, or null to clear`);
}
function createCronScheduleSchema(params) {
	return Type.Optional(Type.Object({
		kind: optionalStringEnum([...params.triggersEnabled ? CRON_SCHEDULE_KINDS : CRON_SCHEDULE_KINDS_TRIGGERS_DISABLED, ...params.management ? ["on-exit"] : []], { description: "Schedule kind" }),
		at: Type.Optional(Type.String({ description: "ISO-8601 time (kind=at)" })),
		everyMs: optionalPositiveIntegerSchema({
			description: "Interval ms (kind=every)",
			maximum: MAX_DATE_TIMESTAMP_MS
		}),
		anchorMs: optionalNonNegativeIntegerSchema({
			description: "Start anchor ms (kind=every)",
			maximum: MAX_DATE_TIMESTAMP_MS
		}),
		expr: Type.Optional(Type.String({ description: "Cron wall-time expr; never UTC-convert. Missing tz=Gateway local. Example \"0 18 * * *\", \"Asia/Shanghai\"." })),
		tz: Type.Optional(Type.String({ description: "IANA timezone for wall-clock fields; missing=Gateway host local timezone. Example \"Asia/Shanghai\"." })),
		staggerMs: optionalNonNegativeIntegerSchema({
			description: "Jitter ms (kind=cron)",
			maximum: MAX_DATE_TIMESTAMP_MS
		}),
		...params.triggersEnabled || params.management ? {
			command: Type.Optional(Type.Union([Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }), ...params.management ? [Type.String()] : []], { description: "Supervised source argv (kind=stream; disabled when cron.triggers.enabled=false)" })),
			cwd: Type.Optional(Type.String({ description: "Working directory (kind=stream)" })),
			mode: optionalStringEnum(["line", "match"]),
			match: Type.Optional(Type.String({ description: "Regex source (stream match mode)" })),
			batchMs: optionalNonNegativeIntegerSchema(),
			maxBatchBytes: optionalNonNegativeIntegerSchema()
		} : {}
	}, { additionalProperties: true }));
}
function createCronPacingSchema() {
	const pacing = Type.Object({
		min: Type.Optional(Type.String({ description: "Minimum dynamic delay" })),
		max: Type.Optional(Type.String({ description: "Maximum dynamic delay" }))
	}, {
		additionalProperties: false,
		description: "Dynamic-cadence bounds; at least one of min or max is required"
	});
	return Type.Optional(Type.Union([pacing, Type.Null()]));
}
function assertCronPacingInput(value) {
	if (value === void 0 || value === null) return;
	if (!isRecord(value)) throw new Error("cron pacing must be an object");
	parseCronPacingBounds(value);
}
function createCronPayloadSchema(params) {
	return Type.Optional(Type.Object({
		kind: optionalStringEnum([...params.triggersEnabled ? CRON_PAYLOAD_KINDS : CRON_PAYLOAD_KINDS_TRIGGERS_DISABLED, ...params.management ? ["command"] : []], { description: "Payload kind" }),
		text: Type.Optional(Type.String({ description: "systemEvent text" })),
		message: Type.Optional(Type.String({ description: "agentTurn prompt" })),
		...params.management ? { argv: Type.Optional(Type.Array(Type.String(), { description: "Existing command job argv" })) } : {},
		...params.triggersEnabled ? { script: Type.Optional(Type.String({ description: "Headless code-mode script" })) } : {},
		model: nullableStringSchema("Model override, or null to clear"),
		thinking: Type.Optional(Type.String({ description: "Thinking override" })),
		timeoutSeconds: optionalFiniteNumberSchema({ minimum: 0 }),
		...params.triggersEnabled ? { toolBudget: optionalPositiveIntegerSchema({ description: "Maximum script tool calls" }) } : {},
		lightContext: Type.Optional(Type.Boolean({ description: "Lightweight bootstrap context (skip full workspace context)" })),
		allowUnsafeExternalContent: Type.Optional(Type.Boolean({ description: "Allow untrusted external content in prompt" })),
		fallbacks: nullableStringArraySchema("Fallback models, or null to clear"),
		toolsAllow: nullableStringArraySchema("Allowed tool ids, or null to clear")
	}, { additionalProperties: true }));
}
function createCronTriggerSchema() {
	const trigger = Type.Object({
		script: Type.String({
			minLength: 1,
			maxLength: 65536
		}),
		once: Type.Optional(Type.Boolean())
	}, { additionalProperties: false });
	return Type.Optional(Type.Union([trigger, Type.Null()]));
}
function createCronDeliverySchema() {
	const failureDestinationObject = Type.Object({
		channel: deliveryStringSchema("Failure delivery channel"),
		to: deliveryStringSchema("Failure delivery target"),
		accountId: deliveryStringSchema("Failure delivery account"),
		mode: Type.Optional(Type.Union([
			Type.Literal("announce"),
			Type.Literal("webhook"),
			Type.Null()
		]))
	}, { additionalProperties: true });
	const completionDestinationObject = Type.Object({
		mode: Type.Literal("webhook"),
		to: Type.String({
			minLength: 1,
			description: "Completion webhook target; only valid with delivery.mode=announce"
		})
	}, { additionalProperties: true });
	return Type.Optional(Type.Object({
		mode: optionalStringEnum(CRON_DELIVERY_MODES, { description: "Delivery mode" }),
		channel: deliveryStringSchema("Delivery channel"),
		to: deliveryStringSchema("Delivery target"),
		threadId: Type.Optional(Type.Union([
			Type.String(),
			Type.Number(),
			Type.Null()
		], { description: "Thread/topic id" })),
		bestEffort: Type.Optional(Type.Boolean({ description: "Omitted/false requires requested delivery for successful completion; true lets successful execution complete and delete a one-shot despite failed/unknown delivery. Intentional silence succeeds in either mode." })),
		accountId: deliveryStringSchema("Delivery account"),
		failureDestination: Type.Optional(Type.Union([failureDestinationObject, Type.Null()], { description: "Failure-alert route override; required-delivery failures bypass after but share the execution-alert cooldown; null clears." })),
		completionDestination: Type.Optional(Type.Union([completionDestinationObject, Type.Null()], { description: "Completion webhook; requires delivery.mode=announce; null clears." }))
	}, { additionalProperties: true }));
}
function createCronFailureAlertSchema() {
	return Type.Optional(Type.Unsafe({
		type: "object",
		properties: {
			after: optionalPositiveIntegerSchema({ description: "Consecutive execution failures before alert; delivery failures bypass this threshold" }),
			channel: Type.Optional(Type.String({ description: "Alert channel" })),
			to: Type.Optional(Type.String({ description: "Alert target" })),
			cooldownMs: optionalNonNegativeIntegerSchema({ description: "Alert cooldown ms" }),
			includeSkipped: Type.Optional(Type.Boolean({ description: "Count skipped runs." })),
			mode: optionalStringEnum(["announce", "webhook"]),
			accountId: Type.Optional(Type.String())
		},
		additionalProperties: true,
		description: "Failure alert policy/route override. Route-backed jobs default to after=2 for execution failures and cooldownMs=3600000 for all failure alerts; false disables execution/delivery alerts but not the auto-disable safety notice."
	}));
}
function createCronToolSchema(options) {
	const triggersEnabled = options?.triggersEnabled !== false;
	const management = Boolean(options?.management);
	const managementOnly = options?.management === "only";
	const job = Type.Optional(Type.Object({
		name: Type.Optional(Type.String({ description: "Job name" })),
		declarationKey: Type.Optional(Type.String({
			description: "Idempotent declaration key (add only).",
			minLength: 1,
			maxLength: 200
		})),
		displayName: Type.Optional(Type.Union([Type.String({ maxLength: 200 }), Type.Null()], { description: "Human-readable label; null clears it" })),
		owner: Type.Optional(Type.Object({
			agentId: Type.Optional(Type.String()),
			sessionKey: Type.Optional(Type.String())
		}, { additionalProperties: false })),
		schedule: createCronScheduleSchema({
			triggersEnabled,
			management
		}),
		pacing: createCronPacingSchema(),
		...triggersEnabled ? { trigger: createCronTriggerSchema() } : {},
		sessionTarget: Type.Optional(Type.String({ description: "main | isolated | current (agentTurn default) | session:<id>" })),
		wakeMode: optionalStringEnum(CRON_WAKE_MODES, { description: "Wake timing" }),
		payload: createCronPayloadSchema({
			triggersEnabled,
			management
		}),
		delivery: createCronDeliverySchema(),
		...management || !options?.agentSessionKey?.trim() ? { agentId: nullableStringSchema("Agent id, or null to clear it") } : {},
		description: Type.Optional(Type.String({ description: "Human description" })),
		enabled: Type.Optional(Type.Boolean()),
		deleteAfterRun: Type.Optional(Type.Boolean({ description: "Delete one-shot after successful completion: delivery confirmed, not requested, intentionally silent, or explicitly bestEffort. Failed/unknown required delivery retains it disabled." })),
		sessionKey: nullableStringSchema("Explicit session key, or null to clear it"),
		failureAlert: createCronFailureAlertSchema()
	}, {
		additionalProperties: true,
		description: managementOnly ? "Partial update: only supplied fields change; null clears." : "Job fields. action=\"add\": full job. action=\"update\": partial patch — only supplied fields change; null clears."
	}));
	const schema = Type.Object({
		action: stringEnum(managementOnly ? CRON_MANAGEMENT_METHODS.map((method) => method.slice(5)) : CRON_ACTIONS),
		...gatewayCallOptionSchemaProperties(),
		includeDisabled: Type.Optional(Type.Boolean()),
		limit: optionalPositiveIntegerSchema({
			maximum: 200,
			description: "Maximum jobs returned by action=\"list\""
		}),
		offset: optionalNonNegativeIntegerSchema({ description: "Job offset for action=\"list\"; use nextOffset to load the next page" }),
		job: managementOnly ? Type.Optional(Type.Omit(job, ["declarationKey", "owner"])) : job,
		jobId: Type.Optional(Type.String()),
		id: Type.Optional(Type.String()),
		in: Type.Optional(Type.String({ description: "Relative duration for action=\"next_check\" (for example, \"15m\")" })),
		text: Type.Optional(Type.String({ description: "systemEvent text for action=\"wake\"" })),
		mode: optionalStringEnum(CRON_WAKE_MODES, { description: "Wake mode for action=\"wake\" (default next-heartbeat)" }),
		runMode: optionalStringEnum(CRON_RUN_MODES, { description: "Run mode for action=\"run\": omitted defaults to \"due\"; use \"force\" to trigger now." }),
		contextMessages: Type.Optional(Type.Integer({
			minimum: 0,
			maximum: 10
		})),
		agentId: Type.Optional(Type.String({ description: managementOnly ? "Agent filter for action=\"list\"." : "List filter for `action: \"list\"`; wake target override for `action: \"wake\"` (defaults to the calling agent when omitted on wake)" })),
		sessionKey: Type.Optional(Type.String({ description: "Wake target override for `action: \"wake\"`: route the event to another session owned by the calling agent. Defaults to the resolved calling-session key when omitted." }))
	}, { additionalProperties: true });
	return managementOnly ? Type.Omit(schema, [
		"in",
		"text",
		"mode",
		"contextMessages",
		"sessionKey"
	]) : schema;
}
//#endregion
//#region src/agents/tools/cron-tool-context.ts
/** Reminder-context projection for cron tool job creation. */
const REMINDER_CONTEXT_PER_MESSAGE_MAX = 220;
const REMINDER_CONTEXT_TOTAL_MAX = 700;
const REMINDER_CONTEXT_MARKER = "\n\nRecent context:\n";
function stripExistingContext(text) {
	const index = text.indexOf(REMINDER_CONTEXT_MARKER);
	if (index === -1) return text;
	return text.slice(0, index).trim();
}
function truncateText(input, maxLen) {
	return truncateWithMarker(input, maxLen, {
		marker: "...",
		reserve: 3,
		trimEnd: true
	});
}
function extractMessageText(message) {
	const role = typeof message.role === "string" ? message.role : "";
	if (role !== "user" && role !== "assistant") return null;
	const text = extractTextFromChatContent(message.content);
	return text ? {
		role,
		text
	} : null;
}
async function buildReminderContextLines(params) {
	const maxMessages = Math.min(10, Math.max(0, Math.floor(params.contextMessages)));
	if (maxMessages <= 0) return [];
	const sessionKey = params.agentSessionKey?.trim();
	if (!sessionKey) return [];
	const cfg = getRuntimeConfig();
	const { mainKey, alias } = resolveMainSessionAlias(cfg);
	const resolvedKey = resolveInternalSessionKey({
		key: sessionKey,
		alias,
		mainKey
	});
	try {
		const res = await params.callGatewayTool("chat.history", params.gatewayOpts, {
			sessionKey: resolvedKey,
			agentId: params.agentId,
			limit: maxMessages
		});
		const recent = (Array.isArray(res?.messages) ? res.messages : []).map((msg) => extractMessageText(msg)).filter((msg) => Boolean(msg)).slice(-maxMessages);
		if (recent.length === 0) return [];
		const lines = [];
		let total = 0;
		for (const entry of recent) {
			const line = `- ${entry.role === "user" ? "User" : "Assistant"}: ${truncateText(entry.text, REMINDER_CONTEXT_PER_MESSAGE_MAX)}`;
			total += line.length;
			if (total > REMINDER_CONTEXT_TOTAL_MAX) break;
			lines.push(line);
		}
		return lines;
	} catch {
		return [];
	}
}
//#endregion
//#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 = Object.hasOwn(params.payload, "toolsAllow") ? 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)) return;
	if (!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 ?? readCronPayloadKind(existingPayload);
	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
//#region src/agents/tools/cron-tool-self-list.ts
const CRON_SELF_LIST_MAX_PAGES = 50;
const CRON_SELF_LIST_MAX_SNAPSHOT_RESTARTS = 3;
function filterDeliveryPreviewsByJobId(previews, jobId) {
	if (!isRecord(previews)) return previews;
	return Object.hasOwn(previews, jobId) ? { [jobId]: previews[jobId] } : {};
}
function filterCronListResultToJobId(result, jobId) {
	if (!isRecord(result) || !Array.isArray(result.jobs)) throw new Error("cron.list returned an invalid inventory page");
	const jobs = result.jobs.filter((job) => isRecord(job) && job.id === jobId);
	const filteredResult = {
		...result,
		jobs,
		total: jobs.length,
		offset: 0,
		limit: jobs.length,
		hasMore: false,
		nextOffset: null,
		...Object.hasOwn(result, "deliveryPreviews") ? { deliveryPreviews: filterDeliveryPreviewsByJobId(result.deliveryPreviews, jobId) } : {}
	};
	delete filteredResult.snapshotRevision;
	return filteredResult;
}
function cronListPageHasJob(result, jobId) {
	return result.jobs.some((job) => isRecord(job) && job.id === jobId);
}
async function listCronSelfJob(params) {
	for (let restart = 0; restart <= CRON_SELF_LIST_MAX_SNAPSHOT_RESTARTS; restart += 1) {
		let offset = 0;
		let snapshotRevision;
		let total;
		let snapshotChanged = false;
		for (let pageNumber = 0; pageNumber < CRON_SELF_LIST_MAX_PAGES; pageNumber += 1) {
			const page = readCanonicalCronListPage(await params.requestPage({
				limit: params.pageSize,
				offset
			}), params.pageSize);
			if (snapshotRevision !== void 0 && page.snapshotRevision !== snapshotRevision || total !== void 0 && page.total !== total) {
				snapshotChanged = true;
				break;
			}
			snapshotRevision ??= page.snapshotRevision;
			total ??= page.total;
			const nextOffset = resolveCronListPageNextOffset(page, offset);
			if (cronListPageHasJob(page, params.jobId) || nextOffset === null) return filterCronListResultToJobId(page, params.jobId);
			offset = nextOffset;
		}
		if (!snapshotChanged) throw new Error("cron.list pagination exceeded maximum pages while reading current automation");
		if (restart === CRON_SELF_LIST_MAX_SNAPSHOT_RESTARTS) throw new Error("cron.list inventory changed repeatedly while reading current automation");
	}
	throw new Error("cron.list inventory changed repeatedly while reading current automation");
}
//#endregion
//#region src/agents/tools/cron-tool-write.ts
function assertNoCronShellExecution(value) {
	if (!isRecord(value)) return;
	const payload = isRecord(value.payload) ? value.payload : void 0;
	if (normalizeLowercaseStringOrEmpty(payload?.kind) === "command") throw new Error("automation command payloads cannot be created or edited through the agent automations tool; use the CLI or Gateway API.");
	if ((isRecord(value.schedule) ? value.schedule : void 0)?.kind === "on-exit") throw new Error("automation on-exit schedules cannot be created or edited through the agent automations tool; use the CLI or Gateway API.");
}
function assertCronCreatorAuthorityResolutionAvailable(params) {
	if (!params.required || params.resolveCreatorToolAuthority) return;
	if (params.unavailableReason === "queued-local-operator-configured-mcp" || !isCronCreatorToolCaptureComplete(params.creatorToolAllowlistCaptureRef)) throw new Error(params.unavailableReason === "queued-local-operator-configured-mcp" ? `Configured MCP authority is unavailable because this local operator turn was queued. ${CRON_CREATOR_AUTHORITY_RECOVERY_MESSAGE}` : INCOMPLETE_CRON_CREATOR_AUTHORITY_MESSAGE);
}
async function prepareCronJobUpdateForGateway(params) {
	params.operationSignal?.throwIfAborted();
	const initialPlan = planCronJobUpdatePatch({
		patch: params.patch,
		creatorToolAllowlist: params.creatorToolAllowlist,
		creatorAuthorityComplete: params.creatorAuthorityComplete
	});
	if (initialPlan.kind === "ready") return { patch: initialPlan.patch };
	const existing = await params.callGateway("cron.get", params.gatewayOpts, { id: params.id });
	params.operationSignal?.throwIfAborted();
	const existingRecord = isRecord(existing) ? existing : void 0;
	const expectedConfigRevision = existingRecord?.configRevision;
	if (typeof expectedConfigRevision !== "string" || expectedConfigRevision.length === 0) throw new Error("cron.get response is missing configRevision; restart the Gateway before retrying this update");
	let resolvedAuthority;
	let finalPlan = planCronJobUpdatePatch({
		patch: params.patch,
		creatorToolAllowlist: params.creatorToolAllowlist,
		currentJob: existingRecord,
		creatorAuthorityComplete: params.creatorAuthorityComplete
	});
	if (finalPlan.kind === "needs-creator-authority") {
		assertCronCreatorAuthorityResolutionAvailable({
			required: true,
			resolveCreatorToolAuthority: params.resolveCreatorToolAuthority,
			creatorToolAllowlistCaptureRef: params.creatorToolAllowlistCaptureRef,
			unavailableReason: params.creatorAuthorityUnavailableReason
		});
		if (!params.resolveCreatorToolAuthority) throw new Error("cron update requires complete creator tool authority");
		resolvedAuthority = await params.resolveCreatorToolAuthority({ signal: params.operationSignal });
		params.operationSignal?.throwIfAborted();
		finalPlan = planCronJobUpdatePatch({
			patch: params.patch,
			creatorToolAllowlist: resolvedAuthority.tools,
			currentJob: existingRecord,
			creatorAuthorityComplete: true
		});
	}
	if (finalPlan.kind !== "ready") throw new Error("cron update patch planning did not use the loaded job");
	return {
		patch: finalPlan.patch,
		expectedConfigRevision,
		resolvedAuthority
	};
}
function isCronJobConfigRevisionConflict(error) {
	if (!(error instanceof Error) || error.name !== "GatewayClientRequestError") return false;
	return (isRecord(error.details) ? error.details : void 0)?.code === "CRON_JOB_CHANGED";
}
async function updateCronJobFromAgentTool(params) {
	const callerIncludedPayloadPatch = isRecord(params.patch.payload);
	let creatorAuthorityPromise;
	const resolveCreatorToolAuthority = params.resolveCreatorToolAuthority ? (options) => creatorAuthorityPromise ??= params.resolveCreatorToolAuthority(options) : void 0;
	for (let attempt = 0; attempt < 2; attempt += 1) {
		params.operationSignal?.throwIfAborted();
		const prepared = await prepareCronJobUpdateForGateway({
			...params,
			creatorAuthorityComplete: isCronCreatorToolCaptureComplete(params.creatorToolAllowlistCaptureRef) && resolveCreatorToolAuthority === void 0 && params.creatorAuthorityUnavailableReason === void 0,
			resolveCreatorToolAuthority,
			operationSignal: params.operationSignal
		});
		if (callerIncludedPayloadPatch && !params.adminManagement) assertNoCronShellExecution(prepared.patch);
		const payload = isRecord(prepared.patch.payload) ? prepared.patch.payload : void 0;
		const captureSource = prepared.resolvedAuthority ? prepared.resolvedAuthority.provenance.source : params.creatorToolAllowlistCaptureRef?.value?.source;
		if (payload?.toolsAllowIsDefault === true && (prepared.resolvedAuthority || params.creatorToolAllowlistCaptureRef) && captureSource !== "final-executable-surface") throw new Error(INCOMPLETE_CRON_CREATOR_AUTHORITY_MESSAGE);
		if (prepared.resolvedAuthority && !params.withCreatorAuthorityProvenance) throw new Error("fresh configured MCP cron authority requires an authenticated local agent run");
		try {
			const write = async () => {
				params.operationSignal?.throwIfAborted();
				return await params.callGateway("cron.update", params.gatewayOpts, {
					id: params.id,
					patch: prepared.patch,
					...prepared.expectedConfigRevision ? { expectedConfigRevision: prepared.expectedConfigRevision } : {}
				});
			};
			return prepared.resolvedAuthority && params.withCreatorAuthorityProvenance ? await params.withCreatorAuthorityProvenance(prepared.resolvedAuthority, write) : await write();
		} catch (error) {
			if (attempt === 0 && isCronJobConfigRevisionConflict(error)) continue;
			throw error;
		}
	}
	throw new Error("cron update retry exhausted");
}
//#endregion
//#region src/agents/tools/cron-tool.ts
/**
* cron built-in tool.
*
* Manages scheduled jobs, wake/run actions, delivery context, and reminder-style payload normalization.
*/
function isMissingOrEmptyObject(value) {
	return !value || isRecord(value) && Object.keys(value).length === 0;
}
function readCronJobIdParam(params) {
	return readToolStringParam(params, "jobId") ?? readToolStringParam(params, "id");
}
function requireCronJobIdParam(params) {
	const id = readCronJobIdParam(params);
	if (!id) throw new Error("jobId required (id accepted for backward compatibility)");
	return id;
}
const CRON_SELF_REMOVE_SCOPE_ERROR = "Automations tool is restricted to the current automation.";
function readCronSelfRemoveOnlyJobId(opts) {
	return opts?.selfRemoveOnlyJobId?.trim() || void 0;
}
function isCronSelfIntrospectionAction(action) {
	return action === "status" || action === "list";
}
function assertCronSelfRemoveScope(opts, action, params) {
	const selfRemoveOnlyJobId = readCronSelfRemoveOnlyJobId(opts);
	if (!selfRemoveOnlyJobId || isCronSelfIntrospectionAction(action)) return;
	if ([
		"next_check",
		"get",
		"remove",
		"runs"
	].includes(action)) {
		const id = readCronJobIdParam(params);
		if (id === selfRemoveOnlyJobId || action === "next_check" && !id) return;
	}
	throw new Error(CRON_SELF_REMOVE_SCOPE_ERROR);
}
function filterCronStatusResultForSelfScope(result) {
	return { enabled: isRecord(result) && result.enabled === true };
}
function formatCronTerminalPresentation(params, result) {
	if (!isRecord(params) || !isRecord(result) || !isRecord(result.details)) return;
	switch (params.action) {
		case "status": return { text: `Automations scheduler status.\nEnabled: ${result.details.enabled === true ? "yes" : "no"}` };
		case "list": {
			const count = (typeof result.details.total === "number" && Number.isFinite(result.details.total) && result.details.total >= 0 ? Math.floor(result.details.total) : void 0) ?? (Array.isArray(result.details.jobs) ? result.details.jobs.length : void 0);
			return count === void 0 ? { text: "Automations listed." } : { text: `Automations listed.\nCount: ${count}` };
		}
		case "get": return { text: "Automation loaded." };
		case "runs": {
			const entries = Array.isArray(result.details.entries) ? result.details.entries.length : void 0;
			return entries === void 0 ? { text: "Automation run history loaded." } : { text: `Automation run history loaded.\nCount: ${entries}` };
		}
		default: return;
	}
}
function isOlderGatewayWithoutCompactCronList(error) {
	return error instanceof GatewayClientRequestError && error.gatewayCode === "INVALID_REQUEST" && error.message.includes("invalid cron.list params") && error.message.includes("unexpected property 'compact'");
}
function buildCronToolDescription(params) {
	const addFields = params.triggersEnabled ? "{name?,schedule,payload,sessionTarget?,pacing?,trigger?,delivery?,enabled?}" : "{name?,schedule,payload,sessionTarget?,pacing?,delivery?,enabled?}";
	const streamScheduleLine = params.triggersEnabled ? "\n- {kind:\"stream\",command:[argv],mode?:\"line\"|\"match\",match?}: fires on supervised process output; disabled only when cron.triggers.enabled=false." : "";
	const scriptPayloadLine = params.triggersEnabled ? "\n- script {kind:\"script\",script,timeoutSeconds?,toolBudget?}: main|isolated only; disabled only when cron.triggers.enabled=false." : "";
	const triggerSection = params.triggersEnabled ? `TRIGGER (condition watcher on every/cron): {script,once?}; available unless cron.triggers.enabled=false — if off, say so; never model-poll instead. Quiet headless check, no model; 30s/5 tool calls/16KB state. Read frozen trigger.state, return json({fire,message?,state?}) with NEW state; dedupe via state, never memory. fire:false saves state only. fire:true runs payload; message is that run's entire context — self-contained. Fire on failures/timeouts too; success-only watchers look healthy when broken. Script stays read-only; actions belong in payload. once:true disables after first fire. Code Mode: await exec({command:"..."}).` : `TRIGGERS DISABLED (cron.triggers.enabled=false): condition triggers, script payloads, and stream schedules are unavailable here. Omit trigger; use plain time-based schedules. If the user asks for a conditional watcher, say it is unsupported — never model-poll instead, and never silently create an unconditional job in its place.`;
	const silentWatcherCue = params.triggersEnabled ? " Silent watcher=>mode:\"none\"." : "";
	return `Gateway scheduler: reminders, delayed self-wakeups, loops, recurring work${params.triggersEnabled ? ", event watchers" : ""}. Never exec sleep/poll as timer.

ACTIONS: status | list [includeDisabled,limit?,offset?] (use nextOffset for the next page) | get jobId | add job | update jobId job (partial: only supplied fields change; null clears) | remove jobId | run jobId (runMode "force"=now) | runs jobId = history | next_check in:"30m" (own paced run only) | wake text mode?:"now"|"next-heartbeat"(default) nudges a caller-owned lane (sessionKey/agentId to pick another).

Authenticated Control UI administrator turns can list/get/update/run/remove any Gateway automation. Other turns have a restricted inventory; use a fresh admin Control UI turn or the Automations page for cross-session management.

ADD: ${addFields}. Required: schedule+payload.

SCHEDULE:
- {kind:"at",at:"ISO-8601"} one-shot; no tz=UTC; auto-deletes after successful completion: delivery confirmed, not requested, intentionally silent, or explicitly bestEffort. Failed/unknown required delivery retains it disabled.
- {kind:"every",everyMs}.
- {kind:"cron",expr,tz?:"IANA"}: expr is wall time in tz; never pre-convert to UTC; no tz=gateway host local. 18:00 Shanghai => {expr:"0 18 * * *",tz:"Asia/Shanghai"}.${streamScheduleLine}

TARGET+PAYLOAD:
- "current" (agentTurn default) = this conversation: the run stays detached, reads bounded chat context, then commits its final visible assistant result to this conversation's durable history. Self-wakeup/"continue later"/loop = at|every + agentTurn + current.
- "isolated" = fresh detached session (shows in \`openclaw tasks\`); standalone background work.
- "main" = heartbeat lane; payload {kind:"systemEvent",text} (systemEvent default target).
- "session:<key>" = named session.
- agentTurn {kind:"agentTurn",message,model?,thinking?,timeoutSeconds?}; timeoutSeconds 0=none.
- Inherited configured MCP authority includes only model-callable tools; interactive app-view-only capabilities are excluded from headless jobs.${scriptPayloadLine}

PACED LOOP: recurring job + pacing{min?,max?} durations ("15m","4h"; at least one). Inside its run, job calls next_check in:"<dur>" to set the next delay (clamped to bounds, measured from run end; failed runs keep normal backoff). Adaptive polling: tighten when active, back off when quiet.

${triggerSection}

DELIVERY {mode:"none"|"announce"|"webhook",channel?,to?,threadId?,bestEffort?,completionDestination?}: where detached run output goes. Omitted=announce (current=>canonical session commit, plus one normal channel send for external chats; isolated=>last route; set channel/to for a specific chat — no messaging tool inside the run). A current announce succeeds only after its history commit; WebChat observes that commit live and after reconnect without another user message.${silentWatcherCue} webhook posts finished-run event (successful empty summary is intentional silence, no POST) to URL in \`to\`. To keep announce delivery and also POST completion, use mode:"announce" with completionDestination:{mode:"webhook",to:"https://..."}.

FAILURE ALERTS: jobs with a failure route default to alerting after 2 consecutive execution failures with a 1h cooldown. Route order: job failureAlert fields, delivery.failureDestination over global cron.failureAlert destination fields, then primary announce. failureAlert:false disables execution/delivery alerts, not the auto-disable safety notice; a failureAlert object activates/tunes. bestEffort suppresses inherited execution alerts. Required completion-delivery failure uses only an alternate route, bypasses after, and shares the execution-alert cooldown from the first failure; it does not increment the execution streak.

Job wakeMode (main jobs): "now"(default)|"next-heartbeat". Restricted automation-run sessions: self status/list/get/runs/remove + own next_check only. jobId canonical (id=compat). contextMessages 0-10 embeds recent chat lines into reminder text.`;
}
function createCronTool(opts, deps) {
	const gatewayCall = deps?.callGatewayTool ?? callGatewayTool;
	const managementAuthority = bindCronManagementGrant(opts?.runId);
	const triggersEnabled = opts?.config?.cron?.triggers?.enabled !== false;
	const tool = {
		label: "Automations",
		name: AUTOMATIONS_TOOL_NAME,
		displaySummary: CRON_TOOL_DISPLAY_SUMMARY,
		description: managementAuthority?.managementOnly ? "Manage any existing automation on this Gateway as the authenticated Control UI administrator. Actions: list [includeDisabled,limit,offset] (follow nextOffset); get jobId; update jobId job (partial patch, null clears); run jobId (runMode:\"force\" runs now); remove jobId. Creator attribution and scheduled execution policy stay intact. Use the Automations page for other actions." : buildCronToolDescription({ triggersEnabled }),
		parameters: createCronToolSchema({
			agentSessionKey: opts?.agentSessionKey,
			triggersEnabled,
			management: managementAuthority ? managementAuthority.managementOnly ? "only" : "also" : void 0
		}),
		execute: async (_toolCallId, args, operationSignal) => {
			operationSignal?.throwIfAborted();
			const callGateway = async (...request) => {
				const identity = getGatewayToolCallerIdentity();
				const grant = managementAuthority?.mint(request[0], operationSignal);
				if (grant && !identity) throw new Error("Automation management requires the active Control UI administrator turn.");
				return grant && identity ? await withGatewayToolCallerIdentity({
					...identity,
					cronManagementGrant: grant
				}, () => gatewayCall(...request)) : await gatewayCall(...request);
			};
			const params = args;
			const action = readToolStringParam(params, "action", { required: true });
			if (managementAuthority?.managementOnly && !CRON_MANAGEMENT_METHODS.some((method) => method === `cron.${action}`)) throw new Error("This turn can only list, get, update, run, or remove automations. Use the Automations page for other actions.");
			assertCronSelfRemoveScope(opts, action, params);
			const parsedGatewayOpts = readGatewayCallOptions(params);
			const gatewayOpts = {
				...parsedGatewayOpts,
				timeoutMs: parsedGatewayOpts.timeoutMs ?? 6e4
			};
			const runtimeConfig = getRuntimeConfig();
			const callerAgentId = opts?.agentSessionKey?.trim() ? resolveSessionAgentId({
				sessionKey: opts.agentSessionKey,
				config: runtimeConfig,
				agentId: opts.agentId
			}) : void 0;
			const creatorExecToolTarget = resolveCronCreatorExecToolTarget(opts?.creatorToolAllowlist);
			const callerIdentity = callerAgentId && opts?.agentSessionKey?.trim() ? {
				agentId: callerAgentId,
				sessionKey: opts.agentSessionKey.trim(),
				turnSourceAccountId: opts.agentAccountId,
				...readCronSelfRemoveOnlyJobId(opts) ? { cronSelfManagementJobId: readCronSelfRemoveOnlyJobId(opts) } : {},
				...opts?.creatorToolAllowlistCaptureRef?.value?.version === 1 && opts.creatorToolAllowlistCaptureRef.value.source === "final-executable-surface" ? {
					cronToolsAllowCapture: "final-executable-surface",
					...creatorExecToolTarget ? { cronExecToolTarget: creatorExecToolTarget } : {}
				} : {}
			} : void 0;
			const withCreatorAuthorityProvenance = async (authority, run) => {
				if (!authority) return await run();
				if (!callerIdentity) throw new Error("fresh configured MCP cron authority requires an authenticated local agent run");
				const cronExecToolTarget = resolveCronCreatorExecToolTarget(authority.tools);
				return await withGatewayToolCallerIdentity({
					...callerIdentity,
					cronToolsAllowCapture: "final-executable-surface",
					...cronExecToolTarget ? { cronExecToolTarget } : {},
					cronCreatorAuthorityGrant: authority.grant
				}, run);
			};
			return await withGatewayToolCallerIdentity(callerIdentity, async () => {
				switch (action) {
					case "status": {
						const result = await callGateway("cron.status", gatewayOpts, {});
						return jsonResult(readCronSelfRemoveOnlyJobId(opts) ? filterCronStatusResultForSelfScope(result) : result);
					}
					case "list": {
						const selfRemoveOnlyJobId = readCronSelfRemoveOnlyJobId(opts);
						const listAgentId = readToolStringParam(params, "agentId");
						const includeDisabled = Boolean(params.includeDisabled);
						const requestedLimit = selfRemoveOnlyJobId ? void 0 : readPositiveIntegerParam(params, "limit", {
							max: 200,
							message: `limit must be a positive integer no greater than 200`
						});
						const requestedOffset = selfRemoveOnlyJobId ? void 0 : readNonNegativeIntegerParam(params, "offset");
						let useCompactList = true;
						const requestListPage = async (pageParams) => {
							for (;;) try {
								return await callGateway("cron.list", gatewayOpts, {
									includeDisabled,
									...useCompactList ? { compact: true } : {},
									...listAgentId ? { agentId: listAgentId } : {},
									...pageParams
								});
							} catch (error) {
								if (!useCompactList || !isOlderGatewayWithoutCompactCronList(error)) throw error;
								useCompactList = false;
							}
						};
						if (!selfRemoveOnlyJobId) {
							const result = await requestListPage({
								...requestedLimit !== void 0 ? { limit: requestedLimit } : {},
								...requestedOffset !== void 0 ? { offset: requestedOffset } : {}
							});
							return jsonResult({
								...result,
								scope: managementAuthority ? "gateway" : "caller",
								...!managementAuthority ? { scopeHint: "Restricted automation inventory. For Gateway-wide management, use a fresh authenticated Control UI administrator turn or the Automations page." } : {}
							});
						}
						return jsonResult(await listCronSelfJob({
							jobId: selfRemoveOnlyJobId,
							pageSize: 200,
							requestPage: requestListPage
						}));
					}
					case "get": {
						const id = requireCronJobIdParam(params);
						return jsonResult(await callGateway("cron.get", gatewayOpts, { id }));
					}
					case "add": {
						if (isMissingOrEmptyObject(params.job)) {
							const synthetic = recoverCronObjectFromFlatParams(params);
							if (synthetic.found && hasCronCreateSignal(synthetic.value)) params.job = synthetic.value;
						}
						if (!params.job || typeof params.job !== "object") throw new Error("job required");
						const canonicalJob = stripCronCreateNullClears(canonicalizeCronToolObject(params.job));
						assertNoCronShellExecution(canonicalJob);
						assertCronDeliveryInputNonBlankFields(canonicalJob.delivery);
						assertCronPacingInput(canonicalJob.pacing);
						if (typeof canonicalJob.declarationKey === "string" && canonicalJob.declarationKey.trim().length === 0) throw new Error("declarationKey must be a non-empty string");
						if (typeof canonicalJob.displayName === "string" && canonicalJob.displayName.trim().length === 0) throw new Error("displayName must be a non-empty string");
						const enabledExplicit = typeof canonicalJob.enabled === "boolean";
						const job = normalizeCronJobCreate(canonicalJob, { sessionContext: { sessionKey: opts?.agentSessionKey } }) ?? canonicalJob;
						if (typeof job.declarationKey === "string" && job.declarationKey.length > 0 && !enabledExplicit) delete job.enabled;
						const requiresCreatorAuthority = cronCreateRequiresCreatorAuthority(job, opts?.creatorToolAllowlist);
						assertCronCreatorAuthorityResolutionAvailable({
							required: requiresCreatorAuthority,
							resolveCreatorToolAuthority: opts?.resolveCreatorToolAuthority,
							creatorToolAllowlistCaptureRef: opts?.creatorToolAllowlistCaptureRef,
							unavailableReason: opts?.creatorAuthorityUnavailableReason
						});
						const resolvedAuthority = requiresCreatorAuthority && opts?.resolveCreatorToolAuthority ? await opts.resolveCreatorToolAuthority({ signal: operationSignal }) : void 0;
						operationSignal?.throwIfAborted();
						const creatorToolAllowlist = resolvedAuthority?.tools ?? opts?.creatorToolAllowlist;
						const creatorToolAllowlistCaptureRef = resolvedAuthority ? { value: resolvedAuthority.provenance } : opts?.creatorToolAllowlistCaptureRef;
						capCronJobToolsAllowOnCreate(job, creatorToolAllowlist);
						assertInheritedCronToolCaptureReady(job, creatorToolAllowlistCaptureRef);
						if (job && typeof job === "object") {
							const { mainKey, alias } = resolveMainSessionAlias(runtimeConfig);
							const resolvedSessionKey = opts?.agentSessionKey ? resolveInternalSessionKey({
								key: opts.agentSessionKey,
								alias,
								mainKey
							}) : void 0;
							const sessionTarget = normalizeLowercaseStringOrEmpty(job.sessionTarget);
							if (!("sessionKey" in job) && resolvedSessionKey && sessionTarget !== "isolated") job.sessionKey = resolvedSessionKey;
						}
						if ((opts?.agentSessionKey || opts?.currentDeliveryContext) && job && typeof job === "object" && "payload" in job && job.payload?.kind === "agentTurn") {
							const deliveryValue = job.delivery;
							const delivery = isRecord(deliveryValue) ? deliveryValue : void 0;
							const modeRaw = typeof delivery?.mode === "string" ? delivery.mode : "";
							const mode = normalizeLowercaseStringOrEmpty(modeRaw);
							if (mode === "webhook") {
								const webhookUrl = normalizeHttpWebhookUrl(delivery?.to);
								if (!webhookUrl) throw new Error("delivery.mode=\"webhook\" requires delivery.to to be a valid http(s) URL");
								if (delivery) delivery.to = webhookUrl;
							}
							const hasTarget = typeof delivery?.channel === "string" && delivery.channel.trim() || typeof delivery?.to === "string" && delivery.to.trim();
							if ((deliveryValue == null || delivery) && (mode === "" || mode === "announce") && !hasTarget) {
								const inferred = resolveCronCreationDelivery({
									cfg: runtimeConfig,
									currentDeliveryContext: opts.currentDeliveryContext,
									agentSessionKey: opts.agentSessionKey
								});
								if (inferred) job.delivery = {
									...inferred,
									...delivery
								};
							}
						}
						const contextMessages = readNonNegativeIntegerParam(params, "contextMessages") ?? 0;
						if (job && typeof job === "object" && "payload" in job && job.payload?.kind === "systemEvent") {
							const payload = job.payload;
							if (typeof payload.text === "string" && payload.text.trim()) {
								const contextLines = await buildReminderContextLines({
									agentSessionKey: opts?.agentSessionKey,
									agentId: callerAgentId,
									gatewayOpts,
									contextMessages,
									callGatewayTool: callGateway
								});
								if (contextLines.length > 0) payload.text = `${stripExistingContext(payload.text)}${REMINDER_CONTEXT_MARKER}${contextLines.join("\n")}`;
							}
						}
						return jsonResult(await withCreatorAuthorityProvenance(resolvedAuthority, () => callGateway("cron.add", gatewayOpts, job)));
					}
					case "update": {
						const id = requireCronJobIdParam(params);
						let recoveredFlatPatch = false;
						if (isMissingOrEmptyObject(params.job)) {
							const synthetic = recoverCronObjectFromFlatParams(params);
							if (synthetic.found) {
								params.job = synthetic.value;
								recoveredFlatPatch = true;
							}
						}
						if (!params.job || typeof params.job !== "object") throw new Error("job required");
						const canonicalPatch = canonicalizeCronToolObject(params.job);
						if (!managementAuthority) assertNoCronShellExecution(canonicalPatch);
						assertCronDeliveryInputNonBlankFields(canonicalPatch.delivery);
						assertCronPacingInput(canonicalPatch.pacing);
						if (typeof canonicalPatch.displayName === "string" && canonicalPatch.displayName.trim().length === 0) throw new Error("displayName must be a non-empty string or null");
						const patch = normalizeCronJobPatch(canonicalPatch) ?? canonicalPatch;
						if (recoveredFlatPatch && isEmptyRecoveredCronPatch(patch)) throw new Error("job required");
						const creatorOptions = managementAuthority ? void 0 : opts;
						return jsonResult(await updateCronJobFromAgentTool({
							id,
							patch,
							adminManagement: Boolean(managementAuthority),
							creatorToolAllowlist: creatorOptions?.creatorToolAllowlist,
							creatorToolAllowlistCaptureRef: creatorOptions?.creatorToolAllowlistCaptureRef,
							resolveCreatorToolAuthority: creatorOptions?.resolveCreatorToolAuthority,
							withCreatorAuthorityProvenance: !managementAuthority && callerIdentity ? withCreatorAuthorityProvenance : void 0,
							gatewayOpts,
							callGateway,
							operationSignal,
							creatorAuthorityUnavailableReason: creatorOptions?.creatorAuthorityUnavailableReason
						}));
					}
					case "remove": {
						const id = requireCronJobIdParam(params);
						return jsonResult(await callGateway("cron.remove", gatewayOpts, { id }));
					}
					case "run": {
						const id = requireCronJobIdParam(params);
						const runMode = params.runMode === "due" || params.runMode === "force" ? params.runMode : "due";
						return jsonResult(await callGateway("cron.run", gatewayOpts, {
							id,
							mode: runMode
						}));
					}
					case "runs": {
						const id = requireCronJobIdParam(params);
						return jsonResult(await callGateway("cron.runs", gatewayOpts, { id }));
					}
					case "next_check": {
						const jobId = readCronSelfRemoveOnlyJobId(opts);
						const runId = opts?.runId?.trim();
						if (!jobId || !runId) throw new Error("cron next_check is only available to the currently running job");
						const rawDuration = readToolStringParam(params, "in", { required: true });
						let delayMs;
						try {
							delayMs = parseDurationMs(rawDuration);
						} catch {
							throw new Error("cron next_check in must be a positive duration");
						}
						if (delayMs <= 0) throw new Error("cron next_check in must be a positive duration");
						recordCronNextCheckProposal(runId, jobId, delayMs);
						return jsonResult({
							ok: true,
							delayMs
						});
					}
					case "wake": {
						const text = readToolStringParam(params, "text", { required: true });
						const mode = params.mode === "now" || params.mode === "next-heartbeat" ? params.mode : "next-heartbeat";
						const { mainKey, alias } = resolveMainSessionAlias(runtimeConfig);
						const explicitSessionKey = readToolStringParam(params, "sessionKey");
						const explicitAgentId = readToolStringParam(params, "agentId");
						const inferredSessionKey = opts?.agentSessionKey ? resolveInternalSessionKey({
							key: opts.agentSessionKey,
							alias,
							mainKey
						}) : void 0;
						const sessionKey = explicitSessionKey ?? inferredSessionKey;
						const agentIdFromExplicitSessionKey = explicitSessionKey ? parseAgentSessionKey(explicitSessionKey)?.agentId : void 0;
						const agentId = explicitAgentId ?? (explicitSessionKey ? agentIdFromExplicitSessionKey : callerAgentId);
						return jsonResult(await callGateway("wake", gatewayOpts, {
							mode,
							text,
							...sessionKey ? { sessionKey } : {},
							...agentId ? { agentId } : {}
						}, { expectFinal: false }));
					}
					default: throw new Error(`Unknown action: ${action}`);
				}
			});
		}
	};
	return setToolTerminalPresentation(tool, formatCronTerminalPresentation);
}
//#endregion
export { replaceWithEffectiveCronCreatorToolAllowlist as i, assertNativeCronCreatorCapabilities as n, captureFinalEffectiveCronCreatorToolAllowlist as r, createCronTool as t };