ahmedallem.
Engineering · 3 min read

Getting Started with Allem SDK AI: Multi-Provider Chat Hooks for React

Learn how to set up @allem-sdk/ai with streaming chat and completion hooks that support Google Gemini, Anthropic Claude, and OpenAI GPT.

Ahmed Allem

Ahmed Allem

Founder & CTO · Aviation, AI & Startups

ShareShare
Getting Started with Allem SDK AI: Multi-Provider Chat Hooks for React

@allem-sdk/ai provides multi-provider AI hooks for React. Built on the Vercel AI SDK, it supports Google Gemini, Anthropic Claude, and OpenAI GPT with streaming responses out of the box. Switch providers with a single prop change.

Installation

npm install @allem-sdk/ai ai @ai-sdk/react

Then install the providers you need:

# Pick one or more
npm install @ai-sdk/google
npm install @ai-sdk/anthropic
npm install @ai-sdk/openai

Setup

1. Create the API Route

Set up a server-side handler that routes requests to the right provider:

// app/api/chat/route.ts
import { createAllemChatHandler } from "@allem-sdk/ai";
import { google } from "@ai-sdk/google";
import { anthropic } from "@ai-sdk/anthropic";

export const POST = createAllemChatHandler({
  providers: {
    google: (model) => google(model ?? "gemini-2.0-flash"),
    anthropic: (model) => anthropic(model ?? "claude-sonnet-4-20250514"),
  },
  defaultProvider: "google",
  systemPrompt: "You are a helpful assistant.",
});

2. Set Environment Variables

GOOGLE_GENERATIVE_AI_API_KEY=your-google-key
ANTHROPIC_API_KEY=your-anthropic-key
# OPENAI_API_KEY=your-openai-key (if using OpenAI)

3. Wrap Your App

import { AllemAIProvider } from "@allem-sdk/ai";

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <AllemAIProvider
      api="/api/chat"
      provider="google"
      model="gemini-2.0-flash"
    >
      {children}
    </AllemAIProvider>
  );
}

useAllemChat

The primary hook for building chat interfaces with streaming:

import { useAllemChat } from "@allem-sdk/ai";

function ChatInterface() {
  const { messages, sendMessage, status } = useAllemChat();
  const isLoading = status === "submitted" || status === "streaming";

  return (
    <div>
      {messages.map((m) => (
        <div key={m.id} className={m.role === "user" ? "text-right" : "text-left"}>
          {m.parts
            ?.filter((p) => p.type === "text")
            .map((p) => p.text)
            .join("")}
        </div>
      ))}

      {isLoading && <p>Thinking...</p>}

      <form
        onSubmit={(e) => {
          e.preventDefault();
          const input = e.currentTarget.elements.namedItem("message") as HTMLInputElement;
          sendMessage({ text: input.value });
          input.value = "";
        }}
      >
        <input name="message" placeholder="Type a message..." />
        <button type="submit" disabled={isLoading}>Send</button>
      </form>
    </div>
  );
}

useAllemChat Options

Option Type Description
api string Override the API endpoint
model string Model identifier
provider "google" | "anthropic" | "openai" Provider name
systemPrompt string System prompt sent with requests
headers Record<string, string> Extra headers
experimental_throttle number Throttle streaming updates (ms)

useAllemChat Returns

Property Type Description
messages UIMessage[] Chat message history
sendMessage ({ text }) => Promise Send a message
status "ready" | "submitted" | "streaming" Current chat status
stop () => void Stop streaming
setMessages (msgs) => void Replace message history

Switching Providers

Change the provider per-component without changing the server:

// Uses Google Gemini (from provider context)
const geminiChat = useAllemChat();

// Override to use Claude for this specific chat
const claudeChat = useAllemChat({
  provider: "anthropic",
  model: "claude-sonnet-4-20250514",
});

useAllemCompletion

For single-turn text completion (not chat):

import { useAllemCompletion } from "@allem-sdk/ai";

function CompletionDemo() {
  const { completion, complete, isLoading } = useAllemCompletion();

  return (
    <div>
      <button
        onClick={() => complete("Write a haiku about React hooks")}
        disabled={isLoading}
      >
        Generate
      </button>
      {completion && <p className="mt-4 whitespace-pre-wrap">{completion}</p>}
    </div>
  );
}

useAllemAIConfig

Access the current provider configuration from anywhere in the tree:

import { useAllemAIConfig } from "@allem-sdk/ai";

function ProviderBadge() {
  const config = useAllemAIConfig();

  return (
    <span className="text-xs text-gray-500">
      Powered by {config.provider} / {config.model}
    </span>
  );
}

Complete Chat App

A full chat interface with provider switching:

"use client";
import { useState } from "react";
import { AllemAIProvider, useAllemChat } from "@allem-sdk/ai";
import { Button, Input, Card, CardBody } from "@allem-ui/react";
import { ChatContainer, ChatList, ChatBubble, ChatInput } from "@allem-ui/chat";

function Chat() {
  const { messages, sendMessage, status, stop } = useAllemChat({
    systemPrompt: "You are a helpful coding assistant.",
  });

  const isLoading = status === "submitted" || status === "streaming";

  return (
    <ChatContainer>
      <ChatList>
        {messages.map((m) => (
          <ChatBubble
            key={m.id}
            variant={m.role === "user" ? "sent" : "received"}
            avatar={m.role === "user" ? "You" : "AI"}
          >
            {m.parts
              ?.filter((p) => p.type === "text")
              .map((p) => p.text)
              .join("")}
          </ChatBubble>
        ))}
      </ChatList>
      <ChatInput
        onSend={(text) => sendMessage({ text })}
        isLoading={isLoading}
        placeholder="Ask me anything..."
      />
    </ChatContainer>
  );
}

export default function ChatPage() {
  const [provider, setProvider] = useState<"google" | "anthropic">("google");

  return (
    <AllemAIProvider api="/api/chat" provider={provider}>
      <div className="flex gap-2 mb-4">
        <Button
          variant={provider === "google" ? "solid" : "outline"}
          size="sm"
          onPress={() => setProvider("google")}
        >
          Gemini
        </Button>
        <Button
          variant={provider === "anthropic" ? "solid" : "outline"}
          size="sm"
          onPress={() => setProvider("anthropic")}
        >
          Claude
        </Button>
      </div>
      <Chat />
    </AllemAIProvider>
  );
}

What's Next