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.
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.
- 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
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");Choose the installation method for your runtime:
npm install @relevanceai/sdk@latest
# or
yarn add @relevanceai/sdk@latest
# or
pnpm add @relevanceai/sdk@latest
# or
bun add @relevanceai/sdk@latestdeno add jsr:@relevanceai/sdkOr import directly:
import { createClient } from "jsr:@relevanceai/sdk";npm install @relevanceai/sdk@latestnpm install @relevanceai/sdk@latestFor bundlers that warn about node:crypto, create a shim:
// shims/crypto.js
export default window.crypto;Configure your bundler to use the shim:
<script type="importmap">
{
"imports": {
"@relevanceai/sdk": "https://esm.run/@relevanceai/sdk"
}
}
</script>
<script type="module">
import { createClient } from "@relevanceai/sdk";
// Your code here
</script>The SDK supports two authentication methods for different use cases:
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);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);// 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);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.
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" },
});// 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);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.
Load existing workforce tasks.
const task = await workforce.getTask("<task-id>");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.
update: Whenever a subject has been update.message: Unified event for all message typeserror: Error notifications
// 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);
});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();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();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);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
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;
}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;
}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
}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>;
}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";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 {}class Tool {
readonly id: string;
readonly name: string;
readonly avatar?: string;
readonly description?: string;
readonly region: Region;
readonly project: string;
readonly parametersSchema: JSONSchema4;
}We welcome contributions to improve the SDK. Please follow these guidelines:
- Clone the repository
- Install Deno (primary development environment)
# Build npm package
deno run dnt- Use TypeScript for all code
- Follow existing patterns and conventions
- Maintain 80-character line width where practical
- Write clear, concise commit messages
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request with clear description
- Core client functionality
- Task creation
- Event-driven messaging
- Multi-environment support
- Workforce support
- Streaming responses
- File upload support
- Enhanced error recovery
- Agent and task management
- Tool support
- WebSocket support for real-time updates
- Offline queue management
- Tool building architecture
- Voice modality
- Issues: GitHub Issues
- Community: Discord Server
MIT License. See LICENSE for details.
For security vulnerabilities, please email [email protected] directly rather than using public issue trackers.