@abassey/aid 0.1.0

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 (53) hide show
  1. package/dist/agents/index.cjs +741 -0
  2. package/dist/agents/index.d.cts +78 -0
  3. package/dist/agents/index.d.ts +78 -0
  4. package/dist/agents/index.js +741 -0
  5. package/dist/ai-AWJOUXFM.js +9 -0
  6. package/dist/ai-DOAYJKKI.cjs +9 -0
  7. package/dist/chunk-2TNYBUNK.js +124 -0
  8. package/dist/chunk-3LGKZRGY.cjs +124 -0
  9. package/dist/chunk-AUR2BBB5.cjs +1436 -0
  10. package/dist/chunk-IJLTRQF4.cjs +276 -0
  11. package/dist/chunk-JPD7UBAZ.js +58 -0
  12. package/dist/chunk-M4RQALTT.js +276 -0
  13. package/dist/chunk-NB65IHJE.cjs +58 -0
  14. package/dist/chunk-YNIEOBDF.js +1436 -0
  15. package/dist/client/index.cjs +18 -0
  16. package/dist/client/index.d.cts +8 -0
  17. package/dist/client/index.d.ts +8 -0
  18. package/dist/client/index.js +18 -0
  19. package/dist/errors-CUVTnseb.d.ts +13 -0
  20. package/dist/errors-CgCce4cK.d.cts +158 -0
  21. package/dist/errors-CgCce4cK.d.ts +158 -0
  22. package/dist/errors-zAPbTlpe.d.cts +13 -0
  23. package/dist/eval/index.cjs +308 -0
  24. package/dist/eval/index.d.cts +106 -0
  25. package/dist/eval/index.d.ts +106 -0
  26. package/dist/eval/index.js +308 -0
  27. package/dist/index.cjs +35 -0
  28. package/dist/index.d.cts +107 -0
  29. package/dist/index.d.ts +107 -0
  30. package/dist/index.js +35 -0
  31. package/dist/middleware/index.cjs +201 -0
  32. package/dist/middleware/index.d.cts +36 -0
  33. package/dist/middleware/index.d.ts +36 -0
  34. package/dist/middleware/index.js +201 -0
  35. package/dist/observability/index.cjs +147 -0
  36. package/dist/observability/index.d.cts +30 -0
  37. package/dist/observability/index.d.ts +30 -0
  38. package/dist/observability/index.js +147 -0
  39. package/dist/react/index.cjs +253 -0
  40. package/dist/react/index.d.cts +64 -0
  41. package/dist/react/index.d.ts +64 -0
  42. package/dist/react/index.js +253 -0
  43. package/dist/serve/index.cjs +545 -0
  44. package/dist/serve/index.d.cts +69 -0
  45. package/dist/serve/index.d.ts +69 -0
  46. package/dist/serve/index.js +545 -0
  47. package/dist/types-BJReASS-.d.cts +196 -0
  48. package/dist/types-BJReASS-.d.ts +196 -0
  49. package/dist/types-CguX3F16.d.cts +173 -0
  50. package/dist/types-CrFH-_qp.d.cts +68 -0
  51. package/dist/types-DvdzPmW0.d.ts +173 -0
  52. package/dist/types-qfE32ADy.d.ts +68 -0
  53. package/package.json +144 -0
@@ -0,0 +1,741 @@
1
+ import {
2
+ ai,
3
+ executeToolLoop
4
+ } from "../chunk-YNIEOBDF.js";
5
+ import {
6
+ AidError
7
+ } from "../chunk-2TNYBUNK.js";
8
+
9
+ // src/tools/tool.ts
10
+ function isRichParam(value) {
11
+ return typeof value === "object" && value !== null && "description" in value;
12
+ }
13
+ function paramsToJsonSchema(params) {
14
+ const properties = {};
15
+ const required = [];
16
+ for (const [key, value] of Object.entries(params)) {
17
+ if (typeof value === "string") {
18
+ properties[key] = { type: "string", description: value };
19
+ required.push(key);
20
+ } else if (isRichParam(value)) {
21
+ const prop = {
22
+ type: value.type ?? "string",
23
+ description: value.description
24
+ };
25
+ if (value.enum) {
26
+ prop.enum = value.enum;
27
+ }
28
+ properties[key] = prop;
29
+ if (!value.optional) {
30
+ required.push(key);
31
+ }
32
+ }
33
+ }
34
+ return {
35
+ type: "object",
36
+ properties,
37
+ required
38
+ };
39
+ }
40
+ function tool(name, description, params, handler) {
41
+ return {
42
+ name,
43
+ description,
44
+ parameters: paramsToJsonSchema(params),
45
+ handler
46
+ };
47
+ }
48
+
49
+ // src/agents/events.ts
50
+ var AgentEventEmitter = class {
51
+ listeners = /* @__PURE__ */ new Map();
52
+ on(event, cb) {
53
+ if (!this.listeners.has(event)) {
54
+ this.listeners.set(event, /* @__PURE__ */ new Set());
55
+ }
56
+ this.listeners.get(event).add(cb);
57
+ }
58
+ off(event, cb) {
59
+ this.listeners.get(event)?.delete(cb);
60
+ }
61
+ emit(event, payload) {
62
+ const cbs = this.listeners.get(event);
63
+ if (cbs) {
64
+ for (const cb of cbs) {
65
+ cb(payload);
66
+ }
67
+ }
68
+ }
69
+ };
70
+
71
+ // src/agents/memory.ts
72
+ var InMemoryProvider = class {
73
+ messages = [];
74
+ maxMessages;
75
+ constructor(options) {
76
+ this.maxMessages = options?.maxMessages ?? 50;
77
+ }
78
+ async add(messages) {
79
+ this.messages.push(...messages);
80
+ if (this.messages.length > this.maxMessages) {
81
+ this.messages = this.messages.slice(-this.maxMessages);
82
+ }
83
+ }
84
+ async retrieve(_query, limit) {
85
+ if (limit !== void 0) {
86
+ return this.messages.slice(-limit);
87
+ }
88
+ return [...this.messages];
89
+ }
90
+ async clear() {
91
+ this.messages = [];
92
+ }
93
+ };
94
+
95
+ // src/agents/agent.ts
96
+ var AgentImpl = class _AgentImpl {
97
+ name;
98
+ config;
99
+ emitter = new AgentEventEmitter();
100
+ memory;
101
+ chatHistory = [];
102
+ chatInitialized = false;
103
+ aiFn;
104
+ constructor(config) {
105
+ this.name = config.name;
106
+ this.config = config;
107
+ this.aiFn = config.ai ?? ai;
108
+ if (config.memory === true) {
109
+ this.memory = new InMemoryProvider();
110
+ } else if (config.memory && typeof config.memory !== "boolean") {
111
+ this.memory = config.memory;
112
+ } else {
113
+ this.memory = null;
114
+ }
115
+ }
116
+ /**
117
+ * Core execution method. Makes an initial LLM call via aiFn WITHOUT tools
118
+ * (to prevent aiCall's internal tool loop), then runs executeToolLoop directly
119
+ * when the LLM requests tool use.
120
+ */
121
+ async executeWithToolLoop(messages) {
122
+ const tools = this.config.tools ?? [];
123
+ const maxIterations = this.config.maxIterations ?? 25;
124
+ const steps = [];
125
+ let stepCount = 0;
126
+ this.emitter.emit("step:start", { step: stepCount, iteration: 0 });
127
+ const initialResponse = await this.aiFn("", {
128
+ model: this.config.model,
129
+ system: this.config.role,
130
+ middleware: this.config.middleware,
131
+ temperature: this.config.temperature,
132
+ maxTokens: this.config.maxTokens,
133
+ _messages: messages
134
+ // NO tools — prevents aiCall's tool loop
135
+ });
136
+ steps.push({
137
+ type: "llm_call",
138
+ iteration: 0,
139
+ timestamp: Date.now(),
140
+ data: {
141
+ model: initialResponse.model,
142
+ tokens: initialResponse.tokens,
143
+ finishReason: initialResponse.finishReason
144
+ },
145
+ durationMs: initialResponse.latencyMs
146
+ });
147
+ this.emitter.emit("step:end", { step: stepCount, iteration: 0, result: initialResponse });
148
+ stepCount++;
149
+ if (tools.length === 0 || initialResponse.finishReason !== "tool_use" || !initialResponse.toolCalls || initialResponse.toolCalls.length === 0) {
150
+ return {
151
+ response: initialResponse,
152
+ allMessages: messages,
153
+ toolCalls: [],
154
+ steps,
155
+ iterations: 0
156
+ };
157
+ }
158
+ const callFn = async (request2) => {
159
+ return this.aiFn("", {
160
+ model: this.config.model,
161
+ system: this.config.role,
162
+ middleware: this.config.middleware,
163
+ temperature: this.config.temperature,
164
+ maxTokens: this.config.maxTokens,
165
+ _messages: request2.messages
166
+ // NO tools — just LLM transport
167
+ });
168
+ };
169
+ const request = {
170
+ model: initialResponse.model,
171
+ messages,
172
+ options: {
173
+ model: initialResponse.model,
174
+ temperature: this.config.temperature ?? 1,
175
+ maxTokens: this.config.maxTokens ?? 4096,
176
+ topP: 1,
177
+ stop: [],
178
+ timeout: 3e4,
179
+ tools,
180
+ middleware: this.config.middleware ?? []
181
+ },
182
+ tools: tools.map((t) => ({
183
+ name: t.name,
184
+ description: t.description,
185
+ parameters: t.parameters
186
+ }))
187
+ };
188
+ const loopResult = await executeToolLoop({
189
+ call: callFn,
190
+ request,
191
+ tools,
192
+ maxIterations,
193
+ initialResponse,
194
+ onToolCall: (tc) => {
195
+ this.emitter.emit("tool:call", { id: tc.id, name: tc.name, args: tc.args });
196
+ steps.push({
197
+ type: "tool_call",
198
+ iteration: stepCount,
199
+ timestamp: Date.now(),
200
+ data: { id: tc.id, name: tc.name, args: tc.args, result: "", isError: false },
201
+ durationMs: 0
202
+ });
203
+ },
204
+ onToolResult: (tc, result, durationMs) => {
205
+ this.emitter.emit("tool:result", { id: tc.id, name: tc.name, result, durationMs });
206
+ for (let i = steps.length - 1; i >= 0; i--) {
207
+ if (steps[i].type === "tool_call") {
208
+ steps[i].data.result = result;
209
+ steps[i].durationMs = durationMs;
210
+ break;
211
+ }
212
+ }
213
+ },
214
+ onLlmCall: (resp) => {
215
+ this.emitter.emit("step:start", { step: stepCount, iteration: stepCount });
216
+ steps.push({
217
+ type: "llm_call",
218
+ iteration: stepCount,
219
+ timestamp: Date.now(),
220
+ data: {
221
+ model: resp.model,
222
+ tokens: resp.tokens,
223
+ finishReason: resp.finishReason
224
+ },
225
+ durationMs: resp.latencyMs
226
+ });
227
+ this.emitter.emit("step:end", { step: stepCount, iteration: stepCount, result: resp });
228
+ stepCount++;
229
+ }
230
+ });
231
+ return {
232
+ response: loopResult.response,
233
+ allMessages: loopResult.messages,
234
+ toolCalls: loopResult.toolCalls,
235
+ steps,
236
+ iterations: loopResult.iterations
237
+ };
238
+ }
239
+ async run(task) {
240
+ const startTime = Date.now();
241
+ let memoryMessages = [];
242
+ if (this.memory) {
243
+ memoryMessages = await this.memory.retrieve(task);
244
+ }
245
+ const messages = [
246
+ ...memoryMessages,
247
+ { role: "user", content: task }
248
+ ];
249
+ this.emitter.emit("message", { role: "user", content: task });
250
+ let completed = true;
251
+ let error;
252
+ let execResult;
253
+ try {
254
+ execResult = await this.executeWithToolLoop(messages);
255
+ } catch (err) {
256
+ if (err instanceof AidError && err.code === "tool_loop_limit") {
257
+ completed = false;
258
+ error = new AidError("agent_loop_limit", `Agent '${this.name}' hit iteration limit`);
259
+ execResult = {
260
+ response: {
261
+ text: "",
262
+ model: this.config.model ?? "unknown",
263
+ tokens: { input: 0, output: 0, total: 0 },
264
+ cost: 0,
265
+ latencyMs: Date.now() - startTime,
266
+ finishReason: "error",
267
+ raw: err
268
+ },
269
+ allMessages: messages,
270
+ toolCalls: [],
271
+ steps: [],
272
+ iterations: 0
273
+ };
274
+ } else {
275
+ throw err;
276
+ }
277
+ }
278
+ const resultMessages = [
279
+ { role: "system", content: this.config.role },
280
+ ...execResult.allMessages
281
+ ];
282
+ if (this.memory) {
283
+ await this.memory.add([
284
+ { role: "user", content: task },
285
+ { role: "assistant", content: execResult.response.text }
286
+ ]);
287
+ }
288
+ const result = {
289
+ text: execResult.response.text,
290
+ completed,
291
+ messages: resultMessages,
292
+ steps: execResult.steps,
293
+ tokens: execResult.response.tokens,
294
+ cost: execResult.response.cost,
295
+ latencyMs: Date.now() - startTime,
296
+ toolCalls: execResult.toolCalls,
297
+ error
298
+ };
299
+ this.emitter.emit("done", { result });
300
+ return result;
301
+ }
302
+ async chat(message) {
303
+ const startTime = Date.now();
304
+ const maxChatHistory = this.config.maxChatHistory ?? 50;
305
+ if (!this.chatInitialized && this.memory) {
306
+ const memoryMessages = await this.memory.retrieve(message);
307
+ this.chatHistory.push(...memoryMessages);
308
+ this.chatInitialized = true;
309
+ }
310
+ this.chatHistory.push({ role: "user", content: message });
311
+ this.emitter.emit("message", { role: "user", content: message });
312
+ const execResult = await this.executeWithToolLoop([...this.chatHistory]);
313
+ this.chatHistory.push({ role: "assistant", content: execResult.response.text });
314
+ if (this.chatHistory.length > maxChatHistory) {
315
+ this.chatHistory = this.chatHistory.slice(-maxChatHistory);
316
+ }
317
+ if (this.memory) {
318
+ await this.memory.add([
319
+ { role: "user", content: message },
320
+ { role: "assistant", content: execResult.response.text }
321
+ ]);
322
+ }
323
+ const resultMessages = [
324
+ { role: "system", content: this.config.role },
325
+ ...this.chatHistory
326
+ ];
327
+ const result = {
328
+ text: execResult.response.text,
329
+ completed: true,
330
+ messages: resultMessages,
331
+ steps: execResult.steps,
332
+ tokens: execResult.response.tokens,
333
+ cost: execResult.response.cost,
334
+ latencyMs: Date.now() - startTime,
335
+ toolCalls: execResult.toolCalls
336
+ };
337
+ this.emitter.emit("done", { result });
338
+ return result;
339
+ }
340
+ clone(overrides) {
341
+ return new _AgentImpl({ ...this.config, ...overrides });
342
+ }
343
+ on(event, cb) {
344
+ this.emitter.on(event, cb);
345
+ }
346
+ off(event, cb) {
347
+ this.emitter.off(event, cb);
348
+ }
349
+ };
350
+ function agent(config) {
351
+ return new AgentImpl(config);
352
+ }
353
+
354
+ // src/agents/crew.ts
355
+ function aggregateTokens(results) {
356
+ return results.reduce(
357
+ (acc, r) => ({
358
+ input: acc.input + r.tokens.input,
359
+ output: acc.output + r.tokens.output,
360
+ total: acc.total + r.tokens.total
361
+ }),
362
+ { input: 0, output: 0, total: 0 }
363
+ );
364
+ }
365
+ function aggregateCost(results) {
366
+ return results.reduce((acc, r) => acc + r.cost, 0);
367
+ }
368
+ function makeErrorResult(agentName, err) {
369
+ const error = err instanceof AidError ? err : new AidError("provider_error", err instanceof Error ? err.message : String(err));
370
+ return {
371
+ text: "",
372
+ completed: false,
373
+ messages: [],
374
+ steps: [],
375
+ tokens: { input: 0, output: 0, total: 0 },
376
+ cost: 0,
377
+ latencyMs: 0,
378
+ toolCalls: [],
379
+ error
380
+ };
381
+ }
382
+ function crew(config) {
383
+ const emitter = new AgentEventEmitter();
384
+ const agentMap = /* @__PURE__ */ new Map();
385
+ for (const a of config.agents) {
386
+ agentMap.set(a.name, a);
387
+ }
388
+ function wireEvents(a) {
389
+ const events = ["step:start", "step:end", "tool:call", "tool:result", "handoff", "message", "done", "error"];
390
+ for (const event of events) {
391
+ a.on(event, (payload) => {
392
+ emitter.emit(event, { ...payload, agent: a.name });
393
+ });
394
+ }
395
+ }
396
+ for (const a of config.agents) {
397
+ wireEvents(a);
398
+ }
399
+ async function runSequential(task) {
400
+ const startTime = Date.now();
401
+ const agentResults = /* @__PURE__ */ new Map();
402
+ let previousOutput = "";
403
+ for (const a of config.agents) {
404
+ const input = previousOutput ? `Previous agent's output:
405
+ ---
406
+ ${previousOutput}
407
+ ---
408
+
409
+ Original task: ${task}` : task;
410
+ const result = await a.run(input);
411
+ agentResults.set(a.name, result);
412
+ previousOutput = result.text;
413
+ }
414
+ const allResults = [...agentResults.values()];
415
+ return {
416
+ text: previousOutput,
417
+ agentResults,
418
+ totalTokens: aggregateTokens(allResults),
419
+ totalCost: aggregateCost(allResults),
420
+ latencyMs: Date.now() - startTime
421
+ };
422
+ }
423
+ async function runParallel(task) {
424
+ const startTime = Date.now();
425
+ const agentResults = /* @__PURE__ */ new Map();
426
+ const settled = await Promise.allSettled(
427
+ config.agents.map((a) => a.run(task))
428
+ );
429
+ for (let i = 0; i < config.agents.length; i++) {
430
+ const a = config.agents[i];
431
+ const s = settled[i];
432
+ if (s.status === "fulfilled") {
433
+ agentResults.set(a.name, s.value);
434
+ } else {
435
+ agentResults.set(a.name, makeErrorResult(a.name, s.reason));
436
+ }
437
+ }
438
+ const lastAgent = config.agents[config.agents.length - 1];
439
+ const lastResult = agentResults.get(lastAgent.name);
440
+ const allResults = [...agentResults.values()];
441
+ return {
442
+ text: lastResult.text,
443
+ agentResults,
444
+ totalTokens: aggregateTokens(allResults),
445
+ totalCost: aggregateCost(allResults),
446
+ latencyMs: Date.now() - startTime
447
+ };
448
+ }
449
+ async function runConditional(task) {
450
+ const startTime = Date.now();
451
+ if (config.strategy !== "conditional") throw new Error("unreachable");
452
+ const targetName = config.router(task);
453
+ const target = agentMap.get(targetName);
454
+ if (!target) {
455
+ throw new AidError("invalid_request", `Unknown agent in crew router: '${targetName}'`);
456
+ }
457
+ const result = await target.run(task);
458
+ const agentResults = /* @__PURE__ */ new Map();
459
+ agentResults.set(targetName, result);
460
+ return {
461
+ text: result.text,
462
+ agentResults,
463
+ totalTokens: result.tokens,
464
+ totalCost: result.cost,
465
+ latencyMs: Date.now() - startTime
466
+ };
467
+ }
468
+ return {
469
+ async run(task) {
470
+ switch (config.strategy) {
471
+ case "sequential":
472
+ return runSequential(task);
473
+ case "parallel":
474
+ return runParallel(task);
475
+ case "conditional":
476
+ return runConditional(task);
477
+ }
478
+ },
479
+ on(event, cb) {
480
+ emitter.on(event, cb);
481
+ },
482
+ off(event, cb) {
483
+ emitter.off(event, cb);
484
+ }
485
+ };
486
+ }
487
+
488
+ // src/agents/workflow.ts
489
+ function workflow(config) {
490
+ const emitter = new AgentEventEmitter();
491
+ const wiredAgents = /* @__PURE__ */ new Set();
492
+ for (const step of config.steps) {
493
+ if (!wiredAgents.has(step.agent.name)) {
494
+ const events = ["step:start", "step:end", "tool:call", "tool:result", "handoff", "message", "done", "error"];
495
+ for (const event of events) {
496
+ step.agent.on(event, (payload) => {
497
+ emitter.emit(event, { ...payload, agent: step.agent.name });
498
+ });
499
+ }
500
+ wiredAgents.add(step.agent.name);
501
+ }
502
+ }
503
+ function getDependencies(step) {
504
+ if (!step.input) return [];
505
+ if (typeof step.input === "string") return [step.input];
506
+ return step.input;
507
+ }
508
+ async function run(task) {
509
+ const startTime = Date.now();
510
+ const stepResults = /* @__PURE__ */ new Map();
511
+ const skippedSteps = /* @__PURE__ */ new Set();
512
+ const failedSteps = /* @__PURE__ */ new Set();
513
+ const stepMap = /* @__PURE__ */ new Map();
514
+ for (const step of config.steps) {
515
+ stepMap.set(step.name, step);
516
+ }
517
+ const completed = /* @__PURE__ */ new Set();
518
+ const pending = new Set(config.steps.map((s) => s.name));
519
+ while (pending.size > 0) {
520
+ const ready = [];
521
+ for (const name of pending) {
522
+ const step = stepMap.get(name);
523
+ const deps = getDependencies(step);
524
+ const allDepsResolved = deps.every(
525
+ (d) => completed.has(d) || skippedSteps.has(d) || failedSteps.has(d)
526
+ );
527
+ if (allDepsResolved) {
528
+ ready.push(step);
529
+ }
530
+ }
531
+ if (ready.length === 0 && pending.size > 0) {
532
+ throw new AidError("workflow_error", "Workflow has unresolvable dependencies");
533
+ }
534
+ const results = await Promise.allSettled(
535
+ ready.map(async (step) => {
536
+ const deps = getDependencies(step);
537
+ const hasFailedDep = deps.some((d) => failedSteps.has(d));
538
+ if (hasFailedDep) {
539
+ failedSteps.add(step.name);
540
+ pending.delete(step.name);
541
+ return;
542
+ }
543
+ if (step.condition && !step.condition(stepResults)) {
544
+ skippedSteps.add(step.name);
545
+ pending.delete(step.name);
546
+ completed.add(step.name);
547
+ return;
548
+ }
549
+ let input;
550
+ if (!step.input) {
551
+ input = task;
552
+ } else if (typeof step.input === "string") {
553
+ const depResult = stepResults.get(step.input);
554
+ input = depResult ? depResult.text : task;
555
+ } else {
556
+ const parts = step.input.filter((name) => stepResults.has(name)).map((name) => `[${name} output]:
557
+ ${stepResults.get(name).text}`);
558
+ input = parts.length > 0 ? parts.join("\n\n") : task;
559
+ }
560
+ const result = await step.agent.run(input);
561
+ stepResults.set(step.name, result);
562
+ pending.delete(step.name);
563
+ completed.add(step.name);
564
+ })
565
+ );
566
+ for (let i = 0; i < ready.length; i++) {
567
+ const step = ready[i];
568
+ const r = results[i];
569
+ if (r.status === "rejected") {
570
+ failedSteps.add(step.name);
571
+ pending.delete(step.name);
572
+ }
573
+ }
574
+ const lastStepName = config.steps[config.steps.length - 1].name;
575
+ if (failedSteps.has(lastStepName)) {
576
+ throw new AidError("workflow_error", `Workflow failed: terminal step '${lastStepName}' failed`);
577
+ }
578
+ const lastStep = stepMap.get(lastStepName);
579
+ const lastDeps = getDependencies(lastStep);
580
+ if (lastDeps.some((d) => failedSteps.has(d)) && !completed.has(lastStepName)) {
581
+ throw new AidError("workflow_error", `Workflow failed: no path to terminal step '${lastStepName}'`);
582
+ }
583
+ }
584
+ let lastText = "";
585
+ for (let i = config.steps.length - 1; i >= 0; i--) {
586
+ const name = config.steps[i].name;
587
+ if (stepResults.has(name)) {
588
+ lastText = stepResults.get(name).text;
589
+ break;
590
+ }
591
+ }
592
+ const allResults = [...stepResults.values()];
593
+ return {
594
+ text: lastText,
595
+ stepResults,
596
+ totalTokens: allResults.reduce(
597
+ (acc, r) => ({
598
+ input: acc.input + r.tokens.input,
599
+ output: acc.output + r.tokens.output,
600
+ total: acc.total + r.tokens.total
601
+ }),
602
+ { input: 0, output: 0, total: 0 }
603
+ ),
604
+ totalCost: allResults.reduce((acc, r) => acc + r.cost, 0),
605
+ latencyMs: Date.now() - startTime
606
+ };
607
+ }
608
+ return {
609
+ run,
610
+ on(event, cb) {
611
+ emitter.on(event, cb);
612
+ },
613
+ off(event, cb) {
614
+ emitter.off(event, cb);
615
+ }
616
+ };
617
+ }
618
+
619
+ // src/agents/swarm.ts
620
+ var HANDOFF_SENTINEL = "__handoff_signal__";
621
+ function makeHandoffTool(agentNames) {
622
+ return {
623
+ name: "__handoff",
624
+ description: `Transfer this conversation to another agent. Available agents: ${agentNames.join(", ")}`,
625
+ parameters: {
626
+ type: "object",
627
+ properties: {
628
+ to: { type: "string", description: "Name of the agent to hand off to" },
629
+ message: { type: "string", description: "Context/reason for the handoff" }
630
+ },
631
+ required: ["to", "message"]
632
+ },
633
+ handler: async (args) => {
634
+ return `${HANDOFF_SENTINEL}:${args.to}:${args.message}`;
635
+ }
636
+ };
637
+ }
638
+ function swarm(config) {
639
+ const emitter = new AgentEventEmitter();
640
+ const maxHandoffs = config.maxHandoffs ?? 10;
641
+ const agentMap = /* @__PURE__ */ new Map();
642
+ const agentNames = config.agents.map((a) => a.name);
643
+ for (const a of config.agents) {
644
+ agentMap.set(a.name, a);
645
+ }
646
+ function wireAgentEvents(a) {
647
+ const events = ["step:start", "step:end", "tool:call", "tool:result", "message", "done", "error"];
648
+ for (const event of events) {
649
+ a.on(event, (payload) => {
650
+ emitter.emit(event, { ...payload, agent: a.name });
651
+ });
652
+ }
653
+ }
654
+ async function run(task) {
655
+ const startTime = Date.now();
656
+ const handoffChain = [];
657
+ const agentResults = /* @__PURE__ */ new Map();
658
+ let handoffCount = 0;
659
+ const entryAgent = agentMap.get(config.entry);
660
+ if (!entryAgent) {
661
+ throw new AidError("handoff_error", `Unknown entry agent: '${config.entry}'`);
662
+ }
663
+ let currentAgentName = config.entry;
664
+ let currentTask = task;
665
+ const handoffTool = makeHandoffTool(agentNames);
666
+ while (true) {
667
+ handoffChain.push(currentAgentName);
668
+ const currentAgent = agentMap.get(currentAgentName);
669
+ const agentWithHandoff = currentAgent.clone({
670
+ tools: [...currentAgent.config.tools ?? [], handoffTool]
671
+ });
672
+ wireAgentEvents(agentWithHandoff);
673
+ const result = await agentWithHandoff.run(currentTask);
674
+ agentResults.set(currentAgentName, result);
675
+ let handoffDetected = false;
676
+ let handoffTo = "";
677
+ let handoffMessage = "";
678
+ for (const tc of result.toolCalls) {
679
+ if (tc.name === "__handoff") {
680
+ handoffDetected = true;
681
+ handoffTo = tc.args.to;
682
+ handoffMessage = tc.args.message;
683
+ break;
684
+ }
685
+ }
686
+ if (!handoffDetected) {
687
+ const allResults = [...agentResults.values()];
688
+ return {
689
+ text: result.text,
690
+ handoffChain,
691
+ agentResults,
692
+ totalTokens: allResults.reduce(
693
+ (acc, r) => ({
694
+ input: acc.input + r.tokens.input,
695
+ output: acc.output + r.tokens.output,
696
+ total: acc.total + r.tokens.total
697
+ }),
698
+ { input: 0, output: 0, total: 0 }
699
+ ),
700
+ totalCost: allResults.reduce((acc, r) => acc + r.cost, 0),
701
+ latencyMs: Date.now() - startTime
702
+ };
703
+ }
704
+ handoffCount++;
705
+ if (handoffCount > maxHandoffs) {
706
+ throw new AidError("handoff_error", `Exceeded maximum handoffs (${maxHandoffs})`);
707
+ }
708
+ if (!agentMap.has(handoffTo)) {
709
+ throw new AidError("handoff_error", `Unknown agent in handoff: '${handoffTo}'`);
710
+ }
711
+ emitter.emit("handoff", {
712
+ from: currentAgentName,
713
+ to: handoffTo,
714
+ message: handoffMessage,
715
+ agent: currentAgentName
716
+ });
717
+ currentAgentName = handoffTo;
718
+ currentTask = `${task}
719
+
720
+ Context from previous agent (${result.text ? "partial response" : "handoff"}): ${handoffMessage}`;
721
+ }
722
+ }
723
+ return {
724
+ run,
725
+ on(event, cb) {
726
+ emitter.on(event, cb);
727
+ },
728
+ off(event, cb) {
729
+ emitter.off(event, cb);
730
+ }
731
+ };
732
+ }
733
+ export {
734
+ AgentEventEmitter,
735
+ InMemoryProvider,
736
+ agent,
737
+ crew,
738
+ swarm,
739
+ tool,
740
+ workflow
741
+ };