@@ -11,7 +11,7 @@ import { Router, RouterOutlet, NavigationEnd } from '@angular/router';
1111import { takeUntilDestroyed , toSignal } from '@angular/core/rxjs-interop' ;
1212import { filter , map , startWith } from 'rxjs/operators' ;
1313import { agent } from '@ngaf/langgraph' ;
14- import { ChatDebugComponent , ChatInterruptPanelComponent , ChatSubagentsComponent , type InterruptAction } from '@ngaf/chat' ;
14+ import { ChatDebugComponent , ChatInterruptPanelComponent , ChatSubagentsComponent , ChatTimelineSliderComponent , type InterruptAction } from '@ngaf/chat' ;
1515import { ControlPalette } from './control-palette.component' ;
1616import { PalettePersistence } from './palette-persistence.service' ;
1717import { DEMO_AGENT } from './shell-tokens' ;
@@ -28,7 +28,7 @@ function modeFromUrl(url: string): DemoMode {
2828@Component ( {
2929 selector : 'demo-shell' ,
3030 standalone : true ,
31- imports : [ RouterOutlet , ControlPalette , ChatDebugComponent , ChatInterruptPanelComponent , ChatSubagentsComponent ] ,
31+ imports : [ RouterOutlet , ControlPalette , ChatDebugComponent , ChatInterruptPanelComponent , ChatSubagentsComponent , ChatTimelineSliderComponent ] ,
3232 changeDetection : ChangeDetectionStrategy . OnPush ,
3333 templateUrl : './demo-shell.component.html' ,
3434 styleUrl : './demo-shell.component.css' ,
@@ -85,6 +85,8 @@ export class DemoShell {
8585
8686 protected readonly debugOpen = signal < boolean > ( this . persistence . read ( 'debug' ) ?? false ) ;
8787
88+ protected readonly timelineOpen = signal < boolean > ( this . persistence . read ( 'timeline' ) ?? false ) ;
89+
8890 protected readonly modelOptions = signal < readonly { value : string ; label : string } [ ] > ( [
8991 { value : 'gpt-5' , label : 'gpt-5' } ,
9092 { value : 'gpt-5-mini' , label : 'gpt-5-mini' } ,
@@ -181,6 +183,29 @@ export class DemoShell {
181183 this . persistence . write ( 'debug' , next ) ;
182184 }
183185
186+ protected onTimelineChange ( next : boolean ) : void {
187+ this . timelineOpen . set ( next ) ;
188+ this . persistence . write ( 'timeline' , next ) ;
189+ }
190+
191+ protected onTimelineReplay ( checkpointId : string ) : void {
192+ void this . agent . submit ( null as never , { checkpointId } as never ) ;
193+ }
194+
195+ protected async onTimelineFork ( checkpointId : string ) : Promise < void > {
196+ await fetch ( 'http://localhost:2024/threads' , {
197+ method : 'POST' ,
198+ headers : { 'Content-Type' : 'application/json' } ,
199+ body : '{}' ,
200+ } )
201+ . then ( ( r ) => r . json ( ) )
202+ . then ( ( t : { thread_id : string } ) => {
203+ this . threadIdSignal . set ( t . thread_id ) ;
204+ this . persistence . write ( 'threadId' , t . thread_id ) ;
205+ void this . agent . submit ( null as never , { checkpointId } as never ) ;
206+ } ) ;
207+ }
208+
184209 /**
185210 * Clear persisted thread id and drop the signal. The next submit
186211 * causes the SDK to create a fresh thread server-side; onThreadId
0 commit comments