AgentTeam

Multi-agent orchestration with sequential or parallel execution

AgentTeam coordinates multiple agents working together, executing tasks sequentially or in parallel.

Diagram

AgentTeam

🤖 Agent 1

🤖 Agent 2

🤖 Agent 3

📥 Input

📤 Results

Quick Start

  1. Simple Usage
    bash
    npm install praisonai
  2. With Configuration
    typescript
    import { Agent, AgentTeam } from 'praisonai';
    
    const researcher = new Agent({
      name: 'Researcher',
      instructions: 'Research the topic thoroughly'
    });
    
    const writer = new Agent({
      name: 'Writer',
      instructions: 'Write based on research findings'
    });
    
    const team = new AgentTeam({
      agents: [researcher, writer]
    });
    
    const results = await team.start();

How It Works

Diagram
Agent2Agent1AgentTeamUserAgent2Agent1AgentTeamUserstart()Execute taskResult 1Execute task (with context)Result 2[Result 1, Result 2]
ModeBehavior
SequentialEach agent runs after the previous completes, sharing context
ParallelAll agents run simultaneously, results collected together

Configuration Options

typescript
import { Agent, AgentTeam } from 'praisonai';

const team = new AgentTeam({
  agents: [agent1, agent2],
  tasks: ['Research AI trends', 'Write summary'],
  process: 'sequential',
  verbose: true,
  pretty: true
});
OptionTypeDefaultDescription
agentsAgent[]requiredArray of agents to orchestrate
tasksstring[][]Custom tasks for each agent
process`’sequential’ \‘parallel’ \‘hierarchical’`'sequential'Execution mode
verbosebooleantrueEnable logging output
prettybooleanfalseEnable formatted output
llmstringAgent defaultDefault LLM for all agents
memory`boolean \string \MemoryConfig \TeamMemoryStore \{ userId?, config?, … }`falseOne shared store for the team — recalled entries are appended to each task prompt as bullet lines, and each task’s result is written back.
context`boolean \string \ContextManagerConfig \ContextManager`falseOne ContextManager for the run — every task sees everything the team produced, not just the previous result.
hooks{ onTaskStart?, onTaskComplete?, completionChecker? }–Team lifecycle callbacks. Returning false from completionChecker retries the task.
execution`string \{ maxIter, maxRetries } \[preset, overrides]`{ maxIter: 10, maxRetries: 5 }Iteration/retry limits — preset (`”fast” \“balanced” \“thorough” \“unlimited”), object, or preset+overrides. Floors: maxRetries ≥ 3, maxIter ≥ 1`.
planning`boolean \string \{ llm, autoApprove, approveFn, onReject } \[model, overrides]`falsePlan-first mode. Task descriptions become one plan request; the plan’s steps replace the tasks for that run. Defaults to gpt-4o-mini as planner.
managerLlmstringOPENAI_MODEL_NAME env, then 'gpt-4o-mini'Model for the hierarchical manager (used only with process: 'hierarchical').
autonomy`’suggest’ \‘auto_edit’ \‘full_auto’ \AutonomyConfig`–Propagated to every member that declared no autonomy of its own. A member’s own autonomy wins — autonomy is a permission boundary, and silently widening one an agent set for itself is the direction that causes harm. A prompting level (anything not full_auto) also creates the member’s approval gate.
toolsRunOn`string \ToolPlaceLike`–One shared tool place for the whole team. Every member that declared no toolsRunOn of its own gets the same ToolPlace instance — one sandbox for the whole team, not one per member. A member’s own toolsRunOn wins. Unknown place names throw at team construction.
runOn––Refused. Passing runOn throws a TypeError at construction, matching Python. runOn hands one agent’s whole loop to a managed runtime, and a team orchestrates several agents locally — there is no single loop to hand over.

Team-Level Options

Nine options now shape how the whole team runs.

memory

One shared store for the team — recalled entries are appended to each task’s prompt as bullet lines, and each task’s result is written back.

typescript
// memory — shared in-process store
const team = new AgentTeam({
  agents: [researcher, writer],
  tasks: ['Summarise whales', 'Draft the article'],
  memory: true,
});

// memory — bring your own store
const teamWithStore = new AgentTeam({
  agents: [researcher, writer],
  memory: {
    search: async (query, limit) => [{ entry: { content: '...', role: 'assistant' }, score: 1 }],
    add: async (content, role, metadata) => undefined,
  },
});

// memory — file path
new AgentTeam({ agents, memory: '/path/to/memories.jsonl' });

// memory — userId-scoped
new AgentTeam({ agents, memory: { userId: 'me', config: store } });

context

One ContextManager for the run — every task is handed the accumulated context of all earlier tasks, not just the previous result.

typescript
// context — third task sees "reply(task one)\n\nreply(task two)…"
const team = new AgentTeam({
  agents: [worker],
  tasks: ['task one', 'task two', 'task three'],
  context: true,
});

hooks

Team lifecycle callbacks. Returning false from completionChecker retries the task.

typescript
new AgentTeam({
  agents: [...],
  tasks: [...],
  hooks: {
    onTaskStart: (task, taskId) => { /* task: TeamTaskRef */ },
    onTaskComplete: (task, output) => { /* output: TaskOutput */ },
    completionChecker: (task, agentOutput) => agentOutput.length > 0, // false → retry
  },
});
// snake_case keys on_task_start, on_task_complete, completion_checker are also accepted

execution

Iteration and retry limits, as a preset, an object, or [preset, overrides].

typescript
new AgentTeam({ agents, execution: 'fast' });        // maxIter 5,  maxRetries 3 (floor)
new AgentTeam({ agents, execution: 'balanced' });    // maxIter 10, maxRetries 5
new AgentTeam({ agents, execution: 'thorough' });    // maxIter 20, maxRetries 5
new AgentTeam({ agents, execution: 'unlimited' });   // maxIter 100, maxRetries 10
new AgentTeam({ agents, execution: { maxIter: 10, maxRetries: 7 } });
new AgentTeam({ agents, execution: ['balanced', { maxRetries: 8 }] });
// snake_case max_iter / max_retries also accepted

planning

Plan first: the task descriptions become one request, a planner turns it into steps, and the steps are what run.

typescript
new AgentTeam({ agents, tasks: ['research whales'], planning: true });   // planner = gpt-4o-mini
new AgentTeam({ agents, planning: 'gpt-4o' });                           // string names planner LLM
new AgentTeam({ agents, planning: { llm: 'gpt-4o', autoApprove: true, approveFn: (plan) => true, onReject: (plan) => {} } });
new AgentTeam({ agents, planning: ['gpt-4o', { autoApprove: false }] });

// After start(), inspect the plan and todo list
team.getPlan();      // Plan | undefined
team.getTodoList();  // TodoList | undefined

managerLlm

Model for the hierarchical manager. With process: 'hierarchical' a Manager agent on this model decides which task runs next and which member runs it.

typescript
const team = new AgentTeam({
  agents: [
    new Agent({ name: 'alpha', instructions: 'a', llm: 'alpha-model' }),
    new Agent({ name: 'beta',  instructions: 'b', llm: 'beta-model' }),
  ],
  tasks: ['task one', 'task two'],
  process: 'hierarchical',
  managerLlm: 'gpt-4o',
});
// Manager replies with JSON: { task_id, agent_name, action: 'execute' | 'stop' }
// Loop is bounded by MAX_INVALID_SELECTIONS = 3, MAX_TASK_RESELECTIONS = 3, plus execution.maxIter
// Results always stay in task order regardless of delegation order

autonomy

One autonomy level for the whole team. Every member that declared no autonomy of its own adopts it; a member’s own autonomy always wins.

typescript
// Every member without its own autonomy adopts 'full_auto'
const team = new AgentTeam({
  agents: [researcher, writer],
  autonomy: 'full_auto',
});
// researcher and writer both get _autonomyConfig.level === 'full_auto'

// Precedence — a member's own choice wins
const cautious = new Agent({ instructions: 'Careful edits', autonomy: 'suggest' });
const bold = new Agent({ instructions: 'Ship it' });
new AgentTeam({ agents: [cautious, bold], autonomy: 'full_auto' });
// cautious keeps 'suggest'; bold adopts 'full_auto'

// A prompting level creates the approval gate on adopted members
new AgentTeam({ agents: [worker], autonomy: 'suggest' });
// worker gets an ApprovalManager (CLI prompt for anything not full_auto) and a DoomLoopTracker

// Explicit opt-out — members are left untouched
new AgentTeam({ agents, autonomy: false });

toolsRunOn

One shared tool place for the whole team. Every member that declared no toolsRunOn of its own gets the same ToolPlace instance — one sandbox for the whole team, not one per member.

typescript
// Both 'local' and 'docker' are built in — no import needed
const team = new AgentTeam({ agents: [a, b], toolsRunOn: 'local' });
a.getToolPlace()?.placeName === 'local';   // true
a.getToolPlace() === b.getToolPlace();      // true — same instance

new AgentTeam({ agents, toolsRunOn: 'docker' });

// Precedence — a member's own place wins
const own = new Agent({ instructions: 'Sandboxed', toolsRunOn: 'local' });
new AgentTeam({ agents: [own], toolsRunOn: 'docker' });
// own keeps its 'local' place

// Explicit opt-out — members are left unplaced
new AgentTeam({ agents, toolsRunOn: false });

// Unknown place — throws at team construction
new AgentTeam({ agents, toolsRunOn: 'nowhere' });
// TypeError: 'nowhere' is not a known place.

The team’s place reaches any agent the team uses, including one that lives on a task or is built lazily from agentConfig — the same shared instance, on first use. A member that already has a place (its own toolsRunOn or one adopted earlier) is not overridden.

runOn (refused)

runOn is refused on a team: it hands one agent’s whole loop to a managed runtime, and a team orchestrates several agents locally — there is no single loop to hand over. Team-level toolsRunOn is honoured (see the tab above) — run every member’s tools in one shared sandbox.

typescript
new AgentTeam({ agents, runOn: 'openai' });
// TypeError: AgentTeam(runOn="openai") is not supported: runOn= hands one agent's whole
// loop to a managed runtime, and a AgentTeam orchestrates several agents locally.
//   To run every step's tools in one shared sandbox: AgentTeam(toolsRunOn: "openai")
//   To host a single agent's loop, put runOn on that Agent.

new AgentTeam({ agents, runOn: 'openai', toolsRunOn: 'docker' });
// TypeError: ...points the tools at two machines...

Hierarchical Process

With process: 'hierarchical', a Manager agent decides task order and delegation.

Diagram

selects task + agent

result

action: stop

🧠 Manager

🤖 Member Agent

✅ Results in task order

The manager is built under the hood on managerLlm and replies with pinned JSON:

json
{ "task_id": 0, "agent_name": "alpha", "action": "execute" }

action is "execute" | "stop". On a parse error the whole run breaks and no member task runs (Python parity). Outcomes (HierarchicalOutcome): 'completed', 'stopped', 'max-iterations', 'invalid-selections', 'manager-error'. Results always come back in task order regardless of the order the manager delegated.


Read-Only Accessors

After start(), inspect what the team assembled.

AccessorReturnsDescription
team.getSharedMemory()`TeamMemoryStore \undefined`The shared memory store, if memory was set
team.getContextManager()`ContextManager \undefined`The run’s context manager, if context was set
team.getPlan()`Plan \undefined`The generated plan, if planning was set
team.getTodoList()`TodoList \undefined`The plan’s todo list, if planning was set

How the Retry Loop Works

completionChecker returning false triggers a retry, bounded by execution.maxRetries.

Diagram

false, retries left

false, exhausted

true

markStarted

onTaskStart

memory.recall → prepend as bullets

🤖 LLM

completionChecker?

markFailed

markCompleted

memory.remember → context.add

onTaskComplete

The default completionChecker accepts any non-empty answer. On final failure the task is marked { status: 'failed' } — the task still ends and the run continues. This is the same rule as Python.


Common Patterns

Array Syntax

typescript
import { Agent, AgentTeam } from 'praisonai';

const agent1 = new Agent({ instructions: 'Analyze data' });
const agent2 = new Agent({ instructions: 'Summarize analysis' });

// Simple array syntax
const team = new AgentTeam([agent1, agent2]);
const results = await team.start();

Sequential

typescript
const team = new AgentTeam({
  agents: [researcher, analyst, writer],
  process: 'sequential'
});

// Research → Analysis → Writing
const results = await team.start();

Parallel

typescript
const team = new AgentTeam({
  agents: [sentimentAgent, summaryAgent, keywordsAgent],
  process: 'parallel',
  tasks: [
    'Analyze sentiment: "Great product!"',
    'Summarize: "Great product!"',
    'Extract keywords: "Great product!"'
  ]
});

// All run simultaneously
const [sentiment, summary, keywords] = await team.start();

With Custom Tasks

typescript
const team = new AgentTeam({
  agents: [agent1, agent2],
  tasks: [
    'Research the latest AI developments',
    'Write a blog post based on the research'
  ]
});

const results = await team.start();

Best Practices

Use sequential for dependent tasks

When agents need context from previous agents, use sequential mode.

typescript
const team = new AgentTeam({
  agents: [researcher, writer],
  process: 'sequential'  // Writer gets research context
});
Use parallel for independent analysis

When tasks are independent, parallel mode is faster.

typescript
const team = new AgentTeam({
  agents: [analyzer1, analyzer2, analyzer3],
  process: 'parallel'  // All analyze simultaneously
});
Match tasks to agents

Provide one task per agent for explicit control.

typescript
const team = new AgentTeam({
  agents: [agent1, agent2, agent3],
  tasks: ['Task 1', 'Task 2', 'Task 3']
});

Backward Compatibility

typescript
// All of these are equivalent
import { AgentTeam, Agents, PraisonAIAgents } from 'praisonai';

const team1 = new AgentTeam([agent1, agent2]);
const team2 = new Agents([agent1, agent2]);
const team3 = new PraisonAIAgents([agent1, agent2]);

// They are the same class
console.log(AgentTeam === Agents);           // true
console.log(AgentTeam === PraisonAIAgents);  // true

Related