@@ -510,6 +510,22 @@ import {
510510} from "./runtime-context-prompt.js" ;
511511import type { EmbeddedRunAttemptParams , EmbeddedRunAttemptResult } from "./types.js" ;
512512
513+ type PreflightRecoveryBudgetSnapshot = Pick <
514+ MidTurnPrecheckRequest ,
515+ "estimatedPromptTokens" | "promptBudgetBeforeReserve" | "overflowTokens"
516+ > ;
517+
518+ // Carries the measured prompt budget into the outer recovery loop. The synthetic
519+ // precheck error is only a routing signal, so compaction engines need these
520+ // fields to compact against the prompt OpenClaw actually rendered.
521+ function buildPreflightRecoveryBudgetSnapshot ( snapshot : PreflightRecoveryBudgetSnapshot ) {
522+ return {
523+ estimatedPromptTokens : snapshot . estimatedPromptTokens ,
524+ promptBudgetBeforeReserve : snapshot . promptBudgetBeforeReserve ,
525+ overflowTokens : snapshot . overflowTokens ,
526+ } ;
527+ }
528+
513529export {
514530 appendAttemptCacheTtlIfNeeded ,
515531 composeSystemPromptWithHookContext ,
@@ -3878,6 +3894,7 @@ export async function runEmbeddedAttempt(
38783894 preflightRecovery = {
38793895 route : "truncate_tool_results_only" ,
38803896 source : "mid-turn" ,
3897+ ...buildPreflightRecoveryBudgetSnapshot ( request ) ,
38813898 handled : true ,
38823899 truncatedCount : truncationResult . truncatedCount ,
38833900 } ;
@@ -3888,7 +3905,11 @@ export async function runEmbeddedAttempt(
38883905 `handled=true truncatedCount=${ truncationResult . truncatedCount } ` ,
38893906 ) ;
38903907 } else {
3891- preflightRecovery = { route : "compact_only" , source : "mid-turn" } ;
3908+ preflightRecovery = {
3909+ route : "compact_only" ,
3910+ source : "mid-turn" ,
3911+ ...buildPreflightRecoveryBudgetSnapshot ( request ) ,
3912+ } ;
38923913 promptError = new Error ( PREEMPTIVE_OVERFLOW_ERROR_TEXT ) ;
38933914 promptErrorSource = "precheck" ;
38943915 logMidTurnPrecheck (
@@ -3897,7 +3918,11 @@ export async function runEmbeddedAttempt(
38973918 ) ;
38983919 }
38993920 } else {
3900- preflightRecovery = { route : request . route , source : "mid-turn" } ;
3921+ preflightRecovery = {
3922+ route : request . route ,
3923+ source : "mid-turn" ,
3924+ ...buildPreflightRecoveryBudgetSnapshot ( request ) ,
3925+ } ;
39013926 promptError = new Error ( PREEMPTIVE_OVERFLOW_ERROR_TEXT ) ;
39023927 promptErrorSource = "precheck" ;
39033928 logMidTurnPrecheck ( request . route ) ;
@@ -4686,6 +4711,7 @@ export async function runEmbeddedAttempt(
46864711 if ( truncationResult . truncated ) {
46874712 preflightRecovery = {
46884713 route : "truncate_tool_results_only" ,
4714+ ...buildPreflightRecoveryBudgetSnapshot ( preemptiveCompaction ) ,
46894715 handled : true ,
46904716 truncatedCount : truncationResult . truncatedCount ,
46914717 } ;
@@ -4708,7 +4734,10 @@ export async function runEmbeddedAttempt(
47084734 `${ params . provider } /${ params . modelId } ; falling back to compaction ` +
47094735 `reason=${ truncationResult . reason ?? "unknown" } sessionFile=${ params . sessionFile } ` ,
47104736 ) ;
4711- preflightRecovery = { route : "compact_only" } ;
4737+ preflightRecovery = {
4738+ route : "compact_only" ,
4739+ ...buildPreflightRecoveryBudgetSnapshot ( preemptiveCompaction ) ,
4740+ } ;
47124741 promptError = new Error ( PREEMPTIVE_OVERFLOW_ERROR_TEXT ) ;
47134742 promptErrorSource = "precheck" ;
47144743 skipPromptSubmission = true ;
@@ -4717,8 +4746,14 @@ export async function runEmbeddedAttempt(
47174746 if ( preemptiveCompaction ?. shouldCompact ) {
47184747 preflightRecovery =
47194748 preemptiveCompaction . route === "compact_then_truncate"
4720- ? { route : "compact_then_truncate" }
4721- : { route : "compact_only" } ;
4749+ ? {
4750+ route : "compact_then_truncate" ,
4751+ ...buildPreflightRecoveryBudgetSnapshot ( preemptiveCompaction ) ,
4752+ }
4753+ : {
4754+ route : "compact_only" ,
4755+ ...buildPreflightRecoveryBudgetSnapshot ( preemptiveCompaction ) ,
4756+ } ;
47224757 promptError = new Error ( PREEMPTIVE_OVERFLOW_ERROR_TEXT ) ;
47234758 promptErrorSource = "precheck" ;
47244759 log . warn (
0 commit comments