@@ -135,7 +135,7 @@ function wrapSystemReminder(text) {
135135 ) ;
136136}
137137
138- function prependToFirstUserMessage ( messages , text ) {
138+ function prependToFirstUserMessage ( messages , text , cacheControl ) {
139139 if ( ! Array . isArray ( messages ) || ! messages . length ) return messages ;
140140 const out = messages . map ( ( m ) => ( {
141141 ...m ,
@@ -144,15 +144,17 @@ function prependToFirstUserMessage(messages, text) {
144144 const idx = out . findIndex ( ( m ) => m . role === "user" ) ;
145145 if ( idx < 0 ) return out ;
146146 const m = out [ idx ] ;
147+ const reminder = {
148+ type : "text" ,
149+ text,
150+ ...( cacheControl ? { cache_control : cacheControl } : { } ) ,
151+ } ;
147152 if ( typeof m . content === "string" ) {
148- out [ idx ] = { ...m , content : text + m . content } ;
153+ out [ idx ] = { ...m , content : [ reminder , { type : " text" , text : m . content } ] } ;
149154 } else if ( Array . isArray ( m . content ) ) {
150- out [ idx ] = {
151- ...m ,
152- content : [ { type : "text" , text } , ...m . content ] ,
153- } ;
155+ out [ idx ] = { ...m , content : [ reminder , ...m . content ] } ;
154156 } else {
155- out [ idx ] = { ...m , content : [ { type : "text" , text : text + String ( m . content ?? "" ) } ] } ;
157+ out [ idx ] = { ...m , content : [ reminder , { type : "text" , text : String ( m . content ?? "" ) } ] } ;
156158 }
157159 return out ;
158160}
@@ -179,11 +181,14 @@ function applyCloaking(body, accessToken, sessionId) {
179181
180182 // Capture original client system for move to user message
181183 let userSystemText = "" ;
184+ let userSystemCacheControl ;
182185 if ( Array . isArray ( result . system ) ) {
183186 userSystemText = result . system
184187 . map ( ( b ) => ( typeof b === "string" ? b : b ?. text || "" ) )
185188 . filter ( Boolean )
186189 . join ( "\n\n" ) ;
190+ userSystemCacheControl = result . system . findLast ?. ( ( block ) => block ?. cache_control ) ?. cache_control
191+ || [ ...result . system ] . reverse ( ) . find ( ( block ) => block ?. cache_control ) ?. cache_control ;
187192 } else if ( typeof result . system === "string" ) {
188193 userSystemText = result . system ;
189194 }
@@ -198,7 +203,8 @@ function applyCloaking(body, accessToken, sessionId) {
198203 if ( sanitized ) {
199204 result . messages = prependToFirstUserMessage (
200205 result . messages || [ ] ,
201- wrapSystemReminder ( sanitized )
206+ wrapSystemReminder ( sanitized ) ,
207+ userSystemCacheControl
202208 ) ;
203209 }
204210 }
@@ -402,35 +408,74 @@ function hasExplicitCacheControl(payload) {
402408
403409/** Apply Claude's four-breakpoint policy only after the router has selected
404410 * Claude. Explicit client-authored breakpoints remain authoritative. */
405- function applyAutomaticCacheControl ( payload ) {
411+ function applyAutomaticCacheControl ( payload , preferredBaseBlocks = [ ] ) {
406412 if ( hasExplicitCacheControl ( payload ) ) return payload ;
407413
408- let baseBlock = null ;
409- for ( const message of payload . messages || [ ] ) {
410- if ( message . role !== "user" || ! Array . isArray ( message . content ) ) continue ;
411- if ( message . content . some ( ( block ) => block ?. type === "tool_result" ) ) continue ;
412- for ( let index = message . content . length - 1 ; index >= 0 ; index -- ) {
413- const block = message . content [ index ] ;
414- if ( block ?. type === "text" || block ?. type === "image" ) {
415- baseBlock = block ;
416- break ;
414+ const baseBlocks = [ ...new Set ( ( Array . isArray ( preferredBaseBlocks ) ? preferredBaseBlocks : [ preferredBaseBlocks ] ) . filter ( Boolean ) ) ] ;
415+ if ( ! baseBlocks . length ) {
416+ let baseBlock = null ;
417+ for ( const message of payload . messages || [ ] ) {
418+ if ( message . role !== "user" || ! Array . isArray ( message . content ) ) continue ;
419+ if ( message . content . some ( ( block ) => block ?. type === "tool_result" ) ) continue ;
420+ for ( let index = message . content . length - 1 ; index >= 0 ; index -- ) {
421+ const block = message . content [ index ] ;
422+ if ( block ?. type === "text" || block ?. type === "image" ) {
423+ baseBlock = block ;
424+ break ;
425+ }
417426 }
418427 }
428+ if ( baseBlock ) baseBlocks . push ( baseBlock ) ;
419429 }
420- if ( baseBlock ) baseBlock . cache_control = { type : "ephemeral" } ;
430+ for ( const block of baseBlocks ) block . cache_control = { type : "ephemeral" } ;
421431
422432 const toolResults = [ ] ;
423433 for ( const message of payload . messages || [ ] ) {
424434 for ( const block of Array . isArray ( message . content ) ? message . content : [ ] ) {
425435 if ( block ?. type === "tool_result" ) toolResults . push ( block ) ;
426436 }
427437 }
428- for ( const block of toolResults . slice ( - 3 ) ) {
429- block . cache_control = { type : "ephemeral" } ;
438+ const availableToolBreakpoints = Math . max ( 0 , 4 - baseBlocks . length ) ;
439+ if ( availableToolBreakpoints > 0 ) {
440+ for ( const block of toolResults . slice ( - availableToolBreakpoints ) ) {
441+ block . cache_control = { type : "ephemeral" } ;
442+ }
430443 }
431444 return payload ;
432445}
433446
447+ function systemCacheScope ( message ) {
448+ return message ?. extra_content ?. openai ?. cache_scope || "" ;
449+ }
450+
451+ function systemTextBlocks ( message ) {
452+ const nativeSystem = message ?. [ ANTHROPIC_METADATA ] ?. content ;
453+ if ( Array . isArray ( nativeSystem ) ) return JSON . parse ( JSON . stringify ( nativeSystem ) ) ;
454+ if ( typeof nativeSystem === "string" ) return [ { type : "text" , text : nativeSystem } ] ;
455+ if ( typeof message ?. content === "string" ) return [ { type : "text" , text : message . content } ] ;
456+ if ( Array . isArray ( message ?. content ) ) {
457+ return message . content
458+ . filter ( ( part ) => part ?. type === "text" && part . text != null )
459+ . map ( ( part ) => ( {
460+ type : "text" ,
461+ text : String ( part . text ) ,
462+ ...( part . cache_control ? { cache_control : part . cache_control } : { } ) ,
463+ } ) ) ;
464+ }
465+ return message ?. content != null ? [ { type : "text" , text : String ( message . content ) } ] : [ ] ;
466+ }
467+
468+ function lastCacheableMessageBlock ( messages ) {
469+ for ( let messageIndex = messages . length - 1 ; messageIndex >= 0 ; messageIndex -- ) {
470+ const blocks = Array . isArray ( messages [ messageIndex ] ?. content ) ? messages [ messageIndex ] . content : [ ] ;
471+ for ( let blockIndex = blocks . length - 1 ; blockIndex >= 0 ; blockIndex -- ) {
472+ const block = blocks [ blockIndex ] ;
473+ if ( [ "text" , "image" , "tool_result" ] . includes ( block ?. type ) ) return block ;
474+ }
475+ }
476+ return null ;
477+ }
478+
434479/**
435480 * Convert OpenAI chat messages → Anthropic messages + system + tools.
436481 * Critical: tool_result must be in a user message; tool_use only on assistant.
@@ -439,6 +484,13 @@ function applyAutomaticCacheControl(payload) {
439484function toAnthropicBody ( body , model , stream ) {
440485 const systemParts = [ ] ;
441486 const messages = [ ] ;
487+ const sourceMessages = body . messages || [ ] ;
488+ const hasScopedSystem = sourceMessages . some ( ( message ) => message . role === "system" && systemCacheScope ( message ) ) ;
489+ const deferredDynamicSystemParts = [ ] ;
490+ const lastDynamicSystemIndex = sourceMessages . findLastIndex ?. (
491+ ( message ) => message . role === "system" && systemCacheScope ( message ) === "dynamic_context"
492+ ) ?? - 1 ;
493+ const preferredCacheBases = [ ] ;
442494
443495 const pushMessage = ( role , blocks ) => {
444496 if ( ! blocks . length ) return ;
@@ -459,32 +511,28 @@ function toAnthropicBody(body, model, stream) {
459511 messages . push ( { role, content : blocks } ) ;
460512 } ;
461513
462- for ( const m of body . messages || [ ] ) {
514+ for ( let sourceIndex = 0 ; sourceIndex < sourceMessages . length ; sourceIndex ++ ) {
515+ const m = sourceMessages [ sourceIndex ] ;
463516 if ( m . role === "system" ) {
464- const nativeSystem = m [ ANTHROPIC_METADATA ] ?. content ;
465- if ( Array . isArray ( nativeSystem ) ) {
466- systemParts . push ( ...JSON . parse ( JSON . stringify ( nativeSystem ) ) ) ;
517+ const parts = systemTextBlocks ( m ) ;
518+ const scope = systemCacheScope ( m ) ;
519+ if ( ! hasScopedSystem || scope === "stable_instruction" || ! scope ) {
520+ systemParts . push ( ...parts ) ;
467521 continue ;
468522 }
469- if ( typeof nativeSystem === "string" ) {
470- systemParts . push ( { type : "text" , text : nativeSystem } ) ;
523+ if ( scope === "dynamic_context" ) {
524+ deferredDynamicSystemParts . push ( ...parts ) ;
525+ if ( sourceIndex !== lastDynamicSystemIndex ) continue ;
526+ const stableBase = [ ...systemParts ] . reverse ( ) . find ( ( block ) => block ?. type === "text" || block ?. type === "image" ) || null ;
527+ const rollingBase = lastCacheableMessageBlock ( messages ) ;
528+ if ( stableBase ) preferredCacheBases . push ( stableBase ) ;
529+ if ( rollingBase ) preferredCacheBases . push ( rollingBase ) ;
530+ const text = deferredDynamicSystemParts . map ( ( part ) => part ?. text || "" ) . filter ( Boolean ) . join ( "\n\n" ) ;
531+ if ( text ) pushMessage ( "user" , [ { type : "text" , text : wrapSystemReminder ( text ) } ] ) ;
471532 continue ;
472533 }
473- if ( typeof m . content === "string" ) {
474- systemParts . push ( { type : "text" , text : m . content } ) ;
475- } else if ( Array . isArray ( m . content ) ) {
476- for ( const part of m . content ) {
477- if ( part ?. type === "text" && part . text != null ) {
478- systemParts . push ( {
479- type : "text" ,
480- text : String ( part . text ) ,
481- ...( part . cache_control ? { cache_control : part . cache_control } : { } ) ,
482- } ) ;
483- }
484- }
485- } else if ( m . content != null ) {
486- systemParts . push ( { type : "text" , text : String ( m . content ) } ) ;
487- }
534+ const text = parts . map ( ( part ) => part ?. text || "" ) . filter ( Boolean ) . join ( "\n\n" ) ;
535+ if ( text ) pushMessage ( "user" , [ { type : "text" , text : wrapSystemReminder ( text ) } ] ) ;
488536 continue ;
489537 }
490538 const blocks = contentBlocksFromMessage ( m ) ;
@@ -515,7 +563,7 @@ function toAnthropicBody(body, model, stream) {
515563 stream : ! ! stream ,
516564 } ;
517565 if ( systemParts . length ) {
518- out . system = systemParts . some ( ( part ) => part . cache_control )
566+ out . system = hasScopedSystem || systemParts . some ( ( part ) => part . cache_control )
519567 ? systemParts
520568 : systemParts . map ( ( part ) => part . text ) . join ( "\n\n" ) ;
521569 }
@@ -560,7 +608,7 @@ function toAnthropicBody(body, model, stream) {
560608 for ( const [ key , value ] of Object . entries ( body [ ANTHROPIC_METADATA ] ?. options || { } ) ) {
561609 out [ key ] = JSON . parse ( JSON . stringify ( value ) ) ;
562610 }
563- return applyAutomaticCacheControl ( applyClaudeEffort ( out , body , model ) ) ;
611+ return applyAutomaticCacheControl ( applyClaudeEffort ( out , body , model ) , preferredCacheBases ) ;
564612}
565613
566614function mapStopReason ( stopReason ) {
0 commit comments