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
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Role functionality
|
|
3
|
+
*
|
|
4
|
+
* Covers role creation, predefined roles, and helper functions.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from 'vitest'
|
|
8
|
+
import {
|
|
9
|
+
Role,
|
|
10
|
+
Roles,
|
|
11
|
+
hasPermission,
|
|
12
|
+
hasSkill,
|
|
13
|
+
getPermissions,
|
|
14
|
+
getSkills,
|
|
15
|
+
mergeRoles,
|
|
16
|
+
} from '../src/index.js'
|
|
17
|
+
|
|
18
|
+
describe('Role', () => {
|
|
19
|
+
describe('Role creation', () => {
|
|
20
|
+
it('creates a role with basic config', () => {
|
|
21
|
+
const role = Role({
|
|
22
|
+
name: 'Developer',
|
|
23
|
+
description: 'Software developer',
|
|
24
|
+
skills: ['typescript', 'javascript'],
|
|
25
|
+
permissions: ['code.write', 'code.read'],
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
expect(role.name).toBe('Developer')
|
|
29
|
+
expect(role.description).toBe('Software developer')
|
|
30
|
+
expect(role.permissions).toEqual(['code.write', 'code.read'])
|
|
31
|
+
expect(role.skills).toEqual(['typescript', 'javascript'])
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('generates id from name', () => {
|
|
35
|
+
const role = Role({
|
|
36
|
+
name: 'Product Manager',
|
|
37
|
+
description: 'Manages products',
|
|
38
|
+
skills: ['strategy'],
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
expect(role.id).toBe('product-manager')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('creates a role with minimal config (skills required)', () => {
|
|
45
|
+
const role = Role({
|
|
46
|
+
name: 'Simple',
|
|
47
|
+
description: 'A simple role',
|
|
48
|
+
skills: ['general'],
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
expect(role.name).toBe('Simple')
|
|
52
|
+
expect(role.description).toBe('A simple role')
|
|
53
|
+
expect(role.permissions).toBeUndefined()
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('creates a role with outputs', () => {
|
|
57
|
+
const role = Role({
|
|
58
|
+
name: 'Writer',
|
|
59
|
+
description: 'Content writer',
|
|
60
|
+
skills: ['writing'],
|
|
61
|
+
outputs: ['blog posts', 'documentation'],
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
expect(role.outputs).toEqual(['blog posts', 'documentation'])
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('creates a role with tools', () => {
|
|
68
|
+
const role = Role({
|
|
69
|
+
name: 'Developer',
|
|
70
|
+
description: 'Software developer',
|
|
71
|
+
skills: ['coding'],
|
|
72
|
+
tools: [
|
|
73
|
+
{ name: 'runTests', description: 'Run tests', parameters: {}, handler: async () => {} },
|
|
74
|
+
],
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
expect(role.tools).toHaveLength(1)
|
|
78
|
+
expect(role.tools?.[0]?.name).toBe('runTests')
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
describe('Predefined Roles', () => {
|
|
83
|
+
it('has ProductManager role', () => {
|
|
84
|
+
const pm = Roles.ProductManager
|
|
85
|
+
|
|
86
|
+
expect(pm.name).toBe('Product Manager')
|
|
87
|
+
expect(pm.permissions).toContain('create:feature')
|
|
88
|
+
expect(pm.skills).toContain('product strategy')
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('has SoftwareEngineer role', () => {
|
|
92
|
+
const engineer = Roles.SoftwareEngineer
|
|
93
|
+
|
|
94
|
+
expect(engineer.name).toBe('Software Engineer')
|
|
95
|
+
expect(engineer.permissions).toContain('write:code')
|
|
96
|
+
expect(engineer.skills).toContain('programming')
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('has Designer role', () => {
|
|
100
|
+
const designer = Roles.Designer
|
|
101
|
+
|
|
102
|
+
expect(designer.name).toBe('Designer')
|
|
103
|
+
expect(designer.permissions).toContain('create:design')
|
|
104
|
+
expect(designer.skills).toContain('UI design')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('has DataAnalyst role', () => {
|
|
108
|
+
const analyst = Roles.DataAnalyst
|
|
109
|
+
|
|
110
|
+
expect(analyst.name).toBe('Data Analyst')
|
|
111
|
+
expect(analyst.permissions).toContain('read:analytics')
|
|
112
|
+
expect(analyst.skills).toContain('data analysis')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('has ContentWriter role', () => {
|
|
116
|
+
const writer = Roles.ContentWriter
|
|
117
|
+
|
|
118
|
+
expect(writer.name).toBe('Content Writer')
|
|
119
|
+
expect(writer.permissions).toContain('create:content')
|
|
120
|
+
expect(writer.skills).toContain('writing')
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('has CustomerSupport role', () => {
|
|
124
|
+
const support = Roles.CustomerSupport
|
|
125
|
+
|
|
126
|
+
expect(support.name).toBe('Customer Support')
|
|
127
|
+
expect(support.permissions).toContain('read:tickets')
|
|
128
|
+
expect(support.skills).toContain('customer service')
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it('has ProjectManager role', () => {
|
|
132
|
+
const manager = Roles.ProjectManager
|
|
133
|
+
|
|
134
|
+
expect(manager.name).toBe('Project Manager')
|
|
135
|
+
expect(manager.permissions).toContain('create:project')
|
|
136
|
+
expect(manager.skills).toContain('project planning')
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('has QAEngineer role', () => {
|
|
140
|
+
const qa = Roles.QAEngineer
|
|
141
|
+
|
|
142
|
+
expect(qa.name).toBe('QA Engineer')
|
|
143
|
+
expect(qa.permissions).toContain('run:tests')
|
|
144
|
+
expect(qa.skills).toContain('manual testing')
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('has MarketingManager role', () => {
|
|
148
|
+
const marketing = Roles.MarketingManager
|
|
149
|
+
|
|
150
|
+
expect(marketing.name).toBe('Marketing Manager')
|
|
151
|
+
expect(marketing.permissions).toContain('create:campaign')
|
|
152
|
+
expect(marketing.skills).toContain('marketing strategy')
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('has DevOpsEngineer role', () => {
|
|
156
|
+
const devops = Roles.DevOpsEngineer
|
|
157
|
+
|
|
158
|
+
expect(devops.name).toBe('DevOps Engineer')
|
|
159
|
+
expect(devops.permissions).toContain('deploy:production')
|
|
160
|
+
expect(devops.skills).toContain('infrastructure management')
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
describe('hasPermission', () => {
|
|
165
|
+
it('returns true when role has permission', () => {
|
|
166
|
+
const role = Role({
|
|
167
|
+
name: 'Test',
|
|
168
|
+
description: 'Test role',
|
|
169
|
+
skills: ['testing'],
|
|
170
|
+
permissions: ['read', 'write', 'admin'],
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
expect(hasPermission(role, 'read')).toBe(true)
|
|
174
|
+
expect(hasPermission(role, 'write')).toBe(true)
|
|
175
|
+
expect(hasPermission(role, 'admin')).toBe(true)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('returns false when role does not have permission', () => {
|
|
179
|
+
const role = Role({
|
|
180
|
+
name: 'Test',
|
|
181
|
+
description: 'Test role',
|
|
182
|
+
skills: ['testing'],
|
|
183
|
+
permissions: ['read'],
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
expect(hasPermission(role, 'write')).toBe(false)
|
|
187
|
+
expect(hasPermission(role, 'admin')).toBe(false)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('returns false when role has no permissions', () => {
|
|
191
|
+
const role = Role({
|
|
192
|
+
name: 'Test',
|
|
193
|
+
description: 'Test role',
|
|
194
|
+
skills: ['testing'],
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
expect(hasPermission(role, 'read')).toBe(false)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('handles empty permissions array', () => {
|
|
201
|
+
const role = Role({
|
|
202
|
+
name: 'Test',
|
|
203
|
+
description: 'Test role',
|
|
204
|
+
skills: ['testing'],
|
|
205
|
+
permissions: [],
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
expect(hasPermission(role, 'read')).toBe(false)
|
|
209
|
+
})
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
describe('hasSkill', () => {
|
|
213
|
+
it('returns true when role has skill', () => {
|
|
214
|
+
const role = Role({
|
|
215
|
+
name: 'Test',
|
|
216
|
+
description: 'Test role',
|
|
217
|
+
skills: ['typescript', 'javascript', 'python'],
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
expect(hasSkill(role, 'typescript')).toBe(true)
|
|
221
|
+
expect(hasSkill(role, 'javascript')).toBe(true)
|
|
222
|
+
expect(hasSkill(role, 'python')).toBe(true)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('returns false when role does not have skill', () => {
|
|
226
|
+
const role = Role({
|
|
227
|
+
name: 'Test',
|
|
228
|
+
description: 'Test role',
|
|
229
|
+
skills: ['typescript'],
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
expect(hasSkill(role, 'rust')).toBe(false)
|
|
233
|
+
expect(hasSkill(role, 'go')).toBe(false)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('performs case-insensitive skill matching', () => {
|
|
237
|
+
const role = Role({
|
|
238
|
+
name: 'Test',
|
|
239
|
+
description: 'Test role',
|
|
240
|
+
skills: ['TypeScript', 'JavaScript'],
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
expect(hasSkill(role, 'typescript')).toBe(true)
|
|
244
|
+
expect(hasSkill(role, 'JAVASCRIPT')).toBe(true)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('performs partial skill matching', () => {
|
|
248
|
+
const role = Role({
|
|
249
|
+
name: 'Test',
|
|
250
|
+
description: 'Test role',
|
|
251
|
+
skills: ['software design', 'system architecture'],
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
expect(hasSkill(role, 'design')).toBe(true)
|
|
255
|
+
expect(hasSkill(role, 'architecture')).toBe(true)
|
|
256
|
+
})
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
describe('getPermissions', () => {
|
|
260
|
+
it('returns all permissions from a role', () => {
|
|
261
|
+
const role = Role({
|
|
262
|
+
name: 'Test',
|
|
263
|
+
description: 'Test role',
|
|
264
|
+
skills: ['testing'],
|
|
265
|
+
permissions: ['read', 'write', 'admin'],
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
expect(getPermissions(role)).toEqual(['read', 'write', 'admin'])
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('returns empty array when no permissions', () => {
|
|
272
|
+
const role = Role({
|
|
273
|
+
name: 'Test',
|
|
274
|
+
description: 'Test role',
|
|
275
|
+
skills: ['testing'],
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
expect(getPermissions(role)).toEqual([])
|
|
279
|
+
})
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
describe('getSkills', () => {
|
|
283
|
+
it('returns all skills from a role', () => {
|
|
284
|
+
const role = Role({
|
|
285
|
+
name: 'Test',
|
|
286
|
+
description: 'Test role',
|
|
287
|
+
skills: ['typescript', 'javascript'],
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
expect(getSkills(role)).toEqual(['typescript', 'javascript'])
|
|
291
|
+
})
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
describe('mergeRoles', () => {
|
|
295
|
+
it('merges two roles with no overlap', () => {
|
|
296
|
+
const role1 = Role({
|
|
297
|
+
name: 'Role1',
|
|
298
|
+
description: 'First role',
|
|
299
|
+
skills: ['typescript'],
|
|
300
|
+
permissions: ['read'],
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
const role2 = Role({
|
|
304
|
+
name: 'Role2',
|
|
305
|
+
description: 'Second role',
|
|
306
|
+
skills: ['javascript'],
|
|
307
|
+
permissions: ['write'],
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
const merged = mergeRoles('Combined Role', role1, role2)
|
|
311
|
+
|
|
312
|
+
expect(merged.name).toBe('Combined Role')
|
|
313
|
+
expect(merged.permissions).toContain('read')
|
|
314
|
+
expect(merged.permissions).toContain('write')
|
|
315
|
+
expect(merged.skills).toContain('typescript')
|
|
316
|
+
expect(merged.skills).toContain('javascript')
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
it('deduplicates permissions and skills', () => {
|
|
320
|
+
const role1 = Role({
|
|
321
|
+
name: 'Role1',
|
|
322
|
+
description: 'First role',
|
|
323
|
+
skills: ['typescript', 'javascript'],
|
|
324
|
+
permissions: ['read', 'write'],
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
const role2 = Role({
|
|
328
|
+
name: 'Role2',
|
|
329
|
+
description: 'Second role',
|
|
330
|
+
skills: ['javascript', 'python'],
|
|
331
|
+
permissions: ['write', 'admin'],
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
const merged = mergeRoles('Combined', role1, role2)
|
|
335
|
+
|
|
336
|
+
expect(merged.permissions).toHaveLength(3)
|
|
337
|
+
expect(merged.skills).toHaveLength(3)
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
it('merges roles with empty arrays', () => {
|
|
341
|
+
const role1 = Role({
|
|
342
|
+
name: 'Role1',
|
|
343
|
+
description: 'First role',
|
|
344
|
+
skills: [],
|
|
345
|
+
permissions: [],
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
const role2 = Role({
|
|
349
|
+
name: 'Role2',
|
|
350
|
+
description: 'Second role',
|
|
351
|
+
skills: ['typescript'],
|
|
352
|
+
permissions: ['read'],
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
const merged = mergeRoles('Combined', role1, role2)
|
|
356
|
+
|
|
357
|
+
expect(merged.permissions).toEqual(['read'])
|
|
358
|
+
expect(merged.skills).toEqual(['typescript'])
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
it('merges roles with undefined permissions', () => {
|
|
362
|
+
const role1 = Role({
|
|
363
|
+
name: 'Role1',
|
|
364
|
+
description: 'First role',
|
|
365
|
+
skills: ['skill1'],
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
const role2 = Role({
|
|
369
|
+
name: 'Role2',
|
|
370
|
+
description: 'Second role',
|
|
371
|
+
skills: ['skill2'],
|
|
372
|
+
permissions: ['read'],
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
const merged = mergeRoles('Combined', role1, role2)
|
|
376
|
+
|
|
377
|
+
expect(merged.permissions).toEqual(['read'])
|
|
378
|
+
expect(merged.skills).toHaveLength(2)
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
it('merges outputs', () => {
|
|
382
|
+
const role1 = Role({
|
|
383
|
+
name: 'Role1',
|
|
384
|
+
description: 'First role',
|
|
385
|
+
skills: ['skill1'],
|
|
386
|
+
outputs: ['output1'],
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
const role2 = Role({
|
|
390
|
+
name: 'Role2',
|
|
391
|
+
description: 'Second role',
|
|
392
|
+
skills: ['skill2'],
|
|
393
|
+
outputs: ['output1', 'output2'],
|
|
394
|
+
})
|
|
395
|
+
|
|
396
|
+
const merged = mergeRoles('Combined', role1, role2)
|
|
397
|
+
|
|
398
|
+
expect(merged.outputs).toContain('output1')
|
|
399
|
+
expect(merged.outputs).toContain('output2')
|
|
400
|
+
// Deduplicated
|
|
401
|
+
expect(merged.outputs).toHaveLength(2)
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
it('combines descriptions', () => {
|
|
405
|
+
const role1 = Role({
|
|
406
|
+
name: 'Role1',
|
|
407
|
+
description: 'First description',
|
|
408
|
+
skills: ['skill1'],
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
const role2 = Role({
|
|
412
|
+
name: 'Role2',
|
|
413
|
+
description: 'Second description',
|
|
414
|
+
skills: ['skill2'],
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
const merged = mergeRoles('Combined', role1, role2)
|
|
418
|
+
|
|
419
|
+
expect(merged.description).toContain('First description')
|
|
420
|
+
expect(merged.description).toContain('Second description')
|
|
421
|
+
})
|
|
422
|
+
})
|
|
423
|
+
})
|