ai 7.0.131 → 7.0.133
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 +25 -0
- package/dist/index.d.ts +122 -101
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +60 -11
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +21 -14
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -1
- package/docs/03-ai-sdk-core/17-mcp-events.mdx +169 -0
- package/docs/03-ai-sdk-core/32-decisions.mdx +54 -6
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +13 -0
- package/docs/07-reference/01-ai-sdk-core/14-decide.mdx +4 -2
- package/docs/07-reference/01-ai-sdk-core/17-create-agent-ui-stream.mdx +41 -2
- package/docs/07-reference/01-ai-sdk-core/18-create-agent-ui-stream-response.mdx +10 -1
- package/docs/07-reference/01-ai-sdk-core/18-pipe-agent-ui-stream-to-response.mdx +10 -1
- package/docs/07-reference/01-ai-sdk-core/23-create-mcp-client.mdx +46 -1
- package/docs/07-reference/01-ai-sdk-core/24-mcp-events.mdx +797 -0
- package/docs/07-reference/01-ai-sdk-core/index.mdx +6 -0
- package/docs/07-reference/02-ai-sdk-ui/50-direct-chat-transport.mdx +13 -0
- package/package.json +12 -12
- package/src/agent/create-agent-ui-stream-response.ts +6 -10
- package/src/agent/create-agent-ui-stream.ts +22 -4
- package/src/agent/pipe-agent-ui-stream-to-response.ts +6 -10
- package/src/decide/decide-events.ts +5 -3
- package/src/decide/decide.ts +7 -9
- package/src/decide/decision-result.ts +1 -2
- package/src/decide/decision-state.ts +61 -0
- package/src/decide/index.ts +8 -2
- package/src/decide/validate-decision.ts +25 -5
- package/src/generate-text/stream-text-result.ts +11 -0
- package/src/generate-text/stream-text.ts +9 -0
- package/src/ui-message-stream/to-ui-message-stream.ts +10 -2
|
@@ -147,6 +147,12 @@ It also contains the following helper functions:
|
|
|
147
147
|
description: 'Creates a client for connecting to MCP servers.',
|
|
148
148
|
href: '/docs/reference/ai-sdk-core/create-mcp-client',
|
|
149
149
|
},
|
|
150
|
+
{
|
|
151
|
+
title: 'MCP Events',
|
|
152
|
+
description:
|
|
153
|
+
'Experimental event methods, webhook delivery, and subscription types.',
|
|
154
|
+
href: '/docs/reference/ai-sdk-core/mcp-events',
|
|
155
|
+
},
|
|
150
156
|
{
|
|
151
157
|
title: 'MCP Apps',
|
|
152
158
|
description:
|
|
@@ -77,6 +77,19 @@ export default function Chat() {
|
|
|
77
77
|
description:
|
|
78
78
|
'Extracts message metadata that will be sent to the client. Called on `start` and `finish` events.',
|
|
79
79
|
},
|
|
80
|
+
{
|
|
81
|
+
name: 'onStepEnd',
|
|
82
|
+
type: 'UIMessageStreamOnStepEndCallback',
|
|
83
|
+
isOptional: true,
|
|
84
|
+
description:
|
|
85
|
+
'Called after each step is converted to UI message parts. Receives messages, isContinuation, and the accumulated responseMessage, including step metadata, for inspection or persistence.',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'onStepFinish',
|
|
89
|
+
type: 'UIMessageStreamOnStepFinishCallback',
|
|
90
|
+
isOptional: true,
|
|
91
|
+
description: 'Deprecated alias for onStepEnd.',
|
|
92
|
+
},
|
|
80
93
|
{
|
|
81
94
|
name: 'sendReasoning',
|
|
82
95
|
type: 'boolean',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.133",
|
|
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,20 +42,20 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/gateway": "4.0.
|
|
46
|
-
"@ai-sdk/provider": "4.0.
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.108",
|
|
46
|
+
"@ai-sdk/provider": "4.0.25",
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.57"
|
|
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/openai": "4.0.
|
|
50
|
+
"@ai-sdk/amazon-bedrock": "5.0.111",
|
|
51
|
+
"@ai-sdk/deepseek": "3.0.62",
|
|
52
|
+
"@ai-sdk/google": "4.0.92",
|
|
53
|
+
"@ai-sdk/groq": "4.0.58",
|
|
54
|
+
"@ai-sdk/huggingface": "2.0.66",
|
|
55
|
+
"@ai-sdk/moonshotai": "3.0.66",
|
|
56
|
+
"@ai-sdk/openai": "4.0.89",
|
|
57
57
|
"@ai-sdk/test-server": "2.0.4",
|
|
58
|
-
"@ai-sdk/xai": "5.0.
|
|
58
|
+
"@ai-sdk/xai": "5.0.19",
|
|
59
59
|
"@edge-runtime/vm": "^5.0.0",
|
|
60
60
|
"@smithy/eventstream-codec": "^4.3.3",
|
|
61
61
|
"@smithy/util-utf8": "^4.3.3",
|
|
@@ -4,20 +4,18 @@ import type {
|
|
|
4
4
|
Experimental_SandboxSession as SandboxSession,
|
|
5
5
|
ToolSet,
|
|
6
6
|
} from '@ai-sdk/provider-utils';
|
|
7
|
-
import type {
|
|
8
|
-
GenerateTextOnStepEndCallback,
|
|
9
|
-
GenerateTextOnStepFinishCallback,
|
|
10
|
-
} from '../generate-text/generate-text-events';
|
|
11
7
|
import type { Output } from '../generate-text/output';
|
|
12
8
|
import type { StreamTextTransform } from '../generate-text/stream-text';
|
|
13
|
-
import type { UIMessageStreamOptions } from '../generate-text/stream-text-result';
|
|
14
9
|
import type { TimeoutConfiguration } from '../prompt/request-options';
|
|
15
10
|
import { createUIMessageStreamResponse } from '../ui-message-stream';
|
|
16
11
|
import type { UIMessageStreamResponseInit } from '../ui-message-stream/ui-message-stream-response-init';
|
|
17
12
|
import type { InferUITools, UIMessage, UIDataTypes } from '../ui/ui-messages';
|
|
18
13
|
import type { Agent } from './agent';
|
|
19
14
|
import type { convertToModelMessages } from '../ui/convert-to-model-messages';
|
|
20
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
createAgentUIStream,
|
|
17
|
+
type AgentUIMessageStreamOptions,
|
|
18
|
+
} from './create-agent-ui-stream';
|
|
21
19
|
|
|
22
20
|
/**
|
|
23
21
|
* Runs the agent and returns a response object with a UI message stream.
|
|
@@ -32,6 +30,7 @@ import { createAgentUIStream } from './create-agent-ui-stream';
|
|
|
32
30
|
* @param experimental_transform - Stream transformations. Optional.
|
|
33
31
|
* @param onStepEnd - Callback that is called when each step ends. Optional.
|
|
34
32
|
* @param onStepFinish - Deprecated alias for `onStepEnd`. Optional.
|
|
33
|
+
* @param onUIMessageStepEnd - Callback with the accumulated UI message after each step. Optional.
|
|
35
34
|
* @param headers - Additional headers for the response. Optional.
|
|
36
35
|
* @param status - The status code for the response. Optional.
|
|
37
36
|
* @param statusText - The status text for the response. Optional.
|
|
@@ -73,11 +72,8 @@ export async function createAgentUIStreamResponse<
|
|
|
73
72
|
experimental_sandbox?: SandboxSession;
|
|
74
73
|
options?: CALL_OPTIONS;
|
|
75
74
|
experimental_transform?: Arrayable<StreamTextTransform<TOOLS>>;
|
|
76
|
-
onStepEnd?: GenerateTextOnStepEndCallback<TOOLS>;
|
|
77
|
-
/** @deprecated Use `onStepEnd` instead. */
|
|
78
|
-
onStepFinish?: GenerateTextOnStepFinishCallback<TOOLS>;
|
|
79
75
|
} & UIMessageStreamResponseInit &
|
|
80
|
-
|
|
76
|
+
AgentUIMessageStreamOptions<TOOLS, UI_MESSAGE>): Promise<Response> {
|
|
81
77
|
return createUIMessageStreamResponse({
|
|
82
78
|
headers,
|
|
83
79
|
status,
|
|
@@ -14,6 +14,7 @@ import type { StreamTextTransform } from '../generate-text/stream-text';
|
|
|
14
14
|
import type { UIMessageStreamOptions } from '../generate-text/stream-text-result';
|
|
15
15
|
import type { TimeoutConfiguration } from '../prompt/request-options';
|
|
16
16
|
import type { InferUIMessageChunk } from '../ui-message-stream';
|
|
17
|
+
import type { UIMessageStreamOnStepEndCallback } from '../ui-message-stream/ui-message-stream-on-step-end-callback';
|
|
17
18
|
import { toUIMessageStream } from '../ui-message-stream/to-ui-message-stream';
|
|
18
19
|
import { convertToModelMessages } from '../ui/convert-to-model-messages';
|
|
19
20
|
import type {
|
|
@@ -29,6 +30,23 @@ import {
|
|
|
29
30
|
} from '../util/async-iterable-stream';
|
|
30
31
|
import type { Agent } from './agent';
|
|
31
32
|
|
|
33
|
+
/**
|
|
34
|
+
* UI stream options with separate generation and UI message step callbacks.
|
|
35
|
+
*/
|
|
36
|
+
export type AgentUIMessageStreamOptions<
|
|
37
|
+
TOOLS extends ToolSet,
|
|
38
|
+
UI_MESSAGE extends UIMessage,
|
|
39
|
+
> = Omit<UIMessageStreamOptions<UI_MESSAGE>, 'onStepEnd' | 'onStepFinish'> & {
|
|
40
|
+
onStepEnd?: GenerateTextOnStepEndCallback<TOOLS>;
|
|
41
|
+
/** @deprecated Use `onStepEnd` instead. */
|
|
42
|
+
onStepFinish?: GenerateTextOnStepFinishCallback<TOOLS>;
|
|
43
|
+
/**
|
|
44
|
+
* Called after each step is converted to UI message parts.
|
|
45
|
+
* Receives the accumulated UI message for inspection or persistence.
|
|
46
|
+
*/
|
|
47
|
+
onUIMessageStepEnd?: UIMessageStreamOnStepEndCallback<UI_MESSAGE>;
|
|
48
|
+
};
|
|
49
|
+
|
|
32
50
|
/**
|
|
33
51
|
* Runs the agent and stream the output as a UI message stream.
|
|
34
52
|
*
|
|
@@ -42,6 +60,7 @@ import type { Agent } from './agent';
|
|
|
42
60
|
* @param experimental_transform - The stream transformations. Optional.
|
|
43
61
|
* @param onStepEnd - Callback that is called when each step ends. Optional.
|
|
44
62
|
* @param onStepFinish - Deprecated alias for `onStepEnd`. Optional.
|
|
63
|
+
* @param onUIMessageStepEnd - Callback with the accumulated UI message after each step. Optional.
|
|
45
64
|
*
|
|
46
65
|
* @returns The UI message stream.
|
|
47
66
|
*/
|
|
@@ -67,6 +86,7 @@ export async function createAgentUIStream<
|
|
|
67
86
|
experimental_transform,
|
|
68
87
|
onStepEnd,
|
|
69
88
|
onStepFinish,
|
|
89
|
+
onUIMessageStepEnd,
|
|
70
90
|
...uiMessageStreamOptions
|
|
71
91
|
}: {
|
|
72
92
|
agent: Agent<CALL_OPTIONS, TOOLS, RUNTIME_CONTEXT, OUTPUT>;
|
|
@@ -83,11 +103,8 @@ export async function createAgentUIStream<
|
|
|
83
103
|
experimental_sandbox?: SandboxSession;
|
|
84
104
|
options?: CALL_OPTIONS;
|
|
85
105
|
experimental_transform?: Arrayable<StreamTextTransform<TOOLS>>;
|
|
86
|
-
onStepEnd?: GenerateTextOnStepEndCallback<TOOLS>;
|
|
87
|
-
/** @deprecated Use `onStepEnd` instead. */
|
|
88
|
-
onStepFinish?: GenerateTextOnStepFinishCallback<TOOLS>;
|
|
89
106
|
// TODO `originalMessages` is part of this for bc, omit in v7
|
|
90
|
-
} &
|
|
107
|
+
} & AgentUIMessageStreamOptions<TOOLS, UI_MESSAGE>): Promise<
|
|
91
108
|
AsyncIterableStream<InferUIMessageChunk<UI_MESSAGE>>
|
|
92
109
|
> {
|
|
93
110
|
const validatedMessages = await validateUIMessagesForAgent<UI_MESSAGE>({
|
|
@@ -125,6 +142,7 @@ export async function createAgentUIStream<
|
|
|
125
142
|
toUIMessageStream({
|
|
126
143
|
...uiMessageStreamOptions,
|
|
127
144
|
originalMessages,
|
|
145
|
+
onStepEnd: onUIMessageStepEnd,
|
|
128
146
|
stream: result.stream,
|
|
129
147
|
tools: agent.tools,
|
|
130
148
|
}),
|
|
@@ -5,20 +5,18 @@ import type {
|
|
|
5
5
|
ToolSet,
|
|
6
6
|
} from '@ai-sdk/provider-utils';
|
|
7
7
|
import type { ServerResponse } from 'node:http';
|
|
8
|
-
import type {
|
|
9
|
-
GenerateTextOnStepEndCallback,
|
|
10
|
-
GenerateTextOnStepFinishCallback,
|
|
11
|
-
} from '../generate-text/generate-text-events';
|
|
12
8
|
import type { Output } from '../generate-text/output';
|
|
13
9
|
import type { StreamTextTransform } from '../generate-text/stream-text';
|
|
14
|
-
import type { UIMessageStreamOptions } from '../generate-text/stream-text-result';
|
|
15
10
|
import type { TimeoutConfiguration } from '../prompt/request-options';
|
|
16
11
|
import { pipeUIMessageStreamToResponse } from '../ui-message-stream';
|
|
17
12
|
import type { UIMessageStreamResponseInit } from '../ui-message-stream/ui-message-stream-response-init';
|
|
18
13
|
import type { InferUITools, UIMessage, UIDataTypes } from '../ui/ui-messages';
|
|
19
14
|
import type { Agent } from './agent';
|
|
20
15
|
import type { convertToModelMessages } from '../ui/convert-to-model-messages';
|
|
21
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
createAgentUIStream,
|
|
18
|
+
type AgentUIMessageStreamOptions,
|
|
19
|
+
} from './create-agent-ui-stream';
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
22
|
* Pipes the agent UI message stream to a Node.js ServerResponse object.
|
|
@@ -34,6 +32,7 @@ import { createAgentUIStream } from './create-agent-ui-stream';
|
|
|
34
32
|
* @param experimental_transform - Stream transformations. Optional.
|
|
35
33
|
* @param onStepEnd - Callback that is called when each step ends. Optional.
|
|
36
34
|
* @param onStepFinish - Deprecated alias for `onStepEnd`. Optional.
|
|
35
|
+
* @param onUIMessageStepEnd - Callback with the accumulated UI message after each step. Optional.
|
|
37
36
|
* @param headers - Additional headers for the response. Optional.
|
|
38
37
|
* @param status - The status code for the response. Optional.
|
|
39
38
|
* @param statusText - The status text for the response. Optional.
|
|
@@ -75,11 +74,8 @@ export async function pipeAgentUIStreamToResponse<
|
|
|
75
74
|
experimental_sandbox?: SandboxSession;
|
|
76
75
|
options?: CALL_OPTIONS;
|
|
77
76
|
experimental_transform?: Arrayable<StreamTextTransform<TOOLS>>;
|
|
78
|
-
onStepEnd?: GenerateTextOnStepEndCallback<TOOLS>;
|
|
79
|
-
/** @deprecated Use `onStepEnd` instead. */
|
|
80
|
-
onStepFinish?: GenerateTextOnStepFinishCallback<TOOLS>;
|
|
81
77
|
} & UIMessageStreamResponseInit &
|
|
82
|
-
|
|
78
|
+
AgentUIMessageStreamOptions<TOOLS, UI_MESSAGE>): Promise<void> {
|
|
83
79
|
return pipeUIMessageStreamToResponse({
|
|
84
80
|
response,
|
|
85
81
|
headers,
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Experimental_DecisionModelV4CallOptions as DecisionModelV4CallOptions,
|
|
3
3
|
Experimental_DecisionModelV4Result as DecisionModelV4Result,
|
|
4
|
+
Experimental_DecisionModelV4Question as DecisionQuestion,
|
|
4
5
|
} from '@ai-sdk/provider';
|
|
5
6
|
import type { Context, ProviderOptions } from '@ai-sdk/provider-utils';
|
|
6
|
-
import type {
|
|
7
|
+
import type { DecisionState } from './decision-state';
|
|
8
|
+
import type { DecisionResult } from './decision-result';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Event passed to the `onStart` callback for decision operations.
|
|
@@ -27,7 +29,7 @@ export type DecideStartEvent<RUNTIME_CONTEXT extends Context = Context> = {
|
|
|
27
29
|
readonly modelId: string;
|
|
28
30
|
|
|
29
31
|
/** The shared state used to make decisions. */
|
|
30
|
-
readonly state:
|
|
32
|
+
readonly state: DecisionState;
|
|
31
33
|
|
|
32
34
|
/** The questions to decide against the shared state. */
|
|
33
35
|
readonly questions: Readonly<Record<string, DecisionQuestion>>;
|
|
@@ -100,7 +102,7 @@ export type DecisionModelCallStartEvent = {
|
|
|
100
102
|
readonly state: DecisionModelV4CallOptions['state'];
|
|
101
103
|
|
|
102
104
|
/** The questions to decide against the shared state. */
|
|
103
|
-
readonly questions:
|
|
105
|
+
readonly questions: DecisionModelV4CallOptions['questions'];
|
|
104
106
|
};
|
|
105
107
|
|
|
106
108
|
/**
|
package/src/decide/decide.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Experimental_DecisionRefusalError as DecisionRefusalError,
|
|
3
3
|
Experimental_DecisionUnsupportedQuestionTypeError as DecisionUnsupportedQuestionTypeError,
|
|
4
|
-
type
|
|
4
|
+
type Experimental_DecisionModelV4Question as DecisionQuestion,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
6
|
import {
|
|
7
7
|
createIdGenerator,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type Context,
|
|
10
10
|
type ProviderOptions,
|
|
11
11
|
} from '@ai-sdk/provider-utils';
|
|
12
|
+
import { prepareDecisionState, type DecisionState } from './decision-state';
|
|
12
13
|
import { resolveDecisionModel } from '../model/resolve-model';
|
|
13
14
|
import { logWarnings } from '../logger/log-warnings';
|
|
14
15
|
import type { TelemetryOptions } from '../telemetry/telemetry-options';
|
|
@@ -17,11 +18,7 @@ import { notify } from '../util/notify';
|
|
|
17
18
|
import { prepareRetries } from '../util/prepare-retries';
|
|
18
19
|
import { VERSION } from '../version';
|
|
19
20
|
import type { DecideEndEvent, DecideStartEvent } from './decide-events';
|
|
20
|
-
import type {
|
|
21
|
-
DecisionModel,
|
|
22
|
-
DecisionQuestion,
|
|
23
|
-
DecisionResult,
|
|
24
|
-
} from './decision-result';
|
|
21
|
+
import type { DecisionModel, DecisionResult } from './decision-result';
|
|
25
22
|
import { createRestrictedTelemetryDispatcher } from './restricted-telemetry-dispatcher';
|
|
26
23
|
import {
|
|
27
24
|
validateDecisionInput,
|
|
@@ -53,7 +50,7 @@ export async function decide<
|
|
|
53
50
|
}: {
|
|
54
51
|
/** A decision model instance or an ID resolved by the configured default provider. */
|
|
55
52
|
model: DecisionModel;
|
|
56
|
-
state:
|
|
53
|
+
state: DecisionState;
|
|
57
54
|
questions: QUESTIONS;
|
|
58
55
|
/** Maximum retries for transient provider failures. Defaults to 2. */
|
|
59
56
|
maxRetries?: number;
|
|
@@ -122,12 +119,13 @@ export async function decide<
|
|
|
122
119
|
});
|
|
123
120
|
|
|
124
121
|
try {
|
|
122
|
+
const preparedState = await prepareDecisionState(state, abortSignal);
|
|
125
123
|
const modelCallEvent = {
|
|
126
124
|
callId,
|
|
127
125
|
operationId: 'ai.decide.doDecide' as const,
|
|
128
126
|
provider: model.provider,
|
|
129
127
|
modelId: model.modelId,
|
|
130
|
-
state,
|
|
128
|
+
state: preparedState,
|
|
131
129
|
questions,
|
|
132
130
|
};
|
|
133
131
|
await notify({
|
|
@@ -139,7 +137,7 @@ export async function decide<
|
|
|
139
137
|
const result = await retry(async () => {
|
|
140
138
|
abortSignal?.throwIfAborted();
|
|
141
139
|
return await model.doDecide({
|
|
142
|
-
state,
|
|
140
|
+
state: preparedState,
|
|
143
141
|
questions,
|
|
144
142
|
abortSignal,
|
|
145
143
|
headers: withUserAgentSuffix(headers ?? {}, `ai/${VERSION}`),
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Experimental_DecisionModelV4 as DecisionModelV4,
|
|
3
3
|
Experimental_EvaluationModelV4 as EvaluationModelV4,
|
|
4
|
-
Experimental_DecisionModelV4Question as DecisionModelV4Question,
|
|
5
4
|
Experimental_DecisionModelV4Result as DecisionModelV4Result,
|
|
5
|
+
Experimental_DecisionModelV4Question as DecisionQuestion,
|
|
6
6
|
} from '@ai-sdk/provider';
|
|
7
7
|
|
|
8
8
|
export type DecisionModel = string | DecisionModelV4 | EvaluationModelV4;
|
|
9
|
-
export type DecisionQuestion = DecisionModelV4Question;
|
|
10
9
|
|
|
11
10
|
export type DecisionAnswer<QUESTION extends DecisionQuestion> =
|
|
12
11
|
QUESTION extends { type: 'choice'; criteria: infer CRITERIA }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Experimental_DecisionModelV4State as DecisionModelV4State,
|
|
3
|
+
JSONObject,
|
|
4
|
+
JSONValue,
|
|
5
|
+
} from '@ai-sdk/provider';
|
|
6
|
+
import type { FilePart, TextPart } from '@ai-sdk/provider-utils';
|
|
7
|
+
import { convertToLanguageModelPrompt } from '../prompt/convert-to-language-model-prompt';
|
|
8
|
+
|
|
9
|
+
/** Shared text, JSON data, or ordered multimodal parts for a decision. */
|
|
10
|
+
export type DecisionState =
|
|
11
|
+
| string
|
|
12
|
+
| Readonly<JSONObject>
|
|
13
|
+
| readonly DecisionStatePart[];
|
|
14
|
+
|
|
15
|
+
export type DecisionStatePart =
|
|
16
|
+
| TextPart
|
|
17
|
+
| FilePart
|
|
18
|
+
| { type: 'json'; value: JSONValue };
|
|
19
|
+
|
|
20
|
+
function isDecisionStateParts(
|
|
21
|
+
state: DecisionState,
|
|
22
|
+
): state is readonly DecisionStatePart[] {
|
|
23
|
+
return Array.isArray(state);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function prepareDecisionState(
|
|
27
|
+
state: DecisionState,
|
|
28
|
+
abortSignal?: AbortSignal,
|
|
29
|
+
): Promise<DecisionModelV4State> {
|
|
30
|
+
if (typeof state === 'string') {
|
|
31
|
+
return [{ type: 'text', text: state }];
|
|
32
|
+
}
|
|
33
|
+
if (!isDecisionStateParts(state)) {
|
|
34
|
+
return [{ type: 'json', value: state }];
|
|
35
|
+
}
|
|
36
|
+
if (
|
|
37
|
+
state.every(
|
|
38
|
+
(part): part is Exclude<DecisionStatePart, FilePart> =>
|
|
39
|
+
part.type !== 'file',
|
|
40
|
+
)
|
|
41
|
+
) {
|
|
42
|
+
return state;
|
|
43
|
+
}
|
|
44
|
+
const files = state.filter((part): part is FilePart => part.type === 'file');
|
|
45
|
+
|
|
46
|
+
const prompt = await convertToLanguageModelPrompt({
|
|
47
|
+
prompt: {
|
|
48
|
+
instructions: undefined,
|
|
49
|
+
messages: [{ role: 'user', content: files }],
|
|
50
|
+
},
|
|
51
|
+
supportedUrls: {},
|
|
52
|
+
download: undefined,
|
|
53
|
+
abortSignal,
|
|
54
|
+
});
|
|
55
|
+
const message = prompt[0];
|
|
56
|
+
if (message.role !== 'user') throw new Error('Expected user message.');
|
|
57
|
+
let fileIndex = 0;
|
|
58
|
+
return state.map(part =>
|
|
59
|
+
part.type === 'file' ? message.content[fileIndex++] : part,
|
|
60
|
+
);
|
|
61
|
+
}
|
package/src/decide/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Context } from '@ai-sdk/provider-utils';
|
|
2
2
|
import { decide } from './decide';
|
|
3
|
+
import type { Experimental_DecisionModelV4Question as DecisionQuestion } from '@ai-sdk/provider';
|
|
3
4
|
import type {
|
|
4
5
|
DecideStartEvent,
|
|
5
6
|
DecideEndEvent,
|
|
@@ -8,7 +9,6 @@ import type {
|
|
|
8
9
|
} from './decide-events';
|
|
9
10
|
import type {
|
|
10
11
|
DecisionModel,
|
|
11
|
-
DecisionQuestion,
|
|
12
12
|
DecisionAnswer,
|
|
13
13
|
DecisionResult,
|
|
14
14
|
} from './decision-result';
|
|
@@ -22,7 +22,6 @@ export type {
|
|
|
22
22
|
} from './decide-events';
|
|
23
23
|
export type {
|
|
24
24
|
DecisionModel as Experimental_DecisionModel,
|
|
25
|
-
DecisionQuestion as Experimental_DecisionQuestion,
|
|
26
25
|
DecisionAnswer as Experimental_DecisionAnswer,
|
|
27
26
|
DecisionResult as Experimental_DecisionResult,
|
|
28
27
|
} from './decision-result';
|
|
@@ -62,3 +61,10 @@ export type Experimental_EvaluationAnswer<QUESTION extends DecisionQuestion> =
|
|
|
62
61
|
export type Experimental_EvaluationResult<
|
|
63
62
|
QUESTIONS extends Record<string, DecisionQuestion>,
|
|
64
63
|
> = DecisionResult<QUESTIONS>;
|
|
64
|
+
|
|
65
|
+
export type {
|
|
66
|
+
DecisionState as Experimental_DecisionState,
|
|
67
|
+
DecisionStatePart as Experimental_DecisionStatePart,
|
|
68
|
+
} from './decision-state';
|
|
69
|
+
|
|
70
|
+
export type { Experimental_DecisionModelV4Question as Experimental_DecisionQuestion } from '@ai-sdk/provider';
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
InvalidResponseDataError,
|
|
3
|
-
type Experimental_DecisionModelV4CallOptions as DecisionModelV4CallOptions,
|
|
4
3
|
type Experimental_DecisionModelV4Result as DecisionModelV4Result,
|
|
4
|
+
type Experimental_DecisionModelV4Question as DecisionQuestion,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
|
+
import { filePartSchema, textPartSchema } from '../prompt/content-part';
|
|
7
|
+
import type { DecisionState } from './decision-state';
|
|
6
8
|
import { InvalidArgumentError } from '../error/invalid-argument-error';
|
|
7
9
|
|
|
8
10
|
// Absolute tolerance for sums and means. Never renormalize provider output.
|
|
@@ -50,12 +52,30 @@ function invalidInput(
|
|
|
50
52
|
export function validateDecisionInput({
|
|
51
53
|
state,
|
|
52
54
|
questions,
|
|
53
|
-
}:
|
|
54
|
-
|
|
55
|
+
}: {
|
|
56
|
+
state: DecisionState;
|
|
57
|
+
questions: Readonly<Record<string, DecisionQuestion>>;
|
|
58
|
+
}) {
|
|
59
|
+
const validState = Array.isArray(state)
|
|
60
|
+
? Array.from(state).every(part => {
|
|
61
|
+
if (!isRecord(part)) return false;
|
|
62
|
+
switch (part.type) {
|
|
63
|
+
case 'text':
|
|
64
|
+
return textPartSchema.safeParse(part).success;
|
|
65
|
+
case 'file':
|
|
66
|
+
return filePartSchema.safeParse(part).success;
|
|
67
|
+
case 'json':
|
|
68
|
+
return isJSON(part.value);
|
|
69
|
+
default:
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
: (typeof state === 'string' || isRecord(state)) && isJSON(state);
|
|
74
|
+
if (!validState) {
|
|
55
75
|
invalidInput(
|
|
56
76
|
'state',
|
|
57
77
|
state,
|
|
58
|
-
'must be a
|
|
78
|
+
'must be a string, JSON object, or array of text, file, or json parts',
|
|
59
79
|
);
|
|
60
80
|
}
|
|
61
81
|
if (!isRecord(questions) || Object.keys(questions).length === 0) {
|
|
@@ -178,7 +198,7 @@ export function validateDecisionAnswers({
|
|
|
178
198
|
answers,
|
|
179
199
|
rounding,
|
|
180
200
|
}: {
|
|
181
|
-
questions:
|
|
201
|
+
questions: Readonly<Record<string, DecisionQuestion>>;
|
|
182
202
|
answers: unknown;
|
|
183
203
|
rounding?: DecisionModelV4Result['rounding'];
|
|
184
204
|
}) {
|
|
@@ -12,6 +12,8 @@ import type { LanguageModelResponseMetadata } from '../types/language-model-resp
|
|
|
12
12
|
import type { LanguageModelUsage } from '../types/usage';
|
|
13
13
|
import type { InferUIMessageChunk } from '../ui-message-stream/ui-message-chunks';
|
|
14
14
|
import type { UIMessageStreamOnEndCallback } from '../ui-message-stream/ui-message-stream-on-end-callback';
|
|
15
|
+
import type { UIMessageStreamOnStepEndCallback } from '../ui-message-stream/ui-message-stream-on-step-end-callback';
|
|
16
|
+
import type { UIMessageStreamOnStepFinishCallback } from '../ui-message-stream/ui-message-stream-on-step-finish-callback';
|
|
15
17
|
import type { UIMessageStreamResponseInit } from '../ui-message-stream/ui-message-stream-response-init';
|
|
16
18
|
import type { InferUIMessageMetadata, UIMessage } from '../ui/ui-messages';
|
|
17
19
|
import type { AsyncIterableStream } from '../util/async-iterable-stream';
|
|
@@ -57,6 +59,15 @@ export type UIMessageStreamOptions<UI_MESSAGE extends UIMessage> = {
|
|
|
57
59
|
*/
|
|
58
60
|
generateMessageId?: IdGenerator;
|
|
59
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Called after each step is converted to UI message parts.
|
|
64
|
+
* Receives the accumulated UI message for inspection or persistence.
|
|
65
|
+
*/
|
|
66
|
+
onStepEnd?: UIMessageStreamOnStepEndCallback<UI_MESSAGE>;
|
|
67
|
+
|
|
68
|
+
/** @deprecated Use `onStepEnd` instead. */
|
|
69
|
+
onStepFinish?: UIMessageStreamOnStepFinishCallback<UI_MESSAGE>;
|
|
70
|
+
|
|
60
71
|
onEnd?: UIMessageStreamOnEndCallback<UI_MESSAGE>;
|
|
61
72
|
|
|
62
73
|
/**
|
|
@@ -3458,6 +3458,8 @@ class DefaultStreamTextResult<
|
|
|
3458
3458
|
toUIMessageStream<UI_MESSAGE extends UIMessage>({
|
|
3459
3459
|
originalMessages,
|
|
3460
3460
|
generateMessageId,
|
|
3461
|
+
onStepEnd,
|
|
3462
|
+
onStepFinish,
|
|
3461
3463
|
onEnd,
|
|
3462
3464
|
onFinish,
|
|
3463
3465
|
messageMetadata,
|
|
@@ -3475,6 +3477,7 @@ class DefaultStreamTextResult<
|
|
|
3475
3477
|
tools: this.tools,
|
|
3476
3478
|
originalMessages,
|
|
3477
3479
|
generateMessageId,
|
|
3480
|
+
onStepEnd: onStepEnd ?? onStepFinish,
|
|
3478
3481
|
onEnd: onEnd ?? onFinish,
|
|
3479
3482
|
messageMetadata,
|
|
3480
3483
|
sendReasoning,
|
|
@@ -3491,6 +3494,8 @@ class DefaultStreamTextResult<
|
|
|
3491
3494
|
{
|
|
3492
3495
|
originalMessages,
|
|
3493
3496
|
generateMessageId,
|
|
3497
|
+
onStepEnd,
|
|
3498
|
+
onStepFinish,
|
|
3494
3499
|
onEnd,
|
|
3495
3500
|
onFinish,
|
|
3496
3501
|
messageMetadata,
|
|
@@ -3507,6 +3512,7 @@ class DefaultStreamTextResult<
|
|
|
3507
3512
|
stream: this.toUIMessageStream({
|
|
3508
3513
|
originalMessages,
|
|
3509
3514
|
generateMessageId,
|
|
3515
|
+
onStepEnd: onStepEnd ?? onStepFinish,
|
|
3510
3516
|
onEnd: onEnd ?? onFinish,
|
|
3511
3517
|
messageMetadata,
|
|
3512
3518
|
sendReasoning,
|
|
@@ -3530,6 +3536,8 @@ class DefaultStreamTextResult<
|
|
|
3530
3536
|
toUIMessageStreamResponse<UI_MESSAGE extends UIMessage>({
|
|
3531
3537
|
originalMessages,
|
|
3532
3538
|
generateMessageId,
|
|
3539
|
+
onStepEnd,
|
|
3540
|
+
onStepFinish,
|
|
3533
3541
|
onEnd,
|
|
3534
3542
|
onFinish,
|
|
3535
3543
|
messageMetadata,
|
|
@@ -3545,6 +3553,7 @@ class DefaultStreamTextResult<
|
|
|
3545
3553
|
stream: this.toUIMessageStream({
|
|
3546
3554
|
originalMessages,
|
|
3547
3555
|
generateMessageId,
|
|
3556
|
+
onStepEnd: onStepEnd ?? onStepFinish,
|
|
3548
3557
|
onEnd: onEnd ?? onFinish,
|
|
3549
3558
|
messageMetadata,
|
|
3550
3559
|
sendReasoning,
|
|
@@ -14,7 +14,7 @@ import { toUIMessageChunk } from './to-ui-message-chunk';
|
|
|
14
14
|
* Converts a stream of `TextStreamPart<TOOLS>` chunks (as emitted by
|
|
15
15
|
* `streamText`'s `stream`) into a stream of `UIMessageChunk`s suitable for
|
|
16
16
|
* UI message streaming, including response message ID injection and
|
|
17
|
-
*
|
|
17
|
+
* step and stream end callbacks.
|
|
18
18
|
*/
|
|
19
19
|
export function toUIMessageStream<
|
|
20
20
|
TOOLS extends ToolSet = ToolSet,
|
|
@@ -30,6 +30,8 @@ export function toUIMessageStream<
|
|
|
30
30
|
messageMetadata,
|
|
31
31
|
originalMessages,
|
|
32
32
|
generateMessageId,
|
|
33
|
+
onStepEnd,
|
|
34
|
+
onStepFinish,
|
|
33
35
|
onEnd,
|
|
34
36
|
onFinish,
|
|
35
37
|
}: {
|
|
@@ -130,7 +132,7 @@ export function toUIMessageStream<
|
|
|
130
132
|
responseMessageId,
|
|
131
133
|
});
|
|
132
134
|
|
|
133
|
-
if (uiMessageChunk != null) {
|
|
135
|
+
if (uiMessageChunk != null && part.type !== 'finish-step') {
|
|
134
136
|
controller.enqueue(uiMessageChunk);
|
|
135
137
|
}
|
|
136
138
|
|
|
@@ -147,6 +149,11 @@ export function toUIMessageStream<
|
|
|
147
149
|
});
|
|
148
150
|
}
|
|
149
151
|
|
|
152
|
+
// Apply step metadata before the boundary triggers a UI snapshot.
|
|
153
|
+
if (uiMessageChunk != null && part.type === 'finish-step') {
|
|
154
|
+
controller.enqueue(uiMessageChunk);
|
|
155
|
+
}
|
|
156
|
+
|
|
150
157
|
if (part.type === 'finish') {
|
|
151
158
|
setSourceOutcome({ status: 'completed' });
|
|
152
159
|
} else if (part.type === 'abort') {
|
|
@@ -166,6 +173,7 @@ export function toUIMessageStream<
|
|
|
166
173
|
stream: uiMessageChunkStream,
|
|
167
174
|
messageId: responseMessageId ?? generateMessageId?.(),
|
|
168
175
|
originalMessages,
|
|
176
|
+
onStepEnd: onStepEnd ?? onStepFinish,
|
|
169
177
|
onEnd: onEnd ?? onFinish,
|
|
170
178
|
onError,
|
|
171
179
|
getOutcome: () => outcome,
|