@statelyai/agent 2.0.0-next.1 → 2.0.0-next.3

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/grumpy-dolphins-think.md +17 -0
  2. package/.changeset/old-teachers-tap.md +5 -0
  3. package/.changeset/pink-eagles-deliver.md +13 -0
  4. package/.changeset/pre.json +9 -1
  5. package/.changeset/quiet-turtles-do.md +7 -0
  6. package/.changeset/smart-yaks-pull.md +23 -0
  7. package/.changeset/sweet-clouds-mix.md +16 -0
  8. package/.changeset/swift-mangos-rush.md +5 -0
  9. package/.changeset/tough-ways-rhyme.md +5 -0
  10. package/CHANGELOG.md +79 -0
  11. package/dist/index.d.mts +116 -100
  12. package/dist/index.d.ts +116 -100
  13. package/dist/index.js +102 -72
  14. package/dist/index.mjs +105 -75
  15. package/examples/chatbot.ts +2 -2
  16. package/examples/cot.ts +21 -73
  17. package/examples/customer-service-sim.ts +3 -3
  18. package/examples/email.ts +3 -5
  19. package/examples/example.ts +2 -2
  20. package/examples/goal.ts +2 -2
  21. package/examples/joke.ts +12 -12
  22. package/examples/jugs.ts +4 -7
  23. package/examples/learn-from-feedback.ts +123 -0
  24. package/examples/number.ts +2 -2
  25. package/examples/raffle.ts +2 -2
  26. package/examples/river-crossing.ts +4 -7
  27. package/examples/simple.ts +13 -10
  28. package/examples/summary.ts +2 -5
  29. package/examples/support.ts +38 -38
  30. package/examples/ticTacToe.ts +46 -4
  31. package/examples/todo.ts +3 -3
  32. package/examples/tutor.ts +2 -2
  33. package/examples/verify.ts +2 -2
  34. package/examples/weather-agent.ts +139 -0
  35. package/examples/weather.ts +26 -23
  36. package/examples/word.ts +8 -6
  37. package/package.json +2 -1
  38. package/src/agent.test.ts +37 -52
  39. package/src/agent.ts +93 -60
  40. package/src/decide.test.ts +56 -8
  41. package/src/decide.ts +42 -32
  42. package/src/strategies/chainOfThought.ts +50 -0
  43. package/src/{planners → strategies}/shortestPath.test.ts +4 -7
  44. package/src/strategies/shortestPath.ts +178 -0
  45. package/src/{planners → strategies}/simple.ts +25 -26
  46. package/src/templates/defaultText.ts +3 -0
  47. package/src/text.ts +13 -13
  48. package/src/types.ts +124 -83
  49. package/src/utils.ts +13 -1
  50. package/src/planners/shortestPath.ts +0 -177
  51. package/src/strategies/chain-of-note.ts +0 -106
package/src/agent.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  import {
2
2
  Actor,
3
3
  ActorRefLike,
4
- AnyEventObject,
5
- AnyStateMachine,
6
4
  EventObject,
7
5
  fromTransition,
8
6
  Subscription,
@@ -11,7 +9,7 @@ import { ZodContextMapping, ZodEventMapping } from './schemas';
11
9
  import {
12
10
  AgentLogic,
13
11
  AgentMessage,
14
- AgentPlanner,
12
+ AgentStrategy,
15
13
  EventsFromZodEventMapping,
16
14
  GenerateTextOptions,
17
15
  AgentLongTermMemory,
@@ -23,13 +21,12 @@ import {
23
21
  AgentFeedback,
24
22
  AgentMessageInput,
25
23
  AgentFeedbackInput,
26
- AgentPlan,
27
- Compute,
28
- AgentDecisionInput,
24
+ AgentDecision,
29
25
  AgentDecideOptions,
30
26
  AnyAgent,
27
+ AgentInteractInput,
31
28
  } from './types';
32
- import { simplePlanner } from './planners/simple';
29
+ import { simpleStrategy } from './strategies/simple';
33
30
  import { agentDecide } from './decide';
34
31
  import { getMachineHash, isActorRef, isMachineActor, randomId } from './utils';
35
32
  import {
@@ -39,7 +36,7 @@ import {
39
36
  } from 'ai';
40
37
  import { createAgentMiddleware } from './middleware';
41
38
 
42
- export const agentLogic: AgentLogic<AnyEventObject> = fromTransition(
39
+ export const agentLogic: AgentLogic<any> = fromTransition(
43
40
  (state, event, { emit }) => {
44
41
  switch (event.type) {
45
42
  case 'agent.feedback': {
@@ -69,12 +66,11 @@ export const agentLogic: AgentLogic<AnyEventObject> = fromTransition(
69
66
  });
70
67
  break;
71
68
  }
72
- case 'agent.plan': {
73
- state.plans.push(event.plan);
69
+ case 'agent.decision': {
70
+ state.decisions.push(event.decision);
74
71
  emit({
75
- type: 'plan',
76
- // @ts-ignore TODO: fix types in XState
77
- plan: event.plan,
72
+ type: 'decision',
73
+ decision: event.decision,
78
74
  });
79
75
  break;
80
76
  }
@@ -91,23 +87,25 @@ export const agentLogic: AgentLogic<AnyEventObject> = fromTransition(
91
87
  feedback: [],
92
88
  messages: [],
93
89
  observations: [],
94
- plans: [],
95
- } as AgentMemoryContext)
90
+ decisions: [],
91
+ } as AgentMemoryContext<any>)
96
92
  );
97
93
 
98
94
  export function createAgent<
99
95
  const TContextSchema extends ZodContextMapping,
100
96
  const TEventSchemas extends ZodEventMapping,
101
97
  TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>,
102
- TContext = ContextFromZodContextMapping<TContextSchema>
98
+ TContext = ContextFromZodContextMapping<TContextSchema>,
99
+ TAgent extends AnyAgent = Agent<TContextSchema, TEventSchemas>
103
100
  >({
104
101
  id,
105
102
  description: description,
106
103
  model,
107
104
  events,
108
105
  context,
109
- planner = simplePlanner as AgentPlanner<Agent<TContextSchema, TEventSchemas>>,
110
- logic = agentLogic as AgentLogic<TEvents>,
106
+ episodeId,
107
+ strategy = simpleStrategy,
108
+ logic = agentLogic as AgentLogic<any>,
111
109
  }: {
112
110
  /**
113
111
  * The unique identifier for the agent.
@@ -134,28 +132,30 @@ export function createAgent<
134
132
  */
135
133
  events: TEventSchemas;
136
134
  context?: TContextSchema;
137
- planner?: AgentPlanner<Agent<TContextSchema, TEventSchemas>>;
135
+ strategy?: AgentStrategy<Agent<TContextSchema, TEventSchemas>>;
138
136
  stringify?: typeof JSON.stringify;
139
137
  /**
140
138
  * A function that retrieves the agent's long term memory
141
139
  */
142
140
  getMemory?: (
143
141
  agent: Agent<TContextSchema, TEventSchemas>
144
- ) => AgentLongTermMemory;
142
+ ) => AgentLongTermMemory<TAgent>;
145
143
  /**
146
144
  * Agent logic
147
145
  */
148
- logic?: AgentLogic<TEvents>;
146
+ logic?: AgentLogic<TAgent>;
149
147
  model: LanguageModel;
150
- } & GenerateTextOptions): Agent<TContextSchema, TEventSchemas> {
148
+ episodeId?: string;
149
+ }): Agent<TContextSchema, TEventSchemas> {
151
150
  return new Agent({
152
151
  id,
153
152
  context,
154
153
  events,
155
154
  description,
156
- planner,
155
+ strategy: strategy,
157
156
  model,
158
157
  logic,
158
+ episodeId,
159
159
  }) as any;
160
160
  }
161
161
 
@@ -164,7 +164,7 @@ export class Agent<
164
164
  const TEventSchemas extends ZodEventMapping,
165
165
  TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>,
166
166
  TContext = ContextFromZodContextMapping<TContextSchema>
167
- > extends Actor<AgentLogic<TEvents>> {
167
+ > extends Actor<AgentLogic<any>> {
168
168
  /**
169
169
  * The name of the agent. All agents with the same name are related and
170
170
  * able to share experiences (observations, feedback) with each other.
@@ -177,43 +177,45 @@ export class Agent<
177
177
  public description?: string;
178
178
  public events: TEventSchemas;
179
179
  public context?: TContextSchema;
180
- public planner?: AgentPlanner<Agent<TContextSchema, TEventSchemas>>;
181
- public types: {
182
- events: TEvents;
183
- context: Compute<TContext>;
184
- };
180
+ public strategy: AgentStrategy<Agent<TContextSchema, TEventSchemas>>;
181
+ // public types: {
182
+ // events: TEvents;
183
+ // context: Compute<TContext>;
184
+ // };
185
185
  public model: LanguageModel;
186
- public memory: AgentLongTermMemory | undefined;
186
+ public memory: AgentLongTermMemory<this> | undefined;
187
187
  public defaultOptions: AgentDecideOptions<AnyAgent> | undefined; // todo
188
188
 
189
189
  constructor({
190
- logic = agentLogic as AgentLogic<TEvents>,
190
+ logic = agentLogic as AgentLogic<any>,
191
191
  id,
192
192
  name,
193
193
  description,
194
194
  model,
195
195
  events,
196
196
  context,
197
- planner = simplePlanner,
197
+ episodeId,
198
+ strategy = simpleStrategy,
198
199
  }: {
199
- logic: AgentLogic<TEvents>;
200
+ logic: AgentLogic<any>;
200
201
  id?: string;
201
202
  name?: string;
202
203
  description?: string;
203
204
  model: GenerateTextOptions['model'];
204
205
  events: TEventSchemas;
205
206
  context?: TContextSchema;
206
- planner?: AgentPlanner<Agent<TContextSchema, TEventSchemas>>;
207
+ strategy?: AgentStrategy<Agent<TContextSchema, TEventSchemas>>;
208
+ episodeId?: string;
207
209
  }) {
208
210
  super(logic);
209
211
  this.model = model;
210
- this.episodeId = id ?? randomId();
212
+ this.episodeId = episodeId ?? randomId('episode-');
211
213
  this.name = name;
212
214
  this.description = description;
213
215
  this.events = events;
214
216
  this.context = context;
215
- this.planner = planner;
216
- this.types = {} as any;
217
+ this.strategy = strategy;
218
+ this.id = id ?? randomId();
217
219
 
218
220
  this.start();
219
221
  }
@@ -225,6 +227,13 @@ export class Agent<
225
227
  return this.on('message', (ev) => fn(ev.message));
226
228
  }
227
229
 
230
+ /**
231
+ * Called whenever the agent (LLM assistant) receives some feedback.
232
+ */
233
+ public onFeedback(fn: (feedback: AgentFeedback) => void) {
234
+ return this.on('feedback', (ev) => fn(ev.feedback));
235
+ }
236
+
228
237
  /**
229
238
  * Retrieves messages from the agent's short-term (local) memory.
230
239
  */
@@ -250,8 +259,8 @@ export class Agent<
250
259
  public addFeedback(feedbackInput: AgentFeedbackInput) {
251
260
  const feedback = {
252
261
  ...feedbackInput,
262
+ comment: feedbackInput.comment ?? undefined,
253
263
  attributes: { ...feedbackInput.attributes },
254
- reward: feedbackInput.reward ?? 0,
255
264
  timestamp: feedbackInput.timestamp ?? Date.now(),
256
265
  episodeId: this.episodeId,
257
266
  } satisfies AgentFeedback;
@@ -270,7 +279,7 @@ export class Agent<
270
279
  }
271
280
 
272
281
  public addObservation(
273
- observationInput: AgentObservationInput
282
+ observationInput: AgentObservationInput<this>
274
283
  ): AgentObservation<any> {
275
284
  const { prevState, event, state } = observationInput;
276
285
  const observation = {
@@ -300,17 +309,17 @@ export class Agent<
300
309
  return this.getSnapshot().context.observations;
301
310
  }
302
311
 
303
- public addPlan(plan: AgentPlan<TEvents>) {
312
+ public addDecision(decision: AgentDecision<this>) {
304
313
  this.send({
305
- type: 'agent.plan',
306
- plan,
314
+ type: 'agent.decision',
315
+ decision,
307
316
  });
308
317
  }
309
318
  /**
310
319
  * Retrieves strategies from the agent's short-term (local) memory.
311
320
  */
312
- public getPlans() {
313
- return this.getSnapshot().context.plans;
321
+ public getDecisions() {
322
+ return this.getSnapshot().context.decisions;
314
323
  }
315
324
 
316
325
  /**
@@ -361,36 +370,40 @@ export class Agent<
361
370
  actorRef: TActor,
362
371
  getInput: (
363
372
  observation: AgentObservation<TActor>
364
- ) => AgentDecisionInput | undefined
373
+ ) => AgentInteractInput<this> | void
365
374
  ): Subscription;
366
375
  public interact<TActor extends ActorRefLike>(
367
376
  actorRef: TActor,
368
377
  getInput?: (
369
378
  observation: AgentObservation<TActor>
370
- ) => AgentDecisionInput | undefined
379
+ ) => AgentInteractInput<this> | void
371
380
  ): Subscription {
372
381
  const actorRefCheck = isActorRef(actorRef) && actorRef.src;
373
382
  const machine = isMachineActor(actorRef) ? actorRef.src : undefined;
374
383
 
375
- let prevState: ObservedState | undefined = undefined;
384
+ let prevState: ObservedState<this> | undefined = undefined;
376
385
  let subscribed = true;
377
386
 
378
387
  const agent = this;
379
388
 
380
- async function handleObservation(observationInput: AgentObservationInput) {
389
+ async function handleObservation(
390
+ observationInput: AgentObservationInput<any>
391
+ ) {
381
392
  const observation = agent.addObservation(observationInput);
382
393
 
383
- const input = getInput?.(observation);
394
+ const interactInput = getInput?.(observation);
384
395
 
385
- if (input) {
386
- const res = await agentDecide(agent, {
396
+ if (interactInput) {
397
+ const decision = await agentDecide(agent, {
387
398
  machine,
388
399
  state: observation.state,
389
- ...input,
400
+ ...interactInput,
390
401
  });
391
402
 
392
- if (res?.nextEvent) {
393
- actorRef.send(res.nextEvent);
403
+ if (decision?.nextEvent) {
404
+ // @ts-ignore
405
+ decision.nextEvent['_decision'] = decision.id;
406
+ actorRef.send(decision.nextEvent);
394
407
  }
395
408
  }
396
409
 
@@ -409,12 +422,21 @@ export class Agent<
409
422
  return;
410
423
  }
411
424
 
425
+ const decisionId = inspEvent.event['_decision'] as
426
+ | string
427
+ | undefined;
428
+
429
+ const decision = decisionId
430
+ ? agent.getDecisions().find((d) => d.id === decisionId)
431
+ : undefined;
432
+
412
433
  const observationInput = {
413
434
  event: inspEvent.event,
414
435
  prevState,
415
436
  state: inspEvent.snapshot as any,
416
437
  machine: (actorRef as any).src,
417
- } satisfies AgentObservationInput;
438
+ goal: decision?.goal,
439
+ } satisfies AgentObservationInput<any>;
418
440
 
419
441
  await handleObservation(observationInput);
420
442
  },
@@ -425,9 +447,10 @@ export class Agent<
425
447
  if ((actorRef as any)._processingStatus === 1) {
426
448
  handleObservation({
427
449
  prevState: undefined,
428
- event: { type: '' }, // TODO: unknown events?
450
+ event: undefined,
429
451
  state: actorRef.getSnapshot(),
430
452
  machine: (actorRef as any).src,
453
+ goal: undefined,
431
454
  });
432
455
  }
433
456
 
@@ -440,7 +463,7 @@ export class Agent<
440
463
  }
441
464
 
442
465
  public observe<TActor extends ActorRefLike>(actorRef: TActor): Subscription {
443
- let prevState: ObservedState = actorRef.getSnapshot();
466
+ let prevState: ObservedState<this> = actorRef.getSnapshot();
444
467
  const actorRefCheck = isActorRef(actorRef);
445
468
 
446
469
  const sub = actorRefCheck
@@ -453,12 +476,20 @@ export class Agent<
453
476
  return;
454
477
  }
455
478
 
479
+ const decisionId = inspEvent.event['_decision'] as
480
+ | string
481
+ | undefined;
482
+ const decision = decisionId
483
+ ? this.getDecisions().find((d) => d.id === decisionId)
484
+ : undefined;
485
+
456
486
  const observationInput = {
457
487
  event: inspEvent.event,
458
488
  prevState,
459
489
  state: inspEvent.snapshot as any,
460
490
  machine: (actorRef as any).src,
461
- } satisfies AgentObservationInput;
491
+ goal: decision?.goal,
492
+ } satisfies AgentObservationInput<this>;
462
493
 
463
494
  prevState = observationInput.state;
464
495
 
@@ -478,14 +509,16 @@ export class Agent<
478
509
  }
479
510
 
480
511
  /**
481
- * Resolves with an `AgentPlan` based on the information provided in the `options`, including:
512
+ * Resolves with an `AgentDecision` based on the information provided in the `options`, including:
482
513
  *
483
514
  * - The `goal` for the agent to achieve
484
515
  * - The observed current `state`
485
516
  * - The `machine` (e.g. a state machine) that specifies what can happen next
486
517
  * - Additional `context`
487
518
  */
488
- public decide(opts: AgentDecideOptions<this>) {
519
+ public async decide(
520
+ opts: AgentDecideOptions<this>
521
+ ): Promise<AgentDecision<this> | undefined> {
489
522
  return agentDecide(this, opts);
490
523
  }
491
524
  }
@@ -154,7 +154,7 @@ test('interacts with an actor (late interaction)', async () => {
154
154
  expect(actor.getSnapshot().value).toBe('third');
155
155
  });
156
156
 
157
- test('agent.decide() makes a decision based on goal and state (simple planner)', async () => {
157
+ test('agent.decide() makes a decision based on goal and state (simple strategy)', async () => {
158
158
  const model = new MockLanguageModelV1({
159
159
  doGenerate,
160
160
  });
@@ -167,7 +167,7 @@ test('agent.decide() makes a decision based on goal and state (simple planner)',
167
167
  },
168
168
  });
169
169
 
170
- const plan = await agent.decide({
170
+ const decision = await agent.decide({
171
171
  goal: 'Make the best move',
172
172
  state: {
173
173
  value: 'playing',
@@ -188,8 +188,8 @@ test('agent.decide() makes a decision based on goal and state (simple planner)',
188
188
  }),
189
189
  });
190
190
 
191
- expect(plan).toBeDefined();
192
- expect(plan!.nextEvent).toEqual(
191
+ expect(decision).toBeDefined();
192
+ expect(decision!.nextEvent).toEqual(
193
193
  expect.objectContaining({
194
194
  type: 'MOVE',
195
195
  })
@@ -243,7 +243,7 @@ test.each([
243
243
  },
244
244
  });
245
245
 
246
- const plan = await agent.decide({
246
+ const decision = await agent.decide({
247
247
  goal: 'Make the best move',
248
248
  state: {
249
249
  value: 'playing',
@@ -263,10 +263,10 @@ test.each([
263
263
  });
264
264
 
265
265
  if (!succeed) {
266
- expect(plan).toBeUndefined();
266
+ expect(decision).toBeUndefined();
267
267
  } else {
268
- expect(plan).toBeDefined();
269
- expect(plan!.nextEvent).toEqual(
268
+ expect(decision).toBeDefined();
269
+ expect(decision!.nextEvent).toEqual(
270
270
  expect.objectContaining({
271
271
  type: 'MOVE',
272
272
  })
@@ -274,3 +274,51 @@ test.each([
274
274
  }
275
275
  }
276
276
  );
277
+
278
+ test.each([['MOVE'], ['FORFEIT']] as const)(
279
+ 'agent.decide() respects allowedEvents constraint (event: %s)',
280
+ async (allowedEventType) => {
281
+ const model = new MockLanguageModelV1({
282
+ doGenerate: async (params: LanguageModelV1CallOptions) => {
283
+ const keys =
284
+ params.mode.type === 'regular'
285
+ ? params.mode.tools?.map((t) => t.name)
286
+ : [];
287
+
288
+ return {
289
+ ...dummyResponseValues,
290
+ finishReason: 'tool-calls',
291
+ toolCalls: [
292
+ {
293
+ toolCallType: 'function',
294
+ toolCallId: 'call-1',
295
+ toolName: keys![0],
296
+ args: `{ "type": "${keys?.[0]}" }`,
297
+ },
298
+ ],
299
+ } as any;
300
+ },
301
+ });
302
+
303
+ const agent = createAgent({
304
+ id: 'test',
305
+ model,
306
+ events: {
307
+ MOVE: z.object({}),
308
+ SKIP: z.object({}),
309
+ FORFEIT: z.object({}),
310
+ },
311
+ });
312
+
313
+ const decision = await agent.decide({
314
+ goal: 'Make the best move',
315
+ state: {
316
+ value: 'playing',
317
+ context: {},
318
+ },
319
+ allowedEvents: [allowedEventType],
320
+ });
321
+
322
+ expect(decision?.nextEvent?.type).toEqual(allowedEventType);
323
+ }
324
+ );
package/src/decide.ts CHANGED
@@ -3,65 +3,77 @@ import {
3
3
  AnyAgent,
4
4
  AgentDecideOptions,
5
5
  AgentDecisionLogic,
6
- AgentDecisionInput,
7
- AgentPlanner,
8
- AgentPlan,
9
- EventsFromZodEventMapping,
10
- AgentPlanInput,
6
+ AgentDecision,
7
+ AgentDecideInput,
11
8
  TransitionData,
9
+ EventFromAgent,
12
10
  } from './types';
13
- import { simplePlanner } from './planners/simple';
14
11
  import { getTransitions } from './utils';
15
12
  import { CoreMessage, CoreTool, tool } from 'ai';
16
13
 
17
- export async function agentDecide<T extends AnyAgent>(
18
- agent: T,
19
- options: AgentDecideOptions<T>
20
- ): Promise<AgentPlan<EventsFromZodEventMapping<T['events']>> | undefined> {
14
+ export async function agentDecide<TAgent extends AnyAgent>(
15
+ agent: TAgent,
16
+ options: AgentDecideOptions<TAgent>
17
+ ): Promise<AgentDecision<TAgent> | undefined> {
21
18
  const resolvedOptions = {
22
19
  ...agent.defaultOptions,
23
20
  ...options,
24
21
  };
25
22
  const {
26
- planner = simplePlanner as AgentPlanner<any>,
23
+ strategy = agent.strategy,
27
24
  goal,
25
+ allowedEvents,
28
26
  events = agent.events,
29
27
  state,
30
28
  machine,
31
29
  model = agent.model,
32
30
  messages,
33
- ...otherPlanInput
31
+ ...otherDecideInput
34
32
  } = resolvedOptions;
35
33
 
34
+ const filteredEventSchemas = allowedEvents
35
+ ? Object.fromEntries(
36
+ Object.entries(events).filter(([key]) => {
37
+ return allowedEvents.includes(key);
38
+ })
39
+ )
40
+ : events;
41
+
36
42
  let attempts = 0;
37
43
 
38
44
  const maxAttempts = resolvedOptions.maxAttempts ?? 2;
39
45
 
40
- let plan;
46
+ let decision: AgentDecision<any> | undefined;
47
+
48
+ const minimalState = {
49
+ value: state.value,
50
+ context: state.context,
51
+ };
41
52
 
42
53
  while (attempts++ < maxAttempts) {
43
- plan = await planner(agent, {
54
+ decision = await strategy(agent, {
44
55
  model,
45
56
  goal,
46
- events,
47
- state,
57
+ events: filteredEventSchemas,
58
+ state: minimalState,
48
59
  machine,
49
60
  messages: messages as CoreMessage[], // TODO: fix UIMessage thing
50
- ...otherPlanInput,
61
+ ...otherDecideInput,
51
62
  });
52
63
 
53
- if (plan?.nextEvent) {
54
- agent.addPlan(plan);
55
- await resolvedOptions.execute?.(plan.nextEvent);
64
+ if (decision?.nextEvent) {
65
+ agent.addDecision(decision);
66
+ await resolvedOptions.execute?.(decision.nextEvent);
67
+ break;
56
68
  }
57
69
  }
58
70
 
59
- return plan;
71
+ return decision;
60
72
  }
61
73
 
62
- export function fromDecision(
63
- agent: AnyAgent,
64
- defaultInput?: AgentDecisionInput
74
+ export function fromDecision<T extends AnyAgent>(
75
+ agent: T,
76
+ defaultInput?: AgentDecideInput<EventFromAgent<T>>
65
77
  ): AgentDecisionLogic<any> {
66
78
  return fromPromise(async ({ input, self }) => {
67
79
  const parentRef = self._parent;
@@ -75,27 +87,25 @@ export function fromDecision(
75
87
  ...defaultInput,
76
88
  ...inputObject,
77
89
  };
78
- const state = {
79
- value: snapshot.value,
80
- context: resolvedInput.context,
81
- };
82
90
 
83
- const plan = await agentDecide(agent, {
91
+ const decision = await agentDecide(agent, {
84
92
  machine: (parentRef as AnyActor).logic,
85
- state,
93
+ state: snapshot,
86
94
  execute: async (event) => {
87
95
  parentRef.send(event);
88
96
  },
89
97
  ...resolvedInput,
98
+ // @ts-ignore
99
+ messages: resolvedInput.messages,
90
100
  });
91
101
 
92
- return plan;
102
+ return decision;
93
103
  }) as AgentDecisionLogic<any>;
94
104
  }
95
105
 
96
106
  export function getToolMap<T extends AnyAgent>(
97
107
  _agent: T,
98
- input: AgentPlanInput<any>
108
+ input: AgentDecideInput<any>
99
109
  ): Record<string, CoreTool<any, any>> | undefined {
100
110
  // Get all of the possible next transitions
101
111
  const transitions: TransitionData[] = input.machine
@@ -0,0 +1,50 @@
1
+ import { generateText } from 'ai';
2
+ import {
3
+ AnyAgent,
4
+ AgentDecideInput,
5
+ AgentDecision,
6
+ PromptTemplate,
7
+ } from '../types';
8
+ import { getMessages } from '../text';
9
+ import { simpleStrategy } from './simple';
10
+ import { convertToXml } from '../utils';
11
+
12
+ const chainOfThoughtPromptTemplate: PromptTemplate<any> = ({
13
+ stateValue,
14
+ context,
15
+ goal,
16
+ }) => {
17
+ return `
18
+ ${convertToXml({ stateValue, context, goal })}
19
+
20
+ How would you achieve the goal? Think step-by-step.
21
+ `.trim();
22
+ };
23
+
24
+ export async function chainOfThoughtStrategy<T extends AnyAgent>(
25
+ agent: T,
26
+ input: AgentDecideInput<any>
27
+ ): Promise<AgentDecision<any> | undefined> {
28
+ const prompt = chainOfThoughtPromptTemplate({
29
+ stateValue: input.state.value,
30
+ context: input.context ?? input.state.context,
31
+ goal: input.goal,
32
+ });
33
+
34
+ const messages = await getMessages(agent, prompt, input);
35
+
36
+ const model = input.model ? agent.wrap(input.model) : agent.model;
37
+
38
+ const result = await generateText({
39
+ model,
40
+ system: input.system ?? agent.description,
41
+ messages,
42
+ });
43
+
44
+ const decision = await simpleStrategy(agent, {
45
+ ...input,
46
+ messages: messages.concat(result.response.messages),
47
+ });
48
+
49
+ return decision;
50
+ }