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.
Files changed (51) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/CHANGELOG.md +9 -0
  3. package/README.md +260 -96
  4. package/dist/actions.d.ts +136 -0
  5. package/dist/actions.d.ts.map +1 -0
  6. package/dist/actions.js +303 -0
  7. package/dist/actions.js.map +1 -0
  8. package/dist/agent.d.ts +49 -0
  9. package/dist/agent.d.ts.map +1 -0
  10. package/dist/agent.js +452 -0
  11. package/dist/agent.js.map +1 -0
  12. package/dist/goals.d.ts +138 -0
  13. package/dist/goals.d.ts.map +1 -0
  14. package/dist/goals.js +342 -0
  15. package/dist/goals.js.map +1 -0
  16. package/dist/index.d.ts +55 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +60 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/metrics.d.ts +245 -0
  21. package/dist/metrics.d.ts.map +1 -0
  22. package/dist/metrics.js +436 -0
  23. package/dist/metrics.js.map +1 -0
  24. package/dist/role.d.ts +122 -0
  25. package/dist/role.d.ts.map +1 -0
  26. package/dist/role.js +393 -0
  27. package/dist/role.js.map +1 -0
  28. package/dist/team.d.ts +152 -0
  29. package/dist/team.d.ts.map +1 -0
  30. package/dist/team.js +347 -0
  31. package/dist/team.js.map +1 -0
  32. package/dist/types.d.ts +327 -0
  33. package/dist/types.d.ts.map +1 -0
  34. package/dist/types.js +8 -0
  35. package/dist/types.js.map +1 -0
  36. package/package.json +27 -36
  37. package/src/actions.ts +366 -0
  38. package/src/agent.ts +548 -0
  39. package/src/goals.ts +435 -0
  40. package/src/index.ts +135 -0
  41. package/src/metrics.ts +591 -0
  42. package/src/role.ts +422 -0
  43. package/src/team.ts +466 -0
  44. package/src/types.ts +356 -0
  45. package/test/actions.test.ts +522 -0
  46. package/test/agent.test.ts +490 -0
  47. package/test/goals.test.ts +570 -0
  48. package/test/metrics.test.ts +707 -0
  49. package/test/role.test.ts +423 -0
  50. package/test/team.test.ts +708 -0
  51. package/tsconfig.json +9 -0
@@ -0,0 +1,708 @@
1
+ /**
2
+ * Tests for Team functionality
3
+ *
4
+ * Covers team creation, member management, and helper functions.
5
+ */
6
+
7
+ import { describe, it, expect, vi } from 'vitest'
8
+ import {
9
+ Team,
10
+ Role,
11
+ Agent,
12
+ createTeamMember,
13
+ teamMemberFromAgent,
14
+ calculateTeamCapacity,
15
+ getTeamSkills,
16
+ teamHasSkill,
17
+ findBestMemberForTask,
18
+ } from '../src/index.js'
19
+ import type { TeamMember } from '../src/index.js'
20
+
21
+ // Mock the ai-functions module for Agent tests
22
+ vi.mock('ai-functions', () => ({
23
+ generateObject: vi.fn().mockResolvedValue({
24
+ object: { result: 'mocked result' },
25
+ }),
26
+ }))
27
+
28
+ describe('Team', () => {
29
+ describe('Team creation', () => {
30
+ it('creates a team with basic config', () => {
31
+ const team = Team({
32
+ name: 'Engineering',
33
+ description: 'Engineering team',
34
+ })
35
+
36
+ expect(team.name).toBe('Engineering')
37
+ expect(team.description).toBe('Engineering team')
38
+ expect(team.getMembers()).toEqual([])
39
+ })
40
+
41
+ it('generates id from name', () => {
42
+ const team = Team({
43
+ name: 'Product Development',
44
+ })
45
+
46
+ expect(team.id).toBe('team-product-development')
47
+ })
48
+
49
+ it('creates a team with initial members', () => {
50
+ const role = Role({
51
+ name: 'Developer',
52
+ description: 'Software developer',
53
+ skills: ['typescript'],
54
+ })
55
+
56
+ const member: TeamMember = {
57
+ id: 'member1',
58
+ name: 'Alice',
59
+ type: 'human',
60
+ role,
61
+ status: 'active',
62
+ availability: 'available',
63
+ }
64
+
65
+ const team = Team({
66
+ name: 'Engineering',
67
+ description: 'Engineering team',
68
+ members: [member],
69
+ })
70
+
71
+ expect(team.getMembers()).toHaveLength(1)
72
+ expect(team.getMember('member1')?.name).toBe('Alice')
73
+ })
74
+
75
+ it('creates a team with goals', () => {
76
+ const team = Team({
77
+ name: 'Engineering',
78
+ goals: [
79
+ { id: 'g1', description: 'Launch feature', target: '100%', status: 'active', priority: 'high' },
80
+ ],
81
+ })
82
+
83
+ expect(team.getGoals()).toHaveLength(1)
84
+ })
85
+
86
+ it('creates a team with channels', () => {
87
+ const team = Team({
88
+ name: 'Engineering',
89
+ channels: [
90
+ { id: 'slack', type: 'slack', config: { channel: '#eng' } },
91
+ ],
92
+ })
93
+
94
+ expect(team.channels).toHaveLength(1)
95
+ })
96
+ })
97
+
98
+ describe('Team member management', () => {
99
+ it('adds a member to team', () => {
100
+ const team = Team({
101
+ name: 'Engineering',
102
+ })
103
+
104
+ const role = Role({
105
+ name: 'Developer',
106
+ description: 'Software developer',
107
+ skills: ['typescript'],
108
+ })
109
+
110
+ const member: TeamMember = {
111
+ id: 'member1',
112
+ name: 'Alice',
113
+ type: 'human',
114
+ role,
115
+ status: 'active',
116
+ availability: 'available',
117
+ }
118
+
119
+ team.addMember(member)
120
+
121
+ expect(team.getMembers()).toHaveLength(1)
122
+ expect(team.getMember('member1')?.name).toBe('Alice')
123
+ })
124
+
125
+ it('throws when adding duplicate member', () => {
126
+ const role = Role({
127
+ name: 'Developer',
128
+ description: 'Software developer',
129
+ skills: ['typescript'],
130
+ })
131
+
132
+ const member: TeamMember = {
133
+ id: 'member1',
134
+ name: 'Alice',
135
+ type: 'human',
136
+ role,
137
+ status: 'active',
138
+ availability: 'available',
139
+ }
140
+
141
+ const team = Team({
142
+ name: 'Engineering',
143
+ members: [member],
144
+ })
145
+
146
+ expect(() => team.addMember(member)).toThrow()
147
+ })
148
+
149
+ it('removes a member from team', () => {
150
+ const role = Role({
151
+ name: 'Developer',
152
+ description: 'Software developer',
153
+ skills: ['typescript'],
154
+ })
155
+
156
+ const member: TeamMember = {
157
+ id: 'member1',
158
+ name: 'Alice',
159
+ type: 'human',
160
+ role,
161
+ status: 'active',
162
+ availability: 'available',
163
+ }
164
+
165
+ const team = Team({
166
+ name: 'Engineering',
167
+ members: [member],
168
+ })
169
+
170
+ const result = team.removeMember('member1')
171
+
172
+ expect(result).toBe(true)
173
+ expect(team.getMembers()).toHaveLength(0)
174
+ })
175
+
176
+ it('returns false when removing non-existent member', () => {
177
+ const team = Team({
178
+ name: 'Engineering',
179
+ })
180
+
181
+ const result = team.removeMember('nonexistent')
182
+
183
+ expect(result).toBe(false)
184
+ })
185
+
186
+ it('finds a member by id', () => {
187
+ const role = Role({
188
+ name: 'Developer',
189
+ description: 'Software developer',
190
+ skills: ['typescript'],
191
+ })
192
+
193
+ const member: TeamMember = {
194
+ id: 'member1',
195
+ name: 'Alice',
196
+ type: 'human',
197
+ role,
198
+ status: 'active',
199
+ availability: 'available',
200
+ }
201
+
202
+ const team = Team({
203
+ name: 'Engineering',
204
+ members: [member],
205
+ })
206
+
207
+ const found = team.getMember('member1')
208
+
209
+ expect(found?.name).toBe('Alice')
210
+ })
211
+
212
+ it('returns undefined for non-existent member', () => {
213
+ const team = Team({
214
+ name: 'Engineering',
215
+ })
216
+
217
+ const found = team.getMember('nonexistent')
218
+
219
+ expect(found).toBeUndefined()
220
+ })
221
+
222
+ it('gets available members', () => {
223
+ const role = Role({
224
+ name: 'Developer',
225
+ description: 'Software developer',
226
+ skills: ['typescript'],
227
+ })
228
+
229
+ const team = Team({
230
+ name: 'Engineering',
231
+ members: [
232
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'available' },
233
+ { id: '2', name: 'Bob', type: 'human', role, status: 'active', availability: 'busy' },
234
+ { id: '3', name: 'Charlie', type: 'human', role, status: 'inactive', availability: 'available' },
235
+ ],
236
+ })
237
+
238
+ const available = team.getAvailableMembers()
239
+
240
+ expect(available).toHaveLength(1)
241
+ expect(available[0]?.name).toBe('Alice')
242
+ })
243
+
244
+ it('gets members by type', () => {
245
+ const role = Role({
246
+ name: 'Developer',
247
+ description: 'Software developer',
248
+ skills: ['typescript'],
249
+ })
250
+
251
+ const team = Team({
252
+ name: 'Engineering',
253
+ members: [
254
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'available' },
255
+ { id: '2', name: 'Bot', type: 'agent', role, status: 'active', availability: 'available' },
256
+ ],
257
+ })
258
+
259
+ const humans = team.getMembersByType('human')
260
+ const agents = team.getMembersByType('agent')
261
+
262
+ expect(humans).toHaveLength(1)
263
+ expect(agents).toHaveLength(1)
264
+ })
265
+
266
+ it('gets members by role', () => {
267
+ const devRole = Role({
268
+ name: 'Developer',
269
+ description: 'Software developer',
270
+ skills: ['typescript'],
271
+ })
272
+
273
+ const designerRole = Role({
274
+ name: 'Designer',
275
+ description: 'Designer',
276
+ skills: ['design'],
277
+ })
278
+
279
+ const team = Team({
280
+ name: 'Product',
281
+ members: [
282
+ { id: '1', name: 'Alice', type: 'human', role: devRole, status: 'active', availability: 'available' },
283
+ { id: '2', name: 'Bob', type: 'human', role: designerRole, status: 'active', availability: 'available' },
284
+ ],
285
+ })
286
+
287
+ const developers = team.getMembersByRole('developer')
288
+
289
+ expect(developers).toHaveLength(1)
290
+ expect(developers[0]?.name).toBe('Alice')
291
+ })
292
+
293
+ it('updates a member', () => {
294
+ const role = Role({
295
+ name: 'Developer',
296
+ description: 'Software developer',
297
+ skills: ['typescript'],
298
+ })
299
+
300
+ const team = Team({
301
+ name: 'Engineering',
302
+ members: [
303
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'available' },
304
+ ],
305
+ })
306
+
307
+ team.updateMember('1', { availability: 'busy' })
308
+
309
+ expect(team.getMember('1')?.availability).toBe('busy')
310
+ })
311
+ })
312
+
313
+ describe('Team goals', () => {
314
+ it('adds a goal', () => {
315
+ const team = Team({ name: 'Engineering' })
316
+
317
+ team.addGoal({
318
+ id: 'g1',
319
+ description: 'Launch feature',
320
+ target: '100%',
321
+ status: 'active',
322
+ priority: 'high',
323
+ })
324
+
325
+ expect(team.getGoals()).toHaveLength(1)
326
+ })
327
+
328
+ it('updates a goal', () => {
329
+ const team = Team({
330
+ name: 'Engineering',
331
+ goals: [
332
+ { id: 'g1', description: 'Launch feature', target: '100%', status: 'active', priority: 'high' },
333
+ ],
334
+ })
335
+
336
+ team.updateGoal('g1', { status: 'completed' })
337
+
338
+ expect(team.getGoals()[0]?.status).toBe('completed')
339
+ })
340
+
341
+ it('removes a goal', () => {
342
+ const team = Team({
343
+ name: 'Engineering',
344
+ goals: [
345
+ { id: 'g1', description: 'Launch feature', target: '100%', status: 'active', priority: 'high' },
346
+ ],
347
+ })
348
+
349
+ const result = team.removeGoal('g1')
350
+
351
+ expect(result).toBe(true)
352
+ expect(team.getGoals()).toHaveLength(0)
353
+ })
354
+ })
355
+
356
+ describe('Team context', () => {
357
+ it('updates context', () => {
358
+ const team = Team({ name: 'Engineering' })
359
+
360
+ team.updateContext('sprint', 'Sprint 1')
361
+
362
+ expect(team.getContext('sprint')).toBe('Sprint 1')
363
+ })
364
+
365
+ it('gets all context', () => {
366
+ const team = Team({
367
+ name: 'Engineering',
368
+ context: { existing: 'value' },
369
+ })
370
+
371
+ team.updateContext('new', 'data')
372
+
373
+ const context = team.getContext()
374
+
375
+ expect(context).toHaveProperty('existing')
376
+ expect(context).toHaveProperty('new')
377
+ })
378
+ })
379
+
380
+ describe('createTeamMember', () => {
381
+ it('creates a team member with basic config', () => {
382
+ const role = Role({
383
+ name: 'Developer',
384
+ description: 'Software developer',
385
+ skills: ['typescript'],
386
+ })
387
+
388
+ const member = createTeamMember({
389
+ id: 'member1',
390
+ name: 'Alice',
391
+ type: 'human',
392
+ role,
393
+ })
394
+
395
+ expect(member.id).toBe('member1')
396
+ expect(member.name).toBe('Alice')
397
+ expect(member.type).toBe('human')
398
+ expect(member.role.name).toBe('Developer')
399
+ expect(member.status).toBe('active')
400
+ expect(member.availability).toBe('available')
401
+ })
402
+
403
+ it('creates a team member with custom status', () => {
404
+ const role = Role({
405
+ name: 'Developer',
406
+ description: 'Software developer',
407
+ skills: ['typescript'],
408
+ })
409
+
410
+ const member = createTeamMember({
411
+ id: 'member1',
412
+ name: 'Alice',
413
+ type: 'human',
414
+ role,
415
+ status: 'away',
416
+ availability: 'busy',
417
+ })
418
+
419
+ expect(member.status).toBe('away')
420
+ expect(member.availability).toBe('busy')
421
+ })
422
+ })
423
+
424
+ describe('teamMemberFromAgent', () => {
425
+ it('creates team member from agent', () => {
426
+ const role = Role({
427
+ name: 'Developer',
428
+ description: 'Software developer',
429
+ skills: ['typescript'],
430
+ })
431
+
432
+ const agent = Agent({
433
+ name: 'CodeBot',
434
+ role,
435
+ })
436
+
437
+ const member = teamMemberFromAgent(agent)
438
+
439
+ expect(member.id).toBe('CodeBot')
440
+ expect(member.name).toBe('CodeBot')
441
+ expect(member.type).toBe('agent')
442
+ expect(member.role.name).toBe('Developer')
443
+ })
444
+
445
+ it('sets availability based on agent status', () => {
446
+ const role = Role({
447
+ name: 'Developer',
448
+ description: 'Software developer',
449
+ skills: ['typescript'],
450
+ })
451
+
452
+ const agent = Agent({
453
+ name: 'CodeBot',
454
+ role,
455
+ })
456
+
457
+ const member = teamMemberFromAgent(agent)
458
+
459
+ // Idle agent should be available
460
+ expect(member.availability).toBe('available')
461
+ })
462
+ })
463
+
464
+ describe('calculateTeamCapacity', () => {
465
+ it('calculates team capacity', () => {
466
+ const role = Role({
467
+ name: 'Developer',
468
+ description: 'Software developer',
469
+ skills: ['typescript'],
470
+ })
471
+
472
+ const team = Team({
473
+ name: 'Engineering',
474
+ members: [
475
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'available' },
476
+ { id: '2', name: 'Bob', type: 'human', role, status: 'active', availability: 'busy' },
477
+ { id: '3', name: 'Charlie', type: 'human', role, status: 'active', availability: 'offline' },
478
+ ],
479
+ })
480
+
481
+ const capacity = calculateTeamCapacity(team)
482
+
483
+ expect(capacity.total).toBe(3)
484
+ expect(capacity.available).toBe(1)
485
+ expect(capacity.busy).toBe(1)
486
+ expect(capacity.offline).toBe(1)
487
+ })
488
+
489
+ it('returns 0 for empty team', () => {
490
+ const team = Team({
491
+ name: 'Empty',
492
+ })
493
+
494
+ const capacity = calculateTeamCapacity(team)
495
+
496
+ expect(capacity.total).toBe(0)
497
+ expect(capacity.available).toBe(0)
498
+ })
499
+ })
500
+
501
+ describe('getTeamSkills', () => {
502
+ it('returns all unique skills from team', () => {
503
+ const role1 = Role({
504
+ name: 'Developer',
505
+ description: 'Software developer',
506
+ skills: ['typescript', 'javascript'],
507
+ })
508
+
509
+ const role2 = Role({
510
+ name: 'Designer',
511
+ description: 'Designer',
512
+ skills: ['figma', 'css'],
513
+ })
514
+
515
+ const team = Team({
516
+ name: 'Product',
517
+ members: [
518
+ { id: '1', name: 'Alice', type: 'human', role: role1, status: 'active', availability: 'available' },
519
+ { id: '2', name: 'Bob', type: 'human', role: role2, status: 'active', availability: 'available' },
520
+ ],
521
+ })
522
+
523
+ const skills = getTeamSkills(team)
524
+
525
+ expect(skills).toContain('typescript')
526
+ expect(skills).toContain('javascript')
527
+ expect(skills).toContain('figma')
528
+ expect(skills).toContain('css')
529
+ })
530
+
531
+ it('deduplicates skills', () => {
532
+ const role = Role({
533
+ name: 'Developer',
534
+ description: 'Software developer',
535
+ skills: ['typescript', 'javascript'],
536
+ })
537
+
538
+ const team = Team({
539
+ name: 'Engineering',
540
+ members: [
541
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'available' },
542
+ { id: '2', name: 'Bob', type: 'human', role, status: 'active', availability: 'available' },
543
+ ],
544
+ })
545
+
546
+ const skills = getTeamSkills(team)
547
+
548
+ expect(skills).toHaveLength(2)
549
+ })
550
+
551
+ it('returns empty array for empty team', () => {
552
+ const team = Team({
553
+ name: 'Empty',
554
+ })
555
+
556
+ const skills = getTeamSkills(team)
557
+
558
+ expect(skills).toEqual([])
559
+ })
560
+ })
561
+
562
+ describe('teamHasSkill', () => {
563
+ it('returns true when team has skill', () => {
564
+ const role = Role({
565
+ name: 'Developer',
566
+ description: 'Software developer',
567
+ skills: ['typescript', 'javascript'],
568
+ })
569
+
570
+ const team = Team({
571
+ name: 'Engineering',
572
+ members: [
573
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'available' },
574
+ ],
575
+ })
576
+
577
+ expect(teamHasSkill(team, 'typescript')).toBe(true)
578
+ })
579
+
580
+ it('returns false when team does not have skill', () => {
581
+ const role = Role({
582
+ name: 'Developer',
583
+ description: 'Software developer',
584
+ skills: ['typescript'],
585
+ })
586
+
587
+ const team = Team({
588
+ name: 'Engineering',
589
+ members: [
590
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'available' },
591
+ ],
592
+ })
593
+
594
+ expect(teamHasSkill(team, 'rust')).toBe(false)
595
+ })
596
+
597
+ it('returns false for empty team', () => {
598
+ const team = Team({
599
+ name: 'Empty',
600
+ })
601
+
602
+ expect(teamHasSkill(team, 'typescript')).toBe(false)
603
+ })
604
+ })
605
+
606
+ describe('findBestMemberForTask', () => {
607
+ it('finds member with required skill', () => {
608
+ const devRole = Role({
609
+ name: 'Developer',
610
+ description: 'Software developer',
611
+ skills: ['typescript', 'javascript'],
612
+ })
613
+
614
+ const designerRole = Role({
615
+ name: 'Designer',
616
+ description: 'Designer',
617
+ skills: ['figma', 'css'],
618
+ })
619
+
620
+ const team = Team({
621
+ name: 'Product',
622
+ members: [
623
+ { id: '1', name: 'Alice', type: 'human', role: devRole, status: 'active', availability: 'available' },
624
+ { id: '2', name: 'Bob', type: 'human', role: designerRole, status: 'active', availability: 'available' },
625
+ ],
626
+ })
627
+
628
+ const best = findBestMemberForTask(team, ['typescript'])
629
+
630
+ expect(best?.name).toBe('Alice')
631
+ })
632
+
633
+ it('returns null when no member has skill', () => {
634
+ const role = Role({
635
+ name: 'Developer',
636
+ description: 'Software developer',
637
+ skills: ['typescript'],
638
+ })
639
+
640
+ const team = Team({
641
+ name: 'Engineering',
642
+ members: [
643
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'available' },
644
+ ],
645
+ })
646
+
647
+ const best = findBestMemberForTask(team, ['rust'])
648
+
649
+ expect(best).toBeNull()
650
+ })
651
+
652
+ it('returns null for empty team', () => {
653
+ const team = Team({
654
+ name: 'Empty',
655
+ })
656
+
657
+ const best = findBestMemberForTask(team, ['typescript'])
658
+
659
+ expect(best).toBeNull()
660
+ })
661
+
662
+ it('considers only available members', () => {
663
+ const role = Role({
664
+ name: 'Developer',
665
+ description: 'Software developer',
666
+ skills: ['typescript'],
667
+ })
668
+
669
+ const team = Team({
670
+ name: 'Engineering',
671
+ members: [
672
+ { id: '1', name: 'Alice', type: 'human', role, status: 'active', availability: 'busy' },
673
+ { id: '2', name: 'Bob', type: 'human', role, status: 'active', availability: 'available' },
674
+ ],
675
+ })
676
+
677
+ const best = findBestMemberForTask(team, ['typescript'])
678
+
679
+ expect(best?.name).toBe('Bob')
680
+ })
681
+
682
+ it('picks member with most matching skills', () => {
683
+ const seniorRole = Role({
684
+ name: 'Senior Dev',
685
+ description: 'Senior developer',
686
+ skills: ['typescript', 'javascript', 'react', 'node'],
687
+ })
688
+
689
+ const juniorRole = Role({
690
+ name: 'Junior Dev',
691
+ description: 'Junior developer',
692
+ skills: ['javascript'],
693
+ })
694
+
695
+ const team = Team({
696
+ name: 'Engineering',
697
+ members: [
698
+ { id: '1', name: 'Junior', type: 'human', role: juniorRole, status: 'active', availability: 'available' },
699
+ { id: '2', name: 'Senior', type: 'human', role: seniorRole, status: 'active', availability: 'available' },
700
+ ],
701
+ })
702
+
703
+ const best = findBestMemberForTask(team, ['typescript', 'react'])
704
+
705
+ expect(best?.name).toBe('Senior')
706
+ })
707
+ })
708
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "outDir": "dist"
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
9
+ }