UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

394 lines (393 loc) 16.4 kB
import { $ as normalizeAgentRunTerminalReplySnapshot, Z as buildAgentRunTerminalReplySnapshot, rt as normalizeAgentRunTerminalReceipt, tt as formatAgentRunRouteChange } from "./openclaw-state-db-BRTnL-D8.js"; import { C as requireActivePluginRegistry } from "./runtime-BL4wZfTq.js"; import { i as buildAgentRunTerminalOutcomeFromLifecycleEvent } from "./agent-run-terminal-outcome-CigeY75d.js"; import { m as resolveAgentRunAbortLifecycleFields } from "./run-termination-jabvTOp5.js"; import { t as runWithModelFallback } from "./model-fallback-runner-DfBb8xXp.js"; import { i as createContextEngineLogicalTurnLease, r as finalizeAcceptedContextEngineTurn, t as discardContextEngineTurnAttemptIntent } from "./context-engine-turn-attempt-DYtIyzTH.js"; import { c as selectAgentHarness } from "./selection-CgLPGlZh.js"; import { t as ensureSelectedAgentHarnessPlugin } from "./runtime-plugin-D91_vuOE.js"; import { i as mergeEmbeddedAgentRunResultForModelFallbackExhaustion, t as classifyEmbeddedAgentRunResultForModelFallback } from "./result-fallback-classifier-C3DQO8OC.js"; //#region src/agents/embedded-agent-runner/run-entry.ts const PRESERVED_FOLLOWUP_RESULT_CODES = /* @__PURE__ */ new Set([ "empty_result", "reasoning_only_result", "planning_only_result" ]); function preserveFollowupResultForDelivery(classification) { if (!classification || !("code" in classification) || !classification.code || !PRESERVED_FOLLOWUP_RESULT_CODES.has(classification.code)) return classification; return { ...classification, preserveResultOnExhaustion: true, preserveResultPriority: -1 }; } function resolveTerminalOutcome(params) { const meta = params.result.meta; return buildAgentRunTerminalOutcomeFromLifecycleEvent({ phase: params.fallbackExhausted || meta.error ? "error" : "end", data: { ...meta, error: meta.error?.message } }); } function canAdvanceContextEngineTurn(params) { const meta = params.result.meta; return params.fallbackOutcome === "completed" && params.terminal.outcome.status === "ok" && meta.yielded !== true && meta.aborted !== true && meta.error === void 0 && meta.timeoutPhase === void 0 && meta.stopReason !== "error" && meta.stopReason !== "timeout"; } function mergeRunEntryExecutionTrace(params) { const currentTrace = params.result.meta.executionTrace; const winnerProvider = params.terminalStatus === "ok" ? currentTrace?.winnerProvider ?? params.provider : void 0; const winnerModel = params.terminalStatus === "ok" ? currentTrace?.winnerModel ?? params.model : void 0; const outerAttempts = params.fallbackAttempts.map((attempt) => ({ provider: attempt.provider, model: attempt.model, result: attempt.reason === "timeout" ? "timeout" : "candidate_failed", ...attempt.reason ? { reason: attempt.reason } : {}, ...typeof attempt.status === "number" ? { status: attempt.status } : {} })); const innerAttempts = (currentTrace?.attempts ?? []).filter((attempt) => attempt.result !== "success"); const winnerAttempt = currentTrace?.attempts?.findLast((attempt) => attempt.result === "success" && attempt.provider === winnerProvider && attempt.model === winnerModel); const attempts = [ ...outerAttempts, ...innerAttempts, ...winnerProvider && winnerModel ? [winnerAttempt ?? { provider: winnerProvider, model: winnerModel, result: "success" }] : [] ]; const terminalReceipt = params.result.meta.agentMeta?.terminalReceipt; const requested = { provider: params.requestedProvider, model: params.requestedModel }; const agentMeta = terminalReceipt ? { ...params.result.meta.agentMeta, terminalReceipt: { ...terminalReceipt, requested, rerouted: terminalReceipt.rerouted || terminalReceipt.effective.provider !== requested.provider || terminalReceipt.effective.model !== requested.model } } : params.result.meta.agentMeta; return { ...params.result, meta: { ...params.result.meta, agentMeta, executionTrace: { ...currentTrace, winnerProvider, winnerModel, attempts: attempts.length > 0 ? attempts : void 0, fallbackUsed: currentTrace?.fallbackUsed === true || outerAttempts.length > 0 } } }; } function buildTerminal(params) { const meta = params.result.meta; const outcome = params.outcome; const internalReply = params.result.messagingToolSourceReplyPayloads?.findLast((payload) => payload.sourceReplyFinal === true); let terminalReply = normalizeAgentRunTerminalReplySnapshot(meta.terminalReply) ?? buildAgentRunTerminalReplySnapshot(internalReply ? { visibleText: internalReply.text } : { visibleText: meta.finalAssistantVisibleText, rawText: meta.finalAssistantRawText, terminalReplyKind: meta.terminalReplyKind }); const agentMeta = meta.agentMeta; const normalizedTerminalReceipt = normalizeAgentRunTerminalReceipt(agentMeta?.terminalReceipt) ?? (params.result.sourceReplyDelivered && agentMeta?.provider && agentMeta.model ? { runId: params.runId, sessionId: params.sessionId, turnId: params.runId, requested: params.requested, effective: { provider: agentMeta.provider, model: agentMeta.model, responseModel: agentMeta.model }, successfulToolNames: ["message"], sourceReplyDelivered: true, rerouted: agentMeta.provider !== params.requested.provider || agentMeta.model !== params.requested.model } : void 0); const terminalReceipt = normalizedTerminalReceipt?.runId === params.runId ? { ...normalizedTerminalReceipt, terminalDisposition: terminalReply.disposition === "visible" ? "visible" : "not-visible" } : void 0; const modelRouteChange = formatAgentRunRouteChange(terminalReceipt, params.runId); if (modelRouteChange && terminalReply.disposition === "visible") terminalReply = { ...terminalReply, modelRouteChange }; const metadata = { terminalReply }; if (terminalReceipt) metadata.terminalReceipt = terminalReceipt; if (params.behavior.kind === "channel-delivery" || params.behavior.kind === "followup-delivery") for (const key of [ "stopReason", "yielded", "timeoutPhase", "providerStarted", "aborted", "livenessState", "replayInvalid" ]) { if (!Object.hasOwn(meta, key)) continue; metadata[key] = key in outcome ? outcome[key] : meta[key]; } else { for (const key of [ "stopReason", "livenessState", "timeoutPhase", "providerStarted" ]) if (outcome[key] !== void 0) metadata[key] = outcome[key]; if (typeof meta.aborted === "boolean") metadata.aborted = meta.aborted; if (meta.replayInvalid === true) metadata.replayInvalid = true; if (meta.yielded === true) metadata.yielded = true; } return { outcome, metadata }; } /** Runs one logical turn across model candidates and advances only the accepted winner. */ async function runEmbeddedAgentEntry(params) { const contextEngineLogicalTurnLease = await createContextEngineLogicalTurnLease({ config: params.selection.cfg, agentDir: params.selection.agentDir, workspaceDir: params.harness.workspaceDir }); let unsettledContextEngineTurnAttempt; let candidateIndex = 0; const committedSideEffect = params.behavior.kind === "command-rpc" ? params.behavior.hasCommittedSideEffect : void 0; const readChannelDeliveryEvidence = params.behavior.kind === "channel-delivery" ? params.behavior.readDeliveryEvidence : void 0; const preparedHarnessRuntimes = /* @__PURE__ */ new Set(); const prepareHarnessRuntime = async (candidate) => { const key = [ candidate.provider, candidate.model, candidate.agentHarnessRuntimeOverride ?? "" ].join("\0"); if (preparedHarnessRuntimes.has(key)) return; const prepare = () => ensureSelectedAgentHarnessPlugin({ config: params.selection.cfg, provider: candidate.provider, modelId: candidate.model, agentId: params.identity.agentId, sessionKey: params.harness.sessionKey, agentHarnessId: candidate.agentHarnessRuntimeOverride, agentHarnessRuntimeOverride: candidate.agentHarnessRuntimeOverride, workspaceDir: params.harness.workspaceDir, pluginRegistry: requireActivePluginRegistry() }); if (params.harness.preparation.kind === "measured") await params.harness.preparation.run(prepare); else await prepare(); preparedHarnessRuntimes.add(key); }; const canFallbackAfterError = committedSideEffect ? () => !committedSideEffect() : readChannelDeliveryEvidence ? () => { const evidence = readChannelDeliveryEvidence(); return !evidence.hasDirectlySentBlockReply && !evidence.hasBlockReplyPipelineOutput; } : void 0; try { const fallbackResult = await runWithModelFallback({ ...params.selection, ...params.identity, abortSignal: params.abortSignal, resolveAgentHarnessRuntimeOverride: params.harness.resolveRuntimeOverride, prepareCandidateChain: async (candidates) => { for (const candidate of candidates) try { const agentHarnessRuntimeOverride = params.harness.resolveRuntimeOverride(candidate.provider, candidate.model); await prepareHarnessRuntime({ provider: candidate.provider, model: candidate.model, ...agentHarnessRuntimeOverride ? { agentHarnessRuntimeOverride } : {} }); const host = params.harness.resolveContextEngineHost?.(candidate.provider, candidate.model) ?? (() => { const harness = selectAgentHarness({ provider: candidate.provider, modelId: candidate.model, config: params.selection.cfg, agentId: params.identity.agentId, sessionKey: params.harness.sessionKey, agentHarnessRuntimeOverride }); return { id: `agent-harness:${harness.id}`, label: `agent harness "${harness.id}"`, capabilities: harness.contextEngineHostCapabilities ?? [] }; })(); contextEngineLogicalTurnLease.selectForHost({ host, operation: "agent-run", requiresDurableCommit: false }); } catch { contextEngineLogicalTurnLease.degradeBeforeStart("a model fallback candidate harness could not be validated before dispatch"); return; } }, prepareAgentHarnessRuntime: prepareHarnessRuntime, onFallbackStep: params.onFallbackStep, ...params.behavior.kind === "maintenance" ? {} : { classifyResult: ({ result }) => result.classification }, ...canFallbackAfterError ? { canFallbackAfterError } : {}, ...params.behavior.kind === "maintenance" ? {} : { mergeExhaustedResult: ({ latestResult, preferredResult }) => ({ result: mergeEmbeddedAgentRunResultForModelFallbackExhaustion({ latestResult: latestResult.result, preferredResult: preferredResult.result }), turnAttempt: latestResult.turnAttempt }) }, run: async (provider, model, options) => { if (!options) throw new Error("Model fallback attempt is missing routing provenance"); const isFallbackRetry = candidateIndex > 0; candidateIndex += 1; let contextEngineTurnCandidate; let classified; const classifyResult = (result) => { if (!classified || classified.result !== result) { const classification = params.behavior.kind === "maintenance" ? void 0 : classifyEmbeddedAgentRunResultForModelFallback({ result, provider, model, ...readChannelDeliveryEvidence?.() }); const effectiveClassification = params.behavior.kind === "followup-delivery" ? preserveFollowupResultForDelivery(classification) : classification; classified = { result, value: effectiveClassification && committedSideEffect?.() ? void 0 : effectiveClassification }; } return classified.value; }; const result = await params.runCandidate(provider, model, { classifyResult, allowTransientCooldownProbe: options?.allowTransientCooldownProbe, isFinalFallbackAttempt: options?.isFinalFallbackAttempt, isFallbackRetry, modelRoutingProvenance: options.modelRoutingProvenance, contextEngineLogicalTurnLease, onContextEngineTurnCandidate: (facts) => { contextEngineTurnCandidate = facts; unsettledContextEngineTurnAttempt = facts; } }); return { result, classification: classifyResult(result), turnAttempt: contextEngineTurnCandidate }; } }); const abortFields = params.behavior.kind === "command-rpc" ? resolveAgentRunAbortLifecycleFields(params.abortSignal) : {}; const candidateResult = abortFields.aborted === true ? { ...fallbackResult.result.result, meta: { ...fallbackResult.result.result.meta, ...abortFields } } : fallbackResult.result.result; const outcome = fallbackResult.outcome === "exhausted" ? "exhausted" : "completed"; const terminalOutcome = resolveTerminalOutcome({ result: candidateResult, fallbackExhausted: outcome === "exhausted" }); const result = mergeRunEntryExecutionTrace({ result: candidateResult, terminalStatus: terminalOutcome.status, provider: fallbackResult.provider, model: fallbackResult.model, requestedProvider: params.selection.provider, requestedModel: params.selection.model, fallbackAttempts: fallbackResult.attempts }); const settledResult = { ...fallbackResult, outcome, result }; const terminal = buildTerminal({ result, outcome: terminalOutcome, behavior: params.behavior, runId: params.identity.runId, requested: { provider: params.selection.provider, model: params.selection.model }, sessionId: params.identity.sessionId }); const acceptedTerminal = !params.abortSignal?.aborted && canAdvanceContextEngineTurn({ result, fallbackOutcome: settledResult.outcome, terminal }); let releaseAcceptedTerminalWork; if (acceptedTerminal) { const acceptedTerminalWork = await params.onAcceptedTerminal?.(); if (typeof acceptedTerminalWork === "function") releaseAcceptedTerminalWork = acceptedTerminalWork; } try { if (fallbackResult.result.turnAttempt) { if (acceptedTerminal) await finalizeAcceptedContextEngineTurn({ facts: fallbackResult.result.turnAttempt, lease: contextEngineLogicalTurnLease }); else discardContextEngineTurnAttemptIntent({ facts: fallbackResult.result.turnAttempt, lease: contextEngineLogicalTurnLease }); unsettledContextEngineTurnAttempt = void 0; } } finally { releaseAcceptedTerminalWork?.(); } let sessionOverrideSettled = false; const settleSessionOverride = async () => { if (sessionOverrideSettled) return; sessionOverrideSettled = true; if (settledResult.outcome === "completed" && params.sessionOverride.kind === "reconcile-completed") await params.sessionOverride.reconcile({ provider: settledResult.provider, model: settledResult.model }); }; return { ...settledResult, terminal, settleSessionOverride }; } finally { if (unsettledContextEngineTurnAttempt) discardContextEngineTurnAttemptIntent({ facts: unsettledContextEngineTurnAttempt, lease: contextEngineLogicalTurnLease }); await contextEngineLogicalTurnLease.dispose(); } } //#endregion //#region src/auto-reply/reply/agent-runner-compaction-accounting.ts function hasSameCompactionWriter(previous, current) { return previous !== void 0 && previous.agentId === current.agentId && previous.sessionKey === current.sessionKey && previous.storePath === current.storePath && previous.lifecycleRevision === current.lifecycleRevision && previous.activeWriterRunId === current.activeWriterRunId; } /** A later opaque candidate may lose freshness, but must never fabricate it. */ function invalidateTurnCompactionContext(compaction) { compaction.durable = compaction.durable.map((fact) => ({ ...fact, currentContextSnapshot: { tokens: void 0 } })); } /** Fold same-writer facts; only an ordered snapshot may refresh context. */ function recordTurnCompaction(compaction, fact) { if (fact.count < 0) return; compaction.count += fact.count; if (fact.kind !== "durable") return; const index = compaction.durable.findIndex(({ target }) => hasSameCompactionWriter(target, fact.target)); const previous = compaction.durable[index]; if (!previous && fact.count === 0) return; if (previous) compaction.durable.splice(index, 1); compaction.durable.push({ ...fact, count: (previous?.count ?? 0) + fact.count, currentContextSnapshot: fact.currentContextSnapshot ?? previous?.currentContextSnapshot }); } //#endregion export { runEmbeddedAgentEntry as i, invalidateTurnCompactionContext as n, recordTurnCompaction as r, hasSameCompactionWriter as t };