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