autonomous-agents 0.1.0 → 2.0.1
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/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +9 -0
- package/README.md +260 -96
- package/dist/actions.d.ts +136 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +303 -0
- package/dist/actions.js.map +1 -0
- package/dist/agent.d.ts +49 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +452 -0
- package/dist/agent.js.map +1 -0
- package/dist/goals.d.ts +138 -0
- package/dist/goals.d.ts.map +1 -0
- package/dist/goals.js +342 -0
- package/dist/goals.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics.d.ts +245 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +436 -0
- package/dist/metrics.js.map +1 -0
- package/dist/role.d.ts +122 -0
- package/dist/role.d.ts.map +1 -0
- package/dist/role.js +393 -0
- package/dist/role.js.map +1 -0
- package/dist/team.d.ts +152 -0
- package/dist/team.d.ts.map +1 -0
- package/dist/team.js +347 -0
- package/dist/team.js.map +1 -0
- package/dist/types.d.ts +327 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +27 -36
- package/src/actions.ts +366 -0
- package/src/agent.ts +548 -0
- package/src/goals.ts +435 -0
- package/src/index.ts +135 -0
- package/src/metrics.ts +591 -0
- package/src/role.ts +422 -0
- package/src/team.ts +466 -0
- package/src/types.ts +356 -0
- package/test/actions.test.ts +522 -0
- package/test/agent.test.ts +490 -0
- package/test/goals.test.ts +570 -0
- package/test/metrics.test.ts +707 -0
- package/test/role.test.ts +423 -0
- package/test/team.test.ts +708 -0
- package/tsconfig.json +9 -0
package/src/team.ts
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team - Define and coordinate a team of agents and humans
|
|
3
|
+
*
|
|
4
|
+
* Teams enable collaboration and coordination between multiple agents
|
|
5
|
+
* and human workers working toward shared goals.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
Team as TeamType,
|
|
12
|
+
TeamMember,
|
|
13
|
+
Agent,
|
|
14
|
+
Role as RoleType,
|
|
15
|
+
Goal,
|
|
16
|
+
CommunicationChannel,
|
|
17
|
+
} from './types.js'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create a team
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { Team, Agent, Role } from 'autonomous-agents'
|
|
25
|
+
*
|
|
26
|
+
* const productTeam = Team({
|
|
27
|
+
* name: 'Product Development',
|
|
28
|
+
* description: 'Cross-functional team building product features',
|
|
29
|
+
* members: [
|
|
30
|
+
* {
|
|
31
|
+
* id: 'pm-1',
|
|
32
|
+
* name: 'Sarah',
|
|
33
|
+
* type: 'human',
|
|
34
|
+
* role: Roles.ProductManager,
|
|
35
|
+
* status: 'active',
|
|
36
|
+
* availability: 'available',
|
|
37
|
+
* },
|
|
38
|
+
* {
|
|
39
|
+
* id: 'dev-agent-1',
|
|
40
|
+
* name: 'DevAgent',
|
|
41
|
+
* type: 'agent',
|
|
42
|
+
* role: Roles.SoftwareEngineer,
|
|
43
|
+
* status: 'active',
|
|
44
|
+
* availability: 'available',
|
|
45
|
+
* },
|
|
46
|
+
* ],
|
|
47
|
+
* goals: [
|
|
48
|
+
* {
|
|
49
|
+
* id: 'q1-goal',
|
|
50
|
+
* description: 'Launch new feature X',
|
|
51
|
+
* target: '100%',
|
|
52
|
+
* deadline: new Date('2024-03-31'),
|
|
53
|
+
* priority: 'high',
|
|
54
|
+
* },
|
|
55
|
+
* ],
|
|
56
|
+
* channels: [
|
|
57
|
+
* { id: 'team-slack', type: 'slack', config: { channel: '#product-dev' } },
|
|
58
|
+
* ],
|
|
59
|
+
* })
|
|
60
|
+
*
|
|
61
|
+
* // Add a new member
|
|
62
|
+
* team.addMember({
|
|
63
|
+
* id: 'designer-1',
|
|
64
|
+
* name: 'Alex',
|
|
65
|
+
* type: 'human',
|
|
66
|
+
* role: Roles.Designer,
|
|
67
|
+
* })
|
|
68
|
+
*
|
|
69
|
+
* // Broadcast to team
|
|
70
|
+
* await team.broadcast('Starting sprint planning!')
|
|
71
|
+
*
|
|
72
|
+
* // Get available members
|
|
73
|
+
* const available = team.getAvailableMembers()
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function Team(config: {
|
|
77
|
+
name: string
|
|
78
|
+
description?: string
|
|
79
|
+
members?: TeamMember[]
|
|
80
|
+
goals?: Goal[]
|
|
81
|
+
context?: Record<string, unknown>
|
|
82
|
+
channels?: CommunicationChannel[]
|
|
83
|
+
}): TeamInstance {
|
|
84
|
+
const team: TeamType = {
|
|
85
|
+
id: generateTeamId(config.name),
|
|
86
|
+
name: config.name,
|
|
87
|
+
description: config.description,
|
|
88
|
+
members: config.members || [],
|
|
89
|
+
goals: config.goals,
|
|
90
|
+
context: config.context,
|
|
91
|
+
channels: config.channels,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
...team,
|
|
96
|
+
addMember,
|
|
97
|
+
removeMember,
|
|
98
|
+
getMember,
|
|
99
|
+
getMembers,
|
|
100
|
+
getAvailableMembers,
|
|
101
|
+
getMembersByRole,
|
|
102
|
+
getMembersByType,
|
|
103
|
+
updateMember,
|
|
104
|
+
addGoal,
|
|
105
|
+
updateGoal,
|
|
106
|
+
removeGoal,
|
|
107
|
+
getGoals,
|
|
108
|
+
addChannel,
|
|
109
|
+
removeChannel,
|
|
110
|
+
broadcast,
|
|
111
|
+
sendTo,
|
|
112
|
+
updateContext,
|
|
113
|
+
getContext,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Add a member to the team
|
|
118
|
+
*/
|
|
119
|
+
function addMember(member: TeamMember): void {
|
|
120
|
+
const existing = team.members.find(m => m.id === member.id)
|
|
121
|
+
if (existing) {
|
|
122
|
+
throw new Error(`Member with id ${member.id} already exists`)
|
|
123
|
+
}
|
|
124
|
+
team.members.push(member)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Remove a member from the team
|
|
129
|
+
*/
|
|
130
|
+
function removeMember(memberId: string): boolean {
|
|
131
|
+
const index = team.members.findIndex(m => m.id === memberId)
|
|
132
|
+
if (index === -1) return false
|
|
133
|
+
team.members.splice(index, 1)
|
|
134
|
+
return true
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get a specific member
|
|
139
|
+
*/
|
|
140
|
+
function getMember(memberId: string): TeamMember | undefined {
|
|
141
|
+
return team.members.find(m => m.id === memberId)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get all members
|
|
146
|
+
*/
|
|
147
|
+
function getMembers(): TeamMember[] {
|
|
148
|
+
return [...team.members]
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get available members
|
|
153
|
+
*/
|
|
154
|
+
function getAvailableMembers(): TeamMember[] {
|
|
155
|
+
return team.members.filter(
|
|
156
|
+
m => m.status === 'active' && m.availability === 'available'
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get members by role
|
|
162
|
+
*/
|
|
163
|
+
function getMembersByRole(roleId: string): TeamMember[] {
|
|
164
|
+
return team.members.filter(m => m.role.id === roleId)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get members by type
|
|
169
|
+
*/
|
|
170
|
+
function getMembersByType(type: 'agent' | 'human'): TeamMember[] {
|
|
171
|
+
return team.members.filter(m => m.type === type)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Update a member
|
|
176
|
+
*/
|
|
177
|
+
function updateMember(
|
|
178
|
+
memberId: string,
|
|
179
|
+
updates: Partial<Omit<TeamMember, 'id'>>
|
|
180
|
+
): void {
|
|
181
|
+
const member = team.members.find(m => m.id === memberId)
|
|
182
|
+
if (!member) {
|
|
183
|
+
throw new Error(`Member with id ${memberId} not found`)
|
|
184
|
+
}
|
|
185
|
+
Object.assign(member, updates)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Add a goal
|
|
190
|
+
*/
|
|
191
|
+
function addGoal(goal: Goal): void {
|
|
192
|
+
if (!team.goals) {
|
|
193
|
+
team.goals = []
|
|
194
|
+
}
|
|
195
|
+
team.goals.push(goal)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Update a goal
|
|
200
|
+
*/
|
|
201
|
+
function updateGoal(goalId: string, updates: Partial<Omit<Goal, 'id'>>): void {
|
|
202
|
+
const goal = team.goals?.find(g => g.id === goalId)
|
|
203
|
+
if (!goal) {
|
|
204
|
+
throw new Error(`Goal with id ${goalId} not found`)
|
|
205
|
+
}
|
|
206
|
+
Object.assign(goal, updates)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Remove a goal
|
|
211
|
+
*/
|
|
212
|
+
function removeGoal(goalId: string): boolean {
|
|
213
|
+
if (!team.goals) return false
|
|
214
|
+
const index = team.goals.findIndex(g => g.id === goalId)
|
|
215
|
+
if (index === -1) return false
|
|
216
|
+
team.goals.splice(index, 1)
|
|
217
|
+
return true
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get all goals
|
|
222
|
+
*/
|
|
223
|
+
function getGoals(): Goal[] {
|
|
224
|
+
return team.goals ? [...team.goals] : []
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Add a communication channel
|
|
229
|
+
*/
|
|
230
|
+
function addChannel(channel: CommunicationChannel): void {
|
|
231
|
+
if (!team.channels) {
|
|
232
|
+
team.channels = []
|
|
233
|
+
}
|
|
234
|
+
team.channels.push(channel)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Remove a communication channel
|
|
239
|
+
*/
|
|
240
|
+
function removeChannel(channelId: string): boolean {
|
|
241
|
+
if (!team.channels) return false
|
|
242
|
+
const index = team.channels.findIndex(c => c.id === channelId)
|
|
243
|
+
if (index === -1) return false
|
|
244
|
+
team.channels.splice(index, 1)
|
|
245
|
+
return true
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Broadcast message to all team members
|
|
250
|
+
*/
|
|
251
|
+
async function broadcast(message: string, channelType?: string): Promise<void> {
|
|
252
|
+
const channels = channelType
|
|
253
|
+
? team.channels?.filter(c => c.type === channelType)
|
|
254
|
+
: team.channels
|
|
255
|
+
|
|
256
|
+
if (!channels || channels.length === 0) {
|
|
257
|
+
console.log(`[Team: ${team.name}] Broadcast: ${message}`)
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// In a real implementation, this would send via the specified channels
|
|
262
|
+
for (const channel of channels) {
|
|
263
|
+
console.log(
|
|
264
|
+
`[Team: ${team.name}] [${channel.type}:${channel.id}] ${message}`
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Send message to specific team members
|
|
271
|
+
*/
|
|
272
|
+
async function sendTo(
|
|
273
|
+
memberIds: string[],
|
|
274
|
+
message: string,
|
|
275
|
+
channelType?: string
|
|
276
|
+
): Promise<void> {
|
|
277
|
+
const members = team.members.filter(m => memberIds.includes(m.id))
|
|
278
|
+
|
|
279
|
+
if (members.length === 0) {
|
|
280
|
+
throw new Error('No valid members found')
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// In a real implementation, this would send via appropriate channels
|
|
284
|
+
for (const member of members) {
|
|
285
|
+
console.log(`[Team: ${team.name}] To ${member.name}: ${message}`)
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Update team context
|
|
291
|
+
*/
|
|
292
|
+
function updateContext(key: string, value: unknown): void {
|
|
293
|
+
if (!team.context) {
|
|
294
|
+
team.context = {}
|
|
295
|
+
}
|
|
296
|
+
team.context[key] = value
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Get team context
|
|
301
|
+
*/
|
|
302
|
+
function getContext<T = unknown>(key?: string): T | Record<string, unknown> {
|
|
303
|
+
if (!team.context) return (key ? undefined : {}) as T | Record<string, unknown>
|
|
304
|
+
if (key) return team.context[key] as T
|
|
305
|
+
return { ...team.context }
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Team instance with methods
|
|
311
|
+
*/
|
|
312
|
+
export interface TeamInstance extends TeamType {
|
|
313
|
+
/** Add a member to the team */
|
|
314
|
+
addMember(member: TeamMember): void
|
|
315
|
+
/** Remove a member from the team */
|
|
316
|
+
removeMember(memberId: string): boolean
|
|
317
|
+
/** Get a specific member */
|
|
318
|
+
getMember(memberId: string): TeamMember | undefined
|
|
319
|
+
/** Get all members */
|
|
320
|
+
getMembers(): TeamMember[]
|
|
321
|
+
/** Get available members */
|
|
322
|
+
getAvailableMembers(): TeamMember[]
|
|
323
|
+
/** Get members by role */
|
|
324
|
+
getMembersByRole(roleId: string): TeamMember[]
|
|
325
|
+
/** Get members by type */
|
|
326
|
+
getMembersByType(type: 'agent' | 'human'): TeamMember[]
|
|
327
|
+
/** Update a member */
|
|
328
|
+
updateMember(memberId: string, updates: Partial<Omit<TeamMember, 'id'>>): void
|
|
329
|
+
/** Add a goal */
|
|
330
|
+
addGoal(goal: Goal): void
|
|
331
|
+
/** Update a goal */
|
|
332
|
+
updateGoal(goalId: string, updates: Partial<Omit<Goal, 'id'>>): void
|
|
333
|
+
/** Remove a goal */
|
|
334
|
+
removeGoal(goalId: string): boolean
|
|
335
|
+
/** Get all goals */
|
|
336
|
+
getGoals(): Goal[]
|
|
337
|
+
/** Add a communication channel */
|
|
338
|
+
addChannel(channel: CommunicationChannel): void
|
|
339
|
+
/** Remove a communication channel */
|
|
340
|
+
removeChannel(channelId: string): boolean
|
|
341
|
+
/** Broadcast message to all team members */
|
|
342
|
+
broadcast(message: string, channelType?: string): Promise<void>
|
|
343
|
+
/** Send message to specific members */
|
|
344
|
+
sendTo(memberIds: string[], message: string, channelType?: string): Promise<void>
|
|
345
|
+
/** Update team context */
|
|
346
|
+
updateContext(key: string, value: unknown): void
|
|
347
|
+
/** Get team context */
|
|
348
|
+
getContext<T = unknown>(key?: string): T | Record<string, unknown>
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Generate a team ID from name
|
|
353
|
+
*/
|
|
354
|
+
function generateTeamId(name: string): string {
|
|
355
|
+
return `team-${name.toLowerCase().replace(/\s+/g, '-')}`
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Create a team member entry
|
|
360
|
+
*/
|
|
361
|
+
export function createTeamMember(config: {
|
|
362
|
+
id: string
|
|
363
|
+
name: string
|
|
364
|
+
type: 'agent' | 'human'
|
|
365
|
+
role: RoleType
|
|
366
|
+
status?: 'active' | 'inactive' | 'away'
|
|
367
|
+
availability?: 'available' | 'busy' | 'offline'
|
|
368
|
+
}): TeamMember {
|
|
369
|
+
return {
|
|
370
|
+
id: config.id,
|
|
371
|
+
name: config.name,
|
|
372
|
+
type: config.type,
|
|
373
|
+
role: config.role,
|
|
374
|
+
status: config.status || 'active',
|
|
375
|
+
availability: config.availability || 'available',
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Create a team member from an agent
|
|
381
|
+
*/
|
|
382
|
+
export function teamMemberFromAgent(agent: Agent): TeamMember {
|
|
383
|
+
return {
|
|
384
|
+
id: agent.config.name,
|
|
385
|
+
name: agent.config.name,
|
|
386
|
+
type: 'agent',
|
|
387
|
+
role: agent.config.role,
|
|
388
|
+
status: agent.status === 'idle' || agent.status === 'completed' ? 'active' : 'active',
|
|
389
|
+
availability: agent.status === 'idle' ? 'available' : 'busy',
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Calculate team capacity based on available members
|
|
395
|
+
*/
|
|
396
|
+
export function calculateTeamCapacity(team: TeamInstance): {
|
|
397
|
+
total: number
|
|
398
|
+
available: number
|
|
399
|
+
busy: number
|
|
400
|
+
offline: number
|
|
401
|
+
} {
|
|
402
|
+
const members = team.getMembers()
|
|
403
|
+
const available = members.filter(m => m.availability === 'available').length
|
|
404
|
+
const busy = members.filter(m => m.availability === 'busy').length
|
|
405
|
+
const offline = members.filter(m => m.availability === 'offline').length
|
|
406
|
+
|
|
407
|
+
return {
|
|
408
|
+
total: members.length,
|
|
409
|
+
available,
|
|
410
|
+
busy,
|
|
411
|
+
offline,
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Get team skills - aggregated from all members
|
|
417
|
+
*/
|
|
418
|
+
export function getTeamSkills(team: TeamInstance): string[] {
|
|
419
|
+
const skills = new Set<string>()
|
|
420
|
+
team.getMembers().forEach(member => {
|
|
421
|
+
member.role.skills.forEach(skill => skills.add(skill))
|
|
422
|
+
})
|
|
423
|
+
return Array.from(skills)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Check if team has a specific skill
|
|
428
|
+
*/
|
|
429
|
+
export function teamHasSkill(team: TeamInstance, skill: string): boolean {
|
|
430
|
+
return team.getMembers().some(member =>
|
|
431
|
+
member.role.skills.some(s =>
|
|
432
|
+
s.toLowerCase() === skill.toLowerCase() ||
|
|
433
|
+
s.toLowerCase().includes(skill.toLowerCase())
|
|
434
|
+
)
|
|
435
|
+
)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Find best member for a task based on role skills
|
|
440
|
+
*/
|
|
441
|
+
export function findBestMemberForTask(
|
|
442
|
+
team: TeamInstance,
|
|
443
|
+
requiredSkills: string[]
|
|
444
|
+
): TeamMember | null {
|
|
445
|
+
const availableMembers = team.getAvailableMembers()
|
|
446
|
+
|
|
447
|
+
if (availableMembers.length === 0) return null
|
|
448
|
+
|
|
449
|
+
// Score each member based on skill matches
|
|
450
|
+
const scored = availableMembers.map(member => {
|
|
451
|
+
const matchingSkills = requiredSkills.filter(skill =>
|
|
452
|
+
member.role.skills.some(s =>
|
|
453
|
+
s.toLowerCase().includes(skill.toLowerCase())
|
|
454
|
+
)
|
|
455
|
+
)
|
|
456
|
+
return {
|
|
457
|
+
member,
|
|
458
|
+
score: matchingSkills.length,
|
|
459
|
+
}
|
|
460
|
+
})
|
|
461
|
+
|
|
462
|
+
// Sort by score descending
|
|
463
|
+
scored.sort((a, b) => b.score - a.score)
|
|
464
|
+
|
|
465
|
+
return scored.length > 0 && scored[0]!.score > 0 ? scored[0]!.member : null
|
|
466
|
+
}
|