@statelyai/agent 1.0.0-beta.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,13 +17,19 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var src_exports = {};
22
32
  __export(src_exports, {
23
- agentDecide: () => agentDecide,
24
- agentGenerateText: () => agentGenerateText,
25
33
  createAgent: () => createAgent,
26
34
  fromDecision: () => fromDecision,
27
35
  fromText: () => fromText,
@@ -36,13 +44,36 @@ var import_xstate3 = require("xstate");
36
44
  var import_ai = require("ai");
37
45
 
38
46
  // src/utils.ts
47
+ var import_object_hash = __toESM(require("object-hash"));
39
48
  function getAllTransitions(state) {
40
49
  const nodes = state._nodes;
41
- const transitions = nodes.map((node) => [...node.transitions.values()]).flat(2).map((transition) => ({
42
- ...transition,
43
- guard: typeof transition.guard === "string" ? { type: transition.guard } : transition.guard
44
- // TODO: fix
45
- }));
50
+ const transitions = nodes.map((node) => [...node.transitions.values()]).map((nodeTransitions) => {
51
+ return nodeTransitions.map((nodeEventTransitions) => {
52
+ return nodeEventTransitions.map((transition) => {
53
+ return {
54
+ ...transition,
55
+ guard: typeof transition.guard === "string" ? { type: transition.guard } : transition.guard
56
+ // TODO: fix
57
+ };
58
+ });
59
+ });
60
+ }).flat(2);
61
+ return transitions;
62
+ }
63
+ function getAllMachineTransitions(stateNode) {
64
+ const transitions = [...stateNode.transitions.values()].map((nodeTransitions) => {
65
+ return nodeTransitions.map((transition) => {
66
+ return {
67
+ ...transition,
68
+ guard: typeof transition.guard === "string" ? { type: transition.guard } : transition.guard
69
+ // TODO: fix
70
+ };
71
+ });
72
+ }).flat(2);
73
+ for (const s of Object.values(stateNode.states)) {
74
+ const stateTransitions = getAllMachineTransitions(s);
75
+ transitions.push(...stateTransitions);
76
+ }
46
77
  return transitions;
47
78
  }
48
79
  function wrapInXml(tagName, content) {
@@ -53,6 +84,14 @@ function randomId() {
53
84
  const random = Math.random().toString(36).substring(2, 9);
54
85
  return timestamp + random;
55
86
  }
87
+ var machineHashes = /* @__PURE__ */ new WeakMap();
88
+ function getMachineHash(machine) {
89
+ if (machineHashes.has(machine)) return machineHashes.get(machine);
90
+ const transitions = getAllMachineTransitions(machine.root);
91
+ const machineHash = (0, import_object_hash.default)(transitions);
92
+ machineHashes.set(machine, machineHash);
93
+ return machineHash;
94
+ }
56
95
 
57
96
  // src/templates/defaultText.ts
58
97
  var defaultTextTemplate = (data) => {
@@ -66,94 +105,11 @@ ${data.goal}
66
105
  `.trim();
67
106
  };
68
107
 
69
- // src/planners/simplePlanner.ts
70
- function getTransitions(state, machine) {
71
- if (!machine) {
72
- return [];
73
- }
74
- const resolvedState = machine.resolveState(state);
75
- return getAllTransitions(resolvedState);
76
- }
77
- var simplePlannerPromptTemplate = (data) => {
78
- return `
79
- ${defaultTextTemplate(data)}
80
-
81
- Only make a single tool call to achieve the above goal.
82
- `.trim();
83
- };
84
- async function simplePlanner(agent, input) {
85
- const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
86
- eventType,
87
- description
88
- }));
89
- const filter = (eventType) => Object.keys(input.events).includes(eventType);
90
- const functionNameMapping = {};
91
- const toolTransitions = transitions.filter((t) => {
92
- return filter(t.eventType);
93
- }).map((t) => {
94
- const name = t.eventType.replace(/\./g, "_");
95
- functionNameMapping[name] = t.eventType;
96
- return {
97
- type: "function",
98
- eventType: t.eventType,
99
- description: t.description,
100
- name
101
- };
102
- });
103
- const toolMap = {};
104
- for (const toolTransitionData of toolTransitions) {
105
- const toolZodType = input.events?.[toolTransitionData.eventType];
106
- if (!toolZodType) {
107
- continue;
108
- }
109
- toolMap[toolTransitionData.name] = (0, import_ai.tool)({
110
- description: toolZodType?.description ?? toolTransitionData.description,
111
- parameters: toolZodType,
112
- execute: async (params) => {
113
- const event = {
114
- type: toolTransitionData.eventType,
115
- ...params
116
- };
117
- return event;
118
- }
119
- });
120
- }
121
- const prompt = simplePlannerPromptTemplate({
122
- context: input.state.context,
123
- goal: input.goal
124
- });
125
- const result = await agent.generateText({
126
- ...input,
127
- prompt,
128
- tools: toolMap,
129
- toolChoice: "required"
130
- });
131
- const singleResult = result.toolResults[0];
132
- if (!singleResult) {
133
- console.warn("No tool call results returned");
134
- return void 0;
135
- }
136
- return {
137
- goal: input.goal,
138
- state: input.state,
139
- steps: [
140
- {
141
- event: singleResult.result
142
- }
143
- ],
144
- nextEvent: singleResult.result,
145
- sessionId: agent.sessionId,
146
- timestamp: Date.now()
147
- };
148
- }
149
-
150
108
  // src/text.ts
151
109
  var import_xstate = require("xstate");
152
110
  async function getMessages(agent, prompt, options) {
153
111
  let messages = [];
154
- if (options.messages === true) {
155
- messages = agent.select((s) => s.messages);
156
- } else if (typeof options.messages === "function") {
112
+ if (typeof options.messages === "function") {
157
113
  messages = await options.messages(agent);
158
114
  } else if (options.messages) {
159
115
  messages = options.messages;
@@ -167,7 +123,8 @@ async function getMessages(agent, prompt, options) {
167
123
  async function agentGenerateText(agent, options) {
168
124
  const resolvedOptions = {
169
125
  ...agent.defaultOptions,
170
- ...options
126
+ ...options,
127
+ correlationId: options.correlationId ?? randomId()
171
128
  };
172
129
  const template = resolvedOptions.template ?? defaultTextTemplate;
173
130
  const id = randomId();
@@ -181,7 +138,9 @@ async function agentGenerateText(agent, options) {
181
138
  id,
182
139
  role: "user",
183
140
  content: promptWithContext,
184
- timestamp: Date.now()
141
+ timestamp: Date.now(),
142
+ correlationId: resolvedOptions.correlationId,
143
+ parentCorrelationId: resolvedOptions.parentCorrelationId
185
144
  });
186
145
  const result = await agent.adapter.generateText({
187
146
  ...resolvedOptions,
@@ -194,14 +153,21 @@ async function agentGenerateText(agent, options) {
194
153
  role: "assistant",
195
154
  timestamp: Date.now(),
196
155
  responseId: id,
197
- result
156
+ result,
157
+ correlationId: resolvedOptions.correlationId,
158
+ parentCorrelationId: resolvedOptions.parentCorrelationId
198
159
  });
199
- return result;
160
+ return {
161
+ ...result,
162
+ parentCorrelationId: resolvedOptions.parentCorrelationId,
163
+ correlationId: resolvedOptions.correlationId
164
+ };
200
165
  }
201
166
  async function agentStreamText(agent, options) {
202
167
  const resolvedOptions = {
203
168
  ...agent.defaultOptions,
204
- ...options
169
+ ...options,
170
+ correlationId: options.correlationId ?? randomId()
205
171
  };
206
172
  const template = resolvedOptions.template ?? defaultTextTemplate;
207
173
  const id = randomId();
@@ -215,7 +181,9 @@ async function agentStreamText(agent, options) {
215
181
  role: "user",
216
182
  content: promptWithContext,
217
183
  id,
218
- timestamp: Date.now()
184
+ timestamp: Date.now(),
185
+ correlationId: resolvedOptions.correlationId,
186
+ parentCorrelationId: resolvedOptions.parentCorrelationId
219
187
  });
220
188
  const result = await agent.adapter.streamText({
221
189
  ...resolvedOptions,
@@ -233,26 +201,33 @@ async function agentStreamText(agent, options) {
233
201
  toolResults: [],
234
202
  usage: res.usage,
235
203
  warnings: res.warnings,
236
- rawResponse: res.rawResponse
204
+ rawResponse: res.rawResponse,
205
+ roundtrips: []
206
+ // TODO: how do we get this information?
237
207
  },
238
208
  content: res.text,
239
209
  id: randomId(),
240
210
  timestamp: Date.now(),
241
- responseId: id
211
+ responseId: id,
212
+ correlationId: resolvedOptions.correlationId,
213
+ parentCorrelationId: resolvedOptions.parentCorrelationId
242
214
  });
243
215
  }
244
216
  });
245
- return result;
217
+ return {
218
+ ...result,
219
+ parentCorrelationId: resolvedOptions.parentCorrelationId,
220
+ correlationId: resolvedOptions.correlationId
221
+ };
246
222
  }
247
223
  function fromTextStream(agent, defaultOptions) {
248
- return (0, import_xstate.fromObservable)(({ input, self }) => {
249
- const context = input.context === true ? (self._parent?.getSnapshot()).context : input.context;
224
+ return (0, import_xstate.fromObservable)(({ input }) => {
250
225
  const observers = /* @__PURE__ */ new Set();
251
226
  (async () => {
252
227
  const result = await agentStreamText(agent, {
253
228
  ...defaultOptions,
254
229
  ...input,
255
- context
230
+ context: input.context
256
231
  });
257
232
  for await (const part of result.fullStream) {
258
233
  if (part.type === "text-delta") {
@@ -276,16 +251,102 @@ function fromTextStream(agent, defaultOptions) {
276
251
  });
277
252
  }
278
253
  function fromText(agent, defaultOptions) {
279
- return (0, import_xstate.fromPromise)(async ({ input, self }) => {
280
- const context = input.context === true ? (self._parent?.getSnapshot()).context : input.context;
254
+ return (0, import_xstate.fromPromise)(async ({ input }) => {
281
255
  return await agentGenerateText(agent, {
282
256
  ...input,
283
257
  ...defaultOptions,
284
- context
258
+ context: input.context
285
259
  });
286
260
  });
287
261
  }
288
262
 
263
+ // src/planners/simplePlanner.ts
264
+ function getTransitions(state, machine) {
265
+ if (!machine) {
266
+ return [];
267
+ }
268
+ const resolvedState = machine.resolveState(state);
269
+ return getAllTransitions(resolvedState);
270
+ }
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) {
279
+ const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
280
+ eventType,
281
+ description
282
+ }));
283
+ const filter = (eventType) => Object.keys(input.events).includes(eventType);
284
+ const functionNameMapping = {};
285
+ const toolTransitions = transitions.filter((t) => {
286
+ return filter(t.eventType);
287
+ }).map((t) => {
288
+ const name = t.eventType.replace(/\./g, "_");
289
+ functionNameMapping[name] = t.eventType;
290
+ return {
291
+ type: "function",
292
+ eventType: t.eventType,
293
+ description: t.description,
294
+ name
295
+ };
296
+ });
297
+ const toolMap = {};
298
+ for (const toolTransitionData of toolTransitions) {
299
+ const toolZodType = input.events?.[toolTransitionData.eventType];
300
+ if (!toolZodType) {
301
+ continue;
302
+ }
303
+ toolMap[toolTransitionData.name] = (0, import_ai.tool)({
304
+ description: toolZodType?.description ?? toolTransitionData.description,
305
+ parameters: toolZodType,
306
+ execute: async (params) => {
307
+ const event = {
308
+ type: toolTransitionData.eventType,
309
+ ...params
310
+ };
311
+ return event;
312
+ }
313
+ });
314
+ }
315
+ if (!Object.keys(toolMap).length) {
316
+ return void 0;
317
+ }
318
+ const prompt = simplePlannerPromptTemplate({
319
+ context: input.state.context,
320
+ goal: input.goal
321
+ });
322
+ const messages = await getMessages(agent, prompt, input);
323
+ const result = await agent.generateText({
324
+ toolChoice: "required",
325
+ ...input,
326
+ prompt,
327
+ messages,
328
+ tools: toolMap
329
+ });
330
+ const singleResult = result.toolResults[0];
331
+ if (!singleResult) {
332
+ console.warn("No tool call results returned");
333
+ return void 0;
334
+ }
335
+ return {
336
+ 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
+ },
344
+ nextEvent: singleResult.result,
345
+ sessionId: agent.sessionId,
346
+ timestamp: Date.now()
347
+ };
348
+ }
349
+
289
350
  // src/decision.ts
290
351
  var import_xstate2 = require("xstate");
291
352
  async function agentDecide(agent, options) {
@@ -400,18 +461,19 @@ var agentLogic = (0, import_xstate3.fromTransition)(
400
461
  }
401
462
  return state;
402
463
  },
403
- {
464
+ () => ({
404
465
  feedback: [],
405
466
  messages: [],
406
467
  observations: [],
407
468
  plans: []
408
- }
469
+ })
409
470
  );
410
471
  function createAgent({
411
472
  name,
412
473
  description,
413
474
  model,
414
475
  events,
476
+ context,
415
477
  planner = simplePlanner,
416
478
  stringify = JSON.stringify,
417
479
  getMemory,
@@ -419,7 +481,6 @@ function createAgent({
419
481
  adapter = vercelAdapter,
420
482
  ...generateTextOptions
421
483
  }) {
422
- const messageHistoryListeners = [];
423
484
  const agent = (0, import_xstate3.createActor)(logic);
424
485
  agent.events = events;
425
486
  agent.model = model;
@@ -432,7 +493,7 @@ function createAgent({
432
493
  };
433
494
  agent.memory = getMemory ? getMemory(agent) : void 0;
434
495
  agent.onMessage = (callback) => {
435
- messageHistoryListeners.push((0, import_xstate3.toObserver)(callback));
496
+ agent.on("message", (ev) => callback(ev.message));
436
497
  };
437
498
  agent.decide = (opts) => {
438
499
  return agentDecide(agent, opts);
@@ -442,7 +503,8 @@ function createAgent({
442
503
  ...messageInput,
443
504
  id: messageInput.id ?? randomId(),
444
505
  timestamp: messageInput.timestamp ?? Date.now(),
445
- sessionId: agent.sessionId
506
+ sessionId: agent.sessionId,
507
+ correlationId: messageInput.correlationId ?? randomId()
446
508
  };
447
509
  agent.send({
448
510
  type: "agent.message",
@@ -450,11 +512,14 @@ function createAgent({
450
512
  });
451
513
  return message;
452
514
  };
515
+ agent.getMessages = () => agent.getSnapshot().context.messages;
453
516
  agent.generateText = (opts) => agentGenerateText(agent, opts);
454
517
  agent.streamText = (opts) => agentStreamText(agent, opts);
455
518
  agent.addFeedback = (feedbackInput) => {
456
519
  const feedback = {
457
520
  ...feedbackInput,
521
+ attributes: { ...feedbackInput.attributes },
522
+ reward: feedbackInput.reward ?? 0,
458
523
  timestamp: feedbackInput.timestamp ?? Date.now(),
459
524
  sessionId: agent.sessionId
460
525
  };
@@ -464,12 +529,17 @@ function createAgent({
464
529
  });
465
530
  return feedback;
466
531
  };
532
+ agent.getFeedback = () => agent.getSnapshot().context.feedback;
467
533
  agent.addObservation = (observationInput) => {
534
+ const { prevState, event, state } = observationInput;
468
535
  const observation = {
469
- ...observationInput,
536
+ prevState,
537
+ event,
538
+ state,
470
539
  id: observationInput.id ?? randomId(),
471
540
  sessionId: agent.sessionId,
472
- timestamp: observationInput.timestamp ?? Date.now()
541
+ timestamp: observationInput.timestamp ?? Date.now(),
542
+ machineHash: observationInput.machine ? getMachineHash(observationInput.machine) : void 0
473
543
  };
474
544
  agent.send({
475
545
  type: "agent.observe",
@@ -477,12 +547,14 @@ function createAgent({
477
547
  });
478
548
  return observation;
479
549
  };
550
+ agent.getObservations = () => agent.getSnapshot().context.observations;
480
551
  agent.addPlan = (plan) => {
481
552
  agent.send({
482
553
  type: "agent.plan",
483
554
  plan
484
555
  });
485
556
  };
557
+ agent.getPlans = () => agent.getSnapshot().context.plans;
486
558
  agent.interact = (actorRef, getInput) => {
487
559
  let prevState = void 0;
488
560
  let subscribed = true;
@@ -509,7 +581,8 @@ function createAgent({
509
581
  const observationInput = {
510
582
  event: inspEvent.event,
511
583
  prevState,
512
- state: inspEvent.snapshot
584
+ state: inspEvent.snapshot,
585
+ machine: actorRef.src
513
586
  };
514
587
  await handleObservation(observationInput);
515
588
  }
@@ -519,7 +592,8 @@ function createAgent({
519
592
  prevState: void 0,
520
593
  event: { type: "" },
521
594
  // TODO: unknown events?
522
- state: actorRef.getSnapshot()
595
+ state: actorRef.getSnapshot(),
596
+ machine: actorRef.src
523
597
  });
524
598
  }
525
599
  return {
@@ -529,13 +603,12 @@ function createAgent({
529
603
  // TODO: make this actually unsubscribe
530
604
  };
531
605
  };
606
+ agent.types = {};
532
607
  agent.start();
533
608
  return agent;
534
609
  }
535
610
  // Annotate the CommonJS export names for ESM import in node:
536
611
  0 && (module.exports = {
537
- agentDecide,
538
- agentGenerateText,
539
612
  createAgent,
540
613
  fromDecision,
541
614
  fromText,