| |
| import { normalizeStructuredPromptSection } from "@openclaw/ai/internal/shared"; |
| import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce"; |
| import { |
| buildMemoryPromptSection, |
| getActivePreparedMemoryPromptSection, |
| prepareMemoryPromptSection, |
| type MemoryPromptSectionParams, |
| type PreparedMemoryPromptSection, |
| } from "../plugins/memory-state.js"; |
| import { parseAgentSessionKey } from "../routing/session-key.js"; |
| import { createLazyRuntimeModule } from "../shared/lazy-runtime.js"; |
| import { |
| isRuntimeCompactionDelegate, |
| markRuntimeCompactionDelegate, |
| } from "./compaction-watchdog.js"; |
| import type { |
| ContextEngine, |
| CompactResult, |
| ContextEngineRuntimeContext, |
| ContextEngineSessionTarget, |
| } from "./types.js"; |
|
|
| const loadCompactRuntime = createLazyRuntimeModule( |
| () => import("../agents/embedded-agent-runner/compact.runtime.js"), |
| ); |
|
|
| function assertCompactionSessionIdentity(params: { |
| agentId?: string; |
| sessionId: string; |
| sessionKey?: string; |
| sessionTarget?: ContextEngineSessionTarget; |
| }): void { |
| const targetAgentId = normalizeOptionalString(params.sessionTarget?.agentId); |
| const targetSessionId = normalizeOptionalString(params.sessionTarget?.sessionId); |
| const targetSessionKey = normalizeOptionalString(params.sessionTarget?.sessionKey); |
| const requestedAgentId = normalizeOptionalString(params.agentId); |
| const callerSessionId = normalizeOptionalString(params.sessionId); |
| const requestedSessionKey = normalizeOptionalString(params.sessionKey); |
| const requestedSessionKeyAgentId = parseAgentSessionKey(requestedSessionKey)?.agentId; |
| if ( |
| (requestedAgentId && targetAgentId && requestedAgentId !== targetAgentId) || |
| (callerSessionId && targetSessionId && callerSessionId !== targetSessionId) || |
| (requestedSessionKey && targetSessionKey && requestedSessionKey !== targetSessionKey) || |
| (requestedSessionKeyAgentId && targetAgentId && requestedSessionKeyAgentId !== targetAgentId) |
| ) { |
| throw new Error("Context-engine successor target conflicts with the caller session identity"); |
| } |
| const agentId = targetAgentId ?? requestedAgentId; |
| const sessionKeyAgentId = parseAgentSessionKey(targetSessionKey ?? requestedSessionKey)?.agentId; |
| if (sessionKeyAgentId && agentId && sessionKeyAgentId !== agentId) { |
| throw new Error("Context-engine successor session key conflicts with its agent identity"); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function delegateCompactionToRuntime( |
| params: Parameters<ContextEngine["compact"]>[0], |
| ): Promise<CompactResult> { |
| type RuntimeCompactionParams = Parameters< |
| Awaited<ReturnType<typeof loadCompactRuntime>>["compactEmbeddedAgentSessionOnDemand"] |
| >[0]; |
|
|
| |
| |
| |
| const runtimeContext = (params.runtimeContext ?? {}) as ContextEngineRuntimeContext & |
| Partial<RuntimeCompactionParams>; |
| const { sessionFile: _legacySessionFile, ...runtimeContextParams } = runtimeContext; |
| const sessionTarget = params.sessionTarget ?? runtimeContext.sessionTarget; |
| const agentId = params.agentId ?? runtimeContext.agentId; |
| const sessionKey = params.sessionKey ?? runtimeContext.sessionKey; |
| |
| |
| assertCompactionSessionIdentity({ |
| agentId, |
| sessionId: params.sessionId, |
| sessionKey, |
| sessionTarget, |
| }); |
| const { compactEmbeddedAgentSessionOnDemand } = await loadCompactRuntime(); |
| const currentTokenCount = |
| params.currentTokenCount ?? |
| (typeof runtimeContext.currentTokenCount === "number" && |
| Number.isFinite(runtimeContext.currentTokenCount) && |
| runtimeContext.currentTokenCount > 0 |
| ? Math.floor(runtimeContext.currentTokenCount) |
| : undefined); |
|
|
| const result = await compactEmbeddedAgentSessionOnDemand({ |
| ...runtimeContextParams, |
| |
| contextEngineRuntimeContext: runtimeContext, |
| agentId, |
| sessionId: params.sessionId, |
| sessionKey, |
| sessionTarget, |
| tokenBudget: params.tokenBudget, |
| ...(currentTokenCount !== undefined ? { currentTokenCount } : {}), |
| force: params.force, |
| customInstructions: params.customInstructions, |
| abortSignal: params.abortSignal, |
| workspaceDir: |
| typeof runtimeContext.workspaceDir === "string" ? runtimeContext.workspaceDir : process.cwd(), |
| }); |
|
|
| return { |
| ok: result.ok, |
| compacted: result.compacted, |
| reason: result.reason, |
| result: result.result |
| ? { |
| summary: result.result.summary, |
| firstKeptEntryId: result.result.firstKeptEntryId, |
| tokensBefore: result.result.tokensBefore, |
| tokensAfter: result.result.tokensAfter, |
| details: result.result.details, |
| ...(result.result.sessionId ? { sessionId: result.result.sessionId } : {}), |
| |
| |
| |
| ...(result.result.sessionTarget ? { sessionTarget: result.result.sessionTarget } : {}), |
| } |
| : undefined, |
| }; |
| } |
|
|
| markRuntimeCompactionDelegate(delegateCompactionToRuntime); |
|
|
| |
| export { isRuntimeCompactionDelegate }; |
|
|
| |
| |
| |
| |
| |
| |
| function renderMemorySystemPromptAddition( |
| params: MemoryPromptSectionParams, |
| prepared?: PreparedMemoryPromptSection, |
| ): string | undefined { |
| const lines = buildMemoryPromptSection(params, prepared); |
| if (lines.length === 0) { |
| return undefined; |
| } |
| const normalized = normalizeStructuredPromptSection(lines.join("\n")); |
| return normalized || undefined; |
| } |
|
|
| export function buildMemorySystemPromptAddition( |
| params: MemoryPromptSectionParams, |
| ): string | undefined { |
| const prepared = getActivePreparedMemoryPromptSection(); |
| if (!prepared) { |
| return renderMemorySystemPromptAddition(params); |
| } |
| const contextParams: MemoryPromptSectionParams = { |
| availableTools: params.availableTools, |
| citationsMode: params.citationsMode ?? prepared.context.citationsMode, |
| agentId: params.agentId ?? prepared.context.agentId, |
| agentSessionKey: params.agentSessionKey ?? prepared.context.agentSessionKey, |
| sandboxed: params.sandboxed ?? prepared.context.sandboxed, |
| }; |
| return renderMemorySystemPromptAddition(contextParams, prepared); |
| } |
|
|
| |
| export async function prepareMemorySystemPromptAddition( |
| params: MemoryPromptSectionParams, |
| ): Promise<string | undefined> { |
| const prepared = await prepareMemoryPromptSection(params); |
| return renderMemorySystemPromptAddition(params, prepared); |
| } |
|
|