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.
Maintainers
Readme
TeamAI
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
- Features
- Installation
- Architecture Overview
- Quick Start
- Conditional Execution with shouldRun
- Advanced shouldRun Patterns
- Session-Based Memory System
- Advanced Tool Integration
- API Reference
- Browser Usage
- Advanced Configuration
- Execution Workflows
- Debugging and Monitoring
- Error Handling & Best Practices
- Performance Optimization
- Testing
- Additional Resources
- 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
shouldRunfor 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-aiFor 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:#ffecb3Core 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:#c8e6c9How 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:#fce4ecSession 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:#ffcdd2Parallel 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
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; }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; }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; }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.
