@tanstack/ai 0.0.1

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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/dist/esm/base-adapter.d.ts +35 -0
  4. package/dist/esm/base-adapter.js +12 -0
  5. package/dist/esm/base-adapter.js.map +1 -0
  6. package/dist/esm/core/chat-common-options.d.ts +52 -0
  7. package/dist/esm/core/chat.d.ts +30 -0
  8. package/dist/esm/core/chat.js +533 -0
  9. package/dist/esm/core/chat.js.map +1 -0
  10. package/dist/esm/core/embedding.d.ts +8 -0
  11. package/dist/esm/core/embedding.js +33 -0
  12. package/dist/esm/core/embedding.js.map +1 -0
  13. package/dist/esm/core/summarize.d.ts +9 -0
  14. package/dist/esm/core/summarize.js +36 -0
  15. package/dist/esm/core/summarize.js.map +1 -0
  16. package/dist/esm/event-client.d.ts +311 -0
  17. package/dist/esm/event-client.js +62 -0
  18. package/dist/esm/event-client.js.map +1 -0
  19. package/dist/esm/index.d.ts +16 -0
  20. package/dist/esm/index.js +50 -0
  21. package/dist/esm/index.js.map +1 -0
  22. package/dist/esm/message-converters.d.ts +52 -0
  23. package/dist/esm/message-converters.js +162 -0
  24. package/dist/esm/message-converters.js.map +1 -0
  25. package/dist/esm/stream/index.d.ts +11 -0
  26. package/dist/esm/stream/json-parser.d.ts +38 -0
  27. package/dist/esm/stream/json-parser.js +28 -0
  28. package/dist/esm/stream/json-parser.js.map +1 -0
  29. package/dist/esm/stream/message-updaters.d.ts +44 -0
  30. package/dist/esm/stream/message-updaters.js +141 -0
  31. package/dist/esm/stream/message-updaters.js.map +1 -0
  32. package/dist/esm/stream/processor.d.ts +242 -0
  33. package/dist/esm/stream/processor.js +693 -0
  34. package/dist/esm/stream/processor.js.map +1 -0
  35. package/dist/esm/stream/strategies.d.ts +43 -0
  36. package/dist/esm/stream/strategies.js +54 -0
  37. package/dist/esm/stream/strategies.js.map +1 -0
  38. package/dist/esm/stream/types.d.ts +71 -0
  39. package/dist/esm/tools/tool-calls.d.ts +112 -0
  40. package/dist/esm/tools/tool-calls.js +302 -0
  41. package/dist/esm/tools/tool-calls.js.map +1 -0
  42. package/dist/esm/tools/tool-definition.d.ts +125 -0
  43. package/dist/esm/tools/tool-definition.js +25 -0
  44. package/dist/esm/tools/tool-definition.js.map +1 -0
  45. package/dist/esm/tools/zod-converter.d.ts +30 -0
  46. package/dist/esm/tools/zod-converter.js +36 -0
  47. package/dist/esm/tools/zod-converter.js.map +1 -0
  48. package/dist/esm/types.d.ts +619 -0
  49. package/dist/esm/utilities/agent-loop-strategies.d.ts +59 -0
  50. package/dist/esm/utilities/agent-loop-strategies.js +23 -0
  51. package/dist/esm/utilities/agent-loop-strategies.js.map +1 -0
  52. package/dist/esm/utilities/chat-options.d.ts +6 -0
  53. package/dist/esm/utilities/chat-options.js +7 -0
  54. package/dist/esm/utilities/chat-options.js.map +1 -0
  55. package/dist/esm/utilities/messages.d.ts +30 -0
  56. package/dist/esm/utilities/messages.js +7 -0
  57. package/dist/esm/utilities/messages.js.map +1 -0
  58. package/dist/esm/utilities/stream-to-response.d.ts +48 -0
  59. package/dist/esm/utilities/stream-to-response.js +62 -0
  60. package/dist/esm/utilities/stream-to-response.js.map +1 -0
  61. package/package.json +65 -0
  62. package/src/base-adapter.ts +85 -0
  63. package/src/core/chat-common-options.ts +55 -0
  64. package/src/core/chat.ts +771 -0
  65. package/src/core/embedding.ts +54 -0
  66. package/src/core/summarize.ts +56 -0
  67. package/src/event-client.ts +389 -0
  68. package/src/index.ts +68 -0
  69. package/src/message-converters.ts +285 -0
  70. package/src/stream/index.ts +41 -0
  71. package/src/stream/json-parser.ts +58 -0
  72. package/src/stream/message-updaters.ts +275 -0
  73. package/src/stream/processor.ts +1092 -0
  74. package/src/stream/strategies.ts +78 -0
  75. package/src/stream/types.ts +94 -0
  76. package/src/tools/tool-calls.ts +471 -0
  77. package/src/tools/tool-definition.ts +206 -0
  78. package/src/tools/zod-converter.ts +85 -0
  79. package/src/types.ts +872 -0
  80. package/src/utilities/agent-loop-strategies.ts +85 -0
  81. package/src/utilities/chat-options.ts +35 -0
  82. package/src/utilities/messages.ts +63 -0
  83. package/src/utilities/stream-to-response.ts +116 -0
@@ -0,0 +1,54 @@
1
+ import { aiEventClient } from '../event-client.js'
2
+ import type {
3
+ AIAdapter,
4
+ EmbeddingOptions,
5
+ EmbeddingResult,
6
+ ExtractModelsFromAdapter,
7
+ } from '../types'
8
+
9
+ function createId(prefix: string): string {
10
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
11
+ }
12
+
13
+ /**
14
+ * Standalone embedding function with type inference from adapter
15
+ */
16
+ export async function embedding<
17
+ TAdapter extends AIAdapter<any, any, any, any, any>,
18
+ >(
19
+ options: Omit<EmbeddingOptions, 'model'> & {
20
+ adapter: TAdapter
21
+ model: ExtractModelsFromAdapter<TAdapter>
22
+ },
23
+ ): Promise<EmbeddingResult> {
24
+ const { adapter, model, ...restOptions } = options
25
+ const requestId = createId('embedding')
26
+ const inputCount = Array.isArray(restOptions.input)
27
+ ? restOptions.input.length
28
+ : 1
29
+ const startTime = Date.now()
30
+
31
+ aiEventClient.emit('embedding:started', {
32
+ requestId,
33
+ model: model as string,
34
+ inputCount,
35
+ timestamp: startTime,
36
+ })
37
+
38
+ const result = await adapter.createEmbeddings({
39
+ ...restOptions,
40
+ model: model as string,
41
+ })
42
+
43
+ const duration = Date.now() - startTime
44
+
45
+ aiEventClient.emit('embedding:completed', {
46
+ requestId,
47
+ model: model as string,
48
+ inputCount,
49
+ duration,
50
+ timestamp: Date.now(),
51
+ })
52
+
53
+ return result
54
+ }
@@ -0,0 +1,56 @@
1
+ import { aiEventClient } from '../event-client.js'
2
+ import type {
3
+ AIAdapter,
4
+ ExtractModelsFromAdapter,
5
+ SummarizationOptions,
6
+ SummarizationResult,
7
+ } from '../types'
8
+
9
+ function createId(prefix: string): string {
10
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
11
+ }
12
+
13
+ /**
14
+ * Standalone summarize function with type inference from adapter
15
+ */
16
+ export async function summarize<
17
+ TAdapter extends AIAdapter<any, any, any, any, any>,
18
+ >(
19
+ options: Omit<SummarizationOptions, 'model'> & {
20
+ adapter: TAdapter
21
+ model: ExtractModelsFromAdapter<TAdapter>
22
+ text: string
23
+ },
24
+ ): Promise<SummarizationResult> {
25
+ const { adapter, model, text, ...restOptions } = options
26
+ const requestId = createId('summarize')
27
+ const inputLength = text.length
28
+ const startTime = Date.now()
29
+
30
+ aiEventClient.emit('summarize:started', {
31
+ requestId,
32
+ model: model as string,
33
+ inputLength,
34
+ timestamp: startTime,
35
+ })
36
+
37
+ const result = await adapter.summarize({
38
+ ...restOptions,
39
+ text,
40
+ model: model as string,
41
+ })
42
+
43
+ const duration = Date.now() - startTime
44
+ const outputLength = result.summary.length
45
+
46
+ aiEventClient.emit('summarize:completed', {
47
+ requestId,
48
+ model: model as string,
49
+ inputLength,
50
+ outputLength,
51
+ duration,
52
+ timestamp: Date.now(),
53
+ })
54
+
55
+ return result
56
+ }
@@ -0,0 +1,389 @@
1
+ import { EventClient } from '@tanstack/devtools-event-client'
2
+
3
+ /**
4
+ * Tool call states - track the lifecycle of a tool call
5
+ * Must match @tanstack/ai-client ToolCallState
6
+ */
7
+ type ToolCallState =
8
+ | 'awaiting-input' // Received start but no arguments yet
9
+ | 'input-streaming' // Partial arguments received
10
+ | 'input-complete' // All arguments received
11
+ | 'approval-requested' // Waiting for user approval
12
+ | 'approval-responded' // User has approved/denied
13
+
14
+ /**
15
+ * Tool result states - track the lifecycle of a tool result
16
+ * Must match @tanstack/ai-client ToolResultState
17
+ */
18
+ type ToolResultState =
19
+ | 'streaming' // Placeholder for future streamed output
20
+ | 'complete' // Result is complete
21
+ | 'error' // Error occurred
22
+
23
+ export interface AIDevtoolsEventMap {
24
+ // AI Stream events - from @tanstack/ai package
25
+ 'tanstack-ai-devtools:stream:started': {
26
+ streamId: string
27
+ model: string
28
+ provider: string
29
+ timestamp: number
30
+ clientId?: string
31
+ }
32
+ 'tanstack-ai-devtools:stream:chunk:content': {
33
+ streamId: string
34
+ messageId?: string
35
+ content: string
36
+ delta?: string
37
+ timestamp: number
38
+ }
39
+ 'tanstack-ai-devtools:stream:chunk:tool-call': {
40
+ streamId: string
41
+ messageId?: string
42
+ toolCallId: string
43
+ toolName: string
44
+ index: number
45
+ arguments: string
46
+ timestamp: number
47
+ }
48
+ 'tanstack-ai-devtools:stream:chunk:tool-result': {
49
+ streamId: string
50
+ messageId?: string
51
+ toolCallId: string
52
+ result: string
53
+ timestamp: number
54
+ }
55
+ 'tanstack-ai-devtools:stream:chunk:done': {
56
+ streamId: string
57
+ messageId?: string
58
+ finishReason: string | null
59
+ usage?: {
60
+ promptTokens: number
61
+ completionTokens: number
62
+ totalTokens: number
63
+ }
64
+ timestamp: number
65
+ }
66
+ 'tanstack-ai-devtools:stream:chunk:error': {
67
+ streamId: string
68
+ messageId?: string
69
+ error: string
70
+ timestamp: number
71
+ }
72
+ 'tanstack-ai-devtools:stream:chunk:thinking': {
73
+ streamId: string
74
+ messageId?: string
75
+ content: string
76
+ delta?: string
77
+ timestamp: number
78
+ }
79
+ 'tanstack-ai-devtools:stream:approval-requested': {
80
+ streamId: string
81
+ messageId?: string
82
+ toolCallId: string
83
+ toolName: string
84
+ input: any
85
+ approvalId: string
86
+ timestamp: number
87
+ }
88
+ 'tanstack-ai-devtools:stream:tool-input-available': {
89
+ streamId: string
90
+ messageId?: string
91
+ toolCallId: string
92
+ toolName: string
93
+ input: any
94
+ timestamp: number
95
+ }
96
+ 'tanstack-ai-devtools:tool:call-completed': {
97
+ requestId: string
98
+ streamId: string
99
+ messageId?: string
100
+ toolCallId: string
101
+ toolName: string
102
+ result: any
103
+ duration: number
104
+ timestamp: number
105
+ }
106
+ 'tanstack-ai-devtools:stream:ended': {
107
+ requestId: string
108
+ streamId: string
109
+ totalChunks: number
110
+ duration: number
111
+ timestamp: number
112
+ }
113
+ 'tanstack-ai-devtools:chat:started': {
114
+ requestId: string
115
+ streamId: string
116
+ provider: string
117
+ model: string
118
+ messageCount: number
119
+ hasTools: boolean
120
+ streaming: boolean
121
+ timestamp: number
122
+ clientId?: string
123
+ toolNames?: Array<string>
124
+ options?: Record<string, unknown>
125
+ providerOptions?: Record<string, unknown>
126
+ }
127
+ 'tanstack-ai-devtools:chat:completed': {
128
+ requestId: string
129
+ streamId: string
130
+ model: string
131
+ content: string
132
+ messageId?: string
133
+ finishReason?: string
134
+ usage?: {
135
+ promptTokens: number
136
+ completionTokens: number
137
+ totalTokens: number
138
+ }
139
+ timestamp: number
140
+ }
141
+ 'tanstack-ai-devtools:chat:iteration': {
142
+ requestId: string
143
+ streamId: string
144
+ iterationNumber: number
145
+ messageCount: number
146
+ toolCallCount: number
147
+ timestamp: number
148
+ }
149
+ 'tanstack-ai-devtools:usage:tokens': {
150
+ requestId: string
151
+ streamId: string
152
+ model: string
153
+ messageId?: string
154
+ usage: {
155
+ promptTokens: number
156
+ completionTokens: number
157
+ totalTokens: number
158
+ }
159
+ timestamp: number
160
+ }
161
+
162
+ // Embedding events
163
+ 'tanstack-ai-devtools:embedding:started': {
164
+ requestId: string
165
+ model: string
166
+ inputCount: number
167
+ timestamp: number
168
+ clientId?: string
169
+ }
170
+ 'tanstack-ai-devtools:embedding:completed': {
171
+ requestId: string
172
+ model: string
173
+ inputCount: number
174
+ duration: number
175
+ timestamp: number
176
+ }
177
+
178
+ // Summarize events
179
+ 'tanstack-ai-devtools:summarize:started': {
180
+ requestId: string
181
+ model: string
182
+ inputLength: number
183
+ timestamp: number
184
+ clientId?: string
185
+ }
186
+ 'tanstack-ai-devtools:summarize:completed': {
187
+ requestId: string
188
+ model: string
189
+ inputLength: number
190
+ outputLength: number
191
+ duration: number
192
+ timestamp: number
193
+ }
194
+
195
+ // Chat Client events - from @tanstack/ai-client package
196
+ 'tanstack-ai-devtools:client:created': {
197
+ clientId: string
198
+ initialMessageCount: number
199
+ timestamp: number
200
+ }
201
+ 'tanstack-ai-devtools:client:message-appended': {
202
+ clientId: string
203
+ messageId: string
204
+ role: 'user' | 'assistant' | 'system' | 'tool'
205
+ contentPreview: string
206
+ timestamp: number
207
+ }
208
+ 'tanstack-ai-devtools:client:message-sent': {
209
+ clientId: string
210
+ messageId: string
211
+ content: string
212
+ timestamp: number
213
+ }
214
+ 'tanstack-ai-devtools:client:loading-changed': {
215
+ clientId: string
216
+ isLoading: boolean
217
+ timestamp: number
218
+ }
219
+ 'tanstack-ai-devtools:client:error-changed': {
220
+ clientId: string
221
+ error: string | null
222
+ timestamp: number
223
+ }
224
+ 'tanstack-ai-devtools:client:messages-cleared': {
225
+ clientId: string
226
+ timestamp: number
227
+ }
228
+ 'tanstack-ai-devtools:client:reloaded': {
229
+ clientId: string
230
+ fromMessageIndex: number
231
+ timestamp: number
232
+ }
233
+ 'tanstack-ai-devtools:client:stopped': {
234
+ clientId: string
235
+ timestamp: number
236
+ }
237
+ 'tanstack-ai-devtools:tool:result-added': {
238
+ clientId: string
239
+ toolCallId: string
240
+ toolName: string
241
+ output: any
242
+ state: 'output-available' | 'output-error'
243
+ timestamp: number
244
+ }
245
+ 'tanstack-ai-devtools:tool:approval-responded': {
246
+ clientId: string
247
+ approvalId: string
248
+ toolCallId: string
249
+ approved: boolean
250
+ timestamp: number
251
+ }
252
+ 'tanstack-ai-devtools:processor:text-updated': {
253
+ streamId: string
254
+ content: string
255
+ timestamp: number
256
+ }
257
+ 'tanstack-ai-devtools:processor:tool-call-state-changed': {
258
+ streamId: string
259
+ toolCallId: string
260
+ toolName: string
261
+ state: ToolCallState
262
+ arguments: any
263
+ timestamp: number
264
+ }
265
+ 'tanstack-ai-devtools:processor:tool-result-state-changed': {
266
+ streamId: string
267
+ toolCallId: string
268
+ content: any
269
+ state: ToolResultState
270
+ error?: string
271
+ timestamp: number
272
+ }
273
+ 'tanstack-ai-devtools:client:assistant-message-updated': {
274
+ clientId: string
275
+ messageId: string
276
+ content: string
277
+ timestamp: number
278
+ }
279
+ 'tanstack-ai-devtools:client:tool-call-updated': {
280
+ clientId: string
281
+ messageId: string
282
+ toolCallId: string
283
+ toolName: string
284
+ state: ToolCallState
285
+ arguments: any
286
+ timestamp: number
287
+ }
288
+ 'tanstack-ai-devtools:client:approval-requested': {
289
+ clientId: string
290
+ messageId: string
291
+ toolCallId: string
292
+ toolName: string
293
+ input: any
294
+ approvalId: string
295
+ timestamp: number
296
+ }
297
+ }
298
+
299
+ // Helper type to strip the prefix at the type level
300
+ type StripPrefix<T extends string> =
301
+ T extends `tanstack-ai-devtools:${infer Suffix}` ? Suffix : never
302
+
303
+ // Get all event names without the prefix
304
+ type EventSuffix = StripPrefix<keyof AIDevtoolsEventMap & string>
305
+
306
+ class AiEventClient extends EventClient<AIDevtoolsEventMap> {
307
+ private eventTarget: EventTarget
308
+
309
+ constructor() {
310
+ super({
311
+ pluginId: 'tanstack-ai-devtools',
312
+ })
313
+ this.eventTarget = new EventTarget()
314
+ }
315
+
316
+ /**
317
+ * Subscribe to events using both the parent EventClient and EventTarget API
318
+ * @param eventSuffix - The event name without the prefix (e.g., "stream:started")
319
+ * @param handler - The event handler function
320
+ * @param options - Optional configuration for event subscription
321
+ * @returns A function to unsubscribe from the event
322
+ */
323
+ override on<TSuffix extends EventSuffix>(
324
+ eventSuffix: TSuffix,
325
+ handler: (event: {
326
+ type: `tanstack-ai-devtools:${TSuffix}`
327
+ payload: AIDevtoolsEventMap[`tanstack-ai-devtools:${TSuffix}`]
328
+ }) => void,
329
+ options?: { withEventTarget?: boolean },
330
+ ): () => void {
331
+ const parentUnsubscribe = super.on(eventSuffix, handler)
332
+
333
+ const withEventTarget = options?.withEventTarget ?? true
334
+ let eventListener: ((event: Event) => void) | undefined
335
+
336
+ if (withEventTarget) {
337
+ // Create a wrapper to handle CustomEvent for EventTarget
338
+ eventListener = (event: Event) => {
339
+ if (event instanceof CustomEvent) {
340
+ handler({
341
+ type: `${eventSuffix}` as `tanstack-ai-devtools:${TSuffix}`,
342
+ payload: event.detail,
343
+ })
344
+ }
345
+ }
346
+
347
+ // Add listener to EventTarget
348
+ this.eventTarget.addEventListener(eventSuffix, eventListener)
349
+ }
350
+
351
+ // Return unsubscribe function that cleans up both subscriptions
352
+ return () => {
353
+ parentUnsubscribe()
354
+ if (withEventTarget && eventListener) {
355
+ this.eventTarget.removeEventListener(eventSuffix, eventListener)
356
+ }
357
+ }
358
+ }
359
+
360
+ /**
361
+ * Emit an event to both the parent EventClient and the EventTarget
362
+ * @param eventSuffix - The event name without the prefix (e.g., "stream:started")
363
+ * @param data - The event data
364
+ */
365
+ override emit<TSuffix extends EventSuffix>(
366
+ eventSuffix: TSuffix,
367
+ data: AIDevtoolsEventMap[`tanstack-ai-devtools:${TSuffix}`],
368
+ ): void {
369
+ super.emit(eventSuffix, data)
370
+
371
+ // Always dispatch to EventTarget (for local listeners)
372
+ const customEvent = new CustomEvent(eventSuffix, {
373
+ detail: data,
374
+ })
375
+ this.eventTarget.dispatchEvent(customEvent)
376
+ }
377
+
378
+ /**
379
+ * Get the underlying EventTarget for advanced use cases
380
+ * @returns The EventTarget instance
381
+ */
382
+ getEventTarget(): EventTarget {
383
+ return this.eventTarget
384
+ }
385
+ }
386
+
387
+ const aiEventClient = new AiEventClient()
388
+
389
+ export { aiEventClient }
package/src/index.ts ADDED
@@ -0,0 +1,68 @@
1
+ export { chat } from './core/chat'
2
+ export { summarize } from './core/summarize'
3
+ export { embedding } from './core/embedding'
4
+ export {
5
+ toolDefinition,
6
+ type ToolDefinition,
7
+ type ToolDefinitionInstance,
8
+ type ToolDefinitionConfig,
9
+ type ServerTool,
10
+ type ClientTool,
11
+ type AnyClientTool,
12
+ type InferToolName,
13
+ type InferToolInput,
14
+ type InferToolOutput,
15
+ } from './tools/tool-definition'
16
+ export { convertZodToJsonSchema } from './tools/zod-converter'
17
+ export {
18
+ toServerSentEventsStream,
19
+ toStreamResponse,
20
+ } from './utilities/stream-to-response'
21
+ export { BaseAdapter } from './base-adapter'
22
+ export { ToolCallManager } from './tools/tool-calls'
23
+ export {
24
+ maxIterations,
25
+ untilFinishReason,
26
+ combineStrategies,
27
+ } from './utilities/agent-loop-strategies'
28
+ export * from './types'
29
+ export { chatOptions } from './utilities/chat-options'
30
+ export { messages } from './utilities/messages'
31
+ export { aiEventClient } from './event-client'
32
+
33
+ // Message converters
34
+ export {
35
+ convertMessagesToModelMessages,
36
+ uiMessageToModelMessages,
37
+ modelMessageToUIMessage,
38
+ modelMessagesToUIMessages,
39
+ normalizeToUIMessage,
40
+ generateMessageId,
41
+ } from './message-converters'
42
+
43
+ // Stream processing (unified for server and client)
44
+ export {
45
+ StreamProcessor,
46
+ createReplayStream,
47
+ ImmediateStrategy,
48
+ PunctuationStrategy,
49
+ BatchStrategy,
50
+ WordBoundaryStrategy,
51
+ CompositeStrategy,
52
+ PartialJSONParser,
53
+ defaultJSONParser,
54
+ parsePartialJSON,
55
+ } from './stream'
56
+ export type {
57
+ ChunkStrategy,
58
+ ChunkRecording,
59
+ InternalToolCallState,
60
+ ProcessorResult,
61
+ ProcessorState,
62
+ StreamProcessorEvents,
63
+ StreamProcessorHandlers,
64
+ StreamProcessorOptions,
65
+ ToolCallState,
66
+ ToolResultState,
67
+ JSONParser,
68
+ } from './stream'