UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

162 lines (161 loc) 7.55 kB
import { D as resolveExpiresAtMsFromDurationMs, E as resolveDateTimestampMs, a as addTimerTimeoutGraceMs, b as parseFiniteNumber, m as clampTimerTimeoutMs, o as asDateTimestampMs } from "./number-coercion-CLj0HTDM.js"; import { t as asBoolean } from "./boolean-DmBL0YJK.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { $ as normalizeAgentRunTerminalReplySnapshot, rt as normalizeAgentRunTerminalReceipt } from "./openclaw-state-db-BRTnL-D8.js"; import { o as callGateway } from "./call-BWR5pPgw.js"; import { t as hasRetryableConnectionErrorCode } from "./retryable-network-errors-D2gJmBqw.js"; import { o as isOpenClawMessageToolMirrorAssistantMessage, s as isTranscriptOnlyOpenClawAssistantMessage } from "./transcript-only-openclaw-assistant-CVgy4bjA.js"; import { a as buildAgentRunTerminalOutcomeFromWaitResult, m as normalizeBlockedLivenessWaitStatus } from "./agent-run-terminal-outcome-CigeY75d.js"; import { v as normalizeAgentRunTimeoutPhase } from "./run-termination-jabvTOp5.js"; import { n as stripToolMessages, t as extractStoredAssistantText } from "./chat-history-text-C2UOMgRe.js"; //#region src/agents/run-wait.ts /** * Gateway-backed agent run wait helpers. * Normalizes run wait responses, reads the latest assistant reply, and drains * pending run sets for tools that need synchronous completion semantics. */ function resolveRunWaitTimeoutMs(value) { return clampTimerTimeoutMs(parseFiniteNumber(value) ?? 1) ?? 1; } function resolveRunWaitDeadlineAtMs(params) { if (params.deadlineAtMs !== void 0) return asDateTimestampMs(params.deadlineAtMs) ?? resolveDateTimestampMs(Date.now()); return resolveExpiresAtMsFromDurationMs(resolveRunWaitTimeoutMs(params.timeoutMs)) ?? resolveDateTimestampMs(Date.now()); } function normalizeAgentWaitResult(status, runId, wait) { const receipt = normalizeAgentRunTerminalReceipt(wait?.terminalReceipt); const stopReason = typeof wait?.stopReason === "string" ? wait.stopReason : void 0; const normalized = normalizeTerminalOutcomeForWait(buildAgentRunTerminalOutcomeFromWaitResult({ ...wait, status }), status, wait?.livenessState); return { status: normalized.status, error: normalized.error, startedAt: typeof wait?.startedAt === "number" ? wait.startedAt : void 0, endedAt: typeof wait?.endedAt === "number" ? wait.endedAt : void 0, stopReason, livenessState: typeof wait?.livenessState === "string" ? wait.livenessState : void 0, yielded: wait?.yielded === true ? true : void 0, pendingError: wait?.pendingError === true ? true : void 0, timeoutPhase: normalizeAgentRunTimeoutPhase(wait?.timeoutPhase), providerStarted: asBoolean(wait?.providerStarted), terminalReply: normalizeAgentRunTerminalReplySnapshot(wait?.terminalReply), sourceReplyDelivered: receipt?.runId === runId && receipt.sourceReplyDelivered === true ? true : void 0 }; } function normalizeTerminalOutcomeForWait(outcome, fallbackStatus, livenessState) { if (outcome?.reason === "hard_timeout") return { status: outcome.status, error: outcome.error }; return normalizeBlockedLivenessWaitStatus({ status: outcome?.status ?? fallbackStatus, livenessState, error: outcome?.error }); } const RECOVERABLE_AGENT_WAIT_ERROR_PATTERNS = [ /gateway closed \(1006/i, /transport close/i, /connection loss/i, /connection closed/i, /gateway not connected/i, /no active .* listener/i, /socket hang up/i ]; /** Return true for transient gateway/transport failures that callers may retry. */ function isRecoverableAgentWaitError(error) { const message = error?.trim(); if (!message) return false; if (message.includes("gateway timeout") || message.includes("gateway request timeout")) return false; return hasRetryableConnectionErrorCode(message) || RECOVERABLE_AGENT_WAIT_ERROR_PATTERNS.some((pattern) => pattern.test(message)); } function normalizePendingRunIds(runIds) { const seen = /* @__PURE__ */ new Set(); for (const runId of runIds) { const normalized = runId.trim(); if (!normalized || seen.has(normalized)) continue; seen.add(normalized); } return [...seen]; } function isAssistantReplyTranscriptArtifact(message) { return isTranscriptOnlyOpenClawAssistantMessage(message) || isOpenClawMessageToolMirrorAssistantMessage(message) || isInterSessionInputMessage(message); } function isInterSessionInputMessage(message) { if (!message || typeof message !== "object" || Array.isArray(message)) return false; const provenance = message.provenance; return Boolean(provenance) && typeof provenance === "object" && !Array.isArray(provenance) && provenance.kind === "inter_session"; } /** Read the latest model-authored assistant text from session history. */ async function readLatestAssistantReply(params) { const history = await (params.callGateway ?? callGateway)({ method: "chat.history", params: { sessionKey: params.sessionKey, ...params.agentId ? { agentId: params.agentId } : {}, limit: params.limit ?? 50 } }); const messages = stripToolMessages(Array.isArray(history?.messages) ? history.messages : []); for (let i = messages.length - 1; i >= 0; i -= 1) { const message = messages[i]; if (isAssistantReplyTranscriptArtifact(message)) continue; const text = extractStoredAssistantText(message); if (text?.trim()) return text; } } /** Wait for one agent run through the gateway and normalize timeout/error states. */ async function waitForAgentRun(params) { const timeoutMs = resolveRunWaitTimeoutMs(params.timeoutMs); try { const wait = await (params.callGateway ?? callGateway)({ method: "agent.wait", params: { runId: params.runId, timeoutMs }, timeoutMs: addTimerTimeoutGraceMs(timeoutMs, 2e3) }); if (wait?.status === "timeout") return normalizeAgentWaitResult("timeout", params.runId, wait); if (wait?.status === "pending") return normalizeAgentWaitResult("pending", params.runId, wait); if (wait?.status === "error") return normalizeAgentWaitResult("error", params.runId, wait); return normalizeAgentWaitResult("ok", params.runId, wait); } catch (err) { const error = formatErrorMessage(err); return { status: error.includes("gateway timeout") || error.includes("gateway request timeout") ? "timeout" : "error", error, ...isRecoverableAgentWaitError(error) ? { retryableTransportError: true } : {} }; } } /** Read the completed run's reply without inferring delivery from display history. */ async function waitForAgentRunReply(params) { const wait = await waitForAgentRun(params); return wait.status === "ok" && wait.terminalReply?.disposition === "visible" ? { ...wait, replyText: wait.terminalReply.text } : wait; } /** Wait until the current and newly spawned pending run IDs are drained or timed out. */ async function waitForAgentRunsToDrain(params) { const deadlineAtMs = resolveRunWaitDeadlineAtMs(params); let pendingRunIds = new Set(normalizePendingRunIds(params.initialPendingRunIds ?? params.getPendingRunIds())); while (pendingRunIds.size > 0 && Date.now() < deadlineAtMs) { const remainingMs = Math.max(1, deadlineAtMs - Date.now()); await Promise.allSettled([...pendingRunIds].map((runId) => waitForAgentRun({ runId, timeoutMs: remainingMs, callGateway: params.callGateway }))); pendingRunIds = new Set(normalizePendingRunIds(params.getPendingRunIds())); } return { timedOut: pendingRunIds.size > 0, pendingRunIds: [...pendingRunIds], deadlineAtMs }; } //#endregion export { waitForAgentRunsToDrain as i, waitForAgentRun as n, waitForAgentRunReply as r, readLatestAssistantReply as t };