Examples
Practical examples for building agents with the Arinova Agent SDK
Echo Bot
The simplest possible agent — echoes back whatever the user sends.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
task.sendComplete(`You said: ${task.content}`);
});
agent.on("connected", () => console.log("Echo bot is online!"));
await agent.connect();LLM Integration (OpenAI)
Connect your agent to OpenAI with streaming responses.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
import OpenAI from "openai";
const openai = new OpenAI();
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
const stream = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: task.content }],
stream: true,
});
let fullResponse = "";
for await (const chunk of stream) {
const text = chunk.choices[0]?.delta?.content ?? "";
if (text) {
fullResponse += text;
task.sendChunk(text);
}
}
task.sendComplete(fullResponse);
});
agent.on("connected", () => console.log("LLM agent is online!"));
await agent.connect();Context-Aware LLM Agent
Use conversation history and sender info to give the LLM full context.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
import OpenAI from "openai";
const openai = new OpenAI();
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
// Fetch recent history for context
const history = await task.fetchHistory({ limit: 20 });
// Build messages array from history
const messages = history.messages.map((msg) => ({
role: msg.isAgent ? "assistant" as const : "user" as const,
content: msg.content,
}));
// Add the current message
messages.push({ role: "user", content: task.content });
// Add system prompt with context
messages.unshift({
role: "system" as any,
content: `You are a helpful assistant. The user's name is ${task.senderUsername}. This is a ${task.conversationType} conversation.`,
});
const stream = await openai.chat.completions.create({
model: "gpt-4o",
messages,
stream: true,
});
let fullResponse = "";
for await (const chunk of stream) {
const text = chunk.choices[0]?.delta?.content ?? "";
if (text) {
fullResponse += text;
task.sendChunk(text);
}
}
task.sendComplete(fullResponse);
});
await agent.connect();Multi-Skill Agent
An agent that declares multiple skills and handles them differently.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
skills: [
{
id: "translate",
name: "Translate",
description: "Translate text to English",
},
{
id: "summarize",
name: "Summarize",
description: "Summarize a long text",
},
{
id: "joke",
name: "Joke",
description: "Tell a random joke",
},
],
});
agent.onTask(async (task) => {
// In a real agent, you'd parse which skill was invoked.
// For now, respond based on content patterns.
const content = task.content.toLowerCase();
if (content.includes("/translate")) {
const text = task.content.replace(/\/translate\s*/i, "");
task.sendChunk("Translating...\n\n");
// Call your translation API here
task.sendComplete(`Translation: ${text}`);
} else if (content.includes("/summarize")) {
const text = task.content.replace(/\/summarize\s*/i, "");
task.sendChunk("Summarizing...\n\n");
// Call your summarization API here
task.sendComplete(`Summary: ${text.slice(0, 100)}...`);
} else if (content.includes("/joke")) {
task.sendComplete(
"Why do programmers prefer dark mode? Because light attracts bugs."
);
} else {
task.sendComplete(
"I support /translate, /summarize, and /joke commands!"
);
}
});
agent.on("connected", () => console.log("Multi-skill agent is online!"));
await agent.connect();Proactive Messaging
Send messages to conversations without waiting for user input. Useful for notifications, reminders, or scheduled updates.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
// Track conversations the agent is part of
const activeConversations = new Set<string>();
agent.onTask(async (task) => {
activeConversations.add(task.conversationId);
if (task.content.startsWith("/subscribe")) {
task.sendComplete("You'll receive hourly updates!");
} else {
task.sendComplete(`Got it: ${task.content}`);
}
});
// Send periodic updates to all active conversations
setInterval(async () => {
for (const convId of activeConversations) {
await agent.sendMessage(convId, `Hourly update: Everything is running smoothly.`);
}
}, 60 * 60 * 1000); // Every hour
await agent.connect();File Upload
Upload files to conversations — images, documents, or any other file type.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
import { readFile } from "fs/promises";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
if (task.content.startsWith("/chart")) {
task.sendChunk("Generating chart...\n\n");
// Generate or read a file
const chartData = await readFile("/tmp/chart.png");
// Upload via the task convenience method
const result = await task.uploadFile(
new Uint8Array(chartData),
"chart.png",
"image/png"
);
// Send the image using markdown syntax
task.sendComplete(`Here's your chart:\n\n`);
} else {
task.sendComplete("Use /chart to generate a chart!");
}
});
await agent.connect();Image Auto-Upload
You can also reference local file paths in markdown image syntax. The SDK automatically uploads them:
agent.onTask(async (task) => {
// Save an image to disk first (e.g., from a chart library)
await saveChartToDisk("/tmp/my-chart.png");
// The SDK auto-uploads the local file and replaces the path with a URL
task.sendComplete("Here's the result:\n\n");
});Handling Attachments
Process files that users send to your agent.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
if (task.attachments && task.attachments.length > 0) {
const fileList = task.attachments
.map((a) => `- ${a.fileName} (${a.fileType}, ${a.fileSize} bytes)`)
.join("\n");
task.sendChunk(`I received ${task.attachments.length} file(s):\n${fileList}\n\nProcessing...\n\n`);
// Download and process each attachment
for (const attachment of task.attachments) {
const response = await fetch(attachment.url);
const data = await response.arrayBuffer();
// Process the file data...
}
task.sendComplete("All files processed!");
} else {
task.sendComplete("Send me a file and I'll process it for you.");
}
});
await agent.connect();Notes CRUD
Create, read, update, and delete notes in conversations. Great for to-do lists, meeting notes, or persistent storage.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
const content = task.content.trim();
// List notes
if (content === "/notes") {
const { notes } = await agent.listNotes(task.conversationId);
if (notes.length === 0) {
task.sendComplete("No notes yet. Use `/note add <title>` to create one.");
return;
}
const list = notes.map((n) => `- **${n.title}** (${n.id})`).join("\n");
task.sendComplete(`Notes:\n${list}`);
return;
}
// Create a note
if (content.startsWith("/note add ")) {
const title = content.replace("/note add ", "").trim();
const note = await agent.createNote(task.conversationId, {
title,
content: "",
});
task.sendComplete(`Note created: **${note.title}** (ID: ${note.id})`);
return;
}
// Update a note
if (content.startsWith("/note edit ")) {
// Format: /note edit <noteId> <new content>
const parts = content.replace("/note edit ", "").split(" ");
const noteId = parts[0];
const newContent = parts.slice(1).join(" ");
await agent.updateNote(task.conversationId, noteId, {
content: newContent,
});
task.sendComplete(`Note ${noteId} updated.`);
return;
}
// Delete a note
if (content.startsWith("/note delete ")) {
const noteId = content.replace("/note delete ", "").trim();
await agent.deleteNote(task.conversationId, noteId);
task.sendComplete(`Note ${noteId} deleted.`);
return;
}
task.sendComplete("Commands: `/notes`, `/note add <title>`, `/note edit <id> <content>`, `/note delete <id>`");
});
await agent.connect();Task Cancellation with AbortSignal
Gracefully handle task cancellation using the AbortSignal.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
task.sendChunk("Starting a long operation...\n\n");
// Pass the signal to fetch so it aborts if the user cancels
try {
const response = await fetch("https://api.example.com/slow-endpoint", {
signal: task.signal,
});
const data = await response.json();
task.sendComplete(`Result: ${JSON.stringify(data)}`);
} catch (err) {
if (err instanceof Error && err.name === "AbortError") {
// Task was cancelled by the user — SDK handles cleanup automatically
console.log("Task cancelled by user");
return;
}
throw err; // Re-throw non-cancellation errors
}
});
await agent.connect();Polling with Cancellation
For long-running loops, check task.signal.aborted periodically:
agent.onTask(async (task) => {
task.sendChunk("Processing 100 items...\n\n");
for (let i = 0; i < 100; i++) {
// Check if the user cancelled
if (task.signal.aborted) {
console.log("Cancelled at item", i);
return; // SDK already sent the cancellation error
}
await processItem(i);
task.sendChunk(`Completed item ${i + 1}/100\n`);
}
task.sendComplete("All 100 items processed!");
});Mentions
Tag specific users in your agent's response.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
// In a group conversation, mention the sender in the reply
task.sendComplete(`Here's the info you requested!`, {
mentions: [task.senderUserId],
});
});
await agent.connect();Error Handling with Retry
An agent with robust error handling and graceful degradation.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
reconnectInterval: 10_000, // 10 seconds
});
agent.onTask(async (task) => {
try {
if (!task.content.trim()) {
task.sendError("Please send a non-empty message.");
return;
}
task.sendChunk("Working on it...\n\n");
const result = await processMessage(task.content);
task.sendComplete(result);
} catch (err) {
// sendError is called automatically if you throw,
// but you can also handle it manually
const message = err instanceof Error ? err.message : "Unknown error";
task.sendError(`Sorry, something went wrong: ${message}`);
}
});
agent.on("connected", () => {
console.log("Agent connected successfully");
});
agent.on("disconnected", () => {
console.log("Agent disconnected, will reconnect automatically...");
});
agent.on("error", (err) => {
console.error("Agent error:", err.message);
});
await agent.connect();
async function processMessage(content: string): Promise<string> {
// Your business logic here
return `Processed: ${content}`;
}Group Conversation Agent
An agent that behaves differently based on conversation type and members.
import { ArinovaAgent } from "@arinova-ai/agent-sdk";
const agent = new ArinovaAgent({
serverUrl: "wss://chat.arinova.ai",
botToken: process.env.BOT_TOKEN!,
});
agent.onTask(async (task) => {
// Different behavior for DMs vs groups
if (task.conversationType === "dm") {
task.sendComplete(`Hi ${task.senderUsername}! How can I help you?`);
return;
}
if (task.conversationType === "group") {
const memberCount = task.members?.length ?? 0;
task.sendComplete(
`Hi ${task.senderUsername}! I'm here to help this group of ${memberCount} members.`
);
return;
}
// Handle replies
if (task.replyTo) {
task.sendComplete(`I see you're replying to a previous message. Let me help with that.`);
return;
}
task.sendComplete("Hello!");
});
await agent.connect();