@statelyai/agent 1.1.6 → 2.0.0-next.1

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 (62) hide show
  1. package/.changeset/cyan-carpets-perform.md +5 -0
  2. package/.changeset/fast-donkeys-argue.md +5 -0
  3. package/.changeset/light-hats-drive.md +9 -0
  4. package/.changeset/old-jobs-check.md +5 -0
  5. package/.changeset/pre.json +13 -0
  6. package/.vscode/launch.json +6 -0
  7. package/CHANGELOG.md +22 -0
  8. package/dist/index.d.mts +262 -171
  9. package/dist/index.d.ts +262 -171
  10. package/dist/index.js +383 -274
  11. package/dist/index.mjs +386 -272
  12. package/examples/chatbot-alt.ts +57 -0
  13. package/examples/chatbot.ts +12 -17
  14. package/examples/cot.ts +26 -23
  15. package/examples/customer-service-sim.ts +107 -0
  16. package/examples/email.ts +37 -41
  17. package/examples/example.ts +6 -6
  18. package/examples/executor.ts +66 -0
  19. package/examples/goal.ts +12 -12
  20. package/examples/helpers/helpers.ts +26 -14
  21. package/examples/joke.ts +79 -76
  22. package/examples/jugs.ts +125 -0
  23. package/examples/multi.ts +5 -5
  24. package/examples/newspaper.ts +98 -104
  25. package/examples/number.ts +6 -5
  26. package/examples/raffle.ts +11 -12
  27. package/examples/river-crossing.ts +140 -0
  28. package/examples/sandbox.ts +1 -1
  29. package/examples/simple.ts +5 -3
  30. package/examples/summary.ts +121 -0
  31. package/examples/support.ts +6 -6
  32. package/examples/ticTacToe.ts +86 -45
  33. package/examples/todo.ts +7 -7
  34. package/examples/tutor.ts +15 -15
  35. package/examples/verify.ts +3 -3
  36. package/examples/weather.ts +6 -9
  37. package/examples/wiki.ts +27 -8
  38. package/examples/word.ts +16 -11
  39. package/package.json +16 -11
  40. package/readme.md +1 -1
  41. package/src/agent-experimental.ts +1 -1
  42. package/src/agent.test.ts +243 -214
  43. package/src/agent.ts +286 -95
  44. package/src/decide.test.ts +276 -0
  45. package/src/decide.ts +163 -0
  46. package/src/index.ts +1 -1
  47. package/src/middleware.ts +91 -0
  48. package/src/mockModel.ts +47 -0
  49. package/src/planners/shortestPath.test.ts +94 -0
  50. package/src/planners/shortestPath.ts +177 -0
  51. package/src/planners/simple.ts +105 -0
  52. package/src/strategies/chain-of-note.ts +6 -55
  53. package/src/text.ts +51 -144
  54. package/src/types.ts +187 -212
  55. package/src/utils.ts +48 -4
  56. package/vitest.config.ts +9 -3
  57. package/src/adapters/vercel.ts +0 -7
  58. package/src/decision.test.ts +0 -179
  59. package/src/decision.ts +0 -84
  60. package/src/memory.ts +0 -25
  61. package/src/planners/shortestPathPlanner.ts +0 -22
  62. package/src/planners/simplePlanner.ts +0 -139
package/dist/index.js CHANGED
@@ -38,10 +38,10 @@ __export(src_exports, {
38
38
  module.exports = __toCommonJS(src_exports);
39
39
 
40
40
  // src/agent.ts
41
- var import_xstate3 = require("xstate");
41
+ var import_xstate4 = require("xstate");
42
42
 
43
- // src/planners/simplePlanner.ts
44
- var import_ai = require("ai");
43
+ // src/planners/simple.ts
44
+ var import_ai3 = require("ai");
45
45
 
46
46
  // src/utils.ts
47
47
  var import_object_hash = __toESM(require("object-hash"));
@@ -79,10 +79,10 @@ function getAllMachineTransitions(stateNode) {
79
79
  function wrapInXml(tagName, content) {
80
80
  return `<${tagName}>${content}</${tagName}>`;
81
81
  }
82
- function randomId() {
82
+ function randomId(prefix) {
83
83
  const timestamp = Date.now().toString(36);
84
84
  const random = Math.random().toString(36).substring(2, 9);
85
- return timestamp + random;
85
+ return `${prefix || ""}${timestamp}${random}`;
86
86
  }
87
87
  var machineHashes = /* @__PURE__ */ new WeakMap();
88
88
  function getMachineHash(machine) {
@@ -92,6 +92,26 @@ function getMachineHash(machine) {
92
92
  machineHashes.set(machine, machineHash);
93
93
  return machineHash;
94
94
  }
95
+ function isActorRef(actorRefLike) {
96
+ return "src" in actorRefLike && "system" in actorRefLike && "sessionId" in actorRefLike;
97
+ }
98
+ function getTransitions(state, machine) {
99
+ if (!machine) {
100
+ return [];
101
+ }
102
+ const resolvedState = machine.resolveState({
103
+ ...state,
104
+ // Need this property defined to make TS happy
105
+ context: state.context
106
+ });
107
+ return getAllTransitions(resolvedState);
108
+ }
109
+ function isMachineActor(actor) {
110
+ return "src" in actor && typeof actor.src === "object" && actor.src !== null && "definition" in actor.src;
111
+ }
112
+
113
+ // src/planners/simple.ts
114
+ var import_xstate3 = require("xstate");
95
115
 
96
116
  // src/templates/defaultText.ts
97
117
  var defaultTextTemplate = (data) => {
@@ -106,6 +126,7 @@ ${data.goal}
106
126
  };
107
127
 
108
128
  // src/text.ts
129
+ var import_ai = require("ai");
109
130
  var import_xstate = require("xstate");
110
131
  async function getMessages(agent, prompt, options) {
111
132
  let messages = [];
@@ -120,120 +141,26 @@ async function getMessages(agent, prompt, options) {
120
141
  });
121
142
  return messages;
122
143
  }
123
- async function agentGenerateText(agent, options) {
124
- const resolvedOptions = {
125
- ...agent.defaultOptions,
126
- ...options,
127
- correlationId: options.correlationId ?? randomId()
128
- };
129
- const template = resolvedOptions.template ?? defaultTextTemplate;
130
- const id = randomId();
131
- const goal = typeof resolvedOptions.prompt === "string" ? resolvedOptions.prompt : await resolvedOptions.prompt(agent);
132
- const promptWithContext = template({
133
- goal,
134
- context: resolvedOptions.context
135
- });
136
- const messages = await getMessages(agent, promptWithContext, resolvedOptions);
137
- agent.addMessage({
138
- id,
139
- role: "user",
140
- content: promptWithContext,
141
- timestamp: Date.now(),
142
- correlationId: resolvedOptions.correlationId,
143
- parentCorrelationId: resolvedOptions.parentCorrelationId
144
- });
145
- const result = await agent.adapter.generateText({
146
- ...resolvedOptions,
147
- prompt: void 0,
148
- messages
149
- });
150
- agent.addMessage({
151
- content: result.text,
152
- id,
153
- role: "assistant",
154
- timestamp: Date.now(),
155
- responseId: id,
156
- result,
157
- correlationId: resolvedOptions.correlationId,
158
- parentCorrelationId: resolvedOptions.parentCorrelationId
159
- });
160
- return {
161
- ...result,
162
- parentCorrelationId: resolvedOptions.parentCorrelationId,
163
- correlationId: resolvedOptions.correlationId
164
- };
165
- }
166
- async function agentStreamText(agent, options) {
167
- const resolvedOptions = {
168
- ...agent.defaultOptions,
169
- ...options,
170
- correlationId: options.correlationId ?? randomId()
171
- };
172
- const template = resolvedOptions.template ?? defaultTextTemplate;
173
- const id = randomId();
174
- const goal = typeof resolvedOptions.prompt === "string" ? resolvedOptions.prompt : await resolvedOptions.prompt(agent);
175
- const promptWithContext = template({
176
- goal,
177
- context: resolvedOptions.context
178
- });
179
- const messages = await getMessages(agent, promptWithContext, resolvedOptions);
180
- agent.addMessage({
181
- role: "user",
182
- content: promptWithContext,
183
- id,
184
- timestamp: Date.now(),
185
- correlationId: resolvedOptions.correlationId,
186
- parentCorrelationId: resolvedOptions.parentCorrelationId
187
- });
188
- const result = await agent.adapter.streamText({
189
- ...resolvedOptions,
190
- prompt: void 0,
191
- messages,
192
- onFinish: async (res) => {
193
- agent.addMessage({
194
- role: "assistant",
195
- result: {
196
- text: res.text,
197
- finishReason: res.finishReason,
198
- logprobs: void 0,
199
- responseMessages: [],
200
- toolCalls: [],
201
- toolResults: [],
202
- usage: res.usage,
203
- warnings: res.warnings,
204
- rawResponse: res.rawResponse,
205
- roundtrips: [],
206
- // TODO: how do we get this information?,
207
- steps: res.steps,
208
- response: res.response,
209
- experimental_providerMetadata: res.experimental_providerMetadata
210
- },
211
- content: res.text,
212
- id: randomId(),
213
- timestamp: Date.now(),
214
- responseId: id,
215
- correlationId: resolvedOptions.correlationId,
216
- parentCorrelationId: resolvedOptions.parentCorrelationId
217
- });
218
- }
219
- });
220
- return {
221
- ...result,
222
- textStream: result.textStream,
223
- fullStream: result.fullStream,
224
- parentCorrelationId: resolvedOptions.parentCorrelationId,
225
- correlationId: resolvedOptions.correlationId
226
- };
227
- }
228
- function fromTextStream(agent, defaultOptions) {
144
+ function fromTextStream(agent, options) {
145
+ const template = options?.template ?? defaultTextTemplate;
229
146
  return (0, import_xstate.fromObservable)(({ input }) => {
230
147
  const observers = /* @__PURE__ */ new Set();
231
148
  (async () => {
232
- const result = await agentStreamText(agent, {
233
- ...defaultOptions,
234
- ...input,
149
+ const model = input.model ? agent.wrap(input.model) : agent.model;
150
+ const goal = typeof input.prompt === "string" ? input.prompt : await input.prompt(agent);
151
+ const promptWithContext = template({
152
+ goal,
235
153
  context: input.context
236
154
  });
155
+ const messages = await getMessages(agent, promptWithContext, input);
156
+ const result = await (0, import_ai.streamText)({
157
+ ...options,
158
+ ...input,
159
+ prompt: void 0,
160
+ // overwritten by messages
161
+ model,
162
+ messages
163
+ });
237
164
  for await (const part of result.fullStream) {
238
165
  if (part.type === "text-delta") {
239
166
  observers.forEach((observer) => {
@@ -255,32 +182,97 @@ function fromTextStream(agent, defaultOptions) {
255
182
  };
256
183
  });
257
184
  }
258
- function fromText(agent, defaultOptions) {
185
+ function fromText(agent, options) {
186
+ const resolvedOptions = {
187
+ ...agent.defaultOptions,
188
+ ...options
189
+ };
190
+ const template = resolvedOptions.template ?? defaultTextTemplate;
259
191
  return (0, import_xstate.fromPromise)(async ({ input }) => {
260
- return await agentGenerateText(agent, {
261
- ...input,
262
- ...defaultOptions,
192
+ const goal = typeof input.prompt === "string" ? input.prompt : await input.prompt(agent);
193
+ const promptWithContext = template({
194
+ goal,
263
195
  context: input.context
264
196
  });
197
+ const messages = await getMessages(agent, promptWithContext, input);
198
+ const model = input.model ? agent.wrap(input.model) : agent.model;
199
+ return await (0, import_ai.generateText)({
200
+ ...input,
201
+ ...options,
202
+ prompt: void 0,
203
+ messages,
204
+ model
205
+ });
265
206
  });
266
207
  }
267
208
 
268
- // src/planners/simplePlanner.ts
269
- function getTransitions(state, machine) {
270
- if (!machine) {
271
- return [];
209
+ // src/decide.ts
210
+ var import_xstate2 = require("xstate");
211
+ var import_ai2 = require("ai");
212
+ async function agentDecide(agent, options) {
213
+ const resolvedOptions = {
214
+ ...agent.defaultOptions,
215
+ ...options
216
+ };
217
+ const {
218
+ planner = simplePlanner,
219
+ goal,
220
+ events = agent.events,
221
+ state,
222
+ machine,
223
+ model = agent.model,
224
+ messages,
225
+ ...otherPlanInput
226
+ } = resolvedOptions;
227
+ let attempts = 0;
228
+ const maxAttempts = resolvedOptions.maxAttempts ?? 2;
229
+ let plan;
230
+ while (attempts++ < maxAttempts) {
231
+ plan = await planner(agent, {
232
+ model,
233
+ goal,
234
+ events,
235
+ state,
236
+ machine,
237
+ messages,
238
+ // TODO: fix UIMessage thing
239
+ ...otherPlanInput
240
+ });
241
+ if (plan?.nextEvent) {
242
+ agent.addPlan(plan);
243
+ await resolvedOptions.execute?.(plan.nextEvent);
244
+ }
272
245
  }
273
- const resolvedState = machine.resolveState(state);
274
- return getAllTransitions(resolvedState);
246
+ return plan;
275
247
  }
276
- var simplePlannerPromptTemplate = (data) => {
277
- return `
278
- ${defaultTextTemplate(data)}
279
-
280
- 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.
281
- `.trim();
282
- };
283
- async function simplePlanner(agent, input) {
248
+ function fromDecision(agent, defaultInput) {
249
+ return (0, import_xstate2.fromPromise)(async ({ input, self }) => {
250
+ const parentRef = self._parent;
251
+ if (!parentRef) {
252
+ return;
253
+ }
254
+ const snapshot = parentRef.getSnapshot();
255
+ const inputObject = typeof input === "string" ? { goal: input } : input;
256
+ const resolvedInput = {
257
+ ...defaultInput,
258
+ ...inputObject
259
+ };
260
+ const state = {
261
+ value: snapshot.value,
262
+ context: resolvedInput.context
263
+ };
264
+ const plan = await agentDecide(agent, {
265
+ machine: parentRef.logic,
266
+ state,
267
+ execute: async (event) => {
268
+ parentRef.send(event);
269
+ },
270
+ ...resolvedInput
271
+ });
272
+ return plan;
273
+ });
274
+ }
275
+ function getToolMap(_agent, input) {
284
276
  const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
285
277
  eventType,
286
278
  description
@@ -305,7 +297,7 @@ async function simplePlanner(agent, input) {
305
297
  if (!toolZodType) {
306
298
  continue;
307
299
  }
308
- toolMap[toolTransitionData.name] = (0, import_ai.tool)({
300
+ toolMap[toolTransitionData.name] = (0, import_ai2.tool)({
309
301
  description: toolZodType?.description ?? toolTransitionData.description,
310
302
  parameters: toolZodType,
311
303
  execute: async (params) => {
@@ -320,17 +312,56 @@ async function simplePlanner(agent, input) {
320
312
  if (!Object.keys(toolMap).length) {
321
313
  return void 0;
322
314
  }
315
+ return toolMap;
316
+ }
317
+
318
+ // src/planners/simple.ts
319
+ var simplePlannerPromptTemplate = (data) => {
320
+ return `
321
+ ${defaultTextTemplate(data)}
322
+
323
+ 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.
324
+ `.trim();
325
+ };
326
+ async function simplePlanner(agent, input) {
327
+ const toolMap = getToolMap(agent, input);
328
+ if (!toolMap) {
329
+ return void 0;
330
+ }
323
331
  const prompt = simplePlannerPromptTemplate({
324
332
  context: input.state.context,
325
333
  goal: input.goal
326
334
  });
327
335
  const messages = await getMessages(agent, prompt, input);
328
- const result = await agent.generateText({
329
- toolChoice: "required",
330
- ...input,
331
- prompt,
336
+ const model = input.model ? agent.wrap(input.model) : agent.model;
337
+ const {
338
+ state,
339
+ machine,
340
+ previousPlan,
341
+ events,
342
+ goal,
343
+ model: _,
344
+ ...rest
345
+ } = input;
346
+ const machineState = input.machine ? input.machine.resolveState({
347
+ ...input.state,
348
+ context: input.state.context
349
+ }) : void 0;
350
+ const result = await (0, import_ai3.generateText)({
351
+ ...rest,
352
+ system: input.system ?? agent.description,
353
+ model,
332
354
  messages,
333
- tools: toolMap
355
+ tools: toolMap,
356
+ toolChoice: input.toolChoice ?? "required"
357
+ });
358
+ result.response.messages.forEach((m) => {
359
+ const message = m;
360
+ agent.addMessage({
361
+ ...message,
362
+ id: randomId(),
363
+ timestamp: Date.now()
364
+ });
334
365
  });
335
366
  const singleResult = result.toolResults[0];
336
367
  if (!singleResult) {
@@ -338,91 +369,94 @@ async function simplePlanner(agent, input) {
338
369
  return void 0;
339
370
  }
340
371
  return {
372
+ planner: "simple",
341
373
  goal: input.goal,
342
- state: input.state,
343
- execute: async (state) => {
344
- if (JSON.stringify(state) === JSON.stringify(input.state)) {
345
- return singleResult.result;
346
- }
347
- return void 0;
348
- },
374
+ goalState: input.state,
349
375
  nextEvent: singleResult.result,
350
- sessionId: agent.sessionId,
351
- timestamp: Date.now()
376
+ episodeId: agent.episodeId,
377
+ timestamp: Date.now(),
378
+ paths: [
379
+ {
380
+ state: void 0,
381
+ steps: [
382
+ {
383
+ event: singleResult.result,
384
+ state: machine && machineState ? (0, import_xstate3.getNextSnapshot)(machine, machineState, singleResult.result) : void 0
385
+ }
386
+ ]
387
+ }
388
+ ]
352
389
  };
353
390
  }
354
391
 
355
- // src/decision.ts
356
- var import_xstate2 = require("xstate");
357
- async function agentDecide(agent, options) {
358
- const resolvedOptions = {
359
- ...agent.defaultOptions,
360
- ...options
361
- };
362
- const {
363
- planner = simplePlanner,
364
- goal,
365
- events = agent.events,
366
- state,
367
- machine,
368
- model = agent.model,
369
- ...otherPlanInput
370
- } = resolvedOptions;
371
- const plan = await planner(agent, {
372
- model,
373
- goal,
374
- events,
375
- state,
376
- machine,
377
- ...otherPlanInput
378
- });
379
- if (plan?.nextEvent) {
380
- agent.addPlan(plan);
381
- await resolvedOptions.execute?.(plan.nextEvent);
382
- }
383
- return plan;
384
- }
385
- function fromDecision(agent, defaultInput) {
386
- return (0, import_xstate2.fromPromise)(async ({ input, self }) => {
387
- const parentRef = self._parent;
388
- if (!parentRef) {
389
- return;
392
+ // src/agent.ts
393
+ var import_ai4 = require("ai");
394
+
395
+ // src/middleware.ts
396
+ function createAgentMiddleware(agent) {
397
+ const middleware = {
398
+ transformParams: async ({ params }) => {
399
+ return params;
400
+ },
401
+ wrapGenerate: async ({ doGenerate, params }) => {
402
+ const id = randomId();
403
+ params.prompt.forEach((message) => {
404
+ agent.addMessage({
405
+ id,
406
+ ...message,
407
+ timestamp: Date.now()
408
+ });
409
+ });
410
+ const result = await doGenerate();
411
+ return result;
412
+ },
413
+ wrapStream: async ({ doStream, params }) => {
414
+ const id = randomId();
415
+ params.prompt.forEach((message) => {
416
+ message.content;
417
+ agent.addMessage({
418
+ id,
419
+ ...message,
420
+ timestamp: Date.now()
421
+ });
422
+ });
423
+ const { stream, ...rest } = await doStream();
424
+ let generatedText = "";
425
+ const transformStream = new TransformStream({
426
+ transform(chunk, controller) {
427
+ if (chunk.type === "text-delta") {
428
+ generatedText += chunk.textDelta;
429
+ }
430
+ controller.enqueue(chunk);
431
+ },
432
+ flush() {
433
+ const content = [];
434
+ if (generatedText) {
435
+ content.push({
436
+ type: "text",
437
+ text: generatedText
438
+ });
439
+ }
440
+ agent.addMessage({
441
+ id: randomId(),
442
+ timestamp: Date.now(),
443
+ role: "assistant",
444
+ content,
445
+ responseId: id
446
+ });
447
+ }
448
+ });
449
+ return {
450
+ stream: stream.pipeThrough(transformStream),
451
+ ...rest
452
+ };
390
453
  }
391
- const snapshot = parentRef.getSnapshot();
392
- const inputObject = typeof input === "string" ? { goal: input } : input;
393
- const resolvedInput = {
394
- ...defaultInput,
395
- ...inputObject
396
- };
397
- const contextToInclude = resolvedInput.context === true ? (
398
- // include entire context
399
- parentRef.getSnapshot().context
400
- ) : resolvedInput.context;
401
- const state = {
402
- value: snapshot.value,
403
- context: contextToInclude
404
- };
405
- const plan = await agentDecide(agent, {
406
- machine: parentRef.logic,
407
- state,
408
- execute: async (event) => {
409
- parentRef.send(event);
410
- },
411
- ...resolvedInput
412
- });
413
- return plan;
414
- });
454
+ };
455
+ return middleware;
415
456
  }
416
457
 
417
- // src/adapters/vercel.ts
418
- var import_ai2 = require("ai");
419
- var vercelAdapter = {
420
- generateText: import_ai2.generateText,
421
- streamText: import_ai2.streamText
422
- };
423
-
424
458
  // src/agent.ts
425
- var agentLogic = (0, import_xstate3.fromTransition)(
459
+ var agentLogic = (0, import_xstate4.fromTransition)(
426
460
  (state, event, { emit }) => {
427
461
  switch (event.type) {
428
462
  case "agent.feedback": {
@@ -461,8 +495,10 @@ var agentLogic = (0, import_xstate3.fromTransition)(
461
495
  });
462
496
  break;
463
497
  }
464
- default:
498
+ default: {
499
+ console.warn("Unrecognized event", event);
465
500
  break;
501
+ }
466
502
  }
467
503
  return state;
468
504
  },
@@ -474,111 +510,149 @@ var agentLogic = (0, import_xstate3.fromTransition)(
474
510
  })
475
511
  );
476
512
  function createAgent({
477
- name,
513
+ id,
478
514
  description,
479
515
  model,
480
516
  events,
481
517
  context,
482
518
  planner = simplePlanner,
483
- stringify = JSON.stringify,
484
- getMemory,
485
- logic = agentLogic,
486
- adapter = vercelAdapter,
487
- ...generateTextOptions
519
+ logic = agentLogic
488
520
  }) {
489
- const agent = (0, import_xstate3.createActor)(logic);
490
- agent.events = events;
491
- agent.model = model;
492
- agent.name = name;
493
- agent.description = description;
494
- agent.adapter = adapter;
495
- agent.defaultOptions = { ...generateTextOptions, model };
496
- agent.select = (selector) => {
497
- return selector(agent.getSnapshot().context);
498
- };
499
- agent.memory = getMemory ? getMemory(agent) : void 0;
500
- agent.onMessage = (callback) => {
501
- agent.on("message", (ev) => callback(ev.message));
502
- };
503
- agent.decide = (opts) => {
504
- return agentDecide(agent, opts);
505
- };
506
- agent.addMessage = (messageInput) => {
521
+ return new Agent({
522
+ id,
523
+ context,
524
+ events,
525
+ description,
526
+ planner,
527
+ model,
528
+ logic
529
+ });
530
+ }
531
+ var Agent = class extends import_xstate4.Actor {
532
+ // todo
533
+ constructor({
534
+ logic = agentLogic,
535
+ id,
536
+ name,
537
+ description,
538
+ model,
539
+ events,
540
+ context,
541
+ planner = simplePlanner
542
+ }) {
543
+ super(logic);
544
+ this.model = model;
545
+ this.episodeId = id ?? randomId();
546
+ this.name = name;
547
+ this.description = description;
548
+ this.events = events;
549
+ this.context = context;
550
+ this.planner = planner;
551
+ this.types = {};
552
+ this.start();
553
+ }
554
+ /**
555
+ * Called whenever the agent (LLM assistant) receives or sends a message.
556
+ */
557
+ onMessage(fn) {
558
+ return this.on("message", (ev) => fn(ev.message));
559
+ }
560
+ /**
561
+ * Retrieves messages from the agent's short-term (local) memory.
562
+ */
563
+ addMessage(messageInput) {
507
564
  const message = {
508
565
  ...messageInput,
509
566
  id: messageInput.id ?? randomId(),
510
567
  timestamp: messageInput.timestamp ?? Date.now(),
511
- sessionId: agent.sessionId,
512
- correlationId: messageInput.correlationId ?? randomId()
568
+ episodeId: this.episodeId
513
569
  };
514
- agent.send({
570
+ this.send({
515
571
  type: "agent.message",
516
572
  message
517
573
  });
518
574
  return message;
519
- };
520
- agent.getMessages = () => agent.getSnapshot().context.messages;
521
- agent.generateText = (opts) => agentGenerateText(agent, opts);
522
- agent.streamText = (opts) => agentStreamText(agent, opts);
523
- agent.addFeedback = (feedbackInput) => {
575
+ }
576
+ getMessages() {
577
+ return this.getSnapshot().context.messages;
578
+ }
579
+ addFeedback(feedbackInput) {
524
580
  const feedback = {
525
581
  ...feedbackInput,
526
582
  attributes: { ...feedbackInput.attributes },
527
583
  reward: feedbackInput.reward ?? 0,
528
584
  timestamp: feedbackInput.timestamp ?? Date.now(),
529
- sessionId: agent.sessionId
585
+ episodeId: this.episodeId
530
586
  };
531
- agent.send({
587
+ this.send({
532
588
  type: "agent.feedback",
533
589
  feedback
534
590
  });
535
591
  return feedback;
536
- };
537
- agent.getFeedback = () => agent.getSnapshot().context.feedback;
538
- agent.addObservation = (observationInput) => {
592
+ }
593
+ /**
594
+ * Retrieves feedback from the agent's short-term (local) memory.
595
+ */
596
+ getFeedback() {
597
+ return this.getSnapshot().context.feedback;
598
+ }
599
+ addObservation(observationInput) {
539
600
  const { prevState, event, state } = observationInput;
540
601
  const observation = {
541
602
  prevState,
542
603
  event,
543
604
  state,
544
605
  id: observationInput.id ?? randomId(),
545
- sessionId: agent.sessionId,
606
+ episodeId: this.episodeId,
546
607
  timestamp: observationInput.timestamp ?? Date.now(),
547
608
  machineHash: observationInput.machine ? getMachineHash(observationInput.machine) : void 0
548
609
  };
549
- agent.send({
610
+ this.send({
550
611
  type: "agent.observe",
551
612
  observation
552
613
  });
553
614
  return observation;
554
- };
555
- agent.getObservations = () => agent.getSnapshot().context.observations;
556
- agent.addPlan = (plan) => {
557
- agent.send({
615
+ }
616
+ /**
617
+ * Retrieves observations from the agent's short-term (local) memory.
618
+ */
619
+ getObservations() {
620
+ return this.getSnapshot().context.observations;
621
+ }
622
+ addPlan(plan) {
623
+ this.send({
558
624
  type: "agent.plan",
559
625
  plan
560
626
  });
561
- };
562
- agent.getPlans = () => agent.getSnapshot().context.plans;
563
- agent.interact = (actorRef, getInput) => {
627
+ }
628
+ /**
629
+ * Retrieves strategies from the agent's short-term (local) memory.
630
+ */
631
+ getPlans() {
632
+ return this.getSnapshot().context.plans;
633
+ }
634
+ interact(actorRef, getInput) {
635
+ const actorRefCheck = isActorRef(actorRef) && actorRef.src;
636
+ const machine = isMachineActor(actorRef) ? actorRef.src : void 0;
564
637
  let prevState = void 0;
565
638
  let subscribed = true;
639
+ const agent = this;
566
640
  async function handleObservation(observationInput) {
567
641
  const observation = agent.addObservation(observationInput);
568
642
  const input = getInput?.(observation);
569
643
  if (input) {
570
- await agentDecide(agent, {
571
- machine: actorRef.src,
644
+ const res = await agentDecide(agent, {
645
+ machine,
572
646
  state: observation.state,
573
- execute: async (event) => {
574
- actorRef.send(event);
575
- },
576
647
  ...input
577
648
  });
649
+ if (res?.nextEvent) {
650
+ actorRef.send(res.nextEvent);
651
+ }
578
652
  }
579
653
  prevState = observationInput.state;
580
654
  }
581
- actorRef.system.inspect({
655
+ const sub = actorRefCheck ? actorRef.system.inspect({
582
656
  next: async (inspEvent) => {
583
657
  if (!subscribed || inspEvent.actorRef !== actorRef || inspEvent.type !== "@xstate.snapshot") {
584
658
  return;
@@ -591,7 +665,7 @@ function createAgent({
591
665
  };
592
666
  await handleObservation(observationInput);
593
667
  }
594
- });
668
+ }) : void 0;
595
669
  if (actorRef._processingStatus === 1) {
596
670
  handleObservation({
597
671
  prevState: void 0,
@@ -603,15 +677,50 @@ function createAgent({
603
677
  }
604
678
  return {
605
679
  unsubscribe: () => {
680
+ sub?.unsubscribe();
606
681
  subscribed = false;
607
682
  }
608
- // TODO: make this actually unsubscribe
609
683
  };
610
- };
611
- agent.types = {};
612
- agent.start();
613
- return agent;
614
- }
684
+ }
685
+ observe(actorRef) {
686
+ let prevState = actorRef.getSnapshot();
687
+ const actorRefCheck = isActorRef(actorRef);
688
+ const sub = actorRefCheck ? actorRef.system.inspect({
689
+ next: async (inspEvent) => {
690
+ if (inspEvent.actorRef !== actorRef || inspEvent.type !== "@xstate.snapshot") {
691
+ return;
692
+ }
693
+ const observationInput = {
694
+ event: inspEvent.event,
695
+ prevState,
696
+ state: inspEvent.snapshot,
697
+ machine: actorRef.src
698
+ };
699
+ prevState = observationInput.state;
700
+ this.addObservation(observationInput);
701
+ }
702
+ }) : void 0;
703
+ return sub ?? { unsubscribe: () => {
704
+ } };
705
+ }
706
+ wrap(modelToWrap) {
707
+ return (0, import_ai4.experimental_wrapLanguageModel)({
708
+ model: modelToWrap,
709
+ middleware: createAgentMiddleware(this)
710
+ });
711
+ }
712
+ /**
713
+ * Resolves with an `AgentPlan` based on the information provided in the `options`, including:
714
+ *
715
+ * - The `goal` for the agent to achieve
716
+ * - The observed current `state`
717
+ * - The `machine` (e.g. a state machine) that specifies what can happen next
718
+ * - Additional `context`
719
+ */
720
+ decide(opts) {
721
+ return agentDecide(this, opts);
722
+ }
723
+ };
615
724
  // Annotate the CommonJS export names for ESM import in node:
616
725
  0 && (module.exports = {
617
726
  createAgent,