@@ -20,6 +20,10 @@ const sessionForkRuntimeLoader = createLazyImportLoader(() => import("./session-
2020
2121export type ParentForkDecision = SessionParentForkDecision ;
2222
23+ type ParentForkTokenCountResolution =
24+ | { status : "resolved" ; parentTokens ?: number }
25+ | { status : "timed-out" } ;
26+
2327type ParentForkDecisionParams = {
2428 parentEntry : SessionEntry ;
2529 agentId ?: string ;
@@ -95,6 +99,17 @@ function formatParentForkTooLargeMessage(params: {
9599 ) ;
96100}
97101
102+ function formatParentForkTokenProbeTimeoutMessage ( ) : string {
103+ return (
104+ `Parent context size could not be verified within ${ PARENT_FORK_TOKEN_COUNT_TIMEOUT_MS } ms; ` +
105+ "starting with isolated context instead."
106+ ) ;
107+ }
108+
109+ function formatParentForkTokenProbeUnavailableMessage ( ) : string {
110+ return "Parent context size could not be verified; starting with isolated context instead." ;
111+ }
112+
98113function resolveParentForkStorePath ( params : {
99114 agentId ?: string ;
100115 config ?: OpenClawConfig ;
@@ -109,12 +124,37 @@ export async function resolveParentForkDecision(
109124 params : ParentForkDecisionParams ,
110125) : Promise < ParentForkDecision > {
111126 const maxTokens = DEFAULT_PARENT_FORK_MAX_TOKENS ;
112- const parentTokens =
113- resolveFreshSessionTotalTokens ( params . parentEntry ) ??
114- ( await resolveParentForkTokenCountWithTimeout ( {
115- parentEntry : params . parentEntry ,
116- storePath : resolveParentForkStorePath ( params ) ,
117- } ) ) ;
127+ const freshParentTokens = resolveFreshSessionTotalTokens ( params . parentEntry ) ;
128+ if ( typeof freshParentTokens === "number" && freshParentTokens > maxTokens ) {
129+ return {
130+ status : "skip" ,
131+ reason : "parent-too-large" ,
132+ maxTokens,
133+ parentTokens : freshParentTokens ,
134+ message : formatParentForkTooLargeMessage ( { parentTokens : freshParentTokens , maxTokens } ) ,
135+ } ;
136+ }
137+ if ( typeof freshParentTokens === "number" ) {
138+ return {
139+ status : "fork" ,
140+ maxTokens,
141+ parentTokens : freshParentTokens ,
142+ } ;
143+ }
144+
145+ const tokenCountResolution = await resolveParentForkTokenCountWithTimeout ( {
146+ parentEntry : params . parentEntry ,
147+ storePath : resolveParentForkStorePath ( params ) ,
148+ } ) ;
149+ if ( tokenCountResolution . status === "timed-out" ) {
150+ return {
151+ status : "skip" ,
152+ reason : "parent-size-timeout" ,
153+ maxTokens,
154+ message : formatParentForkTokenProbeTimeoutMessage ( ) ,
155+ } ;
156+ }
157+ const parentTokens = tokenCountResolution . parentTokens ;
118158 if ( typeof parentTokens === "number" && parentTokens > maxTokens ) {
119159 return {
120160 status : "skip" ,
@@ -124,10 +164,18 @@ export async function resolveParentForkDecision(
124164 message : formatParentForkTooLargeMessage ( { parentTokens, maxTokens } ) ,
125165 } ;
126166 }
167+ if ( typeof parentTokens !== "number" ) {
168+ return {
169+ status : "skip" ,
170+ reason : "parent-size-unavailable" ,
171+ maxTokens,
172+ message : formatParentForkTokenProbeUnavailableMessage ( ) ,
173+ } ;
174+ }
127175 return {
128176 status : "fork" ,
129177 maxTokens,
130- ... ( typeof parentTokens === "number" ? { parentTokens } : { } ) ,
178+ parentTokens,
131179 } ;
132180}
133181
@@ -209,14 +257,22 @@ async function resolveParentForkTokenCount(params: {
209257async function resolveParentForkTokenCountWithTimeout ( params : {
210258 parentEntry : SessionEntry ;
211259 storePath : string ;
212- } ) : Promise < number | undefined > {
213- let timeoutId : number | undefined ;
214- const timeout = new Promise < undefined > ( ( resolve ) => {
215- timeoutId = setTimeout ( resolve , PARENT_FORK_TOKEN_COUNT_TIMEOUT_MS ) ;
260+ } ) : Promise < ParentForkTokenCountResolution > {
261+ let timeoutId : Parameters < typeof clearTimeout > [ 0 ] ;
262+ const tokenCount = resolveParentForkTokenCount ( params ) . then ( ( parentTokens ) =>
263+ typeof parentTokens === "number"
264+ ? ( { status : "resolved" , parentTokens } as const )
265+ : ( { status : "resolved" } as const ) ,
266+ ) ;
267+ const timeout = new Promise < ParentForkTokenCountResolution > ( ( resolve ) => {
268+ timeoutId = setTimeout (
269+ ( ) => resolve ( { status : "timed-out" } ) ,
270+ PARENT_FORK_TOKEN_COUNT_TIMEOUT_MS ,
271+ ) ;
216272 } ) ;
217273 try {
218- // Availability wins over exact sizing when transcript probing stalls .
219- return await Promise . race ( [ resolveParentForkTokenCount ( params ) , timeout ] ) ;
274+ // Isolated context wins when parent sizing stalls or cannot be verified .
275+ return await Promise . race ( [ tokenCount , timeout ] ) ;
220276 } finally {
221277 if ( timeoutId !== undefined ) {
222278 clearTimeout ( timeoutId ) ;
0 commit comments