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/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
|
+
}
|