ai 7.0.126 → 7.0.128
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 +29 -0
- package/dist/index.d.ts +234 -154
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +307 -199
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +278 -68
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +371 -72
- package/dist/internal/index.js.map +1 -1
- package/dist/test/index.d.ts +25 -17
- package/dist/test/index.d.ts.map +1 -1
- package/dist/test/index.js +27 -21
- package/dist/test/index.js.map +1 -1
- package/docs/02-getting-started/03-nextjs-pages-router.mdx +1 -1
- package/docs/02-getting-started/07-expo.mdx +1 -1
- package/docs/03-agents/07-workflow-agent.mdx +80 -12
- package/docs/03-ai-sdk-core/16-mcp-tools.mdx +44 -0
- package/docs/03-ai-sdk-core/19-tool-search.mdx +40 -4
- package/docs/03-ai-sdk-core/{32-evaluation.mdx → 32-decisions.mdx} +49 -49
- package/docs/03-ai-sdk-core/35-image-generation.mdx +6 -1
- package/docs/03-ai-sdk-core/36-transcription.mdx +42 -39
- package/docs/03-ai-sdk-core/37-speech.mdx +2 -0
- package/docs/03-ai-sdk-core/45-provider-management.mdx +8 -8
- package/docs/03-ai-sdk-core/60-telemetry.mdx +40 -31
- package/docs/03-ai-sdk-core/65-lifecycle-callbacks.mdx +21 -22
- package/docs/03-ai-sdk-harnesses/08-terminal-ui.mdx +2 -2
- package/docs/04-ai-sdk-ui/02-chatbot.mdx +2 -1
- package/docs/06-advanced/09-multistep-interfaces.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/14-decide.mdx +74 -0
- package/docs/07-reference/01-ai-sdk-core/23-create-mcp-client.mdx +58 -4
- package/docs/07-reference/01-ai-sdk-core/23-tool-search.mdx +62 -6
- package/docs/07-reference/01-ai-sdk-core/40-provider-registry.mdx +11 -11
- package/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx +9 -9
- package/docs/07-reference/01-ai-sdk-core/66-extract-reasoning-middleware.mdx +24 -8
- package/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx +13 -0
- package/docs/07-reference/02-ai-sdk-ui/32-prune-messages.mdx +1 -1
- package/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx +1 -0
- package/docs/07-reference/04-ai-sdk-workflow/01-workflow-agent.mdx +39 -2
- package/docs/07-reference/05-ai-sdk-errors/ai-decision-unsupported-question-type-error.mdx +31 -0
- package/docs/07-reference/05-ai-sdk-errors/ai-no-such-model-error.mdx +3 -3
- package/docs/07-reference/05-ai-sdk-errors/ai-no-such-provider-error.mdx +3 -3
- package/docs/08-migration-guides/23-migration-guide-7-0.mdx +1 -1
- package/docs/08-migration-guides/29-migration-guide-4-0.mdx +1 -1
- package/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx +2 -2
- package/package.json +12 -12
- package/src/decide/decide-events.ts +129 -0
- package/src/{evaluate/evaluate.ts → decide/decide.ts} +36 -38
- package/src/decide/decision-provider.ts +11 -0
- package/src/decide/decision-result.ts +39 -0
- package/src/decide/index.ts +64 -0
- package/src/{evaluate → decide}/restricted-telemetry-dispatcher.ts +7 -7
- package/src/{evaluate/validate-evaluation.ts → decide/validate-decision.ts} +9 -9
- package/src/error/index.ts +10 -1
- package/src/generate-speech/generated-audio-file.ts +5 -4
- package/src/generate-text/default-generate-text-result.ts +127 -0
- package/src/generate-text/generate-text.ts +2 -122
- package/src/generate-text/validate-tool-approvals.ts +5 -1
- package/src/global.ts +1 -1
- package/src/index.ts +1 -1
- package/src/middleware/extract-reasoning-middleware.ts +25 -6
- package/src/model/resolve-model.ts +45 -14
- package/src/registry/custom-provider.ts +38 -26
- package/src/registry/index.ts +13 -1
- package/src/registry/no-such-provider-error.ts +2 -0
- package/src/registry/provider-registry.ts +56 -29
- package/src/telemetry/create-telemetry-dispatcher.ts +17 -5
- package/src/telemetry/telemetry.ts +35 -19
- package/src/telemetry/tracing-channel.ts +1 -1
- package/src/test/decision-mock-model-v4.ts +35 -0
- package/src/tool-search/prepare-tool-search.ts +49 -29
- package/src/tool-search/tool-search.ts +58 -4
- package/src/transcribe/transcribe.ts +1 -1
- package/src/ui/chat.ts +9 -1
- package/src/ui/process-ui-message-stream.ts +21 -0
- package/src/ui-message-stream/create-ui-message-stream.ts +29 -4
- package/docs/07-reference/01-ai-sdk-core/14-evaluate.mdx +0 -74
- package/docs/07-reference/05-ai-sdk-errors/ai-evaluation-unsupported-question-type-error.mdx +0 -31
- package/src/evaluate/evaluate-events.ts +0 -131
- package/src/evaluate/evaluation-provider.ts +0 -6
- package/src/evaluate/evaluation-result.ts +0 -39
- package/src/evaluate/index.ts +0 -13
- package/src/test/evaluation-mock-model-v4.ts +0 -27
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AI_DecisionUnsupportedQuestionTypeError
|
|
3
|
+
description: Identify a decision question type that a model does not support.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AI_DecisionUnsupportedQuestionTypeError
|
|
7
|
+
|
|
8
|
+
This experimental error identifies a question whose type is unsupported by a
|
|
9
|
+
decision model. It is exported from `ai` and `@ai-sdk/provider` as
|
|
10
|
+
`Experimental_DecisionUnsupportedQuestionTypeError`.
|
|
11
|
+
|
|
12
|
+
## Properties
|
|
13
|
+
|
|
14
|
+
- `questionId`: The ID of the unsupported question.
|
|
15
|
+
- `questionType`: The requested question type.
|
|
16
|
+
- `provider`: The provider of the decision model.
|
|
17
|
+
- `modelId`: The decision model ID.
|
|
18
|
+
- `message`: A description of the unsupported question and model. Providers can
|
|
19
|
+
supply a custom message.
|
|
20
|
+
|
|
21
|
+
## Checking for this Error
|
|
22
|
+
|
|
23
|
+
Use the marker-based `isInstance` check, which works across package copies:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { Experimental_DecisionUnsupportedQuestionTypeError as DecisionUnsupportedQuestionTypeError } from 'ai';
|
|
27
|
+
|
|
28
|
+
if (DecisionUnsupportedQuestionTypeError.isInstance(error)) {
|
|
29
|
+
console.log(error.questionId, error.questionType, error.modelId);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
@@ -25,6 +25,6 @@ if (NoSuchModelError.isInstance(error)) {
|
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
Experimental
|
|
29
|
-
includes unavailable
|
|
30
|
-
provider IDs. See [
|
|
28
|
+
Experimental decision resolution uses `modelType: 'decisionModel'`. This
|
|
29
|
+
includes unavailable decision capabilities and unknown decision model or
|
|
30
|
+
provider IDs. See [Decisions](/docs/ai-sdk-core/decisions#default-provider-strings).
|
|
@@ -27,6 +27,6 @@ if (NoSuchProviderError.isInstance(error)) {
|
|
|
27
27
|
}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
Experimental
|
|
31
|
-
includes unavailable
|
|
32
|
-
provider IDs. See [
|
|
30
|
+
Experimental decision resolution uses `modelType: 'decisionModel'`. This
|
|
31
|
+
includes unavailable decision capabilities and unknown decision model or
|
|
32
|
+
provider IDs. See [Decisions](/docs/ai-sdk-core/decisions#default-provider-strings).
|
|
@@ -1385,7 +1385,7 @@ if (isToolUIPart(part)) {
|
|
|
1385
1385
|
|
|
1386
1386
|
The deprecated tool result content part of `{ type: 'media' }` has been removed in AI SDK 7.
|
|
1387
1387
|
|
|
1388
|
-
Use `{ type: 'file
|
|
1388
|
+
Use `{ type: 'file', mediaType, data: { type: 'data', data } }` for inline tool-result file content, including images, as described below. The legacy `file-data` variant still works through runtime auto-migration, but is deprecated.
|
|
1389
1389
|
|
|
1390
1390
|
#### Tool Result Content: Migrate Away From `image-*` and `file-*` variants to `file`
|
|
1391
1391
|
|
|
@@ -944,7 +944,7 @@ import { useAssistant } from '@ai-sdk/react';
|
|
|
944
944
|
code manually.
|
|
945
945
|
</Note>
|
|
946
946
|
|
|
947
|
-
The `threadId` and `messageId`
|
|
947
|
+
The `threadId` and `messageId` properties have been removed from the argument passed to the `AssistantResponse` callback. The initial response options passed to `AssistantResponse` still require both IDs.
|
|
948
948
|
Please use the `threadId` and `messageId` variables from the outer scope instead.
|
|
949
949
|
|
|
950
950
|
```ts filename="AI SDK 3.4"
|
|
@@ -57,14 +57,14 @@ const { messages, sendMessage, addToolOutput } = useChat({
|
|
|
57
57
|
try {
|
|
58
58
|
const result = await getLocationData();
|
|
59
59
|
|
|
60
|
-
// Important: Don't await inside onToolCall to avoid deadlocks
|
|
60
|
+
// Important: Don't await addToolOutput inside onToolCall to avoid deadlocks
|
|
61
61
|
addToolOutput({
|
|
62
62
|
tool: 'getLocation',
|
|
63
63
|
toolCallId: toolCall.toolCallId,
|
|
64
64
|
output: result,
|
|
65
65
|
});
|
|
66
66
|
} catch (err) {
|
|
67
|
-
// Important: Don't await inside onToolCall to avoid deadlocks
|
|
67
|
+
// Important: Don't await addToolOutput inside onToolCall to avoid deadlocks
|
|
68
68
|
addToolOutput({
|
|
69
69
|
tool: 'getLocation',
|
|
70
70
|
toolCallId: toolCall.toolCallId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.128",
|
|
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.104",
|
|
46
|
+
"@ai-sdk/provider": "4.0.22",
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.54"
|
|
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.106",
|
|
51
|
+
"@ai-sdk/deepseek": "3.0.59",
|
|
52
|
+
"@ai-sdk/google": "4.0.88",
|
|
53
|
+
"@ai-sdk/groq": "4.0.55",
|
|
54
|
+
"@ai-sdk/huggingface": "2.0.63",
|
|
55
|
+
"@ai-sdk/moonshotai": "3.0.63",
|
|
56
|
+
"@ai-sdk/openai": "4.0.84",
|
|
57
57
|
"@ai-sdk/test-server": "2.0.3",
|
|
58
|
-
"@ai-sdk/xai": "5.0.
|
|
58
|
+
"@ai-sdk/xai": "5.0.15",
|
|
59
59
|
"@edge-runtime/vm": "^5.0.0",
|
|
60
60
|
"@smithy/eventstream-codec": "^4.3.3",
|
|
61
61
|
"@smithy/util-utf8": "^4.3.3",
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Experimental_DecisionModelV4CallOptions as DecisionModelV4CallOptions,
|
|
3
|
+
Experimental_DecisionModelV4Result as DecisionModelV4Result,
|
|
4
|
+
} from '@ai-sdk/provider';
|
|
5
|
+
import type { Context, ProviderOptions } from '@ai-sdk/provider-utils';
|
|
6
|
+
import type { DecisionQuestion, DecisionResult } from './decision-result';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Event passed to the `onStart` callback for decision operations.
|
|
10
|
+
*
|
|
11
|
+
* Called when the operation begins, before the decision model is called.
|
|
12
|
+
*/
|
|
13
|
+
export type DecideStartEvent<RUNTIME_CONTEXT extends Context = Context> = {
|
|
14
|
+
/** User-defined runtime context. */
|
|
15
|
+
readonly runtimeContext: RUNTIME_CONTEXT;
|
|
16
|
+
|
|
17
|
+
/** Unique identifier for this decision call, used to correlate events. */
|
|
18
|
+
readonly callId: string;
|
|
19
|
+
|
|
20
|
+
/** Identifies the operation type (`ai.decide`). */
|
|
21
|
+
readonly operationId: 'ai.decide';
|
|
22
|
+
|
|
23
|
+
/** The provider identifier. */
|
|
24
|
+
readonly provider: string;
|
|
25
|
+
|
|
26
|
+
/** The decision model identifier. */
|
|
27
|
+
readonly modelId: string;
|
|
28
|
+
|
|
29
|
+
/** The shared state used to make decisions. */
|
|
30
|
+
readonly state: DecisionModelV4CallOptions['state'];
|
|
31
|
+
|
|
32
|
+
/** The questions to decide against the shared state. */
|
|
33
|
+
readonly questions: Readonly<Record<string, DecisionQuestion>>;
|
|
34
|
+
|
|
35
|
+
/** Maximum number of retries for the decision model call. */
|
|
36
|
+
readonly maxRetries: number;
|
|
37
|
+
|
|
38
|
+
/** Additional HTTP headers sent with the request. */
|
|
39
|
+
readonly headers: Record<string, string> | undefined;
|
|
40
|
+
|
|
41
|
+
/** Additional provider-specific options. */
|
|
42
|
+
readonly providerOptions: ProviderOptions;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Event passed to the `onEnd` callback for decision operations.
|
|
47
|
+
*
|
|
48
|
+
* Called when the operation completes successfully.
|
|
49
|
+
*/
|
|
50
|
+
export type DecideEndEvent<RUNTIME_CONTEXT extends Context = Context> =
|
|
51
|
+
DecideStartEvent<RUNTIME_CONTEXT> & {
|
|
52
|
+
/** Exactly one typed answer per question ID. */
|
|
53
|
+
readonly answers: DecisionResult<
|
|
54
|
+
Record<string, DecisionQuestion>
|
|
55
|
+
>['answers'];
|
|
56
|
+
|
|
57
|
+
/** Token usage for the decision operation. */
|
|
58
|
+
readonly usage: DecisionResult<Record<string, DecisionQuestion>>['usage'];
|
|
59
|
+
|
|
60
|
+
/** Warnings from the decision model. */
|
|
61
|
+
readonly warnings: DecisionResult<
|
|
62
|
+
Record<string, DecisionQuestion>
|
|
63
|
+
>['warnings'];
|
|
64
|
+
|
|
65
|
+
/** Provider-declared decimal precision for probabilities and scores. */
|
|
66
|
+
readonly rounding: DecisionResult<
|
|
67
|
+
Record<string, DecisionQuestion>
|
|
68
|
+
>['rounding'];
|
|
69
|
+
|
|
70
|
+
/** Optional provider-specific metadata. */
|
|
71
|
+
readonly providerMetadata: DecisionResult<
|
|
72
|
+
Record<string, DecisionQuestion>
|
|
73
|
+
>['providerMetadata'];
|
|
74
|
+
|
|
75
|
+
/** Response metadata, including the resolved model ID and timestamp. */
|
|
76
|
+
readonly response: DecisionResult<
|
|
77
|
+
Record<string, DecisionQuestion>
|
|
78
|
+
>['response'];
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Event fired when the decision model call begins.
|
|
83
|
+
*
|
|
84
|
+
* The logical model call includes any provider retries.
|
|
85
|
+
*/
|
|
86
|
+
export type DecisionModelCallStartEvent = {
|
|
87
|
+
/** Unique identifier for the outer decision call. */
|
|
88
|
+
readonly callId: string;
|
|
89
|
+
|
|
90
|
+
/** Identifies the inner operation (`ai.decide.doDecide`). */
|
|
91
|
+
readonly operationId: 'ai.decide.doDecide';
|
|
92
|
+
|
|
93
|
+
/** The provider identifier. */
|
|
94
|
+
readonly provider: string;
|
|
95
|
+
|
|
96
|
+
/** The decision model identifier. */
|
|
97
|
+
readonly modelId: string;
|
|
98
|
+
|
|
99
|
+
/** The shared state used to make decisions. */
|
|
100
|
+
readonly state: DecisionModelV4CallOptions['state'];
|
|
101
|
+
|
|
102
|
+
/** The questions to decide against the shared state. */
|
|
103
|
+
readonly questions: Readonly<Record<string, DecisionQuestion>>;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Event fired after the decision model response has been validated.
|
|
108
|
+
*
|
|
109
|
+
* Contains the result of the logical model call, including any retries.
|
|
110
|
+
*/
|
|
111
|
+
export type DecisionModelCallEndEvent = DecisionModelCallStartEvent & {
|
|
112
|
+
/** Exactly one answer per question ID. */
|
|
113
|
+
readonly answers: DecisionModelV4Result['answers'];
|
|
114
|
+
|
|
115
|
+
/** Token usage reported by the decision model. */
|
|
116
|
+
readonly usage?: DecisionModelV4Result['usage'];
|
|
117
|
+
|
|
118
|
+
/** Warnings from the decision model. */
|
|
119
|
+
readonly warnings: DecisionModelV4Result['warnings'];
|
|
120
|
+
|
|
121
|
+
/** Provider-declared decimal precision for probabilities and scores. */
|
|
122
|
+
readonly rounding?: DecisionModelV4Result['rounding'];
|
|
123
|
+
|
|
124
|
+
/** Optional provider-specific metadata. */
|
|
125
|
+
readonly providerMetadata?: DecisionModelV4Result['providerMetadata'];
|
|
126
|
+
|
|
127
|
+
/** Optional raw response metadata from the provider. */
|
|
128
|
+
readonly response?: DecisionModelV4Result['response'];
|
|
129
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
type
|
|
2
|
+
Experimental_DecisionUnsupportedQuestionTypeError as DecisionUnsupportedQuestionTypeError,
|
|
3
|
+
type Experimental_DecisionModelV4CallOptions as DecisionModelV4CallOptions,
|
|
4
4
|
} from '@ai-sdk/provider';
|
|
5
5
|
import {
|
|
6
6
|
createIdGenerator,
|
|
@@ -8,33 +8,33 @@ import {
|
|
|
8
8
|
type Context,
|
|
9
9
|
type ProviderOptions,
|
|
10
10
|
} from '@ai-sdk/provider-utils';
|
|
11
|
-
import {
|
|
11
|
+
import { resolveDecisionModel } from '../model/resolve-model';
|
|
12
12
|
import { logWarnings } from '../logger/log-warnings';
|
|
13
13
|
import type { TelemetryOptions } from '../telemetry/telemetry-options';
|
|
14
14
|
import type { Callback } from '../util/callback';
|
|
15
15
|
import { notify } from '../util/notify';
|
|
16
16
|
import { prepareRetries } from '../util/prepare-retries';
|
|
17
17
|
import { VERSION } from '../version';
|
|
18
|
-
import type {
|
|
18
|
+
import type { DecideEndEvent, DecideStartEvent } from './decide-events';
|
|
19
19
|
import type {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from './
|
|
20
|
+
DecisionModel,
|
|
21
|
+
DecisionQuestion,
|
|
22
|
+
DecisionResult,
|
|
23
|
+
} from './decision-result';
|
|
24
24
|
import { createRestrictedTelemetryDispatcher } from './restricted-telemetry-dispatcher';
|
|
25
25
|
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} from './validate-
|
|
26
|
+
validateDecisionInput,
|
|
27
|
+
validateDecisionAnswers,
|
|
28
|
+
} from './validate-decision';
|
|
29
29
|
|
|
30
30
|
const originalGenerateCallId = createIdGenerator({
|
|
31
31
|
prefix: 'call',
|
|
32
32
|
size: 24,
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
/**
|
|
36
|
-
export async function
|
|
37
|
-
const QUESTIONS extends Record<string,
|
|
35
|
+
/** Decide answers to typed questions against one shared state. Experimental. */
|
|
36
|
+
export async function decide<
|
|
37
|
+
const QUESTIONS extends Record<string, DecisionQuestion>,
|
|
38
38
|
RUNTIME_CONTEXT extends Context = Context,
|
|
39
39
|
>({
|
|
40
40
|
model: modelArg,
|
|
@@ -50,9 +50,9 @@ export async function evaluate<
|
|
|
50
50
|
onEnd,
|
|
51
51
|
_internal: { generateCallId = originalGenerateCallId } = {},
|
|
52
52
|
}: {
|
|
53
|
-
/**
|
|
54
|
-
model:
|
|
55
|
-
state:
|
|
53
|
+
/** A decision model instance or an ID resolved by the configured default provider. */
|
|
54
|
+
model: DecisionModel;
|
|
55
|
+
state: DecisionModelV4CallOptions['state'];
|
|
56
56
|
questions: QUESTIONS;
|
|
57
57
|
/** Maximum retries for transient provider failures. Defaults to 2. */
|
|
58
58
|
maxRetries?: number;
|
|
@@ -63,22 +63,22 @@ export async function evaluate<
|
|
|
63
63
|
telemetry?: TelemetryOptions<RUNTIME_CONTEXT>;
|
|
64
64
|
/** User-defined runtime context. Treat runtime context as immutable. */
|
|
65
65
|
runtimeContext?: RUNTIME_CONTEXT;
|
|
66
|
-
/** Called when the
|
|
67
|
-
onStart?: Callback<
|
|
68
|
-
/** Called when the
|
|
69
|
-
onEnd?: Callback<
|
|
66
|
+
/** Called when the decide operation begins. */
|
|
67
|
+
onStart?: Callback<DecideStartEvent<RUNTIME_CONTEXT>>;
|
|
68
|
+
/** Called when the decide operation completes. */
|
|
69
|
+
onEnd?: Callback<DecideEndEvent<RUNTIME_CONTEXT>>;
|
|
70
70
|
/** Internal. For test use only. May change without notice. */
|
|
71
71
|
_internal?: {
|
|
72
72
|
generateCallId?: () => string;
|
|
73
73
|
};
|
|
74
|
-
}): Promise<
|
|
75
|
-
const model =
|
|
74
|
+
}): Promise<DecisionResult<QUESTIONS>> {
|
|
75
|
+
const model = resolveDecisionModel(modelArg);
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
validateDecisionInput({ state, questions });
|
|
78
78
|
|
|
79
79
|
for (const [questionId, question] of Object.entries(questions)) {
|
|
80
80
|
if (!model.supportedQuestionTypes.includes(question.type)) {
|
|
81
|
-
throw new
|
|
81
|
+
throw new DecisionUnsupportedQuestionTypeError({
|
|
82
82
|
questionId,
|
|
83
83
|
questionType: question.type,
|
|
84
84
|
provider: model.provider,
|
|
@@ -101,7 +101,7 @@ export async function evaluate<
|
|
|
101
101
|
await execute());
|
|
102
102
|
const startEvent = {
|
|
103
103
|
callId,
|
|
104
|
-
operationId: 'ai.
|
|
104
|
+
operationId: 'ai.decide' as const,
|
|
105
105
|
runtimeContext,
|
|
106
106
|
provider: model.provider,
|
|
107
107
|
modelId: model.modelId,
|
|
@@ -112,7 +112,7 @@ export async function evaluate<
|
|
|
112
112
|
providerOptions,
|
|
113
113
|
};
|
|
114
114
|
return await runInTracingChannelSpan({
|
|
115
|
-
type: '
|
|
115
|
+
type: 'experimental_decide',
|
|
116
116
|
event: startEvent,
|
|
117
117
|
execute: async () => {
|
|
118
118
|
await notify({
|
|
@@ -123,7 +123,7 @@ export async function evaluate<
|
|
|
123
123
|
try {
|
|
124
124
|
const modelCallEvent = {
|
|
125
125
|
callId,
|
|
126
|
-
operationId: 'ai.
|
|
126
|
+
operationId: 'ai.decide.doDecide' as const,
|
|
127
127
|
provider: model.provider,
|
|
128
128
|
modelId: model.modelId,
|
|
129
129
|
state,
|
|
@@ -132,12 +132,12 @@ export async function evaluate<
|
|
|
132
132
|
await notify({
|
|
133
133
|
event: modelCallEvent,
|
|
134
134
|
callbacks: [
|
|
135
|
-
telemetryDispatcher.
|
|
135
|
+
telemetryDispatcher.experimental_onDecisionModelCallStart,
|
|
136
136
|
],
|
|
137
137
|
});
|
|
138
138
|
const result = await retry(async () => {
|
|
139
139
|
abortSignal?.throwIfAborted();
|
|
140
|
-
return await model.
|
|
140
|
+
return await model.doDecide({
|
|
141
141
|
state,
|
|
142
142
|
questions,
|
|
143
143
|
abortSignal,
|
|
@@ -147,16 +147,14 @@ export async function evaluate<
|
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
abortSignal?.throwIfAborted();
|
|
150
|
-
|
|
150
|
+
validateDecisionAnswers({
|
|
151
151
|
questions,
|
|
152
152
|
answers: result.answers,
|
|
153
153
|
rounding: result.rounding,
|
|
154
154
|
});
|
|
155
155
|
await notify({
|
|
156
156
|
event: { ...modelCallEvent, ...result },
|
|
157
|
-
callbacks: [
|
|
158
|
-
telemetryDispatcher.experimental_onEvaluationModelCallEnd,
|
|
159
|
-
],
|
|
157
|
+
callbacks: [telemetryDispatcher.experimental_onDecisionModelCallEnd],
|
|
160
158
|
});
|
|
161
159
|
|
|
162
160
|
logWarnings({
|
|
@@ -167,8 +165,8 @@ export async function evaluate<
|
|
|
167
165
|
|
|
168
166
|
const inputTokens = result.usage?.inputTokens;
|
|
169
167
|
const outputTokens = result.usage?.outputTokens;
|
|
170
|
-
const
|
|
171
|
-
answers: result.answers as
|
|
168
|
+
const decisionResult: DecisionResult<QUESTIONS> = {
|
|
169
|
+
answers: result.answers as DecisionResult<QUESTIONS>['answers'],
|
|
172
170
|
usage: {
|
|
173
171
|
inputTokens,
|
|
174
172
|
outputTokens,
|
|
@@ -188,11 +186,11 @@ export async function evaluate<
|
|
|
188
186
|
};
|
|
189
187
|
|
|
190
188
|
await notify({
|
|
191
|
-
event: { ...startEvent, ...
|
|
189
|
+
event: { ...startEvent, ...decisionResult },
|
|
192
190
|
callbacks: [onEnd, telemetryDispatcher.onEnd],
|
|
193
191
|
});
|
|
194
192
|
|
|
195
|
-
return
|
|
193
|
+
return decisionResult;
|
|
196
194
|
} catch (error) {
|
|
197
195
|
await telemetryDispatcher.onError?.({ callId, error });
|
|
198
196
|
throw error;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Experimental_DecisionModelV4 as DecisionModelV4,
|
|
3
|
+
Experimental_EvaluationModelV4 as EvaluationModelV4,
|
|
4
|
+
} from '@ai-sdk/provider';
|
|
5
|
+
|
|
6
|
+
/** Structural extension; decision is not part of the stable provider contract. */
|
|
7
|
+
export type DecisionProvider = {
|
|
8
|
+
decisionModel?: (modelId: string) => DecisionModelV4;
|
|
9
|
+
/** @deprecated Use `decisionModel` instead. */
|
|
10
|
+
evaluationModel?: (modelId: string) => EvaluationModelV4;
|
|
11
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Experimental_DecisionModelV4 as DecisionModelV4,
|
|
3
|
+
Experimental_EvaluationModelV4 as EvaluationModelV4,
|
|
4
|
+
Experimental_DecisionModelV4Question as DecisionModelV4Question,
|
|
5
|
+
Experimental_DecisionModelV4Result as DecisionModelV4Result,
|
|
6
|
+
} from '@ai-sdk/provider';
|
|
7
|
+
|
|
8
|
+
export type DecisionModel = string | DecisionModelV4 | EvaluationModelV4;
|
|
9
|
+
export type DecisionQuestion = DecisionModelV4Question;
|
|
10
|
+
|
|
11
|
+
export type DecisionAnswer<QUESTION extends DecisionQuestion> =
|
|
12
|
+
QUESTION extends { type: 'choice'; criteria: infer CRITERIA }
|
|
13
|
+
? {
|
|
14
|
+
type: 'choice';
|
|
15
|
+
choice: Extract<keyof CRITERIA, string>;
|
|
16
|
+
probabilities?: Record<Extract<keyof CRITERIA, string>, number>;
|
|
17
|
+
}
|
|
18
|
+
: QUESTION extends { type: 'score' }
|
|
19
|
+
? { type: 'score'; score: number; probabilities?: Record<string, number> }
|
|
20
|
+
: { type: 'boolean'; probability: number };
|
|
21
|
+
|
|
22
|
+
export type DecisionResult<QUESTIONS extends Record<string, DecisionQuestion>> =
|
|
23
|
+
{
|
|
24
|
+
readonly answers: {
|
|
25
|
+
[ID in keyof QUESTIONS]: DecisionAnswer<QUESTIONS[ID]>;
|
|
26
|
+
};
|
|
27
|
+
readonly usage: {
|
|
28
|
+
inputTokens: number | undefined;
|
|
29
|
+
outputTokens: number | undefined;
|
|
30
|
+
totalTokens: number | undefined;
|
|
31
|
+
};
|
|
32
|
+
readonly warnings: DecisionModelV4Result['warnings'];
|
|
33
|
+
readonly rounding: DecisionModelV4Result['rounding'];
|
|
34
|
+
readonly providerMetadata: DecisionModelV4Result['providerMetadata'];
|
|
35
|
+
readonly response: NonNullable<DecisionModelV4Result['response']> & {
|
|
36
|
+
timestamp: Date;
|
|
37
|
+
modelId: string;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Context } from '@ai-sdk/provider-utils';
|
|
2
|
+
import { decide } from './decide';
|
|
3
|
+
import type {
|
|
4
|
+
DecideStartEvent,
|
|
5
|
+
DecideEndEvent,
|
|
6
|
+
DecisionModelCallStartEvent,
|
|
7
|
+
DecisionModelCallEndEvent,
|
|
8
|
+
} from './decide-events';
|
|
9
|
+
import type {
|
|
10
|
+
DecisionModel,
|
|
11
|
+
DecisionQuestion,
|
|
12
|
+
DecisionAnswer,
|
|
13
|
+
DecisionResult,
|
|
14
|
+
} from './decision-result';
|
|
15
|
+
|
|
16
|
+
export { decide as experimental_decide } from './decide';
|
|
17
|
+
export type {
|
|
18
|
+
DecideStartEvent as Experimental_DecideStartEvent,
|
|
19
|
+
DecideEndEvent as Experimental_DecideEndEvent,
|
|
20
|
+
DecisionModelCallStartEvent as Experimental_DecisionModelCallStartEvent,
|
|
21
|
+
DecisionModelCallEndEvent as Experimental_DecisionModelCallEndEvent,
|
|
22
|
+
} from './decide-events';
|
|
23
|
+
export type {
|
|
24
|
+
DecisionModel as Experimental_DecisionModel,
|
|
25
|
+
DecisionQuestion as Experimental_DecisionQuestion,
|
|
26
|
+
DecisionAnswer as Experimental_DecisionAnswer,
|
|
27
|
+
DecisionResult as Experimental_DecisionResult,
|
|
28
|
+
} from './decision-result';
|
|
29
|
+
|
|
30
|
+
/** @deprecated Use `experimental_decide` instead. */
|
|
31
|
+
export const experimental_evaluate: typeof decide = decide;
|
|
32
|
+
|
|
33
|
+
/** @deprecated Use `Experimental_DecideStartEvent` instead. */
|
|
34
|
+
export type Experimental_EvaluateStartEvent<
|
|
35
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
36
|
+
> = DecideStartEvent<RUNTIME_CONTEXT>;
|
|
37
|
+
|
|
38
|
+
/** @deprecated Use `Experimental_DecideEndEvent` instead. */
|
|
39
|
+
export type Experimental_EvaluateEndEvent<
|
|
40
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
41
|
+
> = DecideEndEvent<RUNTIME_CONTEXT>;
|
|
42
|
+
|
|
43
|
+
/** @deprecated Use `Experimental_DecisionModelCallStartEvent` instead. */
|
|
44
|
+
export type Experimental_EvaluationModelCallStartEvent =
|
|
45
|
+
DecisionModelCallStartEvent;
|
|
46
|
+
|
|
47
|
+
/** @deprecated Use `Experimental_DecisionModelCallEndEvent` instead. */
|
|
48
|
+
export type Experimental_EvaluationModelCallEndEvent =
|
|
49
|
+
DecisionModelCallEndEvent;
|
|
50
|
+
|
|
51
|
+
/** @deprecated Use `Experimental_DecisionModel` instead. */
|
|
52
|
+
export type Experimental_EvaluationModel = DecisionModel;
|
|
53
|
+
|
|
54
|
+
/** @deprecated Use `Experimental_DecisionQuestion` instead. */
|
|
55
|
+
export type Experimental_EvaluationQuestion = DecisionQuestion;
|
|
56
|
+
|
|
57
|
+
/** @deprecated Use `Experimental_DecisionAnswer` instead. */
|
|
58
|
+
export type Experimental_EvaluationAnswer<QUESTION extends DecisionQuestion> =
|
|
59
|
+
DecisionAnswer<QUESTION>;
|
|
60
|
+
|
|
61
|
+
/** @deprecated Use `Experimental_DecisionResult` instead. */
|
|
62
|
+
export type Experimental_EvaluationResult<
|
|
63
|
+
QUESTIONS extends Record<string, DecisionQuestion>,
|
|
64
|
+
> = DecisionResult<QUESTIONS>;
|
|
@@ -4,7 +4,7 @@ import { filterIncludedContext } from '../telemetry/filter-included-context';
|
|
|
4
4
|
import type { TelemetryDispatcher } from '../telemetry/telemetry';
|
|
5
5
|
import type { TelemetryOptions } from '../telemetry/telemetry-options';
|
|
6
6
|
import type { Callback } from '../util/callback';
|
|
7
|
-
import type {
|
|
7
|
+
import type { DecideEndEvent, DecideStartEvent } from './decide-events';
|
|
8
8
|
|
|
9
9
|
export function createRestrictedTelemetryDispatcher<
|
|
10
10
|
RUNTIME_CONTEXT extends Context,
|
|
@@ -16,18 +16,18 @@ export function createRestrictedTelemetryDispatcher<
|
|
|
16
16
|
TelemetryDispatcher,
|
|
17
17
|
| 'onStart'
|
|
18
18
|
| 'onEnd'
|
|
19
|
-
| '
|
|
20
|
-
| '
|
|
19
|
+
| 'experimental_onDecideStart'
|
|
20
|
+
| 'experimental_onDecideEnd'
|
|
21
21
|
> & {
|
|
22
|
-
onStart: Callback<
|
|
23
|
-
onEnd: Callback<
|
|
22
|
+
onStart: Callback<DecideStartEvent<RUNTIME_CONTEXT>>;
|
|
23
|
+
onEnd: Callback<DecideEndEvent<RUNTIME_CONTEXT>>;
|
|
24
24
|
} {
|
|
25
25
|
const dispatcher = createTelemetryDispatcher({ telemetry });
|
|
26
26
|
|
|
27
27
|
return {
|
|
28
28
|
...dispatcher,
|
|
29
29
|
onStart: event =>
|
|
30
|
-
dispatcher.
|
|
30
|
+
dispatcher.experimental_onDecideStart?.({
|
|
31
31
|
...event,
|
|
32
32
|
runtimeContext: filterIncludedContext({
|
|
33
33
|
context: event.runtimeContext,
|
|
@@ -35,7 +35,7 @@ export function createRestrictedTelemetryDispatcher<
|
|
|
35
35
|
}),
|
|
36
36
|
}),
|
|
37
37
|
onEnd: event =>
|
|
38
|
-
dispatcher.
|
|
38
|
+
dispatcher.experimental_onDecideEnd?.({
|
|
39
39
|
...event,
|
|
40
40
|
runtimeContext: filterIncludedContext({
|
|
41
41
|
context: event.runtimeContext,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
InvalidResponseDataError,
|
|
3
|
-
type
|
|
4
|
-
type
|
|
3
|
+
type Experimental_DecisionModelV4CallOptions as DecisionModelV4CallOptions,
|
|
4
|
+
type Experimental_DecisionModelV4Result as DecisionModelV4Result,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
6
|
import { InvalidArgumentError } from '../error/invalid-argument-error';
|
|
7
7
|
|
|
@@ -47,10 +47,10 @@ function invalidInput(
|
|
|
47
47
|
throw new InvalidArgumentError({ parameter, value, message });
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export function
|
|
50
|
+
export function validateDecisionInput({
|
|
51
51
|
state,
|
|
52
52
|
questions,
|
|
53
|
-
}:
|
|
53
|
+
}: DecisionModelV4CallOptions) {
|
|
54
54
|
if (!isInput(state)) {
|
|
55
55
|
invalidInput(
|
|
56
56
|
'state',
|
|
@@ -173,21 +173,21 @@ function validateDistribution(
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
export function
|
|
176
|
+
export function validateDecisionAnswers({
|
|
177
177
|
questions,
|
|
178
178
|
answers,
|
|
179
179
|
rounding,
|
|
180
180
|
}: {
|
|
181
|
-
questions:
|
|
181
|
+
questions: DecisionModelV4CallOptions['questions'];
|
|
182
182
|
answers: unknown;
|
|
183
|
-
rounding?:
|
|
183
|
+
rounding?: DecisionModelV4Result['rounding'];
|
|
184
184
|
}) {
|
|
185
185
|
function roundingError(decimals: number | undefined): number {
|
|
186
186
|
if (decimals === undefined) return 0;
|
|
187
187
|
if (!Number.isInteger(decimals) || decimals < 0 || decimals > 15) {
|
|
188
188
|
invalidAnswer(
|
|
189
189
|
answers,
|
|
190
|
-
'
|
|
190
|
+
'Decision rounding decimals must be integers between 0 and 15.',
|
|
191
191
|
);
|
|
192
192
|
}
|
|
193
193
|
return 0.5 * 10 ** -decimals;
|
|
@@ -197,7 +197,7 @@ export function validateEvaluationAnswers({
|
|
|
197
197
|
if (!isRecord(answers) || !hasExactKeys(answers, Object.keys(questions))) {
|
|
198
198
|
invalidAnswer(
|
|
199
199
|
answers,
|
|
200
|
-
'
|
|
200
|
+
'Decision must return exactly one answer for every question.',
|
|
201
201
|
);
|
|
202
202
|
}
|
|
203
203
|
|