TypeScript · 8 providers · 1 runtime

Every model provider.
One agent runtime, not eight.

samai-sdk gives you a real agent runtime — tool loop, handoffs, guardrails, MCP, RAG, structured output, sessions, resumable runs, and full tracing — written once against a single Provider interface. Swap OpenAI for Claude, or drop in a local Ollama model, by changing one line, not your whole app.

$ npx samai-sdk create my-agent
View documentation See the code ↓
OpenAI Anthropic Google Groq Mistral Ollama Azure Bedrock sdk 1 INTERFACE Agent loop Guardrails MCP Tracing

Eight providers converge on one Provider interface — the whole runtime is built against it, not against any one vendor.

OpenAI · openai() Anthropic · anthropic() Google · google() Groq · groq() Mistral · mistral() Ollama · ollama() Azure OpenAI · azureOpenAI() AWS Bedrock · bedrock() OpenAI · openai() Anthropic · anthropic() Google · google() Groq · groq() Mistral · mistral() Ollama · ollama() Azure OpenAI · azureOpenAI() AWS Bedrock · bedrock()
What's in the runtime

Not a wrapper. Not a framework. The primitives, done properly.

Everything a production agent needs, implemented directly against generate()/stream() — so it works identically no matter which provider is behind it.

Runtime

Agent runtime & handoffs

defineAgent() + runAgentStream() — the real tool loop, multi-agent handoffs with cycle prevention, and a full RunTrace on every run.

Protocol

MCP client

createMCPClient() turns any MCP server's tools into ordinary ToolDefinitions — local stdio or remote HTTP/SSE.

Long-horizon

Sandboxed code execution

createSandbox() runs real JS/Python/bash in an isolated temp dir — minimal env, real timeouts, byte-accurate output caps. createSandboxTools() wires it in as agent tools.

Realtime

Voice / realtime agents

createRealtimeSession() — streamed audio/text over WebSocket, server VAD, one-call barge-in interrupt(), plus generateSpeech()/transcribeAudio().

Safety

Guardrails & approval

PII redaction, prompt-injection detection, budget caps, and human-in-the-loop approval gates that fail closed by default.

Knowledge

RAG / vector search

Swappable VectorStore + EmbeddingProvider, wired into a ready-to-use retrieval tool in one call.

Resilience

Retries, fallback & timeouts

Real AbortController deadlines, exponential backoff, and provider fallback chains — every event fully traced.

Observability

Tracing, OTel & a local trace viewer

Every run produces a structured RunTrace. Export it to real OpenTelemetry spans, or render it as an offline HTML timeline with samai-sdk trace.

Durability

Resumable runs

Checkpoint after every turn and resume after a crash — no tool call is ever re-executed.

DX

CLI & framework hooks

npx samai-sdk create scaffolds a runnable project. useAgent() ships for React, Vue and Svelte.

Also included

The rest of the toolkit

Every one of these ships in the same package as the runtime above — no separate install, no separate mental model.

Real web search

createWebSearchTool() — a live Tavily/Brave-backed tool, not a stub.

Structured output

generateObject(), streamObject() and batch, with auto-repair on failed validation.

Standard Schema support

Pass a zod schema or a valibot 1.x (or any Standard Schema) validator, interchangeably.

Prompt caching

promptCaching: true adds Anthropic cache breakpoints and surfaces cache-token usage.

Sessions & memory

In-memory, file, Redis, or SQLite-backed conversation history — one interface, four stores.

Usage & cost tracking

createUsageLedger() attributes token spend per session, user, or model.

Concurrency & rate limits

withConcurrencyLimit() / withRateLimit() queue calls instead of rejecting them.

Testing utilities

createMockProvider() scripts responses with a call log — no API key needed.

Multi-modal input

Image inputs — base64 or URL — correctly branched per provider's real API shape.

Typed error handling

AgentRunError, GuardrailBlockedError and more — every failure mode is a real type.

Edge & serverless ready

A deployment guide covering Node, Vercel Edge, and Cloudflare Workers, with a custom-store recipe.

One Provider interface

Eight adapters. Same generate() / stream() shape.

Nothing in the agent runtime, guardrails, or tracing knows or cares which one is behind a given agent.

OpenAI · openai()
Anthropic · anthropic()
Google · google()
Groq · groq()
Mistral · mistral()
Ollama · ollama() — local, no key
Azure OpenAI · azureOpenAI()
AWS Bedrock · bedrock()
See it in context

Six things you'll actually reach for

The same patterns from the docs, condensed — click through to the full reference for everything else.

import { createClient, anthropic, defineTool } from "samai-sdk";
import { z } from "zod";

const getWeather = defineTool({
  name: "get_weather",
  parameters: z.object({ city: z.string() }),
  execute: async ({ city }) => ({ city, tempC: 28, condition: "sunny" }),
});

const client = createClient({ provider: anthropic({ apiKey }) });

const result = await client.generate({
  model: "claude-sonnet-4-6",
  messages: [{ role: "user", content: "Weather in Chennai?" }],
  tools: [getWeather],
});
const packingAgent = defineAgent({
  name: "packing_specialist",
  instructions: "Give packing advice from the weather already discussed.",
  model: "claude-sonnet-4-6",
});

const routerAgent = defineAgent({
  name: "trip_router",
  instructions: "Look up weather, then hand off to packing_specialist.",
  model: "claude-sonnet-4-6",
  tools: [getWeather],
  handoffs: [packingAgent],
});

const result = await runAgent(client, routerAgent, "Pack for Tokyo?");
result.finalAgent; // "packing_specialist"
const filesystem = createMCPClient({
  transport: {
    transport: "stdio", command: "npx",
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
  },
  toolPrefix: "fs",
});

const agent = defineAgent({
  name: "file_assistant",
  instructions: "Help inspect files in /tmp using the fs__ tools.",
  model: "claude-sonnet-4-6",
  tools: await filesystem.tools(),
});
const sandbox = createSandbox();

const agent = defineAgent({
  name: "coder",
  instructions: "Write and test code using write_file and execute_code.",
  model: "claude-sonnet-4-6",
  tools: createSandboxTools(sandbox), // execute_code, write_file, read_file, list_files
});

const result = await runAgent(client, agent, "Write fibonacci.py, run it, and tell me the output.");
await sandbox.close(); // deletes the temp directory
const session = createRealtimeSession({
  instructions: "You are a helpful, concise voice assistant.",
  voice: "alloy",
  tools: [getWeatherTool], // called automatically when the model invokes them
});

session.on((event) => {
  if (event.type === "audio.delta") playAudioChunk(event.audio);
  if (event.type === "speech_started") stopSpeakerPlayback(); // barge-in
});

await session.connect();
session.sendText("What's the weather in Tokyo?");
session.interrupt(); // cancels the in-flight response, instantly
const client = createClient({
  provider: openai({ apiKey }),
  inputGuardrails: [
    createPiiInputGuardrail({ mode: "redact" }),
    createPromptInjectionGuardrail({ mode: "block" }),
  ],
  outputGuardrails: [
    createSchemaGuardrail(ReviewSchema),
  ],
});
// blocked calls throw GuardrailBlockedError with the reason attached
Where it sits

Between "you build the loop yourself" and vendor lock-in

Thin provider wrapper

One API across providers, but no orchestration — you still write the tool loop, handoffs, retries, and tracing yourself.

samai-sdk

A full agent runtime — loop, handoffs, guardrails, sessions, tracing, resumable runs — written against generate()/stream(), so it stays provider-agnostic by construction. Under 2,500 lines, readable in an afternoon.

Heavyweight framework

Full orchestration, but its own state and deployment model — and it usually shines brightest on one vendor's models.

Scaffold a working agent in one command

No manual wiring — pick a provider, get a runnable project with one agent and one tool already working.

$npx samai-sdk create my-agent --provider anthropic
Read the full docs