UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

94 lines (93 loc) • 7.01 kB
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs"; import { r as truncateUtf16Safe } from "./utf16-slice-D_ngcYKd.mjs"; import { n as HEARTBEAT_TOKEN, r as SILENT_REPLY_TOKEN } from "./tokens-D4ghQG_g.mjs"; import { o as isHeartbeatAcknowledgementText, r as HEARTBEAT_RESPONSE_TOOL_INSTRUCTIONS } from "./heartbeat-BjLIgeQc.mjs"; import "./user-facing-text-DC1sCo4O.mjs"; //#region src/infra/heartbeat-events-filter.ts const MAX_EXEC_EVENT_PROMPT_CHARS = 8e3; const HEARTBEAT_DELIVERY_CONTEXT_KEY_PREFIX = "heartbeat-delivery:"; const STRUCTURED_EXEC_COMPLETION_EVENT_RE = /^exec (completed|failed) \(([a-z0-9_-]{1,64}), (code -?\d+|signal [^)]+)\)(?: :: ([\s\S]*)|\n\n([\s\S]+))?$/i; function parseStructuredExecCompletionEvent(evt) { const trimmed = evt.trim(); const match = STRUCTURED_EXEC_COMPLETION_EVENT_RE.exec(trimmed); if (!match || match[5] !== void 0 && match[5] !== "The command was terminated, but external side effects may already have completed. Verify the resulting state before retrying. Do not automatically rerun non-idempotent commands. Use a higher timeout only when the command is known to be safe to retry.") return null; const action = match[1] ?? ""; const result = match[3] ?? ""; return { raw: trimmed, action, id: match[2] ?? "", result, output: (match[4] ?? "").trim(), notes: (match[5] ?? "").trim(), succeeded: action.toLowerCase() === "completed" && result.toLowerCase() === "code 0" }; } function isRelayableExecCompletionEvent(evt) { const parsed = parseStructuredExecCompletionEvent(evt); if (!parsed) return isExecCompletionEvent(evt); return Boolean(parsed.output) || !parsed.succeeded; } function formatExecEventPromptText(pendingEvents) { let hasMissingOutputFailure = false; return { text: pendingEvents.flatMap((event) => { const parsed = parseStructuredExecCompletionEvent(event); if (!parsed) { const trimmed = event.trim(); return trimmed ? [trimmed] : []; } if (parsed.output) return [parsed.raw]; if (parsed.succeeded) return []; hasMissingOutputFailure = true; const missingOutput = `Exec ${parsed.action} (${parsed.id}, ${parsed.result}) without captured stdout/stderr.`; return [parsed.notes ? `${missingOutput}\n\n${parsed.notes}` : missingOutput]; }).join("\n").trim(), hasMissingOutputFailure }; } function buildCronEventPrompt(pendingEvents, opts) { const deliverToUser = opts?.deliverToUser ?? true; const useHeartbeatResponseTool = opts?.useHeartbeatResponseTool ?? false; const eventText = pendingEvents.join("\n").trim(); if (!eventText) return `A scheduled cron event was triggered, but no event content was found. ${useHeartbeatResponseTool ? HEARTBEAT_RESPONSE_TOOL_INSTRUCTIONS : deliverToUser ? `Reply ${SILENT_REPLY_TOKEN}.` : `Handle this internally and reply ${SILENT_REPLY_TOKEN} when nothing needs user-facing follow-up.`}`; const instruction = deliverToUser ? "Please relay this reminder to the user in a helpful and friendly way." : "Handle this reminder internally. Do not relay it to the user unless explicitly requested."; return "A scheduled reminder has been triggered. The reminder content is:\n\n" + eventText + "\n\n" + instruction; } function buildExecEventPrompt(pendingEvents, opts) { const deliverToUser = opts?.deliverToUser ?? true; const useHeartbeatResponseTool = opts?.useHeartbeatResponseTool ?? false; const { text: rawEventText, hasMissingOutputFailure } = formatExecEventPromptText(pendingEvents); const eventText = rawEventText.length > MAX_EXEC_EVENT_PROMPT_CHARS ? `${truncateUtf16Safe(rawEventText, MAX_EXEC_EVENT_PROMPT_CHARS)}\n\n[truncated]` : rawEventText; if (!eventText) return `An async command completion event was triggered, but no command output was found. ${useHeartbeatResponseTool ? HEARTBEAT_RESPONSE_TOOL_INSTRUCTIONS : `Reply ${SILENT_REPLY_TOKEN} only.`} Do not mention, summarize, or reuse output from any earlier run.`; if (!deliverToUser) return `An async command completion event was triggered, but user delivery is disabled for this run. ${useHeartbeatResponseTool ? `Handle the result internally. ${HEARTBEAT_RESPONSE_TOOL_INSTRUCTIONS}` : `Handle the result internally and reply ${SILENT_REPLY_TOKEN} only.`} Do not mention, summarize, or reuse command output.`; const completionInstruction = useHeartbeatResponseTool ? HEARTBEAT_RESPONSE_TOOL_INSTRUCTIONS : `If no user-facing update is needed, reply ${SILENT_REPLY_TOKEN} only.`; const missingOutputInstruction = hasMissingOutputFailure ? " If reporting a failure without captured output, include the exit status or signal. Do not ask the user to provide missing logs, and do not try to retrieve logs from an exec/session id." : ""; return "An async command you ran earlier has completed. The command completion details are:\n\n" + eventText + "\n\nTreat this completion as an internal continuation, not a new user request. Reconcile it with the conversation and continue any outstanding authorized work. Notify the user only if this provides a requested result not yet delivered, a meaningful change to the outcome, or a new unresolved failure, blocker, or decision they need to know about. Stay silent for routine output, duplicate or superseded results, and failures already recovered from; do not recap them or announce that nothing changed. " + completionInstruction + missingOutputInstruction; } const HEARTBEAT_OK_PREFIX = normalizeLowercaseStringOrEmpty(HEARTBEAT_TOKEN); function isHeartbeatNoiseEvent(evt) { const lower = normalizeLowercaseStringOrEmpty(evt); if (!lower) return false; return isHeartbeatAcknowledgementText(evt, 0) || lower.startsWith(HEARTBEAT_OK_PREFIX) && !/[a-z0-9_]/.test(lower.charAt(HEARTBEAT_OK_PREFIX.length)) || lower.includes("heartbeat poll") || lower.includes("heartbeat wake"); } /** Context-key prefix the restart sentinel gives a continuation queued for one session. */ const RESTART_CONTINUATION_CONTEXT_PREFIX = "task:restart-sentinel:"; /** A restart continuation event resumes a specific session's interrupted turn. */ function isRestartContinuationEvent(event) { return event.contextKey?.startsWith("task:restart-sentinel:") ?? false; } function isExecCompletionEvent(evt) { const trimmed = evt.trimStart(); const normalized = normalizeLowercaseStringOrEmpty(trimmed); return /^exec finished(?::|\s*\()/.test(normalized) || parseStructuredExecCompletionEvent(trimmed) !== null; } function isHeartbeatDeliveryAwarenessEvent(event) { return event.contextKey?.startsWith("heartbeat-delivery:") ?? false; } function isCronSystemEvent(evt) { if (!evt.trim()) return false; return !isHeartbeatNoiseEvent(evt) && !isExecCompletionEvent(evt); } //#endregion export { isCronSystemEvent as a, isRelayableExecCompletionEvent as c, buildExecEventPrompt as i, isRestartContinuationEvent as l, RESTART_CONTINUATION_CONTEXT_PREFIX as n, isExecCompletionEvent as o, buildCronEventPrompt as r, isHeartbeatDeliveryAwarenessEvent as s, HEARTBEAT_DELIVERY_CONTEXT_KEY_PREFIX as t };