Skip to content

Connect Claude, Gemini and other vendors through the Vercel AI SDK

Bring an @ai-sdk/* package — Anthropic, Google, Amazon Bedrock and the others the SDK supports — and the chat streams its replies, reasoning and tool calls.

On this page
bash
npm install @aparte/core @aparte/provider-ai-sdk ai @ai-sdk/anthropic
ts
import { createAnthropic } from '@ai-sdk/anthropic';
import { createAiSdkProvider } from '@aparte/provider-ai-sdk';
import { aparteGlobalConfig, AparteClient, AparteDirectTransport } from '@aparte/core';

aparteGlobalConfig.registerAIProvider(createAiSdkProvider({
  id: 'anthropic',
  name: 'Anthropic',
  languageModel: (modelId, auth) =>
    createAnthropic({
      apiKey: typeof auth === 'string' ? auth : auth?.apiKey,
      headers: { 'anthropic-dangerous-direct-browser-access': 'true' },   // a key used from the browser
    })(modelId),
}));
aparteGlobalConfig.setTransport(new AparteDirectTransport({ byok: true }));
aparteGlobalConfig.setModelConfig({ defaultProvider: 'anthropic', defaultModel: 'claude-sonnet-4-5' });
new AparteClient({
  keyResolver: (providerId) => localStorage.getItem(`${providerId}.key`) ?? undefined,   // the person's key
}).start();

The provider needs ai in the range ^7.0.0 beside it, and the @ai-sdk/* package of your vendor; its options are an AiSdkProviderOptions. languageModel is called for each request with the model’s id and what the key resolver answered, so a key the person types reaches the vendor’s SDK; a factory that already holds its key ignores auth. Stop cancels the vendor’s call.

The SDK has no list of models to fetch. Choose the model with setModelConfig, as above, or give the provider a models option: the model selector lists those, and the client reads a model’s capabilities from them; a model without capabilities is sent the tools. Without models, the selector shows nothing for this provider.

From the SDKIn the chat
textthe reply
reasoninga reasoning block
a tool calla tool the chat runs, then calls the model again
the finish, with its usagethe end of the reply, with its tokens, cached ones included
an errorthe message’s error

The provider calls streamText for one step at a time: the tools go as declarations without an execute, and the chat’s loop runs them. An image in the person’s message goes as an image part.

toModelMessages, toToolSet, toToolChoice and fullStreamToAparteEvents are exported on their own, to answer the chat from a route that already uses the SDK (Keep the key on your server). fullStreamToAparteEvents passes the vendor’s error text along, and a vendor’s refusal can quote parts of the key: replace an error event with a message of your own before it leaves the server.