fix(cron): omit disabled delivery trace errors

This commit is contained in:
Peter Steinberger
2026-04-27 07:50:45 +01:00
parent 4db1faaafc
commit 9ced682a9d
3 changed files with 57 additions and 24 deletions

View File

@@ -32,6 +32,7 @@ Docs: https://docs.openclaw.ai
- Discord: preserve explicit `user:` and `channel:` delivery targets through plugin routing so cron announcements and failure alerts keep their intended recipient kind. Refs #62777; carries forward #62798. Thanks @neeravmakwana.
- Cron: add `failureAlert.includeSkipped` and `openclaw cron edit --failure-alert-include-skipped` so persistently skipped jobs can alert without counting skips as execution errors or affecting retry backoff. Fixes #60846. Thanks @slideshow-dingo.
- Cron: invalidate stale pending runtime slots after live or offline `jobs.json` schedule edits, while preserving due slots for formatting-only rewrites. Fixes #27996 and #71607; carries forward #71651. Thanks @xialonglee and @fagnersouza666.
- Cron: omit synthetic `delivery.resolved` errors from `--no-deliver` run records while preserving explicit no-deliver target traces for agent-initiated messages. Fixes #72210; carries forward #72219. Thanks @hatemclawbot-collab and @xydigit-sj.
- Cron: classify isolated runs as errors from structured embedded-run execution-denial metadata, with final-output marker fallback for `SYSTEM_RUN_DENIED`, `INVALID_REQUEST`, and approval-binding refusals, so blocked commands no longer appear green in cron history. Fixes #67172; carries forward #67186. Thanks @oc-gh-dr, @hclsys, and @1yihui.
- Onboarding/GitHub Copilot: add manifest-owned `--github-copilot-token` support for non-interactive setup, including env fallback, tokenRef storage in ref mode, saved-profile reuse, and current Copilot default-model wiring. Refs #50002 and supersedes #50003. Thanks @scottgl9.
- Gateway/install: add a validated `--wrapper`/`OPENCLAW_WRAPPER` service install path that persists executable LaunchAgent/systemd wrappers across forced reinstalls, updates, and doctor repairs instead of falling back to raw node/bun `ProgramArguments`. Fixes #69400. (#72445) Thanks @willtmc.

View File

@@ -354,7 +354,7 @@ describe("runCronIsolatedAgentTurn message tool policy", () => {
error: undefined,
});
await runCronIsolatedAgentTurn({
const result = await runCronIsolatedAgentTurn({
...makeParams(),
job: {
id: "message-tool-policy",
@@ -374,6 +374,18 @@ describe("runCronIsolatedAgentTurn message tool policy", () => {
messageThreadId: 42,
currentChannelId: "room#42",
});
expect(result.delivery).toEqual(
expect.objectContaining({
intended: { channel: "topicchat", to: "room#42", threadId: 42, source: "explicit" },
resolved: {
ok: true,
channel: "topicchat",
to: "room#42",
threadId: 42,
source: "explicit",
},
}),
);
});
it('does not resolve implicit "last" context for bare delivery.mode none', async () => {
@@ -731,6 +743,15 @@ describe("runCronIsolatedAgentTurn message tool policy", () => {
);
expect(result.delivered).toBe(false);
expect(result.deliveryAttempted).toBe(false);
expect(result.delivery).toEqual(
expect.objectContaining({
intended: { channel: "last", to: null, source: "last" },
messageToolSentTo: [{ channel: "messagechat", to: "123" }],
fallbackUsed: false,
delivered: false,
}),
);
expect(result.delivery).not.toHaveProperty("resolved");
});
});

View File

@@ -200,6 +200,34 @@ function normalizeMessagingToolTarget(
};
}
function buildResolvedCronTraceTarget(
resolvedDelivery: ResolvedCronDeliveryTarget,
): CronDeliveryTrace["resolved"] {
if (resolvedDelivery.ok) {
return {
ok: true,
...normalizeCronTraceTarget({
channel: resolvedDelivery.channel,
to: resolvedDelivery.to,
accountId: resolvedDelivery.accountId,
threadId: resolvedDelivery.threadId,
source: resolvedDelivery.mode === "implicit" ? "last" : "explicit",
}),
};
}
return {
ok: false,
...normalizeCronTraceTarget({
channel: resolvedDelivery.channel,
to: resolvedDelivery.to ?? null,
accountId: resolvedDelivery.accountId,
threadId: resolvedDelivery.threadId,
source: resolvedDelivery.mode === "implicit" ? "last" : "explicit",
}),
error: resolvedDelivery.error.message,
};
}
function buildCronDeliveryTrace(params: {
deliveryPlan: CronDeliveryPlan;
resolvedDelivery: ResolvedCronDeliveryTarget;
@@ -216,28 +244,11 @@ function buildCronDeliveryTrace(params: {
source:
params.deliveryPlan.channel === "last" || !params.deliveryPlan.channel ? "last" : "explicit",
});
const resolved = params.resolvedDelivery.ok
? {
ok: true,
...normalizeCronTraceTarget({
channel: params.resolvedDelivery.channel,
to: params.resolvedDelivery.to,
accountId: params.resolvedDelivery.accountId,
threadId: params.resolvedDelivery.threadId,
source: params.resolvedDelivery.mode === "implicit" ? "last" : "explicit",
}),
}
: {
ok: false,
...normalizeCronTraceTarget({
channel: params.resolvedDelivery.channel,
to: params.resolvedDelivery.to ?? null,
accountId: params.resolvedDelivery.accountId,
threadId: params.resolvedDelivery.threadId,
source: params.resolvedDelivery.mode === "implicit" ? "last" : "explicit",
}),
error: params.resolvedDelivery.error.message,
};
const includeResolved =
params.deliveryPlan.mode !== "none" || hasExplicitCronDeliveryTarget(params.deliveryPlan);
const resolved = includeResolved
? buildResolvedCronTraceTarget(params.resolvedDelivery)
: undefined;
const messageToolSentTo = params.messagingToolSentTargets
.map((target) =>
normalizeMessagingToolTarget(
@@ -249,7 +260,7 @@ function buildCronDeliveryTrace(params: {
.filter((target): target is CronDeliveryTraceMessageTarget => Boolean(target));
return {
...(intended ? { intended } : {}),
resolved,
...(resolved ? { resolved } : {}),
...(messageToolSentTo.length > 0 ? { messageToolSentTo } : {}),
fallbackUsed: params.fallbackUsed,
delivered: params.delivered,