@tanstack/ai-client 0.2.2 → 0.4.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.
- package/README.md +1 -0
- package/dist/esm/chat-client.d.ts +9 -1
- package/dist/esm/chat-client.js +95 -30
- package/dist/esm/chat-client.js.map +1 -1
- package/dist/esm/connection-adapters.d.ts +2 -2
- package/dist/esm/connection-adapters.js +4 -9
- package/dist/esm/connection-adapters.js.map +1 -1
- package/dist/esm/events.d.ts +4 -5
- package/dist/esm/events.js +26 -34
- package/dist/esm/events.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/types.d.ts +8 -0
- package/dist/esm/types.js.map +1 -1
- package/package.json +2 -2
- package/src/chat-client.ts +121 -35
- package/src/connection-adapters.ts +14 -18
- package/src/events.ts +37 -49
- package/src/index.ts +1 -1
- package/src/types.ts +10 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { convertMessagesToModelMessages } from '@tanstack/ai'
|
|
2
1
|
import type { ModelMessage, StreamChunk, UIMessage } from '@tanstack/ai'
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -138,16 +137,15 @@ export function fetchServerSentEvents(
|
|
|
138
137
|
const resolvedOptions =
|
|
139
138
|
typeof options === 'function' ? await options() : options
|
|
140
139
|
|
|
141
|
-
const modelMessages = convertMessagesToModelMessages(messages)
|
|
142
|
-
|
|
143
140
|
const requestHeaders: Record<string, string> = {
|
|
144
141
|
'Content-Type': 'application/json',
|
|
145
142
|
...mergeHeaders(resolvedOptions.headers),
|
|
146
143
|
}
|
|
147
144
|
|
|
148
|
-
//
|
|
145
|
+
// Send messages as-is (UIMessages with parts preserved)
|
|
146
|
+
// Server-side TextEngine handles conversion to ModelMessages
|
|
149
147
|
const requestBody = {
|
|
150
|
-
messages
|
|
148
|
+
messages,
|
|
151
149
|
data,
|
|
152
150
|
...resolvedOptions.body,
|
|
153
151
|
}
|
|
@@ -238,17 +236,15 @@ export function fetchHttpStream(
|
|
|
238
236
|
const resolvedOptions =
|
|
239
237
|
typeof options === 'function' ? await options() : options
|
|
240
238
|
|
|
241
|
-
// Convert UIMessages to ModelMessages if needed
|
|
242
|
-
const modelMessages = convertMessagesToModelMessages(messages)
|
|
243
|
-
|
|
244
239
|
const requestHeaders: Record<string, string> = {
|
|
245
240
|
'Content-Type': 'application/json',
|
|
246
241
|
...mergeHeaders(resolvedOptions.headers),
|
|
247
242
|
}
|
|
248
243
|
|
|
249
|
-
//
|
|
244
|
+
// Send messages as-is (UIMessages with parts preserved)
|
|
245
|
+
// Server-side TextEngine handles conversion to ModelMessages
|
|
250
246
|
const requestBody = {
|
|
251
|
-
messages
|
|
247
|
+
messages,
|
|
252
248
|
data,
|
|
253
249
|
...resolvedOptions.body,
|
|
254
250
|
}
|
|
@@ -302,14 +298,15 @@ export function fetchHttpStream(
|
|
|
302
298
|
*/
|
|
303
299
|
export function stream(
|
|
304
300
|
streamFactory: (
|
|
305
|
-
messages: Array<ModelMessage>,
|
|
301
|
+
messages: Array<UIMessage> | Array<ModelMessage>,
|
|
306
302
|
data?: Record<string, any>,
|
|
307
303
|
) => AsyncIterable<StreamChunk>,
|
|
308
304
|
): ConnectionAdapter {
|
|
309
305
|
return {
|
|
310
306
|
async *connect(messages, data) {
|
|
311
|
-
|
|
312
|
-
|
|
307
|
+
// Pass messages as-is (UIMessages with parts preserved)
|
|
308
|
+
// Server-side chat() handles conversion to ModelMessages
|
|
309
|
+
yield* streamFactory(messages, data)
|
|
313
310
|
},
|
|
314
311
|
}
|
|
315
312
|
}
|
|
@@ -332,16 +329,15 @@ export function stream(
|
|
|
332
329
|
*/
|
|
333
330
|
export function rpcStream(
|
|
334
331
|
rpcCall: (
|
|
335
|
-
messages: Array<ModelMessage>,
|
|
332
|
+
messages: Array<UIMessage> | Array<ModelMessage>,
|
|
336
333
|
data?: Record<string, any>,
|
|
337
334
|
) => AsyncIterable<StreamChunk>,
|
|
338
335
|
): ConnectionAdapter {
|
|
339
336
|
return {
|
|
340
337
|
async *connect(messages, data) {
|
|
341
|
-
|
|
342
|
-
//
|
|
343
|
-
|
|
344
|
-
yield* rpcCall(modelMessages, data)
|
|
338
|
+
// Pass messages as-is (UIMessages with parts preserved)
|
|
339
|
+
// Server-side chat() handles conversion to ModelMessages
|
|
340
|
+
yield* rpcCall(messages, data)
|
|
345
341
|
},
|
|
346
342
|
}
|
|
347
343
|
}
|
package/src/events.ts
CHANGED
|
@@ -17,7 +17,7 @@ export abstract class ChatClientEventEmitter {
|
|
|
17
17
|
*/
|
|
18
18
|
protected abstract emitEvent(
|
|
19
19
|
eventName: string,
|
|
20
|
-
data?: Record<string,
|
|
20
|
+
data?: Record<string, unknown>,
|
|
21
21
|
): void
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -33,14 +33,14 @@ export abstract class ChatClientEventEmitter {
|
|
|
33
33
|
* Emit loading state changed event
|
|
34
34
|
*/
|
|
35
35
|
loadingChanged(isLoading: boolean): void {
|
|
36
|
-
this.emitEvent('client:loading
|
|
36
|
+
this.emitEvent('client:loading:changed', { isLoading })
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
40
|
* Emit error state changed event
|
|
41
41
|
*/
|
|
42
42
|
errorChanged(error: string | null): void {
|
|
43
|
-
this.emitEvent('client:error
|
|
43
|
+
this.emitEvent('client:error:changed', {
|
|
44
44
|
error,
|
|
45
45
|
})
|
|
46
46
|
}
|
|
@@ -49,12 +49,8 @@ export abstract class ChatClientEventEmitter {
|
|
|
49
49
|
* Emit text update events (combines processor and client events)
|
|
50
50
|
*/
|
|
51
51
|
textUpdated(streamId: string, messageId: string, content: string): void {
|
|
52
|
-
this.emitEvent('
|
|
52
|
+
this.emitEvent('text:chunk:content', {
|
|
53
53
|
streamId,
|
|
54
|
-
content,
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
this.emitEvent('client:assistant-message-updated', {
|
|
58
54
|
messageId,
|
|
59
55
|
content,
|
|
60
56
|
})
|
|
@@ -71,15 +67,8 @@ export abstract class ChatClientEventEmitter {
|
|
|
71
67
|
state: string,
|
|
72
68
|
args: string,
|
|
73
69
|
): void {
|
|
74
|
-
this.emitEvent('
|
|
70
|
+
this.emitEvent('tools:call:updated', {
|
|
75
71
|
streamId,
|
|
76
|
-
toolCallId,
|
|
77
|
-
toolName,
|
|
78
|
-
state,
|
|
79
|
-
arguments: args,
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
this.emitEvent('client:tool-call-updated', {
|
|
83
72
|
messageId,
|
|
84
73
|
toolCallId,
|
|
85
74
|
toolName,
|
|
@@ -91,22 +80,6 @@ export abstract class ChatClientEventEmitter {
|
|
|
91
80
|
/**
|
|
92
81
|
* Emit tool result state change event
|
|
93
82
|
*/
|
|
94
|
-
toolResultStateChanged(
|
|
95
|
-
streamId: string,
|
|
96
|
-
toolCallId: string,
|
|
97
|
-
content: string,
|
|
98
|
-
state: string,
|
|
99
|
-
error?: string,
|
|
100
|
-
): void {
|
|
101
|
-
this.emitEvent('processor:tool-result-state-changed', {
|
|
102
|
-
streamId,
|
|
103
|
-
toolCallId,
|
|
104
|
-
content,
|
|
105
|
-
state,
|
|
106
|
-
error,
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
83
|
/**
|
|
111
84
|
* Emit thinking update event
|
|
112
85
|
*/
|
|
@@ -116,7 +89,7 @@ export abstract class ChatClientEventEmitter {
|
|
|
116
89
|
content: string,
|
|
117
90
|
delta?: string,
|
|
118
91
|
): void {
|
|
119
|
-
this.emitEvent('
|
|
92
|
+
this.emitEvent('text:chunk:thinking', {
|
|
120
93
|
streamId,
|
|
121
94
|
messageId,
|
|
122
95
|
content,
|
|
@@ -128,13 +101,15 @@ export abstract class ChatClientEventEmitter {
|
|
|
128
101
|
* Emit approval requested event
|
|
129
102
|
*/
|
|
130
103
|
approvalRequested(
|
|
104
|
+
streamId: string,
|
|
131
105
|
messageId: string,
|
|
132
106
|
toolCallId: string,
|
|
133
107
|
toolName: string,
|
|
134
|
-
input:
|
|
108
|
+
input: unknown,
|
|
135
109
|
approvalId: string,
|
|
136
110
|
): void {
|
|
137
|
-
this.emitEvent('
|
|
111
|
+
this.emitEvent('tools:approval:requested', {
|
|
112
|
+
streamId,
|
|
138
113
|
messageId,
|
|
139
114
|
toolCallId,
|
|
140
115
|
toolName,
|
|
@@ -146,17 +121,18 @@ export abstract class ChatClientEventEmitter {
|
|
|
146
121
|
/**
|
|
147
122
|
* Emit message appended event
|
|
148
123
|
*/
|
|
149
|
-
messageAppended(uiMessage: UIMessage): void {
|
|
150
|
-
const
|
|
151
|
-
.filter((
|
|
152
|
-
.map((
|
|
124
|
+
messageAppended(uiMessage: UIMessage, streamId?: string): void {
|
|
125
|
+
const content = uiMessage.parts
|
|
126
|
+
.filter((part) => part.type === 'text')
|
|
127
|
+
.map((part) => part.content)
|
|
153
128
|
.join(' ')
|
|
154
|
-
.substring(0, 100)
|
|
155
129
|
|
|
156
|
-
this.emitEvent('
|
|
130
|
+
this.emitEvent('text:message:created', {
|
|
131
|
+
streamId,
|
|
157
132
|
messageId: uiMessage.id,
|
|
158
133
|
role: uiMessage.role,
|
|
159
|
-
|
|
134
|
+
content,
|
|
135
|
+
parts: uiMessage.parts,
|
|
160
136
|
})
|
|
161
137
|
}
|
|
162
138
|
|
|
@@ -164,8 +140,15 @@ export abstract class ChatClientEventEmitter {
|
|
|
164
140
|
* Emit message sent event
|
|
165
141
|
*/
|
|
166
142
|
messageSent(messageId: string, content: string): void {
|
|
167
|
-
this.emitEvent('
|
|
143
|
+
this.emitEvent('text:message:created', {
|
|
144
|
+
messageId,
|
|
145
|
+
role: 'user',
|
|
146
|
+
content,
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
this.emitEvent('text:message:user', {
|
|
168
150
|
messageId,
|
|
151
|
+
role: 'user',
|
|
169
152
|
content,
|
|
170
153
|
})
|
|
171
154
|
}
|
|
@@ -190,7 +173,7 @@ export abstract class ChatClientEventEmitter {
|
|
|
190
173
|
* Emit messages cleared event
|
|
191
174
|
*/
|
|
192
175
|
messagesCleared(): void {
|
|
193
|
-
this.emitEvent('client:messages
|
|
176
|
+
this.emitEvent('client:messages:cleared')
|
|
194
177
|
}
|
|
195
178
|
|
|
196
179
|
/**
|
|
@@ -199,10 +182,10 @@ export abstract class ChatClientEventEmitter {
|
|
|
199
182
|
toolResultAdded(
|
|
200
183
|
toolCallId: string,
|
|
201
184
|
toolName: string,
|
|
202
|
-
output:
|
|
185
|
+
output: unknown,
|
|
203
186
|
state: string,
|
|
204
187
|
): void {
|
|
205
|
-
this.emitEvent('
|
|
188
|
+
this.emitEvent('tools:result:added', {
|
|
206
189
|
toolCallId,
|
|
207
190
|
toolName,
|
|
208
191
|
output,
|
|
@@ -218,7 +201,7 @@ export abstract class ChatClientEventEmitter {
|
|
|
218
201
|
toolCallId: string,
|
|
219
202
|
approved: boolean,
|
|
220
203
|
): void {
|
|
221
|
-
this.emitEvent('
|
|
204
|
+
this.emitEvent('tools:approval:responded', {
|
|
222
205
|
approvalId,
|
|
223
206
|
toolCallId,
|
|
224
207
|
approved,
|
|
@@ -235,14 +218,19 @@ export class DefaultChatClientEventEmitter extends ChatClientEventEmitter {
|
|
|
235
218
|
*/
|
|
236
219
|
protected emitEvent(eventName: string, data?: Record<string, any>): void {
|
|
237
220
|
// For client:* and tool:* events, automatically add clientId and timestamp
|
|
238
|
-
if (
|
|
221
|
+
if (
|
|
222
|
+
eventName.startsWith('client:') ||
|
|
223
|
+
eventName.startsWith('tools:') ||
|
|
224
|
+
eventName.startsWith('text:')
|
|
225
|
+
) {
|
|
239
226
|
aiEventClient.emit(eventName as any, {
|
|
240
227
|
...data,
|
|
241
228
|
clientId: this.clientId,
|
|
229
|
+
source: 'client',
|
|
242
230
|
timestamp: Date.now(),
|
|
243
231
|
})
|
|
244
232
|
} else {
|
|
245
|
-
// For other events
|
|
233
|
+
// For other events, just add timestamp
|
|
246
234
|
aiEventClient.emit(eventName as any, {
|
|
247
235
|
...data,
|
|
248
236
|
timestamp: Date.now(),
|
package/src/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type {
|
|
|
11
11
|
ChatClientOptions,
|
|
12
12
|
ChatRequestBody,
|
|
13
13
|
InferChatMessages,
|
|
14
|
+
ChatClientState,
|
|
14
15
|
} from './types'
|
|
15
16
|
export { clientTools, createChatClientOptions } from './types'
|
|
16
17
|
export type {
|
|
@@ -51,7 +52,6 @@ export {
|
|
|
51
52
|
defaultJSONParser,
|
|
52
53
|
type ChunkStrategy,
|
|
53
54
|
type StreamProcessorOptions,
|
|
54
|
-
type StreamProcessorHandlers,
|
|
55
55
|
type StreamProcessorEvents,
|
|
56
56
|
type InternalToolCallState,
|
|
57
57
|
type ToolCallState,
|
package/src/types.ts
CHANGED
|
@@ -26,6 +26,11 @@ export type ToolResultState =
|
|
|
26
26
|
| 'complete' // Result is complete
|
|
27
27
|
| 'error' // Error occurred
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* ChatClient state - track the lifecycle of a chat
|
|
31
|
+
*/
|
|
32
|
+
export type ChatClientState = 'ready' | 'submitted' | 'streaming' | 'error'
|
|
33
|
+
|
|
29
34
|
/**
|
|
30
35
|
* Message parts - building blocks of UIMessage
|
|
31
36
|
*/
|
|
@@ -191,6 +196,11 @@ export interface ChatClientOptions<
|
|
|
191
196
|
*/
|
|
192
197
|
onErrorChange?: (error: Error | undefined) => void
|
|
193
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Callback when chat status changes
|
|
201
|
+
*/
|
|
202
|
+
onStatusChange?: (status: ChatClientState) => void
|
|
203
|
+
|
|
194
204
|
/**
|
|
195
205
|
* Client-side tools with execution logic
|
|
196
206
|
* When provided, tools with execute functions will be called automatically
|