@rabbit-agent-sdk/rabbit-agent-sdk
v0.1.6
Published
<p align="center"> <h1 align="center">π Rabbit SDK</h1> <p align="center"> A type-safe, provider-agnostic framework for building production-grade AI agents in TypeScript. <br /> <br /> <a href="#-quick-start">Quick Start</a> Β·
Readme
Rabbit SDK gives you everything you need to orchestrate Large Language Models with strict type safety, automatic JSON schema conversion, custom tools, conversational memory, provider fallback chains, and safety guardrails β all in a clean, extensible architecture.
import { Agent, OpenAIProvider, Tool } from "@rabbit-agent-sdk/rabbit-agent-sdk";
import { z } from "zod";
const agent = new Agent({
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
systemPrompt: "You are a helpful assistant.",
tools: [{
name: "getWeather",
description: "Get the current weather for a location",
schema: z.object({ location: z.string() }),
execute: async ({ location }) => `The weather in ${location} is sunny.`,
}],
});
const response = await agent.run("What's the weather in Tokyo?");
console.log(response);
// β "The weather in Tokyo is sunny."β¨ Key Features
| Feature | Description |
| :--- | :--- |
| π Provider Agnostic | Swap between OpenAI, Groq, Gemini (or build your own) with a single line change |
| π§ Built-in Memory | Automatic conversational history management with BufferMemory or custom backends |
| π οΈ Zod-Powered Tools | Define tools with zod schemas β automatic JSON Schema conversion and runtime validation |
| π‘οΈ Safety Guardrails | 8 built-in guardrails for PII detection, profanity, prompt injection, tone enforcement, and more |
| π Provider Fallbacks | Self-healing agent loops with automatic fallback to backup providers on failure |
| π‘ Streaming | First-class support for streaming responses via async generators |
| π¦ Built-in Toolkit | Pre-built FetchTool and WebSearchTool ready to use out of the box |
| β‘ Budget Control | maxSteps limiter prevents infinite agentic loops |
π Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β @rabbit-agent-sdk/rabbit-agent-sdk β
β (Umbrella package β re-exports everything) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββ ββββββββββββββββ ββββββββββββββββββββ β
β β @rabbit-agent-sdk/core β β Provider β β Provider β β
β β β β OpenAI β β Groq β β
β β β’ Agent β β β β β β
β β β’ Memory β ββββββββ¬ββββββββ βββββββββ¬βββββββββββ β
β β β’ Tools β β β β
β β β’ Guardrails β ββββββββ΄βββββββββββββββββββ΄βββββββββββ β
β β β’ Errors β β abstract Provider β β
β β β’ Types β β generate(request) β response β β
β ββββββββββββ¬βββββββββ ββββββββ¬βββββββββββββββββββ¬βββββββββββ β
β β β β β
β β ββββββββ΄ββββββββ ββββββββ΄ββββββββ β
β β β Provider β β Provider β β
β β β Gemini β β Anthropic β β
β β ββββββββββββββββ ββββββββββββββββ β
βββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββ΄ββββββββββββββThe SDK is structured as a pnpm monorepo with the following packages:
| Package | npm Name | Purpose |
| :--- | :--- | :--- |
| packages/core | @rabbit-agent-sdk/core | Agent engine, memory, guardrails, tools, types, errors |
| packages/provider-openai | @rabbit-agent-sdk/provider-openai | OpenAI provider (gpt-4o default) |
| packages/provider-groq | @rabbit-agent-sdk/provider-groq | Groq provider (llama3-8b-8192 default) |
| packages/provider-gemini | @rabbit-agent-sdk/provider-gemini | Gemini provider (gemini-2.5-flash default) |
| packages/provider-anthropic | @rabbit-agent-sdk/provider-anthropic | Anthropic provider (claude-3-5-sonnet-20241022 default) |
| packages/rabbit-agent-sdk | @rabbit-agent-sdk/rabbit-agent-sdk | Umbrella package β re-exports all of the above |
π Quick Start
Prerequisites
- Node.js β₯ 18
- pnpm β₯ 9.0 (package manager)
- An API key from at least one provider (OpenAI, Groq, or Gemini)
Step 1 β Clone and Install
git clone https://github.com/arunava2018/rabbit-agent-sdk.git
cd rabbit-agent-sdk
pnpm installStep 2 β Build All Packages
pnpm buildStep 3 β Set Up Environment Variables
Create a .env file in the examples/basic/ directory:
# Pick at least one:
OPENAI_API_KEY=sk-your-openai-key
GROQ_API_KEY=gsk_your-groq-key
GEMINI_API_KEY=your-gemini-key
ANTHROPIC_API_KEY=your-anthropic-key
# Optional β for WebSearchTool
TAVILY_API_KEY=tvly-your-tavily-keyStep 4 β Run the Example
cd examples/basic
pnpm startYou'll see an interactive chat in your terminal:
π€ Agent initialized with primary provider: openai (broken)
π Fallback provider configured: openai (valid)
Chat started! Type 'exit' to quit.
You: What's the weather in Paris?
[Agent Logs] π‘ Calling provider: 'openai'...
[Agent Logs] β οΈ Provider 'openai' failed: 401 Incorrect API key
[Agent Logs] π‘ Calling provider: 'openai'...
[Agent Logs] π οΈ Model requested tool: 'getWeather' with args: { location: "Paris" }
[Agent Logs] β‘ Executing 'getWeather'...
[Agent Logs] β
Tool returned: The weather in Paris is sunny.
Agent: The weather in Paris is sunny!π Documentation
Table of Contents
- Providers
- The Agent
- Tools (Function Calling)
- Memory
- Guardrails
- Streaming
- Provider Fallbacks
- Error Handling
- Built-in Tools
- Custom Providers
1. Providers
Providers are the bridge between the Agent and an LLM API. The SDK ships with three providers, and you can build your own by extending the abstract Provider class.
OpenAI
import { OpenAIProvider } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const provider = new OpenAIProvider({
apiKey: process.env.OPENAI_API_KEY, // Optional β falls back to OPENAI_API_KEY env var
model: "gpt-4o", // Optional β defaults to "gpt-4o"
});Groq
import { GroqProvider } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const provider = new GroqProvider({
apiKey: process.env.GROQ_API_KEY, // Optional β falls back to GROQ_API_KEY env var
model: "llama3-8b-8192", // Optional β defaults to "llama3-8b-8192"
});Gemini
import { GeminiProvider } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const provider = new GeminiProvider({
apiKey: process.env.GEMINI_API_KEY, // Optional β falls back to GOOGLE_GENERATIVE_AI_API_KEY env var
model: "gemini-2.5-flash", // Optional β defaults to "gemini-2.5-flash"
});Anthropic (Claude)
import { AnthropicProvider } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const provider = new AnthropicProvider({
apiKey: process.env.ANTHROPIC_API_KEY, // Optional
model: "claude-3-5-sonnet-20241022", // Optional β defaults to "claude-3-5-sonnet-20241022"
});Switching Providers
Since every provider implements the same abstract interface, swapping is a one-line change:
// Before
const agent = new Agent({ provider: new OpenAIProvider() });
// After β just change the provider
const agent = new Agent({ provider: new GeminiProvider() });2. The Agent
The Agent class is the central orchestration engine. It manages the execution loop, memory, tools, guardrails, and provider fallback chains.
Basic Initialization
import { Agent, OpenAIProvider } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const agent = new Agent({
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
systemPrompt: "You are a helpful and concise assistant.",
});
const response = await agent.run("Hello, who are you?");
console.log(response);
// β "I'm a helpful and concise assistant. How can I help you today?"Full Configuration
import {
Agent,
OpenAIProvider,
GroqProvider,
BufferMemory,
ProfanityGuardrail,
PIIGuardrail,
MaxLengthGuardrail,
FetchTool,
WebSearchTool,
} from "@rabbit-agent-sdk/rabbit-agent-sdk";
const agent = new Agent({
// Required β the primary LLM provider
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
// Optional β backup providers tried in order if primary fails
fallbackProviders: [
new GroqProvider({ apiKey: process.env.GROQ_API_KEY }),
],
// Optional β system prompt injected at the start of every conversation
systemPrompt: "You are a senior financial analyst. Be precise and cite sources.",
// Optional β tools the agent can call
tools: [new FetchTool(), new WebSearchTool(process.env.TAVILY_API_KEY)],
// Optional β input/output validation guardrails
guardrails: [
new ProfanityGuardrail(), // Block profanity in user input
new PIIGuardrail(), // Block PII in user input
new MaxLengthGuardrail(4000, "output"), // Cap output length
],
// Optional β custom memory implementation (defaults to BufferMemory)
memory: new BufferMemory(),
// Optional β enable response streaming (default: false)
stream: false,
// Optional β max agentic loop iterations (default: 5)
maxSteps: 10,
});AgentConfig Reference
| Property | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| provider | Provider | (required) | Primary LLM provider |
| fallbackProviders | Provider[] | [] | Sequential fallback providers |
| systemPrompt | string | undefined | System instruction prepended to every call |
| tools | Tool[] | [] | Tools available to the agent |
| guardrails | Guardrails[] | [] | Input/output validation guardrails |
| memory | Memory | new BufferMemory() | Conversation memory backend |
| stream | boolean | false | Enable streaming responses |
| maxSteps | number | 5 | Max execution loop steps (budget control) |
3. Tools (Function Calling)
Tools let your agent call external functions. Define them with a zod schema and the SDK handles everything β JSON Schema conversion for the LLM, argument validation, execution, and result injection back into the conversation.
Step 1 β Define a Tool
import { Tool } from "@rabbit-agent-sdk/rabbit-agent-sdk";
import { z } from "zod";
const calculatorTool: Tool = {
name: "calculator",
description: "Perform basic arithmetic. Supports +, -, *, /.",
schema: z.object({
expression: z.string().describe("A mathematical expression like '2 + 2'"),
}),
execute: async ({ expression }) => {
try {
// WARNING: eval is used for demonstration only β use a safe parser in production
return String(eval(expression));
} catch {
return "Error: Invalid expression";
}
},
};Step 2 β Register with the Agent
const agent = new Agent({
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
tools: [calculatorTool],
systemPrompt: "You are a math assistant. Use the calculator tool for all arithmetic.",
});Step 3 β Run
const answer = await agent.run("What is 1337 * 42?");
console.log(answer);
// β "1337 Γ 42 = 56,154"What Happens Under the Hood
- The agent sends the user's prompt + tool definitions (auto-converted from Zod β JSON Schema) to the LLM.
- The LLM responds with a tool call (
{ name: "calculator", arguments: { expression: "1337 * 42" } }). - The agent validates arguments against the Zod schema using
tool.schema.parse(...). - The agent executes the tool and saves the result to memory as a
role: "tool"message. - The agent sends the conversation (now including the tool result) back to the LLM.
- The LLM generates a final natural-language response.
Multiple Tools
You can register as many tools as you need:
const agent = new Agent({
provider: new OpenAIProvider(),
tools: [calculatorTool, weatherTool, fetchTool, webSearchTool],
});The LLM decides which tool(s) to call based on the user's prompt and tool descriptions.
4. Memory
Memory manages the conversation history. Every message (user, assistant, tool calls, tool results) is stored and replayed to the provider on each agent.run() call so the model has full context.
Default: BufferMemory
BufferMemory stores everything in an in-memory array. It's the default β you don't need to configure anything:
const agent = new Agent({
provider: new OpenAIProvider(),
});
// Conversation context is automatically maintained
await agent.run("My name is Alice.");
const response = await agent.run("What's my name?");
console.log(response);
// β "Your name is Alice."Using Memory Directly
import { BufferMemory } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const memory = new BufferMemory();
// Add messages
memory.addMessage({ role: "user", content: "Hello!" });
memory.addMessage({ role: "assistant", content: "Hi there!" });
// Retrieve history
const messages = memory.getMessages();
console.log(messages);
// β [{ role: "user", content: "Hello!" }, { role: "assistant", content: "Hi there!" }]
// Clear history
memory.clear();Building a Custom Memory Backend
Extend the abstract Memory class to build custom backends (Redis, PostgreSQL, file-based, etc.):
import { Memory, Message } from "@rabbit-agent-sdk/rabbit-agent-sdk";
class RedisMemory extends Memory {
private redis: RedisClient;
constructor(redis: RedisClient) {
super();
this.redis = redis;
}
async addMessage(message: Message): Promise<void> {
const messages = await this.getMessages();
messages.push(message);
await this.redis.set("chat:history", JSON.stringify(messages));
}
async addMessages(messages: Message[]): Promise<void> {
const existing = await this.getMessages();
existing.push(...messages);
await this.redis.set("chat:history", JSON.stringify(existing));
}
async getMessages(): Promise<Message[]> {
const data = await this.redis.get("chat:history");
return data ? JSON.parse(data) : [];
}
async clear(): Promise<void> {
await this.redis.del("chat:history");
}
}
// Use it
const agent = new Agent({
provider: new OpenAIProvider(),
memory: new RedisMemory(redisClient),
});5. Guardrails
Guardrails validate user input and/or model output. Each guardrail has a type β either "input" (runs before the LLM call) or "output" (runs after the LLM responds). If validation fails, a GuardrailError is thrown.
Built-in Guardrails
The SDK ships with 8 production-ready guardrails:
| Guardrail | Default Type | Description |
| :--- | :--- | :--- |
| ProfanityGuardrail | input | Blocks messages containing profanity (customizable word list) |
| PIIGuardrail | input | Detects SSN and credit card patterns |
| PromptInjectionGuardrail | input | Detects common injection phrases ("ignore previous instructions", etc.) |
| KeywordBlockGuardrail | β | Blocks messages containing specific blacklisted keywords |
| MaxLengthGuardrail | β | Enforces a character length limit |
| RegexGuardrail | input | Validates against a custom regular expression |
| JSONFormatGuardrail | output | Ensures the response is valid JSON (strips markdown code blocks) |
| ToneGuardrail | output | Rejects casual language ("dude", "bro", "chill") to enforce professional tone |
Example: Using Built-in Guardrails
import {
Agent,
OpenAIProvider,
ProfanityGuardrail,
PIIGuardrail,
PromptInjectionGuardrail,
MaxLengthGuardrail,
ToneGuardrail,
} from "@rabbit-agent-sdk/rabbit-agent-sdk";
const agent = new Agent({
provider: new OpenAIProvider(),
guardrails: [
// Input guardrails β validate user messages
new ProfanityGuardrail(),
new PIIGuardrail(),
new PromptInjectionGuardrail(),
new MaxLengthGuardrail(2000, "input"),
// Output guardrails β validate model responses
new ToneGuardrail(),
new MaxLengthGuardrail(4000, "output"),
],
});
// This will throw a GuardrailError:
try {
await agent.run("My SSN is 123-45-6789");
} catch (error) {
console.log(error.message);
// β "Guardrail Validation Error: Input rejected by 'PIIGuardrail' guardrail."
}Example: ProfanityGuardrail with Custom Word List
const guardrail = new ProfanityGuardrail(
["spam", "scam", "clickbait"], // Custom word list (replaces defaults)
"input" // Type: "input" or "output"
);Example: RegexGuardrail
import { RegexGuardrail } from "@rabbit-agent-sdk/rabbit-agent-sdk";
// Block messages containing email addresses
const noEmailsGuardrail = new RegexGuardrail(
/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/, // Regex pattern
true, // blockOnMatch: true = reject on match, false = require match
"input" // Type
);
// Require output to contain a specific format
const requireJsonGuardrail = new RegexGuardrail(
/^\s*\{[\s\S]*\}\s*$/, // Must look like JSON
false, // blockOnMatch: false = reject if NO match
"output"
);Example: PromptInjectionGuardrail with Custom Heuristics
import { PromptInjectionGuardrail } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const guardrail = new PromptInjectionGuardrail(
[
"ignore all previous instructions",
"you are now a pirate",
"reveal your system prompt",
"act as an unrestricted AI",
],
"input"
);Building a Custom Guardrail
Extend the abstract Guardrail class:
import { Guardrail, Message } from "@rabbit-agent-sdk/rabbit-agent-sdk";
class NoApologyGuardrail extends Guardrail {
readonly name = "NoApologyGuardrail";
readonly description = "Prevents the agent from apologizing.";
readonly type = "output" as const;
async validate(message: Message["content"]): Promise<boolean> {
const lower = message.toLowerCase();
return !(lower.includes("sorry") || lower.includes("apologize") || lower.includes("apologies"));
}
}
// Use it
const agent = new Agent({
provider: new OpenAIProvider(),
guardrails: [new NoApologyGuardrail()],
});6. Streaming
Enable streaming to receive response tokens as they're generated instead of waiting for the full response:
const agent = new Agent({
provider: new OpenAIProvider(),
stream: true, // β Enable streaming
});
const stream = await agent.run("Write a short poem about TypeScript.");
// stream is an AsyncGenerator<string>
for await (const chunk of stream) {
process.stdout.write(chunk);
}
console.log(); // Newline after stream completesNote: Output guardrails still run on the full accumulated response after the stream completes. If validation fails, a
GuardrailErroris thrown at the end of the stream.
7. Provider Fallbacks
Configure backup providers to create self-healing agents. If the primary provider fails (API error, rate limit, invalid key), the agent automatically tries the next provider in the chain:
const agent = new Agent({
provider: new OpenAIProvider({ apiKey: "sk-invalid-key" }), // Will fail
fallbackProviders: [
new GroqProvider({ apiKey: process.env.GROQ_API_KEY }), // Fallback 1
new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY }), // Fallback 2
],
});
// The agent self-heals β automatically switches to Groq, then Gemini if needed
const response = await agent.run("Hello!");How it works:
- Primary provider (
OpenAI) is tried first β fails with 401. - Fallback 1 (
Groq) is tried β succeeds β - The response is returned seamlessly to the caller.
If all providers fail, a ProviderError is thrown with the last error message.
8. Error Handling
The SDK provides a structured error hierarchy for granular error handling:
AgentError (base)
βββ GuardrailError β A guardrail rejected the input or output
βββ ToolExecutionError β A tool failed during execution
βββ ProviderError β All providers in the fallback chain failed
βββ BudgetExceededError β The agent exceeded maxStepsCatching Specific Errors
import {
GuardrailError,
ToolExecutionError,
ProviderError,
BudgetExceededError,
} from "@rabbit-agent-sdk/rabbit-agent-sdk";
try {
const response = await agent.run(userInput);
console.log(response);
} catch (error) {
if (error instanceof GuardrailError) {
console.log(`Guardrail "${error.guardrailName}" blocked the message.`);
// β Guardrail "PIIGuardrail" blocked the message.
} else if (error instanceof BudgetExceededError) {
console.log("Agent hit the step limit β consider increasing maxSteps.");
} else if (error instanceof ProviderError) {
console.log("All LLM providers are down. Try again later.");
} else if (error instanceof ToolExecutionError) {
console.log(`Tool "${error.toolName}" failed.`);
} else {
throw error; // Re-throw unexpected errors
}
}9. Built-in Tools
FetchTool
Makes HTTP requests to REST APIs. The LLM can call this to fetch data from any URL.
import { FetchTool } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const fetchTool = new FetchTool();
const agent = new Agent({
provider: new OpenAIProvider(),
tools: [fetchTool],
systemPrompt: "You can fetch data from APIs. Use the FetchTool when asked.",
});
await agent.run("Fetch the latest posts from https://jsonplaceholder.typicode.com/posts?_limit=3");FetchTool Schema:
| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| url | string (URL) | Yes | The URL to fetch |
| method | "GET" \| "POST" \| "PUT" \| "DELETE" | No | HTTP method (default: GET) |
| headers | Record<string, string> | No | HTTP headers as key-value pairs |
| body | string | No | Request body (for POST/PUT) |
WebSearchTool
Searches the web using the Tavily API. Falls back to a mock response if no API key is provided.
import { WebSearchTool } from "@rabbit-agent-sdk/rabbit-agent-sdk";
// With a real API key
const searchTool = new WebSearchTool(process.env.TAVILY_API_KEY);
// Without an API key (returns mock results)
const mockSearchTool = new WebSearchTool();
const agent = new Agent({
provider: new OpenAIProvider(),
tools: [searchTool],
systemPrompt: "Search the web when asked about current events.",
});
await agent.run("What are the latest developments in AI?");WebSearchTool Schema:
| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| query | string | Yes | The search query |
10. Building a Custom Provider
Extend the abstract Provider class to integrate any LLM API:
import { Provider, ProviderRequest, ProviderResponse } from "@rabbit-agent-sdk/rabbit-agent-sdk";
class MistralProvider extends Provider {
public name = "mistral";
private apiKey: string;
constructor(config: { apiKey: string; model?: string }) {
super(config.model || "mistral-large-latest");
this.apiKey = config.apiKey;
}
public async generate(
request: ProviderRequest
): Promise<ProviderResponse | AsyncIterable<ProviderResponse>> {
// 1. Map the standardized messages to Mistral's format
const messages = request.messages.map((m) => ({
role: m.role,
content: m.content,
}));
if (request.systemPrompt) {
messages.unshift({ role: "system", content: request.systemPrompt });
}
// 2. Call the Mistral API
const response = await fetch("https://api.mistral.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.apiKey}`,
},
body: JSON.stringify({
model: request.model,
messages,
max_tokens: request.maxTokens ?? 1024,
}),
});
const data = await response.json();
// 3. Return the standardized ProviderResponse
return {
message: {
role: "assistant",
content: data.choices[0]?.message?.content || "",
},
usage: {
promptTokens: data.usage?.prompt_tokens || 0,
completionTokens: data.usage?.completion_tokens || 0,
totalTokens: data.usage?.total_tokens || 0,
},
};
}
}
// Use it just like any other provider
const agent = new Agent({
provider: new MistralProvider({
apiKey: process.env.MISTRAL_API_KEY!,
model: "mistral-large-latest",
}),
});π API Reference
Agent
class Agent {
constructor(config: AgentConfig);
run(prompt: string): Promise<string | AsyncGenerator<string>>;
}Provider (Abstract)
abstract class Provider {
abstract name: string;
model: string;
abstract generate(request: ProviderRequest): Promise<ProviderResponse | AsyncIterable<ProviderResponse>>;
}Memory (Abstract) / BufferMemory
abstract class Memory {
abstract addMessage(message: Message): Promise<void> | void;
abstract addMessages(messages: Message[]): Promise<void> | void;
abstract getMessages(): Promise<Message[]> | Message[];
abstract clear(): Promise<void> | void;
}
class BufferMemory extends Memory { /* in-memory array implementation */ }Guardrail (Abstract)
abstract class Guardrail implements Guardrails {
abstract readonly name: string;
abstract readonly description: string;
abstract readonly type: "input" | "output";
abstract validate(message: string): Promise<boolean>;
}Core Types
type Role = "user" | "assistant" | "system" | "tool";
interface Message {
role: Role;
content: string;
toolCalls?: ToolCall[];
toolCallId?: string;
name?: string;
}
interface ToolCall {
id: string;
name: string;
arguments: any;
}
interface Tool<TInput = any, TOutput = any> {
name: string;
description: string;
schema: z.ZodSchema<TInput>;
execute: (input: TInput) => Promise<TOutput> | TOutput;
}
interface Guardrails {
name: string;
description: string;
type: "input" | "output";
validate(message: string): Promise<boolean>;
}
interface ProviderRequest {
messages: Message[];
tools?: Tool[];
model: string;
stream?: boolean;
systemPrompt?: string;
temperature?: number;
maxTokens?: number;
}
interface ProviderResponse {
message: Message;
usage?: {
promptTokens: number;
completionTokens: number;
totalTokens: number;
};
}Error Classes
class AgentError extends Error { }
class GuardrailError extends AgentError { guardrailName: string; }
class ToolExecutionError extends AgentError { toolName: string; }
class ProviderError extends AgentError { }
class BudgetExceededError extends AgentError { }π‘ Examples
Interactive Chat Agent
import { Agent, OpenAIProvider, Tool } from "@rabbit-agent-sdk/rabbit-agent-sdk";
import { z } from "zod";
import * as readline from "readline/promises";
const weatherTool: Tool = {
name: "getWeather",
description: "Get the current weather for a location",
schema: z.object({ location: z.string() }),
execute: async ({ location }) => `The weather in ${location} is sunny.`,
};
const agent = new Agent({
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
tools: [weatherTool],
systemPrompt: "You are a helpful assistant with access to a weather tool.",
maxSteps: 3,
});
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
console.log("Chat started! Type 'exit' to quit.\n");
while (true) {
const input = await rl.question("You: ");
if (input.toLowerCase() === "exit") break;
try {
const result = await agent.run(input);
console.log(`Agent: ${result}\n`);
} catch (e: any) {
console.log(`Error: ${e.message}\n`);
}
}
rl.close();Safety-First Agent
import {
Agent,
GeminiProvider,
ProfanityGuardrail,
PIIGuardrail,
PromptInjectionGuardrail,
ToneGuardrail,
MaxLengthGuardrail,
} from "@rabbit-agent-sdk/rabbit-agent-sdk";
const agent = new Agent({
provider: new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY }),
systemPrompt: "You are a professional customer support agent for a bank.",
guardrails: [
// Input
new ProfanityGuardrail(),
new PIIGuardrail(),
new PromptInjectionGuardrail(),
new MaxLengthGuardrail(1000, "input"),
// Output
new ToneGuardrail(),
new MaxLengthGuardrail(2000, "output"),
],
});Multi-Provider Resilient Agent
import { Agent, OpenAIProvider, GroqProvider, GeminiProvider, FetchTool, WebSearchTool } from "@rabbit-agent-sdk/rabbit-agent-sdk";
const agent = new Agent({
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
fallbackProviders: [
new GroqProvider({ apiKey: process.env.GROQ_API_KEY }),
new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY }),
],
tools: [new FetchTool(), new WebSearchTool(process.env.TAVILY_API_KEY)],
systemPrompt: "You are a research assistant. Use web search and fetch tools to find information.",
maxSteps: 10,
});π οΈ Development
Monorepo Commands
# Install all dependencies
pnpm install
# Build all packages
pnpm build
# Run all packages in dev/watch mode
pnpm dev
# Lint all packages
pnpm lint
# Run tests
pnpm testProject Structure
rabbit-agent-sdk/
βββ packages/
β βββ core/ # Core engine (Agent, Memory, Guardrails, Tools, Types)
β β βββ src/
β β βββ agent.ts # Agent class β orchestration engine
β β βββ memory.ts # Memory abstract class + BufferMemory
β β βββ provider.ts # Provider abstract class + request/response types
β β βββ types.ts # Shared TypeScript types & interfaces
β β βββ errors.ts # Custom error hierarchy
β β βββ guardrails/ # 8 built-in guardrails
β β β βββ base.ts
β β β βββ profanity.ts
β β β βββ pii.ts
β β β βββ prompt-injection.ts
β β β βββ keyword-block.ts
β β β βββ max-length.ts
β β β βββ regex.ts
β β β βββ json-format.ts
β β β βββ tone.ts
β β βββ tools/ # Built-in tools
β β βββ fetch.ts
β β βββ web-search.ts
β βββ provider-openai/ # OpenAI provider package
β βββ provider-groq/ # Groq provider package
β βββ provider-gemini/ # Gemini provider package
β βββ rabbit-agent-sdk/ # Umbrella re-export package
βββ examples/
β βββ basic/ # Interactive chat example
βββ turbo.json # Turborepo configuration
βββ pnpm-workspace.yaml # Workspace definition
βββ tsconfig.base.json # Shared TypeScript configπ€ Contributing
Contributions are welcome! Here are some ways to contribute:
- Add a new Provider β Integrate a new LLM API (Anthropic, Mistral, Cohere, etc.)
- Add a new Tool β Build reusable tools (database queries, email sending, image generation, etc.)
- Add a new Guardrail β Create validation logic for specialized use cases
- Improve documentation β Fix typos, add examples, improve explanations
- Report bugs β Open an issue describing the problem and steps to reproduce
Steps
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-new-provider) - Make your changes
- Run
pnpm buildandpnpm lintto verify - Submit a Pull Request
π License
MIT Β© Rabbit SDK Contributors
