fix cron announce routing and timeout handling

This commit is contained in:
Tyler Yust
2026-02-17 11:40:04 -08:00
parent e1015a5197
commit 75001a0490
12 changed files with 298 additions and 43 deletions

View File

@@ -44,6 +44,7 @@ import type { AgentDefaultsConfig } from "../../config/types.js";
import { registerAgentRunContext } from "../../infra/agent-events.js";
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
import { resolveAgentOutboundIdentity } from "../../infra/outbound/identity.js";
import { resolveOutboundSessionRoute } from "../../infra/outbound/outbound-session.js";
import { logWarn } from "../../logger.js";
import { buildAgentMainSessionKey, normalizeAgentId } from "../../routing/session-key.js";
import {
@@ -100,6 +101,40 @@ function resolveCronDeliveryBestEffort(job: CronJob): boolean {
return false;
}
async function resolveCronAnnounceSessionKey(params: {
cfg: OpenClawConfig;
agentId: string;
fallbackSessionKey: string;
delivery: {
channel: Parameters<typeof resolveOutboundSessionRoute>[0]["channel"];
to?: string;
accountId?: string;
threadId?: string | number;
};
}): Promise<string> {
const to = params.delivery.to?.trim();
if (!to) {
return params.fallbackSessionKey;
}
try {
const route = await resolveOutboundSessionRoute({
cfg: params.cfg,
channel: params.delivery.channel,
agentId: params.agentId,
accountId: params.delivery.accountId,
target: to,
threadId: params.delivery.threadId,
});
const resolved = route?.sessionKey?.trim();
if (resolved) {
return resolved;
}
} catch {
// Fall back to main session routing if announce session resolution fails.
}
return params.fallbackSessionKey;
}
export type RunCronAgentTurnResult = {
/** Last non-empty agent text output (not truncated). */
outputText?: string;
@@ -584,15 +619,14 @@ export async function runCronIsolatedAgentTurn(params: {
}
const identity = resolveAgentOutboundIdentity(cfgWithAgentDefaults, agentId);
// Shared subagent announce flow is text-based and prompts the main agent to
// summarize. When we have an explicit delivery target (delivery.to), sender
// identity, or structured content, prefer direct outbound delivery to send
// the actual cron output without summarization.
const hasExplicitDeliveryTarget = Boolean(deliveryPlan.to);
if (deliveryPayloadHasStructuredContent || identity || hasExplicitDeliveryTarget) {
// Route text-only cron announce output back through the main session so it
// follows the same system-message injection path as subagent completions.
// Keep direct outbound delivery only for structured payloads (media/channel
// data), which cannot be represented by the shared announce flow.
if (deliveryPayloadHasStructuredContent) {
try {
const payloadsForDelivery =
deliveryPayloadHasStructuredContent && deliveryPayloads.length > 0
deliveryPayloads.length > 0
? deliveryPayloads
: synthesizedText
? [{ text: synthesizedText }]
@@ -624,10 +658,21 @@ export async function runCronIsolatedAgentTurn(params: {
}
}
} else if (synthesizedText) {
const announceSessionKey = resolveAgentMainSessionKey({
const announceMainSessionKey = resolveAgentMainSessionKey({
cfg: params.cfg,
agentId,
});
const announceSessionKey = await resolveCronAnnounceSessionKey({
cfg: cfgWithAgentDefaults,
agentId,
fallbackSessionKey: announceMainSessionKey,
delivery: {
channel: resolvedDelivery.channel,
to: resolvedDelivery.to,
accountId: resolvedDelivery.accountId,
threadId: resolvedDelivery.threadId,
},
});
const taskLabel =
typeof params.job.name === "string" && params.job.name.trim()
? params.job.name.trim()