Node.js SDK
Advanced Usage
Node.js SDK
Advanced Usage
Advanced patterns and best practices for the Node.js SDK
This guide covers advanced usage patterns and best practices for the Julep Node.js SDK.
Parallel Task Execution
Execute multiple tasks in parallel for better performance:
// Create multiple tasks
const tasks = await Promise.all([
client.tasks.create(agentId, {
name: 'Task 1',
main: [/* ... */]
}),
client.tasks.create(agentId, {
name: 'Task 2',
main: [/* ... */]
})
]);
// Execute tasks in parallel
const executions = await Promise.all(
tasks.map(task => client.executions.create(task.id))
);
// Wait for all executions to complete
const results = await Promise.all(
executions.map(async execution => {
let status;
do {
status = await client.executions.get(execution.id);
await new Promise(resolve => setTimeout(resolve, 1000));
} while (status.status !== 'succeeded' && status.status !== 'failed');
return status;
})
);
Custom Error Handling
Implement robust error handling with retries:
class RetryableError extends Error {
constructor(message, retryAfter = 1000) {
super(message);
this.name = 'RetryableError';
this.retryAfter = retryAfter;
}
}
async function withRetry(fn, maxRetries = 3, initialDelay = 1000) {
let lastError;
let delay = initialDelay;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (error.name === 'ValidationError') {
throw error; // Don't retry validation errors
}
if (error.status === 429) { // Rate limit
delay = error.retryAfter || delay * 2;
} else if (error.status >= 500) { // Server error
delay = delay * 2;
} else {
throw error; // Don't retry other errors
}
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw lastError;
}
// Usage example
const createAgentWithRetry = async () => {
return await withRetry(async () => {
return await client.agents.create({
name: 'Resilient Agent',
model: 'claude-3.5-sonnet'
});
});
};
Event Streaming
Handle real-time updates from task executions:
const { EventEmitter } = require('events');
class ExecutionStream extends EventEmitter {
constructor(client, executionId, pollInterval = 1000) {
super();
this.client = client;
this.executionId = executionId;
this.pollInterval = pollInterval;
this.isRunning = false;
}
async start() {
this.isRunning = true;
while (this.isRunning) {
try {
const status = await this.client.executions.get(this.executionId);
this.emit('update', status);
if (status.status === 'succeeded' || status.status === 'failed') {
this.isRunning = false;
this.emit('end', status);
break;
}
await new Promise(resolve => setTimeout(resolve, this.pollInterval));
} catch (error) {
this.emit('error', error);
this.isRunning = false;
break;
}
}
}
stop() {
this.isRunning = false;
}
}
// Usage example
const stream = new ExecutionStream(client, executionId);
stream.on('update', status => {
console.log('Execution status:', status.status);
});
stream.on('end', status => {
console.log('Execution completed:', status);
});
stream.on('error', error => {
console.error('Execution error:', error);
});
stream.start();
Batch Processing
Process large amounts of data efficiently:
async function processBatch(items, batchSize = 10) {
const batches = [];
for (let i = 0; i < items.length; i += batchSize) {
batches.push(items.slice(i, i + batchSize));
}
const results = [];
for (const batch of batches) {
const batchResults = await Promise.all(
batch.map(async item => {
try {
const execution = await client.executions.create(taskId, {
input: { item }
});
return { item, execution };
} catch (error) {
return { item, error };
}
})
);
results.push(...batchResults);
// Optional: Add delay between batches
await new Promise(resolve => setTimeout(resolve, 1000));
}
return results;
}
// Usage example
const items = ['item1', 'item2', 'item3', /* ... */];
const results = await processBatch(items, 5);
Custom Task Middleware
Add custom middleware to task executions:
class TaskMiddleware {
constructor(client) {
this.client = client;
this.middlewares = [];
}
use(fn) {
this.middlewares.push(fn);
return this;
}
async execute(taskId, input) {
let execution = await this.client.executions.create(taskId, { input });
for (const middleware of this.middlewares) {
execution = await middleware(execution, this.client);
}
return execution;
}
}
// Usage example
const middleware = new TaskMiddleware(client);
// Add logging middleware
middleware.use(async (execution, client) => {
console.log(`Execution ${execution.id} started`);
const result = await client.executions.get(execution.id);
console.log(`Execution ${execution.id} completed:`, result.status);
return result;
});
// Add error handling middleware
middleware.use(async (execution, client) => {
try {
return await client.executions.get(execution.id);
} catch (error) {
console.error(`Execution ${execution.id} failed:`, error);
throw error;
}
});
// Execute task with middleware
const result = await middleware.execute(taskId, { data: 'test' });
Advanced Session Management
Implement sophisticated session management:
class SessionManager {
constructor(client) {
this.client = client;
this.sessions = new Map();
}
async getOrCreateSession(userId, agentId) {
if (this.sessions.has(userId)) {
const session = this.sessions.get(userId);
try {
await this.client.sessions.get(session.id);
return session;
} catch (error) {
this.sessions.delete(userId);
}
}
const session = await this.client.sessions.create({
user_id: userId,
agent_id: agentId,
context_overflow: 'adaptive'
});
this.sessions.set(userId, session);
return session;
}
async chat(userId, message) {
const session = await this.getOrCreateSession(userId);
return await this.client.sessions.chat(session.id, {
messages: [{ role: 'user', content: message }]
});
}
async cleanup(maxAge = 24 * 60 * 60 * 1000) {
const now = Date.now();
for (const [userId, session] of this.sessions) {
if (now - new Date(session.created_at).getTime() > maxAge) {
await this.client.sessions.delete(session.id);
this.sessions.delete(userId);
}
}
}
}
// Usage example
const sessionManager = new SessionManager(client);
// Chat with automatic session management
const response = await sessionManager.chat(userId, 'Hello!');
// Cleanup old sessions
await sessionManager.cleanup();