mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 05:11:36 +00:00
feat(cron): enhance delivery modes and job configuration
- Updated isolated cron jobs to support new delivery modes: `announce` and `none`, improving output management. - Refactored job configuration to remove legacy fields and streamline delivery settings. - Enhanced the `CronJobEditor` UI to reflect changes in delivery options, including a new segmented control for delivery mode selection. - Updated documentation to clarify the new delivery configurations and their implications for job execution. - Improved tests to validate the new delivery behavior and ensure backward compatibility with legacy settings. This update provides users with greater flexibility in managing how isolated jobs deliver their outputs, enhancing overall usability and clarity in job configurations.
This commit is contained in:
committed by
Peter Steinberger
parent
ab9f06f4ff
commit
3f82daefd8
@@ -44,14 +44,13 @@ import {
|
||||
normalizeVerboseLevel,
|
||||
supportsXHighThinking,
|
||||
} from "../../auto-reply/thinking.js";
|
||||
import { createOutboundSendDeps, type CliDeps } from "../../cli/outbound-send-deps.js";
|
||||
import { type CliDeps } from "../../cli/outbound-send-deps.js";
|
||||
import {
|
||||
resolveAgentMainSessionKey,
|
||||
resolveSessionTranscriptPath,
|
||||
updateSessionStore,
|
||||
} from "../../config/sessions.js";
|
||||
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
||||
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
|
||||
import { getRemoteSkillEligibility } from "../../infra/skills-remote.js";
|
||||
import { logWarn } from "../../logger.js";
|
||||
import { buildAgentMainSessionKey, normalizeAgentId } from "../../routing/session-key.js";
|
||||
@@ -242,9 +241,6 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
const agentPayload = params.job.payload.kind === "agentTurn" ? params.job.payload : null;
|
||||
const deliveryPlan = resolveCronDeliveryPlan(params.job);
|
||||
const deliveryRequested = deliveryPlan.requested;
|
||||
const bestEffortDeliver = deliveryPlan.bestEffort;
|
||||
const legacyDeliveryMode =
|
||||
deliveryPlan.source === "payload" ? deliveryPlan.legacyMode : undefined;
|
||||
|
||||
const resolvedDelivery = await resolveDeliveryTarget(cfgWithAgentDefaults, agentId, {
|
||||
channel: deliveryPlan.channel ?? "last",
|
||||
@@ -294,6 +290,10 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
// Internal/trusted source - use original format
|
||||
commandBody = `${base}\n${timeLine}`.trim();
|
||||
}
|
||||
if (deliveryRequested) {
|
||||
commandBody =
|
||||
`${commandBody}\n\nDo not send messages via messaging tools. Return your summary as plain text; delivery is handled automatically. If the task explicitly calls for messaging a specific external recipient, note who/where it should go instead of sending it yourself.`.trim();
|
||||
}
|
||||
|
||||
const existingSnapshot = cronSession.sessionEntry.skillsSnapshot;
|
||||
const skillsSnapshotVersion = getSkillsSnapshotVersion(workspaceDir);
|
||||
@@ -380,6 +380,8 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
verboseLevel: resolvedVerboseLevel,
|
||||
timeoutMs,
|
||||
runId: cronSession.sessionEntry.sessionId,
|
||||
requireExplicitMessageTarget: true,
|
||||
disableMessageTool: deliveryRequested,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -432,7 +434,6 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
const skipHeartbeatDelivery = deliveryRequested && isHeartbeatOnlyResponse(payloads, ackMaxChars);
|
||||
const skipMessagingToolDelivery =
|
||||
deliveryRequested &&
|
||||
legacyDeliveryMode === "auto" &&
|
||||
runResult.didSendViaMessagingTool === true &&
|
||||
(runResult.messagingToolSentTargets ?? []).some((target) =>
|
||||
matchesMessagingToolDeliveryTarget(target, {
|
||||
@@ -443,71 +444,35 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
);
|
||||
|
||||
if (deliveryRequested && !skipHeartbeatDelivery && !skipMessagingToolDelivery) {
|
||||
if (deliveryPlan.mode === "announce") {
|
||||
const requesterSessionKey = resolveAgentMainSessionKey({
|
||||
cfg: cfgWithAgentDefaults,
|
||||
agentId,
|
||||
});
|
||||
const useExplicitOrigin = deliveryPlan.channel !== "last" || Boolean(deliveryPlan.to?.trim());
|
||||
const requesterOrigin = useExplicitOrigin
|
||||
? {
|
||||
channel: resolvedDelivery.channel,
|
||||
to: resolvedDelivery.to,
|
||||
accountId: resolvedDelivery.accountId,
|
||||
threadId: resolvedDelivery.threadId,
|
||||
}
|
||||
: undefined;
|
||||
const outcome: SubagentRunOutcome = { status: "ok" };
|
||||
const taskLabel = params.job.name?.trim() || "cron job";
|
||||
await runSubagentAnnounceFlow({
|
||||
childSessionKey: agentSessionKey,
|
||||
childRunId: cronSession.sessionEntry.sessionId,
|
||||
requesterSessionKey,
|
||||
requesterOrigin,
|
||||
requesterDisplayKey: requesterSessionKey,
|
||||
task: taskLabel,
|
||||
timeoutMs: 30_000,
|
||||
cleanup: "keep",
|
||||
roundOneReply: outputText ?? summary,
|
||||
waitForCompletion: false,
|
||||
label: `Cron: ${taskLabel}`,
|
||||
outcome,
|
||||
});
|
||||
} else {
|
||||
if (!resolvedDelivery.to) {
|
||||
const reason =
|
||||
resolvedDelivery.error?.message ?? "Cron delivery requires a recipient (--to).";
|
||||
if (!bestEffortDeliver) {
|
||||
return {
|
||||
status: "error",
|
||||
summary,
|
||||
outputText,
|
||||
error: reason,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: "skipped",
|
||||
summary: `Delivery skipped (${reason}).`,
|
||||
outputText,
|
||||
};
|
||||
}
|
||||
try {
|
||||
await deliverOutboundPayloads({
|
||||
cfg: cfgWithAgentDefaults,
|
||||
const requesterSessionKey = resolveAgentMainSessionKey({
|
||||
cfg: cfgWithAgentDefaults,
|
||||
agentId,
|
||||
});
|
||||
const useExplicitOrigin = deliveryPlan.channel !== "last" || Boolean(deliveryPlan.to?.trim());
|
||||
const requesterOrigin = useExplicitOrigin
|
||||
? {
|
||||
channel: resolvedDelivery.channel,
|
||||
to: resolvedDelivery.to,
|
||||
accountId: resolvedDelivery.accountId,
|
||||
payloads,
|
||||
bestEffort: bestEffortDeliver,
|
||||
deps: createOutboundSendDeps(params.deps),
|
||||
});
|
||||
} catch (err) {
|
||||
if (!bestEffortDeliver) {
|
||||
return { status: "error", summary, outputText, error: String(err) };
|
||||
threadId: resolvedDelivery.threadId,
|
||||
}
|
||||
return { status: "ok", summary, outputText };
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
const outcome: SubagentRunOutcome = { status: "ok" };
|
||||
const taskLabel = params.job.name?.trim() || "cron job";
|
||||
await runSubagentAnnounceFlow({
|
||||
childSessionKey: agentSessionKey,
|
||||
childRunId: cronSession.sessionEntry.sessionId,
|
||||
requesterSessionKey,
|
||||
requesterOrigin,
|
||||
requesterDisplayKey: requesterSessionKey,
|
||||
task: taskLabel,
|
||||
timeoutMs: 30_000,
|
||||
cleanup: "keep",
|
||||
roundOneReply: outputText ?? summary,
|
||||
waitForCompletion: false,
|
||||
label: `Cron: ${taskLabel}`,
|
||||
outcome,
|
||||
});
|
||||
}
|
||||
|
||||
return { status: "ok", summary, outputText };
|
||||
|
||||
Reference in New Issue
Block a user