@statelyai/agent 2.0.0-alpha.30 → 2.0.0-alpha.31

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 (68) hide show
  1. package/CHANGELOG.md +1733 -0
  2. package/dist/ai-sdk.cjs +8 -8
  3. package/dist/ai-sdk.d.cts +1 -1
  4. package/dist/ai-sdk.d.mts +1 -1
  5. package/dist/ai-sdk.mjs +3 -3
  6. package/dist/{decision-BHkvuImD.mjs → decision-DqO018Tp.mjs} +22 -9
  7. package/dist/{decision-CIb7ddIv.cjs → decision-Iys2hzg3.cjs} +30 -17
  8. package/dist/{event-log-BZRfBRd7.cjs → event-log-Bdww2l1D.cjs} +103 -24
  9. package/dist/{event-log-DJCMHek_.mjs → event-log-DE430ZCa.mjs} +86 -25
  10. package/dist/{event-log-store-DZR4IIWe.cjs → event-log-store-BWMLi6oh.cjs} +1 -1
  11. package/dist/{event-log-store-DsP6GCRh.mjs → event-log-store-CCWdTPEP.mjs} +1 -1
  12. package/dist/{event-log-store-CIIJohjj.d.mts → event-log-store-DTf_OzB-.d.cts} +1 -1
  13. package/dist/{event-log-store-CLAC9q2Y.d.cts → event-log-store-RziIobdW.d.mts} +1 -1
  14. package/dist/index.cjs +129 -21
  15. package/dist/index.d.cts +58 -11
  16. package/dist/index.d.mts +58 -11
  17. package/dist/index.mjs +126 -19
  18. package/dist/log.cjs +2 -2
  19. package/dist/log.d.cts +1 -1
  20. package/dist/log.d.mts +1 -1
  21. package/dist/log.mjs +2 -2
  22. package/dist/machines.cjs +1 -1
  23. package/dist/machines.mjs +1 -1
  24. package/dist/{model-source-BaHwJ1wK.mjs → model-source-CXsSZPq0.mjs} +1 -2
  25. package/dist/{model-source-BCKg4qJ1.cjs → model-source-DQ7KgJaT.cjs} +4 -5
  26. package/dist/openai.cjs +2 -2
  27. package/dist/openai.d.cts +1 -1
  28. package/dist/openai.d.mts +1 -1
  29. package/dist/openai.mjs +2 -2
  30. package/dist/otel.d.cts +1 -1
  31. package/dist/otel.d.mts +1 -1
  32. package/dist/{run-agent-CTlMc3Jb.d.cts → run-agent-B5opVUxx.d.cts} +17 -6
  33. package/dist/{run-agent-CAVt5R-r.d.mts → run-agent-D4MwS5GY.d.mts} +17 -6
  34. package/dist/{run-agent-BpHqkaZw.mjs → run-agent-DWZ1uyBJ.mjs} +89 -35
  35. package/dist/{run-agent-ctLCvNgL.cjs → run-agent-tmk58M0x.cjs} +89 -35
  36. package/dist/{setup-agent-7rV_cujV.mjs → setup-agent-BaffhCcM.mjs} +38 -3
  37. package/dist/{setup-agent-CGELn1qZ.d.mts → setup-agent-CPyg2ic7.d.mts} +11 -3
  38. package/dist/{setup-agent-DoUk7EdC.cjs → setup-agent-D0L8Anl_.cjs} +38 -3
  39. package/dist/{setup-agent-CLPCkXsu.d.cts → setup-agent-yFFVXf5s.d.cts} +11 -3
  40. package/dist/tanstack-ai.cjs +3 -3
  41. package/dist/tanstack-ai.d.cts +1 -1
  42. package/dist/tanstack-ai.d.mts +1 -1
  43. package/dist/tanstack-ai.mjs +3 -3
  44. package/dist/testing.cjs +73 -29
  45. package/dist/testing.d.cts +47 -10
  46. package/dist/testing.d.mts +47 -10
  47. package/dist/testing.mjs +65 -22
  48. package/dist/{text-logic-BRYOPWvY.d.mts → text-logic-BwdrDpO9.d.mts} +4 -0
  49. package/dist/{text-logic-DmciuVUQ.d.cts → text-logic-j9hShB7d.d.cts} +4 -0
  50. package/dist/{usage-BkM3z02Y.d.mts → usage-BYqv7VBw.d.cts} +1 -1
  51. package/dist/{usage-Cm_ovz9V.d.cts → usage-Bl4nK8D-.d.mts} +1 -1
  52. package/dist/validate.cjs +3 -3
  53. package/dist/validate.d.cts +2 -2
  54. package/dist/validate.d.mts +2 -2
  55. package/dist/validate.mjs +3 -3
  56. package/dist/{verify-COFWyprJ.mjs → verify-BH5e0XLK.mjs} +55 -5
  57. package/dist/{verify-Dzwd4Mvk.d.cts → verify-CPKDPMwY.d.cts} +14 -6
  58. package/dist/{verify-CVlsTZ-V.cjs → verify-CS_xxvVU.cjs} +57 -7
  59. package/dist/{verify-Cn86rT8l.d.mts → verify-tkymWz6X.d.mts} +14 -6
  60. package/package.json +34 -4
  61. package/readme.md +70 -40
  62. package/skills/add-evals/SKILL.md +23 -8
  63. package/skills/add-traces/SKILL.md +23 -11
  64. package/skills/generate-machine/SKILL.md +2 -2
  65. package/skills/graph-engineering/SKILL.md +1 -1
  66. package/skills/improve-machine/SKILL.md +7 -6
  67. package/skills/loop-to-machine/SKILL.md +34 -7
  68. package/skills/loop-to-machine/policy.md +14 -18
package/dist/ai-sdk.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_event_log = require("./event-log-BZRfBRd7.cjs");
3
- const require_decision = require("./decision-CIb7ddIv.cjs");
4
- const require_model_source = require("./model-source-BCKg4qJ1.cjs");
2
+ const require_event_log = require("./event-log-Bdww2l1D.cjs");
3
+ const require_decision = require("./decision-Iys2hzg3.cjs");
4
+ const require_model_source = require("./model-source-DQ7KgJaT.cjs");
5
5
  let ai = require("ai");
6
6
  //#region src/ai-sdk/mappers.ts
7
7
  /**
@@ -209,7 +209,7 @@ function toAiSdkOptionTool(options) {
209
209
  */
210
210
  function fromAiSdkOptionCall(toolCall, options, ids) {
211
211
  if (toolCall.toolName !== OPTION_TOOL_NAME) return unofferedOption(`tool '${toolCall.toolName}'`, ids);
212
- const id = require_decision.isRecord(toolCall.input) ? toolCall.input.option : void 0;
212
+ const id = require_event_log.isRecord(toolCall.input) ? toolCall.input.option : void 0;
213
213
  const option = typeof id === "string" ? options[ids.indexOf(id)] : void 0;
214
214
  return option ? option.event : unofferedOption(`option ${JSON.stringify(id)}`, ids);
215
215
  }
@@ -246,7 +246,7 @@ function maxStepsSetting(request) {
246
246
  return typeof maxSteps === "number" ? { stopWhen: (0, ai.stepCountIs)(maxSteps) } : {};
247
247
  }
248
248
  function isDecisionModel(model) {
249
- return require_decision.isRecord(model) && (typeof model.doDecide === "function" || typeof model.doEvaluate === "function");
249
+ return require_event_log.isRecord(model) && (typeof model.doDecide === "function" || typeof model.doEvaluate === "function");
250
250
  }
251
251
  /**
252
252
  * Splits a portable `"provider/model-id"` model ref (the convention JSON
@@ -498,16 +498,16 @@ function decisionResult(event, usage = {}, confidence) {
498
498
  };
499
499
  }
500
500
  function unofferedChoice(error, ids) {
501
- if (!ai.InvalidResponseDataError.isInstance(error) || !require_decision.isRecord(error.data)) return void 0;
501
+ if (!ai.InvalidResponseDataError.isInstance(error) || !require_event_log.isRecord(error.data)) return void 0;
502
502
  const answer = error.data[DECISION_QUESTION_ID];
503
- const choice = require_decision.isRecord(answer) ? answer.choice : void 0;
503
+ const choice = require_event_log.isRecord(answer) ? answer.choice : void 0;
504
504
  return typeof choice === "string" && !ids.includes(choice) ? choice : void 0;
505
505
  }
506
506
  function toDecisionState(value) {
507
507
  if (typeof value === "string") return value;
508
508
  try {
509
509
  const json = JSON.parse(JSON.stringify(value ?? {}));
510
- return require_decision.isRecord(json) ? json : { value: json };
510
+ return require_event_log.isRecord(json) ? json : { value: json };
511
511
  } catch {
512
512
  return String(value);
513
513
  }
package/dist/ai-sdk.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { s as AgentTools, u as ChosenEvent } from "./types-Dp5_Ru4R.cjs";
2
- import { N as AgentDecisionRequest, c as AgentRequestExecutorInfo, f as AgentTextRequest, r as AgentFinishReason, t as AgentCallUsage } from "./text-logic-DmciuVUQ.cjs";
2
+ import { N as AgentDecisionRequest, c as AgentRequestExecutorInfo, f as AgentTextRequest, r as AgentFinishReason, t as AgentCallUsage } from "./text-logic-j9hShB7d.cjs";
3
3
  import { Experimental_DecisionModel, FinishReason, LanguageModel, LanguageModelUsage, ModelMessage, ToolSet, TypedToolCall, TypedToolResult, generateText } from "ai";
4
4
  import { AnyStateMachine } from "xstate";
5
5
  //#region src/ai-sdk/mappers.d.ts
package/dist/ai-sdk.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { s as AgentTools, u as ChosenEvent } from "./types-Dp5_Ru4R.mjs";
2
- import { N as AgentDecisionRequest, c as AgentRequestExecutorInfo, f as AgentTextRequest, r as AgentFinishReason, t as AgentCallUsage } from "./text-logic-BRYOPWvY.mjs";
2
+ import { N as AgentDecisionRequest, c as AgentRequestExecutorInfo, f as AgentTextRequest, r as AgentFinishReason, t as AgentCallUsage } from "./text-logic-BwdrDpO9.mjs";
3
3
  import { AnyStateMachine } from "xstate";
4
4
  import { Experimental_DecisionModel, FinishReason, LanguageModel, LanguageModelUsage, ModelMessage, ToolSet, TypedToolCall, TypedToolResult, generateText } from "ai";
5
5
  //#region src/ai-sdk/mappers.d.ts
package/dist/ai-sdk.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { R as providerOutputSchema, ct as AgentTruncatedError, j as getAgentOutputMode, tt as isStandardSchema } from "./event-log-DJCMHek_.mjs";
2
- import { c as renderDecisionAttempts, m as isRecord, o as decisionOptionIds } from "./decision-BHkvuImD.mjs";
3
- import { t as resolveModelSource } from "./model-source-BaHwJ1wK.mjs";
1
+ import { R as providerOutputSchema, dt as AgentTruncatedError, j as getAgentOutputMode, lt as isRecord, tt as isStandardSchema } from "./event-log-DE430ZCa.mjs";
2
+ import { c as renderDecisionAttempts, o as decisionOptionIds } from "./decision-DqO018Tp.mjs";
3
+ import { t as resolveModelSource } from "./model-source-CXsSZPq0.mjs";
4
4
  import { InvalidResponseDataError, NoObjectGeneratedError, Output, experimental_decide, generateText, jsonSchema, stepCountIs, streamText, tool } from "ai";
5
5
  //#region src/ai-sdk/mappers.ts
6
6
  /**
@@ -1,11 +1,5 @@
1
- import { H as getAgentExecutionOptions, T as DECIDE_ACTOR, V as executorBoundLogics, at as userMessage, ot as validateSchemaSync, st as AgentError, u as canonicalEventJson, z as resolveTextLogicValue } from "./event-log-DJCMHek_.mjs";
1
+ import { H as getAgentExecutionOptions, T as DECIDE_ACTOR, V as executorBoundLogics, at as userMessage, lt as isRecord, ot as validateSchemaSync, u as canonicalEventJson, ut as AgentError, z as resolveTextLogicValue } from "./event-log-DE430ZCa.mjs";
2
2
  import { createAsyncLogic, getNextTransitions } from "xstate";
3
- //#region src/internal/is-record.ts
4
- /** True for a plain object-like value (arrays excluded). @internal */
5
- function isRecord(value) {
6
- return typeof value === "object" && value !== null && !Array.isArray(value);
7
- }
8
- //#endregion
9
3
  //#region src/events.ts
10
4
  /**
11
5
  * Thrown by {@link parseAgentEvent} (and {@link eventFromInteraction}) when a
@@ -135,14 +129,18 @@ function parseAgentEvent(source, payload, options = {}) {
135
129
  * ({@link RESERVED_AGENT_EVENT_PREFIX}) event types are always excluded, before
136
130
  * any `allowedEvents` matching — a machine that handles `'@agent.usage'` still
137
131
  * never offers it to a model.
132
+ *
133
+ * Pass `actor: "agent"` for the list a model may choose from: it also drops an
134
+ * event the state handles through a transition tagged `meta: { actor: "human" }`.
138
135
  */
139
136
  function getAcceptedEvents(snapshot, options = {}) {
140
137
  const eventTypes = options.eventTypes;
138
+ const humanEventTypes = options.actor === "agent" ? getHumanEventTypes(snapshot) : /* @__PURE__ */ new Set();
141
139
  const seen = /* @__PURE__ */ new Set();
142
140
  const usedToolNames = /* @__PURE__ */ new Set();
143
141
  return getNextTransitions(snapshot).flatMap((transitionDefinition) => {
144
142
  const eventType = transitionDefinition.eventType;
145
- if (!eventType || eventType === "*" || eventType.startsWith("xstate.") || isReservedAgentEvent(eventType) || eventTypes && !eventTypes.some((pattern) => matchesEventPattern(eventType, pattern)) || seen.has(eventType)) return [];
143
+ if (!eventType || eventType === "*" || eventType.startsWith("xstate.") || isReservedAgentEvent(eventType) || humanEventTypes.has(eventType) || eventTypes && !eventTypes.some((pattern) => matchesEventPattern(eventType, pattern)) || seen.has(eventType)) return [];
146
144
  seen.add(eventType);
147
145
  const toolName = disambiguateEventToolName(sanitizeEventToolName(eventType), eventType, usedToolNames);
148
146
  const inputSchema = (options.events ?? options.schemas?.events)?.[eventType];
@@ -153,6 +151,21 @@ function getAcceptedEvents(snapshot, options = {}) {
153
151
  }];
154
152
  });
155
153
  }
154
+ /**
155
+ * The event types a snapshot handles through a transition tagged
156
+ * `meta: { actor: "human" }`: a person sends them, so no model is offered them.
157
+ * @internal
158
+ */
159
+ function getHumanEventTypes(snapshot) {
160
+ let types = humanEventTypesBySnapshot.get(snapshot);
161
+ if (!types) {
162
+ types = /* @__PURE__ */ new Set();
163
+ for (const transition of getNextTransitions(snapshot)) if (transition.meta?.actor === "human") types.add(transition.eventType);
164
+ humanEventTypesBySnapshot.set(snapshot, types);
165
+ }
166
+ return types;
167
+ }
168
+ const humanEventTypesBySnapshot = /* @__PURE__ */ new WeakMap();
156
169
  //#endregion
157
170
  //#region src/decision.ts
158
171
  function optionsFromPayloads(eventTypes, payloads) {
@@ -517,4 +530,4 @@ async function resolveDecision(request, executors, options = {}) {
517
530
  throw new AgentDecisionExhaustedError(attempts);
518
531
  }
519
532
  //#endregion
520
- export { createDecisionRequest as a, renderDecisionAttempts as c, getAcceptedEvents as d, isEventPattern as f, createDecisionLogic as i, resolveDecision as l, isRecord as m, acceptedDecisionOptions as n, decisionOptionIds as o, parseAgentEvent as p, createDecideActor as r, isDecisionLogic as s, AgentDecisionExhaustedError as t, AgentInvalidEventPayloadError as u };
533
+ export { createDecisionRequest as a, renderDecisionAttempts as c, getAcceptedEvents as d, getHumanEventTypes as f, createDecisionLogic as i, resolveDecision as l, parseAgentEvent as m, acceptedDecisionOptions as n, decisionOptionIds as o, isEventPattern as p, createDecideActor as r, isDecisionLogic as s, AgentDecisionExhaustedError as t, AgentInvalidEventPayloadError as u };
@@ -1,11 +1,5 @@
1
- const require_event_log = require("./event-log-BZRfBRd7.cjs");
1
+ const require_event_log = require("./event-log-Bdww2l1D.cjs");
2
2
  let xstate = require("xstate");
3
- //#region src/internal/is-record.ts
4
- /** True for a plain object-like value (arrays excluded). @internal */
5
- function isRecord(value) {
6
- return typeof value === "object" && value !== null && !Array.isArray(value);
7
- }
8
- //#endregion
9
3
  //#region src/events.ts
10
4
  /**
11
5
  * Thrown by {@link parseAgentEvent} (and {@link eventFromInteraction}) when a
@@ -103,7 +97,7 @@ function isEventPattern(entry) {
103
97
  * ```
104
98
  */
105
99
  function parseAgentEvent(source, payload, options = {}) {
106
- if (!isRecord(payload) || typeof payload.type !== "string") throw new AgentInvalidEventPayloadError("(unknown)", "expected an object with a string `type`.");
100
+ if (!require_event_log.isRecord(payload) || typeof payload.type !== "string") throw new AgentInvalidEventPayloadError("(unknown)", "expected an object with a string `type`.");
107
101
  const event = payload;
108
102
  if (isReservedAgentEvent(event.type)) throw new AgentInvalidEventPayloadError(event.type, "this event type is reserved for the library and cannot be sent from outside.");
109
103
  const machine = typeof source.provide === "function" ? source : source.machine;
@@ -135,14 +129,18 @@ function parseAgentEvent(source, payload, options = {}) {
135
129
  * ({@link RESERVED_AGENT_EVENT_PREFIX}) event types are always excluded, before
136
130
  * any `allowedEvents` matching — a machine that handles `'@agent.usage'` still
137
131
  * never offers it to a model.
132
+ *
133
+ * Pass `actor: "agent"` for the list a model may choose from: it also drops an
134
+ * event the state handles through a transition tagged `meta: { actor: "human" }`.
138
135
  */
139
136
  function getAcceptedEvents(snapshot, options = {}) {
140
137
  const eventTypes = options.eventTypes;
138
+ const humanEventTypes = options.actor === "agent" ? getHumanEventTypes(snapshot) : /* @__PURE__ */ new Set();
141
139
  const seen = /* @__PURE__ */ new Set();
142
140
  const usedToolNames = /* @__PURE__ */ new Set();
143
141
  return (0, xstate.getNextTransitions)(snapshot).flatMap((transitionDefinition) => {
144
142
  const eventType = transitionDefinition.eventType;
145
- if (!eventType || eventType === "*" || eventType.startsWith("xstate.") || isReservedAgentEvent(eventType) || eventTypes && !eventTypes.some((pattern) => matchesEventPattern(eventType, pattern)) || seen.has(eventType)) return [];
143
+ if (!eventType || eventType === "*" || eventType.startsWith("xstate.") || isReservedAgentEvent(eventType) || humanEventTypes.has(eventType) || eventTypes && !eventTypes.some((pattern) => matchesEventPattern(eventType, pattern)) || seen.has(eventType)) return [];
146
144
  seen.add(eventType);
147
145
  const toolName = disambiguateEventToolName(sanitizeEventToolName(eventType), eventType, usedToolNames);
148
146
  const inputSchema = (options.events ?? options.schemas?.events)?.[eventType];
@@ -153,6 +151,21 @@ function getAcceptedEvents(snapshot, options = {}) {
153
151
  }];
154
152
  });
155
153
  }
154
+ /**
155
+ * The event types a snapshot handles through a transition tagged
156
+ * `meta: { actor: "human" }`: a person sends them, so no model is offered them.
157
+ * @internal
158
+ */
159
+ function getHumanEventTypes(snapshot) {
160
+ let types = humanEventTypesBySnapshot.get(snapshot);
161
+ if (!types) {
162
+ types = /* @__PURE__ */ new Set();
163
+ for (const transition of (0, xstate.getNextTransitions)(snapshot)) if (transition.meta?.actor === "human") types.add(transition.eventType);
164
+ humanEventTypesBySnapshot.set(snapshot, types);
165
+ }
166
+ return types;
167
+ }
168
+ const humanEventTypesBySnapshot = /* @__PURE__ */ new WeakMap();
156
169
  //#endregion
157
170
  //#region src/decision.ts
158
171
  function optionsFromPayloads(eventTypes, payloads) {
@@ -172,8 +185,8 @@ function optionsFromPayloads(eventTypes, payloads) {
172
185
  */
173
186
  function acceptedDecisionOptions(request, can) {
174
187
  if (!request.options) return void 0;
175
- const payloads = isRecord(request.input) ? request.input.payloads : void 0;
176
- return (isRecord(payloads) ? optionsFromPayloads(request.events.map((event) => event.type), payloads) : request.options).filter((option) => {
188
+ const payloads = require_event_log.isRecord(request.input) ? request.input.payloads : void 0;
189
+ return (require_event_log.isRecord(payloads) ? optionsFromPayloads(request.events.map((event) => event.type), payloads) : request.options).filter((option) => {
177
190
  try {
178
191
  return can(option.event);
179
192
  } catch {
@@ -565,22 +578,22 @@ Object.defineProperty(exports, "getAcceptedEvents", {
565
578
  return getAcceptedEvents;
566
579
  }
567
580
  });
568
- Object.defineProperty(exports, "isDecisionLogic", {
581
+ Object.defineProperty(exports, "getHumanEventTypes", {
569
582
  enumerable: true,
570
583
  get: function() {
571
- return isDecisionLogic;
584
+ return getHumanEventTypes;
572
585
  }
573
586
  });
574
- Object.defineProperty(exports, "isEventPattern", {
587
+ Object.defineProperty(exports, "isDecisionLogic", {
575
588
  enumerable: true,
576
589
  get: function() {
577
- return isEventPattern;
590
+ return isDecisionLogic;
578
591
  }
579
592
  });
580
- Object.defineProperty(exports, "isRecord", {
593
+ Object.defineProperty(exports, "isEventPattern", {
581
594
  enumerable: true,
582
595
  get: function() {
583
- return isRecord;
596
+ return isEventPattern;
584
597
  }
585
598
  });
586
599
  Object.defineProperty(exports, "parseAgentEvent", {
@@ -54,6 +54,31 @@ var AgentTruncatedError = class extends AgentError {
54
54
  }
55
55
  };
56
56
  //#endregion
57
+ //#region src/internal/is-record.ts
58
+ /** True for a plain object-like value (arrays excluded). @internal */
59
+ function isRecord(value) {
60
+ return typeof value === "object" && value !== null && !Array.isArray(value);
61
+ }
62
+ /**
63
+ * True for an object whose prototype is `null` or some realm's
64
+ * `Object.prototype`. Comparing against this realm's `Object.prototype` alone
65
+ * rejects plain objects built in another realm: a jest test file's vm
66
+ * context, or `structuredClone`'s output inside one. @internal
67
+ */
68
+ function isPlainObject(value) {
69
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
70
+ const prototype = Object.getPrototypeOf(value);
71
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
72
+ }
73
+ /** True for an `Error` from any realm, where `instanceof Error` sees only this one. @internal */
74
+ function isError(value) {
75
+ return value instanceof Error || Object.prototype.toString.call(value) === "[object Error]";
76
+ }
77
+ /** JSON text with object keys sorted and `undefined` fields dropped, for comparing JSON-like values. @internal */
78
+ function canonicalJson(value) {
79
+ return JSON.stringify(value, (_key, item) => isPlainObject(item) ? Object.fromEntries(Object.keys(item).sort().map((key) => [key, item[key]])) : item) ?? "undefined";
80
+ }
81
+ //#endregion
57
82
  //#region src/utils.ts
58
83
  /** Returns the human-readable text carried by a message, ignoring non-text parts. */
59
84
  function getMessageText(message) {
@@ -103,8 +128,7 @@ function findNonSerializableContextPaths(context, limit = 5) {
103
128
  seen.delete(obj);
104
129
  return;
105
130
  }
106
- const proto = Object.getPrototypeOf(value);
107
- if (proto === Object.prototype || proto === null) {
131
+ if (isPlainObject(value)) {
108
132
  seen.add(obj);
109
133
  for (const [key, item] of Object.entries(value)) walk(item, `${path}.${key}`);
110
134
  seen.delete(obj);
@@ -456,7 +480,7 @@ function responseMessagesOf(raw) {
456
480
  }
457
481
  function dropUndefined(value) {
458
482
  if (Array.isArray(value)) return value.map(dropUndefined);
459
- if (value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
483
+ if (isPlainObject(value)) {
460
484
  const out = {};
461
485
  for (const [key, entry] of Object.entries(value)) if (entry !== void 0) out[key] = dropUndefined(entry);
462
486
  return out;
@@ -932,8 +956,7 @@ function assertJsonSerializable(value, path = "entry", ancestors = /* @__PURE__
932
956
  assertNoHiddenKeys(value, path, (key) => key === "length" || arrayIndexPattern.test(key));
933
957
  return;
934
958
  }
935
- const prototype = Object.getPrototypeOf(value);
936
- if (prototype !== Object.prototype && prototype !== null) throw new NonSerializableAgentEventError(path, value.constructor?.name ?? "object");
959
+ if (!isPlainObject(value)) throw new NonSerializableAgentEventError(path, value.constructor?.name ?? "object");
937
960
  assertNoHiddenKeys(value, path);
938
961
  for (const [key, child] of Object.entries(value)) assertJsonSerializable(child, `${path}.${key}`, ancestors);
939
962
  } finally {
@@ -990,22 +1013,32 @@ function exhaustedAttemptsOf(error) {
990
1013
  return Array.isArray(attempts) && isJsonSerializable(attempts) ? attempts : void 0;
991
1014
  }
992
1015
  /**
993
- * Replaces `Error` instances with plain `{ name, message, cause? }` objects so
994
- * an `xstate.error.actor` payload survives the log's JSON round-trip. A
995
- * decision-exhausted error also keeps its `code` and `attempts`. Cycles
1016
+ * Marks an object {@link normalizeEventErrors} made from an `Error`, so replay
1017
+ * restores that object, and only that one, as an `Error`: a thrown plain
1018
+ * `{ name, message }` stays a plain object.
1019
+ */
1020
+ const NORMALIZED_ERROR_KEY = "@error";
1021
+ /**
1022
+ * Replaces `Error` instances with plain `{ name, message, code?, cause?,
1023
+ * "@error": true }` objects so an `xstate.error.actor` payload survives the
1024
+ * log's JSON round-trip. `code` is kept when it is a string or a number; a
1025
+ * decision-exhausted error also keeps its `attempts`. Replay turns the
1026
+ * object back into an `Error` (see `restoreJournaledEvent`). Cycles
996
1027
  * are preserved by identity; non-plain objects are left alone (and are then
997
1028
  * rejected by {@link assertJsonSerializable}).
998
1029
  */
999
1030
  function normalizeEventErrors(value, seen = /* @__PURE__ */ new WeakMap()) {
1000
- if (value instanceof Error) {
1031
+ if (isError(value)) {
1001
1032
  const normalized = {
1002
1033
  name: value.name,
1003
- message: value.message
1034
+ message: value.message,
1035
+ [NORMALIZED_ERROR_KEY]: true
1004
1036
  };
1005
1037
  seen.set(value, normalized);
1006
1038
  if (value.cause !== void 0) normalized.cause = normalizeEventErrors(value.cause, seen);
1007
- if (value.code === DECISION_EXHAUSTED_CODE) {
1008
- normalized.code = DECISION_EXHAUSTED_CODE;
1039
+ const code = value.code;
1040
+ if (typeof code === "string" || typeof code === "number" && Number.isFinite(code)) normalized.code = code;
1041
+ if (code === DECISION_EXHAUSTED_CODE) {
1009
1042
  const attempts = exhaustedAttemptsOf(value);
1010
1043
  if (attempts !== void 0) normalized.attempts = structuredClone(attempts);
1011
1044
  }
@@ -1020,8 +1053,7 @@ function normalizeEventErrors(value, seen = /* @__PURE__ */ new WeakMap()) {
1020
1053
  for (const item of value) result.push(normalizeEventErrors(item, seen));
1021
1054
  return result;
1022
1055
  }
1023
- const prototype = Object.getPrototypeOf(value);
1024
- if (prototype !== Object.prototype && prototype !== null) return value;
1056
+ if (!isPlainObject(value)) return value;
1025
1057
  const result = {};
1026
1058
  seen.set(value, result);
1027
1059
  for (const [key, item] of Object.entries(value)) result[key] = normalizeEventErrors(item, seen);
@@ -1046,7 +1078,7 @@ function canonicalizeForHash(value, seen = /* @__PURE__ */ new WeakSet(), positi
1046
1078
  if (typeof value === "symbol") return `[symbol:${String(value)}]`;
1047
1079
  if (value === null || typeof value !== "object") return value;
1048
1080
  if (value instanceof Date) return `[Date:${value.toISOString()}]`;
1049
- if (value instanceof Error) {
1081
+ if (isError(value)) {
1050
1082
  if (seen.has(value)) return "[circular]";
1051
1083
  seen.add(value);
1052
1084
  try {
@@ -1141,7 +1173,7 @@ function createReplayEntry(machine, entries, event, options = {}) {
1141
1173
  recordedAt: options.recordedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1142
1174
  machineId: machineIdOf(machine),
1143
1175
  machineVersion,
1144
- event: normalizeDoneActorEvent(normalizeEventErrors(event)),
1176
+ event: normalizeDoneActorEvent(pruneUndefined(normalizeEventErrors(event))),
1145
1177
  ...options.causationId !== void 0 ? { causationId: options.causationId } : {},
1146
1178
  ...options.metadata !== void 0 ? { metadata: options.metadata } : {},
1147
1179
  ...options.attempts !== void 0 && options.attempts.length > 0 ? { attempts: options.attempts } : {}
@@ -1154,15 +1186,23 @@ function createReplayEntry(machine, entries, event, options = {}) {
1154
1186
  }).persistedSnapshot) };
1155
1187
  return entry;
1156
1188
  }
1157
- function pruneUndefined(value) {
1158
- if (Array.isArray(value)) return value.map(pruneUndefined);
1189
+ function pruneUndefined(value, ancestors = /* @__PURE__ */ new WeakSet()) {
1159
1190
  if (value === null || typeof value !== "object") return value;
1160
- if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) return value;
1191
+ if (ancestors.has(value)) return value;
1192
+ if (Array.isArray(value)) {
1193
+ ancestors.add(value);
1194
+ const result = value.map((item) => pruneUndefined(item, ancestors));
1195
+ ancestors.delete(value);
1196
+ return result;
1197
+ }
1198
+ if (!isPlainObject(value)) return value;
1199
+ ancestors.add(value);
1161
1200
  const result = {};
1162
1201
  for (const [key, child] of Object.entries(value)) {
1163
1202
  if (child === void 0) continue;
1164
- result[key] = pruneUndefined(child);
1203
+ result[key] = pruneUndefined(child, ancestors);
1165
1204
  }
1205
+ ancestors.delete(value);
1166
1206
  return result;
1167
1207
  }
1168
1208
  /**
@@ -1359,12 +1399,33 @@ function rebindActorSession(event, snapshot, sessions) {
1359
1399
  sessionId
1360
1400
  };
1361
1401
  }
1362
- function restoreDoneActorOutput(event) {
1363
- if (event.type !== DONE_ACTOR_EVENT_TYPE || Object.hasOwn(event, "output")) return event;
1364
- return {
1402
+ /**
1403
+ * The event as the machine received it live: a done event's dropped
1404
+ * `undefined` output restored, and an error event's normalized error turned
1405
+ * back into an `Error`, so `error instanceof Error` holds on replay too.
1406
+ */
1407
+ function restoreJournaledEvent(event) {
1408
+ if (event.type === DONE_ACTOR_EVENT_TYPE && !Object.hasOwn(event, "output")) return {
1365
1409
  ...event,
1366
1410
  output: void 0
1367
1411
  };
1412
+ if (event.type.startsWith(ERROR_ACTOR_EVENT_TYPE)) {
1413
+ const error = event.error;
1414
+ if (isNormalizedError(error)) return {
1415
+ ...event,
1416
+ error: toError(error)
1417
+ };
1418
+ }
1419
+ return event;
1420
+ }
1421
+ function isNormalizedError(value) {
1422
+ return isPlainObject(value) && value[NORMALIZED_ERROR_KEY] === true && typeof value.name === "string" && typeof value.message === "string";
1423
+ }
1424
+ function toError(normalized) {
1425
+ const { name, message, cause, [NORMALIZED_ERROR_KEY]: _marker, ...rest } = normalized;
1426
+ const error = new Error(message, cause === void 0 ? void 0 : { cause: isNormalizedError(cause) ? toError(cause) : cause });
1427
+ error.name = name;
1428
+ return Object.assign(error, rest);
1368
1429
  }
1369
1430
  function verifyEntry(entry, persisted, mode) {
1370
1431
  if (mode === false) return;
@@ -1412,7 +1473,7 @@ function foldLog(machine, entries, options = {}) {
1412
1473
  verifyEntry(entries[0], persisted, options.verify);
1413
1474
  const sessions = /* @__PURE__ */ new Map();
1414
1475
  const apply = (entry) => {
1415
- const event = restoreDoneActorOutput(rebindActorSession(entry.event, snapshot, sessions));
1476
+ const event = restoreJournaledEvent(rebindActorSession(entry.event, snapshot, sessions));
1416
1477
  [snapshot] = (0, xstate.transition)(machine, snapshot, event);
1417
1478
  persisted = machine.getPersistedSnapshot(snapshot);
1418
1479
  return persisted;
@@ -1610,6 +1671,12 @@ Object.defineProperty(exports, "canonicalEventJson", {
1610
1671
  return canonicalEventJson;
1611
1672
  }
1612
1673
  });
1674
+ Object.defineProperty(exports, "canonicalJson", {
1675
+ enumerable: true,
1676
+ get: function() {
1677
+ return canonicalJson;
1678
+ }
1679
+ });
1613
1680
  Object.defineProperty(exports, "createReplayEntry", {
1614
1681
  enumerable: true,
1615
1682
  get: function() {
@@ -1742,6 +1809,18 @@ Object.defineProperty(exports, "initEntry", {
1742
1809
  return initEntry;
1743
1810
  }
1744
1811
  });
1812
+ Object.defineProperty(exports, "isPlainObject", {
1813
+ enumerable: true,
1814
+ get: function() {
1815
+ return isPlainObject;
1816
+ }
1817
+ });
1818
+ Object.defineProperty(exports, "isRecord", {
1819
+ enumerable: true,
1820
+ get: function() {
1821
+ return isRecord;
1822
+ }
1823
+ });
1745
1824
  Object.defineProperty(exports, "isStandardSchema", {
1746
1825
  enumerable: true,
1747
1826
  get: function() {