@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 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,6 @@
1
+ import type { AgentTeam, AgentTeamConfig } from "./types.js";
2
+ /**
3
+ * Create an agent team coordinator
4
+ */
5
+ export declare function createAgentTeam(config: AgentTeamConfig): AgentTeam;
6
+ //# sourceMappingURL=agent-team.d.ts.map
@@ -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"}