@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.mjs CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  fromTransition
5
5
  } from "xstate";
6
6
 
7
- // src/planners/simplePlanner.ts
7
+ // src/strategies/simple.ts
8
8
  import { generateText as generateText2 } from "ai";
9
9
 
10
10
  // src/utils.ts
@@ -43,6 +43,15 @@ function getAllMachineTransitions(stateNode) {
43
43
  function wrapInXml(tagName, content) {
44
44
  return `<${tagName}>${content}</${tagName}>`;
45
45
  }
46
+ function convertToXml(obj) {
47
+ return Object.entries(obj).map(([key, value]) => {
48
+ if (typeof value === "object" && value !== null) {
49
+ return wrapInXml(key, convertToXml(value));
50
+ } else {
51
+ return wrapInXml(key, value);
52
+ }
53
+ }).join("");
54
+ }
46
55
  function randomId(prefix) {
47
56
  const timestamp = Date.now().toString(36);
48
57
  const random = Math.random().toString(36).substring(2, 9);
@@ -70,10 +79,19 @@ function getTransitions(state, machine) {
70
79
  });
71
80
  return getAllTransitions(resolvedState);
72
81
  }
82
+ function isMachineActor(actor) {
83
+ return "src" in actor && typeof actor.src === "object" && actor.src !== null && "definition" in actor.src;
84
+ }
73
85
 
74
- // src/planners/simplePlanner.ts
86
+ // src/strategies/simple.ts
75
87
  import { getNextSnapshot } from "xstate";
76
88
 
89
+ // src/text.ts
90
+ import {
91
+ generateText,
92
+ streamText
93
+ } from "ai";
94
+
77
95
  // src/templates/defaultText.ts
78
96
  var defaultTextTemplate = (data) => {
79
97
  const preamble = [
@@ -87,10 +105,6 @@ ${data.goal}
87
105
  };
88
106
 
89
107
  // src/text.ts
90
- import {
91
- generateText,
92
- streamText
93
- } from "ai";
94
108
  import {
95
109
  fromObservable,
96
110
  fromPromise,
@@ -183,27 +197,42 @@ async function agentDecide(agent, options) {
183
197
  ...options
184
198
  };
185
199
  const {
186
- planner = simplePlanner,
200
+ strategy = agent.strategy,
187
201
  goal,
202
+ allowedEvents,
188
203
  events = agent.events,
189
204
  state,
190
205
  machine,
191
206
  model = agent.model,
192
- ...otherPlanInput
207
+ messages,
208
+ ...otherDecideInput
193
209
  } = resolvedOptions;
194
- const plan = await planner(agent, {
195
- model,
196
- goal,
197
- events,
198
- state,
199
- machine,
200
- ...otherPlanInput
201
- });
202
- if (plan?.nextEvent) {
203
- agent.addPlan(plan);
204
- await resolvedOptions.execute?.(plan.nextEvent);
210
+ const filteredEventSchemas = allowedEvents ? Object.fromEntries(
211
+ Object.entries(events).filter(([key]) => {
212
+ return allowedEvents.includes(key);
213
+ })
214
+ ) : events;
215
+ let attempts = 0;
216
+ const maxAttempts = resolvedOptions.maxAttempts ?? 2;
217
+ let decision;
218
+ while (attempts++ < maxAttempts) {
219
+ decision = await strategy(agent, {
220
+ model,
221
+ goal,
222
+ events: filteredEventSchemas,
223
+ state,
224
+ machine,
225
+ messages,
226
+ // TODO: fix UIMessage thing
227
+ ...otherDecideInput
228
+ });
229
+ if (decision?.nextEvent) {
230
+ agent.addDecision(decision);
231
+ await resolvedOptions.execute?.(decision.nextEvent);
232
+ break;
233
+ }
205
234
  }
206
- return plan;
235
+ return decision;
207
236
  }
208
237
  function fromDecision(agent, defaultInput) {
209
238
  return fromPromise2(async ({ input, self }) => {
@@ -221,15 +250,18 @@ function fromDecision(agent, defaultInput) {
221
250
  value: snapshot.value,
222
251
  context: resolvedInput.context
223
252
  };
224
- const plan = await agentDecide(agent, {
253
+ const decision = await agentDecide(agent, {
225
254
  machine: parentRef.logic,
226
- state,
255
+ state: snapshot,
256
+ context: resolvedInput.context,
227
257
  execute: async (event) => {
228
258
  parentRef.send(event);
229
259
  },
230
- ...resolvedInput
260
+ ...resolvedInput,
261
+ // @ts-ignore
262
+ messages: resolvedInput.messages
231
263
  });
232
- return plan;
264
+ return decision;
233
265
  });
234
266
  }
235
267
  function getToolMap(_agent, input) {
@@ -275,46 +307,48 @@ function getToolMap(_agent, input) {
275
307
  return toolMap;
276
308
  }
277
309
 
278
- // src/planners/simplePlanner.ts
279
- var simplePlannerPromptTemplate = (data) => {
310
+ // src/strategies/simple.ts
311
+ var simpleStrategyPromptTemplate = (data) => {
280
312
  return `
281
- ${defaultTextTemplate(data)}
313
+ ${convertToXml(data)}
282
314
 
283
315
  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.
284
316
  `.trim();
285
317
  };
286
- async function simplePlanner(agent, input) {
318
+ async function simpleStrategy(agent, input) {
287
319
  const toolMap = getToolMap(agent, input);
288
320
  if (!toolMap) {
289
321
  return void 0;
290
322
  }
291
- const prompt = simplePlannerPromptTemplate({
292
- context: input.state.context,
323
+ const prompt = simpleStrategyPromptTemplate({
324
+ context: input.context,
293
325
  goal: input.goal
294
326
  });
295
327
  const messages = await getMessages(agent, prompt, input);
296
328
  const model = input.model ? agent.wrap(input.model) : agent.model;
297
329
  const {
298
330
  state,
331
+ context,
299
332
  machine,
300
- previousPlan,
333
+ prevDecision,
301
334
  events,
302
335
  goal,
303
336
  model: _,
304
337
  ...rest
305
338
  } = input;
306
- const machineState = input.machine ? input.machine.resolveState({
339
+ const machineState = input.machine && input.state ? input.machine.resolveState({
307
340
  ...input.state,
308
- context: input.state.context
341
+ context: input.state.context ?? {}
309
342
  }) : void 0;
310
343
  const result = await generateText2({
311
344
  ...rest,
345
+ system: input.system ?? agent.description,
312
346
  model,
313
347
  messages,
314
348
  tools: toolMap,
315
349
  toolChoice: input.toolChoice ?? "required"
316
350
  });
317
- result.responseMessages.forEach((m) => {
351
+ result.response.messages.forEach((m) => {
318
352
  const message = m;
319
353
  agent.addMessage({
320
354
  ...message,
@@ -328,7 +362,7 @@ async function simplePlanner(agent, input) {
328
362
  return void 0;
329
363
  }
330
364
  return {
331
- planner: "simple",
365
+ strategy: "simple",
332
366
  goal: input.goal,
333
367
  goalState: input.state,
334
368
  nextEvent: singleResult.result,
@@ -361,13 +395,11 @@ function createAgentMiddleware(agent) {
361
395
  },
362
396
  wrapGenerate: async ({ doGenerate, params }) => {
363
397
  const id = randomId();
364
- params.prompt.forEach((p) => {
398
+ params.prompt.forEach((message) => {
365
399
  agent.addMessage({
366
400
  id,
367
- ...p,
368
- timestamp: Date.now(),
369
- correlationId: params.providerMetadata?.correlationId,
370
- parentCorrelationId: params.providerMetadata?.parentCorrelationId
401
+ ...message,
402
+ timestamp: Date.now()
371
403
  });
372
404
  });
373
405
  const result = await doGenerate();
@@ -380,9 +412,7 @@ function createAgentMiddleware(agent) {
380
412
  agent.addMessage({
381
413
  id,
382
414
  ...message,
383
- timestamp: Date.now(),
384
- correlationId: params.providerMetadata?.correlationId,
385
- parentCorrelationId: params.providerMetadata?.parentCorrelationId
415
+ timestamp: Date.now()
386
416
  });
387
417
  });
388
418
  const { stream, ...rest } = await doStream();
@@ -407,9 +437,7 @@ function createAgentMiddleware(agent) {
407
437
  timestamp: Date.now(),
408
438
  role: "assistant",
409
439
  content,
410
- responseId: id,
411
- correlationId: params.providerMetadata?.correlationId,
412
- parentCorrelationId: params.providerMetadata?.parentCorrelationId
440
+ responseId: id
413
441
  });
414
442
  }
415
443
  });
@@ -453,17 +481,18 @@ var agentLogic = fromTransition(
453
481
  });
454
482
  break;
455
483
  }
456
- case "agent.plan": {
457
- state.plans.push(event.plan);
484
+ case "agent.decision": {
485
+ state.decisions.push(event.decision);
458
486
  emit({
459
- type: "plan",
460
- // @ts-ignore TODO: fix types in XState
461
- plan: event.plan
487
+ type: "decision",
488
+ decision: event.decision
462
489
  });
463
490
  break;
464
491
  }
465
- default:
492
+ default: {
493
+ console.warn("Unrecognized event", event);
466
494
  break;
495
+ }
467
496
  }
468
497
  return state;
469
498
  },
@@ -471,31 +500,28 @@ var agentLogic = fromTransition(
471
500
  feedback: [],
472
501
  messages: [],
473
502
  observations: [],
474
- plans: []
503
+ decisions: []
475
504
  })
476
505
  );
477
506
  function createAgent({
478
507
  id,
479
- name,
480
508
  description,
481
509
  model,
482
510
  events,
483
511
  context,
484
- planner = simplePlanner,
485
- stringify = JSON.stringify,
486
- getMemory,
487
- logic = agentLogic,
488
- ...generateTextOptions
512
+ episodeId,
513
+ strategy = simpleStrategy,
514
+ logic = agentLogic
489
515
  }) {
490
516
  return new Agent({
491
517
  id,
492
518
  context,
493
519
  events,
494
- name,
495
520
  description,
496
- planner,
521
+ strategy,
497
522
  model,
498
- logic
523
+ logic,
524
+ episodeId
499
525
  });
500
526
  }
501
527
  var Agent = class extends Actor {
@@ -508,17 +534,18 @@ var Agent = class extends Actor {
508
534
  model,
509
535
  events,
510
536
  context,
511
- planner = simplePlanner
537
+ episodeId,
538
+ strategy = simpleStrategy
512
539
  }) {
513
540
  super(logic);
514
541
  this.model = model;
515
- this.episodeId = id ?? randomId();
542
+ this.episodeId = episodeId ?? randomId("episode-");
516
543
  this.name = name;
517
544
  this.description = description;
518
545
  this.events = events;
519
546
  this.context = context;
520
- this.planner = planner;
521
- this.types = {};
547
+ this.strategy = strategy;
548
+ this.id = id ?? randomId();
522
549
  this.start();
523
550
  }
524
551
  /**
@@ -527,6 +554,12 @@ var Agent = class extends Actor {
527
554
  onMessage(fn) {
528
555
  return this.on("message", (ev) => fn(ev.message));
529
556
  }
557
+ /**
558
+ * Called whenever the agent (LLM assistant) receives some feedback.
559
+ */
560
+ onFeedback(fn) {
561
+ return this.on("feedback", (ev) => fn(ev.feedback));
562
+ }
530
563
  /**
531
564
  * Retrieves messages from the agent's short-term (local) memory.
532
565
  */
@@ -550,7 +583,6 @@ var Agent = class extends Actor {
550
583
  const feedback = {
551
584
  ...feedbackInput,
552
585
  attributes: { ...feedbackInput.attributes },
553
- reward: feedbackInput.reward ?? 0,
554
586
  timestamp: feedbackInput.timestamp ?? Date.now(),
555
587
  episodeId: this.episodeId
556
588
  };
@@ -589,20 +621,21 @@ var Agent = class extends Actor {
589
621
  getObservations() {
590
622
  return this.getSnapshot().context.observations;
591
623
  }
592
- addPlan(plan) {
624
+ addDecision(decision) {
593
625
  this.send({
594
- type: "agent.plan",
595
- plan
626
+ type: "agent.decision",
627
+ decision
596
628
  });
597
629
  }
598
630
  /**
599
631
  * Retrieves strategies from the agent's short-term (local) memory.
600
632
  */
601
- getPlans() {
602
- return this.getSnapshot().context.plans;
633
+ getDecisions() {
634
+ return this.getSnapshot().context.decisions;
603
635
  }
604
636
  interact(actorRef, getInput) {
605
- const actorRefCheck = isActorRef(actorRef);
637
+ const actorRefCheck = isActorRef(actorRef) && actorRef.src;
638
+ const machine = isMachineActor(actorRef) ? actorRef.src : void 0;
606
639
  let prevState = void 0;
607
640
  let subscribed = true;
608
641
  const agent = this;
@@ -610,14 +643,14 @@ var Agent = class extends Actor {
610
643
  const observation = agent.addObservation(observationInput);
611
644
  const input = getInput?.(observation);
612
645
  if (input) {
613
- await agentDecide(agent, {
614
- machine: actorRefCheck ? actorRef.src : void 0,
646
+ const res = await agentDecide(agent, {
647
+ machine,
615
648
  state: observation.state,
616
- execute: async (event) => {
617
- actorRef.send(event);
618
- },
619
649
  ...input
620
650
  });
651
+ if (res?.nextEvent) {
652
+ actorRef.send(res.nextEvent);
653
+ }
621
654
  }
622
655
  prevState = observationInput.state;
623
656
  }
@@ -638,8 +671,7 @@ var Agent = class extends Actor {
638
671
  if (actorRef._processingStatus === 1) {
639
672
  handleObservation({
640
673
  prevState: void 0,
641
- event: { type: "" },
642
- // TODO: unknown events?
674
+ event: void 0,
643
675
  state: actorRef.getSnapshot(),
644
676
  machine: actorRef.src
645
677
  });
@@ -679,14 +711,14 @@ var Agent = class extends Actor {
679
711
  });
680
712
  }
681
713
  /**
682
- * Resolves with an `AgentPlan` based on the information provided in the `options`, including:
714
+ * Resolves with an `AgentDecision` based on the information provided in the `options`, including:
683
715
  *
684
716
  * - The `goal` for the agent to achieve
685
717
  * - The observed current `state`
686
718
  * - The `machine` (e.g. a state machine) that specifies what can happen next
687
719
  * - Additional `context`
688
720
  */
689
- decide(opts) {
721
+ async decide(opts) {
690
722
  return agentDecide(this, opts);
691
723
  }
692
724
  };
@@ -4,7 +4,7 @@ import { openai } from '@ai-sdk/openai';
4
4
  import { getFromTerminal } from './helpers/helpers';
5
5
 
6
6
  const agent = createAgent({
7
- name: 'chatbot',
7
+ id: 'chatbot',
8
8
  model: openai('gpt-4o-mini'),
9
9
  events: {
10
10
  'agent.respond': z.object({
@@ -1,11 +1,11 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, fromDecision } from '../src';
2
+ import { createAgent, fromDecision, TypesFromAgent } from '../src';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { assign, createActor, log, setup } from 'xstate';
5
5
  import { fromTerminal } from './helpers/helpers';
6
6
 
7
7
  const agent = createAgent({
8
- name: 'chatbot',
8
+ id: 'chatbot',
9
9
  model: openai('gpt-4o-mini'),
10
10
  events: {
11
11
  'agent.respond': z.object({
@@ -19,7 +19,7 @@ const agent = createAgent({
19
19
  });
20
20
 
21
21
  const machine = setup({
22
- types: agent.types,
22
+ types: {} as TypesFromAgent<typeof agent>,
23
23
  actors: { getFromTerminal: fromTerminal },
24
24
  }).createMachine({
25
25
  initial: 'listening',
package/examples/cot.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, fromDecision } from '../src';
2
+ import { createAgent, fromDecision, TypesFromAgent } from '../src';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { assign, createActor, log, setup } from 'xstate';
5
5
  import { fromTerminal } from './helpers/helpers';
6
+ import { chainOfThoughtStrategy } from '../src/strategies/chainOfThought';
6
7
 
7
8
  const agent = createAgent({
8
- name: 'chain-of-thought',
9
+ id: 'chain-of-thought',
9
10
  model: openai('gpt-4o-mini'),
10
11
  events: {
11
12
  'agent.think': z.object({
@@ -19,18 +20,17 @@ const agent = createAgent({
19
20
  },
20
21
  context: {
21
22
  question: z.string().nullable(),
22
- thought: z.string().nullable(),
23
23
  },
24
+ strategy: chainOfThoughtStrategy,
24
25
  });
25
26
 
26
27
  const machine = setup({
27
- types: agent.types,
28
+ types: {} as TypesFromAgent<typeof agent>,
28
29
  actors: { getFromTerminal: fromTerminal },
29
30
  }).createMachine({
30
31
  initial: 'asking',
31
32
  context: {
32
33
  question: null,
33
- thought: null,
34
34
  },
35
35
  states: {
36
36
  asking: {
@@ -41,19 +41,6 @@ const machine = setup({
41
41
  actions: assign({
42
42
  question: ({ event }) => event.output,
43
43
  }),
44
- target: 'thinking',
45
- },
46
- },
47
- },
48
- thinking: {
49
- on: {
50
- 'agent.think': {
51
- actions: [
52
- log(({ event }) => `Thought: ${event.thought}`),
53
- assign({
54
- thought: ({ event }) => event.thought,
55
- }),
56
- ],
57
44
  target: 'answering',
58
45
  },
59
46
  },
@@ -74,14 +61,9 @@ const machine = setup({
74
61
 
75
62
  const actor = createActor(machine).start();
76
63
 
64
+ agent.onMessage(console.log);
65
+
77
66
  agent.interact(actor, (obs) => {
78
- if (obs.state.matches('thinking')) {
79
- return {
80
- goal: 'Think step-by-step about how you would answer the question',
81
- context: obs.state.context,
82
- messages: agent.getMessages(),
83
- };
84
- }
85
67
  if (obs.state.matches('answering')) {
86
68
  return {
87
69
  goal: 'Answer the question',
@@ -1,11 +1,11 @@
1
- import { createAgent, fromDecision } from '../src';
1
+ import { createAgent, EventsFromAgent, fromDecision } from '../src';
2
2
  import { assign, createActor, setup } from 'xstate';
3
3
  import { openai } from '@ai-sdk/openai';
4
4
  import { z } from 'zod';
5
5
 
6
6
  // Create customer service agent
7
7
  const customerServiceAgent = createAgent({
8
- name: 'customer-service',
8
+ id: 'customer-service',
9
9
  model: openai('gpt-4o'),
10
10
  events: {
11
11
  'agent.respond': z.object({
@@ -14,12 +14,12 @@ const customerServiceAgent = createAgent({
14
14
  .describe('The response from the customer service agent'),
15
15
  }),
16
16
  },
17
- system: 'You are a customer service agent for an airline.',
17
+ description: 'You are a customer service agent for an airline.',
18
18
  });
19
19
 
20
20
  // Create simulated customer agent
21
21
  const customerAgent = createAgent({
22
- name: 'customer',
22
+ id: 'customer',
23
23
  model: openai('gpt-4o-mini'),
24
24
  events: {
25
25
  'agent.respond': z.object({
@@ -27,7 +27,7 @@ const customerAgent = createAgent({
27
27
  }),
28
28
  'agent.finish': z.object({}).describe('End the conversation'),
29
29
  },
30
- system: `You are Harrison, a customer trying to get a refund for a trip to Alaska.
30
+ description: `You are Harrison, a customer trying to get a refund for a trip to Alaska.
31
31
  You want them to give you ALL the money back. Be extremely persistent. This trip happened 5 years ago.
32
32
  If you have nothing more to add to the conversation, send agent.finish event.`,
33
33
  });
@@ -38,8 +38,8 @@ const machine = setup({
38
38
  messages: string[];
39
39
  },
40
40
  events: {} as
41
- | typeof customerServiceAgent.types.events
42
- | typeof customerAgent.types.events,
41
+ | EventsFromAgent<typeof customerServiceAgent>
42
+ | EventsFromAgent<typeof customerAgent>,
43
43
  },
44
44
  actors: {
45
45
  customerService: fromDecision(customerServiceAgent),
package/examples/email.ts CHANGED
@@ -1,12 +1,18 @@
1
1
  import { z } from 'zod';
2
- import { createAgent, fromDecision } from '../src';
2
+ import {
3
+ ContextFromAgent,
4
+ createAgent,
5
+ EventsFromAgent,
6
+ fromDecision,
7
+ TypesFromAgent,
8
+ } from '../src';
3
9
  import { openai } from '@ai-sdk/openai';
4
10
  import { assign, createActor, setup } from 'xstate';
5
11
  import { fromTerminal } from './helpers/helpers';
6
12
 
7
13
  const agent = createAgent({
8
- name: 'email',
9
- model: openai('gpt-4o'),
14
+ id: 'email',
15
+ model: openai('gpt-4o-mini'),
10
16
  events: {
11
17
  askForClarification: z.object({
12
18
  questions: z.array(z.string()).describe('The questions to ask the agent'),
@@ -15,23 +21,26 @@ const agent = createAgent({
15
21
  email: z.string().describe('The email to submit'),
16
22
  }),
17
23
  },
24
+ context: {
25
+ email: z.string().describe('The email to respond to'),
26
+ instructions: z.string().describe('The instructions for the email'),
27
+ clarifications: z
28
+ .array(z.string())
29
+ .describe('The clarifications to the email'),
30
+ replyEmail: z.string().nullable().describe('The email to submit'),
31
+ },
18
32
  });
19
33
 
20
34
  const machine = setup({
21
35
  types: {
22
- events: agent.types.events,
36
+ events: {} as EventsFromAgent<typeof agent>,
23
37
  input: {} as {
24
38
  email: string;
25
39
  instructions: string;
26
40
  },
27
- context: {} as {
28
- email: string;
29
- instructions: string;
30
- clarifications: string[];
31
- replyEmail: string | null;
32
- },
41
+ context: {} as ContextFromAgent<typeof agent>,
33
42
  },
34
- actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
43
+ actors: { getFromTerminal: fromTerminal },
35
44
  }).createMachine({
36
45
  initial: 'checking',
37
46
  context: ({ input }) => ({
@@ -42,18 +51,6 @@ const machine = setup({
42
51
  }),
43
52
  states: {
44
53
  checking: {
45
- invoke: {
46
- src: 'agent',
47
- input: ({ context }) => ({
48
- context: {
49
- email: context.email,
50
- instructions: context.instructions,
51
- clarifications: context.clarifications,
52
- },
53
- messages: agent.getMessages(),
54
- goal: 'Respond to the email given the instructions and the provided clarifications. If not enough information is provided, ask for clarification. Otherwise, if you are absolutely sure that there is no ambiguous or missing information, create and submit a response email.',
55
- }),
56
- },
57
54
  on: {
58
55
  askForClarification: {
59
56
  actions: ({ event }) => console.log(event.questions.join('\n')),
@@ -78,17 +75,6 @@ const machine = setup({
78
75
  },
79
76
  },
80
77
  submitting: {
81
- invoke: {
82
- src: 'agent',
83
- input: ({ context }) => ({
84
- context: {
85
- email: context.email,
86
- instructions: context.instructions,
87
- clarifications: context.clarifications,
88
- },
89
- goal: `Create and submit an email based on the instructions.`,
90
- }),
91
- },
92
78
  on: {
93
79
  submitEmail: {
94
80
  actions: assign({
@@ -109,10 +95,26 @@ const machine = setup({
109
95
  },
110
96
  });
111
97
 
112
- createActor(machine, {
98
+ const actor = createActor(machine, {
113
99
  input: {
114
100
  email: 'That sounds great! When are you available?',
115
101
  instructions:
116
102
  'Tell them exactly when I am available. Address them by his full (first and last) name.',
117
103
  },
118
104
  }).start();
105
+
106
+ agent.interact(actor, ({ state }) => {
107
+ if (state.matches('checking')) {
108
+ return {
109
+ goal: 'Respond to the email given the instructions and the provided clarifications. If not enough information is provided, ask for clarification. Otherwise, if you are absolutely sure that there is no ambiguous or missing information, create and submit a response email.',
110
+ context: state.context,
111
+ };
112
+ }
113
+
114
+ if (state.matches('submitting')) {
115
+ return {
116
+ goal: 'Create and submit an email based on the instructions.',
117
+ context: state.context,
118
+ };
119
+ }
120
+ });