npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@relevanceai/sdk

v3.0.0

Published

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.

Readme

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

  • [x] Core client functionality
  • [x] Task creation
  • [x] Event-driven messaging
  • [x] Multi-environment support
  • [x] 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 [email protected] directly rather than using public issue trackers.