@@ -21,10 +21,14 @@ import { toJSONString } from '../internal/json.js';
2121import { tokenize } from '../internal/tokenize.js' ;
2222import { simulateStream , type StreamDelayOptions } from '../streams.js' ;
2323
24- /** Options for the streamed-text builders: a stable part `id` plus a tokenization strategy . */
25- export type StreamPartOptions = {
26- /** Stable id shared by the start/delta/end parts. */
24+ /** Options for a singular stream-part builder: the stable part `id`, defaulting to `'1'` . */
25+ type StreamPartIdOptions = {
26+ /** Stable id shared by the start/delta/end parts of one block . */
2727 id ?: string ;
28+ } ;
29+
30+ /** Options for the streamed-text block builders: a stable part `id` plus a tokenization strategy. */
31+ export type StreamPartOptions = StreamPartIdOptions & {
2832 /** Split the text into fixed-size slices of at most this many characters. */
2933 length ?: number ;
3034 /** Split the text on this delimiter, re-appending it to each token. */
@@ -179,6 +183,22 @@ const reasoningFile = (args: { mediaType: string; data: string | Uint8Array }):
179183const toDeltas = ( text : string | Array < string > , length ?: number , separator ?: string ) : Array < string > =>
180184 Array . isArray ( text ) ? text : tokenize ( text , { length, separator } ) ;
181185
186+ /** A `text-start` part opening a streamed text block. */
187+ const streamTextStart = ( { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( {
188+ type : 'text-start' ,
189+ id,
190+ } ) ;
191+
192+ /** A `text-delta` part carrying a slice of streamed text. */
193+ const streamTextDelta = ( text : string , { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( {
194+ type : 'text-delta' ,
195+ id,
196+ delta : text ,
197+ } ) ;
198+
199+ /** A `text-end` part closing a streamed text block. */
200+ const streamTextEnd = ( { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( { type : 'text-end' , id } ) ;
201+
182202/**
183203 * A streamed text block: `text-start` → `text-delta`* → `text-end`. A `string` is split per
184204 * `length`/`separator`; an `Array<string>` is used as the deltas verbatim.
@@ -187,35 +207,72 @@ const streamText = (
187207 text : string | Array < string > ,
188208 { id = '1' , length, separator } : StreamPartOptions = { } ,
189209) : Array < LanguageModelV4StreamPart > => [
190- { type : 'text-start' , id } ,
191- ...toDeltas ( text , length , separator ) . map ( ( delta ) => ( { type : 'text- delta' as const , id , delta } ) ) ,
192- { type : 'text-end' , id } ,
210+ streamTextStart ( { id } ) ,
211+ ...toDeltas ( text , length , separator ) . map ( ( delta ) => streamTextDelta ( delta , { id } ) ) ,
212+ streamTextEnd ( { id } ) ,
193213] ;
194214
215+ /** A `reasoning-start` part opening a streamed reasoning block. */
216+ const streamReasoningStart = ( { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( {
217+ type : 'reasoning-start' ,
218+ id,
219+ } ) ;
220+
221+ /** A `reasoning-delta` part carrying a slice of streamed reasoning. */
222+ const streamReasoningDelta = ( text : string , { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( {
223+ type : 'reasoning-delta' ,
224+ id,
225+ delta : text ,
226+ } ) ;
227+
228+ /** A `reasoning-end` part closing a streamed reasoning block. */
229+ const streamReasoningEnd = ( { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( {
230+ type : 'reasoning-end' ,
231+ id,
232+ } ) ;
233+
195234/** A streamed reasoning block: `reasoning-start` → `reasoning-delta`* → `reasoning-end`. */
196235const streamReasoning = (
197236 text : string | Array < string > ,
198237 { id = '1' , length, separator } : StreamPartOptions = { } ,
199238) : Array < LanguageModelV4StreamPart > => [
200- { type : 'reasoning-start' , id } ,
201- ...toDeltas ( text , length , separator ) . map ( ( delta ) => ( { type : 'reasoning- delta' as const , id , delta } ) ) ,
202- { type : 'reasoning-end' , id } ,
239+ streamReasoningStart ( { id } ) ,
240+ ...toDeltas ( text , length , separator ) . map ( ( delta ) => streamReasoningDelta ( delta , { id } ) ) ,
241+ streamReasoningEnd ( { id } ) ,
203242] ;
204243
244+ /** A `tool-input-start` part opening a streamed tool input. */
245+ const streamToolInputStart = ( toolName : string , { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( {
246+ type : 'tool-input-start' ,
247+ id,
248+ toolName,
249+ } ) ;
250+
251+ /** A `tool-input-delta` part carrying a slice of the streamed tool input. */
252+ const streamToolInputDelta = ( text : string , { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( {
253+ type : 'tool-input-delta' ,
254+ id,
255+ delta : text ,
256+ } ) ;
257+
258+ /** A `tool-input-end` part closing a streamed tool input. */
259+ const streamToolInputEnd = ( { id = '1' } : StreamPartIdOptions = { } ) : LanguageModelV4StreamPart => ( {
260+ type : 'tool-input-end' ,
261+ id,
262+ } ) ;
263+
205264/**
206265 * A streamed tool input: `tool-input-start` → `tool-input-delta`* → `tool-input-end`.
207266 * Pass a tool-set as `TOOLS` to constrain `toolName` and `input`.
208267 */
209268const streamToolInput = < TOOLS extends ToolSet = never > (
210269 args : StreamToolInputArgs < TOOLS > ,
211270) : Array < LanguageModelV4StreamPart > => [
212- { type : 'tool-input-start' , id : args . id , toolName : args . toolName } ,
213- ...tokenize ( toJSONString ( args . input ) , { length : args . length } ) . map ( ( delta ) => ( {
214- type : 'tool-input-delta' as const ,
215- id : args . id ,
216- delta,
217- } ) ) ,
218- { type : 'tool-input-end' , id : args . id } ,
271+ streamToolInputStart ( args . toolName , { id : args . id } ) ,
272+ ...tokenize ( toJSONString ( args . input ) , { length : args . length } ) . map ( ( delta ) =>
273+ streamToolInputDelta ( delta , { id : args . id } ) ,
274+ ) ,
275+ streamToolInputEnd ( { id : args . id } ) ,
219276] ;
220277
221278/** The opening `stream-start` part carrying call warnings. */
@@ -321,8 +378,17 @@ export const Language = {
321378 source,
322379 custom,
323380 reasoningFile,
381+ streamTextStart,
382+ streamTextDelta,
383+ streamTextEnd,
324384 streamText,
385+ streamReasoningStart,
386+ streamReasoningDelta,
387+ streamReasoningEnd,
325388 streamReasoning,
389+ streamToolInputStart,
390+ streamToolInputDelta,
391+ streamToolInputEnd,
326392 streamToolInput,
327393 streamStart,
328394 streamFinish,
0 commit comments