( messages: (UserMessage | AssistantMessage)[], enablePromptCaching: boolean, querySource?: QuerySource, useCachedMC = false, newCacheEdits?: CachedMCEditsBlock | null, pinnedEdits?: CachedMCPinnedEdits[], skipCacheWrite = false, )
| 3088 | |
| 3089 | // Exported for testing cache_reference placement constraints |
| 3090 | export function addCacheBreakpoints( |
| 3091 | messages: (UserMessage | AssistantMessage)[], |
| 3092 | enablePromptCaching: boolean, |
| 3093 | querySource?: QuerySource, |
| 3094 | useCachedMC = false, |
| 3095 | newCacheEdits?: CachedMCEditsBlock | null, |
| 3096 | pinnedEdits?: CachedMCPinnedEdits[], |
| 3097 | skipCacheWrite = false, |
| 3098 | ): MessageParam[] { |
| 3099 | logEvent('ncode_api_cache_breakpoints', { |
| 3100 | totalMessageCount: messages.length, |
| 3101 | cachingEnabled: enablePromptCaching, |
| 3102 | skipCacheWrite, |
| 3103 | }) |
| 3104 | |
| 3105 | // Exactly one message-level cache_control marker per request. Mycro's |
| 3106 | // turn-to-turn eviction (page_manager/index.rs: Index::insert) frees |
| 3107 | // local-attention KV pages at any cached prefix position NOT in |
| 3108 | // cache_store_int_token_boundaries. With two markers the second-to-last |
| 3109 | // position is protected and its locals survive an extra turn even though |
| 3110 | // nothing will ever resume from there — with one marker they're freed |
| 3111 | // immediately. For fire-and-forget forks (skipCacheWrite) we shift the |
| 3112 | // marker to the second-to-last message: that's the last shared-prefix |
| 3113 | // point, so the write is a no-op merge on mycro (entry already exists) |
| 3114 | // and the fork doesn't leave its own tail in the KVCC. Dense pages are |
| 3115 | // refcounted and survive via the new hash either way. |
| 3116 | const markerIndex = skipCacheWrite ? messages.length - 2 : messages.length - 1 |
| 3117 | const result = messages.map((msg, index) => { |
| 3118 | const addCache = index === markerIndex |
| 3119 | if (msg.type === 'user') { |
| 3120 | return userMessageToMessageParam( |
| 3121 | msg, |
| 3122 | addCache, |
| 3123 | enablePromptCaching, |
| 3124 | querySource, |
| 3125 | ) |
| 3126 | } |
| 3127 | return assistantMessageToMessageParam( |
| 3128 | msg, |
| 3129 | addCache, |
| 3130 | enablePromptCaching, |
| 3131 | querySource, |
| 3132 | ) |
| 3133 | }) |
| 3134 | |
| 3135 | if (!useCachedMC) { |
| 3136 | return result |
| 3137 | } |
| 3138 | |
| 3139 | // Track all cache_references being deleted to prevent duplicates across blocks. |
| 3140 | const seenDeleteRefs = new Set<string>() |
| 3141 | |
| 3142 | // Helper to deduplicate a cache_edits block against already-seen deletions |
| 3143 | const deduplicateEdits = (block: CachedMCEditsBlock): CachedMCEditsBlock => { |
| 3144 | const uniqueEdits = block.edits.filter(edit => { |
| 3145 | if (seenDeleteRefs.has(edit.cache_reference)) { |
| 3146 | return false |
| 3147 | } |
no test coverage detected