Skip to content

Commit

Permalink
ai/core anthropic provider (no tool calls) (#1260)
Browse files Browse the repository at this point in the history
  • Loading branch information
lgrammel authored Apr 4, 2024
1 parent b7732d7 commit 63d587e
Show file tree
Hide file tree
Showing 25 changed files with 1,036 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .changeset/nine-pears-applaud.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'ai': patch
---

Add Anthropic provider for ai/core functions (no tool calling).
5 changes: 5 additions & 0 deletions .changeset/six-years-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'ai': patch
---

Add automatic mime type detection for images in ai/core prompts.
1 change: 1 addition & 0 deletions docs/pages/docs/ai-core/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"openai": "OpenAI Provider",
"mistral": "Mistral Provider",
"google": "Google Provider",
"anthropic": "Anthropic Provider",
"custom-provider": "Custom Providers",
"generate-text": "generateText API",
"stream-text": "streamText API",
Expand Down
50 changes: 50 additions & 0 deletions docs/pages/docs/ai-core/anthropic.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: Anthropic Provider
---

import { Callout } from 'nextra-theme-docs';

# Anthropic Provider

<Callout>The Anthropic provider does not support tool calling yet.</Callout>

The Anthropic provider contains language model support for the [Anthropic Messages API](https://docs.anthropic.com/claude/reference/messages_post).
It creates language model objects that can be used with the `generateText` and `streamText`AI functions.

## Provider Instance

You can import `Anthropic` from `ai/anthropic` and initialize a provider instance with various settings:

```ts
import { Anthropic } from 'ai/anthropic';

const anthropic = new Anthropic({
baseUrl: '', // optional base URL for proxies etc.
apiKey: '', // optional API key, default to env property ANTHROPIC_API_KEY
});
```

The AI SDK also provides a shorthand `anthropic` import with a Anthropic provider instance that uses defaults:

```ts
import { anthropic } from 'ai/anthropic';
```

## Messages Models

You can create models that call the [Anthropic Messages API](https://docs.anthropic.com/claude/reference/messages_post) using the `.messages()` factory method.
The first argument is the model id, e.g. `claude-3-haiku-20240307`.
Some models have multi-modal capabilities.

```ts
const model = anthropic.messages('claude-3-haiku-20240307');
```

Anthropic Messages` models support also some model specific settings that are not part of the [standard call settings](/docs/ai-core/settings).
You can pass them as an options argument:

```ts
const model = anthropic.messages('claude-3-haiku-20240307', {
topK: 0.2,
});
```
1 change: 1 addition & 0 deletions docs/pages/docs/ai-core/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ The AI SDK contains the following providers:
- [OpenAI Provider](/docs/ai-core/openai) (`ai/openai`)
- [Mistral Provider](/docs/ai-core/mistral) (`ai/mistral`)
- [Google Provider](/docs/ai-core/google) (`ai/google`)
- [Anthropic Provider](/docs/ai-core/anthropic) (`ai/anthropic`)

The AI SDK also provides a [language model specification](https://github.com/vercel/ai/tree/main/packages/core/spec/language-model/v1) that you can use to implement [custom providers](/docs/ai-core/custom-provider).

Expand Down
3 changes: 2 additions & 1 deletion examples/ai-core/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
ANTHROPIC_API_KEY=""
OPENAI_API_KEY=""
MISTRAL_API_KEY=""
GOOGLE_GENERATIVE_AI_API_KEY=""
GOOGLE_GENERATIVE_AI_API_KEY=""
26 changes: 26 additions & 0 deletions examples/ai-core/src/generate-text/anthropic-multimodal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { experimental_generateText } from 'ai';
import { anthropic } from 'ai/anthropic';
import dotenv from 'dotenv';
import fs from 'node:fs';

dotenv.config();

async function main() {
const result = await experimental_generateText({
model: anthropic.messages('claude-3-haiku-20240307'),
maxTokens: 512,
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe the image in detail.' },
{ type: 'image', image: fs.readFileSync('./data/comic-cat.png') },
],
},
],
});

console.log(result.text);
}

main();
19 changes: 19 additions & 0 deletions examples/ai-core/src/generate-text/anthropic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { experimental_generateText } from 'ai';
import { anthropic } from 'ai/anthropic';
import dotenv from 'dotenv';

dotenv.config();

async function main() {
const result = await experimental_generateText({
model: anthropic.messages('claude-3-haiku-20240307'),
prompt: 'Invent a new holiday and describe its traditions.',
});

console.log(result.text);
console.log();
console.log('Token usage:', result.usage);
console.log('Finish reason:', result.finishReason);
}

main();
28 changes: 28 additions & 0 deletions examples/ai-core/src/stream-text/anthropic-multimodal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { experimental_streamText } from 'ai';
import { anthropic } from 'ai/anthropic';
import dotenv from 'dotenv';
import fs from 'node:fs';

dotenv.config();

async function main() {
const result = await experimental_streamText({
model: anthropic.messages('claude-3-haiku-20240307'),
maxTokens: 512,
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe the image in detail.' },
{ type: 'image', image: fs.readFileSync('./data/comic-cat.png') },
],
},
],
});

for await (const textPart of result.textStream) {
process.stdout.write(textPart);
}
}

main();
18 changes: 18 additions & 0 deletions examples/ai-core/src/stream-text/anthropic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { experimental_streamText } from 'ai';
import { anthropic } from 'ai/anthropic';
import dotenv from 'dotenv';

dotenv.config();

async function main() {
const result = await experimental_streamText({
model: anthropic.messages('claude-3-haiku-20240307'),
prompt: 'Invent a new holiday and describe its traditions.',
});

for await (const textPart of result.textStream) {
process.stdout.write(textPart);
}
}

main();
17 changes: 17 additions & 0 deletions packages/core/anthropic/anthropic-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { z } from 'zod';
import { createJsonErrorResponseHandler } from '../spec';

const anthropicErrorDataSchema = z.object({
type: z.literal('error'),
error: z.object({
type: z.string(),
message: z.string(),
}),
});

export type AnthropicErrorData = z.infer<typeof anthropicErrorDataSchema>;

export const anthropicFailedResponseHandler = createJsonErrorResponseHandler({
errorSchema: anthropicErrorDataSchema,
errorToMessage: data => data.error.message,
});
58 changes: 58 additions & 0 deletions packages/core/anthropic/anthropic-facade.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { generateId, loadApiKey } from '../spec';
import { AnthropicMessagesLanguageModel } from './anthropic-messages-language-model';
import {
AnthropicMessagesModelId,
AnthropicMessagesSettings,
} from './anthropic-messages-settings';

/**
* Anthropic provider.
*/
export class Anthropic {
readonly baseUrl?: string;
readonly apiKey?: string;

private readonly generateId: () => string;

constructor(
options: {
baseUrl?: string;
apiKey?: string;
generateId?: () => string;
} = {},
) {
this.baseUrl = options.baseUrl;
this.apiKey = options.apiKey;
this.generateId = options.generateId ?? generateId;
}

private get baseConfig() {
return {
baseUrl: this.baseUrl ?? 'https://api.anthropic.com/v1',
headers: () => ({
'anthropic-version': '2023-06-01',
'x-api-key': loadApiKey({
apiKey: this.apiKey,
environmentVariableName: 'ANTHROPIC_API_KEY',
description: 'Anthropic',
}),
}),
};
}

messages(
modelId: AnthropicMessagesModelId,
settings: AnthropicMessagesSettings = {},
) {
return new AnthropicMessagesLanguageModel(modelId, settings, {
provider: 'anthropic.messages',
...this.baseConfig,
generateId: this.generateId,
});
}
}

/**
* Default Anthropic provider instance.
*/
export const anthropic = new Anthropic();
Loading

0 comments on commit 63d587e

Please sign in to comment.