Skip to content

Commit 05b8ca2

Browse files
Backport: feat (provider/anthropic): support passing metadata.user_id (#13783)
This is an automated backport of #13782 to the release-v6.0 branch. FYI @shaper Co-authored-by: Walter Korman <shaper@vercel.com>
1 parent d0a7e0e commit 05b8ca2

File tree

8 files changed

+104
-0
lines changed

8 files changed

+104
-0
lines changed

.changeset/dull-hairs-impress.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ai-sdk/anthropic": patch
3+
---
4+
5+
feat (provider/anthropic): support passing metadata.user_id

content/providers/01-ai-sdk-providers/05-anthropic.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ The following optional provider options are available for Anthropic models:
146146
- `"jsonTool"`: Use a special `"json"` tool to specify the structured output format.
147147
- `"auto"`: Use `"outputFormat"` when supported, otherwise fall back to `"jsonTool"` (default).
148148

149+
- `metadata` _object_
150+
151+
Optional. Metadata to include with the request. See the [Anthropic API documentation](https://platform.claude.com/docs/en/api/messages/create) for details.
152+
153+
- `userId` _string_ - An external identifier for the end-user. Should be a UUID, hash, or other opaque identifier. Must not contain PII.
154+
149155
### Structured Outputs and Tool Input Streaming
150156

151157
Tool call streaming is enabled by default. You can opt out by setting the

content/providers/01-ai-sdk-providers/08-amazon-bedrock.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,16 @@ const { text } = await generateText({
13801380
});
13811381
```
13821382

1383+
### Provider Options
1384+
1385+
The following optional provider options are available for Bedrock Anthropic models:
1386+
1387+
- `metadata` _object_
1388+
1389+
Optional. Metadata to include with the request. See the [Anthropic API documentation](https://platform.claude.com/docs/en/api/messages/create) for details.
1390+
1391+
- `userId` _string_ - An external identifier for the end-user.
1392+
13831393
### Cache Control
13841394

13851395
In the messages and message parts, you can use the `providerOptions` property to set cache control breakpoints.

content/providers/01-ai-sdk-providers/16-google-vertex.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,6 +1429,12 @@ The following optional provider options are available for Anthropic models:
14291429

14301430
Optional. See [Reasoning section](#reasoning) for more details.
14311431

1432+
- `metadata` _object_
1433+
1434+
Optional. Metadata to include with the request. See the [Anthropic API documentation](https://platform.claude.com/docs/en/api/messages/create) for details.
1435+
1436+
- `userId` _string_ - An external identifier for the end-user.
1437+
14321438
### Reasoning
14331439

14341440
Anthropic has reasoning support for the `claude-3-7-sonnet@20250219` model.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import {
2+
anthropic,
3+
type AnthropicLanguageModelOptions,
4+
} from '@ai-sdk/anthropic';
5+
import { generateText } from 'ai';
6+
import { run } from '../../lib/run';
7+
import { print } from '../../lib/print';
8+
9+
run(async () => {
10+
const result = await generateText({
11+
model: anthropic('claude-sonnet-4-5'),
12+
prompt: 'Invent a new holiday and describe its traditions.',
13+
providerOptions: {
14+
anthropic: {
15+
metadata: { userId: 'user-123' },
16+
} satisfies AnthropicLanguageModelOptions,
17+
},
18+
});
19+
20+
print('Content:', result.text);
21+
});

packages/anthropic/src/anthropic-messages-language-model.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4442,6 +4442,42 @@ describe('AnthropicMessagesLanguageModel', () => {
44424442
expect(result.warnings).toStrictEqual([]);
44434443
});
44444444

4445+
it('should pass metadata with user_id to request body', async () => {
4446+
prepareJsonFixtureResponse('anthropic-text');
4447+
4448+
const result = await model.doGenerate({
4449+
prompt: TEST_PROMPT,
4450+
providerOptions: {
4451+
anthropic: {
4452+
metadata: { userId: 'test-user-id' },
4453+
} satisfies AnthropicLanguageModelOptions,
4454+
},
4455+
});
4456+
4457+
expect(await server.calls[0].requestBodyJson).toMatchInlineSnapshot(`
4458+
{
4459+
"max_tokens": 4096,
4460+
"messages": [
4461+
{
4462+
"content": [
4463+
{
4464+
"text": "Hello",
4465+
"type": "text",
4466+
},
4467+
],
4468+
"role": "user",
4469+
},
4470+
],
4471+
"metadata": {
4472+
"user_id": "test-user-id",
4473+
},
4474+
"model": "claude-3-haiku-20240307",
4475+
}
4476+
`);
4477+
4478+
expect(result.warnings).toStrictEqual([]);
4479+
});
4480+
44454481
describe('context management', () => {
44464482
it('should send context_management in request body', async () => {
44474483
prepareJsonFixtureResponse('anthropic-text');

packages/anthropic/src/anthropic-messages-language-model.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV3 {
388388
...(anthropicOptions?.cacheControl && {
389389
cache_control: anthropicOptions.cacheControl,
390390
}),
391+
...(anthropicOptions?.metadata?.userId != null && {
392+
metadata: { user_id: anthropicOptions.metadata.userId },
393+
}),
391394

392395
// mcp servers:
393396
...(anthropicOptions?.mcpServers &&

packages/anthropic/src/anthropic-messages-options.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ export const anthropicLanguageModelOptions = z.object({
112112
})
113113
.optional(),
114114

115+
/**
116+
* Metadata to include with the request.
117+
*
118+
* See https://platform.claude.com/docs/en/api/messages/create for details.
119+
*/
120+
metadata: z
121+
.object({
122+
/**
123+
* An external identifier for the user associated with the request.
124+
*
125+
* Should be a UUID, hash value, or other opaque identifier.
126+
* Must not contain PII (name, email, phone number, etc.).
127+
*/
128+
userId: z.string().optional(),
129+
})
130+
.optional(),
131+
115132
/**
116133
* MCP servers to be utilized in this request.
117134
*/

0 commit comments

Comments
 (0)