@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.
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,18 +44,54 @@ 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) {
49
80
  return `<${tagName}>${content}</${tagName}>`;
50
81
  }
82
+ function randomId() {
83
+ const timestamp = Date.now().toString(36);
84
+ const random = Math.random().toString(36).substring(2, 9);
85
+ return timestamp + random;
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
+ }
51
95
 
52
96
  // src/templates/defaultText.ts
53
97
  var defaultTextTemplate = (data) => {
@@ -61,95 +105,11 @@ ${data.goal}
61
105
  `.trim();
62
106
  };
63
107
 
64
- // src/planners/simplePlanner.ts
65
- function getTransitions(state, machine) {
66
- if (!machine) {
67
- return [];
68
- }
69
- const resolvedState = machine.resolveState(state);
70
- return getAllTransitions(resolvedState);
71
- }
72
- var simplePlannerPromptTemplate = (data) => {
73
- return `
74
- ${defaultTextTemplate(data)}
75
-
76
- Only make a single tool call to achieve the above goal.
77
- `.trim();
78
- };
79
- async function simplePlanner(agent, input) {
80
- const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
81
- eventType,
82
- description
83
- }));
84
- const filter = (eventType) => Object.keys(input.events).includes(eventType);
85
- const functionNameMapping = {};
86
- const toolTransitions = transitions.filter((t) => {
87
- return filter(t.eventType);
88
- }).map((t) => {
89
- const name = t.eventType.replace(/\./g, "_");
90
- functionNameMapping[name] = t.eventType;
91
- return {
92
- type: "function",
93
- eventType: t.eventType,
94
- description: t.description,
95
- name
96
- };
97
- });
98
- const toolMap = {};
99
- for (const toolTransitionData of toolTransitions) {
100
- const toolZodType = input.events?.[toolTransitionData.eventType];
101
- if (!toolZodType) {
102
- continue;
103
- }
104
- toolMap[toolTransitionData.name] = (0, import_ai.tool)({
105
- description: toolZodType?.description ?? toolTransitionData.description,
106
- parameters: toolZodType,
107
- execute: async (params) => {
108
- const event = {
109
- type: toolTransitionData.eventType,
110
- ...params
111
- };
112
- return event;
113
- }
114
- });
115
- }
116
- const prompt = simplePlannerPromptTemplate({
117
- context: input.state.context,
118
- goal: input.goal
119
- });
120
- const result = await agent.generateText({
121
- prompt,
122
- tools: toolMap,
123
- toolChoice: "required",
124
- ...input
125
- });
126
- const singleResult = result.toolResults[0];
127
- if (!singleResult) {
128
- console.warn("No tool call results returned");
129
- return void 0;
130
- }
131
- return {
132
- goal: input.goal,
133
- state: input.state,
134
- steps: [
135
- {
136
- event: singleResult.result
137
- }
138
- ],
139
- nextEvent: singleResult.result,
140
- sessionId: agent.sessionId,
141
- timestamp: Date.now()
142
- };
143
- }
144
-
145
108
  // src/text.ts
146
109
  var import_xstate = require("xstate");
147
- var import_nanoid = require("nanoid");
148
110
  async function getMessages(agent, prompt, options) {
149
111
  let messages = [];
150
- if (options.messages === true) {
151
- messages = agent.select((s) => s.messages);
152
- } else if (typeof options.messages === "function") {
112
+ if (typeof options.messages === "function") {
153
113
  messages = await options.messages(agent);
154
114
  } else if (options.messages) {
155
115
  messages = options.messages;
@@ -166,7 +126,7 @@ async function agentGenerateText(agent, options) {
166
126
  ...options
167
127
  };
168
128
  const template = resolvedOptions.template ?? defaultTextTemplate;
169
- const id = (0, import_nanoid.nanoid)();
129
+ const id = randomId();
170
130
  const goal = typeof resolvedOptions.prompt === "string" ? resolvedOptions.prompt : await resolvedOptions.prompt(agent);
171
131
  const promptWithContext = template({
172
132
  goal,
@@ -200,7 +160,7 @@ async function agentStreamText(agent, options) {
200
160
  ...options
201
161
  };
202
162
  const template = resolvedOptions.template ?? defaultTextTemplate;
203
- const id = (0, import_nanoid.nanoid)();
163
+ const id = randomId();
204
164
  const goal = typeof resolvedOptions.prompt === "string" ? resolvedOptions.prompt : await resolvedOptions.prompt(agent);
205
165
  const promptWithContext = template({
206
166
  goal,
@@ -232,7 +192,7 @@ async function agentStreamText(agent, options) {
232
192
  rawResponse: res.rawResponse
233
193
  },
234
194
  content: res.text,
235
- id: (0, import_nanoid.nanoid)(),
195
+ id: randomId(),
236
196
  timestamp: Date.now(),
237
197
  responseId: id
238
198
  });
@@ -241,14 +201,13 @@ async function agentStreamText(agent, options) {
241
201
  return result;
242
202
  }
243
203
  function fromTextStream(agent, defaultOptions) {
244
- return (0, import_xstate.fromObservable)(({ input, self }) => {
245
- const context = input.context === true ? (self._parent?.getSnapshot()).context : input.context;
204
+ return (0, import_xstate.fromObservable)(({ input }) => {
246
205
  const observers = /* @__PURE__ */ new Set();
247
206
  (async () => {
248
207
  const result = await agentStreamText(agent, {
249
208
  ...defaultOptions,
250
209
  ...input,
251
- context
210
+ context: input.context
252
211
  });
253
212
  for await (const part of result.fullStream) {
254
213
  if (part.type === "text-delta") {
@@ -272,16 +231,103 @@ function fromTextStream(agent, defaultOptions) {
272
231
  });
273
232
  }
274
233
  function fromText(agent, defaultOptions) {
275
- return (0, import_xstate.fromPromise)(async ({ input, self }) => {
276
- const context = input.context === true ? (self._parent?.getSnapshot()).context : input.context;
234
+ return (0, import_xstate.fromPromise)(async ({ input }) => {
277
235
  return await agentGenerateText(agent, {
278
236
  ...input,
279
237
  ...defaultOptions,
280
- context
238
+ context: input.context
281
239
  });
282
240
  });
283
241
  }
284
242
 
243
+ // src/planners/simplePlanner.ts
244
+ function getTransitions(state, machine) {
245
+ if (!machine) {
246
+ return [];
247
+ }
248
+ const resolvedState = machine.resolveState(state);
249
+ return getAllTransitions(resolvedState);
250
+ }
251
+ var simplePlannerPromptTemplate = (data) => {
252
+ return `
253
+ ${defaultTextTemplate(data)}
254
+
255
+ 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.
256
+ `.trim();
257
+ };
258
+ async function simplePlanner(agent, input) {
259
+ const transitions = input.machine ? getTransitions(input.state, input.machine) : Object.entries(input.events).map(([eventType, { description }]) => ({
260
+ eventType,
261
+ description
262
+ }));
263
+ const filter = (eventType) => Object.keys(input.events).includes(eventType);
264
+ const functionNameMapping = {};
265
+ const toolTransitions = transitions.filter((t) => {
266
+ return filter(t.eventType);
267
+ }).map((t) => {
268
+ const name = t.eventType.replace(/\./g, "_");
269
+ functionNameMapping[name] = t.eventType;
270
+ return {
271
+ type: "function",
272
+ eventType: t.eventType,
273
+ description: t.description,
274
+ name
275
+ };
276
+ });
277
+ const toolMap = {};
278
+ for (const toolTransitionData of toolTransitions) {
279
+ const toolZodType = input.events?.[toolTransitionData.eventType];
280
+ if (!toolZodType) {
281
+ continue;
282
+ }
283
+ toolMap[toolTransitionData.name] = (0, import_ai.tool)({
284
+ description: toolZodType?.description ?? toolTransitionData.description,
285
+ parameters: toolZodType,
286
+ execute: async (params) => {
287
+ const event = {
288
+ type: toolTransitionData.eventType,
289
+ ...params
290
+ };
291
+ return event;
292
+ }
293
+ });
294
+ }
295
+ if (!Object.keys(toolMap).length) {
296
+ return void 0;
297
+ }
298
+ const prompt = simplePlannerPromptTemplate({
299
+ context: input.state.context,
300
+ goal: input.goal
301
+ });
302
+ const messages = await getMessages(agent, prompt, input);
303
+ const result = await agent.generateText({
304
+ toolChoice: "required",
305
+ ...input,
306
+ prompt,
307
+ messages,
308
+ tools: toolMap
309
+ });
310
+ const singleResult = result.toolResults[0];
311
+ if (!singleResult) {
312
+ console.log(toolMap);
313
+ console.warn("No tool call results returned");
314
+ return void 0;
315
+ }
316
+ return {
317
+ goal: input.goal,
318
+ state: input.state,
319
+ execute: async (state) => {
320
+ if (JSON.stringify(state) === JSON.stringify(input.state)) {
321
+ return singleResult.result;
322
+ }
323
+ return void 0;
324
+ },
325
+ nextEvent: singleResult.result,
326
+ sessionId: agent.sessionId,
327
+ timestamp: Date.now()
328
+ };
329
+ }
330
+
285
331
  // src/decision.ts
286
332
  var import_xstate2 = require("xstate");
287
333
  async function agentDecide(agent, options) {
@@ -352,7 +398,6 @@ var vercelAdapter = {
352
398
  };
353
399
 
354
400
  // src/agent.ts
355
- var import_nanoid2 = require("nanoid");
356
401
  var agentLogic = (0, import_xstate3.fromTransition)(
357
402
  (state, event, { emit }) => {
358
403
  switch (event.type) {
@@ -409,6 +454,7 @@ function createAgent({
409
454
  description,
410
455
  model,
411
456
  events,
457
+ context,
412
458
  planner = simplePlanner,
413
459
  stringify = JSON.stringify,
414
460
  getMemory,
@@ -437,7 +483,7 @@ function createAgent({
437
483
  agent.addMessage = (messageInput) => {
438
484
  const message = {
439
485
  ...messageInput,
440
- id: messageInput.id ?? (0, import_nanoid2.nanoid)(),
486
+ id: messageInput.id ?? randomId(),
441
487
  timestamp: messageInput.timestamp ?? Date.now(),
442
488
  sessionId: agent.sessionId
443
489
  };
@@ -447,6 +493,7 @@ function createAgent({
447
493
  });
448
494
  return message;
449
495
  };
496
+ agent.getMessages = () => agent.getSnapshot().context.messages;
450
497
  agent.generateText = (opts) => agentGenerateText(agent, opts);
451
498
  agent.streamText = (opts) => agentStreamText(agent, opts);
452
499
  agent.addFeedback = (feedbackInput) => {
@@ -461,12 +508,17 @@ function createAgent({
461
508
  });
462
509
  return feedback;
463
510
  };
511
+ agent.getFeedback = () => agent.getSnapshot().context.feedback;
464
512
  agent.addObservation = (observationInput) => {
513
+ const { prevState, event, state } = observationInput;
465
514
  const observation = {
466
- ...observationInput,
467
- id: observationInput.id ?? (0, import_nanoid2.nanoid)(),
515
+ prevState,
516
+ event,
517
+ state,
518
+ id: observationInput.id ?? randomId(),
468
519
  sessionId: agent.sessionId,
469
- timestamp: observationInput.timestamp ?? Date.now()
520
+ timestamp: observationInput.timestamp ?? Date.now(),
521
+ machineHash: observationInput.machine ? getMachineHash(observationInput.machine) : void 0
470
522
  };
471
523
  agent.send({
472
524
  type: "agent.observe",
@@ -474,12 +526,14 @@ function createAgent({
474
526
  });
475
527
  return observation;
476
528
  };
529
+ agent.getObservations = () => agent.getSnapshot().context.observations;
477
530
  agent.addPlan = (plan) => {
478
531
  agent.send({
479
532
  type: "agent.plan",
480
533
  plan
481
534
  });
482
535
  };
536
+ agent.getPlans = () => agent.getSnapshot().context.plans;
483
537
  agent.interact = (actorRef, getInput) => {
484
538
  let prevState = void 0;
485
539
  let subscribed = true;
@@ -506,7 +560,8 @@ function createAgent({
506
560
  const observationInput = {
507
561
  event: inspEvent.event,
508
562
  prevState,
509
- state: inspEvent.snapshot
563
+ state: inspEvent.snapshot,
564
+ machine: actorRef.src
510
565
  };
511
566
  await handleObservation(observationInput);
512
567
  }
@@ -516,7 +571,8 @@ function createAgent({
516
571
  prevState: void 0,
517
572
  event: { type: "" },
518
573
  // TODO: unknown events?
519
- state: actorRef.getSnapshot()
574
+ state: actorRef.getSnapshot(),
575
+ machine: actorRef.src
520
576
  });
521
577
  }
522
578
  return {
@@ -526,13 +582,12 @@ function createAgent({
526
582
  // TODO: make this actually unsubscribe
527
583
  };
528
584
  };
585
+ agent.types = {};
529
586
  agent.start();
530
587
  return agent;
531
588
  }
532
589
  // Annotate the CommonJS export names for ESM import in node:
533
590
  0 && (module.exports = {
534
- agentDecide,
535
- agentGenerateText,
536
591
  createAgent,
537
592
  fromDecision,
538
593
  fromText,