@@ -220,6 +220,7 @@ const COMPOSIO_CONNECTORS_PAGE_LIMIT_MAX = 1000
220220const PROVIDER_MODELS_FETCH_TIMEOUT_MS = 5_000
221221
222222const THREAD_RESPONSE_TURN_LIMIT = 10
223+ const THREAD_TURN_PAGE_READ_CACHE_TTL_MS = 30_000
223224const THREAD_METHODS_WITH_TURNS = new Set ( [ 'thread/read' , 'thread/resume' , 'thread/fork' , 'thread/rollback' ] )
224225const THREAD_SEARCH_FULL_TEXT_THREAD_LIMIT = 100
225226const PROJECTLESS_THREAD_DIRECTORY_MAX_ATTEMPTS = 100
@@ -4292,6 +4293,8 @@ class AppServerProcess {
42924293 private readonly appServerArgs = buildAppServerArgs ( )
42934294 private readonly streamEventsByThreadId = new Map < string , StreamEventFrame [ ] > ( )
42944295 private readonly lastThreadReadSnapshotByThreadId = new Map < string , unknown > ( )
4296+ private readonly threadTurnPageReadCacheByThreadId = new Map < string , { result : unknown ; expiresAt : number } > ( )
4297+ private readonly threadTurnPageReadPromiseByThreadId = new Map < string , Promise < unknown > > ( )
42954298 private readonly capturedItemsByThreadId = new Map < string , Map < string , CapturedItem > > ( )
42964299 private readonly liveStateCache = new Map < string , { data : unknown ; turnCount : number ; sessionSize : number } > ( )
42974300 private chatgptAuthRefreshPromise : Promise < ChatgptAuthTokensRefreshResponse > | null = null
@@ -4427,7 +4430,10 @@ class AppServerProcess {
44274430 this . recordStreamEvent ( notification )
44284431 this . captureItemFromNotification ( notification )
44294432 const nThreadId = this . extractThreadIdFromParams ( notification . params )
4430- if ( nThreadId ) this . invalidateLiveStateCache ( nThreadId )
4433+ if ( nThreadId ) {
4434+ this . invalidateLiveStateCache ( nThreadId )
4435+ this . threadTurnPageReadCacheByThreadId . delete ( nThreadId )
4436+ }
44314437 for ( const listener of this . notificationListeners ) {
44324438 listener ( notification )
44334439 }
@@ -4481,12 +4487,39 @@ class AppServerProcess {
44814487
44824488 storeThreadReadSnapshot ( threadId : string , snapshot : unknown ) : void {
44834489 this . lastThreadReadSnapshotByThreadId . set ( threadId , snapshot )
4490+ this . threadTurnPageReadCacheByThreadId . delete ( threadId )
44844491 }
44854492
44864493 getLastThreadReadSnapshot ( threadId : string ) : unknown | null {
44874494 return this . lastThreadReadSnapshotByThreadId . get ( threadId ) ?? null
44884495 }
44894496
4497+ async readThreadForTurnPage ( threadId : string ) : Promise < unknown > {
4498+ const now = Date . now ( )
4499+ const cached = this . threadTurnPageReadCacheByThreadId . get ( threadId )
4500+ if ( cached && cached . expiresAt > now ) return cached . result
4501+ if ( cached ) this . threadTurnPageReadCacheByThreadId . delete ( threadId )
4502+
4503+ const pending = this . threadTurnPageReadPromiseByThreadId . get ( threadId )
4504+ if ( pending ) return pending
4505+
4506+ const promise = this . rpc ( 'thread/read' , {
4507+ threadId,
4508+ includeTurns : true ,
4509+ } ) . then ( ( result ) => {
4510+ this . threadTurnPageReadCacheByThreadId . set ( threadId , {
4511+ result,
4512+ expiresAt : Date . now ( ) + THREAD_TURN_PAGE_READ_CACHE_TTL_MS ,
4513+ } )
4514+ return result
4515+ } ) . finally ( ( ) => {
4516+ this . threadTurnPageReadPromiseByThreadId . delete ( threadId )
4517+ } )
4518+
4519+ this . threadTurnPageReadPromiseByThreadId . set ( threadId , promise )
4520+ return promise
4521+ }
4522+
44904523 cacheLiveState ( threadId : string , data : unknown , turnCount : number , sessionSize : number ) : void {
44914524 this . liveStateCache . set ( threadId , { data, turnCount, sessionSize } )
44924525 }
@@ -5786,10 +5819,7 @@ export function createCodexBridgeMiddleware(): CodexBridgeMiddleware {
57865819 return
57875820 }
57885821
5789- const threadReadResult = await appServer . rpc ( 'thread/read' , {
5790- threadId,
5791- includeTurns : true ,
5792- } )
5822+ const threadReadResult = await appServer . readThreadForTurnPage ( threadId )
57935823 const record = asRecord ( threadReadResult )
57945824 const thread = asRecord ( record ?. thread )
57955825 if ( ! record || ! thread ) {
@@ -5801,7 +5831,22 @@ export function createCodexBridgeMiddleware(): CodexBridgeMiddleware {
58015831 const beforeIndex = beforeTurnId
58025832 ? turns . findIndex ( ( turn ) => asRecord ( turn ) ?. id === beforeTurnId )
58035833 : turns . length
5804- const endIndex = beforeIndex >= 0 ? beforeIndex : turns . length
5834+ if ( beforeTurnId && beforeIndex < 0 ) {
5835+ setJson ( res , 200 , {
5836+ result : {
5837+ ...record ,
5838+ thread : {
5839+ ...thread ,
5840+ turns : [ ] ,
5841+ } ,
5842+ } ,
5843+ startTurnIndex : 0 ,
5844+ hasMoreOlder : false ,
5845+ } )
5846+ return
5847+ }
5848+
5849+ const endIndex = beforeIndex
58055850 const startIndex = Math . max ( 0 , endIndex - limit )
58065851 const pageTurns = turns . slice ( startIndex , endIndex )
58075852 const pagedResult = {
0 commit comments