ai 7.0.83 → 7.0.84
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 +12 -0
- package/dist/index.d.ts +33 -19
- package/dist/index.js +81 -51
- package/dist/index.js.map +1 -1
- package/dist/internal/index.js +1 -1
- package/docs/03-ai-sdk-harnesses/02-harness-agent.mdx +76 -1
- package/docs/03-ai-sdk-harnesses/04-skills.mdx +6 -2
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +7 -0
- package/docs/07-reference/01-ai-sdk-core/80-smooth-stream.mdx +4 -2
- package/package.json +11 -12
- package/src/agent/tool-loop-agent-settings.ts +9 -0
- package/src/generate-text/index.ts +2 -0
- package/src/generate-text/smooth-stream.ts +15 -3
- package/src/generate-text/stream-text.ts +111 -52
package/dist/internal/index.js
CHANGED
|
@@ -28,6 +28,7 @@ import { createVercelSandbox } from '@ai-sdk/sandbox-vercel';
|
|
|
28
28
|
|
|
29
29
|
export const agent = new HarnessAgent({
|
|
30
30
|
harness: claudeCode,
|
|
31
|
+
model: 'claude-sonnet-4-6',
|
|
31
32
|
sandbox: createVercelSandbox({
|
|
32
33
|
runtime: 'node24',
|
|
33
34
|
ports: [4000],
|
|
@@ -40,6 +41,9 @@ export const agent = new HarnessAgent({
|
|
|
40
41
|
Construct the agent at module scope. It holds configuration, not a live session.
|
|
41
42
|
Live state belongs to `HarnessAgentSession`.
|
|
42
43
|
|
|
44
|
+
Set `model` to select the model that the harness runtime uses. Model identifiers
|
|
45
|
+
are specific to each harness. When omitted, the harness uses its default model.
|
|
46
|
+
|
|
43
47
|
To use this agent, ensure environment variables with sandbox and harness credentials
|
|
44
48
|
are set.
|
|
45
49
|
|
|
@@ -180,6 +184,73 @@ End every session explicitly:
|
|
|
180
184
|
Use `destroy()` for one-off scripts and tests. Use `detach()` or `stop()` for
|
|
181
185
|
HTTP routes that need multi-turn continuity.
|
|
182
186
|
|
|
187
|
+
## Change Settings Between Turns
|
|
188
|
+
|
|
189
|
+
Use `callOptionsSchema` and `prepareCall` to derive `skills`, `instructions`,
|
|
190
|
+
and `tools` for each new turn. This follows the same call-options pattern as
|
|
191
|
+
`ToolLoopAgent`:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import { HarnessAgent } from '@ai-sdk/harness/agent';
|
|
195
|
+
import { tool } from 'ai';
|
|
196
|
+
import { z } from 'zod';
|
|
197
|
+
|
|
198
|
+
const getPolicy = tool({
|
|
199
|
+
description: 'Look up the active project policy.',
|
|
200
|
+
inputSchema: z.object({}),
|
|
201
|
+
execute: async () => 'Keep public APIs backward compatible.',
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const agent = new HarnessAgent({
|
|
205
|
+
harness: claudeCode,
|
|
206
|
+
sandbox,
|
|
207
|
+
tools: { getPolicy },
|
|
208
|
+
callOptionsSchema: z.object({
|
|
209
|
+
area: z.enum(['frontend', 'backend']),
|
|
210
|
+
enablePolicyTool: z.boolean(),
|
|
211
|
+
}),
|
|
212
|
+
prepareCall: ({ options, ...call }) => ({
|
|
213
|
+
...call,
|
|
214
|
+
instructions: `Work as the ${options.area} specialist.`,
|
|
215
|
+
skills: [options.area === 'frontend' ? frontendSkill : backendSkill],
|
|
216
|
+
tools: options.enablePolicyTool ? { getPolicy } : undefined,
|
|
217
|
+
}),
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const session = await agent.createSession();
|
|
221
|
+
try {
|
|
222
|
+
await agent.generate({
|
|
223
|
+
session,
|
|
224
|
+
prompt: 'Review the current implementation.',
|
|
225
|
+
options: { area: 'frontend', enablePolicyTool: false },
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
await agent.generate({
|
|
229
|
+
session,
|
|
230
|
+
prompt: 'Now review the API contract.',
|
|
231
|
+
options: { area: 'backend', enablePolicyTool: true },
|
|
232
|
+
});
|
|
233
|
+
} finally {
|
|
234
|
+
await session.destroy();
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
`prepareCall` runs for a new prompt after its custom `options` have been
|
|
239
|
+
validated. Its settings are then fixed for that whole turn. If the turn pauses
|
|
240
|
+
for a tool result, approval, stop condition, or process handoff, its
|
|
241
|
+
continuation reuses the same settings and does not call `prepareCall` again.
|
|
242
|
+
This prevents settings from changing mid-turn.
|
|
243
|
+
|
|
244
|
+
The Codex adapter starts a fresh native Codex thread when its skills,
|
|
245
|
+
instructions, or tool catalog changes because `codex exec resume` retains the
|
|
246
|
+
original native thread bootstrap. The harness session remains usable, but prior
|
|
247
|
+
native conversation context does not carry across that settings-change boundary.
|
|
248
|
+
Turns with unchanged settings continue the existing native thread.
|
|
249
|
+
|
|
250
|
+
Pass `abortSignal` directly to `generate()` or `stream()`; it is already a
|
|
251
|
+
per-call setting and is not part of `prepareCall`. `output` also stays fixed on
|
|
252
|
+
the agent because its response format is tied to the agent's output schema.
|
|
253
|
+
|
|
183
254
|
When you pass `sandboxSession` to `agent.createSession()`, the caller retains
|
|
184
255
|
ownership of that sandbox. `session.stop()` and `session.destroy()` still end
|
|
185
256
|
the harness runtime but do not stop or destroy the supplied sandbox session.
|
|
@@ -418,10 +489,14 @@ console.log(preparation.identity);
|
|
|
418
489
|
`HarnessAgent` accepts these main settings:
|
|
419
490
|
|
|
420
491
|
- `harness`: the adapter instance.
|
|
492
|
+
- `model`: optional harness-specific model identifier. When omitted, the
|
|
493
|
+
harness uses its default model.
|
|
421
494
|
- `sandbox`: a `HarnessV1SandboxProvider`.
|
|
422
495
|
- `id`: optional stable agent identifier.
|
|
423
496
|
- `instructions`: instructions appended to the runtime's system or developer
|
|
424
|
-
prompt when supported, or prepended to the
|
|
497
|
+
prompt when supported, or prepended to the user prompt otherwise.
|
|
498
|
+
- `callOptionsSchema` and `prepareCall`: validate custom call options and derive
|
|
499
|
+
skills, instructions, and tools for each new turn.
|
|
425
500
|
- `output`: typed output specification applied to every turn.
|
|
426
501
|
- `stopWhen`: condition(s) for finishing a result slice after a completed
|
|
427
502
|
harness tool step that can continue into another model step.
|
|
@@ -8,8 +8,8 @@ description: Use skills with AI SDK harnesses.
|
|
|
8
8
|
[Skills](https://agentskills.io/) are reusable instruction bundles that can
|
|
9
9
|
be useful for project conventions, workflow guidance, domain-specific procedures,
|
|
10
10
|
or any other instructions that should be discoverable by the underlying harness
|
|
11
|
-
runtime. You can
|
|
12
|
-
|
|
11
|
+
runtime. You can configure skills for a `HarnessAgent` or replace them between
|
|
12
|
+
completed turns.
|
|
13
13
|
|
|
14
14
|
## Define Skills
|
|
15
15
|
|
|
@@ -58,6 +58,10 @@ always being loaded into the agent's context like regular `instructions`.
|
|
|
58
58
|
|
|
59
59
|
Use `instructions` for broad agent behavior and current-session priorities.
|
|
60
60
|
|
|
61
|
+
Skills can be changed between completed turns using `callOptionsSchema` and
|
|
62
|
+
`prepareCall`. See [Change Settings Between Turns](/docs/ai-sdk-harnesses/harness-agent#change-settings-between-turns)
|
|
63
|
+
for details.
|
|
64
|
+
|
|
61
65
|
## Related
|
|
62
66
|
|
|
63
67
|
- [HarnessAgent](/docs/ai-sdk-harnesses/harness-agent)
|
|
@@ -1708,6 +1708,13 @@ To see `streamText` in action, check out [these examples](#examples).
|
|
|
1708
1708
|
description:
|
|
1709
1709
|
'The raw reason why the generation finished (from the provider).',
|
|
1710
1710
|
},
|
|
1711
|
+
{
|
|
1712
|
+
name: 'output',
|
|
1713
|
+
type: 'COMPLETE_OUTPUT | undefined',
|
|
1714
|
+
isOptional: true,
|
|
1715
|
+
description:
|
|
1716
|
+
'The parsed output when an output setting was provided and parsing succeeded.',
|
|
1717
|
+
},
|
|
1711
1718
|
{
|
|
1712
1719
|
name: 'usage',
|
|
1713
1720
|
type: 'LanguageModelUsage',
|
|
@@ -45,7 +45,7 @@ const result = streamText({
|
|
|
45
45
|
type: '"word" | "line" | RegExp | Intl.Segmenter | (buffer: string) => string | undefined | null',
|
|
46
46
|
isOptional: true,
|
|
47
47
|
description:
|
|
48
|
-
'Controls how text and reasoning content is chunked for streaming. Use "word" to stream word by word (default), "line" to stream line by line, an Intl.Segmenter for locale-aware word segmentation (recommended for CJK languages), or provide a custom callback or RegExp pattern for custom chunking.',
|
|
48
|
+
'Controls how text and reasoning content is chunked for streaming. Use "word" to stream word by word (default), "line" to stream line by line, an Intl.Segmenter for locale-aware word segmentation (recommended for CJK languages), or provide a custom callback or RegExp pattern that does not match the empty string for custom chunking.',
|
|
49
49
|
},
|
|
50
50
|
]}
|
|
51
51
|
/>
|
|
@@ -102,7 +102,9 @@ const result = streamText({
|
|
|
102
102
|
|
|
103
103
|
#### Regex based chunking
|
|
104
104
|
|
|
105
|
-
To use regex based chunking, pass a `RegExp` to the `chunking` option.
|
|
105
|
+
To use regex based chunking, pass a `RegExp` to the `chunking` option. Global
|
|
106
|
+
and sticky expressions are supported. The expression must not match the empty
|
|
107
|
+
string.
|
|
106
108
|
|
|
107
109
|
```ts
|
|
108
110
|
// To split on underscores:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.84",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,21 +42,20 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/gateway": "4.0.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.68",
|
|
46
46
|
"@ai-sdk/provider": "4.0.8",
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.33"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@ai-sdk/amazon-bedrock": "5.0.
|
|
51
|
-
"@ai-sdk/deepseek": "3.0.
|
|
52
|
-
"@ai-sdk/google": "4.0.
|
|
53
|
-
"@ai-sdk/groq": "4.0.
|
|
54
|
-
"@ai-sdk/huggingface": "2.0.
|
|
55
|
-
"@ai-sdk/moonshotai": "3.0.
|
|
56
|
-
"@ai-sdk/
|
|
57
|
-
"@ai-sdk/openai": "4.0.50",
|
|
50
|
+
"@ai-sdk/amazon-bedrock": "5.0.67",
|
|
51
|
+
"@ai-sdk/deepseek": "3.0.36",
|
|
52
|
+
"@ai-sdk/google": "4.0.57",
|
|
53
|
+
"@ai-sdk/groq": "4.0.34",
|
|
54
|
+
"@ai-sdk/huggingface": "2.0.40",
|
|
55
|
+
"@ai-sdk/moonshotai": "3.0.42",
|
|
56
|
+
"@ai-sdk/openai": "4.0.51",
|
|
58
57
|
"@ai-sdk/test-server": "2.0.1",
|
|
59
|
-
"@ai-sdk/xai": "4.0.
|
|
58
|
+
"@ai-sdk/xai": "4.0.49",
|
|
60
59
|
"@edge-runtime/vm": "^5.0.0",
|
|
61
60
|
"@smithy/eventstream-codec": "^4.3.3",
|
|
62
61
|
"@smithy/util-utf8": "^4.3.3",
|
|
@@ -140,6 +140,13 @@ export type ToolLoopAgentSettings<
|
|
|
140
140
|
*/
|
|
141
141
|
experimental_toolCallers?: Experimental_ToolCallers<NoInfer<TOOLS>>;
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Secret for HMAC-signing tool approval requests. When set, the server
|
|
145
|
+
* signs each approval request at issuance and verifies the signature when
|
|
146
|
+
* the approval is replayed, preventing client-forged approvals.
|
|
147
|
+
*/
|
|
148
|
+
experimental_toolApprovalSecret?: string | Uint8Array;
|
|
149
|
+
|
|
143
150
|
/**
|
|
144
151
|
* Optional function that you can use to provide different settings for a step.
|
|
145
152
|
*/
|
|
@@ -350,6 +357,7 @@ export type ToolLoopAgentSettings<
|
|
|
350
357
|
| 'toolOrder'
|
|
351
358
|
| 'toolApproval'
|
|
352
359
|
| 'experimental_toolCallers'
|
|
360
|
+
| 'experimental_toolApprovalSecret'
|
|
353
361
|
| 'prepareStep'
|
|
354
362
|
| 'repairToolCall'
|
|
355
363
|
| 'experimental_repairToolCall'
|
|
@@ -391,6 +399,7 @@ export type ToolLoopAgentSettings<
|
|
|
391
399
|
| 'toolOrder'
|
|
392
400
|
| 'toolApproval'
|
|
393
401
|
| 'experimental_toolCallers'
|
|
402
|
+
| 'experimental_toolApprovalSecret'
|
|
394
403
|
| 'prepareStep'
|
|
395
404
|
| 'repairToolCall'
|
|
396
405
|
| 'experimental_repairToolCall'
|
|
@@ -65,8 +65,10 @@ export {
|
|
|
65
65
|
} from './stream-language-model-call';
|
|
66
66
|
export {
|
|
67
67
|
streamText,
|
|
68
|
+
type StreamTextEndEvent,
|
|
68
69
|
type StreamTextInclude,
|
|
69
70
|
type StreamTextOnChunkCallback,
|
|
71
|
+
type StreamTextOnEndCallback,
|
|
70
72
|
type StreamTextOnErrorCallback,
|
|
71
73
|
type StreamTextTransform,
|
|
72
74
|
} from './stream-text';
|
|
@@ -23,7 +23,7 @@ export type ChunkDetector = (buffer: string) => string | undefined | null;
|
|
|
23
23
|
* Smooths text and reasoning streaming output.
|
|
24
24
|
*
|
|
25
25
|
* @param delayInMs - The delay in milliseconds between each chunk. Defaults to 10ms. Can be set to `null` to skip the delay.
|
|
26
|
-
* @param chunking - Controls how the text is chunked for streaming. Use "word" to stream word by word (default), "line" to stream line by line, provide a custom RegExp pattern for custom chunking, provide an Intl.Segmenter for locale-aware word segmentation (recommended for CJK languages), or provide a custom ChunkDetector function.
|
|
26
|
+
* @param chunking - Controls how the text is chunked for streaming. Use "word" to stream word by word (default), "line" to stream line by line, provide a custom RegExp pattern that does not match the empty string for custom chunking, provide an Intl.Segmenter for locale-aware word segmentation (recommended for CJK languages), or provide a custom ChunkDetector function.
|
|
27
27
|
*
|
|
28
28
|
* @returns A transform stream that smooths text streaming output.
|
|
29
29
|
*/
|
|
@@ -95,13 +95,25 @@ export function smoothStream<TOOLS extends ToolSet>({
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
detectChunk = buffer => {
|
|
98
|
-
const
|
|
98
|
+
const lastIndex = chunkingRegex.lastIndex;
|
|
99
|
+
chunkingRegex.lastIndex = 0;
|
|
100
|
+
|
|
101
|
+
let match: RegExpExecArray | null;
|
|
102
|
+
try {
|
|
103
|
+
match = chunkingRegex.exec(buffer);
|
|
104
|
+
} finally {
|
|
105
|
+
chunkingRegex.lastIndex = lastIndex;
|
|
106
|
+
}
|
|
99
107
|
|
|
100
108
|
if (!match) {
|
|
101
109
|
return null;
|
|
102
110
|
}
|
|
103
111
|
|
|
104
|
-
|
|
112
|
+
if (!match[0].length) {
|
|
113
|
+
throw new Error(`Chunking RegExp must not match an empty string.`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return buffer.slice(0, match.index) + match[0];
|
|
105
117
|
};
|
|
106
118
|
}
|
|
107
119
|
|
|
@@ -95,7 +95,7 @@ import {
|
|
|
95
95
|
type ActiveToolSubset,
|
|
96
96
|
} from './filter-active-tools';
|
|
97
97
|
import type {
|
|
98
|
-
|
|
98
|
+
GenerateTextEndEvent,
|
|
99
99
|
GenerateTextOnStartCallback,
|
|
100
100
|
GenerateTextOnStepEndCallback,
|
|
101
101
|
GenerateTextOnStepFinishCallback,
|
|
@@ -275,6 +275,24 @@ export type StreamTextOnChunkCallback<TOOLS extends ToolSet> = (event: {
|
|
|
275
275
|
chunk: TextStreamPart<TOOLS>;
|
|
276
276
|
}) => PromiseLike<void> | void;
|
|
277
277
|
|
|
278
|
+
export type StreamTextEndEvent<
|
|
279
|
+
TOOLS extends ToolSet = ToolSet,
|
|
280
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
281
|
+
OUTPUT extends Output = Output,
|
|
282
|
+
> = GenerateTextEndEvent<TOOLS, RUNTIME_CONTEXT> & {
|
|
283
|
+
/**
|
|
284
|
+
* The parsed output when an output setting was provided and parsing
|
|
285
|
+
* succeeded.
|
|
286
|
+
*/
|
|
287
|
+
readonly output?: InferCompleteOutput<OUTPUT>;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
export type StreamTextOnEndCallback<
|
|
291
|
+
TOOLS extends ToolSet = ToolSet,
|
|
292
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
293
|
+
OUTPUT extends Output = Output,
|
|
294
|
+
> = Callback<StreamTextEndEvent<TOOLS, RUNTIME_CONTEXT, OUTPUT>>;
|
|
295
|
+
|
|
278
296
|
/**
|
|
279
297
|
* Callback that is set using the `onAbort` option.
|
|
280
298
|
*
|
|
@@ -589,7 +607,11 @@ export function streamText<
|
|
|
589
607
|
*
|
|
590
608
|
* The usage is the combined usage of all steps.
|
|
591
609
|
*/
|
|
592
|
-
onEnd?:
|
|
610
|
+
onEnd?: StreamTextOnEndCallback<
|
|
611
|
+
NoInfer<TOOLS>,
|
|
612
|
+
NoInfer<RUNTIME_CONTEXT>,
|
|
613
|
+
NoInfer<OUTPUT>
|
|
614
|
+
>;
|
|
593
615
|
|
|
594
616
|
/**
|
|
595
617
|
* Callback that is called when the LLM response and all request tool executions
|
|
@@ -599,9 +621,10 @@ export function streamText<
|
|
|
599
621
|
*
|
|
600
622
|
* @deprecated Use `onEnd` instead.
|
|
601
623
|
*/
|
|
602
|
-
onFinish?:
|
|
624
|
+
onFinish?: StreamTextOnEndCallback<
|
|
603
625
|
NoInfer<TOOLS>,
|
|
604
|
-
NoInfer<RUNTIME_CONTEXT
|
|
626
|
+
NoInfer<RUNTIME_CONTEXT>,
|
|
627
|
+
NoInfer<OUTPUT>
|
|
605
628
|
>;
|
|
606
629
|
|
|
607
630
|
onAbort?: StreamTextOnAbortCallback<
|
|
@@ -974,6 +997,8 @@ class DefaultStreamTextResult<
|
|
|
974
997
|
Array<ResponseMessage>
|
|
975
998
|
>();
|
|
976
999
|
|
|
1000
|
+
private outputPromise: Promise<InferCompleteOutput<OUTPUT>> | undefined;
|
|
1001
|
+
|
|
977
1002
|
private readonly addStream: (
|
|
978
1003
|
stream: ReadableStream<TextStreamPart<TOOLS>>,
|
|
979
1004
|
callbacks?: {
|
|
@@ -1095,7 +1120,11 @@ class DefaultStreamTextResult<
|
|
|
1095
1120
|
onError: StreamTextOnErrorCallback;
|
|
1096
1121
|
onEnd:
|
|
1097
1122
|
| undefined
|
|
1098
|
-
|
|
|
1123
|
+
| StreamTextOnEndCallback<
|
|
1124
|
+
NoInfer<TOOLS>,
|
|
1125
|
+
NoInfer<RUNTIME_CONTEXT>,
|
|
1126
|
+
NoInfer<OUTPUT>
|
|
1127
|
+
>;
|
|
1099
1128
|
onAbort:
|
|
1100
1129
|
| undefined
|
|
1101
1130
|
| StreamTextOnAbortCallback<NoInfer<TOOLS>, NoInfer<RUNTIME_CONTEXT>>;
|
|
@@ -1486,43 +1515,65 @@ class DefaultStreamTextResult<
|
|
|
1486
1515
|
step => step.dynamicToolResults,
|
|
1487
1516
|
);
|
|
1488
1517
|
const warnings = recordedSteps.flatMap(step => step.warnings ?? []);
|
|
1518
|
+
const onEndWithOutput =
|
|
1519
|
+
onEnd == null
|
|
1520
|
+
? undefined
|
|
1521
|
+
: async (event: GenerateTextEndEvent<TOOLS, RUNTIME_CONTEXT>) => {
|
|
1522
|
+
const parsedOutput =
|
|
1523
|
+
output == null
|
|
1524
|
+
? undefined
|
|
1525
|
+
: await self.getOutputPromise().catch(() => undefined);
|
|
1526
|
+
|
|
1527
|
+
await onEnd({
|
|
1528
|
+
...event,
|
|
1529
|
+
...(output != null ? { output: parsedOutput } : {}),
|
|
1530
|
+
});
|
|
1531
|
+
};
|
|
1489
1532
|
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1533
|
+
const onEndEvent = {
|
|
1534
|
+
callId,
|
|
1535
|
+
toolsContext: finalStep.toolsContext,
|
|
1536
|
+
stepNumber: finalStep.stepNumber,
|
|
1537
|
+
model: finalStep.model,
|
|
1538
|
+
runtimeContext: finalStep.runtimeContext,
|
|
1539
|
+
finishReason: finalStep.finishReason,
|
|
1540
|
+
rawFinishReason: finalStep.rawFinishReason,
|
|
1541
|
+
usage: totalUsage,
|
|
1542
|
+
totalUsage,
|
|
1543
|
+
content,
|
|
1544
|
+
text: finalStep.text,
|
|
1545
|
+
reasoning: finalStep.reasoning,
|
|
1546
|
+
reasoningText: finalStep.reasoningText,
|
|
1547
|
+
files,
|
|
1548
|
+
sources,
|
|
1549
|
+
toolCalls,
|
|
1550
|
+
staticToolCalls,
|
|
1551
|
+
dynamicToolCalls,
|
|
1552
|
+
toolResults,
|
|
1553
|
+
staticToolResults,
|
|
1554
|
+
dynamicToolResults,
|
|
1555
|
+
responseMessages: [
|
|
1556
|
+
...initialResponseMessages,
|
|
1557
|
+
...recordedSteps.flatMap(step => step.response.messages),
|
|
1558
|
+
],
|
|
1559
|
+
warnings,
|
|
1560
|
+
request: finalStep.request,
|
|
1561
|
+
response: finalStep.response,
|
|
1562
|
+
providerMetadata: finalStep.providerMetadata,
|
|
1563
|
+
steps: recordedSteps,
|
|
1564
|
+
finalStep,
|
|
1565
|
+
};
|
|
1566
|
+
|
|
1567
|
+
await Promise.all([
|
|
1568
|
+
notify({
|
|
1569
|
+
event: onEndEvent,
|
|
1570
|
+
callbacks: onEndWithOutput,
|
|
1571
|
+
}),
|
|
1572
|
+
notify({
|
|
1573
|
+
event: onEndEvent,
|
|
1574
|
+
callbacks: telemetryDispatcher.onEnd,
|
|
1575
|
+
}),
|
|
1576
|
+
]);
|
|
1526
1577
|
} catch (error) {
|
|
1527
1578
|
controller.error(error);
|
|
1528
1579
|
}
|
|
@@ -2853,18 +2904,26 @@ class DefaultStreamTextResult<
|
|
|
2853
2904
|
return createAsyncIterableStream(this.teeStream().pipeThrough(transform));
|
|
2854
2905
|
}
|
|
2855
2906
|
|
|
2907
|
+
private getOutputPromise(): Promise<InferCompleteOutput<OUTPUT>> {
|
|
2908
|
+
if (this.outputPromise == null) {
|
|
2909
|
+
this.outputPromise = this.finalStep.then(step => {
|
|
2910
|
+
const output = this.outputSpecification ?? text();
|
|
2911
|
+
return output.parseCompleteOutput(
|
|
2912
|
+
{ text: step.text },
|
|
2913
|
+
{
|
|
2914
|
+
response: step.response,
|
|
2915
|
+
usage: step.usage,
|
|
2916
|
+
finishReason: step.finishReason,
|
|
2917
|
+
},
|
|
2918
|
+
);
|
|
2919
|
+
});
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
return this.outputPromise;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2856
2925
|
get output(): Promise<InferCompleteOutput<OUTPUT>> {
|
|
2857
|
-
return this.
|
|
2858
|
-
const output = this.outputSpecification ?? text();
|
|
2859
|
-
return output.parseCompleteOutput(
|
|
2860
|
-
{ text: step.text },
|
|
2861
|
-
{
|
|
2862
|
-
response: step.response,
|
|
2863
|
-
usage: step.usage,
|
|
2864
|
-
finishReason: step.finishReason,
|
|
2865
|
-
},
|
|
2866
|
-
);
|
|
2867
|
-
});
|
|
2926
|
+
return this.getOutputPromise();
|
|
2868
2927
|
}
|
|
2869
2928
|
|
|
2870
2929
|
toUIMessageStream<UI_MESSAGE extends UIMessage>({
|