Skip to main content
Home

latest
This package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers
This package works with Cloudflare Workers
This package works with Node.js
This package works with Deno
This package works with Bun
This package works with Browsers
JSR Score
70%
Published
2 weeks ago (3.0.0)

Relevance AI JavaScript SDK

A comprehensive JavaScript/TypeScript SDK for building AI-powered applications with Relevance AI's workforce platform. Build, deploy, and scale AI workforces across any JavaScript runtime.

Description

The Relevance AI JavaScript SDK provides a unified interface for integrating AI workforces and agents into your applications. Whether you're building server-side applications, browser-based interfaces, or edge computing solutions, this SDK delivers consistent, type-safe access to Relevance AI's powerful agent ecosystem.

Key Features

  • Universal Compatibility: Works seamlessly across Node.js, Deno, Bun, Cloudflare Workers, and browsers
  • Event-Driven Architecture: Real-time updates via native EventTarget API
  • Type Safety: Full TypeScript support with comprehensive type definitions
  • Zero Dependencies: Built on web standards for minimal footprint

Quick Start

Get up and running in seconds:

import { Agent, createClient, EU_REGION } from "@relevanceai/sdk";

// Initialize client with your credentials
const client = createClient({
  apiKey: process.env.RELEVANCE_API_KEY,
  region: EU_REGION,
  project: process.env.PROJECT_ID,
});

// Load an agent
const agent = await Agent.get("agent-id");
// Start a conversation
const task = await agent.sendMessage("Hello, how can you help me today?");
// Listen for agent responses
task.addEventListener("message", ({ detail: { message } }) => {
  if (message.isAgent()) {
    console.log("Agent:", message.text);
  }
});

// Or use a workforce of agents

import { Workforce } from "@relevanceai/sdk";

// Load the workforce
const workforce = await Workforce.get("workforce-id");
// Start delegating
const task = await workforce.sendMessage("Analyze this complex dataset");

Installation

Choose the installation method for your runtime:

Node.js / Bun

npm install @relevanceai/sdk@latest
# or
yarn add @relevanceai/sdk@latest
# or
pnpm add @relevanceai/sdk@latest
# or
bun add @relevanceai/sdk@latest

Deno

deno add jsr:@relevanceai/sdk

Or import directly:

import { createClient } from "jsr:@relevanceai/sdk";

Cloudflare Workers

npm install @relevanceai/sdk@latest

Browser (with bundler)

npm install @relevanceai/sdk@latest

For bundlers that warn about node:crypto, create a shim:

// shims/crypto.js
export default window.crypto;

Configure your bundler to use the shim:

Browser (CDN)

<script type="importmap">
  {
    "imports": {
      "@relevanceai/sdk": "https://esm.run/@relevanceai/sdk"
    }
  }
</script>
<script type="module">
  import { createClient } from "@relevanceai/sdk";
  // Your code here
</script>

Usage

Authentication

The SDK supports two authentication methods for different use cases:

API Keys (server-side)

API keys grant full access to your project. Use these for server applications and secure environments:

import { createClient, AU_REGION } from "@relevanceai/sdk";

const client = createClient({
  apiKey: "sk-...",
  region: AU_REGION,
  project: "project-uuid",
});

You can also create a Key instance explicitly:

import { Client, Key, AU_REGION } from "@relevanceai/sdk";

const key = new Key({
  key: "sk-...",
  region: AU_REGION,
  project: "project-uuid",
});

const client = new Client(key);

Embed Keys (client-side)

For public-facing applications, use embed keys which are scoped to a specific public agent. Embed keys need to be generated and should be stored in your applications local storage or database. Each embed key corresponds to a single agent or workforce.

import { Key, createClient, US_REGION } from "@relevanceai/sdk";

const embedKey = await Key.generateEmbedKey({
  region: US_REGION,
  project: "project-uuid",
  agentId: "public-agent-id", // Must be a public agent
});

const client = createClient(embedKey);

Agents

Loading agents

// fetch all agents (with pagination)
const agents = await Agent.getAll({ pageSize: 20, page: 1 });

// fetch all agents with custom page size
const agents = await Agent.getAll({ pageSize: 50, page: 3 });

// fetch all agents using default options (pageSize: 20, page: 1)
const agents = await Agent.getAll();

// using the default client
const agent = await Agent.get("agent-id");

// or using a specific client
const agent = await Agent.get("agent-id", client);

// accessing agent properties
console.log(agent.name);
console.log(agent.avatar);
console.log(agent.description);

Sending messages

Use Agent#sendMessage() to send messages to an agent.

// create a new task
const task = await agent.sendMessage("What's the weather like today?");

// reply to existing tasks
await agent.sendMessage("What about tomorrow?", task);

// sending attachments
const contents = await Deno.readFile("./contract.pdf");
const contract = new File([contents], "contract.pdf", {
  type: "application/pdf",
});
await agent.sendMessage("Summarize this contract", [contract]);

Note: Agent#sendMessage() returns once the message is sent and doesn't wait for a response. See Tasks for handling message events.

Retrieving tasks

Fetch and filter tasks for an agent:

// specific task
const task = await agent.getTask("<task-id>");

// pagination
const tasks = await agent.getTasks({
  pageSize: 10,
  page: 1,
  sort: { updatedAt: "desc" },
});

// filtering
const activeTasks = await agent.getTasks({
  filter: { status: ["queued", "running", "idle"] },
});

// searching
const searchResults = await agent.getTasks({
  search: "weather",
  sort: { createdAt: "asc" },
});

Workforces

Loading workforces

// using the default client
const workforce = await Workforce.get("<workforce-id>");

// or with a specific client
const workforce = await Workforce.get("<workforce-id>", client);

// accessing workforce properties
console.log(workforce.name);

Sending messages

Use Workforce#sendMessage() to send messages to a workforce.

// create a new task
const task = await agent.sendMessage("What's the weather like today?");

// reply to existing tasks
await agent.sendMessage("What about tomorrow?", task);

Note: Workforce#sendMessage() returns once the message is sent and doesn't wait for a response. See Tasks for handling message events.

Retrieving tasks

Load existing workforce tasks.

const task = await workforce.getTask("<task-id>");

Tasks

Agents and workforces, subjects, all return an instance of a Task when sending messages. Tasks dispatch events as they would occur on the the subjects timeline in the Relevance AI workforce platform.

Available Events

  • update: Whenever a subject has been update.
  • message: Unified event for all message types
  • error: Error notifications

Listening for Events

// Listen for all messages (agent, user, and tool)
task.addEventListener("message", ({ detail: { message } }) => {
  // use message helpers to determine the message
  if (message.isAgent()) {
    console.log("Agent:", message.text);
  } else if (message.isUser()) {
    console.log("User:", message.text);
  } else if (message.isTool()) {
    console.log("Tool:", message.status);
  }
});

// catching errors
task.addEventListener("error", ({ detail: { message } }) => {
  console.error("Task error:", message.lastError);
});

Unsubscribing

It's important that you unsubscribe from tasks once they have moved out of scope in your application. This will prevent memory leaks by removing dead subscriptions.

task.unsubscribe();

Advanced Usage

Default Client Pattern

Use a singleton client throughout your application:

// Initialize once at startup
createClient({ apiKey, region, project });

// Access anywhere in your app
import { Client } from "@relevanceai/sdk";

const client = Client.default();

Multiple Clients

Manage multiple projects or authentication scopes:

import { Client, Key, EU_REGION } from "@relevanceai/sdk";

const projectOneKey = new Key({
  key: "sk-project1",
  region: EU_REGION,
  project: "project-1-id",
});

const projectTwoKey = new Key({
  key: "sk-project2",
  region: EU_REGION,
  project: "project-2-id",
});

const clientOne = new Client(projectOneKey);
const clientTwo = new Client(projectTwoKey);

// Use different clients for different agents
const agentOne = await Agent.get("agent-1", clientOne);
const agentTwo = await Agent.get("agent-2", clientTwo);

Examples

For complete working examples, check out the internal/examples directory:

  • Deno Examples (internal/examples/deno/):

    • (Agent) Creating tasks
    • (Agent) Getting a task
    • (Agent) Getting all agents
    • (Agent) Getting all tasks
    • (Agent) Getting an agent
    • (Workforce) Creating a task
  • Browser Example (internal/examples/browser/):

    • Full chat application with Preact
    • Real-time message handling
    • UI components for agent interactions

API Reference

Client

class Client {
  constructor(key: Key);

  static default(): Client;

  readonly key: Key;
  readonly region: Region;
  readonly project: string;

  isEmbedKey(): boolean;

  fetch<T>(endpoint: string, init?: RequestInit): Promise<T>;

  url(path: string): URL;
}

function createClient(keyOrOptions: Key | CreateClientOptions): Client;

interface CreateClientOptions {
  apiKey: string;
  region: Region;
  project: string;
}

Key

class Key {
  static async generateEmbedKey(options: GenerateEmbedKeyOptions): Promise<Key>;

  constructor(options: CreateKeyOptions);

  readonly region: Region;
  readonly project: string;
  readonly agentId?: string;
  readonly taskPrefix?: string;

  isEmbed(): boolean;

  fetchHeaders(): HeadersInit;

  toJSON(): CreateKeyOptions;
}

interface CreateKeyOptions {
  key: string;
  region: Region;
  project: string;
  agentId?: string;
  taskPrefix?: string;
}

interface GenerateEmbedKeyOptions {
  region: Region;
  project: string;
  agentId: string;
}

Agent

class Agent {
  static async get(id: string, client?: Client): Promise<Agent>;

  static async getAll(
    options?: GetAllOptions,
    client?: Client
  ): Promise<Agent[]>;

  readonly id: string;
  readonly name?: string;
  readonly description?: string;
  readonly avatar?: string;
  readonly createdAt: Date;
  readonly updatedAt: Date;
  readonly region: Region;
  readonly project: string;

  getTask(taskId: string): Promise<Task>;

  getTasks(): Promise<Task[]>;
  getTasks(options: GetTaskOptions): Promise<Task[]>;

  sendMessage(message: string): Promise<Task>;
  sendMessage(message: string, task: Task): Promise<Task>;
  sendMessage(
    message: string,
    attachments: (File | Attachment)[]
  ): Promise<Task>;
  sendMessage(
    message: string,
    attachments: (File | Attachment)[],
    task: Task
  ): Promise<Task>;
}

interface Attachment {
  fileName: string;
  fileUrl: string;
}

interface GetTaskOptions {
  pageSize?: number; // default: 100
  page?: number; // default: 1
  // default: { createdAt: "asc" }
  sort?: { createdAt: "asc" | "desc" } | { updatedAt: "asc" | "desc" };
  search?: string;
  filter?: {
    status?: TaskStatus[];
  };
}

interface GetAllOptions {
  pageSize?: number; // default: 20
  page?: number; // default: 1
}

Workforce

class Workforce {
  static async get(id: string, client?: Client): Promise<Workforce>;

  readonly id: string;
  readonly name: string;
  readonly region: Region;
  readonly project: string;

  getTask(taskId: string): Promise<Task>;

  sendMessage(message: string): Promise<Task>;
  sendMessage(message: string, task: Task): Promise<Task>;
}

Task

class Task<T extends Agent | Workforce = Agent> extends EventTarget {
  readonly id: string;
  readonly title: string;
  readonly status: TaskStatus;
  readonly subject: Agent | Workforce;

  isRunning(): boolean;

  getMessages(): Promise<AnyTaskMessage[]>;
  getMessages(options: { from: Date }): Promise<AnyTaskMessage[]>;

  subscribe(): void;

  unsubscribe(): void;

  addEventListener(type: string, listener: EventListener): void;

  removeEventListener(type: string, listener: EventListener): void;
}

type TaskStatus =
  | "not-started"
  | "idle"
  | "queued"
  | "running"
  | "action"
  | "completed"
  | "error";

Messages

abstract class GenericMessage {
  readonly id: string;
  readonly type: MessageType;
  readonly createdAt: Date;

  isAgent(): boolean; // Check if message is from agent
  isUser(): boolean; // Check if message is from user
  isTool(): boolean; // Check if message is a tool execution
  isAgentError(): boolean; // Check if message is an agent error
}

class AgentMessage extends GenericMessage {
  readonly text: string;
}

class UserMessage extends GenericMessage {
  readonly text: string;
}

class ToolMessage extends GenericMessage {
  readonly status: "cancelled" | "pending" | "running" | "completed" | "failed";
  readonly tool?: Tool; // Available when message is from a tool (not subagent)
  readonly toolOrAgentId: string; // ID of the tool or subagent

  isSubAgent(): boolean; // Check if this is a subagent execution
  subAgentTaskId: string | null; // Task ID if this is a subagent, null otherwise
}

class AgentErrorMessage extends GenericMessage {}

class WorkforceAgentMessage extends GenericMessage {}

class WorkforceAgentHandoverMessage extends GenericMessage {}

Tool

class Tool {
  readonly id: string;
  readonly name: string;
  readonly avatar?: string;
  readonly description?: string;
  readonly region: Region;
  readonly project: string;
  readonly parametersSchema: JSONSchema4;
}

Contributing

We welcome contributions to improve the SDK. Please follow these guidelines:

Development Setup

  1. Clone the repository
  2. Install Deno (primary development environment)
# Build npm package
deno run dnt

Code Style

  • Use TypeScript for all code
  • Follow existing patterns and conventions
  • Maintain 80-character line width where practical
  • Write clear, concise commit messages

Submitting Changes

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Submit a pull request with clear description

Roadmap

Current

  • Core client functionality
  • Task creation
  • Event-driven messaging
  • Multi-environment support
  • Workforce support

Upcoming Features

  • Streaming responses
  • File upload support
  • Enhanced error recovery
  • Agent and task management
  • Tool support

Future Considerations (2.0)

  • WebSocket support for real-time updates
  • Offline queue management
  • Tool building architecture
  • Voice modality

Support

License

MIT License. See LICENSE for details.

Security

For security vulnerabilities, please email security@relevanceai.com directly rather than using public issue trackers.

New Ticket: Report package

Please provide a reason for reporting this package. We will review your report and take appropriate action.

Please review the JSR usage policy before submitting a report.

Add Package

deno add jsr:@relevanceai/sdk

Import symbol

import * as sdk from "@relevanceai/sdk";
or

Import directly with a jsr specifier

import * as sdk from "jsr:@relevanceai/sdk";

Add Package

pnpm i jsr:@relevanceai/sdk
or (using pnpm 10.8 or older)
pnpm dlx jsr add @relevanceai/sdk

Import symbol

import * as sdk from "@relevanceai/sdk";

Add Package

yarn add jsr:@relevanceai/sdk
or (using Yarn 4.8 or older)
yarn dlx jsr add @relevanceai/sdk

Import symbol

import * as sdk from "@relevanceai/sdk";

Add Package

vlt install jsr:@relevanceai/sdk

Import symbol

import * as sdk from "@relevanceai/sdk";

Add Package

npx jsr add @relevanceai/sdk

Import symbol

import * as sdk from "@relevanceai/sdk";

Add Package

bunx jsr add @relevanceai/sdk

Import symbol

import * as sdk from "@relevanceai/sdk";