@tanstack/ai 0.0.3 → 0.1.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.
Files changed (146) hide show
  1. package/README.md +26 -0
  2. package/dist/esm/activities/chat/adapter.d.ts +100 -0
  3. package/dist/esm/activities/chat/adapter.js +14 -0
  4. package/dist/esm/activities/chat/adapter.js.map +1 -0
  5. package/dist/esm/{utilities → activities/chat}/agent-loop-strategies.d.ts +4 -4
  6. package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -0
  7. package/dist/esm/activities/chat/index.d.ts +165 -0
  8. package/dist/esm/{core/chat.js → activities/chat/index.js} +131 -33
  9. package/dist/esm/activities/chat/index.js.map +1 -0
  10. package/dist/esm/{message-converters.d.ts → activities/chat/messages.d.ts} +1 -1
  11. package/dist/esm/{message-converters.js → activities/chat/messages.js} +7 -7
  12. package/dist/esm/activities/chat/messages.js.map +1 -0
  13. package/dist/esm/activities/chat/stream/json-parser.js.map +1 -0
  14. package/dist/esm/{stream → activities/chat/stream}/message-updaters.d.ts +1 -1
  15. package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -0
  16. package/dist/esm/{stream → activities/chat/stream}/processor.d.ts +1 -1
  17. package/dist/esm/{stream → activities/chat/stream}/processor.js +1 -1
  18. package/dist/esm/activities/chat/stream/processor.js.map +1 -0
  19. package/dist/esm/activities/chat/stream/strategies.js.map +1 -0
  20. package/dist/esm/{stream → activities/chat/stream}/types.d.ts +2 -9
  21. package/dist/esm/{tools → activities/chat/tools}/tool-calls.d.ts +1 -1
  22. package/dist/esm/{tools → activities/chat/tools}/tool-calls.js +9 -5
  23. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -0
  24. package/dist/esm/{tools → activities/chat/tools}/tool-definition.d.ts +14 -14
  25. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -0
  26. package/dist/esm/activities/chat/tools/zod-converter.d.ts +69 -0
  27. package/dist/esm/activities/chat/tools/zod-converter.js +99 -0
  28. package/dist/esm/activities/chat/tools/zod-converter.js.map +1 -0
  29. package/dist/esm/activities/generateImage/adapter.d.ts +68 -0
  30. package/dist/esm/activities/generateImage/adapter.js +14 -0
  31. package/dist/esm/activities/generateImage/adapter.js.map +1 -0
  32. package/dist/esm/activities/generateImage/index.d.ts +89 -0
  33. package/dist/esm/activities/generateImage/index.js +15 -0
  34. package/dist/esm/activities/generateImage/index.js.map +1 -0
  35. package/dist/esm/activities/generateSpeech/adapter.d.ts +62 -0
  36. package/dist/esm/activities/generateSpeech/adapter.js +14 -0
  37. package/dist/esm/activities/generateSpeech/adapter.js.map +1 -0
  38. package/dist/esm/activities/generateSpeech/index.d.ts +69 -0
  39. package/dist/esm/activities/generateSpeech/index.js +15 -0
  40. package/dist/esm/activities/generateSpeech/index.js.map +1 -0
  41. package/dist/esm/activities/generateTranscription/adapter.d.ts +62 -0
  42. package/dist/esm/activities/generateTranscription/adapter.js +14 -0
  43. package/dist/esm/activities/generateTranscription/adapter.js.map +1 -0
  44. package/dist/esm/activities/generateTranscription/index.d.ts +71 -0
  45. package/dist/esm/activities/generateTranscription/index.js +15 -0
  46. package/dist/esm/activities/generateTranscription/index.js.map +1 -0
  47. package/dist/esm/activities/generateVideo/adapter.d.ts +80 -0
  48. package/dist/esm/activities/generateVideo/adapter.js +14 -0
  49. package/dist/esm/activities/generateVideo/adapter.js.map +1 -0
  50. package/dist/esm/activities/generateVideo/index.d.ts +136 -0
  51. package/dist/esm/activities/generateVideo/index.js +47 -0
  52. package/dist/esm/activities/generateVideo/index.js.map +1 -0
  53. package/dist/esm/activities/index.d.ts +22 -0
  54. package/dist/esm/activities/index.js +34 -0
  55. package/dist/esm/activities/index.js.map +1 -0
  56. package/dist/esm/activities/summarize/adapter.d.ts +74 -0
  57. package/dist/esm/activities/summarize/adapter.js +14 -0
  58. package/dist/esm/activities/summarize/adapter.js.map +1 -0
  59. package/dist/esm/activities/summarize/index.d.ts +100 -0
  60. package/dist/esm/activities/summarize/index.js +90 -0
  61. package/dist/esm/activities/summarize/index.js.map +1 -0
  62. package/dist/esm/event-client.d.ts +4 -18
  63. package/dist/esm/event-client.js.map +1 -1
  64. package/dist/esm/index.d.ts +16 -14
  65. package/dist/esm/index.js +28 -19
  66. package/dist/esm/stream-to-response.d.ts +95 -0
  67. package/dist/esm/stream-to-response.js +118 -0
  68. package/dist/esm/stream-to-response.js.map +1 -0
  69. package/dist/esm/types.d.ts +347 -129
  70. package/package.json +5 -1
  71. package/src/activities/chat/adapter.ts +150 -0
  72. package/src/{utilities → activities/chat}/agent-loop-strategies.ts +4 -4
  73. package/src/{core/chat.ts → activities/chat/index.ts} +427 -79
  74. package/src/{message-converters.ts → activities/chat/messages.ts} +10 -13
  75. package/src/{stream → activities/chat/stream}/message-updaters.ts +1 -1
  76. package/src/{stream → activities/chat/stream}/processor.ts +2 -5
  77. package/src/{stream → activities/chat/stream}/types.ts +8 -18
  78. package/src/{tools → activities/chat/tools}/tool-calls.ts +36 -11
  79. package/src/{tools → activities/chat/tools}/tool-definition.ts +36 -27
  80. package/src/activities/chat/tools/zod-converter.ts +235 -0
  81. package/src/activities/generateImage/adapter.ts +104 -0
  82. package/src/activities/generateImage/index.ts +162 -0
  83. package/src/activities/generateSpeech/adapter.ts +87 -0
  84. package/src/activities/generateSpeech/index.ts +122 -0
  85. package/src/activities/generateTranscription/adapter.ts +89 -0
  86. package/src/activities/generateTranscription/index.ts +132 -0
  87. package/src/activities/generateVideo/adapter.ts +116 -0
  88. package/src/activities/generateVideo/index.ts +261 -0
  89. package/src/activities/index.ts +164 -0
  90. package/src/activities/summarize/adapter.ts +107 -0
  91. package/src/activities/summarize/index.ts +287 -0
  92. package/src/event-client.ts +5 -21
  93. package/src/index.ts +58 -15
  94. package/src/stream-to-response.ts +237 -0
  95. package/src/types.ts +404 -280
  96. package/dist/esm/base-adapter.d.ts +0 -36
  97. package/dist/esm/base-adapter.js +0 -12
  98. package/dist/esm/base-adapter.js.map +0 -1
  99. package/dist/esm/core/chat-common-options.d.ts +0 -52
  100. package/dist/esm/core/chat.d.ts +0 -30
  101. package/dist/esm/core/chat.js.map +0 -1
  102. package/dist/esm/core/embedding.d.ts +0 -8
  103. package/dist/esm/core/embedding.js +0 -33
  104. package/dist/esm/core/embedding.js.map +0 -1
  105. package/dist/esm/core/summarize.d.ts +0 -9
  106. package/dist/esm/core/summarize.js +0 -36
  107. package/dist/esm/core/summarize.js.map +0 -1
  108. package/dist/esm/message-converters.js.map +0 -1
  109. package/dist/esm/stream/json-parser.js.map +0 -1
  110. package/dist/esm/stream/message-updaters.js.map +0 -1
  111. package/dist/esm/stream/processor.js.map +0 -1
  112. package/dist/esm/stream/strategies.js.map +0 -1
  113. package/dist/esm/tools/tool-calls.js.map +0 -1
  114. package/dist/esm/tools/tool-definition.js.map +0 -1
  115. package/dist/esm/tools/zod-converter.d.ts +0 -30
  116. package/dist/esm/tools/zod-converter.js +0 -36
  117. package/dist/esm/tools/zod-converter.js.map +0 -1
  118. package/dist/esm/utilities/agent-loop-strategies.js.map +0 -1
  119. package/dist/esm/utilities/chat-options.d.ts +0 -6
  120. package/dist/esm/utilities/chat-options.js +0 -7
  121. package/dist/esm/utilities/chat-options.js.map +0 -1
  122. package/dist/esm/utilities/messages.d.ts +0 -30
  123. package/dist/esm/utilities/messages.js +0 -7
  124. package/dist/esm/utilities/messages.js.map +0 -1
  125. package/dist/esm/utilities/stream-to-response.d.ts +0 -48
  126. package/dist/esm/utilities/stream-to-response.js +0 -62
  127. package/dist/esm/utilities/stream-to-response.js.map +0 -1
  128. package/src/base-adapter.ts +0 -86
  129. package/src/core/chat-common-options.ts +0 -55
  130. package/src/core/embedding.ts +0 -54
  131. package/src/core/summarize.ts +0 -56
  132. package/src/tools/zod-converter.ts +0 -85
  133. package/src/utilities/chat-options.ts +0 -35
  134. package/src/utilities/messages.ts +0 -63
  135. package/src/utilities/stream-to-response.ts +0 -116
  136. /package/dist/esm/{utilities → activities/chat}/agent-loop-strategies.js +0 -0
  137. /package/dist/esm/{stream → activities/chat/stream}/index.d.ts +0 -0
  138. /package/dist/esm/{stream → activities/chat/stream}/json-parser.d.ts +0 -0
  139. /package/dist/esm/{stream → activities/chat/stream}/json-parser.js +0 -0
  140. /package/dist/esm/{stream → activities/chat/stream}/message-updaters.js +0 -0
  141. /package/dist/esm/{stream → activities/chat/stream}/strategies.d.ts +0 -0
  142. /package/dist/esm/{stream → activities/chat/stream}/strategies.js +0 -0
  143. /package/dist/esm/{tools → activities/chat/tools}/tool-definition.js +0 -0
  144. /package/src/{stream → activities/chat/stream}/index.ts +0 -0
  145. /package/src/{stream → activities/chat/stream}/json-parser.ts +0 -0
  146. /package/src/{stream → activities/chat/stream}/strategies.ts +0 -0
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Summarize Activity
3
+ *
4
+ * Generates summaries from text input.
5
+ * This is a self-contained module with implementation, types, and JSDoc.
6
+ */
7
+
8
+ import { aiEventClient } from '../../event-client.js'
9
+ import type { SummarizeAdapter } from './adapter'
10
+ import type {
11
+ StreamChunk,
12
+ SummarizationOptions,
13
+ SummarizationResult,
14
+ } from '../../types'
15
+
16
+ // ===========================
17
+ // Activity Kind
18
+ // ===========================
19
+
20
+ /** The adapter kind this activity handles */
21
+ export const kind = 'summarize' as const
22
+
23
+ // ===========================
24
+ // Type Extraction Helpers
25
+ // ===========================
26
+
27
+ /** Extract provider options from a SummarizeAdapter via ~types */
28
+ export type SummarizeProviderOptions<TAdapter> =
29
+ TAdapter extends SummarizeAdapter<any, any>
30
+ ? TAdapter['~types']['providerOptions']
31
+ : object
32
+
33
+ // ===========================
34
+ // Activity Options Type
35
+ // ===========================
36
+
37
+ /**
38
+ * Options for the summarize activity.
39
+ * The model is extracted from the adapter's model property.
40
+ *
41
+ * @template TAdapter - The summarize adapter type
42
+ * @template TStream - Whether to stream the output
43
+ */
44
+ export interface SummarizeActivityOptions<
45
+ TAdapter extends SummarizeAdapter<string, object>,
46
+ TStream extends boolean = false,
47
+ > {
48
+ /** The summarize adapter to use (must be created with a model) */
49
+ adapter: TAdapter & { kind: typeof kind }
50
+ /** The text to summarize */
51
+ text: string
52
+ /** Maximum length of the summary (in words or characters, provider-dependent) */
53
+ maxLength?: number
54
+ /** Style of summary to generate */
55
+ style?: 'bullet-points' | 'paragraph' | 'concise'
56
+ /** Topics or aspects to focus on in the summary */
57
+ focus?: Array<string>
58
+ /** Provider-specific options */
59
+ modelOptions?: SummarizeProviderOptions<TAdapter>
60
+ /**
61
+ * Whether to stream the summarization result.
62
+ * When true, returns an AsyncIterable<StreamChunk> for streaming output.
63
+ * When false or not provided, returns a Promise<SummarizationResult>.
64
+ *
65
+ * @default false
66
+ */
67
+ stream?: TStream
68
+ }
69
+
70
+ // ===========================
71
+ // Activity Result Type
72
+ // ===========================
73
+
74
+ /**
75
+ * Result type for the summarize activity.
76
+ * - If stream is true: AsyncIterable<StreamChunk>
77
+ * - Otherwise: Promise<SummarizationResult>
78
+ */
79
+ export type SummarizeActivityResult<TStream extends boolean> =
80
+ TStream extends true
81
+ ? AsyncIterable<StreamChunk>
82
+ : Promise<SummarizationResult>
83
+
84
+ // ===========================
85
+ // Helper Functions
86
+ // ===========================
87
+
88
+ function createId(prefix: string): string {
89
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
90
+ }
91
+
92
+ // ===========================
93
+ // Activity Implementation
94
+ // ===========================
95
+
96
+ /**
97
+ * Summarize activity - generates summaries from text.
98
+ *
99
+ * Supports both streaming and non-streaming modes.
100
+ *
101
+ * @example Basic summarization
102
+ * ```ts
103
+ * import { summarize } from '@tanstack/ai'
104
+ * import { openaiSummarize } from '@tanstack/ai-openai'
105
+ *
106
+ * const result = await summarize({
107
+ * adapter: openaiSummarize('gpt-4o-mini'),
108
+ * text: 'Long article text here...'
109
+ * })
110
+ *
111
+ * console.log(result.summary)
112
+ * ```
113
+ *
114
+ * @example Summarization with style
115
+ * ```ts
116
+ * const result = await summarize({
117
+ * adapter: openaiSummarize('gpt-4o-mini'),
118
+ * text: 'Long article text here...',
119
+ * style: 'bullet-points',
120
+ * maxLength: 100
121
+ * })
122
+ * ```
123
+ *
124
+ * @example Focused summarization
125
+ * ```ts
126
+ * const result = await summarize({
127
+ * adapter: openaiSummarize('gpt-4o-mini'),
128
+ * text: 'Long technical document...',
129
+ * focus: ['key findings', 'methodology']
130
+ * })
131
+ * ```
132
+ *
133
+ * @example Streaming summarization
134
+ * ```ts
135
+ * for await (const chunk of summarize({
136
+ * adapter: openaiSummarize('gpt-4o-mini'),
137
+ * text: 'Long article text here...',
138
+ * stream: true
139
+ * })) {
140
+ * if (chunk.type === 'content') {
141
+ * process.stdout.write(chunk.delta)
142
+ * }
143
+ * }
144
+ * ```
145
+ */
146
+ export function summarize<
147
+ TAdapter extends SummarizeAdapter<string, object>,
148
+ TStream extends boolean = false,
149
+ >(
150
+ options: SummarizeActivityOptions<TAdapter, TStream>,
151
+ ): SummarizeActivityResult<TStream> {
152
+ const { stream } = options
153
+
154
+ if (stream) {
155
+ return runStreamingSummarize(
156
+ options as unknown as SummarizeActivityOptions<
157
+ SummarizeAdapter<string, object>,
158
+ true
159
+ >,
160
+ ) as SummarizeActivityResult<TStream>
161
+ }
162
+
163
+ return runSummarize(
164
+ options as unknown as SummarizeActivityOptions<
165
+ SummarizeAdapter<string, object>,
166
+ false
167
+ >,
168
+ ) as SummarizeActivityResult<TStream>
169
+ }
170
+
171
+ /**
172
+ * Run non-streaming summarization
173
+ */
174
+ async function runSummarize(
175
+ options: SummarizeActivityOptions<SummarizeAdapter<string, object>, false>,
176
+ ): Promise<SummarizationResult> {
177
+ const { adapter, text, maxLength, style, focus } = options
178
+ const model = adapter.model
179
+ const requestId = createId('summarize')
180
+ const inputLength = text.length
181
+ const startTime = Date.now()
182
+
183
+ aiEventClient.emit('summarize:started', {
184
+ requestId,
185
+ model,
186
+ inputLength,
187
+ timestamp: startTime,
188
+ })
189
+
190
+ const summarizeOptions: SummarizationOptions = {
191
+ model,
192
+ text,
193
+ maxLength,
194
+ style,
195
+ focus,
196
+ }
197
+
198
+ const result = await adapter.summarize(summarizeOptions)
199
+
200
+ const duration = Date.now() - startTime
201
+ const outputLength = result.summary.length
202
+
203
+ aiEventClient.emit('summarize:completed', {
204
+ requestId,
205
+ model,
206
+ inputLength,
207
+ outputLength,
208
+ duration,
209
+ timestamp: Date.now(),
210
+ })
211
+
212
+ return result
213
+ }
214
+
215
+ /**
216
+ * Run streaming summarization
217
+ * Uses the adapter's native streaming if available, otherwise falls back
218
+ * to non-streaming and yields the result as a single chunk.
219
+ */
220
+ async function* runStreamingSummarize(
221
+ options: SummarizeActivityOptions<SummarizeAdapter<string, object>, true>,
222
+ ): AsyncIterable<StreamChunk> {
223
+ const { adapter, text, maxLength, style, focus } = options
224
+ const model = adapter.model
225
+
226
+ const summarizeOptions: SummarizationOptions = {
227
+ model,
228
+ text,
229
+ maxLength,
230
+ style,
231
+ focus,
232
+ }
233
+
234
+ // Use real streaming if the adapter supports it
235
+ if (adapter.summarizeStream) {
236
+ yield* adapter.summarizeStream(summarizeOptions)
237
+ return
238
+ }
239
+
240
+ // Fall back to non-streaming and yield as a single chunk
241
+ const result = await adapter.summarize(summarizeOptions)
242
+
243
+ // Yield content chunk with the summary
244
+ yield {
245
+ type: 'content',
246
+ id: result.id,
247
+ model: result.model,
248
+ timestamp: Date.now(),
249
+ delta: result.summary,
250
+ content: result.summary,
251
+ role: 'assistant',
252
+ }
253
+
254
+ // Yield done chunk
255
+ yield {
256
+ type: 'done',
257
+ id: result.id,
258
+ model: result.model,
259
+ timestamp: Date.now(),
260
+ finishReason: 'stop',
261
+ usage: result.usage,
262
+ }
263
+ }
264
+
265
+ // ===========================
266
+ // Options Factory
267
+ // ===========================
268
+
269
+ /**
270
+ * Create typed options for the summarize() function without executing.
271
+ */
272
+ export function createSummarizeOptions<
273
+ TAdapter extends SummarizeAdapter<string, object>,
274
+ TStream extends boolean = false,
275
+ >(
276
+ options: SummarizeActivityOptions<TAdapter, TStream>,
277
+ ): SummarizeActivityOptions<TAdapter, TStream> {
278
+ return options
279
+ }
280
+
281
+ // Re-export adapter types
282
+ export type {
283
+ SummarizeAdapter,
284
+ SummarizeAdapterConfig,
285
+ AnySummarizeAdapter,
286
+ } from './adapter'
287
+ export { BaseSummarizeAdapter } from './adapter'
@@ -110,7 +110,7 @@ export interface AIDevtoolsEventMap {
110
110
  duration: number
111
111
  timestamp: number
112
112
  }
113
- 'tanstack-ai-devtools:chat:started': {
113
+ 'tanstack-ai-devtools:text:started': {
114
114
  requestId: string
115
115
  streamId: string
116
116
  provider: string
@@ -122,9 +122,9 @@ export interface AIDevtoolsEventMap {
122
122
  clientId?: string
123
123
  toolNames?: Array<string>
124
124
  options?: Record<string, unknown>
125
- providerOptions?: Record<string, unknown>
125
+ modelOptions?: Record<string, unknown>
126
126
  }
127
- 'tanstack-ai-devtools:chat:completed': {
127
+ 'tanstack-ai-devtools:text:completed': {
128
128
  requestId: string
129
129
  streamId: string
130
130
  model: string
@@ -138,7 +138,7 @@ export interface AIDevtoolsEventMap {
138
138
  }
139
139
  timestamp: number
140
140
  }
141
- 'tanstack-ai-devtools:chat:iteration': {
141
+ 'tanstack-ai-devtools:text:iteration': {
142
142
  requestId: string
143
143
  streamId: string
144
144
  iterationNumber: number
@@ -159,22 +159,6 @@ export interface AIDevtoolsEventMap {
159
159
  timestamp: number
160
160
  }
161
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
162
  // Summarize events
179
163
  'tanstack-ai-devtools:summarize:started': {
180
164
  requestId: string
@@ -192,7 +176,7 @@ export interface AIDevtoolsEventMap {
192
176
  timestamp: number
193
177
  }
194
178
 
195
- // Chat Client events - from @tanstack/ai-client package
179
+ // Text Client events - from @tanstack/ai-client package
196
180
  'tanstack-ai-devtools:client:created': {
197
181
  clientId: string
198
182
  initialMessageCount: number
package/src/index.ts CHANGED
@@ -1,6 +1,40 @@
1
- export { chat } from './core/chat'
2
- export { summarize } from './core/summarize'
3
- export { embedding } from './core/embedding'
1
+ // Activity functions - individual exports for each activity
2
+ export {
3
+ chat,
4
+ summarize,
5
+ generateImage,
6
+ generateVideo,
7
+ getVideoJobStatus,
8
+ generateSpeech,
9
+ generateTranscription,
10
+ } from './activities/index'
11
+
12
+ // Create options functions - for pre-defining typed configurations
13
+ export { createChatOptions } from './activities/chat/index'
14
+ export { createSummarizeOptions } from './activities/summarize/index'
15
+ export { createImageOptions } from './activities/generateImage/index'
16
+ export { createVideoOptions } from './activities/generateVideo/index'
17
+ export { createSpeechOptions } from './activities/generateSpeech/index'
18
+ export { createTranscriptionOptions } from './activities/generateTranscription/index'
19
+
20
+ // Re-export types
21
+ export type {
22
+ AIAdapter,
23
+ ImageAdapter,
24
+ AnyImageAdapter,
25
+ TextAdapter,
26
+ AnyTextAdapter,
27
+ AnySummarizeAdapter,
28
+ SummarizeAdapter,
29
+ AnyTTSAdapter,
30
+ TTSAdapter,
31
+ AnyTranscriptionAdapter,
32
+ TranscriptionAdapter,
33
+ AnyVideoAdapter,
34
+ VideoAdapter,
35
+ } from './activities/index'
36
+
37
+ // Tool definition
4
38
  export {
5
39
  toolDefinition,
6
40
  type ToolDefinition,
@@ -12,33 +46,42 @@ export {
12
46
  type InferToolName,
13
47
  type InferToolInput,
14
48
  type InferToolOutput,
15
- } from './tools/tool-definition'
16
- export { convertZodToJsonSchema } from './tools/zod-converter'
49
+ } from './activities/chat/tools/tool-definition'
50
+ export { convertZodToJsonSchema } from './activities/chat/tools/zod-converter'
51
+
52
+ // Stream utilities
17
53
  export {
54
+ streamToText,
18
55
  toServerSentEventsStream,
19
56
  toStreamResponse,
20
- } from './utilities/stream-to-response'
21
- export { BaseAdapter } from './base-adapter'
22
- export { ToolCallManager } from './tools/tool-calls'
57
+ toHttpStream,
58
+ } from './stream-to-response'
59
+
60
+ // Tool call management
61
+ export { ToolCallManager } from './activities/chat/tools/tool-calls'
62
+
63
+ // Agent loop strategies
23
64
  export {
24
65
  maxIterations,
25
66
  untilFinishReason,
26
67
  combineStrategies,
27
- } from './utilities/agent-loop-strategies'
68
+ } from './activities/chat/agent-loop-strategies'
69
+
70
+ // All types
28
71
  export * from './types'
29
- export { chatOptions } from './utilities/chat-options'
30
- export { messages } from './utilities/messages'
72
+
73
+ // Event client
31
74
  export { aiEventClient } from './event-client'
32
75
 
33
76
  // Message converters
34
77
  export {
35
78
  convertMessagesToModelMessages,
79
+ generateMessageId,
36
80
  uiMessageToModelMessages,
37
81
  modelMessageToUIMessage,
38
82
  modelMessagesToUIMessages,
39
83
  normalizeToUIMessage,
40
- generateMessageId,
41
- } from './message-converters'
84
+ } from './activities/chat/messages'
42
85
 
43
86
  // Stream processing (unified for server and client)
44
87
  export {
@@ -52,7 +95,7 @@ export {
52
95
  PartialJSONParser,
53
96
  defaultJSONParser,
54
97
  parsePartialJSON,
55
- } from './stream'
98
+ } from './activities/chat/stream/index'
56
99
  export type {
57
100
  ChunkStrategy,
58
101
  ChunkRecording,
@@ -65,4 +108,4 @@ export type {
65
108
  ToolCallState,
66
109
  ToolResultState,
67
110
  JSONParser,
68
- } from './stream'
111
+ } from './activities/chat/stream/index'
@@ -0,0 +1,237 @@
1
+ import type { StreamChunk } from './types'
2
+
3
+ /**
4
+ * Collect all text content from a StreamChunk async iterable and return as a string.
5
+ *
6
+ * This function consumes the entire stream, accumulating content from 'content' type chunks,
7
+ * and returns the final concatenated text.
8
+ *
9
+ * @param stream - AsyncIterable of StreamChunks from chat()
10
+ * @returns Promise<string> - The accumulated text content
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const stream = chat({
15
+ * adapter: openaiText(),
16
+ * model: 'gpt-4o',
17
+ * messages: [{ role: 'user', content: 'Hello!' }]
18
+ * });
19
+ * const text = await streamToText(stream);
20
+ * console.log(text); // "Hello! How can I help you today?"
21
+ * ```
22
+ */
23
+ export async function streamToText(
24
+ stream: AsyncIterable<StreamChunk>,
25
+ ): Promise<string> {
26
+ let accumulatedContent = ''
27
+
28
+ for await (const chunk of stream) {
29
+ if (chunk.type === 'content' && chunk.delta) {
30
+ accumulatedContent += chunk.delta
31
+ }
32
+ }
33
+
34
+ return accumulatedContent
35
+ }
36
+
37
+ /**
38
+ * Convert a StreamChunk async iterable to a ReadableStream in Server-Sent Events format
39
+ *
40
+ * This creates a ReadableStream that emits chunks in SSE format:
41
+ * - Each chunk is prefixed with "data: "
42
+ * - Each chunk is followed by "\n\n"
43
+ * - Stream ends with "data: [DONE]\n\n"
44
+ *
45
+ * @param stream - AsyncIterable of StreamChunks from chat()
46
+ * @param abortController - Optional AbortController to abort when stream is cancelled
47
+ * @returns ReadableStream in Server-Sent Events format
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const stream = chat({ adapter: openaiText(), model: "gpt-4o", messages: [...] });
52
+ * const readableStream = toServerSentEventsStream(stream);
53
+ * // Use with Response, or any API that accepts ReadableStream
54
+ * ```
55
+ */
56
+ export function toServerSentEventsStream(
57
+ stream: AsyncIterable<StreamChunk>,
58
+ abortController?: AbortController,
59
+ ): ReadableStream<Uint8Array> {
60
+ const encoder = new TextEncoder()
61
+
62
+ return new ReadableStream({
63
+ async start(controller) {
64
+ try {
65
+ for await (const chunk of stream) {
66
+ // Check if stream was cancelled/aborted
67
+ if (abortController?.signal.aborted) {
68
+ break
69
+ }
70
+
71
+ // Send each chunk as Server-Sent Events format
72
+ controller.enqueue(
73
+ encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`),
74
+ )
75
+ }
76
+
77
+ // Send completion marker
78
+ controller.enqueue(encoder.encode('data: [DONE]\n\n'))
79
+ controller.close()
80
+ } catch (error: any) {
81
+ // Don't send error if aborted
82
+ if (abortController?.signal.aborted) {
83
+ controller.close()
84
+ return
85
+ }
86
+
87
+ // Send error chunk
88
+ controller.enqueue(
89
+ encoder.encode(
90
+ `data: ${JSON.stringify({
91
+ type: 'error',
92
+ error: {
93
+ message: error.message || 'Unknown error occurred',
94
+ code: error.code,
95
+ },
96
+ })}\n\n`,
97
+ ),
98
+ )
99
+ controller.close()
100
+ }
101
+ },
102
+ cancel() {
103
+ // When the ReadableStream is cancelled (e.g., client disconnects),
104
+ // abort the underlying stream
105
+ if (abortController) {
106
+ abortController.abort()
107
+ }
108
+ },
109
+ })
110
+ }
111
+
112
+ /**
113
+ * Convert a StreamChunk async iterable to a ReadableStream in HTTP stream format (newline-delimited JSON)
114
+ *
115
+ * This creates a ReadableStream that emits chunks as newline-delimited JSON:
116
+ * - Each chunk is JSON.stringify'd and followed by "\n"
117
+ * - No SSE formatting (no "data: " prefix)
118
+ *
119
+ * This format is compatible with `fetchHttpStream` connection adapter.
120
+ *
121
+ * @param stream - AsyncIterable of StreamChunks from chat()
122
+ * @param abortController - Optional AbortController to abort when stream is cancelled
123
+ * @returns ReadableStream in HTTP stream format (newline-delimited JSON)
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const stream = chat({ adapter: openaiText(), model: "gpt-4o", messages: [...] });
128
+ * const readableStream = toHttpStream(stream);
129
+ * // Use with Response for HTTP streaming (not SSE)
130
+ * return new Response(readableStream, {
131
+ * headers: { 'Content-Type': 'application/x-ndjson' }
132
+ * });
133
+ * ```
134
+ */
135
+ export function toHttpStream(
136
+ stream: AsyncIterable<StreamChunk>,
137
+ abortController?: AbortController,
138
+ ): ReadableStream<Uint8Array> {
139
+ const encoder = new TextEncoder()
140
+
141
+ return new ReadableStream({
142
+ async start(controller) {
143
+ try {
144
+ for await (const chunk of stream) {
145
+ // Check if stream was cancelled/aborted
146
+ if (abortController?.signal.aborted) {
147
+ break
148
+ }
149
+
150
+ // Send each chunk as newline-delimited JSON
151
+ controller.enqueue(encoder.encode(`${JSON.stringify(chunk)}\n`))
152
+ }
153
+
154
+ controller.close()
155
+ } catch (error: any) {
156
+ // Don't send error if aborted
157
+ if (abortController?.signal.aborted) {
158
+ controller.close()
159
+ return
160
+ }
161
+
162
+ // Send error chunk
163
+ controller.enqueue(
164
+ encoder.encode(
165
+ `${JSON.stringify({
166
+ type: 'error',
167
+ error: {
168
+ message: error.message || 'Unknown error occurred',
169
+ code: error.code,
170
+ },
171
+ })}\n`,
172
+ ),
173
+ )
174
+ controller.close()
175
+ }
176
+ },
177
+ cancel() {
178
+ // When the ReadableStream is cancelled (e.g., client disconnects),
179
+ // abort the underlying stream
180
+ if (abortController) {
181
+ abortController.abort()
182
+ }
183
+ },
184
+ })
185
+ }
186
+
187
+ /**
188
+ * Create a streaming HTTP response from a StreamChunk async iterable
189
+ * Includes proper headers for Server-Sent Events
190
+ *
191
+ * @deprecated Use `toServerSentEventsStream` instead. This function will be removed in a future version.
192
+ *
193
+ * @param stream - AsyncIterable of StreamChunks from chat()
194
+ * @param init - Optional Response initialization options
195
+ * @param abortController - Optional AbortController to abort when client disconnects
196
+ * @returns Response object with SSE headers and streaming body
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * export async function POST(request: Request) {
201
+ * const { messages } = await request.json();
202
+ * const abortController = new AbortController();
203
+ * const stream = chat({
204
+ * adapter: openaiText(),
205
+ * model: "gpt-4o",
206
+ * messages,
207
+ * options: { abortSignal: abortController.signal }
208
+ * });
209
+ * return toStreamResponse(stream, undefined, abortController);
210
+ * }
211
+ * ```
212
+ */
213
+ export function toStreamResponse(
214
+ stream: AsyncIterable<StreamChunk>,
215
+ init?: ResponseInit & { abortController?: AbortController },
216
+ ): Response {
217
+ if (typeof console !== 'undefined') {
218
+ console.warn(
219
+ '`toStreamResponse` is deprecated. Use `toServerSentEventsStream` instead. Example:\n' +
220
+ ' const readableStream = toServerSentEventsStream(stream, abortController);\n' +
221
+ ' return new Response(readableStream, {\n' +
222
+ " headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' }\n" +
223
+ ' });',
224
+ )
225
+ }
226
+
227
+ const { headers, abortController, ...responseInit } = init ?? {}
228
+ return new Response(toServerSentEventsStream(stream, abortController), {
229
+ ...responseInit,
230
+ headers: {
231
+ 'Content-Type': 'text/event-stream',
232
+ 'Cache-Control': 'no-cache',
233
+ Connection: 'keep-alive',
234
+ ...(headers || {}),
235
+ },
236
+ })
237
+ }