@@ -769,6 +769,86 @@ describe("runCliTurnCompactionLifecycle", () => {
769769 expect ( updatedEntry ?. compactionCount ) . toBe ( 1 ) ;
770770 } ) ;
771771
772+ it ( "falls back to context-engine compaction when Codex native compaction returns a raw missing thread reason" , async ( ) => {
773+ const sessionKey = "agent:main:codex-raw-stale-binding" ;
774+ const sessionId = "session-codex-raw-stale-binding" ;
775+ const sessionFile = path . join ( tmpDir , "session-codex-raw-stale-binding.jsonl" ) ;
776+ const storePath = path . join ( tmpDir , "sessions-codex-raw-stale-binding.json" ) ;
777+ await writeSessionFile ( { sessionFile, sessionId } ) ;
778+
779+ const sessionEntry : SessionEntry = {
780+ sessionId,
781+ updatedAt : Date . now ( ) ,
782+ sessionFile,
783+ contextTokens : 1_000 ,
784+ totalTokens : 950 ,
785+ totalTokensFresh : true ,
786+ agentHarnessId : "codex" ,
787+ } ;
788+ const sessionStore : Record < string , SessionEntry > = { [ sessionKey ] : sessionEntry } ;
789+ await fs . writeFile ( storePath , JSON . stringify ( sessionStore , null , 2 ) , "utf-8" ) ;
790+
791+ const compactCalls : Array < Parameters < ContextEngine [ "compact" ] > [ 0 ] > = [ ] ;
792+ const compactAgentHarnessSession = vi . fn ( async ( ) => ( {
793+ ok : false ,
794+ compacted : false ,
795+ reason : "thread not found: thread-raw" ,
796+ } ) ) ;
797+ const maintenance = vi . fn ( async ( ) => ( { changed : false , bytesFreed : 0 , rewrittenEntries : 0 } ) ) ;
798+ const recordCliCompactionInStore = vi . fn ( async ( ) => ( {
799+ ...sessionEntry ,
800+ compactionCount : 1 ,
801+ } ) ) ;
802+ setCliCompactionTestDeps ( {
803+ resolveContextEngine : async ( ) => buildContextEngine ( { compactCalls } ) ,
804+ ensureSelectedAgentHarnessPlugin : vi . fn ( async ( ) => undefined ) ,
805+ maybeCompactAgentHarnessSession : compactAgentHarnessSession as never ,
806+ createPreparedEmbeddedAgentSettingsManager : async ( ) => ( {
807+ getCompactionReserveTokens : ( ) => 200 ,
808+ getCompactionKeepRecentTokens : ( ) => 0 ,
809+ applyOverrides : ( ) => { } ,
810+ } ) ,
811+ shouldPreemptivelyCompactBeforePrompt : ( ) => ( {
812+ route : "fits" ,
813+ shouldCompact : false ,
814+ estimatedPromptTokens : 600 ,
815+ promptBudgetBeforeReserve : 800 ,
816+ overflowTokens : 0 ,
817+ toolResultReducibleChars : 0 ,
818+ effectiveReserveTokens : 200 ,
819+ } ) ,
820+ resolveLiveToolResultMaxChars : ( ) => 20_000 ,
821+ runContextEngineMaintenance : maintenance ,
822+ recordCliCompactionInStore,
823+ } ) ;
824+
825+ const updatedEntry = await runCliTurnCompactionLifecycle ( {
826+ cfg : { } as OpenClawConfig ,
827+ sessionId,
828+ sessionKey,
829+ sessionEntry,
830+ sessionStore,
831+ storePath,
832+ sessionAgentId : "main" ,
833+ workspaceDir : tmpDir ,
834+ agentDir : tmpDir ,
835+ provider : "codex" ,
836+ model : "gpt-5.5" ,
837+ } ) ;
838+
839+ expect ( compactAgentHarnessSession ) . toHaveBeenCalledTimes ( 1 ) ;
840+ expect ( compactCalls ) . toHaveLength ( 1 ) ;
841+ expect ( maintenance ) . toHaveBeenCalledTimes ( 1 ) ;
842+ expect ( recordCliCompactionInStore ) . toHaveBeenCalledWith (
843+ expect . objectContaining ( {
844+ provider : "codex" ,
845+ sessionKey,
846+ tokensAfter : undefined ,
847+ } ) ,
848+ ) ;
849+ expect ( updatedEntry ?. compactionCount ) . toBe ( 1 ) ;
850+ } ) ;
851+
772852 it ( "keeps successful context-engine fallback when post-compaction maintenance fails" , async ( ) => {
773853 const sessionKey = "agent:main:codex-stale-maintenance" ;
774854 const sessionId = "session-codex-stale-maintenance" ;
0 commit comments