@statelyai/agent 2.0.0-next.0 → 2.0.0-next.2

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/.changeset/cyan-carpets-perform.md +5 -0
  2. package/.changeset/fast-donkeys-argue.md +5 -0
  3. package/.changeset/grumpy-dolphins-think.md +17 -0
  4. package/.changeset/old-jobs-check.md +5 -0
  5. package/.changeset/old-teachers-tap.md +5 -0
  6. package/.changeset/pre.json +7 -1
  7. package/.changeset/smart-yaks-pull.md +23 -0
  8. package/CHANGELOG.md +52 -0
  9. package/dist/index.d.mts +69 -66
  10. package/dist/index.d.ts +69 -66
  11. package/dist/index.js +111 -79
  12. package/dist/index.mjs +114 -82
  13. package/examples/chatbot-alt.ts +1 -1
  14. package/examples/chatbot.ts +3 -3
  15. package/examples/cot.ts +7 -25
  16. package/examples/customer-service-sim.ts +7 -7
  17. package/examples/email.ts +37 -35
  18. package/examples/example.ts +3 -3
  19. package/examples/goal.ts +3 -3
  20. package/examples/joke.ts +3 -3
  21. package/examples/jugs.ts +5 -8
  22. package/examples/learn-from-feedback.ts +100 -0
  23. package/examples/multi.ts +1 -1
  24. package/examples/number.ts +3 -3
  25. package/examples/raffle.ts +3 -3
  26. package/examples/river-crossing.ts +5 -8
  27. package/examples/simple.ts +14 -11
  28. package/examples/summary.ts +3 -6
  29. package/examples/support.ts +43 -39
  30. package/examples/ticTacToe.ts +48 -6
  31. package/examples/todo.ts +3 -3
  32. package/examples/tutor.ts +4 -4
  33. package/examples/verify.ts +3 -3
  34. package/examples/weather-agent.ts +141 -0
  35. package/examples/weather.ts +24 -24
  36. package/examples/wiki.ts +1 -1
  37. package/examples/word.ts +9 -7
  38. package/package.json +6 -3
  39. package/src/agent.test.ts +161 -19
  40. package/src/agent.ts +66 -250
  41. package/src/decide.test.ts +172 -3
  42. package/src/decide.ts +50 -30
  43. package/src/middleware.ts +2 -14
  44. package/src/strategies/chainOfThought.ts +48 -0
  45. package/src/strategies/shortestPath.test.ts +91 -0
  46. package/src/{planners/shortestPathPlanner.ts → strategies/shortestPath.ts} +32 -19
  47. package/src/{planners/simplePlanner.ts → strategies/simple.ts} +28 -24
  48. package/src/types.ts +75 -34
  49. package/src/utils.ts +23 -0
  50. package/vitest.config.ts +9 -3
  51. package/src/strategies/chain-of-note.ts +0 -106
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ module.exports = __toCommonJS(src_exports);
40
40
  // src/agent.ts
41
41
  var import_xstate4 = require("xstate");
42
42
 
43
- // src/planners/simplePlanner.ts
43
+ // src/strategies/simple.ts
44
44
  var import_ai3 = require("ai");
45
45
 
46
46
  // src/utils.ts
@@ -79,6 +79,15 @@ function getAllMachineTransitions(stateNode) {
79
79
  function wrapInXml(tagName, content) {
80
80
  return `<${tagName}>${content}</${tagName}>`;
81
81
  }
82
+ function convertToXml(obj) {
83
+ return Object.entries(obj).map(([key, value]) => {
84
+ if (typeof value === "object" && value !== null) {
85
+ return wrapInXml(key, convertToXml(value));
86
+ } else {
87
+ return wrapInXml(key, value);
88
+ }
89
+ }).join("");
90
+ }
82
91
  function randomId(prefix) {
83
92
  const timestamp = Date.now().toString(36);
84
93
  const random = Math.random().toString(36).substring(2, 9);
@@ -106,10 +115,16 @@ function getTransitions(state, machine) {
106
115
  });
107
116
  return getAllTransitions(resolvedState);
108
117
  }
118
+ function isMachineActor(actor) {
119
+ return "src" in actor && typeof actor.src === "object" && actor.src !== null && "definition" in actor.src;
120
+ }
109
121
 
110
- // src/planners/simplePlanner.ts
122
+ // src/strategies/simple.ts
111
123
  var import_xstate3 = require("xstate");
112
124
 
125
+ // src/text.ts
126
+ var import_ai = require("ai");
127
+
113
128
  // src/templates/defaultText.ts
114
129
  var defaultTextTemplate = (data) => {
115
130
  const preamble = [
@@ -123,7 +138,6 @@ ${data.goal}
123
138
  };
124
139
 
125
140
  // src/text.ts
126
- var import_ai = require("ai");
127
141
  var import_xstate = require("xstate");
128
142
  async function getMessages(agent, prompt, options) {
129
143
  let messages = [];
@@ -212,27 +226,42 @@ async function agentDecide(agent, options) {
212
226
  ...options
213
227
  };
214
228
  const {
215
- planner = simplePlanner,
229
+ strategy = agent.strategy,
216
230
  goal,
231
+ allowedEvents,
217
232
  events = agent.events,
218
233
  state,
219
234
  machine,
220
235
  model = agent.model,
221
- ...otherPlanInput
236
+ messages,
237
+ ...otherDecideInput
222
238
  } = resolvedOptions;
223
- const plan = await planner(agent, {
224
- model,
225
- goal,
226
- events,
227
- state,
228
- machine,
229
- ...otherPlanInput
230
- });
231
- if (plan?.nextEvent) {
232
- agent.addPlan(plan);
233
- await resolvedOptions.execute?.(plan.nextEvent);
239
+ const filteredEventSchemas = allowedEvents ? Object.fromEntries(
240
+ Object.entries(events).filter(([key]) => {
241
+ return allowedEvents.includes(key);
242
+ })
243
+ ) : events;
244
+ let attempts = 0;
245
+ const maxAttempts = resolvedOptions.maxAttempts ?? 2;
246
+ let decision;
247
+ while (attempts++ < maxAttempts) {
248
+ decision = await strategy(agent, {
249
+ model,
250
+ goal,
251
+ events: filteredEventSchemas,
252
+ state,
253
+ machine,
254
+ messages,
255
+ // TODO: fix UIMessage thing
256
+ ...otherDecideInput
257
+ });
258
+ if (decision?.nextEvent) {
259
+ agent.addDecision(decision);
260
+ await resolvedOptions.execute?.(decision.nextEvent);
261
+ break;
262
+ }
234
263
  }
235
- return plan;
264
+ return decision;
236
265
  }
237
266
  function fromDecision(agent, defaultInput) {
238
267
  return (0, import_xstate2.fromPromise)(async ({ input, self }) => {
@@ -250,15 +279,18 @@ function fromDecision(agent, defaultInput) {
250
279
  value: snapshot.value,
251
280
  context: resolvedInput.context
252
281
  };
253
- const plan = await agentDecide(agent, {
282
+ const decision = await agentDecide(agent, {
254
283
  machine: parentRef.logic,
255
- state,
284
+ state: snapshot,
285
+ context: resolvedInput.context,
256
286
  execute: async (event) => {
257
287
  parentRef.send(event);
258
288
  },
259
- ...resolvedInput
289
+ ...resolvedInput,
290
+ // @ts-ignore
291
+ messages: resolvedInput.messages
260
292
  });
261
- return plan;
293
+ return decision;
262
294
  });
263
295
  }
264
296
  function getToolMap(_agent, input) {
@@ -304,46 +336,48 @@ function getToolMap(_agent, input) {
304
336
  return toolMap;
305
337
  }
306
338
 
307
- // src/planners/simplePlanner.ts
308
- var simplePlannerPromptTemplate = (data) => {
339
+ // src/strategies/simple.ts
340
+ var simpleStrategyPromptTemplate = (data) => {
309
341
  return `
310
- ${defaultTextTemplate(data)}
342
+ ${convertToXml(data)}
311
343
 
312
344
  Make at most one tool call to achieve the above goal. If the goal cannot be achieved with any tool calls, do not make any tool call.
313
345
  `.trim();
314
346
  };
315
- async function simplePlanner(agent, input) {
347
+ async function simpleStrategy(agent, input) {
316
348
  const toolMap = getToolMap(agent, input);
317
349
  if (!toolMap) {
318
350
  return void 0;
319
351
  }
320
- const prompt = simplePlannerPromptTemplate({
321
- context: input.state.context,
352
+ const prompt = simpleStrategyPromptTemplate({
353
+ context: input.context,
322
354
  goal: input.goal
323
355
  });
324
356
  const messages = await getMessages(agent, prompt, input);
325
357
  const model = input.model ? agent.wrap(input.model) : agent.model;
326
358
  const {
327
359
  state,
360
+ context,
328
361
  machine,
329
- previousPlan,
362
+ prevDecision,
330
363
  events,
331
364
  goal,
332
365
  model: _,
333
366
  ...rest
334
367
  } = input;
335
- const machineState = input.machine ? input.machine.resolveState({
368
+ const machineState = input.machine && input.state ? input.machine.resolveState({
336
369
  ...input.state,
337
- context: input.state.context
370
+ context: input.state.context ?? {}
338
371
  }) : void 0;
339
372
  const result = await (0, import_ai3.generateText)({
340
373
  ...rest,
374
+ system: input.system ?? agent.description,
341
375
  model,
342
376
  messages,
343
377
  tools: toolMap,
344
378
  toolChoice: input.toolChoice ?? "required"
345
379
  });
346
- result.responseMessages.forEach((m) => {
380
+ result.response.messages.forEach((m) => {
347
381
  const message = m;
348
382
  agent.addMessage({
349
383
  ...message,
@@ -357,7 +391,7 @@ async function simplePlanner(agent, input) {
357
391
  return void 0;
358
392
  }
359
393
  return {
360
- planner: "simple",
394
+ strategy: "simple",
361
395
  goal: input.goal,
362
396
  goalState: input.state,
363
397
  nextEvent: singleResult.result,
@@ -388,13 +422,11 @@ function createAgentMiddleware(agent) {
388
422
  },
389
423
  wrapGenerate: async ({ doGenerate, params }) => {
390
424
  const id = randomId();
391
- params.prompt.forEach((p) => {
425
+ params.prompt.forEach((message) => {
392
426
  agent.addMessage({
393
427
  id,
394
- ...p,
395
- timestamp: Date.now(),
396
- correlationId: params.providerMetadata?.correlationId,
397
- parentCorrelationId: params.providerMetadata?.parentCorrelationId
428
+ ...message,
429
+ timestamp: Date.now()
398
430
  });
399
431
  });
400
432
  const result = await doGenerate();
@@ -407,9 +439,7 @@ function createAgentMiddleware(agent) {
407
439
  agent.addMessage({
408
440
  id,
409
441
  ...message,
410
- timestamp: Date.now(),
411
- correlationId: params.providerMetadata?.correlationId,
412
- parentCorrelationId: params.providerMetadata?.parentCorrelationId
442
+ timestamp: Date.now()
413
443
  });
414
444
  });
415
445
  const { stream, ...rest } = await doStream();
@@ -434,9 +464,7 @@ function createAgentMiddleware(agent) {
434
464
  timestamp: Date.now(),
435
465
  role: "assistant",
436
466
  content,
437
- responseId: id,
438
- correlationId: params.providerMetadata?.correlationId,
439
- parentCorrelationId: params.providerMetadata?.parentCorrelationId
467
+ responseId: id
440
468
  });
441
469
  }
442
470
  });
@@ -480,17 +508,18 @@ var agentLogic = (0, import_xstate4.fromTransition)(
480
508
  });
481
509
  break;
482
510
  }
483
- case "agent.plan": {
484
- state.plans.push(event.plan);
511
+ case "agent.decision": {
512
+ state.decisions.push(event.decision);
485
513
  emit({
486
- type: "plan",
487
- // @ts-ignore TODO: fix types in XState
488
- plan: event.plan
514
+ type: "decision",
515
+ decision: event.decision
489
516
  });
490
517
  break;
491
518
  }
492
- default:
519
+ default: {
520
+ console.warn("Unrecognized event", event);
493
521
  break;
522
+ }
494
523
  }
495
524
  return state;
496
525
  },
@@ -498,31 +527,28 @@ var agentLogic = (0, import_xstate4.fromTransition)(
498
527
  feedback: [],
499
528
  messages: [],
500
529
  observations: [],
501
- plans: []
530
+ decisions: []
502
531
  })
503
532
  );
504
533
  function createAgent({
505
534
  id,
506
- name,
507
535
  description,
508
536
  model,
509
537
  events,
510
538
  context,
511
- planner = simplePlanner,
512
- stringify = JSON.stringify,
513
- getMemory,
514
- logic = agentLogic,
515
- ...generateTextOptions
539
+ episodeId,
540
+ strategy = simpleStrategy,
541
+ logic = agentLogic
516
542
  }) {
517
543
  return new Agent({
518
544
  id,
519
545
  context,
520
546
  events,
521
- name,
522
547
  description,
523
- planner,
548
+ strategy,
524
549
  model,
525
- logic
550
+ logic,
551
+ episodeId
526
552
  });
527
553
  }
528
554
  var Agent = class extends import_xstate4.Actor {
@@ -535,17 +561,18 @@ var Agent = class extends import_xstate4.Actor {
535
561
  model,
536
562
  events,
537
563
  context,
538
- planner = simplePlanner
564
+ episodeId,
565
+ strategy = simpleStrategy
539
566
  }) {
540
567
  super(logic);
541
568
  this.model = model;
542
- this.episodeId = id ?? randomId();
569
+ this.episodeId = episodeId ?? randomId("episode-");
543
570
  this.name = name;
544
571
  this.description = description;
545
572
  this.events = events;
546
573
  this.context = context;
547
- this.planner = planner;
548
- this.types = {};
574
+ this.strategy = strategy;
575
+ this.id = id ?? randomId();
549
576
  this.start();
550
577
  }
551
578
  /**
@@ -554,6 +581,12 @@ var Agent = class extends import_xstate4.Actor {
554
581
  onMessage(fn) {
555
582
  return this.on("message", (ev) => fn(ev.message));
556
583
  }
584
+ /**
585
+ * Called whenever the agent (LLM assistant) receives some feedback.
586
+ */
587
+ onFeedback(fn) {
588
+ return this.on("feedback", (ev) => fn(ev.feedback));
589
+ }
557
590
  /**
558
591
  * Retrieves messages from the agent's short-term (local) memory.
559
592
  */
@@ -577,7 +610,6 @@ var Agent = class extends import_xstate4.Actor {
577
610
  const feedback = {
578
611
  ...feedbackInput,
579
612
  attributes: { ...feedbackInput.attributes },
580
- reward: feedbackInput.reward ?? 0,
581
613
  timestamp: feedbackInput.timestamp ?? Date.now(),
582
614
  episodeId: this.episodeId
583
615
  };
@@ -616,20 +648,21 @@ var Agent = class extends import_xstate4.Actor {
616
648
  getObservations() {
617
649
  return this.getSnapshot().context.observations;
618
650
  }
619
- addPlan(plan) {
651
+ addDecision(decision) {
620
652
  this.send({
621
- type: "agent.plan",
622
- plan
653
+ type: "agent.decision",
654
+ decision
623
655
  });
624
656
  }
625
657
  /**
626
658
  * Retrieves strategies from the agent's short-term (local) memory.
627
659
  */
628
- getPlans() {
629
- return this.getSnapshot().context.plans;
660
+ getDecisions() {
661
+ return this.getSnapshot().context.decisions;
630
662
  }
631
663
  interact(actorRef, getInput) {
632
- const actorRefCheck = isActorRef(actorRef);
664
+ const actorRefCheck = isActorRef(actorRef) && actorRef.src;
665
+ const machine = isMachineActor(actorRef) ? actorRef.src : void 0;
633
666
  let prevState = void 0;
634
667
  let subscribed = true;
635
668
  const agent = this;
@@ -637,14 +670,14 @@ var Agent = class extends import_xstate4.Actor {
637
670
  const observation = agent.addObservation(observationInput);
638
671
  const input = getInput?.(observation);
639
672
  if (input) {
640
- await agentDecide(agent, {
641
- machine: actorRefCheck ? actorRef.src : void 0,
673
+ const res = await agentDecide(agent, {
674
+ machine,
642
675
  state: observation.state,
643
- execute: async (event) => {
644
- actorRef.send(event);
645
- },
646
676
  ...input
647
677
  });
678
+ if (res?.nextEvent) {
679
+ actorRef.send(res.nextEvent);
680
+ }
648
681
  }
649
682
  prevState = observationInput.state;
650
683
  }
@@ -665,8 +698,7 @@ var Agent = class extends import_xstate4.Actor {
665
698
  if (actorRef._processingStatus === 1) {
666
699
  handleObservation({
667
700
  prevState: void 0,
668
- event: { type: "" },
669
- // TODO: unknown events?
701
+ event: void 0,
670
702
  state: actorRef.getSnapshot(),
671
703
  machine: actorRef.src
672
704
  });
@@ -706,14 +738,14 @@ var Agent = class extends import_xstate4.Actor {
706
738
  });
707
739
  }
708
740
  /**
709
- * Resolves with an `AgentPlan` based on the information provided in the `options`, including:
741
+ * Resolves with an `AgentDecision` based on the information provided in the `options`, including:
710
742
  *
711
743
  * - The `goal` for the agent to achieve
712
744
  * - The observed current `state`
713
745
  * - The `machine` (e.g. a state machine) that specifies what can happen next
714
746
  * - Additional `context`
715
747
  */
716
- decide(opts) {
748
+ async decide(opts) {
717
749
  return agentDecide(this, opts);
718
750
  }
719
751
  };