@ai-sdk/workflow 2.0.57 → 2.0.59
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/CHANGELOG.md +31 -0
- package/dist/index.d.ts +61 -43
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +681 -299
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/build-model-step-result.ts +329 -0
- package/src/do-generate-step.ts +212 -0
- package/src/do-stream-step.ts +50 -179
- package/src/index.ts +3 -0
- package/src/{stream-text-iterator.ts → model-call-iterator.ts} +117 -297
- package/src/model-call.ts +196 -0
- package/src/providers/mock-function-wrapper.ts +32 -0
- package/src/test/agent-e2e-workflows.ts +60 -1
- package/src/test/approval-workflows.ts +105 -0
- package/src/test/generation-boundary-model.ts +115 -0
- package/src/test/generation-boundary-workflows.ts +106 -0
- package/src/test/model-call-payload-workflow.ts +132 -0
- package/src/to-model-response-messages.ts +28 -0
- package/src/workflow-agent.ts +509 -201
- package/src/workflow-execution-result.ts +55 -0
|
@@ -6,13 +6,11 @@ import type {
|
|
|
6
6
|
} from '@ai-sdk/provider';
|
|
7
7
|
import type { Context } from '@ai-sdk/provider-utils';
|
|
8
8
|
import {
|
|
9
|
-
DefaultGeneratedFile,
|
|
10
9
|
experimental_filterActiveTools as filterActiveTools,
|
|
11
10
|
type ActiveTools,
|
|
12
11
|
type Experimental_SandboxSession as SandboxSession,
|
|
13
12
|
type Instructions,
|
|
14
13
|
type LanguageModel,
|
|
15
|
-
type LanguageModelUsage,
|
|
16
14
|
type ModelMessage,
|
|
17
15
|
type StepResult,
|
|
18
16
|
type ToolCallRepairFunction,
|
|
@@ -23,20 +21,22 @@ import {
|
|
|
23
21
|
createRestrictedTelemetryDispatcher,
|
|
24
22
|
createToolSearchState,
|
|
25
23
|
} from 'ai/internal';
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
import { buildModelStepResult } from './build-model-step-result.js';
|
|
25
|
+
import { doGenerateStep } from './do-generate-step.js';
|
|
26
|
+
import { doStreamStep } from './do-stream-step.js';
|
|
27
|
+
import type {
|
|
28
|
+
ModelCallStreamPart,
|
|
29
|
+
ModelCallOptions,
|
|
30
|
+
ModelStopCondition,
|
|
31
|
+
ParsedToolCall,
|
|
32
|
+
ProviderExecutedToolResult,
|
|
33
|
+
ToolInputLifecycleEvent,
|
|
34
|
+
} from './model-call.js';
|
|
36
35
|
import {
|
|
37
36
|
addToolResultsToConversation,
|
|
38
37
|
type ProviderExecutedToolResultPosition,
|
|
39
38
|
} from './add-tool-results-to-conversation.js';
|
|
39
|
+
import { toModelResponseMessages } from './to-model-response-messages.js';
|
|
40
40
|
import { resolveToolContext } from './resolve-tool-context.js';
|
|
41
41
|
import { serializeToolSet } from './serializable-schema.js';
|
|
42
42
|
import type {
|
|
@@ -51,7 +51,7 @@ import type {
|
|
|
51
51
|
} from './workflow-agent.js';
|
|
52
52
|
|
|
53
53
|
// Re-export for consumers
|
|
54
|
-
export type { ProviderExecutedToolResult } from './
|
|
54
|
+
export type { ProviderExecutedToolResult } from './model-call.js';
|
|
55
55
|
|
|
56
56
|
const prepareStepGenerationSettingKeys = [
|
|
57
57
|
'maxOutputTokens',
|
|
@@ -87,7 +87,7 @@ function mergePrepareStepGenerationSettings(
|
|
|
87
87
|
* The value yielded by the stream text iterator when tool calls are requested.
|
|
88
88
|
* Contains both the tool calls and the current conversation messages.
|
|
89
89
|
*/
|
|
90
|
-
export interface
|
|
90
|
+
export interface ModelCallIteratorYieldValue {
|
|
91
91
|
/** The tool calls requested by the model (parsed with typed inputs) */
|
|
92
92
|
toolCalls: ParsedToolCall[];
|
|
93
93
|
/** The tools available for execution in the current step. */
|
|
@@ -108,19 +108,21 @@ export interface StreamTextIteratorYieldValue {
|
|
|
108
108
|
experimental_sandbox?: SandboxSession;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
export interface
|
|
111
|
+
export interface ModelCallIteratorAbortedValue {
|
|
112
112
|
aborted: true;
|
|
113
113
|
messages: LanguageModelV4Prompt;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
export interface
|
|
116
|
+
export interface ModelCallIteratorErrorValue {
|
|
117
117
|
error: unknown;
|
|
118
118
|
messages: LanguageModelV4Prompt;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
// This runs in the workflow context
|
|
122
|
-
export async function*
|
|
122
|
+
export async function* modelCallIterator({
|
|
123
123
|
prompt,
|
|
124
|
+
mode = 'stream',
|
|
125
|
+
include,
|
|
124
126
|
initialInstructions,
|
|
125
127
|
initialMessages = prompt as unknown as ModelMessage[],
|
|
126
128
|
tools = {},
|
|
@@ -145,6 +147,8 @@ export async function* streamTextIterator({
|
|
|
145
147
|
experimental_sandbox: sandbox,
|
|
146
148
|
}: {
|
|
147
149
|
prompt: LanguageModelV4Prompt;
|
|
150
|
+
mode?: 'generate' | 'stream';
|
|
151
|
+
include?: ModelCallOptions['include'];
|
|
148
152
|
initialInstructions?: Instructions;
|
|
149
153
|
initialMessages?: Array<ModelMessage>;
|
|
150
154
|
tools: ToolSet;
|
|
@@ -171,10 +175,10 @@ export async function* streamTextIterator({
|
|
|
171
175
|
| Array<StreamTextTransform<ToolSet>>;
|
|
172
176
|
experimental_sandbox?: SandboxSession;
|
|
173
177
|
}): AsyncGenerator<
|
|
174
|
-
|
|
178
|
+
ModelCallIteratorYieldValue,
|
|
175
179
|
| LanguageModelV4Prompt
|
|
176
|
-
|
|
|
177
|
-
|
|
|
180
|
+
| ModelCallIteratorAbortedValue
|
|
181
|
+
| ModelCallIteratorErrorValue,
|
|
178
182
|
LanguageModelV4ToolResultPart[]
|
|
179
183
|
> {
|
|
180
184
|
let conversationPrompt = [...prompt]; // Create a mutable copy
|
|
@@ -202,7 +206,7 @@ export async function* streamTextIterator({
|
|
|
202
206
|
});
|
|
203
207
|
|
|
204
208
|
// TODO(#12164): replace this AI-core telemetry bridge with a
|
|
205
|
-
// WorkflowAgent-specific typed dispatcher. `
|
|
209
|
+
// WorkflowAgent-specific typed dispatcher. `modelCallIterator` widens
|
|
206
210
|
// tools/runtime context and emits Workflow-shaped events that are only
|
|
207
211
|
// approximately compatible with generateText telemetry event types.
|
|
208
212
|
const telemetryDispatcher = createRestrictedTelemetryDispatcher<
|
|
@@ -218,6 +222,8 @@ export async function* streamTextIterator({
|
|
|
218
222
|
while (!done) {
|
|
219
223
|
// Check for abort signal
|
|
220
224
|
if (currentGenerationSettings.abortSignal?.aborted) {
|
|
225
|
+
if (mode === 'generate')
|
|
226
|
+
currentGenerationSettings.abortSignal.throwIfAborted();
|
|
221
227
|
break;
|
|
222
228
|
}
|
|
223
229
|
|
|
@@ -362,30 +368,43 @@ export async function* streamTextIterator({
|
|
|
362
368
|
headers: currentGenerationSettings.headers,
|
|
363
369
|
} as never);
|
|
364
370
|
|
|
365
|
-
const stepInputMessages =
|
|
366
|
-
|
|
367
|
-
conversationPrompt
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
371
|
+
const stepInputMessages = (mode === 'generate'
|
|
372
|
+
? [...conversationPrompt]
|
|
373
|
+
: conversationPrompt) as unknown as ModelMessage[];
|
|
374
|
+
const callOptions = {
|
|
375
|
+
...currentGenerationSettings,
|
|
376
|
+
toolChoice: currentToolChoice,
|
|
377
|
+
includeRawChunks,
|
|
378
|
+
timeoutAt,
|
|
379
|
+
repairToolCall,
|
|
380
|
+
responseFormat,
|
|
381
|
+
include,
|
|
382
|
+
experimental_transform,
|
|
383
|
+
};
|
|
384
|
+
const modelCallResult =
|
|
385
|
+
mode === 'generate'
|
|
386
|
+
? await doGenerateStep(
|
|
387
|
+
conversationPrompt,
|
|
388
|
+
currentModel,
|
|
389
|
+
serializedTools,
|
|
390
|
+
callOptions,
|
|
391
|
+
)
|
|
392
|
+
: await doStreamStep(
|
|
393
|
+
conversationPrompt,
|
|
394
|
+
currentModel,
|
|
395
|
+
writable,
|
|
396
|
+
serializedTools,
|
|
397
|
+
callOptions,
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
if (modelCallResult.aborted) {
|
|
383
401
|
wasAborted = true;
|
|
384
402
|
break;
|
|
385
403
|
}
|
|
386
404
|
|
|
387
|
-
if ('terminalError' in
|
|
388
|
-
|
|
405
|
+
if ('terminalError' in modelCallResult) {
|
|
406
|
+
if (mode === 'generate') throw modelCallResult.terminalError;
|
|
407
|
+
terminalError = modelCallResult.terminalError;
|
|
389
408
|
hasTerminalError = true;
|
|
390
409
|
}
|
|
391
410
|
|
|
@@ -395,7 +414,7 @@ export async function* streamTextIterator({
|
|
|
395
414
|
raw,
|
|
396
415
|
providerExecutedToolResults,
|
|
397
416
|
toolInputLifecycleEvents,
|
|
398
|
-
} =
|
|
417
|
+
} = modelCallResult;
|
|
399
418
|
await invokeToolInputLifecycleCallbacks({
|
|
400
419
|
events: toolInputLifecycleEvents ?? [],
|
|
401
420
|
toolCalls,
|
|
@@ -408,12 +427,17 @@ export async function* streamTextIterator({
|
|
|
408
427
|
// Reconstruct the full StepResult outside the step boundary so the
|
|
409
428
|
// durable event log doesn't carry StepResult's redundant copies (or the
|
|
410
429
|
// per-chunk snapshot the step used to return).
|
|
411
|
-
const step =
|
|
430
|
+
const step = await buildModelStepResult(
|
|
412
431
|
raw,
|
|
413
432
|
toolCalls,
|
|
414
433
|
finish,
|
|
415
434
|
providerExecutedToolResults,
|
|
416
435
|
{
|
|
436
|
+
tools: effectiveTools,
|
|
437
|
+
requestMessages:
|
|
438
|
+
mode === 'generate' && include?.requestMessages
|
|
439
|
+
? stepInputMessages
|
|
440
|
+
: undefined,
|
|
417
441
|
stepNumber,
|
|
418
442
|
runtimeContext: currentRuntimeContext,
|
|
419
443
|
toolsContext: currentToolsContext,
|
|
@@ -471,7 +495,7 @@ export async function* streamTextIterator({
|
|
|
471
495
|
const {
|
|
472
496
|
content: assistantContent,
|
|
473
497
|
providerExecutedToolResultPositions,
|
|
474
|
-
} = getAssistantMessageContent(step);
|
|
498
|
+
} = getAssistantMessageContent(step, mode);
|
|
475
499
|
const includedToolCallIds = new Set(
|
|
476
500
|
assistantContent.flatMap(part =>
|
|
477
501
|
part.type === 'tool-call' ? [part.toolCallId] : [],
|
|
@@ -484,7 +508,7 @@ export async function* streamTextIterator({
|
|
|
484
508
|
// Note: providerMetadata from the tool call is mapped to providerOptions
|
|
485
509
|
// in the prompt format, following the AI SDK convention. This is critical
|
|
486
510
|
// for providers like Gemini that require thoughtSignature to be preserved
|
|
487
|
-
// across multi-turn tool calls.
|
|
511
|
+
// across multi-turn tool calls. Some fields are sanitized before mapping.
|
|
488
512
|
conversationPrompt.push({
|
|
489
513
|
role: 'assistant',
|
|
490
514
|
content: [
|
|
@@ -522,7 +546,9 @@ export async function* streamTextIterator({
|
|
|
522
546
|
providerExecutedToolResultPositions,
|
|
523
547
|
});
|
|
524
548
|
step.response.messages.push(
|
|
525
|
-
...(
|
|
549
|
+
...(mode === 'generate'
|
|
550
|
+
? toModelResponseMessages(responseMessages)
|
|
551
|
+
: (responseMessages as unknown as typeof step.response.messages)),
|
|
526
552
|
);
|
|
527
553
|
|
|
528
554
|
const stopConditionList =
|
|
@@ -541,9 +567,17 @@ export async function* streamTextIterator({
|
|
|
541
567
|
done =
|
|
542
568
|
stopConditionMet ||
|
|
543
569
|
(!hasClientToolCalls && pendingDeferredToolCallIds.size === 0);
|
|
544
|
-
} else if (
|
|
570
|
+
} else if (
|
|
571
|
+
mode === 'generate' ||
|
|
572
|
+
finishReason === 'stop' ||
|
|
573
|
+
finishReason === 'tool-calls' ||
|
|
574
|
+
finishReason === 'length'
|
|
575
|
+
) {
|
|
545
576
|
// Add assistant response content to the conversation
|
|
546
|
-
const { content: assistantContent } = getAssistantMessageContent(
|
|
577
|
+
const { content: assistantContent } = getAssistantMessageContent(
|
|
578
|
+
step,
|
|
579
|
+
mode,
|
|
580
|
+
);
|
|
547
581
|
|
|
548
582
|
if (assistantContent.length > 0) {
|
|
549
583
|
const assistantMessage = {
|
|
@@ -552,13 +586,14 @@ export async function* streamTextIterator({
|
|
|
552
586
|
} as const;
|
|
553
587
|
conversationPrompt.push(assistantMessage);
|
|
554
588
|
step.response.messages.push(
|
|
555
|
-
|
|
589
|
+
...(mode === 'generate'
|
|
590
|
+
? toModelResponseMessages([assistantMessage])
|
|
591
|
+
: [
|
|
592
|
+
assistantMessage as unknown as (typeof step.response.messages)[number],
|
|
593
|
+
]),
|
|
556
594
|
);
|
|
557
595
|
}
|
|
558
596
|
|
|
559
|
-
done = true;
|
|
560
|
-
} else if (finishReason === 'length') {
|
|
561
|
-
// Model hit max tokens - stop but don't throw
|
|
562
597
|
done = true;
|
|
563
598
|
} else if (finishReason === 'content-filter') {
|
|
564
599
|
// Content filter triggered - stop but don't throw
|
|
@@ -716,239 +751,11 @@ function normalizeStepForTelemetry(step: StepResult<any, any>) {
|
|
|
716
751
|
};
|
|
717
752
|
}
|
|
718
753
|
|
|
719
|
-
/**
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
* arrays are initialized here and populated after execution. The shape matches
|
|
725
|
-
* what the AI SDK's `streamText` exposes to callers.
|
|
726
|
-
*/
|
|
727
|
-
function buildStepResult(
|
|
728
|
-
raw: DoStreamStepRawResult,
|
|
729
|
-
toolCalls: ParsedToolCall[],
|
|
730
|
-
finish: StreamFinish | undefined,
|
|
731
|
-
providerExecutedToolResults: Map<string, ProviderExecutedToolResult>,
|
|
732
|
-
opts: {
|
|
733
|
-
stepNumber: number;
|
|
734
|
-
runtimeContext: Context;
|
|
735
|
-
toolsContext: Record<string, Context | undefined>;
|
|
736
|
-
},
|
|
737
|
-
): StepResult<ToolSet, any> {
|
|
738
|
-
const {
|
|
739
|
-
content: rawContent,
|
|
740
|
-
reasoning: reasoningParts,
|
|
741
|
-
responseMetadata,
|
|
742
|
-
warnings,
|
|
743
|
-
} = raw;
|
|
744
|
-
const reasoningText = reasoningParts.map(r => r.text).join('') || undefined;
|
|
745
|
-
const validToolCallsByIndex = new Map(
|
|
746
|
-
toolCalls.flatMap((tc, index) =>
|
|
747
|
-
tc.invalid
|
|
748
|
-
? []
|
|
749
|
-
: [
|
|
750
|
-
[
|
|
751
|
-
index,
|
|
752
|
-
{
|
|
753
|
-
type: 'tool-call' as const,
|
|
754
|
-
toolCallId: tc.toolCallId,
|
|
755
|
-
toolName: tc.toolName,
|
|
756
|
-
input: tc.input,
|
|
757
|
-
...(tc.providerExecuted != null
|
|
758
|
-
? { providerExecuted: tc.providerExecuted }
|
|
759
|
-
: {}),
|
|
760
|
-
...(tc.title != null ? { title: tc.title } : {}),
|
|
761
|
-
...(tc.toolMetadata != null
|
|
762
|
-
? { toolMetadata: tc.toolMetadata }
|
|
763
|
-
: {}),
|
|
764
|
-
...(tc.dynamic ? { dynamic: true as const } : {}),
|
|
765
|
-
...(tc.providerExecuted ? { providerExecuted: true } : {}),
|
|
766
|
-
...(tc.providerMetadata != null
|
|
767
|
-
? { providerMetadata: tc.providerMetadata }
|
|
768
|
-
: {}),
|
|
769
|
-
},
|
|
770
|
-
] as const,
|
|
771
|
-
],
|
|
772
|
-
),
|
|
773
|
-
);
|
|
774
|
-
const validToolCalls = [...validToolCallsByIndex.values()];
|
|
775
|
-
const content: StepResult<ToolSet, any>['content'] = [];
|
|
776
|
-
const files: StepResult<ToolSet, any>['files'] = [];
|
|
777
|
-
const sources: StepResult<ToolSet, any>['sources'] = [];
|
|
778
|
-
let text = '';
|
|
779
|
-
|
|
780
|
-
for (const part of rawContent) {
|
|
781
|
-
switch (part.type) {
|
|
782
|
-
case 'text':
|
|
783
|
-
text += part.text;
|
|
784
|
-
content.push({
|
|
785
|
-
type: 'text',
|
|
786
|
-
text: part.text,
|
|
787
|
-
...(part.providerMetadata != null
|
|
788
|
-
? { providerMetadata: part.providerMetadata }
|
|
789
|
-
: {}),
|
|
790
|
-
});
|
|
791
|
-
break;
|
|
792
|
-
case 'reasoning': {
|
|
793
|
-
const reasoningPart = reasoningParts[part.reasoningIndex];
|
|
794
|
-
if (reasoningPart != null) {
|
|
795
|
-
content.push({
|
|
796
|
-
type: 'reasoning',
|
|
797
|
-
text: reasoningPart.text,
|
|
798
|
-
...(reasoningPart.providerMetadata != null
|
|
799
|
-
? { providerMetadata: reasoningPart.providerMetadata }
|
|
800
|
-
: {}),
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
|
-
break;
|
|
804
|
-
}
|
|
805
|
-
case 'file': {
|
|
806
|
-
const file = new DefaultGeneratedFile({
|
|
807
|
-
data: part.data,
|
|
808
|
-
mediaType: part.mediaType,
|
|
809
|
-
providerMetadata: part.providerMetadata,
|
|
810
|
-
});
|
|
811
|
-
files.push(file);
|
|
812
|
-
content.push({
|
|
813
|
-
type: 'file',
|
|
814
|
-
file,
|
|
815
|
-
...(part.providerMetadata != null
|
|
816
|
-
? { providerMetadata: part.providerMetadata }
|
|
817
|
-
: {}),
|
|
818
|
-
});
|
|
819
|
-
break;
|
|
820
|
-
}
|
|
821
|
-
case 'source':
|
|
822
|
-
sources.push(part);
|
|
823
|
-
content.push(part);
|
|
824
|
-
break;
|
|
825
|
-
case 'tool-call': {
|
|
826
|
-
const toolCall = validToolCallsByIndex.get(part.toolCallIndex);
|
|
827
|
-
if (toolCall != null) {
|
|
828
|
-
content.push(toolCall);
|
|
829
|
-
}
|
|
830
|
-
break;
|
|
831
|
-
}
|
|
832
|
-
case 'provider-tool-result': {
|
|
833
|
-
const result = providerExecutedToolResults.get(part.toolCallId);
|
|
834
|
-
if (result == null) {
|
|
835
|
-
break;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
const toolCall = toolCalls.find(
|
|
839
|
-
toolCall => toolCall.toolCallId === result.toolCallId,
|
|
840
|
-
);
|
|
841
|
-
const common = {
|
|
842
|
-
toolCallId: result.toolCallId,
|
|
843
|
-
toolName: result.toolName,
|
|
844
|
-
input: toolCall?.input,
|
|
845
|
-
providerExecuted: true as const,
|
|
846
|
-
...(result.dynamic === true || toolCall?.dynamic === true
|
|
847
|
-
? { dynamic: true as const }
|
|
848
|
-
: {}),
|
|
849
|
-
...(result.providerMetadata != null
|
|
850
|
-
? { providerMetadata: result.providerMetadata }
|
|
851
|
-
: {}),
|
|
852
|
-
...(toolCall?.toolMetadata != null
|
|
853
|
-
? { toolMetadata: toolCall.toolMetadata }
|
|
854
|
-
: {}),
|
|
855
|
-
};
|
|
856
|
-
|
|
857
|
-
content.push(
|
|
858
|
-
result.isError
|
|
859
|
-
? {
|
|
860
|
-
type: 'tool-error',
|
|
861
|
-
...common,
|
|
862
|
-
error: result.result,
|
|
863
|
-
}
|
|
864
|
-
: {
|
|
865
|
-
type: 'tool-result',
|
|
866
|
-
...common,
|
|
867
|
-
output: result.result,
|
|
868
|
-
},
|
|
869
|
-
);
|
|
870
|
-
break;
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
const toolResults = content.filter(
|
|
876
|
-
part => part.type === 'tool-result',
|
|
877
|
-
) as StepResult<ToolSet, any>['toolResults'];
|
|
878
|
-
|
|
879
|
-
return {
|
|
880
|
-
callId: 'workflow-agent',
|
|
881
|
-
stepNumber: opts.stepNumber,
|
|
882
|
-
model: {
|
|
883
|
-
provider: responseMetadata?.modelId?.split(':')[0] ?? 'unknown',
|
|
884
|
-
modelId: responseMetadata?.modelId ?? 'unknown',
|
|
885
|
-
},
|
|
886
|
-
functionId: undefined,
|
|
887
|
-
metadata: undefined,
|
|
888
|
-
runtimeContext: opts.runtimeContext ?? {},
|
|
889
|
-
toolsContext: opts.toolsContext ?? {},
|
|
890
|
-
content,
|
|
891
|
-
text,
|
|
892
|
-
reasoning: reasoningParts.map(r => ({
|
|
893
|
-
type: 'reasoning' as const,
|
|
894
|
-
text: r.text,
|
|
895
|
-
...(r.providerMetadata != null
|
|
896
|
-
? { providerMetadata: r.providerMetadata }
|
|
897
|
-
: {}),
|
|
898
|
-
})),
|
|
899
|
-
reasoningText,
|
|
900
|
-
files,
|
|
901
|
-
sources,
|
|
902
|
-
toolCalls: validToolCalls,
|
|
903
|
-
staticToolCalls: validToolCalls.filter(tc => tc.dynamic !== true),
|
|
904
|
-
dynamicToolCalls: validToolCalls.filter(tc => tc.dynamic),
|
|
905
|
-
toolResults,
|
|
906
|
-
staticToolResults: toolResults.filter(result => result.dynamic !== true),
|
|
907
|
-
dynamicToolResults: toolResults.filter(result => result.dynamic === true),
|
|
908
|
-
finishReason: finish?.finishReason ?? 'other',
|
|
909
|
-
rawFinishReason: finish?.rawFinishReason,
|
|
910
|
-
usage:
|
|
911
|
-
finish?.usage ??
|
|
912
|
-
({
|
|
913
|
-
inputTokens: 0,
|
|
914
|
-
inputTokenDetails: {
|
|
915
|
-
noCacheTokens: undefined,
|
|
916
|
-
cacheReadTokens: undefined,
|
|
917
|
-
cacheWriteTokens: undefined,
|
|
918
|
-
},
|
|
919
|
-
outputTokens: 0,
|
|
920
|
-
outputTokenDetails: {
|
|
921
|
-
textTokens: undefined,
|
|
922
|
-
reasoningTokens: undefined,
|
|
923
|
-
},
|
|
924
|
-
totalTokens: 0,
|
|
925
|
-
} as LanguageModelUsage),
|
|
926
|
-
performance: {
|
|
927
|
-
effectiveOutputTokensPerSecond: 0,
|
|
928
|
-
outputTokensPerSecond: undefined,
|
|
929
|
-
inputTokensPerSecond: undefined,
|
|
930
|
-
effectiveTotalTokensPerSecond: 0,
|
|
931
|
-
stepTimeMs: 0,
|
|
932
|
-
responseTimeMs: 0,
|
|
933
|
-
toolExecutionMs: {},
|
|
934
|
-
timeToFirstOutputMs: undefined,
|
|
935
|
-
},
|
|
936
|
-
warnings,
|
|
937
|
-
request: {
|
|
938
|
-
body: '',
|
|
939
|
-
messages: [], // TODO implement step request messages
|
|
940
|
-
},
|
|
941
|
-
response: {
|
|
942
|
-
id: responseMetadata?.id ?? 'unknown',
|
|
943
|
-
timestamp: responseMetadata?.timestamp ?? new Date(),
|
|
944
|
-
modelId: responseMetadata?.modelId ?? 'unknown',
|
|
945
|
-
messages: [],
|
|
946
|
-
},
|
|
947
|
-
providerMetadata: finish?.providerMetadata ?? {},
|
|
948
|
-
} as StepResult<ToolSet, any>;
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
function getAssistantMessageContent(step: StepResult<any, any>): {
|
|
754
|
+
/** Preserve assistant ordering and positions for provider-executed results. */
|
|
755
|
+
function getAssistantMessageContent(
|
|
756
|
+
step: StepResult<any, any>,
|
|
757
|
+
mode: 'generate' | 'stream',
|
|
758
|
+
): {
|
|
952
759
|
content: Extract<
|
|
953
760
|
LanguageModelV4Prompt[number],
|
|
954
761
|
{ role: 'assistant' }
|
|
@@ -965,28 +772,41 @@ function getAssistantMessageContent(step: StepResult<any, any>): {
|
|
|
965
772
|
|
|
966
773
|
for (const part of step.content) {
|
|
967
774
|
switch (part.type) {
|
|
968
|
-
case '
|
|
775
|
+
case 'text':
|
|
776
|
+
if (part.text.length > 0) {
|
|
777
|
+
content.push({
|
|
778
|
+
type: 'text',
|
|
779
|
+
text: part.text,
|
|
780
|
+
...(part.providerMetadata != null
|
|
781
|
+
? { providerOptions: part.providerMetadata }
|
|
782
|
+
: {}),
|
|
783
|
+
});
|
|
784
|
+
contentIndex++;
|
|
785
|
+
}
|
|
786
|
+
break;
|
|
787
|
+
case 'reasoning': {
|
|
788
|
+
const { providerMetadata, ...messagePart } = part;
|
|
969
789
|
content.push({
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
? {
|
|
974
|
-
providerOptions:
|
|
975
|
-
part.providerMetadata as SharedV4ProviderOptions,
|
|
976
|
-
}
|
|
790
|
+
...messagePart,
|
|
791
|
+
...(providerMetadata != null
|
|
792
|
+
? { providerOptions: providerMetadata }
|
|
977
793
|
: {}),
|
|
978
794
|
});
|
|
979
795
|
contentIndex++;
|
|
980
796
|
break;
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
797
|
+
}
|
|
798
|
+
case 'custom':
|
|
799
|
+
if (mode === 'generate') {
|
|
800
|
+
const { providerMetadata, ...messagePart } = part;
|
|
801
|
+
content.push({ ...messagePart, providerOptions: providerMetadata });
|
|
984
802
|
contentIndex++;
|
|
985
803
|
}
|
|
986
804
|
break;
|
|
805
|
+
case 'reasoning-file':
|
|
806
|
+
if (mode !== 'generate') break;
|
|
987
807
|
case 'file':
|
|
988
808
|
content.push({
|
|
989
|
-
type:
|
|
809
|
+
type: part.type,
|
|
990
810
|
data: { type: 'data', data: part.file.base64 },
|
|
991
811
|
mediaType: part.file.mediaType,
|
|
992
812
|
...(part.providerMetadata != null
|