@mastra/client-js 0.10.10 → 0.10.11-alpha.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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +9 -0
- package/dist/index.cjs +246 -217
- package/dist/index.d.cts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +247 -218
- package/package.json +2 -2
- package/src/example.ts +45 -17
- package/src/resources/agent.ts +288 -252
package/src/resources/agent.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parsePartialJson,
|
|
3
3
|
processDataStream,
|
|
4
|
+
processTextStream,
|
|
4
5
|
type JSONValue,
|
|
5
6
|
type ReasoningUIPart,
|
|
6
7
|
type TextUIPart,
|
|
@@ -144,12 +145,18 @@ export class Agent extends BaseResource {
|
|
|
144
145
|
});
|
|
145
146
|
|
|
146
147
|
if (response.finishReason === 'tool-calls') {
|
|
147
|
-
|
|
148
|
+
const toolCalls = (
|
|
148
149
|
response as unknown as {
|
|
149
150
|
toolCalls: { toolName: string; args: any; toolCallId: string }[];
|
|
150
151
|
messages: CoreMessage[];
|
|
151
152
|
}
|
|
152
|
-
).toolCalls
|
|
153
|
+
).toolCalls;
|
|
154
|
+
|
|
155
|
+
if (!toolCalls || !Array.isArray(toolCalls)) {
|
|
156
|
+
return response;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
for (const toolCall of toolCalls) {
|
|
153
160
|
const clientTool = params.clientTools?.[toolCall.toolName] as Tool;
|
|
154
161
|
|
|
155
162
|
if (clientTool && clientTool.execute) {
|
|
@@ -198,6 +205,7 @@ export class Agent extends BaseResource {
|
|
|
198
205
|
onFinish,
|
|
199
206
|
getCurrentDate = () => new Date(),
|
|
200
207
|
lastMessage,
|
|
208
|
+
streamProtocol,
|
|
201
209
|
}: {
|
|
202
210
|
stream: ReadableStream<Uint8Array>;
|
|
203
211
|
update: (options: { message: UIMessage; data: JSONValue[] | undefined; replaceLastMessage: boolean }) => void;
|
|
@@ -206,6 +214,7 @@ export class Agent extends BaseResource {
|
|
|
206
214
|
generateId?: () => string;
|
|
207
215
|
getCurrentDate?: () => Date;
|
|
208
216
|
lastMessage: UIMessage | undefined;
|
|
217
|
+
streamProtocol: 'text' | 'data';
|
|
209
218
|
}) {
|
|
210
219
|
const replaceLastMessage = lastMessage?.role === 'assistant';
|
|
211
220
|
let step = replaceLastMessage
|
|
@@ -289,297 +298,265 @@ export class Agent extends BaseResource {
|
|
|
289
298
|
});
|
|
290
299
|
}
|
|
291
300
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
message.parts.push(currentTextPart);
|
|
301
|
-
} else {
|
|
302
|
-
currentTextPart.text += value;
|
|
303
|
-
}
|
|
301
|
+
if (streamProtocol === 'text') {
|
|
302
|
+
await processTextStream({
|
|
303
|
+
stream,
|
|
304
|
+
onTextPart(value) {
|
|
305
|
+
message.content += value;
|
|
306
|
+
execUpdate();
|
|
307
|
+
},
|
|
308
|
+
});
|
|
304
309
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
310
|
+
onFinish?.({ message, finishReason, usage });
|
|
311
|
+
} else {
|
|
312
|
+
await processDataStream({
|
|
313
|
+
stream,
|
|
314
|
+
onTextPart(value) {
|
|
315
|
+
if (currentTextPart == null) {
|
|
316
|
+
currentTextPart = {
|
|
317
|
+
type: 'text',
|
|
318
|
+
text: value,
|
|
319
|
+
};
|
|
320
|
+
message.parts.push(currentTextPart);
|
|
321
|
+
} else {
|
|
322
|
+
currentTextPart.text += value;
|
|
313
323
|
}
|
|
314
|
-
} else {
|
|
315
|
-
currentReasoningTextDetail.text += value;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (currentReasoningPart == null) {
|
|
319
|
-
currentReasoningPart = {
|
|
320
|
-
type: 'reasoning',
|
|
321
|
-
reasoning: value,
|
|
322
|
-
details: [currentReasoningTextDetail],
|
|
323
|
-
};
|
|
324
|
-
message.parts.push(currentReasoningPart);
|
|
325
|
-
} else {
|
|
326
|
-
currentReasoningPart.reasoning += value;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
message.reasoning = (message.reasoning ?? '') + value;
|
|
330
|
-
|
|
331
|
-
execUpdate();
|
|
332
|
-
},
|
|
333
|
-
onReasoningSignaturePart(value) {
|
|
334
|
-
if (currentReasoningTextDetail != null) {
|
|
335
|
-
currentReasoningTextDetail.signature = value.signature;
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
onRedactedReasoningPart(value) {
|
|
339
|
-
if (currentReasoningPart == null) {
|
|
340
|
-
currentReasoningPart = {
|
|
341
|
-
type: 'reasoning',
|
|
342
|
-
reasoning: '',
|
|
343
|
-
details: [],
|
|
344
|
-
};
|
|
345
|
-
message.parts.push(currentReasoningPart);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
currentReasoningPart.details.push({
|
|
349
|
-
type: 'redacted',
|
|
350
|
-
data: value.data,
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
currentReasoningTextDetail = undefined;
|
|
354
324
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
325
|
+
message.content += value;
|
|
326
|
+
execUpdate();
|
|
327
|
+
},
|
|
328
|
+
onReasoningPart(value) {
|
|
329
|
+
if (currentReasoningTextDetail == null) {
|
|
330
|
+
currentReasoningTextDetail = { type: 'text', text: value };
|
|
331
|
+
if (currentReasoningPart != null) {
|
|
332
|
+
currentReasoningPart.details.push(currentReasoningTextDetail);
|
|
333
|
+
}
|
|
334
|
+
} else {
|
|
335
|
+
currentReasoningTextDetail.text += value;
|
|
336
|
+
}
|
|
363
337
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
338
|
+
if (currentReasoningPart == null) {
|
|
339
|
+
currentReasoningPart = {
|
|
340
|
+
type: 'reasoning',
|
|
341
|
+
reasoning: value,
|
|
342
|
+
details: [currentReasoningTextDetail],
|
|
343
|
+
};
|
|
344
|
+
message.parts.push(currentReasoningPart);
|
|
345
|
+
} else {
|
|
346
|
+
currentReasoningPart.reasoning += value;
|
|
347
|
+
}
|
|
371
348
|
|
|
372
|
-
|
|
373
|
-
},
|
|
374
|
-
onToolCallStreamingStartPart(value) {
|
|
375
|
-
if (message.toolInvocations == null) {
|
|
376
|
-
message.toolInvocations = [];
|
|
377
|
-
}
|
|
349
|
+
message.reasoning = (message.reasoning ?? '') + value;
|
|
378
350
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
351
|
+
execUpdate();
|
|
352
|
+
},
|
|
353
|
+
onReasoningSignaturePart(value) {
|
|
354
|
+
if (currentReasoningTextDetail != null) {
|
|
355
|
+
currentReasoningTextDetail.signature = value.signature;
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
onRedactedReasoningPart(value) {
|
|
359
|
+
if (currentReasoningPart == null) {
|
|
360
|
+
currentReasoningPart = {
|
|
361
|
+
type: 'reasoning',
|
|
362
|
+
reasoning: '',
|
|
363
|
+
details: [],
|
|
364
|
+
};
|
|
365
|
+
message.parts.push(currentReasoningPart);
|
|
366
|
+
}
|
|
386
367
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
toolName: value.toolName,
|
|
392
|
-
args: undefined,
|
|
393
|
-
} as const;
|
|
368
|
+
currentReasoningPart.details.push({
|
|
369
|
+
type: 'redacted',
|
|
370
|
+
data: value.data,
|
|
371
|
+
});
|
|
394
372
|
|
|
395
|
-
|
|
373
|
+
currentReasoningTextDetail = undefined;
|
|
396
374
|
|
|
397
|
-
|
|
375
|
+
execUpdate();
|
|
376
|
+
},
|
|
377
|
+
onFilePart(value) {
|
|
378
|
+
message.parts.push({
|
|
379
|
+
type: 'file',
|
|
380
|
+
mimeType: value.mimeType,
|
|
381
|
+
data: value.data,
|
|
382
|
+
});
|
|
398
383
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
384
|
+
execUpdate();
|
|
385
|
+
},
|
|
386
|
+
onSourcePart(value) {
|
|
387
|
+
message.parts.push({
|
|
388
|
+
type: 'source',
|
|
389
|
+
source: value,
|
|
390
|
+
});
|
|
403
391
|
|
|
404
|
-
|
|
392
|
+
execUpdate();
|
|
393
|
+
},
|
|
394
|
+
onToolCallStreamingStartPart(value) {
|
|
395
|
+
if (message.toolInvocations == null) {
|
|
396
|
+
message.toolInvocations = [];
|
|
397
|
+
}
|
|
405
398
|
|
|
406
|
-
|
|
399
|
+
// add the partial tool call to the map
|
|
400
|
+
partialToolCalls[value.toolCallId] = {
|
|
401
|
+
text: '',
|
|
402
|
+
step,
|
|
403
|
+
toolName: value.toolName,
|
|
404
|
+
index: message.toolInvocations.length,
|
|
405
|
+
};
|
|
407
406
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
407
|
+
const invocation = {
|
|
408
|
+
state: 'partial-call',
|
|
409
|
+
step,
|
|
410
|
+
toolCallId: value.toolCallId,
|
|
411
|
+
toolName: value.toolName,
|
|
412
|
+
args: undefined,
|
|
413
|
+
} as const;
|
|
415
414
|
|
|
416
|
-
|
|
415
|
+
message.toolInvocations.push(invocation);
|
|
417
416
|
|
|
418
|
-
|
|
417
|
+
updateToolInvocationPart(value.toolCallId, invocation);
|
|
419
418
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
state: 'call',
|
|
425
|
-
step,
|
|
426
|
-
...value,
|
|
427
|
-
} as const;
|
|
428
|
-
|
|
429
|
-
if (partialToolCalls[value.toolCallId] != null) {
|
|
430
|
-
// change the partial tool call to a full tool call
|
|
431
|
-
message.toolInvocations![partialToolCalls[value.toolCallId]!.index] = invocation;
|
|
432
|
-
} else {
|
|
433
|
-
if (message.toolInvocations == null) {
|
|
434
|
-
message.toolInvocations = [];
|
|
435
|
-
}
|
|
419
|
+
execUpdate();
|
|
420
|
+
},
|
|
421
|
+
onToolCallDeltaPart(value) {
|
|
422
|
+
const partialToolCall = partialToolCalls[value.toolCallId];
|
|
436
423
|
|
|
437
|
-
|
|
438
|
-
}
|
|
424
|
+
partialToolCall!.text += value.argsTextDelta;
|
|
439
425
|
|
|
440
|
-
|
|
426
|
+
const { value: partialArgs } = parsePartialJson(partialToolCall!.text);
|
|
441
427
|
|
|
442
|
-
|
|
428
|
+
const invocation = {
|
|
429
|
+
state: 'partial-call',
|
|
430
|
+
step: partialToolCall!.step,
|
|
431
|
+
toolCallId: value.toolCallId,
|
|
432
|
+
toolName: partialToolCall!.toolName,
|
|
433
|
+
args: partialArgs,
|
|
434
|
+
} as const;
|
|
443
435
|
|
|
444
|
-
|
|
445
|
-
// In the future we should make this non-blocking, which
|
|
446
|
-
// requires additional state management for error handling etc.
|
|
447
|
-
if (onToolCall) {
|
|
448
|
-
const result = await onToolCall({ toolCall: value });
|
|
449
|
-
if (result != null) {
|
|
450
|
-
const invocation = {
|
|
451
|
-
state: 'result',
|
|
452
|
-
step,
|
|
453
|
-
...value,
|
|
454
|
-
result,
|
|
455
|
-
} as const;
|
|
436
|
+
message.toolInvocations![partialToolCall!.index] = invocation;
|
|
456
437
|
|
|
457
|
-
|
|
458
|
-
message.toolInvocations![message.toolInvocations!.length - 1] = invocation;
|
|
438
|
+
updateToolInvocationPart(value.toolCallId, invocation);
|
|
459
439
|
|
|
460
|
-
|
|
440
|
+
execUpdate();
|
|
441
|
+
},
|
|
442
|
+
async onToolCallPart(value) {
|
|
443
|
+
const invocation = {
|
|
444
|
+
state: 'call',
|
|
445
|
+
step,
|
|
446
|
+
...value,
|
|
447
|
+
} as const;
|
|
448
|
+
|
|
449
|
+
if (partialToolCalls[value.toolCallId] != null) {
|
|
450
|
+
// change the partial tool call to a full tool call
|
|
451
|
+
message.toolInvocations![partialToolCalls[value.toolCallId]!.index] = invocation;
|
|
452
|
+
} else {
|
|
453
|
+
if (message.toolInvocations == null) {
|
|
454
|
+
message.toolInvocations = [];
|
|
455
|
+
}
|
|
461
456
|
|
|
462
|
-
|
|
457
|
+
message.toolInvocations.push(invocation);
|
|
463
458
|
}
|
|
464
|
-
}
|
|
465
|
-
},
|
|
466
|
-
onToolResultPart(value) {
|
|
467
|
-
const toolInvocations = message.toolInvocations;
|
|
468
459
|
|
|
469
|
-
|
|
470
|
-
throw new Error('tool_result must be preceded by a tool_call');
|
|
471
|
-
}
|
|
460
|
+
updateToolInvocationPart(value.toolCallId, invocation);
|
|
472
461
|
|
|
473
|
-
|
|
474
|
-
// and replace it with the result
|
|
475
|
-
const toolInvocationIndex = toolInvocations.findIndex(invocation => invocation.toolCallId === value.toolCallId);
|
|
462
|
+
execUpdate();
|
|
476
463
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
464
|
+
// invoke the onToolCall callback if it exists. This is blocking.
|
|
465
|
+
// In the future we should make this non-blocking, which
|
|
466
|
+
// requires additional state management for error handling etc.
|
|
467
|
+
if (onToolCall) {
|
|
468
|
+
const result = await onToolCall({ toolCall: value });
|
|
469
|
+
if (result != null) {
|
|
470
|
+
const invocation = {
|
|
471
|
+
state: 'result',
|
|
472
|
+
step,
|
|
473
|
+
...value,
|
|
474
|
+
result,
|
|
475
|
+
} as const;
|
|
480
476
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
state: 'result' as const,
|
|
484
|
-
...value,
|
|
485
|
-
} as const;
|
|
477
|
+
// store the result in the tool invocation
|
|
478
|
+
message.toolInvocations![message.toolInvocations!.length - 1] = invocation;
|
|
486
479
|
|
|
487
|
-
|
|
480
|
+
updateToolInvocationPart(value.toolCallId, invocation);
|
|
488
481
|
|
|
489
|
-
|
|
482
|
+
execUpdate();
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
onToolResultPart(value) {
|
|
487
|
+
const toolInvocations = message.toolInvocations;
|
|
490
488
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
data.push(...value);
|
|
495
|
-
execUpdate();
|
|
496
|
-
},
|
|
497
|
-
onMessageAnnotationsPart(value) {
|
|
498
|
-
if (messageAnnotations == null) {
|
|
499
|
-
messageAnnotations = [...value];
|
|
500
|
-
} else {
|
|
501
|
-
messageAnnotations.push(...value);
|
|
502
|
-
}
|
|
489
|
+
if (toolInvocations == null) {
|
|
490
|
+
throw new Error('tool_result must be preceded by a tool_call');
|
|
491
|
+
}
|
|
503
492
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
493
|
+
// find if there is any tool invocation with the same toolCallId
|
|
494
|
+
// and replace it with the result
|
|
495
|
+
const toolInvocationIndex = toolInvocations.findIndex(
|
|
496
|
+
invocation => invocation.toolCallId === value.toolCallId,
|
|
497
|
+
);
|
|
508
498
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
currentReasoningTextDetail = undefined;
|
|
513
|
-
},
|
|
514
|
-
onStartStepPart(value) {
|
|
515
|
-
// keep message id stable when we are updating an existing message:
|
|
516
|
-
if (!replaceLastMessage) {
|
|
517
|
-
message.id = value.messageId;
|
|
518
|
-
}
|
|
499
|
+
if (toolInvocationIndex === -1) {
|
|
500
|
+
throw new Error('tool_result must be preceded by a tool_call with the same toolCallId');
|
|
501
|
+
}
|
|
519
502
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
finishReason = value.finishReason;
|
|
526
|
-
if (value.usage != null) {
|
|
527
|
-
// usage = calculateLanguageModelUsage(value.usage);
|
|
528
|
-
usage = value.usage;
|
|
529
|
-
}
|
|
530
|
-
},
|
|
531
|
-
onErrorPart(error) {
|
|
532
|
-
throw new Error(error);
|
|
533
|
-
},
|
|
534
|
-
});
|
|
503
|
+
const invocation = {
|
|
504
|
+
...toolInvocations[toolInvocationIndex],
|
|
505
|
+
state: 'result' as const,
|
|
506
|
+
...value,
|
|
507
|
+
} as const;
|
|
535
508
|
|
|
536
|
-
|
|
537
|
-
}
|
|
509
|
+
toolInvocations[toolInvocationIndex] = invocation as ToolInvocation;
|
|
538
510
|
|
|
539
|
-
|
|
540
|
-
* Streams a response from the agent
|
|
541
|
-
* @param params - Stream parameters including prompt
|
|
542
|
-
* @returns Promise containing the enhanced Response object with processDataStream method
|
|
543
|
-
*/
|
|
544
|
-
async stream<T extends JSONSchema7 | ZodSchema | undefined = undefined>(
|
|
545
|
-
params: StreamParams<T>,
|
|
546
|
-
): Promise<
|
|
547
|
-
Response & {
|
|
548
|
-
processDataStream: (options?: Omit<Parameters<typeof processDataStream>[0], 'stream'>) => Promise<void>;
|
|
549
|
-
}
|
|
550
|
-
> {
|
|
551
|
-
const processedParams = {
|
|
552
|
-
...params,
|
|
553
|
-
output: params.output ? zodToJsonSchema(params.output) : undefined,
|
|
554
|
-
experimental_output: params.experimental_output ? zodToJsonSchema(params.experimental_output) : undefined,
|
|
555
|
-
runtimeContext: parseClientRuntimeContext(params.runtimeContext),
|
|
556
|
-
clientTools: processClientTools(params.clientTools),
|
|
557
|
-
};
|
|
511
|
+
updateToolInvocationPart(value.toolCallId, invocation as ToolInvocation);
|
|
558
512
|
|
|
559
|
-
|
|
560
|
-
|
|
513
|
+
execUpdate();
|
|
514
|
+
},
|
|
515
|
+
onDataPart(value) {
|
|
516
|
+
data.push(...value);
|
|
517
|
+
execUpdate();
|
|
518
|
+
},
|
|
519
|
+
onMessageAnnotationsPart(value) {
|
|
520
|
+
if (messageAnnotations == null) {
|
|
521
|
+
messageAnnotations = [...value];
|
|
522
|
+
} else {
|
|
523
|
+
messageAnnotations.push(...value);
|
|
524
|
+
}
|
|
561
525
|
|
|
562
|
-
|
|
563
|
-
|
|
526
|
+
execUpdate();
|
|
527
|
+
},
|
|
528
|
+
onFinishStepPart(value) {
|
|
529
|
+
step += 1;
|
|
564
530
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
531
|
+
// reset the current text and reasoning parts
|
|
532
|
+
currentTextPart = value.isContinued ? currentTextPart : undefined;
|
|
533
|
+
currentReasoningPart = undefined;
|
|
534
|
+
currentReasoningTextDetail = undefined;
|
|
535
|
+
},
|
|
536
|
+
onStartStepPart(value) {
|
|
537
|
+
// keep message id stable when we are updating an existing message:
|
|
538
|
+
if (!replaceLastMessage) {
|
|
539
|
+
message.id = value.messageId;
|
|
540
|
+
}
|
|
573
541
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
542
|
+
// add a step boundary part to the message
|
|
543
|
+
message.parts.push({ type: 'step-start' });
|
|
544
|
+
execUpdate();
|
|
545
|
+
},
|
|
546
|
+
onFinishMessagePart(value) {
|
|
547
|
+
finishReason = value.finishReason;
|
|
548
|
+
if (value.usage != null) {
|
|
549
|
+
// usage = calculateLanguageModelUsage(value.usage);
|
|
550
|
+
usage = value.usage;
|
|
551
|
+
}
|
|
552
|
+
},
|
|
553
|
+
onErrorPart(error) {
|
|
554
|
+
throw new Error(error);
|
|
555
|
+
},
|
|
579
556
|
});
|
|
580
|
-
};
|
|
581
557
|
|
|
582
|
-
|
|
558
|
+
onFinish?.({ message, finishReason, usage });
|
|
559
|
+
}
|
|
583
560
|
}
|
|
584
561
|
|
|
585
562
|
/**
|
|
@@ -599,6 +576,7 @@ export class Agent extends BaseResource {
|
|
|
599
576
|
}
|
|
600
577
|
|
|
601
578
|
try {
|
|
579
|
+
const streamProtocol = processedParams.output ? 'text' : 'data';
|
|
602
580
|
let toolCalls: ToolInvocation[] = [];
|
|
603
581
|
let finishReasonToolCalls = false;
|
|
604
582
|
let messages: UIMessage[] = [];
|
|
@@ -707,11 +685,14 @@ export class Agent extends BaseResource {
|
|
|
707
685
|
}
|
|
708
686
|
} else {
|
|
709
687
|
setTimeout(() => {
|
|
710
|
-
writable.
|
|
688
|
+
if (!writable.locked) {
|
|
689
|
+
writable.close();
|
|
690
|
+
}
|
|
711
691
|
}, 0);
|
|
712
692
|
}
|
|
713
693
|
},
|
|
714
694
|
lastMessage: undefined,
|
|
695
|
+
streamProtocol,
|
|
715
696
|
});
|
|
716
697
|
} catch (error) {
|
|
717
698
|
console.error('Error processing stream response:', error);
|
|
@@ -719,6 +700,61 @@ export class Agent extends BaseResource {
|
|
|
719
700
|
return response;
|
|
720
701
|
}
|
|
721
702
|
|
|
703
|
+
/**
|
|
704
|
+
* Streams a response from the agent
|
|
705
|
+
* @param params - Stream parameters including prompt
|
|
706
|
+
* @returns Promise containing the enhanced Response object with processDataStream and processTextStream methods
|
|
707
|
+
*/
|
|
708
|
+
async stream<T extends JSONSchema7 | ZodSchema | undefined = undefined>(
|
|
709
|
+
params: StreamParams<T>,
|
|
710
|
+
): Promise<
|
|
711
|
+
Response & {
|
|
712
|
+
processDataStream: (options?: Omit<Parameters<typeof processDataStream>[0], 'stream'>) => Promise<void>;
|
|
713
|
+
processTextStream: (options?: Omit<Parameters<typeof processTextStream>[0], 'stream'>) => Promise<void>;
|
|
714
|
+
}
|
|
715
|
+
> {
|
|
716
|
+
const processedParams = {
|
|
717
|
+
...params,
|
|
718
|
+
output: params.output ? zodToJsonSchema(params.output) : undefined,
|
|
719
|
+
experimental_output: params.experimental_output ? zodToJsonSchema(params.experimental_output) : undefined,
|
|
720
|
+
runtimeContext: parseClientRuntimeContext(params.runtimeContext),
|
|
721
|
+
clientTools: processClientTools(params.clientTools),
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
// Create a readable stream that will handle the response processing
|
|
725
|
+
const { readable, writable } = new TransformStream<Uint8Array, Uint8Array>();
|
|
726
|
+
// Start processing the response in the background
|
|
727
|
+
const response = await this.processStreamResponse(processedParams, writable);
|
|
728
|
+
|
|
729
|
+
// Create a new response with the readable stream
|
|
730
|
+
const streamResponse = new Response(readable, {
|
|
731
|
+
status: response.status,
|
|
732
|
+
statusText: response.statusText,
|
|
733
|
+
headers: response.headers,
|
|
734
|
+
}) as Response & {
|
|
735
|
+
processDataStream: (options?: Omit<Parameters<typeof processDataStream>[0], 'stream'>) => Promise<void>;
|
|
736
|
+
processTextStream: (options?: Omit<Parameters<typeof processTextStream>[0], 'stream'>) => Promise<void>;
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
// Add the processDataStream method to the response
|
|
740
|
+
streamResponse.processDataStream = async (options = {}) => {
|
|
741
|
+
await processDataStream({
|
|
742
|
+
stream: streamResponse.body as ReadableStream<Uint8Array>,
|
|
743
|
+
...options,
|
|
744
|
+
});
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
//Add the processTextStream method to the response
|
|
748
|
+
streamResponse.processTextStream = async options => {
|
|
749
|
+
await processTextStream({
|
|
750
|
+
stream: streamResponse.body as ReadableStream<Uint8Array>,
|
|
751
|
+
onTextPart: options?.onTextPart ?? (() => {}),
|
|
752
|
+
});
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
return streamResponse;
|
|
756
|
+
}
|
|
757
|
+
|
|
722
758
|
/**
|
|
723
759
|
* Gets details about a specific tool available to the agent
|
|
724
760
|
* @param toolId - ID of the tool to retrieve
|