ai 7.0.129 → 7.0.131
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 +19 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -8
- package/dist/index.js.map +1 -1
- package/dist/internal/index.js +1 -1
- package/docs/02-foundations/04-tools.mdx +1 -1
- package/docs/03-agents/06-memory.mdx +1 -1
- package/docs/03-ai-sdk-core/32-decisions.mdx +3 -0
- package/docs/03-ai-sdk-core/42-batch.mdx +2 -2
- package/docs/03-ai-sdk-core/45-provider-management.mdx +2 -2
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/14-decide.mdx +2 -1
- package/docs/07-reference/05-ai-sdk-errors/ai-decision-refusal-error.mdx +33 -0
- package/package.json +12 -12
- package/src/decide/decide.ts +11 -0
- package/src/decide/validate-decision.ts +1 -0
- package/src/error/index.ts +1 -0
- package/src/generate-text/stream-text.ts +22 -5
package/dist/internal/index.js
CHANGED
|
@@ -227,7 +227,7 @@ import { generateText, isStepCount } from 'ai';
|
|
|
227
227
|
import { searchTool } from 'some-tool-package';
|
|
228
228
|
|
|
229
229
|
const { text } = await generateText({
|
|
230
|
-
model: 'anthropic/claude-haiku-
|
|
230
|
+
model: 'anthropic/claude-haiku-5.5',
|
|
231
231
|
prompt: 'When was Vercel Ship AI?',
|
|
232
232
|
tools: {
|
|
233
233
|
webSearch: searchTool,
|
|
@@ -248,6 +248,9 @@ substitute models automatically.
|
|
|
248
248
|
|
|
249
249
|
Invalid inputs throw `InvalidArgumentError`. Missing answers, mismatched answer
|
|
250
250
|
types, invalid options, scores, or probabilities throw `InvalidResponseDataError`.
|
|
251
|
+
If the model refuses any question, the call throws
|
|
252
|
+
`Experimental_DecisionRefusalError` with the refused question IDs, and is not
|
|
253
|
+
retried.
|
|
251
254
|
Transient provider failures use the normal retry policy (`maxRetries: 2` by
|
|
252
255
|
default). Use `abortSignal` to cancel the decisions request, `headers` for request headers,
|
|
253
256
|
and `providerOptions` for provider-specific settings.
|
|
@@ -92,13 +92,13 @@ const batch = await startBatch({
|
|
|
92
92
|
{
|
|
93
93
|
id: 'capital-france',
|
|
94
94
|
type: 'text',
|
|
95
|
-
model: 'claude-haiku-
|
|
95
|
+
model: 'claude-haiku-5-5',
|
|
96
96
|
prompt: 'What is the capital of France?',
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
id: 'capital-germany',
|
|
100
100
|
type: 'text',
|
|
101
|
-
model: 'claude-haiku-
|
|
101
|
+
model: 'claude-haiku-5-5',
|
|
102
102
|
prompt: 'What is the capital of Germany?',
|
|
103
103
|
},
|
|
104
104
|
],
|
|
@@ -80,7 +80,7 @@ export const anthropic = customProvider({
|
|
|
80
80
|
languageModels: {
|
|
81
81
|
opus: gateway('anthropic/claude-opus-5.5'),
|
|
82
82
|
sonnet: gateway('anthropic/claude-sonnet-5.5'),
|
|
83
|
-
haiku: gateway('anthropic/claude-haiku-
|
|
83
|
+
haiku: gateway('anthropic/claude-haiku-5.5'),
|
|
84
84
|
},
|
|
85
85
|
fallbackProvider: gateway,
|
|
86
86
|
});
|
|
@@ -390,7 +390,7 @@ export const registry = createProviderRegistry(
|
|
|
390
390
|
// setup model name aliases
|
|
391
391
|
anthropic: customProvider({
|
|
392
392
|
languageModels: {
|
|
393
|
-
fast: anthropic('claude-haiku-
|
|
393
|
+
fast: anthropic('claude-haiku-5-5'),
|
|
394
394
|
|
|
395
395
|
// simple model
|
|
396
396
|
writing: anthropic('claude-sonnet-4-5'),
|
|
@@ -480,7 +480,7 @@ To see `streamText` in action, check out [these examples](#examples).
|
|
|
480
480
|
type: 'AbortSignal',
|
|
481
481
|
isOptional: true,
|
|
482
482
|
description:
|
|
483
|
-
'An optional abort signal that can be used to cancel the call.',
|
|
483
|
+
'An optional abort signal that can be used to cancel the call. When it fires during streaming, pending result promises such as text and steps reject with the abort reason without waiting for onAbort or provider cancellation. Completed steps are available through onAbort.',
|
|
484
484
|
},
|
|
485
485
|
{
|
|
486
486
|
name: 'timeout',
|
|
@@ -57,7 +57,8 @@ The public core types are `Experimental_DecisionModel`,
|
|
|
57
57
|
|
|
58
58
|
Unsupported types throw `Experimental_DecisionUnsupportedQuestionTypeError`
|
|
59
59
|
before provider I/O. Invalid inputs throw `InvalidArgumentError`; malformed
|
|
60
|
-
answers throw `InvalidResponseDataError`.
|
|
60
|
+
answers throw `InvalidResponseDataError`. Questions the model refuses throw
|
|
61
|
+
`Experimental_DecisionRefusalError`. Invalid answers and refusals are not retried.
|
|
61
62
|
Neither partial results nor missing probability synthesis are supported.
|
|
62
63
|
|
|
63
64
|
## Model resolution
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AI_DecisionRefusalError
|
|
3
|
+
description: Identify decision questions that a model declined to answer.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AI_DecisionRefusalError
|
|
7
|
+
|
|
8
|
+
This experimental error identifies questions that a decision model declined to
|
|
9
|
+
answer, such as a question the provider's safety policy refuses. It is exported
|
|
10
|
+
from `ai` and `@ai-sdk/provider` as `Experimental_DecisionRefusalError`.
|
|
11
|
+
|
|
12
|
+
Decision models report a refusal as an answer with `type: 'refusal'`.
|
|
13
|
+
`experimental_decide` throws this error when any answer is a refusal, after the
|
|
14
|
+
provider call and without retrying it.
|
|
15
|
+
|
|
16
|
+
## Properties
|
|
17
|
+
|
|
18
|
+
- `questionIds`: The IDs of the refused questions.
|
|
19
|
+
- `provider`: The provider of the decision model.
|
|
20
|
+
- `modelId`: The decision model ID.
|
|
21
|
+
- `message`: A description of the refused questions and model.
|
|
22
|
+
|
|
23
|
+
## Checking for this Error
|
|
24
|
+
|
|
25
|
+
Use the marker-based `isInstance` check, which works across package copies:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { Experimental_DecisionRefusalError as DecisionRefusalError } from 'ai';
|
|
29
|
+
|
|
30
|
+
if (DecisionRefusalError.isInstance(error)) {
|
|
31
|
+
console.log(error.questionIds, error.modelId);
|
|
32
|
+
}
|
|
33
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.131",
|
|
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.107",
|
|
46
|
+
"@ai-sdk/provider": "4.0.24",
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.56"
|
|
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.109",
|
|
51
|
+
"@ai-sdk/deepseek": "3.0.61",
|
|
52
|
+
"@ai-sdk/google": "4.0.90",
|
|
53
|
+
"@ai-sdk/groq": "4.0.57",
|
|
54
|
+
"@ai-sdk/huggingface": "2.0.65",
|
|
55
|
+
"@ai-sdk/moonshotai": "3.0.65",
|
|
56
|
+
"@ai-sdk/openai": "4.0.87",
|
|
57
57
|
"@ai-sdk/test-server": "2.0.4",
|
|
58
|
-
"@ai-sdk/xai": "5.0.
|
|
58
|
+
"@ai-sdk/xai": "5.0.18",
|
|
59
59
|
"@edge-runtime/vm": "^5.0.0",
|
|
60
60
|
"@smithy/eventstream-codec": "^4.3.3",
|
|
61
61
|
"@smithy/util-utf8": "^4.3.3",
|
package/src/decide/decide.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Experimental_DecisionRefusalError as DecisionRefusalError,
|
|
2
3
|
Experimental_DecisionUnsupportedQuestionTypeError as DecisionUnsupportedQuestionTypeError,
|
|
3
4
|
type Experimental_DecisionModelV4CallOptions as DecisionModelV4CallOptions,
|
|
4
5
|
} from '@ai-sdk/provider';
|
|
@@ -152,6 +153,16 @@ export async function decide<
|
|
|
152
153
|
answers: result.answers,
|
|
153
154
|
rounding: result.rounding,
|
|
154
155
|
});
|
|
156
|
+
const refusedQuestionIds = Object.keys(questions).filter(
|
|
157
|
+
id => result.answers[id]?.type === 'refusal',
|
|
158
|
+
);
|
|
159
|
+
if (refusedQuestionIds.length > 0) {
|
|
160
|
+
throw new DecisionRefusalError({
|
|
161
|
+
questionIds: refusedQuestionIds,
|
|
162
|
+
provider: model.provider,
|
|
163
|
+
modelId: model.modelId,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
155
166
|
await notify({
|
|
156
167
|
event: { ...modelCallEvent, ...result },
|
|
157
168
|
callbacks: [telemetryDispatcher.experimental_onDecisionModelCallEnd],
|
|
@@ -203,6 +203,7 @@ export function validateDecisionAnswers({
|
|
|
203
203
|
|
|
204
204
|
for (const [id, question] of Object.entries(questions)) {
|
|
205
205
|
const answer = answers[id];
|
|
206
|
+
if (isRecord(answer) && answer.type === 'refusal') continue;
|
|
206
207
|
if (!isRecord(answer) || answer.type !== question.type) {
|
|
207
208
|
invalidAnswer(
|
|
208
209
|
answers,
|
package/src/error/index.ts
CHANGED
|
@@ -1849,16 +1849,30 @@ class DefaultStreamTextResult<
|
|
|
1849
1849
|
|
|
1850
1850
|
// resilient stream that handles abort signals and errors:
|
|
1851
1851
|
const reader = stitchableStream.stream.getReader();
|
|
1852
|
+
const cancelOnAbort = () => {
|
|
1853
|
+
// Result promises must settle before any potentially stalled callback.
|
|
1854
|
+
this.rejectResultPromises(abortSignal?.reason);
|
|
1855
|
+
// Cancelling the reader releases a pending read immediately, even when
|
|
1856
|
+
// the provider body or its cancellation promise does not settle.
|
|
1857
|
+
void reader.cancel(abortSignal?.reason).catch(() => {});
|
|
1858
|
+
};
|
|
1859
|
+
const removeAbortListener = () =>
|
|
1860
|
+
abortSignal?.removeEventListener('abort', cancelOnAbort);
|
|
1852
1861
|
let stream = new ReadableStream<InternalTextStreamPart<TOOLS>>({
|
|
1853
1862
|
async start(controller) {
|
|
1854
1863
|
// send start event:
|
|
1855
1864
|
controller.enqueue({ type: 'start' });
|
|
1865
|
+
abortSignal?.addEventListener('abort', cancelOnAbort, { once: true });
|
|
1866
|
+
if (abortSignal?.aborted) {
|
|
1867
|
+
cancelOnAbort();
|
|
1868
|
+
}
|
|
1856
1869
|
},
|
|
1857
1870
|
|
|
1858
1871
|
async pull(controller) {
|
|
1859
1872
|
// abort handling:
|
|
1860
1873
|
async function abort() {
|
|
1861
1874
|
isAborted = true;
|
|
1875
|
+
removeAbortListener();
|
|
1862
1876
|
|
|
1863
1877
|
await notify({
|
|
1864
1878
|
event: {
|
|
@@ -1885,18 +1899,20 @@ class DefaultStreamTextResult<
|
|
|
1885
1899
|
try {
|
|
1886
1900
|
const { done, value } = await reader.read();
|
|
1887
1901
|
|
|
1888
|
-
if (
|
|
1889
|
-
|
|
1902
|
+
if (abortSignal?.aborted) {
|
|
1903
|
+
await abort();
|
|
1890
1904
|
return;
|
|
1891
1905
|
}
|
|
1892
1906
|
|
|
1893
|
-
if (
|
|
1894
|
-
|
|
1907
|
+
if (done) {
|
|
1908
|
+
removeAbortListener();
|
|
1909
|
+
controller.close();
|
|
1895
1910
|
return;
|
|
1896
1911
|
}
|
|
1897
1912
|
|
|
1898
1913
|
controller.enqueue(value);
|
|
1899
1914
|
} catch (error) {
|
|
1915
|
+
removeAbortListener();
|
|
1900
1916
|
if (isAbortError(error) && abortSignal?.aborted) {
|
|
1901
1917
|
await abort();
|
|
1902
1918
|
} else {
|
|
@@ -1907,7 +1923,8 @@ class DefaultStreamTextResult<
|
|
|
1907
1923
|
},
|
|
1908
1924
|
|
|
1909
1925
|
cancel(reason) {
|
|
1910
|
-
|
|
1926
|
+
removeAbortListener();
|
|
1927
|
+
return reader.cancel(reason);
|
|
1911
1928
|
},
|
|
1912
1929
|
});
|
|
1913
1930
|
|