@@ -3,6 +3,10 @@ import path from "node:path";
33import { resolveTimestampMsToIsoString } from "@openclaw/normalization-core/number-coercion" ;
44import { CURRENT_SESSION_VERSION } from "../../config/sessions/version.js" ;
55import type { OpenClawConfig } from "../../config/types.openclaw.js" ;
6+ import {
7+ persistAgentRunSessionTargetIdentity ,
8+ type ResolvedAgentRunSessionTarget ,
9+ } from "../run-session-target.js" ;
610import type { CompactionEntry , SessionEntry , SessionHeader } from "../sessions/index.js" ;
711import { collectDuplicateUserMessageEntryIdsForCompaction } from "./compaction-duplicate-user-messages.js" ;
812import {
@@ -21,6 +25,7 @@ export type CompactionTranscriptRotation = {
2125 reason ?: string ;
2226 sessionId ?: string ;
2327 sessionFile ?: string ;
28+ targetIdentityPersisted ?: boolean ;
2429 compactionEntryId ?: string ;
2530 leafId ?: string ;
2631 entriesWritten ?: number ;
@@ -83,6 +88,44 @@ export async function rotateTranscriptAfterCompaction(params: {
8388 } ;
8489}
8590
91+ /** Rotates a compaction successor and persists the active run target in one operation. */
92+ export async function rotateAgentRunSessionTargetAfterCompaction ( params : {
93+ allowTargetPersistenceRetry ?: boolean ;
94+ runSessionTarget : ResolvedAgentRunSessionTarget ;
95+ sessionManager : ReadonlySessionManagerForRotation ;
96+ sessionFile : string ;
97+ now ?: ( ) => Date ;
98+ } ) : Promise < CompactionTranscriptRotation > {
99+ const rotation = await rotateTranscriptAfterCompaction ( {
100+ sessionManager : params . sessionManager ,
101+ sessionFile : params . sessionFile ,
102+ ...( params . now ? { now : params . now } : { } ) ,
103+ } ) ;
104+ const targetIdentityPersisted = await persistRotatedAgentRunSessionTarget ( {
105+ allowTargetPersistenceRetry : params . allowTargetPersistenceRetry ,
106+ runSessionTarget : params . runSessionTarget ,
107+ rotation,
108+ } ) ;
109+ return rotation . rotated ? { ...rotation , targetIdentityPersisted } : rotation ;
110+ }
111+
112+ /** Opens a transcript file, rotates its compaction successor, and persists the active target. */
113+ export async function rotateAgentRunSessionTargetFileAfterCompaction ( params : {
114+ allowTargetPersistenceRetry ?: boolean ;
115+ runSessionTarget : ResolvedAgentRunSessionTarget ;
116+ sessionFile : string ;
117+ now ?: ( ) => Date ;
118+ } ) : Promise < CompactionTranscriptRotation > {
119+ const state = await readTranscriptFileState ( params . sessionFile ) ;
120+ return rotateAgentRunSessionTargetAfterCompaction ( {
121+ allowTargetPersistenceRetry : params . allowTargetPersistenceRetry ,
122+ runSessionTarget : params . runSessionTarget ,
123+ sessionManager : state ,
124+ sessionFile : params . sessionFile ,
125+ ...( params . now ? { now : params . now } : { } ) ,
126+ } ) ;
127+ }
128+
86129export async function rotateTranscriptFileAfterCompaction ( params : {
87130 sessionFile : string ;
88131 now ?: ( ) => Date ;
@@ -95,6 +138,31 @@ export async function rotateTranscriptFileAfterCompaction(params: {
95138 } ) ;
96139}
97140
141+ async function persistRotatedAgentRunSessionTarget ( params : {
142+ allowTargetPersistenceRetry ?: boolean ;
143+ runSessionTarget : ResolvedAgentRunSessionTarget ;
144+ rotation : CompactionTranscriptRotation ;
145+ } ) : Promise < boolean > {
146+ if ( ! params . rotation . rotated || ! params . rotation . sessionId || ! params . rotation . sessionFile ) {
147+ return false ;
148+ }
149+ try {
150+ await persistAgentRunSessionTargetIdentity ( {
151+ target : params . runSessionTarget ,
152+ sessionFile : params . rotation . sessionFile ,
153+ sessionId : params . rotation . sessionId ,
154+ } ) ;
155+ return true ;
156+ } catch ( err ) {
157+ if ( params . allowTargetPersistenceRetry !== true ) {
158+ throw err ;
159+ }
160+ // The successor transcript already exists. Return it so callers can adopt
161+ // the rotation and, when they own the run loop, retry target persistence.
162+ return false ;
163+ }
164+ }
165+
98166function findLatestCompactionIndex ( entries : SessionEntry [ ] ) : number {
99167 for ( let index = entries . length - 1 ; index >= 0 ; index -= 1 ) {
100168 if ( entries [ index ] ?. type === "compaction" ) {
0 commit comments