The lightweight, universal AI client for JavaScript & TypeScript.
One function. Any model. Zero dependencies.
Docs · Install · Quickstart · Providers · Streaming · Structured Output · Tool Calling
npm install aiclientjsimport { ai } from 'aiclientjs';
const { text } = await ai('Explain quantum computing in one sentence');That's it. No boilerplate. No framework lock-in. Works everywhere.
| aiclientjs | Vercel AI SDK | Direct API calls | |
|---|---|---|---|
| Bundle size | ~8 KB gzipped | ~150 KB+ | N/A |
| Dependencies | 0 | 20+ | varies |
| Providers | OpenAI, Anthropic, Google, Ollama, custom | OpenAI, Anthropic, Google, more | 1 per SDK |
| Runtimes | Node, Deno, Bun, Browser, Edge | Primarily Node/Edge | varies |
| Streaming | for await...of |
React hooks / streams | manual SSE parsing |
| TypeScript | First-class, fully typed | Yes | varies |
| Learning curve | 1 function | Framework concepts | Per-provider docs |
npm install aiclientjs # npm
pnpm add aiclientjs # pnpm
yarn add aiclientjs # yarn
bun add aiclientjs # bunexport OPENAI_API_KEY=sk-...
# or
export ANTHROPIC_API_KEY=sk-ant-...
# or
export GOOGLE_API_KEY=AI...import { ai } from 'aiclientjs';
// OpenAI (default)
const res = await ai('Hello!');
console.log(res.text);
// Anthropic Claude
const res = await ai('Hello!', { provider: 'anthropic' });
// Google Gemini
const res = await ai('Hello!', { provider: 'google' });
// Local model via Ollama
const res = await ai('Hello!', { provider: 'ollama', model: 'llama3.1' });const stream = await ai('Write a poem about code', { stream: true });
for await (const chunk of stream) {
process.stdout.write(chunk); // tokens arrive in real-time
}const stream = await ai('Tell me a story', { stream: true });
const response = await stream.response(); // waits for stream to finish
console.log(response.text);
console.log(response.usage);const stream = await ai('Hello', { stream: true });
return new Response(stream.toReadableStream());Get type-safe JSON responses. Works with JSON Schema or Zod.
const res = await ai<{ colors: string[] }>('List 5 colors', {
schema: {
type: 'object',
properties: {
colors: { type: 'array', items: { type: 'string' } },
},
required: ['colors'],
},
});
console.log(res.data.colors); // string[] — fully typedimport { z } from 'zod';
const res = await ai('List 5 colors', {
schema: z.object({
colors: z.array(z.string()),
}),
});
console.log(res.data.colors); // inferred as string[]aiclientjs detects Zod schemas automatically — no plugins, no adapters, no zodToJsonSchema calls.
Define tools with execute handlers and aiclientjs runs them automatically.
const res = await ai('What is the weather in London?', {
tools: {
getWeather: {
description: 'Get current weather for a city',
parameters: {
type: 'object',
properties: {
city: { type: 'string' },
},
required: ['city'],
},
execute: async ({ city }) => {
const data = await fetch(`https://api.weather.com/${city}`);
return data.json();
},
},
},
});
console.log(res.toolResults); // [{ toolName: 'getWeather', result: { temp: 15 } }]Create reusable clients with createAIClient:
import { createAIClient } from 'aiclientjs';
const gpt = createAIClient({
provider: 'openai',
model: 'gpt-4o',
system: 'You are a helpful assistant. Be concise.',
temperature: 0.7,
});
const claude = createAIClient({
provider: 'anthropic',
model: 'claude-sonnet-4-20250514',
});
// Use without repeating config
const answer = await gpt('What is 2+2?');
const story = await claude('Tell me a short story', { stream: true });| Provider | Models | Auth |
|---|---|---|
openai |
GPT-4o, GPT-4, o1, etc. | OPENAI_API_KEY |
anthropic |
Claude Sonnet, Opus, Haiku | ANTHROPIC_API_KEY |
google |
Gemini 2.0, 1.5, etc. | GOOGLE_API_KEY |
ollama |
Llama, Mistral, Phi, any local model | No auth needed |
Any OpenAI-compatible endpoint works with the openai provider + a custom baseURL:
// Together AI
const res = await ai('Hello', {
provider: 'openai',
baseURL: 'https://api.together.xyz/v1',
apiKey: process.env.TOGETHER_API_KEY,
model: 'meta-llama/Llama-3-70b-chat-hf',
});
// Groq
const res = await ai('Hello', {
provider: 'openai',
baseURL: 'https://api.groq.com/openai/v1',
apiKey: process.env.GROQ_API_KEY,
model: 'llama3-70b-8192',
});Register your own provider:
import { registerProvider } from 'aiclientjs';
registerProvider('my-provider', {
name: 'my-provider',
async chat(request, config) {
// Implement your provider logic
return { text: '...', toolCalls: [], usage: { ... }, ... };
},
async *stream(request, config) {
// Yield stream events
yield { type: 'text', text: 'Hello' };
yield { type: 'finish', finishReason: 'stop' };
},
});
const res = await ai('Hello', { provider: 'my-provider' });const res = await ai([
{
role: 'user',
content: [
{ type: 'text', text: 'What is in this image?' },
{ type: 'image', url: 'https://example.com/photo.jpg' },
],
},
]);const controller = new AbortController();
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
const res = await ai('Write a very long essay', {
signal: controller.signal,
});import { ai, AIError } from 'aiclientjs';
try {
const res = await ai('Hello');
} catch (err) {
if (err instanceof AIError) {
console.log(err.code); // 'AUTH_ERROR' | 'RATE_LIMIT' | 'PROVIDER_ERROR' | ...
console.log(err.statusCode); // 401, 429, 500, etc.
console.log(err.provider); // 'openai', 'anthropic', etc.
}
}| Parameter | Type | Description |
|---|---|---|
prompt |
string | Message[] |
Text prompt or conversation messages |
options.provider |
string |
Provider name (default: 'openai') |
options.model |
string |
Model ID (default varies by provider) |
options.apiKey |
string |
API key (or use env vars) |
options.baseURL |
string |
Custom API endpoint |
options.system |
string |
System prompt |
options.stream |
boolean |
Enable streaming |
options.schema |
JsonSchema | ZodSchema |
Structured output schema |
options.tools |
Record<string, ToolDefinition> |
Tool definitions |
options.temperature |
number |
Sampling temperature (0-2) |
options.maxTokens |
number |
Max response tokens |
options.signal |
AbortSignal |
Cancellation signal |
Creates a preconfigured ai function with defaults baked in.
Register a custom provider. See Custom Providers.
┌─────────────────────────────────────────┐
│ ai() / client │ ← Simple public API
├─────────────────────────────────────────┤
│ Provider Registry │ ← Strategy pattern
├──────────┬──────────┬───────┬───────────┤
│ OpenAI │Anthropic │Google │ Ollama │ ← Adapters
├──────────┴──────────┴───────┴───────────┤
│ BaseProvider (shared HTTP/SSE) │ ← Template method
├─────────────────────────────────────────┤
│ SSE Parser │ Schema │ Tool Executor │ ← Zero-dep utilities
└─────────────────────────────────────────┘
Design principles:
- Zero dependencies — uses native
fetch,ReadableStream,TextDecoder - Strategy pattern — providers are interchangeable strategies
- Template method —
BaseProviderhandles HTTP; subclasses handle serialization - Open/Closed — add providers without modifying core code
- Dependency inversion — core depends on
AIProviderinterface, not implementations
| Runtime | Supported |
|---|---|
| Node.js 18+ | Yes |
| Deno | Yes |
| Bun | Yes |
| Cloudflare Workers | Yes |
| Browser | Yes |
| Vercel Edge | Yes |
MIT
