feat(cron): add --tools flag for per-job tool allow-list (#58504)

Add toolsAllow field to cron agent-turn payloads, enabling users to
restrict which tool schemas are sent to the model for a given cron job.

When --tools is set:
- Only listed tools are included in the provider request
- promptMode is forced to 'minimal' (strips skills catalog, reply tags,
  heartbeat, messaging, docs, memory, model aliases, silent replies)
- Dramatically reduces input tokens for small local models (~16K to ~800)

CLI surface:
- openclaw cron add --tools exec,read,write
- openclaw cron edit <id> --tools exec
- openclaw cron edit <id> --clear-tools (remove allow-list)

Closes #58435

Co-authored-by: andyk-ms <andyk-ms@users.noreply.github.com>
This commit is contained in:
Andy
2026-03-31 18:09:17 -07:00
committed by GitHub
parent 3a52b475ab
commit 4d8c07b97c
7 changed files with 54 additions and 3 deletions

View File

@@ -563,6 +563,7 @@ export async function runCronIsolatedAgentTurn(params: {
timeoutMs,
bootstrapContextMode: agentPayload?.lightContext ? "lightweight" : undefined,
bootstrapContextRunKind: "cron",
toolsAllow: agentPayload?.toolsAllow,
runId: cronSession.sessionEntry.sessionId,
requireExplicitMessageTarget: toolPolicy.requireExplicitMessageTarget,
disableMessageTool: toolPolicy.disableMessageTool,

View File

@@ -160,6 +160,21 @@ function coercePayload(payload: UnknownRecord) {
) {
delete next.allowUnsafeExternalContent;
}
if ("toolsAllow" in next) {
if (Array.isArray(next.toolsAllow)) {
next.toolsAllow = (next.toolsAllow as unknown[])
.filter((t): t is string => typeof t === "string" && t.trim().length > 0)
.map((t) => t.trim());
if ((next.toolsAllow as string[]).length === 0) {
delete next.toolsAllow;
}
} else if (next.toolsAllow === null) {
// Explicit null means "clear the allow-list" (edit --clear-tools)
next.toolsAllow = null;
} else {
delete next.toolsAllow;
}
}
return next;
}

View File

@@ -96,6 +96,8 @@ type CronAgentTurnPayloadFields = {
externalContentSource?: HookExternalContentSource;
/** If true, run with lightweight bootstrap context. */
lightContext?: boolean;
/** Optional tool allow-list; when set, only these tools are sent to the model. */
toolsAllow?: string[];
deliver?: boolean;
channel?: CronMessageChannel;
to?: string;