@tanstack/ai-client 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ import type { UIMessage } from './types'
2
+
3
+ function validDate(value: unknown): Date | undefined {
4
+ if (value instanceof Date)
5
+ return Number.isNaN(value.getTime()) ? undefined : value
6
+ if (typeof value !== 'string') return undefined
7
+ const date = new Date(value)
8
+ return Number.isNaN(date.getTime()) ? undefined : date
9
+ }
10
+
11
+ export function normalizeMessageDates(message: UIMessage): UIMessage {
12
+ const messageDate = validDate(message.createdAt)
13
+ const parts = message.parts.map((part) => {
14
+ if (part.type !== 'tool-result') return part
15
+ const date = validDate(part.createdAt)
16
+ const { createdAt: _ignored, ...rest } = part
17
+ return date ? { ...rest, createdAt: date } : rest
18
+ })
19
+ const { createdAt: _ignored, ...rest } = message
20
+ return messageDate
21
+ ? { ...rest, parts, createdAt: messageDate }
22
+ : { ...rest, parts }
23
+ }
24
+
25
+ export function normalizeMessagesDates(
26
+ messages: Array<UIMessage>,
27
+ ): Array<UIMessage> {
28
+ return messages.map(normalizeMessageDates)
29
+ }
@@ -1,4 +1,5 @@
1
- import type { ChatPersistedState, ChatStorageAdapter } from './types'
1
+ import type { ChatPersistedState, ChatStorageAdapter, UIMessage } from './types'
2
+ import { normalizeMessagesDates } from './message-date-normalizer'
2
3
 
3
4
  export interface WebStoragePersistenceOptions {
4
5
  keyPrefix?: string
@@ -45,6 +46,16 @@ function stringifyJson(value: ChatPersistedState): string {
45
46
  return serialized
46
47
  }
47
48
 
49
+ function reviveMessageCreatedAt(message: UIMessage): UIMessage {
50
+ return normalizeMessagesDates([message]).at(0) ?? message
51
+ }
52
+
53
+ function revivePersistedState(state: ChatPersistedState): ChatPersistedState {
54
+ if (state == null || typeof state !== 'object') return state
55
+ if (!Array.isArray(state.messages)) return state
56
+ return { ...state, messages: state.messages.map(reviveMessageCreatedAt) }
57
+ }
58
+
48
59
  function createWebStoragePersistence(
49
60
  storageName: 'localStorage' | 'sessionStorage',
50
61
  options: WebStoragePersistenceOptions,
@@ -69,7 +80,7 @@ function createWebStoragePersistence(
69
80
  return {
70
81
  getItem(id) {
71
82
  const item = getStorage().getItem(key(id))
72
- return item === null ? null : deserialize(item)
83
+ return item === null ? null : revivePersistedState(deserialize(item))
73
84
  },
74
85
  setItem(id, value) {
75
86
  getStorage().setItem(key(id), serialize(value))
package/src/types.ts CHANGED
@@ -595,10 +595,14 @@ export type ToolCallPart<TTools extends ReadonlyArray<AnyClientTool> = any> =
595
595
 
596
596
  export interface ToolResultPart {
597
597
  type: 'tool-result'
598
+ id?: string
599
+ name?: string
598
600
  toolCallId: string
599
601
  content: string | Array<ContentPart>
600
602
  state: ToolResultState
601
603
  error?: string // Error message if state is "error"
604
+ metadata?: Record<string, unknown>
605
+ createdAt?: Date
602
606
  }
603
607
 
604
608
  export interface ThinkingPart {
@@ -639,6 +643,7 @@ export interface UIMessage<
639
643
  > {
640
644
  id: string
641
645
  role: 'system' | 'user' | 'assistant'
646
+ name?: string
642
647
  parts: Array<MessagePart<TTools, TData>>
643
648
  createdAt?: Date
644
649
  /**