openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
250 lines (249 loc) • 11.6 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs";
import { a as asOptionalRecord, i as asOptionalObjectRecord } from "./record-coerce-TIsquoVR.mjs";
import { n as AGENT_RUN_RESTART_ABORT_ERROR, r as AGENT_RUN_RESTART_ABORT_ERROR_CODE } from "./run-termination-5c-0T0hN.mjs";
import "./code-mode-control-tools-FkhKD315.mjs";
import { f as isMainSessionRestartRecoveryInputProvenance } from "./input-provenance-B5YZS2Do.mjs";
import { n as getTranscriptMessageRole, o as isIntermediateAssistantTranscriptMessage, s as isMeaningfulTranscriptMessage, u as readTerminalSourceReplyDeliveryMirror } from "./message-visibility-DbYIDWQY.mjs";
import { r as isAgentToolReplaySafe } from "./tool-replay-safety-BvINajgM.mjs";
//#region src/agents/main-session-recovery/main-session-restart-recovery-resume-policy.ts
function readDeliveredTerminalSourceReplyToolCallId(messages, expectedSourceTurnId) {
if (!expectedSourceTurnId) return;
for (const message of messages.toReversed()) {
if (getTranscriptMessageRole(message) !== "assistant") continue;
const mirror = readTerminalSourceReplyDeliveryMirror(message);
if (mirror?.sourceTurnId === expectedSourceTurnId) return mirror.toolCallId;
}
}
function readCodeModeWaitCall(message) {
const record = asOptionalObjectRecord(message);
if (getTranscriptMessageRole(message) !== "assistant" || record?.stopReason !== "toolUse") return;
const content = record.content;
if (!Array.isArray(content)) return;
const supportedTypes = /* @__PURE__ */ new Set([
"text",
"thinking",
"toolCall",
"toolUse",
"tool_use"
]);
if (content.some((block) => !block || typeof block !== "object" || !supportedTypes.has(String(block.type)) || block.type === "text" && Boolean(normalizeOptionalString(block.text)))) return;
const toolCalls = content.filter((block) => {
const type = block.type;
return type === "toolCall" || type === "toolUse" || type === "tool_use";
});
if (toolCalls.length !== 1) return;
const block = toolCalls[0];
if (normalizeOptionalString(block.name) !== "wait") return;
const args = asOptionalObjectRecord(block.arguments ?? block.input);
const runId = normalizeOptionalString(args?.runId);
if (!runId) return;
const toolCallId = normalizeOptionalString(block.id);
return {
runId,
...toolCallId ? { toolCallId } : {}
};
}
function isResumableTailMessage(message) {
const role = getTranscriptMessageRole(message);
return role === "user" || role === "tool" || role === "toolResult";
}
function readPendingAssistantContent(message) {
const record = asOptionalObjectRecord(message);
return getTranscriptMessageRole(message) === "assistant" && normalizeOptionalString(record?.stopReason) === "toolUse" && Array.isArray(record?.content) ? record.content : void 0;
}
function isPendingAssistantToolCall(message) {
const content = readPendingAssistantContent(message);
if (!content) return false;
let hasToolCall = false;
for (const block of content) {
if (!block || typeof block !== "object") return false;
const type = normalizeOptionalString(block.type);
if (type === "toolCall" || type === "toolUse" || type === "tool_use") {
hasToolCall = true;
continue;
}
if (type === "thinking") continue;
if (type === "text" && !normalizeOptionalString(block.text)) continue;
return false;
}
return hasToolCall;
}
function classifyDanglingToolCalls(content) {
if (!Array.isArray(content)) return;
let allReplaySafe = true;
let hasToolCall = false;
for (const block of content) {
if (!block || typeof block !== "object") return;
const type = normalizeOptionalString(block.type);
if (type !== "toolCall" && type !== "toolUse" && type !== "tool_use") continue;
const name = normalizeOptionalString(block.name);
if (name === "exec" || name === "wait") return { kind: "code-mode" };
if (!isAgentToolReplaySafe({ name })) allReplaySafe = false;
hasToolCall = true;
}
return hasToolCall ? {
kind: "resumable",
forceRestartSafeTools: !allReplaySafe
} : { kind: "none" };
}
function readCodeModeCheckpoint(message) {
const record = asOptionalObjectRecord(message);
const role = getTranscriptMessageRole(message);
if (!record || role !== "tool" && role !== "toolResult") return;
const toolName = normalizeOptionalString(record.toolName);
if (toolName !== "exec" && toolName !== "wait") return;
const content = record.content;
if (!Array.isArray(content)) return;
const textBlock = content.find((block) => block && typeof block === "object" && block.type === "text");
const text = normalizeOptionalString(textBlock?.text);
if (!text) return;
try {
const result = JSON.parse(text);
if (result.status === "completed" || result.status === "failed") return { replaySafe: result.replaySafe === true };
const runId = normalizeOptionalString(result.runId);
return result.status === "waiting" && runId ? {
replaySafe: result.replaySafe === true,
runId
} : void 0;
} catch {
return;
}
}
function hasReplaySafeCodeModeCheckpointInCurrentTurn(messages) {
for (let index = messages.length - 1; index >= 0; index -= 1) {
const message = messages[index];
if (getTranscriptMessageRole(message) === "user" && !isMainSessionRestartRecoveryInputProvenance(asOptionalRecord(message)?.provenance)) return false;
if (readCodeModeCheckpoint(message)?.replaySafe === true) return true;
}
return false;
}
const LEGACY_RESTART_ABORT_ERROR_MESSAGES = /* @__PURE__ */ new Set([
"Request was aborted",
"This operation was aborted",
AGENT_RUN_RESTART_ABORT_ERROR
]);
const CODE_MODE_RESTART_ABORT_ERROR = "code mode execution aborted";
function isRestartAbortAssistantMessage(message) {
const record = asOptionalObjectRecord(message);
if (!record || getTranscriptMessageRole(message) !== "assistant") return false;
const stopReason = normalizeOptionalString(record.stopReason);
if (stopReason === "aborted") return true;
if (stopReason !== "error") return false;
const errorCode = normalizeOptionalString(record.errorCode);
if (errorCode !== void 0) return errorCode === AGENT_RUN_RESTART_ABORT_ERROR_CODE;
const errorMessage = normalizeOptionalString(record.errorMessage);
return errorMessage !== void 0 && LEGACY_RESTART_ABORT_ERROR_MESSAGES.has(errorMessage);
}
function isRestartAbortTailArtifact(message) {
if (!isRestartAbortAssistantMessage(message)) return false;
const content = message.content;
return Array.isArray(content) && content.length === 0;
}
function isRestartAbortedWaitFailure(message) {
const record = asOptionalObjectRecord(message);
if (!record || getTranscriptMessageRole(message) !== "toolResult") return false;
if (normalizeOptionalString(record.toolName) !== "wait" || record.isError !== true) return false;
const details = asOptionalObjectRecord(record.details);
if (details?.status !== "failed") return false;
const content = record.content;
const contentText = Array.isArray(content) ? content.filter((block) => block && typeof block === "object" && block.type === "text").map((block) => normalizeOptionalString(block.text) ?? "").join("\n") : "";
const errorText = normalizeOptionalString(details.error) ?? normalizeOptionalString(contentText);
const code = normalizeOptionalString(details.code);
if (code === "aborted") return errorText === CODE_MODE_RESTART_ABORT_ERROR;
if (code !== "internal_error") return false;
return /^(?:(?:Abort)?Error:\s*)?(?:The|This) operation was aborted\.?$/u.test(errorText ?? "");
}
function isRestartAbortedWaitResultArtifact(message, waitMessage) {
if (!isRestartAbortedWaitFailure(message)) return false;
const toolCallId = normalizeOptionalString(message.toolCallId);
const waitCall = readCodeModeWaitCall(waitMessage);
return Boolean(toolCallId && waitCall?.toolCallId === toolCallId);
}
function requiresRestartSafeToolResult(message) {
const record = asOptionalObjectRecord(message);
if (!record || getTranscriptMessageRole(message) !== "toolResult") return false;
const details = asOptionalObjectRecord(record.details);
return details?.reason === "missing_tool_result" || details?.status === "approval-pending";
}
function resolveMainSessionResumePolicy(messages, forceRestartSafeTools = false, expectedSourceTurnId, beforeAgentReplyState, deliveryReceiptState, deliveryToolCallId, fullAccess = false) {
const mirroredToolCallId = readDeliveredTerminalSourceReplyToolCallId(messages, expectedSourceTurnId);
if (mirroredToolCallId) return {
action: "complete",
reason: "delivered-terminal",
toolCallId: mirroredToolCallId
};
if (deliveryReceiptState === "delivered-terminal") return deliveryToolCallId ? {
action: "complete",
reason: "delivered-terminal-receipt",
toolCallId: deliveryToolCallId
} : {
action: "resume",
forceRestartSafeTools: true
};
if (deliveryReceiptState === "terminal-pending") return {
action: "resume",
forceRestartSafeTools: true
};
if (beforeAgentReplyState === "handled-silent") return {
action: "complete",
reason: "handled-silent"
};
if (beforeAgentReplyState === "pending" || beforeAgentReplyState === "handled-reply" || beforeAgentReplyState === "handled-unrecoverable") return {
action: "resume",
forceRestartSafeTools: true
};
if (fullAccess && !hasReplaySafeCodeModeCheckpointInCurrentTurn(messages)) return {
action: "resume",
forceRestartSafeTools: false
};
const meaningfulMessages = messages.toReversed().filter((message) => isMeaningfulTranscriptMessage(message) && !isIntermediateAssistantTranscriptMessage(message));
if (isRestartAbortAssistantMessage(meaningfulMessages[0])) {
const dangling = classifyDanglingToolCalls(meaningfulMessages[0].content);
if (dangling?.kind === "resumable") return {
action: "resume",
forceRestartSafeTools: dangling.forceRestartSafeTools
};
if (dangling?.kind === "none") meaningfulMessages.shift();
}
if (isRestartAbortedWaitResultArtifact(meaningfulMessages[0], meaningfulMessages[1])) meaningfulMessages.shift();
const lastMeaningful = meaningfulMessages[0];
if (forceRestartSafeTools && isPendingAssistantToolCall(lastMeaningful) || isRestartAbortedWaitFailure(lastMeaningful)) return {
action: "resume",
forceRestartSafeTools: true
};
const waitCall = readCodeModeWaitCall(lastMeaningful);
const checkpoint = readCodeModeCheckpoint(meaningfulMessages[waitCall ? 1 : 0]);
if (waitCall || checkpoint) return checkpoint?.replaySafe === true && (!waitCall || checkpoint.runId === waitCall.runId) ? {
action: "resume",
forceRestartSafeTools: true,
forceCodeModeTools: true
} : {
action: "resume",
forceRestartSafeTools: true
};
const pendingToolCallTail = classifyDanglingToolCalls(readPendingAssistantContent(lastMeaningful));
if (pendingToolCallTail?.kind === "resumable") return {
action: "resume",
forceRestartSafeTools: pendingToolCallTail.forceRestartSafeTools
};
if ((lastMeaningful && typeof lastMeaningful === "object" ? classifyDanglingToolCalls(lastMeaningful.content) : void 0)?.kind === "code-mode") return {
action: "resume",
forceRestartSafeTools: true
};
if (!lastMeaningful || !isResumableTailMessage(lastMeaningful)) return {
action: "resume",
forceRestartSafeTools: false
};
if (requiresRestartSafeToolResult(lastMeaningful)) return {
action: "resume",
forceRestartSafeTools: true
};
const forceCodeModeTools = hasReplaySafeCodeModeCheckpointInCurrentTurn(messages);
return {
action: "resume",
forceRestartSafeTools: forceCodeModeTools,
...forceCodeModeTools ? { forceCodeModeTools: true } : {}
};
}
//#endregion
export { isRestartAbortTailArtifact as n, resolveMainSessionResumePolicy as r, hasReplaySafeCodeModeCheckpointInCurrentTurn as t };