Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.julep.ai/llms.txt

Use this file to discover all available pages before exploring further.

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();

Next Steps

API Reference

Complete API documentation

Examples

Real-world examples

Error Handling

Common error patterns

Testing

Testing strategies