UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

77 lines (76 loc) 4.19 kB
import "./tokens-U6o7_k27.js"; import { o as listDescendantRunsForRequester } from "./subagent-registry-read-BmI9NJyA.js"; import { n as readLatestAssistantReply, o as waitForAgentRunsToDrain } from "./run-wait-Dy2KLsSJ.js"; import { n as isLikelyInterimCronMessage } from "./subagent-followup-hints-WJCMG0pw.js"; //#region src/cron/isolated-agent/subagent-followup.ts /** Reads or waits for descendant subagent summaries after isolated cron orchestration. */ function resolveCronSubagentTimings() { const fastTestMode = process.env.OPENCLAW_TEST_FAST === "1"; return { waitMinMs: fastTestMode ? 10 : 3e4, finalReplyGraceMs: fastTestMode ? 50 : 5e3, gracePollMs: fastTestMode ? 8 : 200 }; } /** Reads completed descendant subagent replies when the orchestrator only emitted interim text. */ async function readDescendantSubagentFallbackReply(params) { const descendants = listDescendantRunsForRequester(params.sessionKey).filter((entry) => typeof entry.endedAt === "number" && entry.endedAt >= params.runStartedAt && entry.childSessionKey.trim().length > 0).toSorted((a, b) => (a.endedAt ?? 0) - (b.endedAt ?? 0)); if (descendants.length === 0) return; const latestByChild = /* @__PURE__ */ new Map(); for (const entry of descendants) { const childKey = entry.childSessionKey.trim(); if (!childKey) continue; const current = latestByChild.get(childKey); if (!current || (entry.endedAt ?? 0) >= (current.endedAt ?? 0)) latestByChild.set(childKey, entry); } const replies = []; const latestRuns = [...latestByChild.values()].toSorted((a, b) => (a.endedAt ?? 0) - (b.endedAt ?? 0)).slice(-4); for (const entry of latestRuns) { const frozenResultText = entry.completion?.resultText; const frozenReply = typeof frozenResultText === "string" && frozenResultText.trim() ? frozenResultText.trim() : void 0; const usesInternalTranscript = typeof entry.execution?.transcriptFile === "string"; let reply = usesInternalTranscript ? frozenReply : void 0; if (!reply && !usesInternalTranscript) reply = (await readLatestAssistantReply({ sessionKey: entry.childSessionKey }))?.trim(); if (!reply && frozenReply) reply = frozenReply; if (!reply || reply.toUpperCase() === "NO_REPLY".toUpperCase()) continue; replies.push(reply); } if (replies.length === 0) return; if (replies.length === 1) return replies[0]; return replies.join("\n\n"); } /** * Waits for descendant subagents to complete using a push-based approach: * each active descendant run is awaited via `agent.wait` (gateway RPC) instead * of a busy-poll loop. After all active runs settle, a short grace period * polls the cron agent's session for a post-orchestration synthesis message. */ async function waitForDescendantSubagentSummary(params) { const timings = resolveCronSubagentTimings(); const initialReply = params.initialReply?.trim(); const deadline = Date.now() + Math.max(timings.waitMinMs, Math.floor(params.timeoutMs)); const getActiveRuns = () => listDescendantRunsForRequester(params.sessionKey).filter((entry) => typeof entry.endedAt !== "number"); const initialActiveRuns = getActiveRuns(); if (!(params.observedActiveDescendants === true || initialActiveRuns.length > 0)) return initialReply; await waitForAgentRunsToDrain({ deadlineAtMs: deadline, initialPendingRunIds: initialActiveRuns.map((entry) => entry.runId), getPendingRunIds: () => getActiveRuns().map((entry) => entry.runId) }); const gracePeriodDeadline = Math.min(Date.now() + timings.finalReplyGraceMs, deadline); const resolveUsableLatestReply = async () => { const latest = (await readLatestAssistantReply({ sessionKey: params.sessionKey }))?.trim(); if (latest && latest.toUpperCase() !== "NO_REPLY".toUpperCase() && (latest !== initialReply || !isLikelyInterimCronMessage(latest))) return latest; }; while (Date.now() < gracePeriodDeadline) { const latest = await resolveUsableLatestReply(); if (latest) return latest; await new Promise((resolve) => { setTimeout(resolve, timings.gracePollMs); }); } const latest = await resolveUsableLatestReply(); if (latest) return latest; } //#endregion export { readDescendantSubagentFallbackReply, waitForDescendantSubagentSummary };