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 🙏

© 2026 – Pkg Stats / Ryan Hefner

team-ai

v0.1.0

Published

A powerful JavaScript SDK for creating and managing teams of AI agents with dependency management, parallel/sequential execution, and memory capabilities.

Readme

TeamAI

npm version License: ISC Node.js Version

TeamAI is a powerful JavaScript SDK for creating, orchestrating, and managing teams of AI agents with advanced dependency management, conditional execution, parallel/sequential execution, session-based memory capabilities, and sophisticated tool integration.

Table of Contents

  1. Features
  2. Installation
  3. Architecture Overview
  4. Quick Start
  5. Conditional Execution with shouldRun
  6. Advanced shouldRun Patterns
  7. Session-Based Memory System
  8. Advanced Tool Integration
  9. API Reference
  10. Browser Usage
  11. Advanced Configuration
  12. Execution Workflows
  13. Debugging and Monitoring
  14. Error Handling & Best Practices
  15. Performance Optimization
  16. Testing
  17. Additional Resources
  18. License

🚀 Features

  • 🤝 Multi-Agent Orchestration: Create and manage teams of specialized AI agents
  • 🔄 Smart Dependency Management: Define complex workflows with automatic circular dependency detection
  • 🎯 Conditional Execution: Use shouldRun for intelligent agent execution based on runtime conditions
  • ⚡ Flexible Execution Modes: Support for both sequential and parallel execution patterns
  • 🧠 Session-Based Memory System: Intelligent conversation memory with per-session isolation and automatic token management
  • 🛠️ Advanced Tool Integration: Register and execute custom tools with automatic parameter injection and result aggregation
  • 📝 Dynamic Placeholder System: Runtime variable replacement throughout agent configurations with support for dependency chaining
  • 🤖 OpenAI Native Integration: First-class support for OpenAI GPT models with streaming and function calling
  • 🔍 Comprehensive Error Handling: Detailed error tracking, retry mechanisms, and graceful failure recovery
  • 🌐 Universal Module Support: Works seamlessly in Node.js, browsers, and all module systems (ES6, CommonJS, UMD)
  • 📊 Execution Analytics: Built-in performance monitoring, memory usage tracking, and result analysis
  • 🔐 Security Features: Input sanitization, rate limiting, and secure API key management
  • ⚡ Performance Optimization: Adaptive concurrency, memory optimization, and intelligent batching

📦 Installation

npm install team-ai

For browser usage:

<script src="https://unpkg.com/team-ai@latest/dist/team-ai.umd.js"></script>

🏗️ Architecture Overview

graph TB
    A[TeamAI SDK] --> B[AgentTeam]
    A --> C[Agent]
    A --> D[AgentMemory]
    A --> E[Tool Registry]

    B --> F[Sequential Execution]
    B --> G[Parallel Execution]
    B --> H[Dependency Validation]
    B --> I[Circular Detection]
    B --> J[shouldRun Evaluation]

    C --> K[OpenAI Integration]
    C --> L[Tool Execution]
    C --> M[Session Management]
    C --> N[Placeholder Resolution]
    C --> O[Conditional Logic]

    D --> P[Session Isolation]
    D --> Q[Token Management]
    D --> R[Memory Cleanup]
    D --> S[Conversation Storage]

    E --> T[Global Tools]
    E --> U[Agent-Specific Tools]
    E --> V[Parameter Injection]

    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style C fill:#e8f5e8
    style D fill:#fff3e0
    style E fill:#fce4ec
    style J fill:#ffecb3
    style O fill:#ffecb3

Core Components

| Component | Purpose | Key Features | |-----------|---------|--------------| | TeamAI | Main SDK orchestrator | Team management, global tools, execution coordination, performance monitoring | | AgentTeam | Agent group manager | Dependency resolution, execution modes, workflow orchestration, parallel processing, conditional execution | | Agent | Individual AI worker | Task execution, tool integration, session management, placeholder resolution, shouldRun logic | | AgentMemory | Session-based storage | Per-session isolation, automatic cleanup, token limits, conversation history |

🚀 Quick Start

Basic Setup

import { TeamAI } from 'team-ai';
import OpenAI from 'openai';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
});

const teamAI = new TeamAI();

const researcher = teamAI.createAgent({
  name: 'market-researcher',
  model: 'gpt-4',
  llm: openai,
  goal: 'Research comprehensive market data about {industry}',
  task: 'Analyze market trends, key players, and opportunities in {industry}',
  backHistory: 'You are a senior market research analyst with 10+ years of experience'
});

researcher.setSessionId('research-session-1');

const result = await researcher.execute({}, { industry: 'artificial intelligence' });
console.log(result.response);

Conditional Workflow with shouldRun

const customerServiceTeam = teamAI.createTeam('customer-service', {
  parallelMode: false
});

const router = teamAI.createAgent({
  name: 'Router',
  model: 'gpt-3.5-turbo',
  llm: openai,
  goal: 'Analyze customer message and determine intent',
  task: 'Analyze: "{customerMessage}" and classify as: GREETING, QUESTION, COMPLAINT, or GOODBYE',
  dependencies: []
});

const greetingAgent = teamAI.createAgent({
  name: 'GreetingAgent',
  model: 'gpt-3.5-turbo',
  llm: openai,
  goal: 'Handle customer greetings warmly',
  task: 'Respond to greeting: "{customerMessage}"',
  dependencies: ['Router'],

  shouldRun: (deps, placeholders) => {
    const routerResponse = deps.Router?.response || '';

    return routerResponse.toLowerCase().includes('greeting') ||
           routerResponse.toLowerCase().includes('hello') ||
           routerResponse.toLowerCase().includes('hi');
  }
});

const questionAgent = teamAI.createAgent({
  name: 'QuestionAgent',
  model: 'gpt-4',
  llm: openai,
  goal: 'Answer customer questions',
  task: 'Answer: "{customerMessage}"',
  dependencies: ['Router'],

  shouldRun: (deps, placeholders) => {
    const routerResponse = deps.Router?.response || '';

    return routerResponse.toLowerCase().includes('question') ||
           routerResponse.toLowerCase().includes('?') ||
           routerResponse.toLowerCase().includes('how');
  }
});

const complaintAgent = teamAI.createAgent({
  name: 'ComplaintAgent',
  model: 'gpt-4',
  llm: openai,
  goal: 'Handle complaints with empathy',
  task: 'Address complaint: "{customerMessage}" with empathy and solutions',
  dependencies: ['Router'],

  shouldRun: (deps, placeholders) => {
    const routerResponse = deps.Router?.response || '';

    return routerResponse.toLowerCase().includes('complaint') ||
           routerResponse.toLowerCase().includes('problem') ||
           routerResponse.toLowerCase().includes('issue');
  }
});

[router, greetingAgent, questionAgent, complaintAgent]
  .forEach(agent => customerServiceTeam.addAgent(agent));

const testMessages = [
  'Hello! How are you today?',
  'How do I reset my password?',
  'I have a problem with my order!',
  'Hi! I have a question about pricing'
];

for (const message of testMessages) {
  const result = await customerServiceTeam.execute({
    customerMessage: message
  });

  console.log(`Message: "${message}"`);
  console.log(`Executed: ${result.summary.successful} agents`);
  console.log(`Skipped: ${result.skippedAgents.join(', ')}`);
}

🎯 Conditional Execution with shouldRun

shouldRun Flow Architecture

flowchart TD
    A[Start Team Execution] --> B[Validate Dependencies]
    B --> C[Topological Sort Agents]
    C --> D[Begin Agent Loop]

    D --> E[Get Next Agent]
    E --> F[Collect Dependency Results]
    F --> G{Agent has shouldRun?}

    G -->|No| H[Execute Agent]
    G -->|Yes| I[Evaluate shouldRun Function]

    I --> J{shouldRun Returns True?}
    J -->|Yes| H[Execute Agent]
    J -->|No| K[Skip Agent]

    K --> L[Create Skipped Result]
    L --> M[Add to Skipped List]
    M --> N[Record in History]

    H --> O[Agent Execution]
    O --> P{Execution Success?}
    P -->|Yes| Q[Store Success Result]
    P -->|No| R[Store Error Result]

    Q --> S[Mark as Completed]
    R --> S
    N --> T[Next Agent Check]
    S --> T

    T --> U{More Agents?}
    U -->|Yes| E
    U -->|No| V[Generate Summary]
    V --> W[Return Results]

    style I fill:#fff3c4
    style J fill:#fff3c4
    style K fill:#ffcdd2
    style L fill:#ffcdd2
    style M fill:#ffcdd2
    style H fill:#c8e6c9
    style O fill:#c8e6c9

How shouldRun Works

The shouldRun function provides intelligent conditional execution for agents:

const agent = teamAI.createAgent({
  name: 'conditional-agent',
  dependencies: ['previous-agent'],

  shouldRun: (deps, placeholders) => {
    const previousResult = deps['previous-agent'];
    return previousResult?.success && previousResult.data?.length > 0;
  },

  goal: 'Process data if previous agent succeeded',
  task: 'Process the data: {previous-agent.response}'
});

shouldRun Parameters

| Parameter | Type | Description | |-----------|------|-------------| | deps | Object | Results from all dependency agents with structure: { agentName: { success, response, tools, ... } } | | placeholders | Object | Global variables passed to team.execute(placeholders) |

Return Value: boolean - true to execute, false to skip

🔄 Advanced shouldRun Patterns

1. Data Validation Workflow

const dataProcessingTeam = teamAI.createTeam('data-processing');

const collector = teamAI.createAgent({
  name: 'DataCollector',
  goal: 'Collect data from source',
  task: 'Collect data about: {topic}',
  dependencies: [],
  shouldUseTool: true
});

collector.registerTool('collect-data', async (params) => {
  const success = Math.random() > 0.3;

  if (!success) {
    return {
      success: false,
      error: 'Data source unavailable',
      needsUserInput: true
    };
  }

  return {
    success: true,
    data: `Data about ${params.topic}`,
    recordCount: 100
  };
});

const validator = teamAI.createAgent({
  name: 'DataValidator',
  goal: 'Validate collected data',
  task: 'Validate data quality',
  dependencies: ['DataCollector'],

  shouldRun: (deps, placeholders) => {
    const collectorResult = deps.DataCollector;

    if (!collectorResult?.success) {
      console.log('⚠️ DataValidator skipped: Collection failed');
      return false;
    }

    const toolResult = collectorResult.tools?.['collect-data'];
    if (!toolResult?.success) {
      console.log('⚠️ DataValidator skipped: No data to validate');
      return false;
    }

    console.log('✅ DataValidator will run: Data collected successfully');
    return true;
  }
});

const processor = teamAI.createAgent({
  name: 'DataProcessor',
  goal: 'Process validated data',
  task: 'Process the validated data',
  dependencies: ['DataValidator'],

  shouldRun: (deps, placeholders) => {
    const validatorResult = deps.DataValidator;

    if (validatorResult?.skipped) {
      console.log('⚠️ DataProcessor skipped: Validator was skipped');
      return false;
    }

    if (!validatorResult?.success) {
      console.log('⚠️ DataProcessor skipped: Validation failed');
      return false;
    }

    console.log('✅ DataProcessor will run: Data validated');
    return true;
  }
});

const userInputAgent = teamAI.createAgent({
  name: 'UserInputAgent',
  goal: 'Request user input when needed',
  task: 'Request additional information from user',
  dependencies: ['DataCollector'],

  shouldRun: (deps, placeholders) => {
    const collectorResult = deps.DataCollector;

    if (collectorResult?.success) {
      return false;
    }

    const toolResult = collectorResult?.tools?.['collect-data'];
    return toolResult?.needsUserInput === true;
  }
});

[collector, validator, processor, userInputAgent]
  .forEach(agent => dataProcessingTeam.addAgent(agent));

2. Fallback System with shouldRun

const analysisTeam = teamAI.createTeam('analysis-system', {
  parallelMode: true,
  maxConcurrent: 3
});

const primaryAnalyzer = teamAI.createAgent({
  name: 'PrimaryAnalyzer',
  goal: 'Perform advanced analysis',
  task: 'Analyze: {inputData}',
  dependencies: [],
  shouldUseTool: true
});

primaryAnalyzer.registerTool('advanced-analysis', async (params) => {
  const shouldFail = Math.random() > 0.7;

  if (shouldFail) {
    return {
      success: false,
      error: 'Advanced analysis service unavailable',
      fallbackNeeded: true
    };
  }

  return {
    success: true,
    analysis: 'Advanced analysis results',
    confidence: 0.95
  };
});

const backupAnalyzer = teamAI.createAgent({
  name: 'BackupAnalyzer',
  goal: 'Perform backup analysis',
  task: 'Fallback analysis for: {inputData}',
  dependencies: ['PrimaryAnalyzer'],

  shouldRun: (deps, placeholders) => {
    const primaryResult = deps.PrimaryAnalyzer;

    if (primaryResult?.success) {
      console.log('⚠️ BackupAnalyzer skipped: Primary succeeded');
      return false;
    }

    const toolResult = primaryResult?.tools?.['advanced-analysis'];
    if (toolResult?.fallbackNeeded) {
      console.log('✅ BackupAnalyzer will run: Fallback needed');
      return true;
    }

    return false;
  }
});

const reportGenerator = teamAI.createAgent({
  name: 'ReportGenerator',
  goal: 'Generate analysis report',
  task: 'Create report from available analysis',
  dependencies: ['PrimaryAnalyzer', 'BackupAnalyzer'],

  shouldRun: (deps, placeholders) => {
    const primaryResult = deps.PrimaryAnalyzer;
    const backupResult = deps.BackupAnalyzer;

    const hasValidAnalysis = primaryResult?.success || backupResult?.success;

    if (hasValidAnalysis) {
      console.log('✅ ReportGenerator will run: Valid analysis available');
      return true;
    }

    console.log('⚠️ ReportGenerator skipped: No valid analysis');
    return false;
  }
});

[primaryAnalyzer, backupAnalyzer, reportGenerator]
  .forEach(agent => analysisTeam.addAgent(agent));

3. Permission-Based Execution

const workflowTeam = teamAI.createTeam('permission-workflow');

const authChecker = teamAI.createAgent({
  name: 'AuthChecker',
  goal: 'Verify user authentication and permissions',
  task: 'Check auth for user: {userId}',
  dependencies: [],
  shouldUseTool: true
});

authChecker.registerTool('check-auth', async (params) => {
  const roles = ['admin', 'user', 'guest'];
  const isAuth = Math.random() > 0.2;

  return {
    success: isAuth,
    authenticated: isAuth,
    role: isAuth ? roles[Math.floor(Math.random() * roles.length)] : null,
    permissions: isAuth ? ['read', 'write', 'delete'].slice(0,
      isAuth ? (Math.floor(Math.random() * 3) + 1) : 0) : []
  };
});

const adminOps = teamAI.createAgent({
  name: 'AdminOperations',
  goal: 'Perform admin operations',
  task: 'Execute admin task: {adminTask}',
  dependencies: ['AuthChecker'],

  shouldRun: (deps, placeholders) => {
    const authResult = deps.AuthChecker;

    if (!authResult?.success) {
      console.log('⚠️ AdminOps skipped: Auth failed');
      return false;
    }

    const authTool = authResult.tools?.['check-auth'];
    if (authTool?.role !== 'admin') {
      console.log('⚠️ AdminOps skipped: User not admin');
      return false;
    }

    console.log('✅ AdminOps will run: Admin authenticated');
    return true;
  }
});

const userOps = teamAI.createAgent({
  name: 'UserOperations',
  goal: 'Perform user operations',
  task: 'Execute user task: {userTask}',
  dependencies: ['AuthChecker'],

  shouldRun: (deps, placeholders) => {
    const authResult = deps.AuthChecker;

    if (!authResult?.success) {
      console.log('⚠️ UserOps skipped: Auth failed');
      return false;
    }

    const authTool = authResult.tools?.['check-auth'];
    const allowedRoles = ['user', 'admin'];

    if (!allowedRoles.includes(authTool?.role)) {
      console.log('⚠️ UserOps skipped: Insufficient permissions');
      return false;
    }

    console.log('✅ UserOps will run: User has permissions');
    return true;
  }
});

const guestOps = teamAI.createAgent({
  name: 'GuestOperations',
  goal: 'Perform guest operations',
  task: 'Execute guest task: {guestTask}',
  dependencies: ['AuthChecker'],

  shouldRun: (deps, placeholders) => {
    const authResult = deps.AuthChecker;

    if (authResult?.skipped) {
      console.log('⚠️ GuestOps skipped: Auth check was skipped');
      return false;
    }

    console.log('✅ GuestOps will run: Auth check completed');
    return true;
  }
});

[authChecker, adminOps, userOps, guestOps]
  .forEach(agent => workflowTeam.addAgent(agent));

📊 shouldRun Results and Tracking

When agents are skipped via shouldRun, TeamAI provides comprehensive tracking:

Execution Results

const result = await team.execute(placeholders);

console.log(result);
/*
{
  teamName: 'customer-service',
  executionTime: 3500,
  mode: 'sequential',
  placeholders: { customerMessage: 'Hello!' },
  results: {
    Router: { success: true, response: '...', skipped: false },
    GreetingAgent: { success: true, response: '...', skipped: false },
    QuestionAgent: {
      success: false,
      response: 'Agent QuestionAgent was skipped: shouldRun condition not met',
      skipped: true,
      reason: 'shouldRun condition not met'
    },
    ComplaintAgent: {
      success: false,
      response: 'Agent ComplaintAgent was skipped: shouldRun condition not met',
      skipped: true,
      reason: 'shouldRun condition not met'
    }
  },
  summary: {
    total: 4,
    successful: 2,
    failed: 0,
    skipped: 2,
    successRate: 50.0,
    executionRate: 50.0
  },
  skippedAgents: ['QuestionAgent', 'ComplaintAgent']
}
*/

Execution History

const history = team.getExecutionHistory();

console.log(history);
/*
[
  {
    agent: 'Router',
    timestamp: '2024-01-15T10:30:00.000Z',
    result: { success: true, response: '...' },
    placeholders: { customerMessage: 'Hello!' },
    skipped: false
  },
  {
    agent: 'GreetingAgent',
    timestamp: '2024-01-15T10:30:02.000Z',
    result: { success: true, response: '...' },
    placeholders: { customerMessage: 'Hello!' },
    skipped: false
  },
  {
    agent: 'QuestionAgent',
    timestamp: '2024-01-15T10:30:02.100Z',
    result: { skipped: true, reason: 'shouldRun condition not met' },
    placeholders: { customerMessage: 'Hello!' },
    skipped: true,
    reason: 'shouldRun condition not met'
  }
]
*/

🎯 Best Practices for shouldRun

1. Keep Logic Simple and Fast

// ✅ Good: Simple, fast evaluation
shouldRun: (deps, placeholders) => {
  return deps.PreviousAgent?.success === true;
}

// ❌ Bad: Complex, slow evaluation
shouldRun: async (deps, placeholders) => {
  const result = await someAsyncOperation();
  return result.complexCalculation();
}

2. Handle Missing Dependencies Gracefully

// ✅ Good: Defensive programming
shouldRun: (deps, placeholders) => {
  const depResult = deps.RequiredAgent;

  if (!depResult || depResult.skipped) {
    console.log('Dependency not available or was skipped');
    return false;
  }

  return depResult.success && depResult.data?.length > 0;
}

3. Provide Clear Logging

// ✅ Good: Clear decision logging
shouldRun: (deps, placeholders) => {
  const authResult = deps.AuthChecker;
  const userRole = authResult?.tools?.auth?.role;

  if (userRole === 'admin') {
    console.log('✅ AdminAgent will run: User is admin');
    return true;
  } else {
    console.log(`⚠️ AdminAgent skipped: User role is ${userRole || 'unknown'}`);
    return false;
  }
}

4. Consider Parallel vs Sequential Execution

const parallelTeam = teamAI.createTeam('parallel-team', {
  parallelMode: true,
  maxConcurrent: 3
});

🧠 Session-Based Memory System

Memory Architecture

graph TB
    A[AgentMemory] --> B[Global Memory]
    A --> C[Session Manager]

    C --> D[Session 1]
    C --> E[Session 2]
    C --> F[Session N]

    D --> G[State Map]
    D --> H[Metadata]
    D --> I[Token Counter]

    G --> J[Conversation History]
    G --> K[Task Results]
    G --> L[Context Data]

    M[Cleanup Service] --> C
    N[Token Limiter] --> D
    N --> E
    N --> F

    style A fill:#e3f2fd
    style C fill:#f3e5f5
    style D fill:#e8f5e8
    style M fill:#fff3e0
    style N fill:#fce4ec

Session Management

import { AgentMemory } from 'team-ai';

const memory = new AgentMemory(8000, {
  maxSessions: 1000,
  memoryTimeout: 3600000,
  cleanupInterval: 600000
});

const sessionId = 'user-conversation-123';

memory.set('conversation_1', 'User asked about market trends', sessionId);
memory.set('analysis_result', 'Market shows 15% growth potential', sessionId);

const sessionData = memory.get(sessionId);
console.log('Session conversations:', sessionData);

memory.setSessionMetadata(sessionId, 'user_id', 'user123');
memory.setSessionMetadata(sessionId, 'domain', 'finance');

const results = memory.search('market trends', sessionId);

const sessionInfo = memory.getSessionInfo(sessionId);
console.log('Session info:', sessionInfo);

memory.cleanupExpiredSessions();

const exportedData = memory.exportSession(sessionId);
memory.importSession(exportedData);

🛠️ Advanced Tool Integration with shouldRun

Tools can also be conditionally executed based on agent state:

const smartAgent = teamAI.createAgent({
  name: 'SmartAgent',
  shouldUseTool: true,
  goal: 'Smart data processing',
  task: 'Process data intelligently based on conditions',
  dependencies: ['DataSource']
});

smartAgent.registerTool('conditional-processor', async (params) => {
  const sourceData = params.DataSource;

  if (!sourceData?.success || !sourceData.data) {
    return {
      success: false,
      error: 'No valid source data available',
      skipped: true
    };
  }

  return {
    success: true,
    processedData: processData(sourceData.data),
    metadata: {
      processingTime: Date.now(),
      recordsProcessed: sourceData.data.length
    }
  };
});

const reportAgent = teamAI.createAgent({
  name: 'ReportAgent',
  goal: 'Generate report from processed data',
  task: 'Create report from: {SmartAgent.tools.conditional-processor}',
  dependencies: ['SmartAgent'],

  shouldRun: (deps, placeholders) => {
    const smartResult = deps.SmartAgent;
    const toolResult = smartResult?.tools?.['conditional-processor'];

    return toolResult?.success === true && !toolResult.skipped;
  }
});

📋 API Reference

AgentTeam Class Updates

| Method | Parameters | Returns | Description | |--------|------------|---------|-------------| | execute(placeholders) | placeholders: Object | Promise<ExecutionResult> | Executes team with shouldRun evaluation | | getSkippedAgents() | - | string[] | Returns list of skipped agent names | | evaluateAgentShouldRun(agent, completed, placeholders) | agent: Agent, completed: Map, placeholders: Object | Object | Evaluates shouldRun condition |

Agent Class Updates

| Method | Parameters | Returns | Description | |--------|------------|---------|-------------| | constructor(config) | config: AgentConfig | Agent | Creates agent with optional shouldRun |

Updated Type Definitions

interface AgentConfig {
  name: string;
  model?: string;
  llm: OpenAI;
  goal: string;
  task: string;
  backHistory?: string;
  dependencies?: string[];
  maxTokens?: number;
  shouldUseTool?: boolean;
  memory?: AgentMemory;
  shouldRun?: (deps: DependencyResults, placeholders: PlaceholderObject) => boolean;
}

interface DependencyResults {
  [agentName: string]: {
    success: boolean;
    response: string;
    tools: Record<string, any>;
    skipped?: boolean;
    reason?: string;
  };
}

interface PlaceholderObject {
  [key: string]: any;
}

interface ExecutionResult {
  teamName: string;
  executionTime: number;
  mode: 'sequential' | 'parallel';
  placeholders: Object;
  results: Record<string, AgentResult>;
  summary: ExecutionSummary;
  skippedAgents: string[];
}

interface AgentResult {
  success: boolean;
  response: string;
  tools: Record<string, any>;
  skipped?: boolean;
  reason?: string;
}

interface ExecutionSummary {
  total: number;
  successful: number;
  failed: number;
  skipped: number;
  successRate: number;
  executionRate: number;
}

🌐 Browser Usage

Via CDN (UMD)

<!DOCTYPE html>
<html>
<head>
    <title>TeamAI Browser Demo with shouldRun</title>
</head>
<body>
    <script src="https://unpkg.com/team-ai@latest/dist/team-ai.umd.js"></script>
    <script>
        const teamAI = new TeamAI();

        const userAgent = teamAI.createAgent({
            name: 'user-detector',
            model: 'gpt-3.5-turbo',
            llm: openai,
            goal: 'Detect if user is logged in',
            task: 'Check user authentication status'
        });

        const authenticatedAgent = teamAI.createAgent({
            name: 'authenticated-features',
            model: 'gpt-3.5-turbo',
            llm: openai,
            goal: 'Show authenticated features',
            task: 'Display user dashboard',
            dependencies: ['user-detector'],

            shouldRun: (deps, placeholders) => {
                const userStatus = deps['user-detector']?.response || '';
                return userStatus.includes('authenticated') || userStatus.includes('logged in');
            }
        });

        userAgent.setSessionId(`browser-user-${Date.now()}`);
        authenticatedAgent.setSessionId(`browser-auth-${Date.now()}`);

        const browserTeam = teamAI.createTeam('browser-team');
        browserTeam.addAgent(userAgent).addAgent(authenticatedAgent);

        browserTeam.execute().then(result => {
            console.log('Browser execution result:', result);
            console.log('Skipped agents:', result.skippedAgents);
        });
    </script>
</body>
</html>

Via ES Modules

<script type="module">
  import { TeamAI, AgentMemory } from 'https://unpkg.com/team-ai@latest/dist/team-ai.esm.js';

  const teamAI = new TeamAI();

  const pageAnalyzer = teamAI.createAgent({
    name: 'page-analyzer',
    memory: new AgentMemory(4000),
    goal: 'Analyze current page',
    task: 'Analyze page content and structure'
  }).setSessionId('browser-session');

  const modalAgent = teamAI.createAgent({
    name: 'modal-trigger',
    goal: 'Show modal if needed',
    task: 'Display modal based on page analysis',
    dependencies: ['page-analyzer'],

    shouldRun: (deps, placeholders) => {
      const analysis = deps['page-analyzer']?.response || '';
      return analysis.includes('show-modal') || analysis.includes('call-to-action');
    }
  }).setSessionId('modal-session');
</script>

🔧 Advanced shouldRun Configuration

Complex Conditional Logic

const complexAgent = teamAI.createAgent({
  name: 'ComplexDecisionAgent',
  dependencies: ['DataAgent', 'AuthAgent', 'ConfigAgent'],

  shouldRun: (deps, placeholders) => {
    const dataResult = deps.DataAgent;
    const authResult = deps.AuthAgent;
    const configResult = deps.ConfigAgent;

    const hasValidData = dataResult?.success &&
                        dataResult.tools?.fetch?.recordCount > 0;

    const isAuthorized = authResult?.success &&
                        authResult.tools?.auth?.permissions?.includes('process');

    const isEnabled = configResult?.success &&
                     configResult.tools?.config?.features?.includes('advanced-processing');

    const shouldExecute = hasValidData && isAuthorized && isEnabled;

    console.log('🔍 ComplexDecisionAgent shouldRun evaluation:');
    console.log(`   📊 Has valid data: ${hasValidData}`);
    console.log(`   🔐 Is authorized: ${isAuthorized}`);
    console.log(`   ⚙️ Is enabled: ${isEnabled}`);
    console.log(`   ✅ Final decision: ${shouldExecute ? 'EXECUTE' : 'SKIP'}`);

    return shouldExecute;
  },

  goal: 'Perform complex data processing',
  task: 'Process data with advanced algorithms'
});

shouldRun with Placeholder Conditions

const parameterBasedAgent = teamAI.createAgent({
  name: 'ParameterAgent',
  dependencies: ['InputValidator'],

  shouldRun: (deps, placeholders) => {
    const userRole = placeholders.userRole;
    const processMode = placeholders.mode;
    const dataSize = placeholders.dataSize;

    const validationResult = deps.InputValidator;

    const isValidInput = validationResult?.success;
    const hasPermission = ['admin', 'poweruser'].includes(userRole);
    const isBatchMode = processMode === 'batch';
    const isLargeDataset = dataSize > 1000;

    const shouldExecute = isValidInput && hasPermission && isBatchMode && isLargeDataset;

    if (!shouldExecute) {
      const reasons = [];
      if (!isValidInput) reasons.push('invalid input');
      if (!hasPermission) reasons.push('insufficient permissions');
      if (!isBatchMode) reasons.push('not batch mode');
      if (!isLargeDataset) reasons.push('dataset too small');

      console.log(`⚠️ ParameterAgent skipped: ${reasons.join(', ')}`);
    }

    return shouldExecute;
  },

  goal: 'Process large datasets in batch mode',
  task: 'Execute batch processing for {dataSize} records'
});

await team.execute({
  userRole: 'admin',
  mode: 'batch',
  dataSize: 5000
});

await team.execute({
  userRole: 'user',
  mode: 'interactive',
  dataSize: 100
});

shouldRun Error Handling

const robustAgent = teamAI.createAgent({
  name: 'RobustAgent',
  dependencies: ['UnreliableAgent'],

  shouldRun: (deps, placeholders) => {
    try {
      const depResult = deps.UnreliableAgent;

      if (depResult?.skipped) {
        console.log('⚠️ RobustAgent: Dependency was skipped, proceeding with fallback');
        return placeholders.allowFallback === true;
      }

      if (!depResult?.success) {
        console.log('⚠️ RobustAgent: Dependency failed, checking error type');
        return depResult?.error?.includes('retryable');
      }

      return depResult.data?.isValid === true;

    } catch (error) {
      console.error('❌ RobustAgent shouldRun error:', error.message);
      return false;
    }
  },

  goal: 'Handle unreliable dependencies gracefully',
  task: 'Process data with error recovery'
});

🔄 Execution Workflows with shouldRun

Sequential Execution with Conditional Logic

graph TD
    A[Start Sequential Execution] --> B[Get Sorted Agents]
    B --> C[Begin Agent Loop]

    C --> D[Get Next Agent]
    D --> E[Collect Dependencies]
    E --> F{Has shouldRun?}

    F -->|No| G[Execute Agent]
    F -->|Yes| H[Call shouldRun Function]

    H --> I{Returns True?}
    I -->|Yes| G[Execute Agent]
    I -->|No| J[Skip Agent]

    J --> K[Create Skipped Result]
    K --> L[Mark as Skipped]
    L --> M[Continue to Next]

    G --> N[Execute Agent Logic]
    N --> O{Success?}
    O -->|Yes| P[Store Success]
    O -->|No| Q[Store Error]

    P --> R[Mark Completed]
    Q --> R
    M --> S{More Agents?}
    R --> S

    S -->|Yes| D
    S -->|No| T[Generate Final Summary]
    T --> U[Return Results with Skip Info]

    style H fill:#fff3c4
    style I fill:#fff3c4
    style J fill:#ffcdd2
    style K fill:#ffcdd2
    style L fill:#ffcdd2

Parallel Execution with shouldRun

graph TD
    A[Start Parallel Execution] --> B[Initialize State]
    B --> C[Main Execution Loop]

    C --> D[Find Ready Agents]
    D --> E[Filter by Dependencies]
    E --> F[Check shouldRun for Each]

    F --> G[Split into Execute/Skip Groups]
    G --> H[Create Skip Results]
    G --> I[Execute Batch]

    H --> J[Update Skipped Set]
    I --> K[Parallel Agent Execution]

    K --> L{All Batch Complete?}
    L -->|No| M[Wait for Completion]
    M --> L
    L -->|Yes| N[Update Completed Set]

    N --> O{More Agents Available?}
    O -->|Yes| D
    O -->|No| P[Check Remaining]

    P --> Q{Unprocessed Agents?}
    Q -->|Yes| R[Mark as Dependency Failed]
    Q -->|No| S[Generate Summary]

    R --> S
    S --> T[Return Results]

    style F fill:#fff3c4
    style G fill:#fff3c4
    style H fill:#ffcdd2
    style J fill:#ffcdd2

🔍 Debugging and Monitoring shouldRun

Enhanced Monitoring with shouldRun Tracking

class shouldRunMonitor {
  constructor(teamAI) {
    this.teamAI = teamAI;
    this.shouldRunHistory = new Map();
    this.decisionLog = [];
  }

  wrapTeamForShouldRunMonitoring(team) {
    const originalEvaluate = team.evaluateAgentShouldRun.bind(team);

    team.evaluateAgentShouldRun = (agent, completed, placeholders) => {
      const startTime = Date.now();

      const result = originalEvaluate(agent, completed, placeholders);

      const evaluationTime = Date.now() - startTime;

      const decision = {
        agentName: agent.name,
        shouldRun: result.shouldRun,
        reason: result.reason,
        evaluationTime,
        timestamp: new Date().toISOString(),
        dependencyStates: Object.keys(result.dependencyResults).reduce((acc, key) => {
          acc[key] = {
            success: result.dependencyResults[key]?.success,
            skipped: result.dependencyResults[key]?.skipped
          };
          return acc;
        }, {}),
        placeholders: { ...placeholders }
      };

      this.decisionLog.push(decision);

      if (!this.shouldRunHistory.has(agent.name)) {
        this.shouldRunHistory.set(agent.name, []);
      }
      this.shouldRunHistory.get(agent.name).push(decision);

      console.log(`🎯 shouldRun Decision for ${agent.name}:`);
      console.log(`   Decision: ${result.shouldRun ? '✅ EXECUTE' : '⏭️ SKIP'}`);
      console.log(`   Reason: ${result.reason || 'Condition met'}`);
      console.log(`   Evaluation time: ${evaluationTime}ms`);
      console.log(`   Dependencies: ${Object.keys(result.dependencyResults).length}`);

      return result;
    };

    return team;
  }

  getShouldRunStats() {
    const stats = {
      totalDecisions: this.decisionLog.length,
      executionDecisions: this.decisionLog.filter(d => d.shouldRun).length,
      skipDecisions: this.decisionLog.filter(d => !d.shouldRun).length,
      averageEvaluationTime: 0,
      agentStats: new Map()
    };

    if (this.decisionLog.length > 0) {
      stats.averageEvaluationTime = this.decisionLog.reduce((sum, d) => sum + d.evaluationTime, 0) / this.decisionLog.length;
    }

    for (const [agentName, decisions] of this.shouldRunHistory) {
      const agentExecutions = decisions.filter(d => d.shouldRun).length;
      const agentSkips = decisions.filter(d => !d.shouldRun).length;

      stats.agentStats.set(agentName, {
        totalDecisions: decisions.length,
        executions: agentExecutions,
        skips: agentSkips,
        executionRate: (agentExecutions / decisions.length) * 100,
        averageEvaluationTime: decisions.reduce((sum, d) => sum + d.evaluationTime, 0) / decisions.length,
        commonSkipReasons: this.getCommonSkipReasons(decisions.filter(d => !d.shouldRun))
      });
    }

    return stats;
  }

  getCommonSkipReasons(skipDecisions) {
    const reasonCounts = {};
    skipDecisions.forEach(decision => {
      const reason = decision.reason || 'Unknown';
      reasonCounts[reason] = (reasonCounts[reason] || 0) + 1;
    });

    return Object.entries(reasonCounts)
      .sort(([,a], [,b]) => b - a)
      .slice(0, 5)
      .map(([reason, count]) => ({ reason, count }));
  }

  printShouldRunReport() {
    const stats = this.getShouldRunStats();

    console.log('\n📊 shouldRun Execution Report');
    console.log('='.repeat(50));
    console.log(`📈 Total Decisions: ${stats.totalDecisions}`);
    console.log(`✅ Executions: ${stats.executionDecisions} (${((stats.executionDecisions/stats.totalDecisions)*100).toFixed(1)}%)`);
    console.log(`⏭️ Skips: ${stats.skipDecisions} (${((stats.skipDecisions/stats.totalDecisions)*100).toFixed(1)}%)`);
    console.log(`⚡ Avg Evaluation Time: ${stats.averageEvaluationTime.toFixed(2)}ms`);

    console.log('\n🤖 Per-Agent Statistics:');
    for (const [agentName, agentStats] of stats.agentStats) {
      console.log(`\n  ${agentName}:`);
      console.log(`    Decisions: ${agentStats.totalDecisions}`);
      console.log(`    Execution Rate: ${agentStats.executionRate.toFixed(1)}%`);
      console.log(`    Avg Eval Time: ${agentStats.averageEvaluationTime.toFixed(2)}ms`);

      if (agentStats.commonSkipReasons.length > 0) {
        console.log(`    Common Skip Reasons:`);
        agentStats.commonSkipReasons.forEach(({ reason, count }) => {
          console.log(`      - ${reason}: ${count}x`);
        });
      }
    }
  }

  exportDecisionLog() {
    return {
      metadata: {
        exportTime: new Date().toISOString(),
        totalDecisions: this.decisionLog.length,
        version: '1.0'
      },
      decisions: this.decisionLog,
      stats: this.getShouldRunStats()
    };
  }
}

const monitor = new shouldRunMonitor(teamAI);
const monitoredTeam = monitor.wrapTeamForShouldRunMonitoring(customerServiceTeam);

const result = await monitoredTeam.execute({ customerMessage: 'Hello!' });
monitor.printShouldRunReport();

const decisionData = monitor.exportDecisionLog();
console.log('Decision log exported:', decisionData.metadata);

🚨 Error Handling & Best Practices with shouldRun

shouldRun-Aware Error Recovery

class RobustTeamExecution {
  constructor(teamAI) {
    this.teamAI = teamAI;
    this.errorLog = new Map();
    this.shouldRunFailures = new Map();
  }

  async executeWithShouldRunRecovery(teamName, placeholders, options = {}) {
    const {
      maxRetries = 3,
      timeout = 300000,
      sessionPrefix = 'robust-session',
      shouldRunRetryPolicy = 'skip'
    } = options;

    const team = this.teamAI.getTeam(teamName);

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        console.log(`🔄 Attempt ${attempt}/${maxRetries} for team ${teamName}`);

        this.wrapShouldRunForErrorHandling(team, shouldRunRetryPolicy);

        this.setupRetrySessionIds(team, sessionPrefix, attempt);

        const result = await this.executeWithTimeout(team, placeholders, timeout);

        console.log(`✅ Team ${teamName} succeeded on attempt ${attempt}`);

        this.logShouldRunStats(result);

        return result;

      } catch (error) {
        this.logError(teamName, attempt, error);

        if (attempt === maxRetries) {
          throw new Error(`Team ${teamName} failed after ${maxRetries} attempts: ${error.message}`);
        }

        this.cleanupFailedAttempt(team);
        await this.wait(Math.pow(2, attempt) * 1000);
      }
    }
  }

  wrapShouldRunForErrorHandling(team, retryPolicy) {
    team.agents.forEach((agent, name) => {
      if (agent.shouldRun && typeof agent.shouldRun === 'function') {
        const originalShouldRun = agent.shouldRun;

        agent.shouldRun = (deps, placeholders) => {
          try {
            const result = originalShouldRun(deps, placeholders);

            if (!this.shouldRunFailures.has(name)) {
              this.shouldRunFailures.set(name, { successes: 0, failures: 0 });
            }
            this.shouldRunFailures.get(name).successes++;

            return result;

          } catch (error) {
            console.error(`❌ shouldRun error for agent ${name}:`, error.message);

            if (!this.shouldRunFailures.has(name)) {
              this.shouldRunFailures.set(name, { successes: 0, failures: 0 });
            }
            this.shouldRunFailures.get(name).failures++;

            switch (retryPolicy) {
              case 'skip':
                console.log(`⏭️ Skipping agent ${name} due to shouldRun error`);
                return false;

              case 'retry':
                console.log(`🔄 Retrying shouldRun for agent ${name}`);
                try {
                  return originalShouldRun(deps, placeholders);
                } catch (retryError) {
                  console.error(`❌ shouldRun retry failed for ${name}:`, retryError.message);
                  return false;
                }

              case 'fallback':
                console.log(`🛡️ Using fallback logic for agent ${name}`);
                return Object.values(deps).every(dep => dep?.success);

              default:
                return false;
            }
          }
        };
      }
    });
  }

  logShouldRunStats(result) {
    const skippedCount = result.skippedAgents.length;
    const executedCount = result.summary.successful + result.summary.failed;
    const totalCount = result.summary.total;

    console.log('\n📊 shouldRun Execution Summary:');
    console.log(`   🎯 Total Agents: ${totalCount}`);
    console.log(`   ✅ Executed: ${executedCount}`);
    console.log(`   ⏭️ Skipped: ${skippedCount}`);
    console.log(`   📈 Execution Rate: ${((executedCount/totalCount)*100).toFixed(1)}%`);

    if (this.shouldRunFailures.size > 0) {
      console.log('\n🚨 shouldRun Error Summary:');
      for (const [agentName, stats] of this.shouldRunFailures) {
        const totalEvals = stats.successes + stats.failures;
        const errorRate = (stats.failures / totalEvals) * 100;

        if (stats.failures > 0) {
          console.log(`   ⚠️ ${agentName}: ${stats.failures}/${totalEvals} evaluations failed (${errorRate.toFixed(1)}%)`);
        }
      }
    }
  }
}

shouldRun Input Validation

class InputValidator {
  static validateShouldRunFunction(shouldRunFn, agentName) {
    if (!shouldRunFn) return true;

    if (typeof shouldRunFn !== 'function') {
      throw new Error(`Agent ${agentName}: shouldRun must be a function`);
    }

    try {
      const testResult = shouldRunFn({}, {});
      if (typeof testResult !== 'boolean') {
        console.warn(`⚠️ Agent ${agentName}: shouldRun should return boolean, got ${typeof testResult}`);
      }
    } catch (error) {
      console.warn(`⚠️ Agent ${agentName}: shouldRun function validation failed:`, error.message);
    }

    return true;
  }

  static validateDependencyAccess(shouldRunFn, agentName, dependencies) {
    if (!shouldRunFn || dependencies.length === 0) return true;

    const mockDeps = {};
    dependencies.forEach(dep => {
      mockDeps[dep] = {
        success: true,
        response: 'mock response',
        tools: {},
        skipped: false
      };
    });

    try {
      shouldRunFn(mockDeps, {});
      console.log(`✅ Agent ${agentName}: shouldRun dependency access validated`);
    } catch (error) {
      console.warn(`⚠️ Agent ${agentName}: shouldRun dependency access issue:`, error.message);
    }

    return true;
  }
}

const createValidatedAgent = (teamAI, config) => {
  if (config.shouldRun) {
    InputValidator.validateShouldRunFunction(config.shouldRun, config.name);
    InputValidator.validateDependencyAccess(config.shouldRun, config.name, config.dependencies || []);
  }

  return teamAI.createAgent(config);
};

const validatedAgent = createValidatedAgent(teamAI, {
  name: 'ValidatedAgent',
  dependencies: ['DataAgent'],
  shouldRun: (deps, placeholders) => {
    const dataResult = deps.DataAgent;
    return dataResult?.success === true;
  },
  goal: 'Process validated data',
  task: 'Handle data processing with validation'
});

📈 Performance Optimization with shouldRun

shouldRun Caching

class ShouldRunCache {
  constructor(maxSize = 1000, ttl = 300000) {
    this.cache = new Map();
    this.maxSize = maxSize;
    this.ttl = ttl;
  }

  generateCacheKey(agentName, deps, placeholders) {
    const depsHash = this.hashObject(deps);
    const placeholdersHash = this.hashObject(placeholders);
    return `${agentName}:${depsHash}:${placeholdersHash}`;
  }

  hashObject(obj) {
    return btoa(JSON.stringify(obj)).slice(0, 16);
  }

  get(key) {
    const entry = this.cache.get(key);
    if (!entry) return null;

    if (Date.now() - entry.timestamp > this.ttl) {
      this.cache.delete(key);
      return null;
    }

    entry.hits++;
    return entry.value;
  }

  set(key, value) {
    if (this.cache.size >= this.maxSize) {
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }

    this.cache.set(key, {
      value,
      timestamp: Date.now(),
      hits: 0
    });
  }

  getStats() {
    const entries = Array.from(this.cache.values());
    return {
      size: this.cache.size,
      totalHits: entries.reduce((sum, entry) => sum + entry.hits, 0),
      avgAge: entries.length > 0 ?
        (Date.now() - entries.reduce((sum, entry) => sum + entry.timestamp, 0) / entries.length) / 1000 : 0
    };
  }
}

function createCachedShouldRun(originalShouldRun, agentName, cache) {
  return (deps, placeholders) => {
    const cacheKey = cache.generateCacheKey(agentName, deps, placeholders);

    const cached = cache.get(cacheKey);
    if (cached !== null) {
      console.log(`🚀 shouldRun cache hit for ${agentName}`);
      return cached;
    }

    const result = originalShouldRun(deps, placeholders);
    cache.set(cacheKey, result);

    return result;
  };
}

const shouldRunCache = new ShouldRunCache();

const cachedAgent = teamAI.createAgent({
  name: 'CachedAgent',
  dependencies: ['DataAgent'],
  shouldRun: createCachedShouldRun(
    (deps, placeholders) => {
      console.log('🔍 Performing expensive shouldRun evaluation...');
      return deps.DataAgent?.success && placeholders.enableProcessing;
    },
    'CachedAgent',
    shouldRunCache
  ),
  goal: 'Process with cached shouldRun',
  task: 'Handle cached decision making'
});

🧪 Testing shouldRun Functions

shouldRun Test Suite

class ShouldRunTestSuite {
  constructor() {
    this.tests = [];
    this.results = [];
  }

  addShouldRunTest(description, shouldRunFn, testCases) {
    this.tests.push({
      description,
      shouldRunFn,
      testCases
    });
  }

  async runAllTests() {
    console.log(`\n🧪 Running shouldRun Tests...`);
    console.log('='.repeat(50));

    for (const test of this.tests) {
      await this.runShouldRunTest(test);
    }

    this.printTestSummary();
  }

  async runShouldRunTest(test) {
    console.log(`\n🔍 Testing: ${test.description}`);

    let passed = 0;
    let failed = 0;

    for (const testCase of test.testCases) {
      try {
        const result = test.shouldRunFn(testCase.deps, testCase.placeholders);

        if (result === testCase.expected) {
          console.log(`  ✅ ${testCase.name}: Expected ${testCase.expected}, got ${result}`);
          passed++;
        } else {
          console.log(`  ❌ ${testCase.name}: Expected ${testCase.expected}, got ${result}`);
          failed++;
        }
      } catch (error) {
        console.log(`  💥 ${testCase.name}: Error - ${error.message}`);
        failed++;
      }
    }

    const testResult = {
      description: test.description,
      passed,
      failed,
      total: test.testCases.length
    };

    this.results.push(testResult);

    console.log(`📊 Result: ${passed}/${passed + failed} passed`);
  }

  printTestSummary() {
    const totalPassed = this.results.reduce((sum, r) => sum + r.passed, 0);
    const totalFailed = this.results.reduce((sum, r) => sum + r.failed, 0);
    const totalTests = totalPassed + totalFailed;

    console.log('\n📈 shouldRun Test Summary:');
    console.log('='.repeat(30));
    console.log(`Total Tests: ${totalTests}`);
    console.log(`Passed: ${totalPassed}`);
    console.log(`Failed: ${totalFailed}`);
    console.log(`Pass Rate: ${((totalPassed / totalTests) * 100).toFixed(1)}%`);

    if (totalFailed > 0) {
      console.log('\n❌ Failed Test Suites:');
      this.results.filter(r => r.failed > 0).forEach(result => {
        console.log(`  - ${result.description}: ${result.failed} failures`);
      });
    }
  }
}

const testSuite = new ShouldRunTestSuite();

testSuite.addShouldRunTest(
  'Basic dependency success check',
  (deps, placeholders) => {
    return deps.DataCollector?.success === true;
  },
  [
    {
      name: 'Success case',
      deps: { DataCollector: { success: true, response: 'data collected' } },
      placeholders: {},
      expected: true
    },
    {
      name: 'Failure case',
      deps: { DataCollector: { success: false, response: 'failed' } },
      placeholders: {},
      expected: false
    },
    {
      name: 'Missing dependency',
      deps: {},
      placeholders: {},
      expected: false
    }
  ]
);

testSuite.addShouldRunTest(
  'Multi-condition validation',
  (deps, placeholders) => {
    const authResult = deps.AuthChecker;
    const dataResult = deps.DataCollector;

    return authResult?.success &&
           authResult.tools?.auth?.role === 'admin' &&
           dataResult?.success &&
           placeholders.mode === 'production';
  },
  [
    {
      name: 'All conditions met',
      deps: {
        AuthChecker: {
          success: true,
          tools: { auth: { role: 'admin' } }
        },
        DataCollector: { success: true }
      },
      placeholders: { mode: 'production' },
      expected: true
    },
    {
      name: 'Wrong user role',
      deps: {
        AuthChecker: {
          success: true,
          tools: { auth: { role: 'user' } }
        },
        DataCollector: { success: true }
      },
      placeholders: { mode: 'production' },
      expected: false
    },
    {
      name: 'Development mode',
      deps: {
        AuthChecker: {
          success: true,
          tools: { auth: { role: 'admin' } }
        },
        DataCollector: { success: true }
      },
      placeholders: { mode: 'development' },
      expected: false
    }
  ]
);

testSuite.addShouldRunTest(
  'Tool result validation',
  (deps, placeholders) => {
    const collectorResult = deps.DataCollector;
    const toolResult = collectorResult?.tools?.['data-fetch'];

    return toolResult?.success && toolResult.recordCount > 0;
  },
  [
    {
      name: 'Valid tool result',
      deps: {
        DataCollector: {
          success: true,
          tools: {
            'data-fetch': {
              success: true,
              recordCount: 100
            }
          }
        }
      },
      placeholders: {},
      expected: true
    },
    {
      name: 'Empty dataset',
      deps: {
        DataCollector: {
          success: true,
          tools: {
            'data-fetch': {
              success: true,
              recordCount: 0
            }
          }
        }
      },
      placeholders: {},
      expected: false
    },
    {
      name: 'Tool failed',
      deps: {
        DataCollector: {
          success: true,
          tools: {
            'data-fetch': {
              success: false,
              error: 'API timeout'
            }
          }
        }
      },
      placeholders: {},
      expected: false
    }
  ]
);

testSuite.runAllTests();

🔗 Additional Resources

shouldRun Best Practices Guide

  1. Keep Functions Pure and Deterministic

    // ✅ Good: Pure function
    shouldRun: (deps, placeholders) => {
      return deps.DataAgent?.success && placeholders.enableProcessing;
    }
    
    // ❌ Bad: Side effects and non-deterministic
    shouldRun: (deps, placeholders) => {
      console.log('Deciding...');
      return Math.random() > 0.5;
    }
  2. Handle Edge Cases Gracefully

    shouldRun: (deps, placeholders) => {
      const dep = deps.RequiredAgent;
    
      if (!dep) return false;
      if (dep.skipped) return false;
      if (!dep.success) return false;
    
      return dep.data?.isValid === true;
    }
  3. Use Meaningful Variable Names

    // ✅ Good: Clear and descriptive
    shouldRun: (deps, placeholders) => {
      const authenticationResult = deps.AuthService;
      const hasValidPermissions = authenticationResult?.tools?.auth?.permissions?.includes('write');
      const isProductionMode = placeholders.environment === 'production';
    
      return hasValidPermissions && isProductionMode;
    }
  4. Document Complex Logic

    shouldRun: (deps, placeholders) => {
      const dataResult = deps.DataCollector;
      const authResult = deps.AuthService;
    
      // Only process data if:
      // 1. Data collection succeeded
      // 2. User is authenticated
      // 3. Dataset is not empty
      // 4. Processing is enabled in config
      return dataResult?.success &&
             authResult?.success &&
             dataResult.tools?.fetch?.recordCount > 0 &&
             placeholders.enableProcessing === true;
    }

Community Examples

  • E-commerce Workflows: Product recommendation systems with user preference routing
  • Content Management: Dynamic content processing based on user roles and content types
  • Data Processing Pipelines: ETL workflows with validation and error handling
  • Financial Analysis: Multi-stage analysis with risk assessment and compliance checks
  • Customer Service: Intelligent ticket routing and escalation systems
  • DevOps Automation: Deployment pipelines with environment-specific conditions

Migration from Static Workflows

If you're upgrading from static agent workflows to shouldRun-based conditional execution:

// BEFORE: Static workflow
const oldTeam = teamAI.createTeam('old-workflow');
const processor = teamAI.createAgent({
  name: 'DataProcessor',
  dependencies: ['DataCollector'],
  goal: 'Process all collected data',
  task: 'Process data regardless of quality'
});

// AFTER: Conditional workflow with shouldRun
const newTeam = teamAI.createTeam('new-workflow');
const smartProcessor = teamAI.createAgent({
  name: 'SmartDataProcessor',
  dependencies: ['DataCollector'],

  shouldRun: (deps, placeholders) => {
    const collectorResult = deps.DataCollector;
    const quality = collectorResult?.tools?.validator?.qualityScore || 0;

    return collectorResult?.success && quality >= 0.8;
  },

  goal: 'Process high-quality data only',
  task: 'Process validated, high-quality data'
});

const fallbackProcessor = teamAI.createAgent({
  name: 'FallbackProcessor',
  dependencies: ['DataCollector'],

  shouldRun: (deps, placeholders) => {
    const collectorResult = deps.DataCollector;
    const quality = collectorResult?.tools?.validator?.qualityScore || 0;

    return collectorResult?.success && quality < 0.8 && quality >= 0.5;
  },

  goal: 'Handle medium-quality data',
  task: 'Process data with additional validation'
});

📄 License

ISC License - see LICENSE file for details.


🚀 Quick Links