@statelyai/agent 1.0.0-beta.0 → 1.0.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.
@@ -2,7 +2,6 @@ import { assign, setup, assertEvent, createActor } from 'xstate';
2
2
  import { z } from 'zod';
3
3
  import { createAgent, fromDecision, fromTextStream } from '../src';
4
4
  import { openai } from '@ai-sdk/openai';
5
- import { defaultToolCallTemplate } from '../src/templates/defaultToolCall';
6
5
 
7
6
  const agent = createAgent({
8
7
  name: 'tic-tac-toe-bot',
@@ -24,25 +23,30 @@ const agent = createAgent({
24
23
  }),
25
24
  reset: z.object({}).describe('Reset the game to the initial state'),
26
25
  },
26
+ context: {
27
+ board: z
28
+ .array(z.union([z.literal(null), z.literal('x'), z.literal('o')]))
29
+ .describe('The 3x3 board represented as a 9-element array.'),
30
+ moves: z
31
+ .number()
32
+ .min(0)
33
+ .max(9)
34
+ .describe('The number of moves made in the game.'),
35
+ player: z
36
+ .union([z.literal('x'), z.literal('o')])
37
+ .describe('The current player (x or o)'),
38
+ gameReport: z.string(),
39
+ },
27
40
  });
28
41
 
29
42
  type Player = 'x' | 'o';
30
43
 
31
- interface GameContext {
32
- board: (Player | null)[];
33
- moves: number;
34
- player: Player;
35
- gameReport: string;
36
- events: string[];
37
- }
38
-
39
44
  const initialContext = {
40
45
  board: Array(9).fill(null) as Array<Player | null>,
41
46
  moves: 0,
42
47
  player: 'x' as Player,
43
48
  gameReport: '',
44
- events: [],
45
- } satisfies GameContext;
49
+ } satisfies typeof agent.types.context;
46
50
 
47
51
  function getWinner(board: typeof initialContext.board): Player | null {
48
52
  const lines = [
@@ -65,8 +69,8 @@ function getWinner(board: typeof initialContext.board): Player | null {
65
69
 
66
70
  export const ticTacToeMachine = setup({
67
71
  types: {
68
- context: {} as GameContext,
69
- events: agent.eventTypes,
72
+ context: agent.types.context,
73
+ events: agent.types.events,
70
74
  },
71
75
  actors: {
72
76
  agent: fromDecision(agent),
@@ -82,16 +86,8 @@ export const ticTacToeMachine = setup({
82
86
  },
83
87
  moves: ({ context }) => context.moves + 1,
84
88
  player: ({ context }) => (context.player === 'x' ? 'o' : 'x'),
85
- events: ({ context, event }) => {
86
- return [...context.events, JSON.stringify(event)];
87
- },
88
89
  }),
89
90
  resetGame: assign(initialContext),
90
- recordEvent: assign({
91
- events: ({ context, event }) => {
92
- return [...context.events, JSON.stringify(event)];
93
- },
94
- }),
95
91
  printBoard: ({ context }) => {
96
92
  // Print the context.board in a 3 x 3 grid format
97
93
  let boardString = '';
@@ -173,7 +169,7 @@ export const ticTacToeMachine = setup({
173
169
  src: 'gameReporter',
174
170
  input: ({ context }) => ({
175
171
  context: {
176
- events: context.events,
172
+ events: agent.getObservations().map((o) => o.event),
177
173
  board: context.board,
178
174
  },
179
175
  prompt: 'Provide a short game report analyzing the game.',
package/examples/todo.ts CHANGED
@@ -36,7 +36,9 @@ const machine = setup({
36
36
  todos: Todo[];
37
37
  command: string | null;
38
38
  },
39
- events: {} as typeof agent.eventTypes | { type: 'assist'; command: string },
39
+ events: {} as
40
+ | typeof agent.types.events
41
+ | { type: 'assist'; command: string },
40
42
  },
41
43
  actors: { agent: fromDecision(agent), getFromTerminal },
42
44
  }).createMachine({
package/examples/tutor.ts CHANGED
@@ -28,7 +28,7 @@ const machine = setup({
28
28
  context: {} as {
29
29
  conversation: string[];
30
30
  },
31
- events: agent.eventTypes,
31
+ events: agent.types.events,
32
32
  },
33
33
  actors: { agent: fromDecision(agent), getFromTerminal },
34
34
  }).createMachine({
@@ -35,7 +35,7 @@ const machine = setup({
35
35
  answer: string | null;
36
36
  validation: string | null;
37
37
  },
38
- events: agent.eventTypes,
38
+ events: agent.types.events,
39
39
  },
40
40
  actors: {
41
41
  getFromTerminal,
@@ -78,7 +78,7 @@ const machine = setup({
78
78
  history: string[];
79
79
  count: number;
80
80
  },
81
- events: agent.eventTypes,
81
+ events: agent.types.events,
82
82
  },
83
83
  actors: {
84
84
  agent: fromDecision(agent),
package/examples/wiki.ts CHANGED
@@ -20,7 +20,7 @@ async function main() {
20
20
  console.log(response1.text);
21
21
 
22
22
  const response2 = await agent.generateText({
23
- messages: true,
23
+ messages: (x) => x.select((ctx) => ctx.messages),
24
24
  prompt: 'What about the first one?',
25
25
  });
26
26
 
package/examples/word.ts CHANGED
@@ -12,7 +12,7 @@ const context = {
12
12
 
13
13
  const agent = createAgent({
14
14
  name: 'word',
15
- model: openai('gpt-4-1106-preview'),
15
+ model: openai('gpt-4o'),
16
16
  events: {
17
17
  'agent.guessLetter': z.object({
18
18
  letter: z.string().min(1).max(1).describe('The letter guessed'),
@@ -36,18 +36,21 @@ const agent = createAgent({
36
36
  const wordGuesserMachine = setup({
37
37
  types: {
38
38
  context: {} as typeof context,
39
- events: agent.eventTypes,
39
+ events: agent.types.events,
40
40
  },
41
41
  actors: {
42
42
  agent: fromDecision(agent),
43
43
  getFromTerminal,
44
44
  },
45
+ actions: {
46
+ resetContext: assign(context),
47
+ },
45
48
  }).createMachine({
46
49
  initial: 'providingWord',
47
50
  context,
48
51
  states: {
49
52
  providingWord: {
50
- entry: assign(context),
53
+ entry: 'resetContext',
51
54
  invoke: {
52
55
  src: 'getFromTerminal',
53
56
  input: 'Enter a word, and an agent will try to guess it.',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@statelyai/agent",
3
- "version": "1.0.0-beta.0",
4
- "description": "",
3
+ "version": "1.0.0",
4
+ "description": "Stateful agents that make decisions based on finite-state machine models",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
@@ -9,27 +9,35 @@
9
9
  "build": "tsup src/index.ts --format cjs,esm --dts",
10
10
  "lint": "tsc --noEmit",
11
11
  "test": "vitest",
12
+ "test:ci": "vitest --run",
12
13
  "example": "ts-node examples/helpers/runner.ts",
13
14
  "prepublishOnly": "tsup src/index.ts --format cjs,esm --dts",
14
15
  "changeset": "changeset",
15
16
  "release": "changeset publish",
16
17
  "version": "changeset version"
17
18
  },
18
- "keywords": [],
19
+ "keywords": [
20
+ "ai",
21
+ "state machine",
22
+ "agent",
23
+ "rl",
24
+ "reinforcement learning"
25
+ ],
19
26
  "author": "",
20
27
  "license": "MIT",
21
28
  "devDependencies": {
22
29
  "@changesets/changelog-github": "^0.5.0",
23
- "@changesets/cli": "^2.27.5",
30
+ "@changesets/cli": "^2.27.7",
24
31
  "@langchain/community": "^0.0.53",
25
32
  "@langchain/core": "^0.1.63",
26
33
  "@langchain/openai": "^0.0.28",
27
- "@types/node": "^20.14.2",
34
+ "@types/node": "^20.14.10",
35
+ "@types/object-hash": "^3.0.6",
28
36
  "dotenv": "^16.4.5",
29
37
  "json-schema-to-ts": "^3.1.0",
30
38
  "ts-node": "^10.9.2",
31
39
  "tsup": "^8.1.0",
32
- "typescript": "^5.4.5",
40
+ "typescript": "^5.5.3",
33
41
  "vitest": "^1.6.0",
34
42
  "wikipedia": "^2.1.2",
35
43
  "zod": "^3.23.8"
@@ -38,11 +46,11 @@
38
46
  "access": "public"
39
47
  },
40
48
  "dependencies": {
41
- "@ai-sdk/openai": "^0.0.13",
49
+ "@ai-sdk/openai": "^0.0.31",
42
50
  "@xstate/graph": "^2.0.0",
43
- "ai": "^3.1.32",
44
- "nanoid": "^5.0.7",
45
- "xstate": "^5.13.2"
51
+ "ai": "^3.2.22",
52
+ "object-hash": "^3.0.0",
53
+ "xstate": "^5.15.0"
46
54
  },
47
55
  "packageManager": "pnpm@8.11.0"
48
56
  }
package/src/agent.test.ts CHANGED
@@ -1,6 +1,8 @@
1
- import { test, expect } from 'vitest';
1
+ import { test, expect, vi } from 'vitest';
2
2
  import { createAgent, type AIAdapter } from './';
3
3
  import { createActor, createMachine } from 'xstate';
4
+ import { GenerateTextResult } from 'ai';
5
+ import { z } from 'zod';
4
6
 
5
7
  test('an agent has the expected interface', () => {
6
8
  const agent = createAgent({
@@ -13,11 +15,16 @@ test('an agent has the expected interface', () => {
13
15
  expect(agent.generateText).toBeDefined();
14
16
  expect(agent.streamText).toBeDefined();
15
17
 
16
- expect(agent.addFeedback).toBeDefined();
17
18
  expect(agent.addMessage).toBeDefined();
18
19
  expect(agent.addObservation).toBeDefined();
20
+ expect(agent.addFeedback).toBeDefined();
19
21
  expect(agent.addPlan).toBeDefined();
20
22
 
23
+ expect(agent.getMessages).toBeDefined();
24
+ expect(agent.getObservations).toBeDefined();
25
+ expect(agent.getFeedback).toBeDefined();
26
+ expect(agent.getPlans).toBeDefined();
27
+
21
28
  expect(agent.interact).toBeDefined();
22
29
  });
23
30
 
@@ -45,6 +52,11 @@ test('agent.addMessage() adds to message history', () => {
45
52
  content: 'msg 1',
46
53
  })
47
54
  );
55
+ expect(agent.getMessages()).toContainEqual(
56
+ expect.objectContaining({
57
+ content: 'msg 1',
58
+ })
59
+ );
48
60
 
49
61
  expect(agent.select((c) => c.messages)).toContainEqual(
50
62
  expect.objectContaining({
@@ -53,6 +65,13 @@ test('agent.addMessage() adds to message history', () => {
53
65
  timestamp: expect.any(Number),
54
66
  })
55
67
  );
68
+ expect(agent.getMessages()).toContainEqual(
69
+ expect.objectContaining({
70
+ content: 'response 1',
71
+ sessionId: expect.any(String),
72
+ timestamp: expect.any(Number),
73
+ })
74
+ );
56
75
  });
57
76
 
58
77
  test('agent.addFeedback() adds to feedback', () => {
@@ -83,6 +102,17 @@ test('agent.addFeedback() adds to feedback', () => {
83
102
  timestamp: expect.any(Number),
84
103
  })
85
104
  );
105
+ expect(agent.getFeedback()).toContainEqual(
106
+ expect.objectContaining({
107
+ attributes: {
108
+ score: -1,
109
+ },
110
+ goal: 'Win the game',
111
+ observationId: 'obs-1',
112
+ sessionId: expect.any(String),
113
+ timestamp: expect.any(Number),
114
+ })
115
+ );
86
116
  });
87
117
 
88
118
  test('agent.addObservation() adds to observations', () => {
@@ -111,6 +141,46 @@ test('agent.addObservation() adds to observations', () => {
111
141
  );
112
142
  });
113
143
 
144
+ test('agent.addObservation() adds to observations with machine hash', () => {
145
+ const agent = createAgent({
146
+ name: 'test',
147
+ events: {},
148
+ model: {} as any,
149
+ });
150
+
151
+ const machine = createMachine({
152
+ initial: 'playing',
153
+ states: {
154
+ playing: {
155
+ on: {
156
+ play: 'lost',
157
+ },
158
+ },
159
+ lost: {},
160
+ },
161
+ });
162
+
163
+ const observation = agent.addObservation({
164
+ prevState: { value: 'playing', context: {} },
165
+ event: { type: 'play', position: 3 },
166
+ state: { value: 'lost', context: {} },
167
+ machine,
168
+ });
169
+
170
+ expect(observation.sessionId).toEqual(agent.sessionId);
171
+
172
+ expect(agent.select((c) => c.observations)).toContainEqual(
173
+ expect.objectContaining({
174
+ prevState: { value: 'playing', context: {} },
175
+ event: { type: 'play', position: 3 },
176
+ state: { value: 'lost', context: {} },
177
+ machineHash: expect.any(String),
178
+ sessionId: expect.any(String),
179
+ timestamp: expect.any(Number),
180
+ })
181
+ );
182
+ });
183
+
114
184
  test('agent.interact() observes machine actors (no 2nd arg)', () => {
115
185
  const machine = createMachine({
116
186
  initial: 'a',
@@ -140,6 +210,12 @@ test('agent.interact() observes machine actors (no 2nd arg)', () => {
140
210
  state: expect.objectContaining({ value: 'a' }),
141
211
  })
142
212
  );
213
+ expect(agent.getObservations()).toContainEqual(
214
+ expect.objectContaining({
215
+ prevState: undefined,
216
+ state: expect.objectContaining({ value: 'a' }),
217
+ })
218
+ );
143
219
 
144
220
  actor.send({ type: 'NEXT' });
145
221
 
@@ -175,7 +251,8 @@ test('Agents can use a custom adapter', async () => {
175
251
  expect(res.text).toEqual('Response');
176
252
  });
177
253
 
178
- test.skip('You can listen for emitted agent events', () => {
254
+ test('You can listen for feedback events', () => {
255
+ const fn = vi.fn();
179
256
  const agent = createAgent({
180
257
  name: 'test',
181
258
  events: {},
@@ -183,5 +260,100 @@ test.skip('You can listen for emitted agent events', () => {
183
260
  model: {} as any,
184
261
  });
185
262
 
186
- agent.on('feedback', (x) => {});
263
+ agent.on('feedback', fn);
264
+
265
+ agent.addFeedback({
266
+ attributes: {
267
+ score: -1,
268
+ },
269
+ goal: 'Win the game',
270
+ observationId: 'obs-1',
271
+ });
272
+
273
+ expect(fn).toHaveBeenCalled();
274
+ });
275
+
276
+ test('You can listen for plan events', async () => {
277
+ const fn = vi.fn();
278
+ const agent = createAgent({
279
+ name: 'test',
280
+ model: {} as any,
281
+ events: {
282
+ WIN: z.object({}),
283
+ },
284
+ adapter: {
285
+ generateText: async (arg) => {
286
+ const keys = Object.keys(arg.tools!);
287
+
288
+ if (keys.length !== 1) {
289
+ throw new Error('Expected only 1 choice');
290
+ }
291
+
292
+ return {
293
+ toolResults: [
294
+ {
295
+ result: {
296
+ type: keys[0],
297
+ },
298
+ },
299
+ ],
300
+ } as any as GenerateTextResult<any>;
301
+ },
302
+ streamText: {} as any,
303
+ },
304
+ });
305
+
306
+ agent.on('plan', fn);
307
+
308
+ await agent.decide({
309
+ goal: 'Win the game',
310
+ state: {
311
+ value: 'playing',
312
+ context: {},
313
+ },
314
+ machine: createMachine({
315
+ initial: 'playing',
316
+ states: {
317
+ playing: {
318
+ on: {
319
+ WIN: {
320
+ target: 'won',
321
+ },
322
+ },
323
+ },
324
+ won: {},
325
+ },
326
+ }),
327
+ });
328
+
329
+ expect(fn).toHaveBeenCalledWith(
330
+ expect.objectContaining({
331
+ plan: expect.objectContaining({
332
+ nextEvent: {
333
+ type: 'WIN',
334
+ },
335
+ }),
336
+ })
337
+ );
338
+ });
339
+
340
+ test('agent.types provides context and event types', () => {
341
+ const agent = createAgent({
342
+ model: {} as any,
343
+ events: {
344
+ setScore: z.object({
345
+ score: z.number(),
346
+ }),
347
+ },
348
+ context: {
349
+ score: z.number(),
350
+ },
351
+ });
352
+
353
+ agent.types satisfies { context: any; events: any };
354
+
355
+ agent.types.context satisfies { score: number };
356
+
357
+ // @ts-expect-error
358
+ agent.types.context satisfies { score: string };
187
359
  });
package/src/agent.ts CHANGED
@@ -7,11 +7,11 @@ import {
7
7
  Observer,
8
8
  toObserver,
9
9
  } from 'xstate';
10
- import { ZodEventMapping } from './schemas';
10
+ import { ZodContextMapping, ZodEventMapping } from './schemas';
11
11
  import {
12
12
  Agent,
13
13
  AgentLogic,
14
- AgentMessageHistory,
14
+ AgentMessage,
15
15
  AgentPlanner,
16
16
  EventsFromZodEventMapping,
17
17
  GenerateTextOptions,
@@ -20,12 +20,14 @@ import {
20
20
  ObservedState,
21
21
  AgentObservationInput,
22
22
  AgentMemoryContext,
23
+ AgentObservation,
24
+ ContextFromZodContextMapping,
23
25
  } from './types';
24
26
  import { simplePlanner } from './planners/simplePlanner';
25
27
  import { agentGenerateText, agentStreamText } from './text';
26
28
  import { agentDecide } from './decision';
27
29
  import { vercelAdapter } from './adapters/vercel';
28
- import { nanoid } from 'nanoid';
30
+ import { getMachineHash, randomId } from './utils';
29
31
 
30
32
  export const agentLogic: AgentLogic<AnyEventObject> = fromTransition(
31
33
  (state, event, { emit }) => {
@@ -80,24 +82,42 @@ export const agentLogic: AgentLogic<AnyEventObject> = fromTransition(
80
82
  );
81
83
 
82
84
  export function createAgent<
85
+ const TContextSchema extends ZodContextMapping,
83
86
  const TEventSchemas extends ZodEventMapping,
84
- TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>
87
+ TEvents extends EventObject = EventsFromZodEventMapping<TEventSchemas>,
88
+ TContext = ContextFromZodContextMapping<TContextSchema>
85
89
  >({
86
90
  name,
87
91
  description,
88
92
  model,
89
93
  events,
90
- planner = simplePlanner as AgentPlanner<Agent<TEvents>>,
94
+ context,
95
+ planner = simplePlanner as AgentPlanner<Agent<TContext, TEvents>>,
91
96
  stringify = JSON.stringify,
92
97
  getMemory,
93
98
  logic = agentLogic as AgentLogic<TEvents>,
94
99
  adapter = vercelAdapter,
95
100
  ...generateTextOptions
96
101
  }: {
102
+ /**
103
+ * The unique identifier for the agent.
104
+ *
105
+ * This should be the same across all sessions of a specific agent, as it can be
106
+ * used to retrieve memory for this agent.
107
+ *
108
+ * @example
109
+ * ```ts
110
+ * const agent = createAgent({
111
+ * id: 'recipe-assistant',
112
+ * // ...
113
+ * });
114
+ * ```
115
+ */
116
+ id?: string;
97
117
  /**
98
118
  * The name of the agent
99
119
  */
100
- name: string;
120
+ name?: string;
101
121
  /**
102
122
  * A description of the role of the agent
103
123
  */
@@ -107,21 +127,22 @@ export function createAgent<
107
127
  * that the agent knows about.
108
128
  */
109
129
  events: TEventSchemas;
110
- planner?: AgentPlanner<Agent<TEvents>>;
130
+ context?: TContextSchema;
131
+ planner?: AgentPlanner<Agent<TContext, TEvents>>;
111
132
  stringify?: typeof JSON.stringify;
112
133
  /**
113
134
  * A function that retrieves the agent's long term memory
114
135
  */
115
- getMemory?: (agent: Agent<any>) => AgentLongTermMemory;
136
+ getMemory?: (agent: Agent<TContext, TEvents>) => AgentLongTermMemory;
116
137
  /**
117
138
  * Agent logic
118
139
  */
119
140
  logic?: AgentLogic<TEvents>;
120
141
  adapter?: AIAdapter;
121
- } & GenerateTextOptions): Agent<TEvents> {
122
- const messageHistoryListeners: Observer<AgentMessageHistory>[] = [];
142
+ } & GenerateTextOptions): Agent<TContext, TEvents> {
143
+ const messageHistoryListeners: Observer<AgentMessage>[] = [];
123
144
 
124
- const agent = createActor(logic) as unknown as Agent<TEvents>;
145
+ const agent = createActor(logic) as unknown as Agent<TContext, TEvents>;
125
146
  agent.events = events;
126
147
  agent.model = model;
127
148
  agent.name = name;
@@ -144,7 +165,7 @@ export function createAgent<
144
165
  agent.addMessage = (messageInput) => {
145
166
  const message = {
146
167
  ...messageInput,
147
- id: messageInput.id ?? nanoid(),
168
+ id: messageInput.id ?? randomId(),
148
169
  timestamp: messageInput.timestamp ?? Date.now(),
149
170
  sessionId: agent.sessionId,
150
171
  };
@@ -155,6 +176,7 @@ export function createAgent<
155
176
 
156
177
  return message;
157
178
  };
179
+ agent.getMessages = () => agent.getSnapshot().context.messages;
158
180
 
159
181
  agent.generateText = (opts) => agentGenerateText(agent, opts);
160
182
 
@@ -172,14 +194,21 @@ export function createAgent<
172
194
  });
173
195
  return feedback;
174
196
  };
197
+ agent.getFeedback = () => agent.getSnapshot().context.feedback;
175
198
 
176
199
  agent.addObservation = (observationInput) => {
200
+ const { prevState, event, state } = observationInput;
177
201
  const observation = {
178
- ...observationInput,
179
- id: observationInput.id ?? nanoid(),
202
+ prevState,
203
+ event,
204
+ state,
205
+ id: observationInput.id ?? randomId(),
180
206
  sessionId: agent.sessionId,
181
207
  timestamp: observationInput.timestamp ?? Date.now(),
182
- };
208
+ machineHash: observationInput.machine
209
+ ? getMachineHash(observationInput.machine)
210
+ : undefined,
211
+ } satisfies AgentObservation<any>;
183
212
 
184
213
  agent.send({
185
214
  type: 'agent.observe',
@@ -188,6 +217,7 @@ export function createAgent<
188
217
 
189
218
  return observation;
190
219
  };
220
+ agent.getObservations = () => agent.getSnapshot().context.observations;
191
221
 
192
222
  agent.addPlan = (plan) => {
193
223
  agent.send({
@@ -195,8 +225,9 @@ export function createAgent<
195
225
  plan,
196
226
  });
197
227
  };
228
+ agent.getPlans = () => agent.getSnapshot().context.plans;
198
229
 
199
- agent.interact = (actorRef, getInput) => {
230
+ agent.interact = ((actorRef, getInput) => {
200
231
  let prevState: ObservedState | undefined = undefined;
201
232
  let subscribed = true;
202
233
 
@@ -234,7 +265,8 @@ export function createAgent<
234
265
  event: inspEvent.event,
235
266
  prevState,
236
267
  state: inspEvent.snapshot as any,
237
- };
268
+ machine: (actorRef as any).src,
269
+ } satisfies AgentObservationInput;
238
270
 
239
271
  await handleObservation(observationInput);
240
272
  },
@@ -246,6 +278,7 @@ export function createAgent<
246
278
  prevState: undefined,
247
279
  event: { type: '' }, // TODO: unknown events?
248
280
  state: actorRef.getSnapshot(),
281
+ machine: (actorRef as any).src,
249
282
  });
250
283
  }
251
284
 
@@ -254,7 +287,9 @@ export function createAgent<
254
287
  subscribed = false;
255
288
  }, // TODO: make this actually unsubscribe
256
289
  };
257
- };
290
+ }) as typeof agent.interact;
291
+
292
+ agent.types = {} as any;
258
293
 
259
294
  agent.start();
260
295
 
package/src/decision.ts CHANGED
@@ -1,17 +1,18 @@
1
1
  import { AnyMachineSnapshot, fromPromise } from 'xstate';
2
2
  import {
3
- Agent,
3
+ AnyAgent,
4
4
  AgentDecideOptions,
5
5
  AgentDecisionLogic,
6
6
  AgentDecisionInput,
7
7
  AgentPlanner,
8
+ AgentPlan,
8
9
  } from './types';
9
10
  import { simplePlanner } from './planners/simplePlanner';
10
11
 
11
- export async function agentDecide<T extends Agent<any>>(
12
+ export async function agentDecide<T extends AnyAgent>(
12
13
  agent: T,
13
14
  options: AgentDecideOptions
14
- ) {
15
+ ): Promise<AgentPlan<any> | undefined> {
15
16
  const resolvedOptions = {
16
17
  ...agent.defaultOptions,
17
18
  ...options,
@@ -44,9 +45,9 @@ export async function agentDecide<T extends Agent<any>>(
44
45
  }
45
46
 
46
47
  export function fromDecision(
47
- agent: Agent<any>,
48
+ agent: AnyAgent,
48
49
  defaultInput?: AgentDecisionInput
49
- ) {
50
+ ): AgentDecisionLogic<any> {
50
51
  return fromPromise(async ({ input, self }) => {
51
52
  const parentRef = self._parent;
52
53
  if (!parentRef) {