@@ -43,6 +43,17 @@ type CompactResult = {
4343 result ?: unknown ;
4444} ;
4545
46+ type CompactDelegate = ( arg : {
47+ sessionId : string ;
48+ sessionFile : string ;
49+ tokenBudget ?: number ;
50+ force ?: boolean ;
51+ currentTokenCount ?: number ;
52+ compactionTarget ?: "budget" | "threshold" ;
53+ customInstructions ?: string ;
54+ runtimeContext ?: Record < string , unknown > ;
55+ } ) => Promise < CompactResult > ;
56+
4657type ContextEngine = {
4758 info : ContextEngineInfo ;
4859 ingest : ( params : { sessionId : string ; message : AgentMessage ; isHeartbeat ?: boolean } ) => Promise < IngestResult > ;
@@ -93,38 +104,113 @@ function estimateTokens(messages: AgentMessage[]): number {
93104 return Math . max ( 1 , messages . length * 80 ) ;
94105}
95106
96- async function tryLegacyCompact ( params : {
97- sessionId : string ;
98- sessionFile : string ;
99- tokenBudget ?: number ;
100- force ?: boolean ;
101- currentTokenCount ?: number ;
102- compactionTarget ?: "budget" | "threshold" ;
103- customInstructions ?: string ;
104- runtimeContext ?: Record < string , unknown > ;
105- } ) : Promise < CompactResult | null > {
107+ function describeError ( err : unknown ) : string {
108+ if ( err instanceof Error ) {
109+ return err . message || err . name || String ( err ) ;
110+ }
111+ return String ( err ) ;
112+ }
113+
114+ function isModuleResolutionError ( err : unknown ) : boolean {
115+ if ( ! ( err instanceof Error ) ) {
116+ return false ;
117+ }
118+ const message = `${ err . name } : ${ err . message } ` . toLowerCase ( ) ;
119+ return (
120+ message . includes ( "cannot find module" ) ||
121+ message . includes ( "module not found" ) ||
122+ message . includes ( "package path not exported" ) ||
123+ message . includes ( "is not defined by 'exports'" ) ||
124+ message . includes ( "unsupported dir import" ) ||
125+ message . includes ( "failed to resolve module specifier" )
126+ ) ;
127+ }
128+
129+ async function tryDelegatedCompact (
130+ params : {
131+ sessionId : string ;
132+ sessionFile : string ;
133+ tokenBudget ?: number ;
134+ force ?: boolean ;
135+ currentTokenCount ?: number ;
136+ compactionTarget ?: "budget" | "threshold" ;
137+ customInstructions ?: string ;
138+ runtimeContext ?: Record < string , unknown > ;
139+ } ,
140+ logger : Logger ,
141+ ) : Promise < CompactResult | null > {
142+ let delegateCompactionToRuntime : CompactDelegate | null ;
143+ try {
144+ delegateCompactionToRuntime = await loadCompactDelegate ( logger ) ;
145+ } catch ( err ) {
146+ return {
147+ ok : false ,
148+ compacted : false ,
149+ reason : `delegate_compact_import_failed:${ describeError ( err ) } ` ,
150+ } ;
151+ }
152+
153+ if ( ! delegateCompactionToRuntime ) {
154+ if ( cachedCompactUnavailableReason ) {
155+ warnOrInfo (
156+ logger ,
157+ `openviking: delegated compaction unavailable (${ cachedCompactUnavailableReason } )` ,
158+ ) ;
159+ }
160+ return null ;
161+ }
162+
163+ try {
164+ return await delegateCompactionToRuntime ( params ) ;
165+ } catch ( err ) {
166+ logger . error ( `openviking: delegated compaction failed: ${ describeError ( err ) } ` ) ;
167+ return {
168+ ok : false ,
169+ compacted : false ,
170+ reason : `delegate_compact_failed:${ describeError ( err ) } ` ,
171+ } ;
172+ }
173+ }
174+
175+ let cachedCompactDelegate : CompactDelegate | null | undefined ;
176+ let cachedCompactUnavailableReason : string | undefined ;
177+
178+ async function loadCompactDelegate ( logger : Logger ) : Promise < CompactDelegate | null > {
179+ if ( cachedCompactDelegate !== undefined ) {
180+ return cachedCompactDelegate ;
181+ }
182+
106183 const candidates = [
107- "openclaw/context-engine/legacy " ,
108- "openclaw/dist/context-engine/legacy.js " ,
184+ "openclaw/plugin-sdk/core " ,
185+ "openclaw/plugin-sdk " ,
109186 ] ;
187+ const importErrors : string [ ] = [ ] ;
110188
111189 for ( const path of candidates ) {
112190 try {
113191 const mod = ( await import ( path ) ) as {
114- LegacyContextEngine ?: new ( ) => {
115- compact : ( arg : typeof params ) => Promise < CompactResult > ;
116- } ;
192+ delegateCompactionToRuntime ?: CompactDelegate ;
117193 } ;
118- if ( ! mod ?. LegacyContextEngine ) {
194+ if ( ! mod ?. delegateCompactionToRuntime ) {
195+ importErrors . push ( `${ path } : delegateCompactionToRuntime export missing` ) ;
119196 continue ;
120197 }
121- const legacy = new mod . LegacyContextEngine ( ) ;
122- return legacy . compact ( params ) ;
123- } catch {
124- // continue
198+ cachedCompactDelegate = mod . delegateCompactionToRuntime ;
199+ cachedCompactUnavailableReason = undefined ;
200+ return cachedCompactDelegate ;
201+ } catch ( err ) {
202+ const detail = `${ path } : ${ describeError ( err ) } ` ;
203+ importErrors . push ( detail ) ;
204+ if ( ! isModuleResolutionError ( err ) ) {
205+ logger . error ( `openviking: delegated compaction import failed: ${ detail } ` ) ;
206+ throw err ;
207+ }
125208 }
126209 }
127210
211+ cachedCompactUnavailableReason =
212+ `failed to load compact delegate from candidates: ${ importErrors . join ( " | " ) } ` ;
213+ cachedCompactDelegate = null ;
128214 return null ;
129215}
130216
@@ -295,20 +381,20 @@ export function createMemoryOpenVikingContextEngine(params: {
295381 } ,
296382
297383 async compact ( compactParams ) : Promise < CompactResult > {
298- const delegated = await tryLegacyCompact ( compactParams ) ;
384+ const delegated = await tryDelegatedCompact ( compactParams , logger ) ;
299385 if ( delegated ) {
300386 return delegated ;
301387 }
302388
303389 warnOrInfo (
304390 logger ,
305- "openviking: legacy compaction delegation unavailable; skipping compact" ,
391+ "openviking: delegated compaction unavailable; skipping compact" ,
306392 ) ;
307393
308394 return {
309395 ok : true ,
310396 compacted : false ,
311- reason : "legacy_compact_unavailable " ,
397+ reason : "delegate_compact_unavailable " ,
312398 } ;
313399 } ,
314400 } ;
0 commit comments