@ai-sdk/anthropic 3.0.126 → 3.0.127
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 +6 -0
- package/dist/index.d.mts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +50 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +50 -1
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +49 -0
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +49 -0
- package/dist/internal/index.mjs.map +1 -1
- package/docs/05-anthropic.mdx +51 -0
- package/package.json +1 -1
- package/src/anthropic-message-metadata.ts +14 -0
- package/src/anthropic-messages-api.ts +23 -0
- package/src/anthropic-messages-language-model.ts +28 -0
- package/src/anthropic-messages-options.ts +19 -0
package/docs/05-anthropic.mdx
CHANGED
|
@@ -399,6 +399,57 @@ const servedByFallback = iterations?.some(
|
|
|
399
399
|
console.log('Served by fallback:', servedByFallback);
|
|
400
400
|
```
|
|
401
401
|
|
|
402
|
+
### Dangerous Tool Use Safeguard
|
|
403
|
+
|
|
404
|
+
The `safeguards` option asks the API to run additional server-side checks as part of the request. The `dangerous_tool_use` safeguard classifies every `tool_use` block in the response for dangerous actions, such as destructive shell commands or data exfiltration, and returns a verdict per tool call. This is the check that Claude Code's auto mode relies on. The `dangerous-tool-use-2026-09-03` beta header is added for you.
|
|
405
|
+
|
|
406
|
+
```ts highlight="9-16"
|
|
407
|
+
import { anthropic, AnthropicLanguageModelOptions } from '@ai-sdk/anthropic';
|
|
408
|
+
import { generateText, tool } from 'ai';
|
|
409
|
+
import { z } from 'zod';
|
|
410
|
+
|
|
411
|
+
const result = await generateText({
|
|
412
|
+
model: anthropic('claude-sonnet-4-5'),
|
|
413
|
+
prompt: 'Use the bash tool to run: echo hello',
|
|
414
|
+
tools: { bash: tool({ inputSchema: z.object({ command: z.string() }) }) },
|
|
415
|
+
providerOptions: {
|
|
416
|
+
anthropic: {
|
|
417
|
+
safeguards: [
|
|
418
|
+
{
|
|
419
|
+
type: 'dangerous_tool_use',
|
|
420
|
+
classifierContext: { v: 1, permission_mode: 'auto' },
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
} satisfies AnthropicLanguageModelOptions,
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
console.log(result.providerMetadata?.anthropic?.safeguardResults);
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
The verdicts are available on `providerMetadata.anthropic.safeguardResults`, one entry per requested safeguard, in the API's wire shape:
|
|
431
|
+
|
|
432
|
+
```json
|
|
433
|
+
[
|
|
434
|
+
{
|
|
435
|
+
"type": "dangerous_tool_use",
|
|
436
|
+
"status": {
|
|
437
|
+
"type": "available",
|
|
438
|
+
"tool_uses": {
|
|
439
|
+
"toolu_01Ti4QpUfhLV6QqCTFVY8C7w": {
|
|
440
|
+
"type": "evaluated",
|
|
441
|
+
"outcome": "not_flagged"
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
]
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`status.type` is `available` when the classifier ran; `unsupported` means the API key is not enabled for the beta. Inside `status.tool_uses`, each tool call id maps to `evaluated` (with an `outcome` of `not_flagged` or `flagged`, the latter with an `explanation` such as `[Data Exfiltration]`), `skipped`, or `unavailable` (a transient classifier failure). When streaming, the verdicts arrive on the final `message_delta` event and are exposed on the `finish` part's provider metadata.
|
|
450
|
+
|
|
451
|
+
Anthropic's platform reference does not document the beta yet; the feature is described from the client side in the Claude Code [auto mode classifier](https://code.claude.com/docs/en/auto-mode-classifier-billing) and [gateway compatibility](https://code.claude.com/docs/en/llm-gateway-protocol#feature-pass-through) guides.
|
|
452
|
+
|
|
402
453
|
### Reasoning
|
|
403
454
|
|
|
404
455
|
Anthropic models support extended thinking, where Claude shows its reasoning process before providing a final answer.
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { JSONObject } from '@ai-sdk/provider';
|
|
2
|
+
import type { AnthropicSafeguardResult } from './anthropic-messages-api';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Represents a single iteration in the usage breakdown.
|
|
@@ -65,6 +66,19 @@ export interface AnthropicMessageMetadata {
|
|
|
65
66
|
reason: string;
|
|
66
67
|
}>;
|
|
67
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Verdicts of the server-side safeguards requested with
|
|
71
|
+
* `providerOptions.anthropic.safeguards`, one entry per requested safeguard.
|
|
72
|
+
* For `dangerous_tool_use`, `status.type` is `'available'` when the
|
|
73
|
+
* classifier ran and `status.tool_uses` maps each tool call id to its
|
|
74
|
+
* verdict (`type: 'evaluated'` with an `outcome` of `'not_flagged'` or
|
|
75
|
+
* `'flagged'` plus an `explanation`, `'skipped'`, or `'unavailable'`).
|
|
76
|
+
*
|
|
77
|
+
* Kept in the API's wire shape (snake_case), since consumers such as Claude
|
|
78
|
+
* Code read the verdicts verbatim.
|
|
79
|
+
*/
|
|
80
|
+
safeguardResults?: AnthropicSafeguardResult[];
|
|
81
|
+
|
|
68
82
|
/**
|
|
69
83
|
* Details about why the request stopped. Present only when the API returns
|
|
70
84
|
* a `refusal` stop reason together with a `stop_details` object (a
|
|
@@ -649,6 +649,27 @@ const anthropicStopDetailsSchema = z.object({
|
|
|
649
649
|
|
|
650
650
|
export type AnthropicStopDetails = z.infer<typeof anthropicStopDetailsSchema>;
|
|
651
651
|
|
|
652
|
+
const anthropicSafeguardResultSchema = z.object({
|
|
653
|
+
type: z.string(),
|
|
654
|
+
status: z.object({
|
|
655
|
+
type: z.string(),
|
|
656
|
+
tool_uses: z
|
|
657
|
+
.record(
|
|
658
|
+
z.string(),
|
|
659
|
+
z.object({
|
|
660
|
+
type: z.string(),
|
|
661
|
+
outcome: z.string().nullish(),
|
|
662
|
+
explanation: z.string().nullish(),
|
|
663
|
+
}),
|
|
664
|
+
)
|
|
665
|
+
.nullish(),
|
|
666
|
+
}),
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
export type AnthropicSafeguardResult = z.infer<
|
|
670
|
+
typeof anthropicSafeguardResultSchema
|
|
671
|
+
>;
|
|
672
|
+
|
|
652
673
|
const anthropicToolCallCallerSchema = z.union([
|
|
653
674
|
z.object({
|
|
654
675
|
type: z.literal('code_execution_20250825'),
|
|
@@ -963,6 +984,7 @@ export const anthropicMessagesResponseSchema = lazySchema(() =>
|
|
|
963
984
|
input_transformations: z
|
|
964
985
|
.array(anthropicInputTransformationSchema)
|
|
965
986
|
.nullish(),
|
|
987
|
+
safeguard_results: z.array(anthropicSafeguardResultSchema).nullish(),
|
|
966
988
|
usage: z.looseObject({
|
|
967
989
|
input_tokens: z.number(),
|
|
968
990
|
output_tokens: z.number(),
|
|
@@ -1397,6 +1419,7 @@ export const anthropicMessagesChunkSchema = lazySchema(() =>
|
|
|
1397
1419
|
stop_reason: z.string().nullish(),
|
|
1398
1420
|
stop_sequence: z.string().nullish(),
|
|
1399
1421
|
stop_details: anthropicStopDetailsSchema.nullish(),
|
|
1422
|
+
safeguard_results: z.array(anthropicSafeguardResultSchema).nullish(),
|
|
1400
1423
|
container: z
|
|
1401
1424
|
.object({
|
|
1402
1425
|
expires_at: z.string(),
|
|
@@ -702,6 +702,16 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
|
|
|
702
702
|
system: messagesPrompt.system,
|
|
703
703
|
messages: messagesPrompt.messages,
|
|
704
704
|
|
|
705
|
+
...(anthropicOptions?.safeguards &&
|
|
706
|
+
anthropicOptions.safeguards.length > 0 && {
|
|
707
|
+
safeguards: anthropicOptions.safeguards.map(safeguard => ({
|
|
708
|
+
type: safeguard.type,
|
|
709
|
+
...(safeguard.classifierContext !== undefined && {
|
|
710
|
+
classifier_context: safeguard.classifierContext,
|
|
711
|
+
}),
|
|
712
|
+
})),
|
|
713
|
+
}),
|
|
714
|
+
|
|
705
715
|
...(contextManagement && {
|
|
706
716
|
context_management: {
|
|
707
717
|
edits: contextManagement.edits
|
|
@@ -841,6 +851,13 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
|
|
|
841
851
|
betas.add('mcp-client-2025-04-04');
|
|
842
852
|
}
|
|
843
853
|
|
|
854
|
+
if (
|
|
855
|
+
anthropicOptions?.safeguards &&
|
|
856
|
+
anthropicOptions.safeguards.length > 0
|
|
857
|
+
) {
|
|
858
|
+
betas.add('dangerous-tool-use-2026-09-03');
|
|
859
|
+
}
|
|
860
|
+
|
|
844
861
|
if (contextManagement) {
|
|
845
862
|
betas.add('context-management-2025-06-27');
|
|
846
863
|
|
|
@@ -1588,6 +1605,9 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
|
|
|
1588
1605
|
...(response.input_transformations != null
|
|
1589
1606
|
? { inputTransformations: response.input_transformations }
|
|
1590
1607
|
: {}),
|
|
1608
|
+
...(response.safeguard_results != null
|
|
1609
|
+
? { safeguardResults: response.safeguard_results }
|
|
1610
|
+
: {}),
|
|
1591
1611
|
|
|
1592
1612
|
iterations: response.usage.iterations
|
|
1593
1613
|
? response.usage.iterations.map(
|
|
@@ -1732,6 +1752,7 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
|
|
|
1732
1752
|
let stopSequence: string | null = null;
|
|
1733
1753
|
let stopDetails: AnthropicMessageMetadata['stopDetails'] = undefined;
|
|
1734
1754
|
let inputTransformations: AnthropicMessageMetadata['inputTransformations'];
|
|
1755
|
+
let safeguardResults: AnthropicMessageMetadata['safeguardResults'];
|
|
1735
1756
|
let container: AnthropicMessageMetadata['container'] | null = null;
|
|
1736
1757
|
let isJsonResponseFromTool = false;
|
|
1737
1758
|
let isMessageOpen = false;
|
|
@@ -2802,6 +2823,12 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
|
|
|
2802
2823
|
inputTransformations = value.input_transformations;
|
|
2803
2824
|
}
|
|
2804
2825
|
|
|
2826
|
+
// Earlier deltas may carry null while the classifier is still
|
|
2827
|
+
// running; the last non-null value is the final verdict.
|
|
2828
|
+
if (value.delta.safeguard_results != null) {
|
|
2829
|
+
safeguardResults = value.delta.safeguard_results;
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2805
2832
|
rawUsage = {
|
|
2806
2833
|
...rawUsage,
|
|
2807
2834
|
...(value.usage as JSONObject),
|
|
@@ -2822,6 +2849,7 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
|
|
|
2822
2849
|
...(inputTransformations != null
|
|
2823
2850
|
? { inputTransformations }
|
|
2824
2851
|
: {}),
|
|
2852
|
+
...(safeguardResults != null ? { safeguardResults } : {}),
|
|
2825
2853
|
iterations: usage.iterations
|
|
2826
2854
|
? usage.iterations.map(
|
|
2827
2855
|
iter =>
|
|
@@ -364,6 +364,25 @@ export const anthropicLanguageModelOptions = z.object({
|
|
|
364
364
|
*/
|
|
365
365
|
anthropicBeta: z.array(z.string()).optional(),
|
|
366
366
|
|
|
367
|
+
/**
|
|
368
|
+
* Server-side safeguards to run as part of the request.
|
|
369
|
+
*
|
|
370
|
+
* `dangerous_tool_use` asks the API to classify every `tool_use` block in
|
|
371
|
+
* the response for dangerous actions (the check Claude Code's auto mode
|
|
372
|
+
* relies on). The per-call verdicts are returned in
|
|
373
|
+
* `providerMetadata.anthropic.safeguardResults`, keyed by tool call id.
|
|
374
|
+
* `classifierContext` is passed through to the API as `classifier_context`.
|
|
375
|
+
* The `dangerous-tool-use-2026-09-03` beta is added automatically.
|
|
376
|
+
*/
|
|
377
|
+
safeguards: z
|
|
378
|
+
.array(
|
|
379
|
+
z.object({
|
|
380
|
+
type: z.literal('dangerous_tool_use'),
|
|
381
|
+
classifierContext: z.record(z.string(), z.unknown()).optional(),
|
|
382
|
+
}),
|
|
383
|
+
)
|
|
384
|
+
.optional(),
|
|
385
|
+
|
|
367
386
|
contextManagement: z
|
|
368
387
|
.object({
|
|
369
388
|
edits: z.array(
|