Cron: suppress fallback main summary for delivery-target errors (openclaw#24074) thanks @Takhoffman

Verified:
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: Takhoffman <781889+Takhoffman@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Tak Hoffman
2026-02-22 20:24:08 -06:00
committed by GitHub
parent 457835b104
commit a54dc7fe80
5 changed files with 39 additions and 15 deletions

View File

@@ -78,6 +78,7 @@ Docs: https://docs.openclaw.ai
- Cron/Timer: keep a watchdog recheck timer armed while `onTimer` is actively executing so the scheduler continues polling even if a due-run tick stalls for an extended period. (#23628) Thanks @dsgraves.
- Cron/Run log: clean up settled per-path run-log write queue entries so long-running cron uptime does not retain stale promise bookkeeping in memory.
- Cron/Run log: harden `cron.runs` run-log path resolution by rejecting path-separator `id`/`jobId` inputs and enforcing reads within the per-cron `runs/` directory.
- Cron/Announce: when announce delivery target resolution fails (for example multiple configured channels with no explicit target), skip injecting fallback `Cron (error): ...` into the main session so runs fail cleanly without accidental last-route sends. (#24074)
- Cron/Isolation: force fresh session IDs for isolated cron runs so `sessionTarget="isolated"` executions never reuse prior run context. (#23470) Thanks @echoVic.
- Plugins/Install: strip `workspace:*` devDependency entries from copied plugin manifests before `npm install --omit=dev`, preventing `EUNSUPPORTEDPROTOCOL` install failures for npm-published channel plugins (including Feishu and MS Teams).
- Feishu/Plugins: restore bundled Feishu SDK availability for global installs and strip `openclaw: workspace:*` from plugin `devDependencies` during plugin-version sync so npm-installed Feishu plugins do not fail dependency install. (#23611, #23645, #23603)

View File

@@ -635,29 +635,26 @@ export async function runCronIsolatedAgentTurn(params: {
// `true` means we confirmed at least one outbound send reached the target.
// Keep this strict so timer fallback can safely decide whether to wake main.
let delivered = skipMessagingToolDelivery;
const failDeliveryTarget = (error: string) =>
withRunSession({
status: "error",
error,
errorKind: "delivery-target",
summary,
outputText,
...telemetry,
});
if (deliveryRequested && !skipHeartbeatDelivery && !skipMessagingToolDelivery) {
if (resolvedDelivery.error) {
if (!deliveryBestEffort) {
return withRunSession({
status: "error",
error: resolvedDelivery.error.message,
summary,
outputText,
...telemetry,
});
return failDeliveryTarget(resolvedDelivery.error.message);
}
logWarn(`[cron:${params.job.id}] ${resolvedDelivery.error.message}`);
return withRunSession({ status: "ok", summary, outputText, ...telemetry });
}
const failOrWarnMissingDeliveryField = (message: string) => {
if (!deliveryBestEffort) {
return withRunSession({
status: "error",
error: message,
summary,
outputText,
...telemetry,
});
return failDeliveryTarget(message);
}
logWarn(`[cron:${params.job.id}] ${message}`);
return withRunSession({ status: "ok", summary, outputText, ...telemetry });

View File

@@ -680,6 +680,28 @@ describe("CronService", () => {
await store.cleanup();
});
it("does not post fallback main summary for isolated delivery-target errors", async () => {
const runIsolatedAgentJob = vi.fn(async () => ({
status: "error" as const,
summary: "last output",
error: "Channel is required when multiple channels are configured: telegram, discord",
errorKind: "delivery-target" as const,
}));
const { store, cron, enqueueSystemEvent, requestHeartbeatNow, events } =
await createIsolatedAnnounceHarness(runIsolatedAgentJob);
await runIsolatedAnnounceJobAndWait({
cron,
events,
name: "isolated delivery target error test",
status: "error",
});
expect(enqueueSystemEvent).not.toHaveBeenCalled();
expect(requestHeartbeatNow).not.toHaveBeenCalled();
cron.stop();
await store.cleanup();
});
it("rejects unsupported session/payload combinations", async () => {
ensureDir(fixturesRoot);
const store = await makeStorePath();

View File

@@ -737,7 +737,9 @@ export async function executeJobCore(
// See: https://github.com/openclaw/openclaw/issues/15692
const summaryText = res.summary?.trim();
const deliveryPlan = resolveCronDeliveryPlan(job);
if (summaryText && deliveryPlan.requested && !res.delivered) {
const suppressMainSummary =
res.status === "error" && res.errorKind === "delivery-target" && deliveryPlan.requested;
if (summaryText && deliveryPlan.requested && !res.delivered && !suppressMainSummary) {
const prefix = "Cron";
const label =
res.status === "error" ? `${prefix} (error): ${summaryText}` : `${prefix}: ${summaryText}`;

View File

@@ -47,6 +47,8 @@ export type CronRunTelemetry = {
export type CronRunOutcome = {
status: CronRunStatus;
error?: string;
/** Optional classifier for execution errors to guide fallback behavior. */
errorKind?: "delivery-target";
summary?: string;
sessionId?: string;
sessionKey?: string;