Use case
Our chat UI shows a "Worked for Xs" duration label on each assistant turn. Live turns time themselves client-side, but after a reload/rehydrate via reconstructChat + persistence: true there is no way to recover run durations through the library:
ReconstructedChat returns messages (from MessageStore.loadThread → ModelMessage[], no timestamps) and activeRun as a bare { runId } cursor.
- Finished runs never reach the client, even though
RunRecord already carries startedAt/finishedAt in the RunStore contract — the data is sitting in the store the server is already querying.
Today the only options are a parallel app-owned history endpoint (defeats the point of the library owning hydration) or dropping durations on resumed turns (what we chose).
Proposal
Have reconstructChat (optionally?) include the thread's terminal runs — e.g.
interface ReconstructedChat {
messages: Array<UIMessage>
activeRun: { runId: string } | null
runs?: Array<{ runId: string; status: TerminalRunStatus; startedAt: number; finishedAt?: number }>
interrupts: /* … */
}
requiring only a RunStore.listRuns(threadId) (or similar) addition. An opt-in flag on ReconstructChatOptions would keep the default payload unchanged.
Happy to PR this if the shape sounds right.
Versions: @tanstack/ai@0.43.0, @tanstack/ai-persistence@0.1.0, @tanstack/ai-client@0.23.0.
Use case
Our chat UI shows a "Worked for Xs" duration label on each assistant turn. Live turns time themselves client-side, but after a reload/rehydrate via
reconstructChat+persistence: truethere is no way to recover run durations through the library:ReconstructedChatreturnsmessages(fromMessageStore.loadThread→ModelMessage[], no timestamps) andactiveRunas a bare{ runId }cursor.RunRecordalready carriesstartedAt/finishedAtin theRunStorecontract — the data is sitting in the store the server is already querying.Today the only options are a parallel app-owned history endpoint (defeats the point of the library owning hydration) or dropping durations on resumed turns (what we chose).
Proposal
Have
reconstructChat(optionally?) include the thread's terminal runs — e.g.requiring only a
RunStore.listRuns(threadId)(or similar) addition. An opt-in flag onReconstructChatOptionswould keep the default payload unchanged.Happy to PR this if the shape sounds right.
Versions:
@tanstack/ai@0.43.0,@tanstack/ai-persistence@0.1.0,@tanstack/ai-client@0.23.0.