diff --git a/.changeset/chilly-bees-sin.md b/.changeset/chilly-bees-sin.md new file mode 100644 index 000000000000..7af27a68c1ab --- /dev/null +++ b/.changeset/chilly-bees-sin.md @@ -0,0 +1,6 @@ +--- +'@ai-sdk/anthropic': patch +'@example/ai-core': patch +--- + +Adds url-based pdf support for tool results diff --git a/examples/ai-core/src/generate-text/anthropic-pdf-tool-results.ts b/examples/ai-core/src/generate-text/anthropic-pdf-tool-results-base64.ts similarity index 100% rename from examples/ai-core/src/generate-text/anthropic-pdf-tool-results.ts rename to examples/ai-core/src/generate-text/anthropic-pdf-tool-results-base64.ts diff --git a/examples/ai-core/src/generate-text/anthropic-pdf-tool-results-url.ts b/examples/ai-core/src/generate-text/anthropic-pdf-tool-results-url.ts new file mode 100644 index 000000000000..3c8be263971d --- /dev/null +++ b/examples/ai-core/src/generate-text/anthropic-pdf-tool-results-url.ts @@ -0,0 +1,50 @@ +import { generateText, stepCountIs, tool } from 'ai'; +import { run } from '../lib/run'; +import { z } from 'zod'; +import { anthropic } from '@ai-sdk/anthropic'; + +run(async () => { + const readPDFDocument = tool({ + description: `Read and return a PDF document`, + inputSchema: z.object({}), + execute: async () => { + try { + return { + success: true, + description: 'Successfully loaded PDF document', + pdfUrl: 'https://arxiv.org/pdf/2001.08361', // Scaling Laws Paper + }; + } catch (error) { + throw new Error(`Failed to analyze PDF: ${error}`); + } + }, + toModelOutput(result) { + return { + type: 'content', + value: [ + { + type: 'text', + text: result.description, + }, + { + type: 'media', + data: result.pdfUrl, + mediaType: 'application/pdf', + }, + ], + }; + }, + }); + + const result = await generateText({ + model: anthropic('claude-sonnet-4-0'), + prompt: + 'Please read the pdf document using the tool provided and return the summary of that pdf', + tools: { + readPDFDocument, + }, + stopWhen: stepCountIs(4), + }); + + console.log(`Assisstant response : ${JSON.stringify(result.text, null, 2)}`); +}); diff --git a/packages/anthropic/package.json b/packages/anthropic/package.json index 2a60f8e7cf41..80ec4a724000 100644 --- a/packages/anthropic/package.json +++ b/packages/anthropic/package.json @@ -1,5 +1,5 @@ { - "name": "@ai-sdk/anthropic", + "name": "@flatfile/anthropic", "version": "3.0.0-beta.24", "license": "Apache-2.0", "sideEffects": false, diff --git a/packages/anthropic/src/convert-to-anthropic-messages-prompt.test.ts b/packages/anthropic/src/convert-to-anthropic-messages-prompt.test.ts index e612d102efb1..781291c4d30b 100644 --- a/packages/anthropic/src/convert-to-anthropic-messages-prompt.test.ts +++ b/packages/anthropic/src/convert-to-anthropic-messages-prompt.test.ts @@ -491,7 +491,7 @@ describe('tool messages', () => { `); }); - it('should handle tool result with PDF content', async () => { + it('should handle tool result with base64 PDF content', async () => { const result = await convertToAnthropicMessagesPrompt({ prompt: [ { @@ -563,6 +563,78 @@ describe('tool messages', () => { } `); }); + + it('should handle tool result with url-based PDF content', async () => { + const result = await convertToAnthropicMessagesPrompt({ + prompt: [ + { + role: 'tool', + content: [ + { + type: 'tool-result', + toolName: 'image-generator', + toolCallId: 'image-gen-1', + output: { + type: 'content', + value: [ + { + type: 'media', + data: 'https://example.com/document.pdf', + mediaType: 'application/pdf', + }, + { + type: 'text', + text: 'Document loaded successfully', + }, + ], + }, + }, + ], + }, + ], + sendReasoning: true, + warnings: [], + }); + + expect(result).toMatchInlineSnapshot(` + { + "betas": Set { + "pdfs-2024-09-25", + }, + "prompt": { + "messages": [ + { + "content": [ + { + "cache_control": undefined, + "content": [ + { + "cache_control": undefined, + "source": { + "type": "url", + "url": "https://example.com/document.pdf", + }, + "type": "document", + }, + { + "cache_control": undefined, + "text": "Document loaded successfully", + "type": "text", + }, + ], + "is_error": undefined, + "tool_use_id": "image-gen-1", + "type": "tool_result", + }, + ], + "role": "user", + }, + ], + "system": undefined, + }, + } + `); + }); }); describe('assistant messages', () => { diff --git a/packages/anthropic/src/convert-to-anthropic-messages-prompt.ts b/packages/anthropic/src/convert-to-anthropic-messages-prompt.ts index 4b4c15baddf8..04cb4dce0bfe 100644 --- a/packages/anthropic/src/convert-to-anthropic-messages-prompt.ts +++ b/packages/anthropic/src/convert-to-anthropic-messages-prompt.ts @@ -46,6 +46,15 @@ function convertToString(data: LanguageModelV3DataContent): string { }); } +function isValidUrl(string: string): boolean { + try { + new URL(string); + return true; + } catch { + return false; + } +} + export async function convertToAnthropicMessagesPrompt({ prompt, sendReasoning, @@ -268,6 +277,16 @@ export async function convertToAnthropicMessagesPrompt({ }; case 'media': { if (contentPart.mediaType.startsWith('image/')) { + if (isValidUrl(contentPart.data)) { + return { + type: 'image', + source: { + type: 'url', + url: contentPart.data, + }, + cache_control: undefined, + }; + } return { type: 'image', source: { @@ -282,6 +301,17 @@ export async function convertToAnthropicMessagesPrompt({ if (contentPart.mediaType === 'application/pdf') { betas.add('pdfs-2024-09-25'); + if (isValidUrl(contentPart.data)) { + return { + type: 'document', + source: { + type: 'url', + url: contentPart.data, + }, + cache_control: undefined, + }; + } + return { type: 'document', source: {