@@ -8,13 +8,21 @@ import { createDefaultDependencies } from "@intx/inference/providers";
88import type {
99 ConversationTurn ,
1010 InferenceEvent ,
11+ InferenceSource ,
1112 ReactorAction ,
1213} from "@intx/types/runtime" ;
1314import { createChatDirector } from "../agent/director.js" ;
1415import {
1516 COMPACTION_CONTINUATION_EVENT ,
1617 lastCycleSourceFromRunModel ,
1718} from "../agent/compaction.js" ;
19+ import {
20+ buildAnthropicSource ,
21+ buildGoSource ,
22+ buildOpenAISource ,
23+ buildZenSource ,
24+ } from "../config/index.js" ;
25+ import { resumeCacheWriteSeed } from "../provider/cache-ttl.js" ;
1826import { HANDOFF_LATEST_KEY } from "./compaction-handoff.js" ;
1927import { COMPACTED_PREFIX , createPruningCompactor } from "./compactor.js" ;
2028import { createOptimizedContextStore } from "./optimized-context-store.js" ;
@@ -62,7 +70,10 @@ function actionsOf(result: ReactorAction | ReactorAction[]): ReactorAction[] {
6270 return Array . isArray ( result ) ? result : [ result ] ;
6371}
6472
65- async function resumeAndInfer ( args : { at : number ; model : string } ) : Promise < {
73+ async function resumeAndInfer ( args : {
74+ at : number ;
75+ source : InferenceSource ;
76+ } ) : Promise < {
6677 first : ReactorAction [ ] ;
6778 stored : ConversationTurn [ ] ;
6879 prompt : ConversationTurn [ ] ;
@@ -80,10 +91,21 @@ async function resumeAndInfer(args: { at: number; model: string }): Promise<{
8091 } ) ;
8192 await store . commit ( { message : "seed" } ) ;
8293
83- const source = lastCycleSourceFromRunModel ( args . model ) ;
84- if ( source === undefined ) throw new Error ( "missing source" ) ;
94+ const storedModel = `${ args . source . id } :${ args . source . model } ` ;
95+ const cacheSeed = resumeCacheWriteSeed ( {
96+ at : args . at ,
97+ storedModel,
98+ liveProvider : args . source . id ,
99+ liveProtocol : args . source . provider ,
100+ } ) ;
101+ const source =
102+ cacheSeed === undefined
103+ ? undefined
104+ : lastCycleSourceFromRunModel ( cacheSeed . model ) ;
85105 const director = createChatDirector ( "test" , [ ] , { } ) ;
86- director . restoreCacheWrite ( { at : args . at , source, turns : seed } ) ;
106+ if ( cacheSeed !== undefined && source !== undefined ) {
107+ director . restoreCacheWrite ( { at : cacheSeed . at , source, turns : seed } ) ;
108+ }
87109 const original = director . decide . bind ( director ) ;
88110 let first : ReactorAction [ ] | undefined ;
89111 director . decide = async ( event , state , capabilities ) => {
@@ -104,13 +126,7 @@ async function resumeAndInfer(args: { at: number; model: string }): Promise<{
104126 const reactor = createReactor ( {
105127 sessionId : "cache-ttl-resume" ,
106128 director,
107- source : {
108- id : "anthropic:claude-opus-4-6" ,
109- provider : "anthropic" ,
110- model : "claude-opus-4-6" ,
111- baseURL : "https://example.invalid" ,
112- credentialId : "test" ,
113- } ,
129+ source : args . source ,
114130 toolRunner : {
115131 async run ( call ) {
116132 return { callId : call . id , content : "ok" } ;
@@ -150,9 +166,9 @@ async function resumeAndInfer(args: { at: number; model: string }): Promise<{
150166 } ,
151167 usage : USAGE ,
152168 source : {
153- sourceId : source . sourceId ,
154- provider : source . provider ,
155- model : source . model ,
169+ sourceId : args . source . id ,
170+ provider : args . source . provider ,
171+ model : args . source . model ,
156172 } ,
157173 } ,
158174 } ;
@@ -216,10 +232,16 @@ async function resumeAndInfer(args: { at: number; model: string }): Promise<{
216232}
217233
218234describe ( "resumed Anthropic cache write compacts before infer" , ( ) => {
235+ const native = buildAnthropicSource ( {
236+ id : "anthropic" ,
237+ baseURL : "https://example.invalid" ,
238+ model : "claude-opus-4-6" ,
239+ } ) ;
240+
219241 test ( "an expired Anthropic stamp folds into the context store first" , async ( ) => {
220242 const result = await resumeAndInfer ( {
221243 at : Date . now ( ) - 6 * MINUTE_MS ,
222- model : "anthropic:claude-opus-4-6" ,
244+ source : native ,
223245 } ) ;
224246
225247 expect ( result . first [ 0 ] ) . toMatchObject ( {
@@ -242,7 +264,7 @@ describe("resumed Anthropic cache write compacts before infer", () => {
242264 test ( "a write inside 5 minutes leaves the stored turns in place" , async ( ) => {
243265 const result = await resumeAndInfer ( {
244266 at : Date . now ( ) - 2 * MINUTE_MS ,
245- model : "anthropic:claude-opus-4-6" ,
267+ source : native ,
246268 } ) ;
247269
248270 expect ( result . first . some ( ( action ) => action . type === "compact" ) ) . toBe (
@@ -255,7 +277,11 @@ describe("resumed Anthropic cache write compacts before infer", () => {
255277 test ( "a non-Anthropic stored stamp does not compact" , async ( ) => {
256278 const result = await resumeAndInfer ( {
257279 at : Date . now ( ) - 6 * MINUTE_MS ,
258- model : "openai:gpt-5.6" ,
280+ source : buildOpenAISource ( {
281+ id : "openai" ,
282+ baseURL : "https://example.invalid/v1" ,
283+ model : "gpt-5.6" ,
284+ } ) ,
259285 } ) ;
260286
261287 expect ( result . first . some ( ( action ) => action . type === "compact" ) ) . toBe (
@@ -264,4 +290,37 @@ describe("resumed Anthropic cache write compacts before infer", () => {
264290 expect ( texts ( result . stored ) ) . toEqual ( texts ( result . seed ) ) ;
265291 expect ( result . handoff ) . toBeUndefined ( ) ;
266292 } ) ;
293+
294+ test ( "expired Zen, OpenCode Go, and custom Anthropic catalog ids fold before infer" , async ( ) => {
295+ const sources = [
296+ buildZenSource ( {
297+ id : "zen" ,
298+ model : "claude-opus-4-6" ,
299+ sessionId : "sess-zen" ,
300+ } ) ,
301+ buildGoSource ( {
302+ id : "opencode-go" ,
303+ model : "minimax-m3" ,
304+ sessionId : "sess-go" ,
305+ } ) ,
306+ buildAnthropicSource ( {
307+ id : "acme" ,
308+ baseURL : "https://example.invalid" ,
309+ model : "claude-opus-4-6" ,
310+ } ) ,
311+ ] ;
312+ for ( const source of sources ) {
313+ expect ( source . id ) . not . toBe ( source . provider ) ;
314+ const result = await resumeAndInfer ( {
315+ at : Date . now ( ) - 6 * MINUTE_MS ,
316+ source,
317+ } ) ;
318+ expect ( result . first [ 0 ] ) . toMatchObject ( {
319+ type : "compact" ,
320+ compactor : "pruning-compactor" ,
321+ reason : "cache-ttl-recompress" ,
322+ } ) ;
323+ expect ( result . stored . length ) . toBeLessThan ( result . seed . length ) ;
324+ }
325+ } ) ;
267326} ) ;
0 commit comments