Skip to content

fix: should trigger request again when throttle is not undefined #5528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion content/cookbook/05-node/51-call-tools-in-parallel.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Call Tools in Parallels
title: Call Tools in Parallel
description: Learn how to call tools in parallel using the AI SDK and Node
tags: ['node', 'tool use']
---
Expand Down
6 changes: 3 additions & 3 deletions content/docs/02-getting-started/06-nodejs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ Let's enhance your chatbot by adding a simple weather tool.

Modify your `index.ts` file to include the new weather tool:

```ts filename="index.ts" highlight="2,4,25-36"
```ts filename="index.ts" highlight="2,4,25-38"
import { openai } from '@ai-sdk/openai';
import { CoreMessage, streamText, tool } from 'ai';
import dotenv from 'dotenv';
Expand Down Expand Up @@ -289,7 +289,7 @@ To solve this, you can enable multi-step tool calls using `maxSteps`. This featu

Modify your `index.ts` file to include the `maxSteps` option:

```ts filename="index.ts" highlight="37-40"
```ts filename="index.ts" highlight="39-42"
import { openai } from '@ai-sdk/openai';
import { CoreMessage, streamText, tool } from 'ai';
import dotenv from 'dotenv';
Expand Down Expand Up @@ -362,7 +362,7 @@ By setting `maxSteps` to 5, you're allowing the model to use up to 5 "steps" for

Update your `index.ts` file to add a new tool to convert the temperature from Celsius to Fahrenheit:

```ts filename="index.ts" highlight="36-45"
```ts filename="index.ts" highlight="38-49"
import { openai } from '@ai-sdk/openai';
import { CoreMessage, streamText, tool } from 'ai';
import dotenv from 'dotenv';
Expand Down
75 changes: 21 additions & 54 deletions content/providers/02-openai-compatible-providers/40-baseten.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,27 @@ To use Baseten, you can create a custom provider instance with the `createOpenAI
```ts
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';

const BASETEN_MODEL_ID = '<deployment-id>';
const BASETEN_DEPLOYMENT_ID = null;

// see https://docs.baseten.co/api-reference/openai for more information
const basetenExtraPayload = {
model_id: BASETEN_MODEL_ID,
deployment_id: BASETEN_DEPLOYMENT_ID,
};
const BASETEN_MODEL_ID = '<model-id>'; // e.g. 5q3z8xcw
const BASETEN_MODEL_URL = `https://model-${BASETEN_MODEL_ID}.api.baseten.co/environments/production/sync/v1`;

const baseten = createOpenAICompatible({
name: 'baseten',
apiKey: process.env.BASETEN_API_KEY,
baseURL: 'https://bridge.baseten.co/v1/direct',
fetch: async (url, request) => {
const bodyWithBasetenPayload = JSON.stringify({
...JSON.parse(request.body),
baseten: basetenExtraPayload,
});
return await fetch(url, { ...request, body: bodyWithBasetenPayload });
baseURL: BASETEN_MODEL_URL,
headers: {
Authorization: `Bearer ${process.env.BASETEN_API_KEY ?? ''}`,
},
});
```

Be sure to have your `BASETEN_API_KEY` set in your environment and the model `deployment id` ready. The `deployment_id` will be given after you have deployed the model on Baseten.
Be sure to have your `BASETEN_API_KEY` set in your environment and the model `<model-id>` ready. The `<model-id>` will be given after you have deployed the model on Baseten.

## Language Models

You can create [Baseten models](https://baseten.co/models) using a provider instance.
The first argument is the served model name, e.g. `ultravox`.
You can create [Baseten models](https://www.baseten.co/library/) using a provider instance.
The first argument is the served model name, e.g. `llama`.

```ts
const model = baseten('ultravox');
const model = baseten('llama');
```

### Example
Expand All @@ -74,30 +63,19 @@ You can use Baseten language models to generate text with the `generateText` fun
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
import { generateText } from 'ai';

const BASETEN_MODEL_ID = '<deployment-id>';
const BASETEN_DEPLOYMENT_ID = null;

// see https://docs.baseten.co/api-reference/openai for more information
const basetenExtraPayload = {
model_id: BASETEN_MODEL_ID,
deployment_id: BASETEN_DEPLOYMENT_ID,
};
const BASETEN_MODEL_ID = '<model-id>'; // e.g. 5q3z8xcw
const BASETEN_MODEL_URL = `https://model-${BASETEN_MODEL_ID}.api.baseten.co/environments/production/sync/v1`;

const baseten = createOpenAICompatible({
name: 'baseten',
apiKey: process.env.BASETEN_API_KEY,
baseURL: 'https://bridge.baseten.co/v1/direct',
fetch: async (url, request) => {
const bodyWithBasetenPayload = JSON.stringify({
...JSON.parse(request.body),
baseten: basetenExtraPayload,
});
return await fetch(url, { ...request, body: bodyWithBasetenPayload });
baseURL: BASETEN_MODEL_URL,
headers: {
Authorization: `Bearer ${process.env.BASETEN_API_KEY ?? ''}`,
},
});

const { text } = await generateText({
model: baseten('ultravox'),
model: baseten('llama'),
prompt: 'Tell me about yourself in one sentence',
});

Expand All @@ -110,30 +88,19 @@ Baseten language models are also able to generate text in a streaming fashion wi
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
import { streamText } from 'ai';

const BASETEN_MODEL_ID = '<deployment-id>';
const BASETEN_DEPLOYMENT_ID = null;

// see https://docs.baseten.co/api-reference/openai for more information
const basetenExtraPayload = {
model_id: BASETEN_MODEL_ID,
deployment_id: BASETEN_DEPLOYMENT_ID,
};
const BASETEN_MODEL_ID = '<model-id>'; // e.g. 5q3z8xcw
const BASETEN_MODEL_URL = `https://model-${BASETEN_MODEL_ID}.api.baseten.co/environments/production/sync/v1`;

const baseten = createOpenAICompatible({
name: 'baseten',
apiKey: process.env.BASETEN_API_KEY,
baseURL: 'https://bridge.baseten.co/v1/direct',
fetch: async (url, request) => {
const bodyWithBasetenPayload = JSON.stringify({
...JSON.parse(request.body),
baseten: basetenExtraPayload,
});
return await fetch(url, { ...request, body: bodyWithBasetenPayload });
baseURL: BASETEN_MODEL_URL,
headers: {
Authorization: `Bearer ${process.env.BASETEN_API_KEY ?? ''}`,
},
});

const result = streamText({
model: baseten('ultravox'),
model: baseten('llama'),
prompt: 'Tell me about yourself in one sentence',
});

Expand Down
4 changes: 2 additions & 2 deletions examples/ai-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"dependencies": {
"@ai-sdk/amazon-bedrock": "2.2.4",
"@ai-sdk/anthropic": "1.2.4",
"@ai-sdk/anthropic": "1.2.5",
"@ai-sdk/azure": "1.3.6",
"@ai-sdk/cerebras": "0.2.5",
"@ai-sdk/cohere": "1.2.4",
Expand All @@ -13,7 +13,7 @@
"@ai-sdk/fal": "0.1.4",
"@ai-sdk/fireworks": "0.2.5",
"@ai-sdk/google": "1.2.5",
"@ai-sdk/google-vertex": "2.2.7",
"@ai-sdk/google-vertex": "2.2.8",
"@ai-sdk/groq": "1.2.3",
"@ai-sdk/luma": "0.1.3",
"@ai-sdk/mistral": "1.2.3",
Expand Down
23 changes: 3 additions & 20 deletions examples/ai-core/src/stream-text/baseten.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,15 @@
import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
import { streamText } from 'ai';
import 'dotenv/config';

const BASETEN_MODEL_ID = '<deployment-id>';
const BASETEN_DEPLOYMENT_ID = null;

// see https://docs.baseten.co/api-reference/openai for more information
const basetenExtraPayload = {
model_id: BASETEN_MODEL_ID,
deployment_id: BASETEN_DEPLOYMENT_ID,
};
const BASETEN_MODEL_ID = '<model-id>'; // e.g. 5q3z8xcw
const BASETEN_MODEL_URL = `https://model-${BASETEN_MODEL_ID}.api.baseten.co/environments/production/sync/v1`;

const baseten = createOpenAICompatible({
name: 'baseten',
baseURL: BASETEN_MODEL_URL,
headers: {
Authorization: `Bearer ${process.env.BASETEN_API_KEY ?? ''}`,
},
baseURL: 'https://bridge.baseten.co/v1/direct',
fetch: async (url, request) => {
if (!request || !request.body) {
throw new Error('Request body is undefined');
}
const bodyWithBasetenPayload = JSON.stringify({
...JSON.parse(String(request.body)),
baseten: basetenExtraPayload,
});
return await fetch(url, { ...request, body: bodyWithBasetenPayload });
},
});

async function main() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import 'dotenv/config';
import { vertexAnthropic } from '@ai-sdk/google-vertex/anthropic';
import { streamText } from 'ai';
import fs from 'node:fs';

async function main() {
const result = streamText({
model: vertexAnthropic('claude-3-7-sonnet@20250219'),
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe the image in detail.' },
{
type: 'image',
image:
'https://github.com/vercel/ai/blob/main/examples/ai-core/data/comic-cat.png?raw=true',
},
],
},
],
});

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

main().catch(console.error);
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import fs from 'node:fs';

async function main() {
const result = streamText({
model: vertexAnthropic('claude-3-5-sonnet-v2@20241022'),
model: vertexAnthropic('claude-3-7-sonnet@20250219'),
messages: [
{
role: 'user',
Expand Down
2 changes: 1 addition & 1 deletion examples/next-google-vertex/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@ai-sdk/google-vertex": "2.2.7",
"@ai-sdk/google-vertex": "2.2.8",
"ai": "4.2.10",
"geist": "^1.3.1",
"next": "latest",
Expand Down
4 changes: 2 additions & 2 deletions examples/next-openai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
"lint": "next lint"
},
"dependencies": {
"@ai-sdk/anthropic": "1.2.4",
"@ai-sdk/anthropic": "1.2.5",
"@ai-sdk/deepseek": "0.2.5",
"@ai-sdk/fireworks": "0.2.5",
"@ai-sdk/openai": "1.3.6",
"@ai-sdk/google": "1.2.5",
"@ai-sdk/google-vertex": "2.2.7",
"@ai-sdk/google-vertex": "2.2.8",
"@ai-sdk/perplexity": "1.1.3",
"@ai-sdk/ui-utils": "1.2.4",
"@ai-sdk/react": "1.2.5",
Expand Down
6 changes: 6 additions & 0 deletions packages/anthropic/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @ai-sdk/anthropic

## 1.2.5

### Patch Changes

- 292f543: fix (provider/google-vertex): fix anthropic support for image urls in messages

## 1.2.4

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/anthropic/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ai-sdk/anthropic",
"version": "1.2.4",
"version": "1.2.5",
"license": "Apache-2.0",
"sideEffects": false,
"main": "./dist/index.js",
Expand Down
7 changes: 5 additions & 2 deletions packages/anthropic/src/anthropic-messages-language-model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
InvalidArgumentError,
LanguageModelV1,
LanguageModelV1CallWarning,
LanguageModelV1FinishReason,
Expand Down Expand Up @@ -33,6 +32,7 @@ type AnthropicMessagesConfig = {
provider: string;
baseURL: string;
headers: Resolvable<Record<string, string | undefined>>;
supportsImageUrls: boolean;
fetch?: FetchFunction;
buildRequestUrl?: (baseURL: string, isStreaming: boolean) => string;
transformRequestBody?: (args: Record<string, any>) => Record<string, any>;
Expand All @@ -41,7 +41,6 @@ type AnthropicMessagesConfig = {
export class AnthropicMessagesLanguageModel implements LanguageModelV1 {
readonly specificationVersion = 'v1';
readonly defaultObjectGenerationMode = 'tool';
readonly supportsImageUrls = true;

readonly modelId: AnthropicMessagesModelId;
readonly settings: AnthropicMessagesSettings;
Expand All @@ -62,6 +61,10 @@ export class AnthropicMessagesLanguageModel implements LanguageModelV1 {
return this.config.provider;
}

get supportsImageUrls(): boolean {
return this.config.supportsImageUrls;
}

private async getArgs({
mode,
prompt,
Expand Down
1 change: 1 addition & 0 deletions packages/anthropic/src/anthropic-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export function createAnthropic(
baseURL,
headers: getHeaders,
fetch: options.fetch,
supportsImageUrls: true,
});

const provider = function (
Expand Down
8 changes: 8 additions & 0 deletions packages/google-vertex/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @ai-sdk/google-vertex

## 2.2.8

### Patch Changes

- 292f543: fix (provider/google-vertex): fix anthropic support for image urls in messages
- Updated dependencies [292f543]
- @ai-sdk/[email protected]

## 2.2.7

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/google-vertex/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ai-sdk/google-vertex",
"version": "2.2.7",
"version": "2.2.8",
"license": "Apache-2.0",
"sideEffects": false,
"main": "./dist/index.js",
Expand Down Expand Up @@ -49,7 +49,7 @@
}
},
"dependencies": {
"@ai-sdk/anthropic": "1.2.4",
"@ai-sdk/anthropic": "1.2.5",
"@ai-sdk/google": "1.2.5",
"@ai-sdk/provider": "1.1.0",
"@ai-sdk/provider-utils": "2.2.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export function createVertexAnthropic(
baseURL,
headers: options.headers ?? {},
fetch: options.fetch,
supportsImageUrls: false,
buildRequestUrl: (baseURL, isStreaming) =>
`${baseURL}/${modelId}:${
isStreaming ? 'streamRawPredict' : 'rawPredict'
Expand Down
16 changes: 10 additions & 6 deletions packages/react/src/use-chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,15 +317,19 @@ By default, it's set to 1, which means that only a single LLM call is made.
onUpdate({ message, data, replaceLastMessage }) {
mutateStatus('streaming');

const newMessages = [
...(replaceLastMessage
? chatMessages.slice(0, chatMessages.length - 1)
: chatMessages),
message,
];

throttledMutate(
[
...(replaceLastMessage
? chatMessages.slice(0, chatMessages.length - 1)
: chatMessages),
message,
],
newMessages,
false,
);

messagesRef.current = newMessages;

if (data?.length) {
throttledMutateStreamData(
Expand Down
Loading