Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/silver-falcons-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@ai-sdk/amazon-bedrock': patch
---

Support citations in amazon-bedrock-provider
45 changes: 45 additions & 0 deletions content/providers/01-ai-sdk-providers/08-amazon-bedrock.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,51 @@ if (result.providerMetadata?.bedrock.trace) {

See the [Amazon Bedrock Guardrails documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html) for more information.

### Citations

Amazon Bedrock supports citations for document-based inputs across compatible models. When enabled:

- Some models can read documents with visual understanding, not just extracting text
- Models can cite specific parts of documents you provide, making it easier to trace information back to its source (Not Supported Yet)

```ts
import { bedrock } from '@ai-sdk/amazon-bedrock';
import { generateObject } from 'ai';
import { z } from 'zod';
import fs from 'fs';

const result = await generateObject({
model: bedrock('apac.anthropic.claude-sonnet-4-20250514-v1:0'),
schema: z.object({
summary: z.string().describe('Summary of the PDF document'),
keyPoints: z.array(z.string()).describe('Key points from the PDF'),
}),
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'Summarize this PDF and provide key points.',
},
{
type: 'file',
data: fs.readFileSync('./document.pdf'),
mediaType: 'application/pdf',
providerOptions: {
bedrock: {
citations: { enabled: true },
},
},
},
],
},
],
});

console.log('Response:', result.object);
```

### Cache Points

<Note>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { bedrock, BedrockProviderOptions } from '@ai-sdk/amazon-bedrock';
import { generateObject } from 'ai';
import { z } from 'zod';
import fs from 'fs';
import 'dotenv/config';

async function main() {
const result = await generateObject({
model: bedrock('us.anthropic.claude-sonnet-4-20250514-v1:0'),
schema: z.object({
summary: z.string().describe('Summary of the PDF document'),
keyPoints: z.array(z.string()).describe('Key points from the PDF'),
}),
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'Summarize this PDF and provide key points.',
},
{
type: 'file',
data: fs.readFileSync('./data/ai.pdf'),
mediaType: 'application/pdf',
providerOptions: {
bedrock: {
citations: { enabled: true },
},
},
},
],
},
],
});

console.log('Response:', JSON.stringify(result, null, 2));
}

main().catch(console.error);
3 changes: 3 additions & 0 deletions packages/amazon-bedrock/src/bedrock-api-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ export interface BedrockDocumentBlock {
source: {
bytes: string;
};
citations?: {
enabled: boolean;
};
};
}

Expand Down
23 changes: 23 additions & 0 deletions packages/amazon-bedrock/src/bedrock-chat-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,29 @@ export type BedrockChatModelId =
| 'us.meta.llama4-maverick-17b-instruct-v1:0'
| (string & {});

/**
* Bedrock file part provider options for document-specific features.
* These options apply to individual file parts (documents).
*/
export const bedrockFilePartProviderOptions = z.object({
/**
* Citation configuration for this document.
* When enabled, this document will generate citations in the response.
*/
citations: z
.object({
/**
* Enable citations for this document
*/
enabled: z.boolean(),
})
.optional(),
});

export type BedrockFilePartProviderOptions = z.infer<
typeof bedrockFilePartProviderOptions
>;

export const bedrockProviderOptions = z.object({
/**
* Additional inference parameters that the model supports,
Expand Down
161 changes: 161 additions & 0 deletions packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,167 @@ describe('tool messages', () => {
});
});

describe('citations', () => {
it('should handle citations enabled for PDF', async () => {
const pdfData = new Uint8Array([0, 1, 2, 3]);

const result = await convertToBedrockChatMessages([
{
role: 'user',
content: [
{
type: 'file',
data: Buffer.from(pdfData).toString('base64'),
mediaType: 'application/pdf',
providerOptions: {
bedrock: {
citations: {
enabled: true,
},
},
},
},
],
},
]);

expect(result.messages[0].content[0]).toEqual({
document: {
format: 'pdf',
name: 'document-1',
source: {
bytes: 'AAECAw==',
},
citations: {
enabled: true,
},
},
});
});

it('should handle citations disabled for PDF', async () => {
const pdfData = new Uint8Array([0, 1, 2, 3]);

const result = await convertToBedrockChatMessages([
{
role: 'user',
content: [
{
type: 'file',
data: Buffer.from(pdfData).toString('base64'),
mediaType: 'application/pdf',
providerOptions: {
bedrock: {
citations: {
enabled: false,
},
},
},
},
],
},
]);

expect(result.messages[0].content[0]).toEqual({
document: {
format: 'pdf',
name: 'document-1',
source: {
bytes: 'AAECAw==',
},
},
});
});

it('should handle no citations specified for PDF (default)', async () => {
const pdfData = new Uint8Array([0, 1, 2, 3]);

const result = await convertToBedrockChatMessages([
{
role: 'user',
content: [
{
type: 'file',
data: Buffer.from(pdfData).toString('base64'),
mediaType: 'application/pdf',
},
],
},
]);

expect(result.messages[0].content[0]).toEqual({
document: {
format: 'pdf',
name: 'document-1',
source: {
bytes: 'AAECAw==',
},
},
});
});

it('should handle multiple PDFs with different citation settings', async () => {
const pdfData1 = new Uint8Array([0, 1, 2, 3]);
const pdfData2 = new Uint8Array([4, 5, 6, 7]);

const result = await convertToBedrockChatMessages([
{
role: 'user',
content: [
{
type: 'file',
data: Buffer.from(pdfData1).toString('base64'),
mediaType: 'application/pdf',
providerOptions: {
bedrock: {
citations: {
enabled: true,
},
},
},
},
{
type: 'file',
data: Buffer.from(pdfData2).toString('base64'),
mediaType: 'application/pdf',
providerOptions: {
bedrock: {
citations: {
enabled: false,
},
},
},
},
],
},
]);

expect(result.messages[0].content).toEqual([
{
document: {
format: 'pdf',
name: 'document-1',
source: {
bytes: 'AAECAw==',
},
citations: {
enabled: true,
},
},
},
{
document: {
format: 'pdf',
name: 'document-2',
source: {
bytes: 'BAUGBw==',
},
},
},
]);
});
});

describe('additional file format tests', () => {
it('should throw an error for unsupported file mime type in user message content', async () => {
await expect(
Expand Down
20 changes: 20 additions & 0 deletions packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,26 @@ import {
BedrockUserMessage,
} from './bedrock-api-types';
import { bedrockReasoningMetadataSchema } from './bedrock-chat-language-model';
import { bedrockFilePartProviderOptions } from './bedrock-chat-options';

function getCachePoint(
providerMetadata: SharedV2ProviderMetadata | undefined,
): BedrockCachePoint | undefined {
return providerMetadata?.bedrock?.cachePoint as BedrockCachePoint | undefined;
}

async function shouldEnableCitations(
providerMetadata: SharedV2ProviderMetadata | undefined,
): Promise<boolean> {
const bedrockOptions = await parseProviderOptions({
provider: 'bedrock',
providerOptions: providerMetadata,
schema: bedrockFilePartProviderOptions,
});

return bedrockOptions?.citations?.enabled ?? false;
}

export async function convertToBedrockChatMessages(
prompt: LanguageModelV2Prompt,
): Promise<{
Expand Down Expand Up @@ -108,11 +121,18 @@ export async function convertToBedrockChatMessages(
});
}

const enableCitations = await shouldEnableCitations(
part.providerOptions,
);

bedrockContent.push({
document: {
format: getBedrockDocumentFormat(part.mediaType),
name: generateDocumentName(),
source: { bytes: convertToBase64(part.data) },
...(enableCitations && {
citations: { enabled: true },
}),
},
});
}
Expand Down
Loading