AgentTeam
Multi-agent orchestration with sequential or parallel execution
AgentTeam coordinates multiple agents working together, executing tasks sequentially or in parallel.
Quick Start
- Simple Usage
bash npm install praisonai - 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
| Mode | Behavior |
|---|---|
| Sequential | Each agent runs after the previous completes, sharing context |
| Parallel | All agents run simultaneously, results collected together |
Configuration Options
import { Agent, AgentTeam } from 'praisonai';
const team = new AgentTeam({
agents: [agent1, agent2],
tasks: ['Research AI trends', 'Write summary'],
process: 'sequential',
verbose: true,
pretty: true
});| Option | Type | Default | Description | |||||
|---|---|---|---|---|---|---|---|---|
agents | Agent[] | required | Array of agents to orchestrate | |||||
tasks | string[] | [] | Custom tasks for each agent | |||||
process | `’sequential’ \ | ‘parallel’ \ | ‘hierarchical’` | 'sequential' | Execution mode | |||
verbose | boolean | true | Enable logging output | |||||
pretty | boolean | false | Enable formatted output | |||||
llm | string | Agent default | Default LLM for all agents | |||||
memory | `boolean \ | string \ | MemoryConfig \ | TeamMemoryStore \ | { userId?, config?, … }` | false | One 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` | false | One 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]` | false | Plan-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. | ||
managerLlm | string | OPENAI_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.
// 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.
// 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.
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 acceptedexecution
Iteration and retry limits, as a preset, an object, or [preset, overrides].
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 acceptedplanning
Plan first: the task descriptions become one request, a planner turns it into steps, and the steps are what run.
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 | undefinedmanagerLlm
Model for the hierarchical manager. With process: 'hierarchical' a Manager agent on this model decides which task runs next and which member runs it.
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 orderautonomy
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.
// 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.
// 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.
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.
The manager is built under the hood on managerLlm and replies with pinned 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.
| Accessor | Returns | Description | |
|---|---|---|---|
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.
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
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
const team = new AgentTeam({
agents: [researcher, analyst, writer],
process: 'sequential'
});
// Research → Analysis → Writing
const results = await team.start();Parallel
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
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.
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.
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.
const team = new AgentTeam({
agents: [agent1, agent2, agent3],
tasks: ['Task 1', 'Task 2', 'Task 3']
});Backward Compatibility
// 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