@@ -613,6 +613,14 @@ function checkpointByRunId(
613613 return map ;
614614}
615615
616+ function timestampFromIso ( value : string | undefined ) : number | undefined {
617+ if ( ! value ) {
618+ return undefined ;
619+ }
620+ const parsed = Date . parse ( value ) ;
621+ return Number . isFinite ( parsed ) ? parsed : undefined ;
622+ }
623+
616624function runStatusFromCheckpoint (
617625 checkpoint : ConversationCheckpointDto | undefined ,
618626) : LiveRun [ "runStatus" ] | undefined {
@@ -1273,11 +1281,25 @@ function applyConversationToolCall(state: LiveRun, toolCall: ConversationToolCal
12731281function finalizeHydratedRunSegment (
12741282 state : LiveRun ,
12751283 tools : ConversationToolCallDto [ ] ,
1284+ checkpoint : ConversationCheckpointDto | undefined ,
12761285) : LiveRun {
1286+ const checkpointStatus = runStatusFromCheckpoint ( checkpoint ) ;
1287+ if ( checkpointStatus === "running" || checkpointStatus === "queued" ) {
1288+ return state ;
1289+ }
1290+ if ( checkpointStatus === "failed" ) {
1291+ return reduceLiveRunEvent ( state , {
1292+ type : "RUN_ERROR" ,
1293+ message : checkpoint ?. errorMessage ?. trim ( ) || ORPHANED_RUN_ASSISTANT_PLACEHOLDER ,
1294+ } ) ;
1295+ }
1296+ if ( checkpointStatus === "canceled" ) {
1297+ return reduceLiveRunEvent ( state , { type : "RUN_FINISHED" , status : "canceled" } ) ;
1298+ }
12771299 if ( tools . length === 0 ) {
12781300 return state ;
12791301 }
1280- if ( isPendingCollaborationRunEnd ( tools ) ) {
1302+ if ( checkpointStatus === "suspended" || isPendingCollaborationRunEnd ( tools ) ) {
12811303 let next = reduceLiveRunEvent ( state , {
12821304 type : "STATE_DELTA" ,
12831305 delta : [ { op : "replace" , path : "/runStatus" , value : "suspended" } ] ,
@@ -1291,9 +1313,9 @@ function finalizeHydratedRunSegment(
12911313function finalizeMessageOnlyHydratedRunSegment (
12921314 state : LiveRun ,
12931315 segment : RestorableRunSegment ,
1316+ checkpoint : ConversationCheckpointDto | undefined ,
12941317 dto : SessionConversationDto ,
12951318) : LiveRun {
1296- const checkpoint = checkpointByRunId ( dto ) . get ( segment . runId ) ;
12971319 const checkpointStatus = runStatusFromCheckpoint ( checkpoint ) ;
12981320 if ( checkpointStatus === "running" || checkpointStatus === "queued" ) {
12991321 return state ;
@@ -1305,7 +1327,7 @@ function finalizeMessageOnlyHydratedRunSegment(
13051327 } ) ;
13061328 }
13071329 if ( checkpointStatus === "canceled" ) {
1308- return reduceLiveRunEvent ( state , { type : "RUN_FINISHED" } ) ;
1330+ return reduceLiveRunEvent ( state , { type : "RUN_FINISHED" , status : "canceled" } ) ;
13091331 }
13101332 if ( segment . hasUser && ! segment . hasAssistant ) {
13111333 return reduceLiveRunEvent ( state , {
@@ -1316,6 +1338,22 @@ function finalizeMessageOnlyHydratedRunSegment(
13161338 return reduceLiveRunEvent ( state , { type : "RUN_FINISHED" } ) ;
13171339}
13181340
1341+ function applyHydratedRunCheckpointTiming (
1342+ state : LiveRun ,
1343+ checkpoint : ConversationCheckpointDto | undefined ,
1344+ ) : LiveRun {
1345+ const startedAt = timestampFromIso ( checkpoint ?. startedAt ) ;
1346+ const finishedAt = timestampFromIso ( checkpoint ?. finishedAt ) ;
1347+ if ( startedAt === undefined && finishedAt === undefined ) {
1348+ return state ;
1349+ }
1350+ return {
1351+ ...state ,
1352+ ...( startedAt !== undefined ? { runStartedAt : startedAt } : { } ) ,
1353+ ...( finishedAt !== undefined ? { runFinishedAt : finishedAt } : { } ) ,
1354+ } ;
1355+ }
1356+
13191357function startNextHydratedRunGroup ( state : LiveRun , runId ?: string ) : LiveRun {
13201358 if ( state . runStatus === "suspended" ) {
13211359 const archived : LiveRun = {
@@ -1470,9 +1508,11 @@ export function hydrateLiveRunFromConversation(
14701508 }
14711509
14721510 const runSegments = collectRestorableRunSegments ( dto ) ;
1511+ const checkpoints = checkpointByRunId ( dto ) ;
14731512
14741513 let next = createInitialLiveRun ( ) ;
14751514 for ( const [ index , segment ] of runSegments . entries ( ) ) {
1515+ const checkpoint = checkpoints . get ( segment . runId ) ;
14761516 next =
14771517 index === 0
14781518 ? reduceLiveRunEvent ( next , { type : "RUN_STARTED" , runId : segment . runId } )
@@ -1486,8 +1526,9 @@ export function hydrateLiveRunFromConversation(
14861526
14871527 next =
14881528 segment . tools . length > 0
1489- ? finalizeHydratedRunSegment ( next , segment . tools )
1490- : finalizeMessageOnlyHydratedRunSegment ( next , segment , dto ) ;
1529+ ? finalizeHydratedRunSegment ( next , segment . tools , checkpoint )
1530+ : finalizeMessageOnlyHydratedRunSegment ( next , segment , checkpoint , dto ) ;
1531+ next = applyHydratedRunCheckpointTiming ( next , checkpoint ) ;
14911532 }
14921533
14931534 next = reconcileLiveRunArtifacts ( mergePreservedLiveRunSessionData ( state , next ) ) ;
0 commit comments