@itaylor/agentic-team 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +348 -0
- package/dist/agent-team.d.ts +6 -0
- package/dist/agent-team.d.ts.map +1 -0
- package/dist/agent-team.js +823 -0
- package/dist/agent-team.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +224 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ian Taylor
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# @itaylor/agentic-team
|
|
2
|
+
|
|
3
|
+
A library for coordinating teams of AI agents working together toward a shared goal.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`@itaylor/agentic-team` provides coordination primitives for managing a team of AI agents, where a manager agent delegates tasks to team members and coordinates their work. It builds on [@itaylor/agentic-loop](../agentic-loop) to provide multi-agent orchestration with task management, inter-agent communication, and automatic task queueing.
|
|
8
|
+
|
|
9
|
+
## Why does this exist?
|
|
10
|
+
It's my belief that the best Agentic Coding UI may not be the terminal or the IDE, but something else that we haven't seen yet. Whatever that other UI paradigm may be, there's a need to have an agent that oversees the work of other agents, and coordinates their work towards a shared goal. This is an attempt to implement that pattern that is detached from any particular UI or specific sets of rules/patterns for "development" that we may wish to enforce.
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- **Task Management**: Assign tasks to agents, track completion, automatic queueing
|
|
15
|
+
- **Inter-Agent Communication**: Ask/tell messaging with automatic suspension/resumption
|
|
16
|
+
- **Manager Delegation**: Manager agent coordinates team and delegates work
|
|
17
|
+
- **Built-in Coordination Tools**: Task assignment, status checking, messaging
|
|
18
|
+
- **Event-Based Persistence**: Callbacks for all state changes (tasks, messages, completions)
|
|
19
|
+
- **Resumable Sessions**: Full state can be persisted and restored across restarts
|
|
20
|
+
- **Blocking Semantics**: Agents suspend when waiting for replies, resume when answered
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @itaylor/agentic-team @itaylor/agentic-loop
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Example
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { createAgentTeam } from '@itaylor/agentic-team';
|
|
32
|
+
|
|
33
|
+
// Create a team
|
|
34
|
+
const team = createAgentTeam({
|
|
35
|
+
teamId: 'project-001',
|
|
36
|
+
goal: 'Implement user authentication feature',
|
|
37
|
+
modelConfig: {
|
|
38
|
+
provider: 'anthropic',
|
|
39
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
40
|
+
apiKey: process.env.ANTHROPIC_API_KEY
|
|
41
|
+
},
|
|
42
|
+
manager: {
|
|
43
|
+
id: 'Morgan#1',
|
|
44
|
+
role: 'manager',
|
|
45
|
+
// systemPrompt is optional — defaults to a generic manager prompt
|
|
46
|
+
// The library provides the manager with goal context and workflow instructions automatically
|
|
47
|
+
},
|
|
48
|
+
team: [
|
|
49
|
+
{
|
|
50
|
+
id: 'Bailey#1',
|
|
51
|
+
role: 'backend_engineer',
|
|
52
|
+
// systemPrompt is optional — defaults to a role-based prompt
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'Alex#1',
|
|
56
|
+
role: 'frontend_engineer',
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
callbacks: {
|
|
60
|
+
onTaskCreated: (task) => console.log('Task created:', task.id),
|
|
61
|
+
onTaskCompleted: (task) => console.log('Task completed:', task.id),
|
|
62
|
+
onGoalComplete: (summary) => console.log('Goal complete:', summary),
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
// Run the team autonomously until goal is complete
|
|
68
|
+
const result = await team.run();
|
|
69
|
+
|
|
70
|
+
console.log('Goal complete:', result.complete);
|
|
71
|
+
console.log('Iterations:', result.iterations);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Core Concepts
|
|
75
|
+
|
|
76
|
+
### Manager and Team Members
|
|
77
|
+
|
|
78
|
+
- **Manager**: Special agent that assigns tasks and coordinates the team
|
|
79
|
+
- **Team Members**: Agents that execute tasks assigned by the manager
|
|
80
|
+
- Both run using the agentic-loop library with their own system prompts and tools
|
|
81
|
+
- **System prompts are optional** — the library provides sensible defaults. The manager automatically receives goal context and workflow instructions as its first message; workers receive their task brief and standard completion instructions.
|
|
82
|
+
|
|
83
|
+
### Tasks
|
|
84
|
+
|
|
85
|
+
Tasks have a lifecycle:
|
|
86
|
+
1. **queued**: Task is assigned but agent is busy
|
|
87
|
+
2. **active**: Agent is currently working on this task
|
|
88
|
+
3. **completed**: Agent finished and called `task_complete`
|
|
89
|
+
|
|
90
|
+
Agents work on one task at a time. Additional tasks are queued automatically.
|
|
91
|
+
|
|
92
|
+
### Messages
|
|
93
|
+
|
|
94
|
+
Agents communicate via `ask` and `tell`:
|
|
95
|
+
- **ask**: Sends a question and suspends the agent until reply arrives
|
|
96
|
+
- **tell**: Sends a message or reply to a question
|
|
97
|
+
|
|
98
|
+
When an agent calls `ask`, their session suspends (using agentic-loop's suspension mechanism). When a reply is delivered, the agent can be resumed.
|
|
99
|
+
|
|
100
|
+
The manager can also suspend by calling `wait_for_task_completions()` after assigning work. This prevents the manager from looping unnecessarily while waiting for team members to finish. The manager automatically resumes when task completion notifications arrive.
|
|
101
|
+
|
|
102
|
+
### Built-in Tools
|
|
103
|
+
|
|
104
|
+
**Manager Tools:**
|
|
105
|
+
- `assign_task(assignee, title, brief)` - Create and assign a task
|
|
106
|
+
- `wait_for_task_completions()` - Wait for assigned tasks to complete (suspends)
|
|
107
|
+
- `check_team_status()` - See all agents and tasks
|
|
108
|
+
- `ask(to, question)` - Ask agent or external entity (suspends)
|
|
109
|
+
- `tell(to, message, inReplyTo?)` - Send message
|
|
110
|
+
- `task_complete(summary)` - Complete the overall goal (built-in from agentic-loop)
|
|
111
|
+
|
|
112
|
+
**Team Member Tools:**
|
|
113
|
+
- `get_task_brief()` - Re-read current task details
|
|
114
|
+
- `ask(to, question)` - Ask for help (suspends)
|
|
115
|
+
- `tell(to, message, inReplyTo?)` - Send message
|
|
116
|
+
- `task_complete(summary)` - Complete current task (built-in from agentic-loop)
|
|
117
|
+
|
|
118
|
+
## API
|
|
119
|
+
|
|
120
|
+
### `createAgentTeam(config)`
|
|
121
|
+
|
|
122
|
+
Creates a new agent team coordinator.
|
|
123
|
+
|
|
124
|
+
**Config:**
|
|
125
|
+
```typescript
|
|
126
|
+
{
|
|
127
|
+
teamId: string; // Unique team identifier
|
|
128
|
+
goal: string; // Overall goal the team is working toward
|
|
129
|
+
modelConfig: ModelConfig; // LLM configuration
|
|
130
|
+
manager: ManagerConfig; // Manager agent configuration
|
|
131
|
+
team: TeamMember[]; // Team member configurations
|
|
132
|
+
resumeFrom?: AgentTeamState; // Resume from previous state (for crash recovery)
|
|
133
|
+
callbacks?: TeamCallbacks; // Event callbacks for persistence
|
|
134
|
+
logger?: Logger; // Custom logger
|
|
135
|
+
maxTurnsPerSession?: number; // Max turns per agent run (default: 50)
|
|
136
|
+
tokenLimit?: number; // Token limit for summarization
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**TeamMember / ManagerConfig:**
|
|
141
|
+
```typescript
|
|
142
|
+
{
|
|
143
|
+
id: string; // Unique agent identifier (e.g. "Bailey#1")
|
|
144
|
+
role: string; // Role label (e.g. "backend_engineer")
|
|
145
|
+
systemPrompt?: string; // Optional — library provides a default if omitted
|
|
146
|
+
tools?: Record<string, Tool>; // Domain-specific tools (coordination tools added automatically)
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
If you want to give your agents code editing capabilities (read/write files, search, apply patches, etc.), consider using [agent-mcp](https://github.com/itaylor/agent-mcp) to supply tools via the MCP stdio protocol:
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { Experimental_StdioMCPTransport } from "@ai-sdk/mcp/mcp-stdio";
|
|
154
|
+
import { createMCPClient } from "@ai-sdk/mcp";
|
|
155
|
+
|
|
156
|
+
const transport = new Experimental_StdioMCPTransport({
|
|
157
|
+
command: "/path/to/agent-mcp",
|
|
158
|
+
args: ["/path/to/your/repo"],
|
|
159
|
+
});
|
|
160
|
+
const mcpClient = await createMCPClient({ transport });
|
|
161
|
+
const mcpTools = await mcpClient.tools();
|
|
162
|
+
|
|
163
|
+
const team = createAgentTeam({
|
|
164
|
+
// ...
|
|
165
|
+
team: [
|
|
166
|
+
{
|
|
167
|
+
id: "Bailey#1",
|
|
168
|
+
role: "backend_engineer",
|
|
169
|
+
tools: mcpTools, // agent-mcp tools merged with built-in coordination tools
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await team.run();
|
|
175
|
+
await mcpClient.close();
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Returns:** `AgentTeam` object
|
|
179
|
+
|
|
180
|
+
### `team.run()`
|
|
181
|
+
|
|
182
|
+
Run the team autonomously until the goal is complete or agents are blocked waiting for external input (like BigBoss replies).
|
|
183
|
+
|
|
184
|
+
**Returns:** `Promise<{ complete: boolean, blockedAgents: Array<{ agentId, messageId }>, iterations: number }>`
|
|
185
|
+
|
|
186
|
+
This is the primary way to use the library - just call `run()` and the team coordinates itself automatically.
|
|
187
|
+
|
|
188
|
+
### `team.runAgent(agentId)`
|
|
189
|
+
|
|
190
|
+
Run an agent (manager or team member). The agent will work on their current task or process messages.
|
|
191
|
+
|
|
192
|
+
**Returns:** `Promise<AgentRunResult>`
|
|
193
|
+
```typescript
|
|
194
|
+
{
|
|
195
|
+
agentId: string;
|
|
196
|
+
completed?: boolean; // True if task completed
|
|
197
|
+
suspended?: boolean; // True if agent blocked
|
|
198
|
+
suspendInfo?: { reason, data }; // Suspension details
|
|
199
|
+
finalOutput: string; // Agent's final message
|
|
200
|
+
completionReason: string; // How session ended
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### `team.getNextWork()`
|
|
205
|
+
|
|
206
|
+
Get agents that have active tasks ready to work on.
|
|
207
|
+
|
|
208
|
+
**Returns:** `WorkItem[]`
|
|
209
|
+
```typescript
|
|
210
|
+
{
|
|
211
|
+
agentId: string;
|
|
212
|
+
taskId: string;
|
|
213
|
+
task: Task;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### `team.getBlockedAgents()`
|
|
218
|
+
|
|
219
|
+
Get agents that are blocked waiting for message replies.
|
|
220
|
+
|
|
221
|
+
**Returns:** `Array<{ agentId, messageId }>`
|
|
222
|
+
|
|
223
|
+
### `team.deliverMessageReply(messageId, replyContent)`
|
|
224
|
+
|
|
225
|
+
Deliver a reply to a message, unblocking the waiting agent.
|
|
226
|
+
|
|
227
|
+
**Returns:** `string | null` - The agent ID that should be resumed, or null if not found
|
|
228
|
+
|
|
229
|
+
### `team.isGoalComplete()`
|
|
230
|
+
|
|
231
|
+
Check if the overall goal has been completed (manager called `task_complete`).
|
|
232
|
+
|
|
233
|
+
**Returns:** `boolean`
|
|
234
|
+
|
|
235
|
+
## Event Callbacks
|
|
236
|
+
|
|
237
|
+
All callbacks are optional and can be used for persistence, logging, or UI updates:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
{
|
|
241
|
+
onTaskCreated: (task: Task) => void;
|
|
242
|
+
onTaskActivated: (task: Task) => void;
|
|
243
|
+
onTaskCompleted: (task: Task) => void;
|
|
244
|
+
onMessageSent: (message: TeamMessage) => void;
|
|
245
|
+
onMessageDelivered: (message: TeamMessage) => void;
|
|
246
|
+
onAgentBlocked: (agentId: string, messageId: string) => void;
|
|
247
|
+
onAgentUnblocked: (agentId: string) => void;
|
|
248
|
+
onGoalComplete: (summary: string) => void;
|
|
249
|
+
onStateChange: (state: AgentTeamState) => void;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Persistence and Resumption
|
|
254
|
+
|
|
255
|
+
The library is designed to be stateless - all state is in the `AgentTeamState` object which can be serialized and restored:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Save state
|
|
259
|
+
const state = team.state;
|
|
260
|
+
await fs.writeFile('team-state.json', JSON.stringify(state));
|
|
261
|
+
|
|
262
|
+
// Resume later (even after server restart)
|
|
263
|
+
const savedState = JSON.parse(await fs.readFile('team-state.json'));
|
|
264
|
+
const team = createAgentTeam({
|
|
265
|
+
...config,
|
|
266
|
+
resumeFrom: savedState
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Note: The `agentStates` Map needs special handling for JSON serialization:
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// Serialize
|
|
274
|
+
const stateForSave = {
|
|
275
|
+
...state,
|
|
276
|
+
agentStates: Array.from(state.agentStates.entries())
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// Deserialize
|
|
280
|
+
const loaded = JSON.parse(savedData);
|
|
281
|
+
const state = {
|
|
282
|
+
...loaded,
|
|
283
|
+
agentStates: new Map(loaded.agentStates)
|
|
284
|
+
};
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Example: Full Workflow
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import { createAgentTeam } from '@itaylor/agentic-team';
|
|
291
|
+
|
|
292
|
+
const team = createAgentTeam({
|
|
293
|
+
teamId: 'feature-auth',
|
|
294
|
+
goal: 'Implement user authentication with login and signup',
|
|
295
|
+
modelConfig: { provider: 'anthropic', model: 'claude-3-5-sonnet-20241022', apiKey: '...' },
|
|
296
|
+
manager: {
|
|
297
|
+
id: 'Morgan#1',
|
|
298
|
+
role: 'manager',
|
|
299
|
+
// No systemPrompt needed — the library provides goal context and workflow instructions
|
|
300
|
+
},
|
|
301
|
+
team: [
|
|
302
|
+
{ id: 'Bailey#1', role: 'backend_engineer' },
|
|
303
|
+
{ id: 'Alex#1', role: 'frontend_engineer' }
|
|
304
|
+
]
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
// Run the team autonomously
|
|
309
|
+
const result = await team.run();
|
|
310
|
+
|
|
311
|
+
if (result.complete) {
|
|
312
|
+
console.log('Goal complete!', team.state.goalSummary);
|
|
313
|
+
console.log('Completed in', result.iterations, 'iterations');
|
|
314
|
+
} else if (result.blockedAgents.length > 0) {
|
|
315
|
+
console.log('Blocked on external input:', result.blockedAgents);
|
|
316
|
+
// Handle external questions (e.g., from BigBoss via UI)
|
|
317
|
+
// Then call team.run() again to resume
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Handling External Communication
|
|
322
|
+
|
|
323
|
+
When an agent asks an external entity (like "BigBoss"), `team.run()` returns with blocked agents:
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
// Run team
|
|
327
|
+
const result = await team.run();
|
|
328
|
+
|
|
329
|
+
if (!result.complete && result.blockedAgents.length > 0) {
|
|
330
|
+
for (const blocked of result.blockedAgents) {
|
|
331
|
+
const message = team.state.messages.find(m => m.id === blocked.messageId);
|
|
332
|
+
if (message && message.to === 'BigBoss') {
|
|
333
|
+
// Get answer from human (via UI, CLI, etc.)
|
|
334
|
+
const humanAnswer = await promptHuman(message.content);
|
|
335
|
+
|
|
336
|
+
// Deliver reply
|
|
337
|
+
team.deliverMessageReply(blocked.messageId, humanAnswer);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Resume team
|
|
342
|
+
const resumedResult = await team.run();
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## License
|
|
347
|
+
|
|
348
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-team.d.ts","sourceRoot":"","sources":["../src/agent-team.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EAUhB,MAAM,YAAY,CAAC;AAiCpB;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CA2+BlE"}
|