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
package/src/agent.ts ADDED
@@ -0,0 +1,548 @@
1
+ /**
2
+ * Agent - Create an autonomous agent
3
+ *
4
+ * Agents are autonomous AI workers that can execute tasks, make decisions,
5
+ * and collaborate with other agents and humans.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ import { generateObject, type AIGenerateOptions, type SimpleSchema } from 'ai-functions'
11
+ import type {
12
+ Agent,
13
+ AgentConfig,
14
+ AgentStatus,
15
+ AgentHistoryEntry,
16
+ ApprovalRequest,
17
+ ApprovalResult,
18
+ ApprovalStatus,
19
+ } from './types.js'
20
+ import { executeApproval } from './actions.js'
21
+
22
+ /**
23
+ * Create an autonomous agent
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { Agent, Role } from 'autonomous-agents'
28
+ *
29
+ * const agent = Agent({
30
+ * name: 'ProductAgent',
31
+ * role: Role({
32
+ * name: 'Product Manager',
33
+ * description: 'Manages product strategy and roadmap',
34
+ * skills: ['product strategy', 'user research', 'roadmap planning'],
35
+ * }),
36
+ * mode: 'autonomous',
37
+ * goals: [
38
+ * { id: 'g1', description: 'Define Q1 product roadmap', target: '100%' }
39
+ * ],
40
+ * })
41
+ *
42
+ * // Execute a task
43
+ * const result = await agent.do('Create a product brief for new feature X')
44
+ *
45
+ * // Ask a question
46
+ * const answer = await agent.ask('What are the top 3 customer pain points?')
47
+ *
48
+ * // Make a decision
49
+ * const decision = await agent.decide(['feature A', 'feature B', 'feature C'], 'Which should we prioritize?')
50
+ *
51
+ * // Request approval
52
+ * const approval = await agent.approve({
53
+ * title: 'Budget Request',
54
+ * description: 'Request $50k budget for user research',
55
+ * data: { amount: 50000, purpose: 'User research study' },
56
+ * approver: 'manager@company.com',
57
+ * })
58
+ * ```
59
+ */
60
+ export function Agent(config: AgentConfig): Agent {
61
+ // Initialize agent state
62
+ const state: Record<string, unknown> = config.context || {}
63
+ let status: AgentStatus = 'idle'
64
+ const history: AgentHistoryEntry[] = []
65
+
66
+ // Default model and parameters
67
+ const model = config.model || 'sonnet'
68
+ const temperature = config.temperature ?? 0.7
69
+ const maxIterations = config.maxIterations || 10
70
+
71
+ /**
72
+ * Record action in history
73
+ */
74
+ function recordHistory(entry: Omit<AgentHistoryEntry, 'timestamp'>): void {
75
+ history.push({
76
+ ...entry,
77
+ timestamp: new Date(),
78
+ })
79
+ }
80
+
81
+ /**
82
+ * Execute a task
83
+ */
84
+ async function doTask<TResult = unknown>(
85
+ task: string,
86
+ context?: unknown
87
+ ): Promise<TResult> {
88
+ const startTime = Date.now()
89
+ status = 'thinking'
90
+
91
+ try {
92
+ // Build system prompt with role and goals
93
+ const systemPrompt = buildSystemPrompt(config)
94
+
95
+ // For autonomous mode, use agentic loop
96
+ if (config.mode === 'autonomous') {
97
+ const result = await executeAgenticTask<TResult>(
98
+ task,
99
+ context,
100
+ systemPrompt,
101
+ config.tools || [],
102
+ maxIterations
103
+ )
104
+
105
+ recordHistory({
106
+ type: 'task',
107
+ action: task,
108
+ input: context,
109
+ output: result,
110
+ duration: Date.now() - startTime,
111
+ })
112
+
113
+ status = 'completed'
114
+ return result
115
+ }
116
+
117
+ // For supervised/manual mode, generate response with optional approval
118
+ const result = await generateObject({
119
+ model,
120
+ schema: {
121
+ result: 'The result of the task',
122
+ reasoning: 'Step-by-step reasoning',
123
+ needsApproval: 'Whether this needs approval (boolean)',
124
+ },
125
+ system: systemPrompt,
126
+ prompt: `Task: ${task}\n\nContext: ${JSON.stringify(context || {})}`,
127
+ temperature,
128
+ })
129
+
130
+ const response = result.object as unknown as {
131
+ result: unknown
132
+ reasoning: string
133
+ needsApproval: boolean
134
+ }
135
+
136
+ // Request approval if needed and agent requires approval
137
+ if (config.requiresApproval || response.needsApproval) {
138
+ const approval = await executeApproval({
139
+ title: `Task: ${task}`,
140
+ description: response.reasoning,
141
+ data: response.result,
142
+ approver: config.supervisor,
143
+ channel: 'web',
144
+ })
145
+
146
+ if (approval.status !== 'approved') {
147
+ throw new Error(`Task approval ${approval.status}: ${approval.notes || ''}`)
148
+ }
149
+ }
150
+
151
+ recordHistory({
152
+ type: 'task',
153
+ action: task,
154
+ input: context,
155
+ output: response.result,
156
+ duration: Date.now() - startTime,
157
+ })
158
+
159
+ status = 'completed'
160
+ return response.result as TResult
161
+ } catch (error) {
162
+ status = 'error'
163
+ recordHistory({
164
+ type: 'error',
165
+ action: task,
166
+ input: context,
167
+ error: error instanceof Error ? error.message : String(error),
168
+ duration: Date.now() - startTime,
169
+ })
170
+ throw error
171
+ } finally {
172
+ if (status !== 'error') {
173
+ status = 'idle'
174
+ }
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Ask a question
180
+ */
181
+ async function ask<TResult = unknown>(
182
+ question: string,
183
+ context?: unknown
184
+ ): Promise<TResult> {
185
+ const startTime = Date.now()
186
+ status = 'thinking'
187
+
188
+ try {
189
+ const systemPrompt = buildSystemPrompt(config)
190
+
191
+ const result = await generateObject({
192
+ model,
193
+ schema: {
194
+ answer: 'The answer to the question',
195
+ reasoning: 'Supporting reasoning and evidence',
196
+ },
197
+ system: systemPrompt,
198
+ prompt: `Question: ${question}\n\nContext: ${JSON.stringify(context || {})}`,
199
+ temperature,
200
+ })
201
+
202
+ const response = result.object as { answer: unknown; reasoning: string }
203
+
204
+ recordHistory({
205
+ type: 'question',
206
+ action: question,
207
+ input: context,
208
+ output: response.answer,
209
+ duration: Date.now() - startTime,
210
+ })
211
+
212
+ status = 'idle'
213
+ return response.answer as TResult
214
+ } catch (error) {
215
+ status = 'error'
216
+ recordHistory({
217
+ type: 'error',
218
+ action: question,
219
+ input: context,
220
+ error: error instanceof Error ? error.message : String(error),
221
+ duration: Date.now() - startTime,
222
+ })
223
+ throw error
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Make a decision
229
+ */
230
+ async function decide<T extends string>(
231
+ options: T[],
232
+ context?: string
233
+ ): Promise<T> {
234
+ const startTime = Date.now()
235
+ status = 'thinking'
236
+
237
+ try {
238
+ const systemPrompt = buildSystemPrompt(config)
239
+
240
+ const result = await generateObject({
241
+ model,
242
+ schema: {
243
+ decision: options.join(' | '),
244
+ reasoning: 'Reasoning for this decision',
245
+ confidence: 'Confidence level 0-100 (number)',
246
+ },
247
+ system: systemPrompt,
248
+ prompt: `Make a decision between these options:\n${options.map((o, i) => `${i + 1}. ${o}`).join('\n')}\n\nContext: ${context || 'No additional context'}`,
249
+ temperature,
250
+ })
251
+
252
+ const response = result.object as unknown as {
253
+ decision: T
254
+ reasoning: string
255
+ confidence: number
256
+ }
257
+
258
+ recordHistory({
259
+ type: 'decision',
260
+ action: `Choose from: ${options.join(', ')}`,
261
+ input: context,
262
+ output: response,
263
+ duration: Date.now() - startTime,
264
+ })
265
+
266
+ status = 'idle'
267
+ return response.decision
268
+ } catch (error) {
269
+ status = 'error'
270
+ recordHistory({
271
+ type: 'error',
272
+ action: 'decision',
273
+ input: { options, context },
274
+ error: error instanceof Error ? error.message : String(error),
275
+ duration: Date.now() - startTime,
276
+ })
277
+ throw error
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Request approval
283
+ */
284
+ async function approve<TResult = unknown>(
285
+ request: ApprovalRequest
286
+ ): Promise<ApprovalResult<TResult>> {
287
+ const startTime = Date.now()
288
+ status = 'waiting'
289
+
290
+ try {
291
+ const result = await executeApproval(request)
292
+
293
+ recordHistory({
294
+ type: 'approval',
295
+ action: request.title,
296
+ input: request,
297
+ output: result,
298
+ duration: Date.now() - startTime,
299
+ })
300
+
301
+ status = 'idle'
302
+ return result as ApprovalResult<TResult>
303
+ } catch (error) {
304
+ status = 'error'
305
+ recordHistory({
306
+ type: 'error',
307
+ action: request.title,
308
+ input: request,
309
+ error: error instanceof Error ? error.message : String(error),
310
+ duration: Date.now() - startTime,
311
+ })
312
+ throw error
313
+ }
314
+ }
315
+
316
+ /**
317
+ * Generate content
318
+ */
319
+ async function generate(options: AIGenerateOptions): Promise<unknown> {
320
+ const startTime = Date.now()
321
+ status = 'acting'
322
+
323
+ try {
324
+ const systemPrompt = buildSystemPrompt(config)
325
+
326
+ const result = await generateObject({
327
+ model: options.model || model,
328
+ schema: options.schema || { result: 'Generated content' },
329
+ system: options.system || systemPrompt,
330
+ prompt: options.prompt || '',
331
+ temperature: options.temperature ?? temperature,
332
+ })
333
+
334
+ recordHistory({
335
+ type: 'task',
336
+ action: 'generate',
337
+ input: options,
338
+ output: result.object,
339
+ duration: Date.now() - startTime,
340
+ })
341
+
342
+ status = 'idle'
343
+ return result.object
344
+ } catch (error) {
345
+ status = 'error'
346
+ recordHistory({
347
+ type: 'error',
348
+ action: 'generate',
349
+ input: options,
350
+ error: error instanceof Error ? error.message : String(error),
351
+ duration: Date.now() - startTime,
352
+ })
353
+ throw error
354
+ }
355
+ }
356
+
357
+ /**
358
+ * Type checking/validation
359
+ */
360
+ async function is(value: unknown, type: string | SimpleSchema): Promise<boolean> {
361
+ try {
362
+ const schema = typeof type === 'string'
363
+ ? { isValid: `Is this value a valid ${type}? (boolean)` }
364
+ : { isValid: 'Does this value match the schema? (boolean)' }
365
+
366
+ const result = await generateObject({
367
+ model,
368
+ schema,
369
+ system: 'You are a type validator. Determine if the value matches the expected type.',
370
+ prompt: `Value: ${JSON.stringify(value)}\n\nExpected type: ${typeof type === 'string' ? type : JSON.stringify(type)}`,
371
+ temperature: 0,
372
+ })
373
+
374
+ return (result.object as unknown as { isValid: boolean }).isValid
375
+ } catch {
376
+ return false
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Send notification
382
+ */
383
+ async function notify(message: string, channel?: string): Promise<void> {
384
+ const startTime = Date.now()
385
+
386
+ try {
387
+ // In a real implementation, this would send via the specified channel
388
+ recordHistory({
389
+ type: 'notification',
390
+ action: 'notify',
391
+ input: { message, channel },
392
+ duration: Date.now() - startTime,
393
+ })
394
+
395
+ // For now, just log
396
+ console.log(`[${config.name}] ${message}`)
397
+ } catch (error) {
398
+ recordHistory({
399
+ type: 'error',
400
+ action: 'notify',
401
+ input: { message, channel },
402
+ error: error instanceof Error ? error.message : String(error),
403
+ duration: Date.now() - startTime,
404
+ })
405
+ throw error
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Update agent state
411
+ */
412
+ function setState(key: string, value: unknown): void {
413
+ state[key] = value
414
+ }
415
+
416
+ /**
417
+ * Get agent state
418
+ */
419
+ function getState<T = unknown>(key: string): T | undefined {
420
+ return state[key] as T | undefined
421
+ }
422
+
423
+ /**
424
+ * Get agent history
425
+ */
426
+ function getHistory(): AgentHistoryEntry[] {
427
+ return [...history]
428
+ }
429
+
430
+ /**
431
+ * Reset agent state
432
+ */
433
+ function reset(): void {
434
+ Object.keys(state).forEach(key => delete state[key])
435
+ history.length = 0
436
+ status = 'idle'
437
+ }
438
+
439
+ return {
440
+ config,
441
+ status,
442
+ state,
443
+ do: doTask,
444
+ ask,
445
+ decide,
446
+ approve,
447
+ generate,
448
+ is,
449
+ notify,
450
+ setState,
451
+ getState,
452
+ getHistory,
453
+ reset,
454
+ }
455
+ }
456
+
457
+ /**
458
+ * Build system prompt from agent configuration
459
+ */
460
+ function buildSystemPrompt(config: AgentConfig): string {
461
+ const parts: string[] = []
462
+
463
+ parts.push(`You are ${config.name}, an autonomous AI agent.`)
464
+
465
+ if (config.description) {
466
+ parts.push(config.description)
467
+ }
468
+
469
+ if (config.role) {
470
+ parts.push(`\nRole: ${config.role.name}`)
471
+ parts.push(config.role.description)
472
+
473
+ if (config.role.skills.length > 0) {
474
+ parts.push(`\nSkills: ${config.role.skills.join(', ')}`)
475
+ }
476
+ }
477
+
478
+ if (config.goals && config.goals.length > 0) {
479
+ parts.push('\nGoals:')
480
+ config.goals.forEach((goal, i) => {
481
+ parts.push(`${i + 1}. ${goal.description}`)
482
+ })
483
+ }
484
+
485
+ if (config.system) {
486
+ parts.push(`\n${config.system}`)
487
+ }
488
+
489
+ return parts.join('\n')
490
+ }
491
+
492
+ /**
493
+ * Execute an agentic task with tool use
494
+ */
495
+ async function executeAgenticTask<TResult>(
496
+ task: string,
497
+ context: unknown,
498
+ systemPrompt: string,
499
+ tools: import('ai-functions').AIFunctionDefinition[],
500
+ maxIterations: number
501
+ ): Promise<TResult> {
502
+ let iteration = 0
503
+ const toolResults: unknown[] = []
504
+
505
+ while (iteration < maxIterations) {
506
+ iteration++
507
+
508
+ const result = await generateObject({
509
+ model: 'sonnet',
510
+ schema: {
511
+ thinking: 'Your step-by-step reasoning',
512
+ action: {
513
+ type: 'tool | done',
514
+ toolName: 'Name of tool to use (if action is tool)',
515
+ arguments: 'Arguments for the tool as JSON string',
516
+ },
517
+ result: 'The final result if done',
518
+ },
519
+ system: systemPrompt,
520
+ prompt: `Task: ${task}\n\nContext: ${JSON.stringify(context)}\n\nPrevious actions:\n${toolResults.map((r, i) => `${i + 1}. ${JSON.stringify(r)}`).join('\n') || 'None yet'}\n\nWhat should you do next?`,
521
+ })
522
+
523
+ const response = result.object as {
524
+ thinking: string
525
+ action: { type: string; toolName?: string; arguments?: string }
526
+ result?: unknown
527
+ }
528
+
529
+ // Check if done
530
+ if (response.action.type === 'done' || response.result) {
531
+ return response.result as TResult
532
+ }
533
+
534
+ // Execute tool
535
+ if (response.action.type === 'tool' && response.action.toolName) {
536
+ const tool = tools.find(t => t.name === response.action.toolName)
537
+ if (tool) {
538
+ const args = JSON.parse(response.action.arguments || '{}')
539
+ const toolResult = await tool.handler(args)
540
+ toolResults.push({ tool: response.action.toolName, result: toolResult })
541
+ } else {
542
+ toolResults.push({ error: `Tool not found: ${response.action.toolName}` })
543
+ }
544
+ }
545
+ }
546
+
547
+ throw new Error(`Agent exceeded maximum iterations (${maxIterations})`)
548
+ }