UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

564 lines (563 loc) • 27.4 kB
import { s as normalizeNullableString } from "./string-coerce-1VuiLaaR.mjs"; import { s as asFiniteNumber } from "./number-coercion-CkhMiRw8.mjs"; import { l as resolveAgentIdFromSessionKey } from "./session-key-DY3MOX4N.mjs"; import { r as classifyToolUseResultPairing } from "./tool-result-pairing--BK1RaBE.mjs"; import "./defaults-Jag53zwP.mjs"; import { a as IMAGE_BLOCK_TOKENS, c as calculateContextTokens, p as estimateTokens } from "./agent-core-D7okjbP7.mjs"; import { _ as stripRuntimeContextCustomMessages } from "./internal-runtime-context-D5iQhnLo.mjs"; import { c as resolveContextEngineTranscriptByteLimit } from "./registry-BSFHwbcu.mjs"; import { b as runWithPreparedRunSourceScope } from "./admitted-run-context-D0yzk2io.mjs"; import { x as runWithPreparedMemoryPromptSection } from "./memory-state-YBTzZa6s.mjs"; import { i as runWithSessionTranscriptReadFence } from "./session-transcript-read-fence-DqVaDIch.mjs"; import { n as prepareSessionTranscriptHydration } from "./session-transcript-hydration-ClYSEJcc.mjs"; import { n as OPENCLAW_EMBEDDED_CONTEXT_ENGINE_HOST } from "./host-compat-DWLjZN89.mjs"; import { i as sanitizeToolUseResultPairingForModel } from "./session-transcript-repair-BkR36ZME.mjs"; import { F as estimateToolSchemaTokens, I as SAFETY_MARGIN, M as estimateMessageTokenPressure, N as estimateRenderedPromptTokens, P as estimateStringTokenPressure, j as estimateJsonPayloadTokenPressure } from "./settings-manager-2KjnbEXR.mjs"; import { t as estimateToolResultReductionPotential } from "./tool-result-truncation-CgpKdRPP.mjs"; import { t as resolveEffectiveCompactionReserveTokens } from "./agent-compaction-constants-DmXQuPyL.mjs"; import { t as runContextEngineMaintenance } from "./context-engine-maintenance-lAvtCTBg.mjs"; import { r as completedTurnMessageAnchor } from "./session-manager-BpvVpTVC.mjs"; import { createHash } from "node:crypto"; import { prependSystemPromptAdditionAfterCacheBoundary } from "@openclaw/ai/internal/shared"; import { resolveCompactionReplayPressure } from "@openclaw/ai/transports"; //#region src/context-engine/runtime-settings.ts const RUNTIME_REASON_PATTERNS = [ ["provider_timeout", /timeout/iu], ["rate_limited", /rate|limit|429/iu], ["context_overflow", /overflow|context|pressure/iu], ["runtime_unavailable", /runtime/iu], ["provider_unavailable", /provider|primary|unavailable/iu] ]; function normalizeReasonCode(value) { const normalized = normalizeNullableString(value); if (!normalized) return null; return RUNTIME_REASON_PATTERNS.find(([, pattern]) => pattern.test(normalized))?.[0] ?? "unknown"; } function buildContextEngineRuntimeSettings(params) { const hostId = normalizeNullableString(params.contextEngineHost.id); const selectedId = normalizeNullableString(params.selectedContextEngineId); const selectionSource = params.contextEngineSelectionSource ?? (selectedId ? "configured" : "unknown"); const requestedModel = normalizeNullableString(params.requestedModel); const resolvedModel = normalizeNullableString(params.resolvedModel); const fallbackReason = normalizeReasonCode(params.fallbackReason); const degradedReason = normalizeReasonCode(params.degradedReason); const resolvedViaFallback = requestedModel !== null && resolvedModel !== null && requestedModel !== resolvedModel; return { schemaVersion: 1, runtime: { host: "openclaw", mode: params.mode ?? (degradedReason ? "degraded" : fallbackReason || resolvedViaFallback ? "fallback" : "normal"), harnessId: normalizeNullableString(params.harnessId), runtimeId: normalizeNullableString(params.runtimeId) }, model: { requested: requestedModel, resolved: resolvedModel, provider: normalizeNullableString(params.provider), family: normalizeNullableString(params.modelFamily) }, contextEngineSelection: { selectedId, source: selectionSource }, executionHost: { id: hostId, label: normalizeNullableString(params.contextEngineHost.label) }, limits: { promptTokenBudget: asFiniteNumber(params.promptTokenBudget) ?? null, maxOutputTokens: asFiniteNumber(params.maxOutputTokens) ?? null }, diagnostics: { fallbackReason, degradedReason } }; } //#endregion //#region src/agents/embedded-agent-runner/run/preemptive-compaction.ts const PREEMPTIVE_OVERFLOW_ERROR_TEXT = "Context overflow: prompt too large for the model (precheck)."; const TRUNCATION_ROUTE_BUFFER_TOKENS = 512; function isProviderContextUsageBarrier(message) { if (message.role !== "assistant" || !message.usage) return false; return message.api === "cli" && message.usage.contextUsage === void 0 || message.usage.contextUsage?.state === "unavailable" && calculateContextTokens(message.usage) === 0; } function resolveProviderContextBoundary(messages) { for (let index = messages.length - 1; index >= 0; index -= 1) { const message = messages[index]; if (message && isProviderContextUsageBarrier(message)) return; const contextUsage = message?.role === "assistant" ? message.usage?.contextUsage : void 0; if (contextUsage?.state === "available" && Number.isFinite(contextUsage.totalTokens) && contextUsage.totalTokens > 0) return { index, totalTokens: Math.ceil(contextUsage.totalTokens) }; } } function estimateToolSchemaTokenPressure(tools) { return Math.ceil(estimateToolSchemaTokens(tools) * SAFETY_MARGIN); } function estimateTranscriptBoundaryTokenPressure(params) { const replay = params.replay ? resolveCompactionReplayPressure(params.messages, params.replay.model, params.replay, { text: estimateStringTokenPressure, image: () => IMAGE_BLOCK_TOKENS, json: estimateJsonPayloadTokenPressure, toolResult: (value) => estimateStringTokenPressure(value, 4, "tool-result") }, params.systemPrompt) : void 0; const messages = replay?.messages ?? params.messages; const boundary = resolveProviderContextBoundary(messages); const measuredTokens = replay?.measuredTokens ?? boundary?.totalTokens; const locallyEstimatedTokens = (boundary ? messages.slice(boundary.index + 1) : messages).reduce((sum, message) => sum + estimateMessageTokenPressure(message), estimateRenderedPromptTokens(params) + (boundary ? 0 : (replay?.prefixTokens ?? 0) - (replay?.measuredTokens ?? 0))); const toolSchemaTokens = Math.max(0, params.toolSchemaTokens ?? 0); return { estimatedPromptTokens: (measuredTokens ?? 0) + Math.ceil(locallyEstimatedTokens * SAFETY_MARGIN) + (boundary && !replay ? 0 : toolSchemaTokens), source: measuredTokens !== void 0 ? "provider_context_usage" : replay ? "provider_compaction_estimate" : "transcript_estimate", messages, hasCompactionReplay: Boolean(replay) }; } function estimateLlmBoundaryTokenPressure(params) { return estimateTranscriptBoundaryTokenPressure(params).estimatedPromptTokens; } /** Estimates only the rendered prompt/system portion when history has already been accounted for. */ function estimateRenderedLlmBoundaryTokenPressure(params) { return Math.max(0, Math.ceil(estimateRenderedPromptTokens(params) * SAFETY_MARGIN)); } function normalizeLlmBoundaryTokenPressure(pressure) { if (!pressure || !Number.isFinite(pressure.estimatedPromptTokens)) return; return { estimatedPromptTokens: Math.max(0, Math.ceil(pressure.estimatedPromptTokens)), source: pressure.source.trim() || "rendered_llm_boundary" }; } /** * Decides whether a run should compact before submitting the prompt, and * whether reducible tool results can avoid or follow compaction. Rendered LLM * boundary pressure wins over local transcript estimates when supplied. */ function shouldPreemptivelyCompactBeforePrompt(params) { const llmBoundaryTokenPressure = normalizeLlmBoundaryTokenPressure(params.llmBoundaryTokenPressure); const estimateTranscriptPressure = (messages, replay) => estimateTranscriptBoundaryTokenPressure({ messages, systemPrompt: params.systemPrompt, prompt: params.prompt, replay, ...typeof params.toolSchemaTokens === "number" ? { toolSchemaTokens: params.toolSchemaTokens } : {} }); const transcriptTokenPressure = llmBoundaryTokenPressure && !params.replay ? void 0 : estimateTranscriptPressure(params.messages, params.replay); const boundaryPressure = transcriptTokenPressure?.hasCompactionReplay ? void 0 : llmBoundaryTokenPressure; const outgoingDecision = resolveCompactionPressureDecision({ messages: transcriptTokenPressure?.messages ?? params.messages, estimatedPromptTokens: boundaryPressure?.estimatedPromptTokens ?? transcriptTokenPressure?.estimatedPromptTokens ?? 0, source: boundaryPressure?.source ?? transcriptTokenPressure?.source ?? "transcript_estimate" }, params); let diagnosticDecision = outgoingDecision; if (params.unwindowedMessages && params.unwindowedMessages !== params.messages) { const unwindowedTokenPressure = estimateTranscriptPressure(params.unwindowedMessages); if (unwindowedTokenPressure.estimatedPromptTokens > outgoingDecision.estimatedPromptTokens) diagnosticDecision = resolveCompactionPressureDecision({ ...unwindowedTokenPressure, source: `unwindowed_${unwindowedTokenPressure.source}` }, params); } return { ...diagnosticDecision, ...transcriptTokenPressure?.hasCompactionReplay ? { compactionReplay: outgoingDecision } : {} }; } function resolveCompactionPressureDecision(pressure, params) { const { estimatedPromptTokens } = pressure; const contextTokenBudget = Math.max(1, Math.floor(params.contextTokenBudget)); const effectiveReserveTokens = resolveEffectiveCompactionReserveTokens({ contextTokenBudget, reserveTokens: params.reserveTokens }); const promptBudgetBeforeReserve = Math.max(1, contextTokenBudget - effectiveReserveTokens); const overflowTokens = Math.max(0, estimatedPromptTokens - promptBudgetBeforeReserve); const toolResultPotential = estimateToolResultReductionPotential({ messages: pressure.messages, contextWindowTokens: params.contextTokenBudget, maxCharsOverride: params.toolResultMaxChars }); const overflowChars = overflowTokens * 4; const truncateOnlyThresholdChars = Math.max(overflowChars + TRUNCATION_ROUTE_BUFFER_TOKENS * 4, Math.ceil(overflowChars * 1.5)); const toolResultReducibleChars = toolResultPotential.maxReducibleChars; const route = overflowTokens > 0 ? toolResultReducibleChars <= 0 ? "compact_only" : toolResultReducibleChars >= truncateOnlyThresholdChars ? "truncate_tool_results_only" : "compact_then_truncate" : "fits"; return { route, shouldCompact: route === "compact_only" || route === "compact_then_truncate", estimatedPromptTokens, pressureSource: pressure.source, promptBudgetBeforeReserve, overflowTokens, toolResultReducibleChars, effectiveReserveTokens }; } function formatPrePromptPrecheckLog(params) { const { result } = params; return `[context-overflow-precheck] pre-prompt check sessionKey=${params.sessionKey ?? params.sessionId ?? "unknown"} provider=${params.provider}/${params.modelId} route=${result.route} estimatedPromptTokens=${result.estimatedPromptTokens} pressureSource=${result.pressureSource ?? "unknown"} promptBudgetBeforeReserve=${result.promptBudgetBeforeReserve} overflowTokens=${result.overflowTokens} toolResultReducibleChars=${result.toolResultReducibleChars} reserveTokens=${params.reserveTokens} effectiveReserveTokens=${result.effectiveReserveTokens} contextTokenBudget=${params.contextTokenBudget} messages=${params.messageCount} unwindowedMessages=${params.unwindowedMessageCount ?? params.messageCount} sessionFile=${params.sessionFile}`; } function buildPrePromptContextBudgetStatus(params) { const { result } = params; const remainingPromptBudgetTokens = Math.max(0, result.promptBudgetBeforeReserve - result.estimatedPromptTokens); return { schemaVersion: 1, source: "pre-prompt-estimate", updatedAt: params.now ?? Date.now(), provider: params.provider, model: params.modelId, route: result.route, shouldCompact: result.shouldCompact, estimatedPromptTokens: result.estimatedPromptTokens, contextTokenBudget: Math.max(1, Math.floor(params.contextTokenBudget)), promptBudgetBeforeReserve: result.promptBudgetBeforeReserve, reserveTokens: Math.max(0, Math.floor(params.reserveTokens)), effectiveReserveTokens: result.effectiveReserveTokens, remainingPromptBudgetTokens, overflowTokens: result.overflowTokens, toolResultReducibleChars: result.toolResultReducibleChars, messageCount: Math.max(0, Math.floor(params.messageCount)), unwindowedMessageCount: Math.max(0, Math.floor(params.unwindowedMessageCount ?? params.messageCount)), ...params.sessionId ? { sessionId: params.sessionId } : {} }; } //#endregion //#region src/context-engine/bounded-context.ts /** Bounds only the model view; required instructions and the pending input stay with their owners. */ function boundContextEngineAssembly(assembled, maxBytes, tokenBudget) { if (maxBytes === void 0) return assembled; const { messages } = assembled; let bytes = 2; let tokens = 0; let cut = messages.length; let exceedsByteBudget = false; for (let index = messages.length - 1; index >= 0; index--) { const message = messages[index]; bytes += Buffer.byteLength(JSON.stringify(message), "utf8") + 1; tokens += estimateTokens(message); if (bytes > maxBytes) { exceedsByteBudget = true; break; } if (tokenBudget !== void 0 && tokens > tokenBudget) continue; if (index === 0 || message.role === "user") cut = index; } if (!exceedsByteBudget) return assembled; for (const frame of classifyToolUseResultPairing(messages).frames) { if (frame.startIndex >= cut) break; for (const occurrence of frame.occurrences) if (occurrence.sourceResultIndex !== void 0 && occurrence.sourceResultIndex >= cut) { cut = occurrence.sourceResultIndex + 1; while (cut < messages.length && messages[cut]?.role !== "user") cut++; } } const retained = messages.slice(cut); const fingerprint = createHash("sha256").update(JSON.stringify([ assembled.contextProjection, maxBytes, messages[cut - 1], retained, assembled.systemPromptAddition ])).digest("hex"); return { ...assembled, messages: retained, estimatedTokens: retained.reduce((sum, message) => sum + estimateTokens(message), 0), promptAuthority: "assembled", contextProjection: { mode: "thread_bootstrap", epoch: `bounded:${fingerprint}`, fingerprint } }; } //#endregion //#region src/agents/harness/context-engine-lifecycle.ts function preparePreTurnRuntimeContext(runtimeContext) { if (!runtimeContext?.rewriteTranscriptEntries) return runtimeContext; const { rewriteTranscriptEntries: _rewriteTranscriptEntries, ...fenced } = runtimeContext; return fenced; } function runWithHarnessSourceFence(params, run) { return runWithSessionTranscriptReadFence(params.transcriptReadFence, () => runWithPreparedRunSourceScope(params, run)); } function buildHarnessContextEngineRuntimeSettings(params) { if (params.runtimeSettings !== void 0 && params.runtimeSettings !== null) return params.runtimeSettings; const selectedId = params.contextEngine?.info.id; return buildContextEngineRuntimeSettings({ contextEngineHost: params.contextEngineHostSupport ?? OPENCLAW_EMBEDDED_CONTEXT_ENGINE_HOST, harnessId: params.harnessId, runtimeId: params.runtimeId, provider: params.providerId, requestedModel: params.requestedModelId, resolvedModel: params.modelId ?? params.requestedModelId, modelFamily: params.modelFamily ?? null, selectedContextEngineId: selectedId, contextEngineSelectionSource: selectedId === "legacy" ? "default" : selectedId ? "configured" : "unknown", promptTokenBudget: params.tokenBudget, maxOutputTokens: params.maxOutputTokens, fallbackReason: params.fallbackReason, degradedReason: params.degradedReason }); } async function bootstrapHarnessContextEngine(params) { if (!params.hadSessionFile || !(params.contextEngine?.bootstrap || params.contextEngine?.maintain)) return; await runWithHarnessSourceFence(params, async () => { try { const runtimeSettings = buildHarnessContextEngineRuntimeSettings(params); const runtimeContext = preparePreTurnRuntimeContext(params.runtimeContext); if (typeof params.contextEngine?.bootstrap === "function") await params.contextEngine.bootstrap({ sessionId: params.sessionId, sessionKey: params.sessionKey, sessionTarget: params.sessionTarget, sessionFile: params.sessionFile, runtimeSettings, runtimeContext }); await (params.runMaintenance ?? runHarnessContextEngineMaintenance)({ contextEngine: params.contextEngine, sessionId: params.sessionId, sessionKey: params.sessionKey, sessionTarget: params.sessionTarget, sessionFile: params.sessionFile, reason: "bootstrap", sessionManager: params.sessionManager, runtimeContext, runtimeSettings, config: params.config }); } catch (bootstrapErr) { params.warn(`context engine bootstrap failed: ${String(bootstrapErr)}`); } }); } async function assembleHarnessContextEngine(params) { if (!params.contextEngine) return; return runWithHarnessSourceFence(params, () => assembleHarnessContextEngineWithinSourceScope(params)); } function resolveAssemblyHistoryTokenBudget(params) { if (!params.promptBudget) return params.tokenBudget; const { contextTokens, reserveTokens, systemPrompt, prompt } = params.promptBudget; return Math.max(1, Math.max(1, Math.max(1, Math.floor(contextTokens ?? 2e5)) - Math.max(0, Math.floor(reserveTokens))) - estimateRenderedLlmBoundaryTokenPressure({ systemPrompt, prompt })); } async function assembleHarnessContextEngineWithinSourceScope(params) { if (!params.contextEngine) return; const contextEngine = params.contextEngine; const tokenBudget = resolveAssemblyHistoryTokenBudget(params); const maxOutputTokens = params.promptBudget ? Math.max(0, Math.floor(params.promptBudget.reserveTokens)) : params.maxOutputTokens; const messages = (params.appendOnlyRuntimeContext ? params.messages : stripRuntimeContextCustomMessages(params.messages)).slice(); const runtimeSettings = buildHarnessContextEngineRuntimeSettings({ ...params, maxOutputTokens, tokenBudget }); const runtimeContext = preparePreTurnRuntimeContext(params.runtimeContext); const assemble = () => contextEngine.assemble({ sessionId: params.sessionId, sessionKey: params.sessionKey, messages, tokenBudget, ...params.availableTools ? { availableTools: params.availableTools } : {}, ...params.citationsMode ? { citationsMode: params.citationsMode } : {}, model: params.modelId, runtimeSettings, runtimeContext, ...params.prompt !== void 0 ? { prompt: params.prompt } : {} }); return boundContextEngineAssembly(ensureAssembleResultShape(contextEngine.info.id === "legacy" ? await assemble() : await runWithPreparedMemoryPromptSection({ availableTools: params.availableTools ?? /* @__PURE__ */ new Set(), citationsMode: params.citationsMode, agentId: params.agentId ?? resolveAgentIdFromSessionKey(params.sessionKey), agentSessionKey: params.sessionKey, sandboxed: params.sandboxed }, assemble), contextEngine.info.id), resolveContextEngineTranscriptByteLimit(contextEngine), tokenBudget); } async function prepareHarnessContextEnginePrompt(params) { const initial = { messages: params.messages, systemPrompt: params.promptBudget.systemPrompt, contextEnginePromptAuthority: "assembled", contextEngineAssemblySucceeded: false }; if (!params.contextEngine) return initial; return runWithHarnessSourceFence(params, async () => { try { const preassemblyMessages = params.messages.slice(); const assembled = await assembleHarnessContextEngineWithinSourceScope(params); if (!assembled) throw new Error("context engine assemble returned no result"); const authority = assembled.promptAuthority ?? "assembled"; return { messages: params.repairToolUseResultPairing ? sanitizeToolUseResultPairingForModel(assembled.messages, params.isOpenAIResponsesApi) : assembled.messages, systemPrompt: assembled.systemPromptAddition ? prependSystemPromptAdditionAfterCacheBoundary({ systemPrompt: initial.systemPrompt, systemPromptAddition: assembled.systemPromptAddition }) : initial.systemPrompt, contextEnginePromptAuthority: authority, contextEngineAssemblySucceeded: true, ...authority === "preassembly_may_overflow" ? { unwindowedContextEngineMessagesForPrecheck: preassemblyMessages } : {} }; } catch (error) { params.warn(`context engine assemble failed, using pipeline messages: ${String(error)}`); return { ...initial, messages: boundContextEngineAssembly({ messages: initial.messages, estimatedTokens: 0 }, resolveContextEngineTranscriptByteLimit(params.contextEngine), resolveAssemblyHistoryTokenBudget(params)).messages }; } }); } /** Invalid plugin results must fail here so the runner can fall back without poisoning state. */ function ensureAssembleResultShape(result, engineId) { if (!result || typeof result !== "object") throw new Error(`context engine "${engineId}" assemble() returned an invalid result: expected an object with a "messages" array (got ${describeAssembleResultType(result)})`); const candidate = result; if (!Array.isArray(candidate.messages)) throw new Error(`context engine "${engineId}" assemble() returned an invalid result: expected an object with a "messages" array (got messages of type ${describeAssembleResultType(candidate.messages)})`); return result; } function describeAssembleResultType(value) { if (value === null) return "null"; if (Array.isArray(value)) return "array"; return typeof value; } async function finalizeHarnessContextEngineTurn(params) { if (!params.contextEngine || params.promptError || params.aborted || params.yieldAborted) return { postTurnFinalizationSucceeded: true }; if (params.turnCandidate) { const { admission, terminalEntryId, record } = params.turnCandidate; if (admission && terminalEntryId) { const committed = params.turnCandidate[completedTurnMessageAnchor]; let terminal = committed?.anchor; if (!committed) { const { waitForSessionTranscriptProjection } = await import("./config/sessions/session-transcript-reconcile.js"); await waitForSessionTranscriptProjection(admission, params.abortSignal); params.abortSignal?.throwIfAborted(); const reader = prepareSessionTranscriptHydration(admission, void 0, params.abortSignal); const { version } = await reader.readMaintenance({ operation: "version" }); terminal = version ? (await reader.readCurrentTurnEntry({ entryId: terminalEntryId, version, includeEntry: false })).anchor : void 0; reader.assertCurrent(); params.abortSignal?.throwIfAborted(); } committed?.assertCurrent(); if (terminal) record({ boundary: { admission, terminal }, sessionIdUsed: params.sessionIdUsed, sessionKey: params.sessionKey, sessionTarget: params.sessionTarget, promptError: params.promptError, aborted: params.aborted, yieldAborted: params.yieldAborted, isHeartbeat: params.isHeartbeat, runtimeContext: { provider: params.providerId ?? void 0, modelId: params.modelId ?? void 0, modelContextWindow: params.modelContextWindow, tokenBudget: params.tokenBudget ?? void 0 } }); } return { postTurnFinalizationSucceeded: true }; } const conversationSnapshot = buildContextEngineConversationSnapshot({ messagesSnapshot: params.messagesSnapshot, prePromptMessageCount: params.prePromptMessageCount }); const runtimeSettings = buildHarnessContextEngineRuntimeSettings(params); const runtimeContext = params.runtimeContext; let postTurnFinalizationSucceeded = true; if (typeof params.contextEngine.afterTurn === "function") try { await params.contextEngine.afterTurn({ sessionId: params.sessionIdUsed, sessionKey: params.sessionKey, sessionTarget: params.sessionTarget, sessionFile: params.sessionFile, messages: conversationSnapshot.messages, prePromptMessageCount: conversationSnapshot.prePromptMessageCount, tokenBudget: params.tokenBudget, runtimeSettings, runtimeContext, isHeartbeat: params.isHeartbeat }); } catch (afterTurnErr) { postTurnFinalizationSucceeded = false; params.warn(`context engine afterTurn failed: ${String(afterTurnErr)}`); } else { const newMessages = conversationSnapshot.messages.slice(conversationSnapshot.prePromptMessageCount); if (newMessages.length > 0) { if (typeof params.contextEngine.ingestBatch === "function") try { await params.contextEngine.ingestBatch({ sessionId: params.sessionIdUsed, sessionKey: params.sessionKey, messages: newMessages, isHeartbeat: params.isHeartbeat }); } catch (ingestErr) { postTurnFinalizationSucceeded = false; params.warn(`context engine ingest failed: ${String(ingestErr)}`); } else for (const msg of newMessages) try { await params.contextEngine.ingest?.({ sessionId: params.sessionIdUsed, sessionKey: params.sessionKey, message: msg, isHeartbeat: params.isHeartbeat }); } catch (ingestErr) { postTurnFinalizationSucceeded = false; params.warn(`context engine ingest failed: ${String(ingestErr)}`); } } } if (postTurnFinalizationSucceeded) await (params.runMaintenance ?? runHarnessContextEngineMaintenance)({ contextEngine: params.contextEngine, sessionId: params.sessionIdUsed, sessionKey: params.sessionKey, sessionTarget: params.sessionTarget, sessionFile: params.sessionFile, reason: "turn", sessionManager: params.sessionManager, runtimeContext, runtimeSettings, config: params.config }); return { postTurnFinalizationSucceeded }; } function buildContextEngineConversationSnapshot(params) { const prePromptMessages = stripRuntimeContextCustomMessages(params.messagesSnapshot.slice(0, params.prePromptMessageCount)); const turnMessages = stripRuntimeContextCustomMessages(params.messagesSnapshot.slice(params.prePromptMessageCount)); return { messages: [...prePromptMessages, ...turnMessages], prePromptMessageCount: prePromptMessages.length }; } async function runHarnessContextEngineMaintenance(params) { const runtimeSettings = buildHarnessContextEngineRuntimeSettings(params); return await runContextEngineMaintenance({ contextEngine: params.contextEngine, sessionId: params.sessionId, sessionKey: params.sessionKey, sessionTarget: params.sessionTarget, sessionFile: params.sessionFile, reason: params.reason, sessionManager: params.sessionManager, withSessionManagerRewriteLock: params.withSessionManagerRewriteLock, runtimeContext: params.runtimeContext, runtimeSettings, executionMode: params.executionMode, onDeferredMaintenance: params.onDeferredMaintenance, config: params.config }); } function isActiveHarnessContextEngine(contextEngine) { return Boolean(contextEngine && contextEngine.info.id !== "legacy"); } //#endregion export { prepareHarnessContextEnginePrompt as a, buildPrePromptContextBudgetStatus as c, estimateToolSchemaTokenPressure as d, formatPrePromptPrecheckLog as f, isActiveHarnessContextEngine as i, estimateLlmBoundaryTokenPressure as l, buildContextEngineRuntimeSettings as m, bootstrapHarnessContextEngine as n, runHarnessContextEngineMaintenance as o, shouldPreemptivelyCompactBeforePrompt as p, finalizeHarnessContextEngineTurn as r, PREEMPTIVE_OVERFLOW_ERROR_TEXT as s, assembleHarnessContextEngine as t, estimateRenderedLlmBoundaryTokenPressure as u };