@@ -437,6 +437,8 @@ interface ContextDebuggerProps {
437437 onNavigateToContext ?: ( contextId : string ) => void ;
438438}
439439
440+ const TURNS_PAGE_SIZE = 100 ;
441+
440442export function ContextDebugger ( { contextId, isOpen, onClose, lastEvent, initialTurnId, onTurnChange, onNavigateToContext } : ContextDebuggerProps ) {
441443 const containerRef = useRef < HTMLDivElement | null > ( null ) ;
442444 const turnListRef = useRef < HTMLDivElement | null > ( null ) ;
@@ -447,6 +449,7 @@ export function ContextDebugger({ contextId, isOpen, onClose, lastEvent, initial
447449
448450 // Data fetching state
449451 const [ loading , setLoading ] = useState ( false ) ;
452+ const [ loadingMore , setLoadingMore ] = useState ( false ) ;
450453 const [ error , setError ] = useState < string | null > ( null ) ;
451454 const [ data , setData ] = useState < TurnResponse | null > ( null ) ;
452455
@@ -474,7 +477,7 @@ export function ContextDebugger({ contextId, isOpen, onClose, lastEvent, initial
474477
475478 try {
476479 const response = await fetchTurns ( contextId , {
477- limit : 100 ,
480+ limit : TURNS_PAGE_SIZE ,
478481 view : 'typed' ,
479482 include_unknown : true ,
480483 } ) ;
@@ -491,6 +494,32 @@ export function ContextDebugger({ contextId, isOpen, onClose, lastEvent, initial
491494 }
492495 } , [ contextId ] ) ;
493496
497+ // Load older turns using pagination cursor
498+ const loadMore = useCallback ( async ( ) => {
499+ if ( ! contextId || ! data ?. next_before_turn_id ) return ;
500+
501+ setLoadingMore ( true ) ;
502+ try {
503+ const response = await fetchTurns ( contextId , {
504+ limit : TURNS_PAGE_SIZE ,
505+ before_turn_id : data . next_before_turn_id ,
506+ view : 'typed' ,
507+ include_unknown : true ,
508+ } ) ;
509+ const prepended = response . turns . length ;
510+ setData ( prev => prev ? {
511+ ...prev ,
512+ turns : [ ...response . turns , ...prev . turns ] ,
513+ next_before_turn_id : response . next_before_turn_id ,
514+ } : response ) ;
515+ setSelectedIdx ( prev => prev + prepended ) ;
516+ } catch {
517+ // Keep existing data on failure
518+ } finally {
519+ setLoadingMore ( false ) ;
520+ }
521+ } , [ contextId , data ?. next_before_turn_id ] ) ;
522+
494523 useEffect ( ( ) => {
495524 if ( isOpen && contextId ) {
496525 loadTurns ( ) ;
@@ -617,7 +646,7 @@ export function ContextDebugger({ contextId, isOpen, onClose, lastEvent, initial
617646
618647 // Count stats - count both tool_call turns AND tool_calls embedded in assistant turns
619648 const stats = useMemo ( ( ) => {
620- if ( ! data ?. turns ) return { total : 0 , toolCalls : 0 , errors : 0 } ;
649+ if ( ! data ?. turns ) return { total : 0 , loaded : 0 , toolCalls : 0 , errors : 0 } ;
621650 let toolCalls = 0 ;
622651 let errors = 0 ;
623652 for ( const turn of data . turns ) {
@@ -632,7 +661,8 @@ export function ContextDebugger({ contextId, isOpen, onClose, lastEvent, initial
632661 const result = extractToolResult ( turn ) ;
633662 if ( result ?. isError ) errors ++ ;
634663 }
635- return { total : data . turns . length , toolCalls, errors } ;
664+ const totalDepth = ( data . meta ?. head_depth ?? - 1 ) + 1 ;
665+ return { total : totalDepth , loaded : data . turns . length , toolCalls, errors } ;
636666 } , [ data ] ) ;
637667
638668 // Auto-select last turn when following and new turns arrive
@@ -759,7 +789,7 @@ export function ContextDebugger({ contextId, isOpen, onClose, lastEvent, initial
759789 </ div >
760790 { data && (
761791 < div className = "flex items-center gap-3 text-xs text-theme-text-dim" >
762- < span > { stats . total } turns</ span >
792+ < span > { stats . loaded < stats . total ? ` ${ stats . loaded } of ${ stats . total } turns` : ` ${ stats . total } turns` } </ span >
763793 < span > { stats . toolCalls } tool calls</ span >
764794 { stats . errors > 0 && (
765795 < span className = "text-red-400" > { stats . errors } errors</ span >
@@ -836,7 +866,17 @@ export function ContextDebugger({ contextId, isOpen, onClose, lastEvent, initial
836866 { data ?. turns . length === 0 ? 'No turns.' : 'No matches.' }
837867 </ div >
838868 ) : (
839- filteredTurns . map ( ( turn , idx ) => {
869+ < >
870+ { data && data . turns . length > 0 && data . turns [ 0 ] . depth > 0 && (
871+ < button
872+ onClick = { loadMore }
873+ disabled = { loadingMore }
874+ className = "w-full px-3 py-2 text-xs text-theme-accent hover:bg-theme-bg-tertiary/40 border-b border-theme-border-dim/60 transition-colors disabled:opacity-50"
875+ >
876+ { loadingMore ? 'Loading...' : `Load older turns (${ data . turns [ 0 ] . depth } remaining)` }
877+ </ button >
878+ ) }
879+ { filteredTurns . map ( ( turn , idx ) => {
840880 const kind = detectTurnKind ( turn ) ;
841881 const colors = getKindColors ( kind ) ;
842882 const isSelected = idx === selectedIdx ;
@@ -880,7 +920,8 @@ export function ContextDebugger({ contextId, isOpen, onClose, lastEvent, initial
880920 </ div >
881921 </ button >
882922 ) ;
883- } )
923+ } ) }
924+ </ >
884925 ) }
885926
886927 { /* Resume following indicator */ }
0 commit comments