Tabbi SDK

TypeScript SDK for building AI coding agent applications.

Installation

npm install tabbi-sdk

Quick Start

import { Tabbi } from "tabbi-sdk";
// Initialize the client
const tabbi = new Tabbi({
apiKey: "tb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
});
// Create a session (streams progress, returns when ready)
const session = await tabbi.createSession({
onProgress: (event) => console.log(event.message)
});
// Output: "Session created", "Creating sandbox...", "Sandbox ready..."
// Session is immediately ready - no need to call waitForReady()!
// Send a message and stream the response
const message = await session.sendMessage("Create a hello world app", {
onEvent: (event) => {
if (event.type === "message.assistant") {
process.stdout.write(event.data.content);
}
}
});
// Access files in the workspace
const files = await session.listFiles("/");
const content = await session.getFileText("/src/index.ts");
// Cleanup
await session.delete();

API Reference

Tabbi

Main client class for interacting with the Tabbi API.

Constructor

new Tabbi(config: TabbiConfig)
ParameterTypeRequiredDescription
config.apiKeystringYesAPI key (tb_live_xxx or tb_test_xxx)
config.baseUrlstringNoAPI base URL (default: https://api.tabbi.dev)
config.timeoutnumberNoRequest timeout in ms (default: 30000)

createSession(options?)

Create a new session with an isolated sandbox environment. Uses SSE streaming to report progress and returns when the session is ready.

const session = await tabbi.createSession({
repo: "owner/repo", // Optional: Git repository to clone
gitToken: "ghp_xxx", // Optional: Token for private repos
onProgress: (event) => { // Optional: Progress callback
console.log(event.message);
}
});
// Session is ready to use immediately - no need to call waitForReady()
ParameterTypeRequiredDescription
options.repostringNoGit repository to clone (owner/repo format)
options.gitTokenstringNoGitHub token for private repositories
options.onProgress(event: SessionProgressEvent) => voidNoCallback for progress updates

Returns: Promise<Session> (session is ready to use)

getSession(id)

Get an existing session by ID.

const session = tabbi.getSession("e2e1091c-daa3-42de-ba3b-0d0a05e72fc1");

Returns: Session


Session

Represents an active session with a sandbox environment.

Properties

PropertyTypeDescription
idstringSession UUID
statusSessionStatusCurrent status: idle, starting, running, paused, error
createdAtstringISO 8601 creation timestamp

sendMessage(content, options?)

Send a message and stream the response.

const message = await session.sendMessage("Fix the bug in auth.ts", {
onEvent: (event) => {
switch (event.type) {
case "message.assistant":
console.log(event.data.content);
break;
case "message.tool":
console.log(`Tool: ${event.data.toolName} - ${event.data.status}`);
break;
case "error":
console.error(event.data.message);
break;
}
},
signal: abortController.signal // Optional: for cancellation
});
ParameterTypeRequiredDescription
contentstringYesMessage to send
options.onEvent(event: SSEEvent) => voidNoEvent callback
options.signalAbortSignalNoAbort signal for cancellation

Returns: Promise<Message>

listFiles(path?)

List files in the workspace.

const files = await session.listFiles("/src");
// [{ name: "index.ts", path: "/workspace/src/index.ts", isDirectory: false, size: 1234 }]

Returns: Promise<FileInfo[]>

getFile(path)

Get file content as a Blob.

const blob = await session.getFile("/src/index.ts");

Returns: Promise<Blob>

getFileText(path)

Get file content as text.

const content = await session.getFileText("/src/index.ts");

Returns: Promise<string>

delete()

Delete the session and cleanup resources.

await session.delete();

Returns: Promise<void>


Types

SSEEvent

Server-Sent Event from the message stream.

interface SSEEvent {
type: SSEEventType;
data: SSEEventData;
timestamp: string;
}

SSEEventType

TypeDescription
session.startingSandbox is initializing
session.runningProcessing message
session.idleReady for next message
session.pausedSession paused
message.userUser message received
message.assistantAssistant response (may be partial)
message.toolTool call or result
message.completeMessage finished
errorAn error occurred

Event Data Types

// message.assistant
interface MessageAssistantData {
content: string;
isPartial: boolean;
}
// message.tool
interface MessageToolData {
toolName: string;
toolId: string;
status: "calling" | "result";
result?: string;
}
// error
interface ErrorData {
code: string;
message: string;
details?: Record<string, unknown>;
}

FileInfo

interface FileInfo {
name: string;
path: string;
isDirectory: boolean;
size?: number;
}

Message

interface Message {
id: string;
role: "user" | "assistant";
content: string;
toolCalls?: ToolCall[];
createdAt: string;
}

Error Handling

The SDK throws TabbiError for API errors.

import { TabbiError } from "tabbi-sdk";
try {
await session.sendMessage("...");
} catch (error) {
if (error instanceof TabbiError) {
console.error(`Error ${error.code}: ${error.message}`);
console.error(`HTTP Status: ${error.status}`);
console.error(`Details:`, error.details);
}
}

Error Codes

CodeHTTP StatusDescription
INVALID_API_KEY401API key is missing or invalid
SESSION_NOT_OWNED403Session belongs to a different API key
SESSION_NOT_FOUND404Session does not exist
FILE_NOT_FOUND404File not found in workspace
SESSION_BUSY409Session is processing another message
RATE_LIMIT_EXCEEDED429Too many requests
SANDBOX_CREATE_FAILED500Failed to create sandbox
SANDBOX_TIMEOUT500Sandbox operation timed out
INTERNAL_ERROR500Internal server error

Examples

Basic Usage

import { Tabbi } from "tabbi-sdk";
const tabbi = new Tabbi({ apiKey: process.env.TABBI_API_KEY! });
async function main() {
// Create session with progress updates
const session = await tabbi.createSession({
onProgress: (event) => console.log(event.message)
});
// Session is ready immediately - no waitForReady() needed!
try {
// Send a coding task
await session.sendMessage("Create a TypeScript function that calculates fibonacci numbers", {
onEvent: (e) => {
if (e.type === "message.assistant") {
process.stdout.write(e.data.content);
}
}
});
// Get the created file
const files = await session.listFiles("/");
console.log("\nFiles:", files);
} finally {
await session.delete();
}
}
main();

Working with Git Repositories

const session = await tabbi.createSession({
repo: "myorg/myrepo",
gitToken: process.env.GITHUB_TOKEN
});
await session.sendMessage("Fix the failing tests in src/auth.test.ts");
// Get the diff
const originalContent = "..."; // stored before
const newContent = await session.getFileText("/src/auth.ts");

Streaming to a Frontend

// API Route (Next.js example)
export async function POST(req: Request) {
const { sessionId, content } = await req.json();
const tabbi = new Tabbi({ apiKey: process.env.TABBI_API_KEY! });
const session = tabbi.getSession(sessionId);
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
try {
await session.sendMessage(content, {
onEvent: (event) => {
controller.enqueue(
encoder.encode(`data: ${JSON.stringify(event)}\n\n`)
);
}
});
controller.close();
} catch (error) {
controller.error(error);
}
}
});
return new Response(stream, {
headers: { "Content-Type": "text/event-stream" }
});
}

Cancellation

const controller = new AbortController();
// Cancel after 30 seconds
setTimeout(() => controller.abort(), 30000);
try {
await session.sendMessage("Refactor the entire codebase", {
signal: controller.signal
});
} catch (error) {
if (error.name === "AbortError") {
console.log("Request was cancelled");
}
}

Best Practices

  1. Always delete sessions when done to free up resources
  2. Use onProgress callback to show users real-time progress during session creation
  3. Handle SESSION_BUSY errors - wait and retry if the session is processing
  4. Stream events to provide real-time feedback to users
  5. Set appropriate timeouts for long-running tasks

Environment Variables

TABBI_API_KEY=tb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TABBI_API_URL=https://api.tabbi.dev # Optional