UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

408 lines (407 loc) 17.8 kB
import { t as createSubsystemLogger } from "./subsystem-BzXSmsuh.js"; import { a as normalizeOptionalAgentRuntimeId } from "./agent-runtime-id-DiL2DId7.js"; import { o as resolveContextEngine } from "./registry-Dca-zXEr.js"; import { t as SessionManager } from "./session-manager-_IGt1AS6.js"; import { i as resolveCliBackendConfig } from "./cli-backends-CcaQo9wE.js"; import { J as createPreparedEmbeddedAgentSettingsManager } from "./compaction-successor-transcript-ONv2lneO.js"; import { a as resolveEffectiveCompactionMode, n as applyAgentAutoCompactionGuard } from "./agent-settings-Btt05WNB.js"; import { t as ensureContextEnginesInitialized } from "./init-CJMy1vMZ.js"; import { t as buildEmbeddedCompactionRuntimeContext } from "./compaction-runtime-context-DTO0IG8s.js"; import { a as resolveLiveToolResultMaxChars } from "./tool-result-truncation-BiAgZIVd.js"; import { c as resolveCompactionTimeoutMs, o as compactContextEngineWithSafetyTimeout, s as compactWithSafetyTimeout } from "./tool-result-middleware-B3Hdp_cV.js"; import { c as runContextEngineMaintenance } from "./context-engine-lifecycle-CVy46YJP.js"; import { c as shouldPreemptivelyCompactBeforePrompt } from "./attempt.tool-run-context-CJUiBo7z.js"; import { n as isRecoverableNativeHarnessBindingFailure, t as maybeCompactAgentHarnessSession } from "./compaction-CkgVnI5n.js"; import { t as ensureSelectedAgentHarnessPlugin } from "./runtime-plugin-CzEDIZOU.js"; import { n as classifyCompactionReason } from "./compact-reasons-DWsY2uIR.js"; import { n as recordCliCompactionInStore, t as clearCliSessionInStore } from "./session-store-D7_qqNTY.js"; //#region src/agents/command/cli-compaction.ts const CODEX_APP_SERVER_OWNS_AUTO_COMPACTION_REASON = "codex app-server owns automatic compaction"; const log = createSubsystemLogger("agents/cli-compaction"); const cliCompactionDeps = { openSessionManager: (sessionFile) => SessionManager.open(sessionFile), ensureContextEnginesInitialized, resolveContextEngine, createPreparedEmbeddedAgentSettingsManager, applyAgentAutoCompactionGuard, shouldPreemptivelyCompactBeforePrompt, resolveLiveToolResultMaxChars, runContextEngineMaintenance, ensureSelectedAgentHarnessPlugin, maybeCompactAgentHarnessSession, clearCliSessionInStore, resolveCliBackendConfig, recordCliCompactionInStore }; /** Overrides CLI compaction dependencies for focused tests. */ function setCliCompactionTestDeps(overrides) { Object.assign(cliCompactionDeps, overrides); } /** Restores production CLI compaction dependencies after tests. */ function resetCliCompactionTestDeps() { Object.assign(cliCompactionDeps, { openSessionManager: (sessionFile) => SessionManager.open(sessionFile), ensureContextEnginesInitialized, resolveContextEngine, createPreparedEmbeddedAgentSettingsManager, applyAgentAutoCompactionGuard, shouldPreemptivelyCompactBeforePrompt, resolveLiveToolResultMaxChars, runContextEngineMaintenance, ensureSelectedAgentHarnessPlugin, maybeCompactAgentHarnessSession, clearCliSessionInStore, resolveCliBackendConfig, recordCliCompactionInStore }); } function resolvePositiveInteger(value) { if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return; return Math.floor(value); } function getSessionBranchMessages(sessionManager) { return sessionManager.getBranch().flatMap((entry) => entry.type === "message" && typeof entry.message === "object" && entry.message !== null ? [entry.message] : []); } function resolveSessionTokenSnapshot(sessionEntry) { return resolvePositiveInteger(sessionEntry?.totalTokensFresh === false ? void 0 : sessionEntry?.totalTokens); } function isNativeHarnessCompactionSession(sessionEntry, provider) { const harnessId = sessionEntry?.agentHarnessId?.trim().toLowerCase(); if (!harnessId || normalizeOptionalAgentRuntimeId(harnessId) === "openclaw") return false; const providerId = provider.trim().toLowerCase(); return harnessId === providerId || harnessId === "copilot" && providerId === "github-copilot" || harnessId === "codex" && (providerId === "codex" || providerId === "openai"); } function isUnsupportedNativeHarnessCompaction(result) { return result?.ok === false && result.failure?.reason === "unsupported_harness_compaction"; } function isBelowCompactionTargetReason(reason) { return classifyCompactionReason(reason) === "below_threshold"; } function isIntentionalNativeAutoCompactionSkip(result) { return result?.ok === true && !result.compacted && result.reason === CODEX_APP_SERVER_OWNS_AUTO_COMPACTION_REASON; } function readAgentIdFromSessionKey(sessionKey) { const parts = sessionKey.trim().split(":"); return parts[0] === "agent" && parts[1]?.trim() ? parts[1].trim() : void 0; } function buildCliCompactionRuntimeContext(params) { return { ...buildEmbeddedCompactionRuntimeContext({ sessionKey: params.sessionKey, messageChannel: params.messageChannel, messageProvider: params.messageChannel, agentAccountId: params.agentAccountId, authProfileId: params.authProfileId, workspaceDir: params.workspaceDir, cwd: params.cwd, agentDir: params.agentDir, config: params.cfg, skillsSnapshot: params.skillsSnapshot, senderIsOwner: params.senderIsOwner, provider: params.provider, modelId: params.model, thinkLevel: params.thinkLevel, extraSystemPrompt: params.extraSystemPrompt }), currentTokenCount: params.currentTokenCount, tokenBudget: params.contextTokenBudget, trigger: params.trigger }; } async function compactCliTranscript(params) { const runtimeContext = buildCliCompactionRuntimeContext({ sessionKey: params.sessionKey, messageChannel: params.messageChannel, agentAccountId: params.agentAccountId, authProfileId: params.authProfileId, workspaceDir: params.workspaceDir, cwd: params.cwd, agentDir: params.agentDir, cfg: params.cfg, skillsSnapshot: params.skillsSnapshot, senderIsOwner: params.senderIsOwner, provider: params.provider, model: params.model, thinkLevel: params.thinkLevel, extraSystemPrompt: params.extraSystemPrompt, currentTokenCount: params.currentTokenCount, contextTokenBudget: params.contextTokenBudget, trigger: "cli_budget" }); let compactResult; try { compactResult = await compactContextEngineWithSafetyTimeout(params.contextEngine, { sessionId: params.sessionId, sessionKey: params.sessionKey, sessionFile: params.sessionFile, tokenBudget: params.contextTokenBudget, currentTokenCount: params.currentTokenCount, force: true, compactionTarget: "budget", runtimeContext }, resolveCompactionTimeoutMs(params.cfg)); } catch (error) { log.warn(`CLI transcript compaction failed for ${params.provider}/${params.model}: ${error instanceof Error ? error.message : String(error)}`); return { compacted: false, failureReason: error instanceof Error ? error.message : String(error) }; } if (!compactResult.compacted) { const reason = compactResult.reason ?? "nothing to compact"; if (isBelowCompactionTargetReason(reason)) { log.info(`CLI transcript compaction skipped for ${params.provider}/${params.model}: ${reason}`); return { compacted: false }; } log.warn(`CLI transcript compaction did not reduce context for ${params.provider}/${params.model}: ${reason}`); return { compacted: false, failureReason: compactResult.reason ?? "compaction did not reduce context" }; } try { await cliCompactionDeps.runContextEngineMaintenance({ contextEngine: params.contextEngine, sessionId: params.sessionId, sessionKey: params.sessionKey, sessionFile: params.sessionFile, reason: "compaction", sessionManager: params.sessionManager, runtimeContext, config: params.cfg }); } catch (error) { if (!params.bestEffortMaintenance) throw error; log.warn(`CLI transcript compaction maintenance failed after fallback for ${params.provider}/${params.model}: ${error instanceof Error ? error.message : String(error)}`); } return { compacted: true }; } async function compactNativeHarnessCliTranscript(params) { let result; try { const sessionAgentId = readAgentIdFromSessionKey(params.sessionKey); const nativeHarnessId = params.sessionEntry.agentHarnessId?.trim(); const authProfileId = params.sessionEntry.authProfileOverride?.trim() || void 0; await cliCompactionDeps.ensureSelectedAgentHarnessPlugin({ provider: params.provider, modelId: params.model, config: params.cfg, sessionKey: params.sessionKey, workspaceDir: params.workspaceDir, ...sessionAgentId ? { agentId: sessionAgentId } : {}, ...nativeHarnessId ? { agentHarnessRuntimeOverride: nativeHarnessId } : {} }); result = await compactWithSafetyTimeout((abortSignal) => cliCompactionDeps.maybeCompactAgentHarnessSession({ sessionId: params.sessionId, sessionKey: params.sessionKey, sessionFile: params.sessionFile, workspaceDir: params.workspaceDir, cwd: params.cwd, agentDir: params.agentDir, config: params.cfg, skillsSnapshot: params.skillsSnapshot, provider: params.provider, model: params.model, authProfileId, contextTokenBudget: params.contextTokenBudget, currentTokenCount: params.currentTokenCount, trigger: "budget", force: true, messageChannel: params.messageChannel, agentAccountId: params.agentAccountId, senderIsOwner: params.senderIsOwner, thinkLevel: params.thinkLevel, extraSystemPrompt: params.extraSystemPrompt, allowGatewaySubagentBinding: true, ...params.contextEngine ? { contextEngine: params.contextEngine, contextEngineRuntimeContext: buildCliCompactionRuntimeContext({ sessionKey: params.sessionKey, messageChannel: params.messageChannel, agentAccountId: params.agentAccountId, authProfileId, workspaceDir: params.workspaceDir, cwd: params.cwd, agentDir: params.agentDir, cfg: params.cfg, skillsSnapshot: params.skillsSnapshot, senderIsOwner: params.senderIsOwner, provider: params.provider, model: params.model, thinkLevel: params.thinkLevel, extraSystemPrompt: params.extraSystemPrompt, currentTokenCount: params.currentTokenCount, contextTokenBudget: params.contextTokenBudget, trigger: "cli_native_budget" }) } : {}, ...nativeHarnessId ? { agentHarnessId: nativeHarnessId } : {}, ...abortSignal ? { abortSignal } : {} }), resolveCompactionTimeoutMs(params.cfg)); } catch (error) { log.warn(`CLI native harness compaction failed for ${params.provider}/${params.model}: ${error instanceof Error ? error.message : String(error)}`); return { compacted: false, failureReason: error instanceof Error ? error.message : String(error) }; } if (!result?.compacted) { const reason = result?.reason ?? "nothing to compact"; if (isBelowCompactionTargetReason(reason)) { log.info(`CLI native harness compaction skipped for ${params.provider}/${params.model}: ${reason}`); return { compacted: false }; } if (isIntentionalNativeAutoCompactionSkip(result)) return { compacted: false, fallbackToContextEngine: true, failureReason: CODEX_APP_SERVER_OWNS_AUTO_COMPACTION_REASON }; const recoverableBindingFailure = isRecoverableNativeHarnessBindingFailure(result); const fallbackToContextEngine = isUnsupportedNativeHarnessCompaction(result) || recoverableBindingFailure; log.warn(`CLI native harness compaction did not reduce context for ${params.provider}/${params.model}: ${reason}`); return { compacted: false, fallbackToContextEngine, clearCliSessionBinding: recoverableBindingFailure, failureReason: result?.reason ?? "native harness compaction did not reduce context" }; } return { compacted: true, result }; } /** Runs pre-turn compaction for a CLI session and returns the updated session entry. */ async function runCliTurnCompactionLifecycle(params) { const sessionFile = params.sessionEntry?.sessionFile; const contextTokenBudget = resolvePositiveInteger(params.sessionEntry?.contextTokens); if (!sessionFile || !contextTokenBudget) return params.sessionEntry; const sessionManager = cliCompactionDeps.openSessionManager(sessionFile); const settingsManager = await cliCompactionDeps.createPreparedEmbeddedAgentSettingsManager({ cwd: params.cwd ?? params.workspaceDir, agentDir: params.agentDir, cfg: params.cfg, contextTokenBudget }); const preemptiveCompaction = cliCompactionDeps.shouldPreemptivelyCompactBeforePrompt({ messages: getSessionBranchMessages(sessionManager), prompt: "", contextTokenBudget, reserveTokens: settingsManager.getCompactionReserveTokens(), toolResultMaxChars: cliCompactionDeps.resolveLiveToolResultMaxChars({ contextWindowTokens: contextTokenBudget, cfg: params.cfg, agentId: params.sessionAgentId }) }); const tokenSnapshot = resolveSessionTokenSnapshot(params.sessionEntry); const currentTokenCount = Math.max(preemptiveCompaction.estimatedPromptTokens, tokenSnapshot ?? 0); if (!preemptiveCompaction.shouldCompact && currentTokenCount <= preemptiveCompaction.promptBudgetBeforeReserve) return params.sessionEntry; if (cliCompactionDeps.resolveCliBackendConfig(params.provider, params.cfg)?.ownsNativeCompaction && !isNativeHarnessCompactionSession(params.sessionEntry, params.provider)) { log.info(`CLI backend "${params.provider}" owns native compaction — deferring to backend`); return params.sessionEntry; } let compacted = false; let nativeCompactionResult; let useContextEngineCompaction = true; let nativeFallbackToContextEngine = false; let nativeFallbackNeedsBindingClear = false; let resolvedContextEngine; let autoCompactionGuardApplied = false; const authProfileId = params.sessionEntry?.authProfileOverride?.trim() || void 0; const applyAutoCompactionGuard = async (contextEngine) => { if (autoCompactionGuardApplied) return; autoCompactionGuardApplied = true; await cliCompactionDeps.applyAgentAutoCompactionGuard({ settingsManager, contextEngineInfo: contextEngine.info, compactionMode: resolveEffectiveCompactionMode(params.cfg) }); }; if (isNativeHarnessCompactionSession(params.sessionEntry, params.provider)) { cliCompactionDeps.ensureContextEnginesInitialized(); resolvedContextEngine = await cliCompactionDeps.resolveContextEngine(params.cfg); await applyAutoCompactionGuard(resolvedContextEngine); const nativeOutcome = await compactNativeHarnessCliTranscript({ cfg: params.cfg, sessionId: params.sessionId, sessionKey: params.sessionKey, sessionFile, sessionEntry: params.sessionEntry, workspaceDir: params.workspaceDir, cwd: params.cwd, agentDir: params.agentDir, provider: params.provider, model: params.model, contextTokenBudget, currentTokenCount, contextEngine: resolvedContextEngine, skillsSnapshot: params.skillsSnapshot, messageChannel: params.messageChannel, agentAccountId: params.agentAccountId, senderIsOwner: params.senderIsOwner, thinkLevel: params.thinkLevel, extraSystemPrompt: params.extraSystemPrompt }); if (nativeOutcome.compacted) { compacted = true; nativeCompactionResult = nativeOutcome.result; useContextEngineCompaction = false; } else if (nativeOutcome.fallbackToContextEngine) { nativeFallbackToContextEngine = true; nativeFallbackNeedsBindingClear = nativeOutcome.clearCliSessionBinding === true; } else if (nativeOutcome.failureReason) throw new Error(`CLI native harness compaction failed for ${params.provider}/${params.model}: ${nativeOutcome.failureReason ?? "compaction did not reduce context"}`); else useContextEngineCompaction = false; } if (useContextEngineCompaction) { if (!resolvedContextEngine) { cliCompactionDeps.ensureContextEnginesInitialized(); resolvedContextEngine = await cliCompactionDeps.resolveContextEngine(params.cfg); } const contextEngine = resolvedContextEngine; await applyAutoCompactionGuard(contextEngine); const contextOutcome = await compactCliTranscript({ contextEngine, sessionId: params.sessionId, sessionKey: params.sessionKey, sessionFile, sessionManager, cfg: params.cfg, workspaceDir: params.workspaceDir, cwd: params.cwd, agentDir: params.agentDir, provider: params.provider, model: params.model, contextTokenBudget, currentTokenCount, skillsSnapshot: params.skillsSnapshot, messageChannel: params.messageChannel, agentAccountId: params.agentAccountId, authProfileId, senderIsOwner: params.senderIsOwner, thinkLevel: params.thinkLevel, extraSystemPrompt: params.extraSystemPrompt, bestEffortMaintenance: nativeFallbackToContextEngine }); compacted = contextOutcome.compacted; if (!compacted && contextOutcome.failureReason) throw new Error(`CLI transcript compaction failed for ${params.provider}/${params.model}: ${contextOutcome.failureReason ?? "compaction did not reduce context"}`); } if (nativeFallbackNeedsBindingClear && !compacted && params.sessionStore && params.storePath) return await cliCompactionDeps.clearCliSessionInStore({ provider: params.provider, sessionKey: params.sessionKey, sessionStore: params.sessionStore, storePath: params.storePath }) ?? params.sessionEntry; if (!compacted || !params.sessionStore || !params.storePath) return params.sessionEntry; return await cliCompactionDeps.recordCliCompactionInStore({ provider: params.provider, sessionKey: params.sessionKey, sessionStore: params.sessionStore, storePath: params.storePath, tokensAfter: nativeCompactionResult?.result?.tokensAfter, newSessionId: nativeCompactionResult?.result?.sessionId, newSessionFile: nativeCompactionResult?.result?.sessionFile }) ?? params.sessionEntry; } //#endregion export { resetCliCompactionTestDeps, runCliTurnCompactionLifecycle, setCliCompactionTestDeps };