@noetaris/harness 0.11.0 → 0.13.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
@@ -564,6 +564,9 @@ function composeObservers(observers, onObserverError) {
564
564
  onStepSettled: (ctx, event) => {
565
565
  for (const o of observers) safeInvoke("onStepSettled", () => o.onStepSettled?.(ctx, event), onObserverError);
566
566
  },
567
+ onCheckpoint: (ctx, event) => {
568
+ for (const o of observers) safeInvoke("onCheckpoint", () => o.onCheckpoint?.(ctx, event), onObserverError);
569
+ },
567
570
  // Each observer isolated on its own; later keys win.
568
571
  carry: (ctx) => {
569
572
  let merged;
@@ -634,16 +637,14 @@ function extractRunListeners(resources) {
634
637
  // src/agent/ctx-within.ts
635
638
  function createWithinFn(observer, currentStep, onObserverError) {
636
639
  return (type, payload, fn) => {
637
- const wrap = observer?.wrap;
638
640
  const stepCtx = currentStep();
639
- if (wrap === void 0 || stepCtx === null) return fn();
640
- return runWrapped((inner) => wrap(stepCtx, { kind: "event", type, payload }, inner), fn, onObserverError);
641
+ if (observer?.wrap === void 0 || stepCtx === null) return fn();
642
+ return runWrapped((inner) => observer.wrap?.(stepCtx, { kind: "event", type, payload }, inner), fn, onObserverError);
641
643
  };
642
644
  }
643
645
  function runStepScope(observer, stepCtx, fn, onObserverError) {
644
- const wrap = observer?.wrap;
645
- if (wrap === void 0) return fn();
646
- return runWrapped((inner) => wrap(stepCtx, { kind: "step" }, inner), fn, onObserverError);
646
+ if (observer?.wrap === void 0) return fn();
647
+ return runWrapped((inner) => observer.wrap?.(stepCtx, { kind: "step" }, inner), fn, onObserverError);
647
648
  }
648
649
 
649
650
  // src/loop/loop-executor.ts
@@ -707,10 +708,9 @@ function applyUpdate(state, update, schema, touchedKeys) {
707
708
  }
708
709
  }
709
710
  function fireSettled(obs, stepCtx, stepStart, fields, onObserverError) {
710
- const hook = obs?.onStepSettled;
711
- if (hook === void 0) return;
711
+ if (obs?.onStepSettled === void 0) return;
712
712
  const event = { ...fields, durationMs: Date.now() - stepStart };
713
- safeInvoke("onStepSettled", () => hook(stepCtx, event), onObserverError);
713
+ safeInvoke("onStepSettled", () => obs.onStepSettled?.(stepCtx, event), onObserverError);
714
714
  }
715
715
  function stepContextOf(runCtx, stepName) {
716
716
  return {
@@ -769,12 +769,39 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
769
769
  ctx["within"] = createWithinFn(obs, () => stepCtxRef.current, onObserverError);
770
770
  const telemetryObserver = obs !== void 0 ? composeObservers([obs], onObserverError) : NOOP_OBSERVER;
771
771
  let cursor = startCursor ?? graph.entryStep;
772
+ let first = true;
772
773
  try {
773
- while (true) {
774
+ for (; ; first = false) {
774
775
  if (shouldStop?.()) {
775
776
  endRun("$stopped");
776
777
  return withCarrier({ state, signal: null, cursor, paused: true });
777
778
  }
779
+ if (callbacks?.debugGate !== void 0) {
780
+ const next = isForkCursor(cursor) ? cursor.fork : cursor;
781
+ const fork = isForkCursor(cursor) || graph.steps.some((s) => s.name === next && isForkDef(s));
782
+ const { patches, halt } = await callbacks.debugGate(next, state, {
783
+ branchPath: branchPath ?? [],
784
+ fork,
785
+ ...callbacks.touchedKeys !== void 0 ? { touchedKeys: callbacks.touchedKeys } : {},
786
+ ...ctx.signal !== void 0 ? { signal: ctx.signal } : {}
787
+ });
788
+ const nextCtx = stepContextOf(runCtx, next);
789
+ for (const patch of patches) {
790
+ safeInvoke("onEvent", () => obs?.onEvent?.(nextCtx, "debug.setState", { patch }), onObserverError);
791
+ }
792
+ if (halt || shouldStop?.()) {
793
+ endRun("$stopped");
794
+ return withCarrier({ state, signal: null, cursor, paused: true });
795
+ }
796
+ }
797
+ if (!first && callbacks?.checkpoint !== void 0 && typeof cursor === "string") {
798
+ const started = Date.now();
799
+ const saved = await callbacks.checkpoint(cursor, state, carrier);
800
+ if (saved !== void 0) {
801
+ const event = { step: cursor, version: saved.version, durationMs: Date.now() - started };
802
+ safeInvoke("onCheckpoint", () => obs?.onCheckpoint?.(runCtx, event), onObserverError);
803
+ }
804
+ }
778
805
  if (isForkCursor(cursor)) {
779
806
  const forkCursor = cursor;
780
807
  const forkNode = graph.steps.find((s) => s.name === forkCursor.fork);
@@ -961,7 +988,7 @@ async function dispatchFork(forkNode, priorBranches, outerState, outerCtx, schem
961
988
  const branchSignals = forkNode.branches.map(
962
989
  (_, i) => outerSignal !== void 0 ? AbortSignal.any([outerSignal, localAborts[i].signal]) : localAborts[i].signal
963
990
  );
964
- const { onBeforeStep: _outerOnBeforeStep, onAfterStep: _outerOnAfterStep, onComplete: _outerOnComplete, ...branchCallbacksRest } = callbacks ?? {};
991
+ const { onBeforeStep: _outerOnBeforeStep, onAfterStep: _outerOnAfterStep, onComplete: _outerOnComplete, checkpoint: _outerCheckpoint, ...branchCallbacksRest } = callbacks ?? {};
965
992
  const branchCallbacksBase = callbacks !== void 0 ? branchCallbacksRest : void 0;
966
993
  const settled = await Promise.allSettled(
967
994
  forkNode.branches.map(async (branch, i) => {
@@ -1028,6 +1055,7 @@ async function dispatchFork(forkNode, priorBranches, outerState, outerCtx, schem
1028
1055
  } else {
1029
1056
  outerState[key] = outcome.result.state[key];
1030
1057
  }
1058
+ callbacks?.touchedKeys?.add(key);
1031
1059
  }
1032
1060
  }
1033
1061
  return {
@@ -1093,6 +1121,13 @@ function defaultClaimTtlMs() {
1093
1121
  const ttlMs = Number(process.env["HARNESS_CLAIM_TTL_MS"]);
1094
1122
  return isValidTtlMs(ttlMs) ? ttlMs : 3e4;
1095
1123
  }
1124
+ function isCheckpointMode(value) {
1125
+ return value === "off" || value === "step";
1126
+ }
1127
+ async function saveRun(store, agentId, sessionId, run, lease) {
1128
+ if (lease !== null && lease !== void 0) await store.save(agentId, sessionId, run, { lease });
1129
+ else await store.save(agentId, sessionId, run);
1130
+ }
1096
1131
  function collectPendingInterrupts(cursor, state) {
1097
1132
  if (cursor !== void 0 && isForkCursor(cursor)) {
1098
1133
  const result = [];
@@ -1114,14 +1149,23 @@ function storedSessionToPhase(loaded) {
1114
1149
  if (loaded === null) {
1115
1150
  return { phase: "fresh" };
1116
1151
  }
1152
+ const step = loaded.step === void 0 ? "" : isForkCursor(loaded.step) ? loaded.step.fork : loaded.step;
1117
1153
  if (loaded.phase === "paused") {
1118
- const step = loaded.step === void 0 ? "" : isForkCursor(loaded.step) ? loaded.step.fork : loaded.step;
1119
1154
  const pendingInterrupts = collectPendingInterrupts(loaded.step, loaded.finalState);
1120
1155
  if (loaded.signal !== void 0) {
1121
1156
  return { phase: "paused", step, signal: loaded.signal, pendingInterrupts };
1122
1157
  }
1123
1158
  return { phase: "paused", step, pendingInterrupts };
1124
1159
  }
1160
+ if (loaded.phase === "running") {
1161
+ const instanceId = loaded.metadata?.instanceId;
1162
+ return {
1163
+ phase: "running",
1164
+ step,
1165
+ ...instanceId !== void 0 ? { instanceId } : {},
1166
+ checkpointedAt: loaded.settledAt
1167
+ };
1168
+ }
1125
1169
  if (loaded.signal !== void 0) {
1126
1170
  return { phase: "completed", signal: loaded.signal };
1127
1171
  }
@@ -1183,6 +1227,15 @@ var SessionInFlightError = class extends Error {
1183
1227
  this.sessionId = sessionId;
1184
1228
  }
1185
1229
  };
1230
+ var SessionInDebugError = class extends Error {
1231
+ /** The session being debugged. */
1232
+ sessionId;
1233
+ constructor(sessionId) {
1234
+ super(`session "${sessionId}" is being debugged`);
1235
+ this.name = "SessionInDebugError";
1236
+ this.sessionId = sessionId;
1237
+ }
1238
+ };
1186
1239
  var SessionPendingInterruptError = class extends Error {
1187
1240
  /** The session that is awaiting an interrupt response. */
1188
1241
  sessionId;
@@ -1213,12 +1266,19 @@ var SessionBusyError = class extends Error {
1213
1266
  var LeaseExpiredError = class extends Error {
1214
1267
  /** The session whose lease expired. */
1215
1268
  sessionId;
1216
- constructor(sessionId) {
1269
+ constructor(sessionId, cause) {
1217
1270
  super(`lease for session "${sessionId}" has expired \u2014 run stopped without saving`);
1218
1271
  this.name = "LeaseExpiredError";
1219
1272
  this.sessionId = sessionId;
1273
+ if (cause !== void 0) this.cause = cause;
1220
1274
  }
1221
1275
  };
1276
+ function isLeaseLost(error) {
1277
+ return error instanceof Error && error.name === "LeaseLostError";
1278
+ }
1279
+ function isConflict(error) {
1280
+ return error instanceof Error && error.name === "ConcurrentModificationError";
1281
+ }
1222
1282
 
1223
1283
  // src/agent/ctx-keep-alive.ts
1224
1284
  function createKeepAliveFn(leaseRef, store, originalTtlMs) {
@@ -1328,7 +1388,7 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1328
1388
  }
1329
1389
  return false;
1330
1390
  };
1331
- const { mode = "run", requestId: callerRequestId, ...loopOptions } = options ?? {};
1391
+ const { mode = "run", requestId: callerRequestId, checkpoint: checkpointMode = "off", ...loopOptions } = options ?? {};
1332
1392
  if (store === void 0) {
1333
1393
  const state2 = initializeState(null, initialStateArg, schema);
1334
1394
  const result2 = await runLoop(graph, state2, ctx, schema, composedShouldStop, void 0, {
@@ -1369,7 +1429,7 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1369
1429
  state: row.finalState,
1370
1430
  signal: row.signal ?? null,
1371
1431
  cursor: row.step ?? null,
1372
- paused: row.phase === "paused"
1432
+ paused: row.phase !== "completed"
1373
1433
  };
1374
1434
  }
1375
1435
  const segmentRequestId = mode === "run" ? requestId : loaded?.requestId;
@@ -1378,8 +1438,47 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1378
1438
  const state = initializeState(base, input, schema);
1379
1439
  const initialStateSnapshot = { ...state };
1380
1440
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
1441
+ const metadata = options?.instanceId !== void 0 ? { instanceId: options.instanceId } : void 0;
1442
+ let nextVersion = (loaded?.version ?? -1) + 1;
1443
+ const baseRow = (carrier) => ({
1444
+ agentId,
1445
+ runId,
1446
+ sessionId,
1447
+ version: nextVersion,
1448
+ startedAt,
1449
+ settledAt: (/* @__PURE__ */ new Date()).toISOString(),
1450
+ initialState: initialStateSnapshot,
1451
+ ...metadata !== void 0 ? { metadata } : {},
1452
+ ...carrier !== void 0 ? { carrier } : {},
1453
+ ...segmentRequestId !== void 0 ? { requestId: segmentRequestId } : {}
1454
+ });
1455
+ const checkpoint = async (next, live, carrier) => {
1456
+ let finalState;
1457
+ try {
1458
+ finalState = structuredClone(live);
1459
+ } catch (error) {
1460
+ options?.onStoreError?.(error, "checkpoint");
1461
+ return void 0;
1462
+ }
1463
+ const row = { ...baseRow(carrier), phase: "running", step: next, finalState };
1464
+ try {
1465
+ await saveRun(store, agentId, sessionId, row, leaseRef.current);
1466
+ } catch (error) {
1467
+ if (isLeaseLost(error) || isConflict(error)) {
1468
+ const expiredError = new LeaseExpiredError(sessionId, error);
1469
+ options?.onStoreError?.(expiredError, "claim");
1470
+ throw expiredError;
1471
+ }
1472
+ options?.onStoreError?.(error, "checkpoint");
1473
+ return void 0;
1474
+ }
1475
+ nextVersion++;
1476
+ await extendLease(store, leaseRef, options?.claimTtlMs ?? defaultClaimTtlMs());
1477
+ return { version: row.version };
1478
+ };
1381
1479
  const result = await runLoop(graph, state, ctx, schema, composedShouldStop, loaded?.step, {
1382
1480
  ...loopOptions,
1481
+ ...checkpointMode === "step" ? { checkpoint } : {},
1383
1482
  runId,
1384
1483
  ...options?.parentRunId !== void 0 ? { parentRunId: options.parentRunId } : {},
1385
1484
  ...segmentRequestId !== void 0 ? { requestId: segmentRequestId } : {},
@@ -1390,53 +1489,39 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1390
1489
  options?.onStoreError?.(expiredError, "claim");
1391
1490
  throw expiredError;
1392
1491
  }
1393
- const settledAt = (/* @__PURE__ */ new Date()).toISOString();
1394
- const metadata = options?.instanceId !== void 0 ? { instanceId: options.instanceId } : void 0;
1492
+ const saved = {
1493
+ ...baseRow(result.carrier),
1494
+ phase: result.paused ? "paused" : "completed",
1495
+ finalState: result.state,
1496
+ ...result.paused ? { step: result.cursor } : {},
1497
+ ...result.signal !== null ? { signal: result.signal } : {}
1498
+ };
1395
1499
  try {
1396
- const version = (loaded?.version ?? -1) + 1;
1397
- if (result.paused) {
1398
- const saved = {
1399
- agentId,
1400
- runId,
1401
- sessionId,
1402
- version,
1403
- startedAt,
1404
- settledAt,
1405
- phase: "paused",
1406
- initialState: initialStateSnapshot,
1407
- finalState: result.state,
1408
- step: result.cursor,
1409
- ...result.signal !== null ? { signal: result.signal } : {},
1410
- ...metadata !== void 0 ? { metadata } : {},
1411
- ...result.carrier !== void 0 ? { carrier: result.carrier } : {},
1412
- ...segmentRequestId !== void 0 ? { requestId: segmentRequestId } : {}
1413
- };
1414
- await store.save(agentId, sessionId, saved);
1415
- } else {
1416
- const saved = {
1417
- agentId,
1418
- runId,
1419
- sessionId,
1420
- version,
1421
- startedAt,
1422
- settledAt,
1423
- phase: "completed",
1424
- initialState: initialStateSnapshot,
1425
- finalState: result.state,
1426
- ...result.signal !== null ? { signal: result.signal } : {},
1427
- ...metadata !== void 0 ? { metadata } : {},
1428
- ...result.carrier !== void 0 ? { carrier: result.carrier } : {},
1429
- ...segmentRequestId !== void 0 ? { requestId: segmentRequestId } : {}
1430
- };
1431
- await store.save(agentId, sessionId, saved);
1432
- }
1500
+ await saveRun(store, agentId, sessionId, saved, leaseRef.current);
1433
1501
  } catch (error) {
1502
+ if (isLeaseLost(error)) {
1503
+ const expiredError = new LeaseExpiredError(sessionId, error);
1504
+ options?.onStoreError?.(expiredError, "claim");
1505
+ throw expiredError;
1506
+ }
1434
1507
  options?.onStoreError?.(error, "persist");
1435
1508
  }
1436
1509
  return result;
1437
1510
  }
1511
+ async function extendLease(store, leaseRef, ttlMs) {
1512
+ const held = leaseRef.current;
1513
+ if (held === null || typeof store.extendClaim !== "function") return;
1514
+ try {
1515
+ leaseRef.current = await store.extendClaim(held, { ttlMs });
1516
+ } catch {
1517
+ }
1518
+ }
1438
1519
 
1439
1520
  // src/agent/claim-scope.ts
1521
+ function heldLease(options) {
1522
+ const lease = options.leaseRef?.current ?? null;
1523
+ return lease !== null ? { lease } : {};
1524
+ }
1440
1525
  function failOutcome(failState, error) {
1441
1526
  const state = failState();
1442
1527
  state["$error"] = error;
@@ -1530,7 +1615,7 @@ function injectInterruptResponseIntoState(cursor, state, interruptId, response)
1530
1615
  found: true
1531
1616
  };
1532
1617
  }
1533
- async function injectInterruptResponse(store, agentId, sessionId, interruptId, response) {
1618
+ async function injectInterruptResponse(store, agentId, sessionId, interruptId, response, lease) {
1534
1619
  const loaded = await store.load(agentId, sessionId);
1535
1620
  if (loaded === null) throw new NoInterruptError();
1536
1621
  if (loaded.phase !== "paused") throw new NoInterruptError();
@@ -1553,14 +1638,19 @@ async function injectInterruptResponse(store, agentId, sessionId, interruptId, r
1553
1638
  ...loaded.branchedFrom !== void 0 ? { branchedFrom: loaded.branchedFrom } : {},
1554
1639
  ...loaded.requestId !== void 0 ? { requestId: loaded.requestId } : {}
1555
1640
  };
1556
- await store.save(agentId, sessionId, updated);
1641
+ await saveRun(store, agentId, sessionId, updated, lease);
1557
1642
  }
1558
1643
  async function injectThenRun(args) {
1559
- const { store, agentId, sessionId, interruptId, response, onStoreError, failState, run } = args;
1644
+ const { store, agentId, sessionId, interruptId, response, lease, onStoreError, failState, run } = args;
1560
1645
  try {
1561
- await injectInterruptResponse(store, agentId, sessionId, interruptId, response);
1646
+ await injectInterruptResponse(store, agentId, sessionId, interruptId, response, lease);
1562
1647
  } catch (injectError) {
1563
1648
  if (injectError instanceof NoInterruptError) throw injectError;
1649
+ if (isLeaseLost(injectError)) {
1650
+ const expiredError = new LeaseExpiredError(sessionId, injectError);
1651
+ onStoreError?.(expiredError, "claim");
1652
+ return failOutcome(failState, expiredError);
1653
+ }
1564
1654
  const storeError = new StoreLoadError(injectError);
1565
1655
  onStoreError?.(storeError, "claim");
1566
1656
  return failOutcome(failState, storeError);
@@ -1617,6 +1707,572 @@ function createRunHandle(sessionId, runId, execution, stopFlag, stepRef, resumeF
1617
1707
  return handle;
1618
1708
  }
1619
1709
 
1710
+ // src/agent/debug-session.ts
1711
+ var DebugCommandError = class extends Error {
1712
+ /**
1713
+ * - `busy`: another command is still running
1714
+ * - `not-held`: the focused frame is not held at a step stop (or, for `answer`, the session is not at
1715
+ * an interrupt stop; for `focus`, the frame is not held)
1716
+ * - `not-a-fork`: `stepInto` where the next step is not a fork node
1717
+ * - `reserved-key`: `setState` was given a framework key (`$…`)
1718
+ * - `ended`: the session is over
1719
+ */
1720
+ reason;
1721
+ /** The command that was refused. */
1722
+ command;
1723
+ constructor(reason, command, detail) {
1724
+ super(`${command}(): ${detail ?? describeReason(reason)}`);
1725
+ this.name = "DebugCommandError";
1726
+ this.reason = reason;
1727
+ this.command = command;
1728
+ }
1729
+ };
1730
+ function describeReason(reason) {
1731
+ switch (reason) {
1732
+ case "busy":
1733
+ return "another debug command is still running";
1734
+ case "not-held":
1735
+ return "the debug session is not stopped where this command applies";
1736
+ case "not-a-fork":
1737
+ return "the next step is not a fork";
1738
+ case "reserved-key":
1739
+ return "framework keys ($\u2026) cannot be set";
1740
+ case "ended":
1741
+ return "the debug session has ended";
1742
+ }
1743
+ }
1744
+ function cloneOrShare(value) {
1745
+ try {
1746
+ return { value: structuredClone(value), shared: false };
1747
+ } catch {
1748
+ return { value, shared: true };
1749
+ }
1750
+ }
1751
+ function snapshotOf(source) {
1752
+ const values = {};
1753
+ const shared = [];
1754
+ for (const [key, raw] of Object.entries(source)) {
1755
+ const copy = cloneOrShare(raw);
1756
+ values[key] = copy.value;
1757
+ if (copy.shared) shared.push(key);
1758
+ }
1759
+ return { values, shared };
1760
+ }
1761
+ function deferred() {
1762
+ let resolve;
1763
+ let reject;
1764
+ const promise = new Promise((res, rej) => {
1765
+ resolve = res;
1766
+ reject = rej;
1767
+ });
1768
+ promise.catch(() => {
1769
+ });
1770
+ return { promise, resolve, reject };
1771
+ }
1772
+ var keyOf = (path) => JSON.stringify(path);
1773
+ var samePath = (a, b) => a.length === b.length && a.every((s, i) => s === b[i]);
1774
+ var within = (path, root) => path.length >= root.length && root.every((s, i) => s === path[i]);
1775
+ function branchStart(parentForkMode) {
1776
+ return {
1777
+ mode: parentForkMode === "fork-entry" ? "fork-entry" : "continue",
1778
+ lastRelease: parentForkMode === "continue" || parentForkMode === void 0 ? "continue" : "hold"
1779
+ };
1780
+ }
1781
+ function createDebugSession(args) {
1782
+ const { store, signal, onEnd } = args;
1783
+ let status = "starting";
1784
+ let handle;
1785
+ let topMode = "start";
1786
+ let frames = /* @__PURE__ */ new Map();
1787
+ let seq = 0;
1788
+ let focus = [];
1789
+ let lastByFrame = /* @__PURE__ */ new Map();
1790
+ let topInterrupt;
1791
+ let interrupts = [];
1792
+ let pausedForks = /* @__PURE__ */ new Map();
1793
+ let paused;
1794
+ let stopRequested = false;
1795
+ let lease = {};
1796
+ let renewal;
1797
+ const breakpoints = /* @__PURE__ */ new Map();
1798
+ let command;
1799
+ let idle;
1800
+ const first = deferred();
1801
+ let current = first.promise;
1802
+ let started = false;
1803
+ const ended = deferred();
1804
+ const done = deferred();
1805
+ const anyHeld = () => [...frames.values()].some((f) => f.status === "held");
1806
+ const updateRenewal = () => {
1807
+ if (!anyHeld()) {
1808
+ if (renewal !== void 0) clearInterval(renewal);
1809
+ renewal = void 0;
1810
+ return;
1811
+ }
1812
+ if (renewal !== void 0) return;
1813
+ const { leaseRef, claimTtlMs } = lease;
1814
+ const extendClaim = store?.extendClaim;
1815
+ if (leaseRef === void 0 || claimTtlMs === void 0 || typeof extendClaim !== "function") return;
1816
+ const renew = () => {
1817
+ const held = leaseRef.current;
1818
+ if (held === null) return;
1819
+ extendClaim.call(store, held, { ttlMs: claimTtlMs }).then((renewed) => {
1820
+ leaseRef.current = renewed;
1821
+ }, () => {
1822
+ });
1823
+ };
1824
+ renew();
1825
+ renewal = setInterval(renew, claimTtlMs / 3);
1826
+ renewal.unref?.();
1827
+ };
1828
+ const frameOf = (path) => frames.get(keyOf(path));
1829
+ const addFrame = (path, init) => {
1830
+ const frame = { path, seq: seq++, patches: [], ...init };
1831
+ frames.set(keyOf(path), frame);
1832
+ return frame;
1833
+ };
1834
+ const treeOrder = (a, b) => {
1835
+ const n = Math.min(a.path.length, b.path.length);
1836
+ for (let i = 0; i < n; i++) {
1837
+ if (a.path[i] !== b.path[i]) {
1838
+ const sa = frameOf(a.path.slice(0, i + 1))?.seq ?? 0;
1839
+ const sb = frameOf(b.path.slice(0, i + 1))?.seq ?? 0;
1840
+ return sa - sb;
1841
+ }
1842
+ }
1843
+ return a.path.length - b.path.length;
1844
+ };
1845
+ const sortedFrames = () => [...frames.values()].sort(treeOrder);
1846
+ const dropDescendants = (root) => {
1847
+ for (const [key, frame] of frames) {
1848
+ if (frame.path.length > root.length && within(frame.path, root)) frames.delete(key);
1849
+ }
1850
+ };
1851
+ const seedPausedFork = (frame, forkName) => {
1852
+ const settled = pausedForks.get(keyOf(frame.path));
1853
+ if (settled?.fork === void 0 || settled.name !== forkName) return;
1854
+ pausedForks.delete(keyOf(frame.path));
1855
+ for (const branch of settled.fork.branches) {
1856
+ addFrame([...frame.path, branch.name], { status: branch.status === "done" ? "ended" : "running", ...branchStart(frame.forkMode) });
1857
+ }
1858
+ };
1859
+ const setCurrent = (stop) => {
1860
+ current = Promise.resolve(stop);
1861
+ if (!started) {
1862
+ started = true;
1863
+ first.resolve(stop);
1864
+ }
1865
+ };
1866
+ const deliver = (stop, frame) => {
1867
+ focus = frame;
1868
+ setCurrent(stop);
1869
+ const c = command;
1870
+ command = void 0;
1871
+ c?.result.resolve(stop);
1872
+ const w = idle;
1873
+ idle = void 0;
1874
+ w?.resolve(stop);
1875
+ };
1876
+ const offerStop = (stop) => {
1877
+ if (!started) return deliver(stop, stop.frame);
1878
+ if (command !== void 0) {
1879
+ const { target, orphan } = command;
1880
+ if (target === "any" || orphan !== void 0 || within(stop.frame, target)) deliver(stop, stop.frame);
1881
+ return;
1882
+ }
1883
+ if (idle !== void 0) deliver(stop, stop.frame);
1884
+ };
1885
+ const branchEndStop = (frame, endedFrame) => {
1886
+ const held = frame.stop;
1887
+ const stop = {
1888
+ kind: "step",
1889
+ frame: frame.path,
1890
+ reason: "branch-end",
1891
+ ended: endedFrame,
1892
+ runId: held.runId,
1893
+ next: held.next,
1894
+ ...held.last !== void 0 ? { last: held.last } : {},
1895
+ state: held.state
1896
+ };
1897
+ frame.stop = stop;
1898
+ return stop;
1899
+ };
1900
+ const afterFrameEnd = (endedFrame) => {
1901
+ setTimeout(() => {
1902
+ if (status !== "active") return;
1903
+ const heldFrame = sortedFrames().find((f) => f.status === "held");
1904
+ if (command !== void 0) {
1905
+ if (command.orphan !== endedFrame) return;
1906
+ if (heldFrame !== void 0) deliver(branchEndStop(heldFrame, endedFrame), heldFrame.path);
1907
+ return;
1908
+ }
1909
+ if (!samePath(focus, endedFrame.frame)) return;
1910
+ if (heldFrame !== void 0) {
1911
+ focus = heldFrame.path;
1912
+ setCurrent(branchEndStop(heldFrame, endedFrame));
1913
+ } else {
1914
+ idle ??= deferred();
1915
+ current = idle.promise;
1916
+ }
1917
+ }, 0);
1918
+ };
1919
+ const onFrameEnd = (path, signal2) => {
1920
+ const frame = frameOf(path);
1921
+ if (frame === void 0) return;
1922
+ frame.status = "ended";
1923
+ const parent = frameOf(path.slice(0, -1));
1924
+ if (parent !== void 0) parent.joinHold = frame.lastRelease === "hold";
1925
+ const outcome = signal2 === "$interrupt" ? "interrupt" : signal2 === "$error" ? "error" : signal2 === "$stopped" ? "stopped" : "done";
1926
+ const last = lastByFrame.get(keyOf(path));
1927
+ const endedFrame = { frame: path, outcome, ...last !== void 0 ? { last } : {} };
1928
+ updateRenewal();
1929
+ if (command !== void 0) {
1930
+ if (command.target !== "any" && samePath(command.target, path)) {
1931
+ command.orphan = endedFrame;
1932
+ afterFrameEnd(endedFrame);
1933
+ }
1934
+ return;
1935
+ }
1936
+ if (samePath(focus, path)) afterFrameEnd(endedFrame);
1937
+ };
1938
+ const onAbort = () => {
1939
+ void session.stop();
1940
+ };
1941
+ const cleanup = () => {
1942
+ for (const frame of frames.values()) if (frame.status === "held") frame.status = "ended";
1943
+ updateRenewal();
1944
+ signal?.removeEventListener("abort", onAbort);
1945
+ onEnd();
1946
+ };
1947
+ const topLast = () => lastByFrame.get(keyOf([]));
1948
+ const finish = (outcome) => {
1949
+ const last = topLast();
1950
+ const stop = { kind: "end", runId: handle.runId, ...last !== void 0 ? { last } : {}, outcome };
1951
+ status = "ended";
1952
+ cleanup();
1953
+ done.resolve(outcome);
1954
+ deliver(stop, []);
1955
+ ended.resolve(stop);
1956
+ };
1957
+ const fail = (error) => {
1958
+ status = "ended";
1959
+ cleanup();
1960
+ done.reject(error);
1961
+ const c = command;
1962
+ command = void 0;
1963
+ c?.result.reject(error);
1964
+ const w = idle;
1965
+ idle = void 0;
1966
+ w?.reject(error);
1967
+ if (!started) first.reject(error);
1968
+ else current = done.promise.then(() => {
1969
+ throw error;
1970
+ });
1971
+ current.catch(() => {
1972
+ });
1973
+ ended.reject(error);
1974
+ };
1975
+ const pendingInterrupts = () => {
1976
+ const pending = [];
1977
+ const walk = (path) => {
1978
+ const settled = lastByFrame.get(keyOf(path));
1979
+ if (settled?.fork === void 0) return;
1980
+ for (const branch of settled.fork.branches) {
1981
+ if (branch.status !== "paused") continue;
1982
+ const branchPath = [...path, branch.name];
1983
+ const raised = interrupts.find((i) => samePath(i.branchPath, branchPath));
1984
+ if (raised !== void 0) pending.push({ interruptId: raised.interruptId, prompt: raised.prompt, frame: branchPath });
1985
+ else walk(branchPath);
1986
+ }
1987
+ };
1988
+ if (topInterrupt !== void 0 && topLast()?.fork === void 0) {
1989
+ pending.push({ interruptId: topInterrupt.interruptId, prompt: topInterrupt.prompt, frame: [] });
1990
+ } else {
1991
+ walk([]);
1992
+ }
1993
+ return pending;
1994
+ };
1995
+ const attach = (h) => {
1996
+ h.then((outcome) => {
1997
+ const last = topLast();
1998
+ if (outcome.signal === "$interrupt" && !stopRequested && last !== void 0) {
1999
+ const pending = pendingInterrupts();
2000
+ const head = pending[0];
2001
+ if (head !== void 0) {
2002
+ status = "interrupt";
2003
+ paused = { outcome, pending };
2004
+ for (const frame of frames.values()) if (frame.status === "held") frame.status = "ended";
2005
+ updateRenewal();
2006
+ deliver({
2007
+ kind: "interrupt",
2008
+ frame: head.frame,
2009
+ runId: h.runId,
2010
+ last,
2011
+ interruptId: head.interruptId,
2012
+ prompt: head.prompt,
2013
+ pending,
2014
+ state: snapshotOf(outcome.state)
2015
+ }, head.frame);
2016
+ return;
2017
+ }
2018
+ }
2019
+ finish(outcome);
2020
+ }, fail);
2021
+ };
2022
+ const gate = async (next, state, info) => {
2023
+ const path = info.branchPath;
2024
+ let frame = frameOf(path);
2025
+ if (frame === void 0) {
2026
+ if (path.length === 0) {
2027
+ frame = addFrame(path, { status: "running", mode: topMode, lastRelease: "hold" });
2028
+ } else {
2029
+ frame = addFrame(path, { status: "running", ...branchStart(frameOf(path.slice(0, -1))?.forkMode) });
2030
+ }
2031
+ } else if (frame.status === "in-fork") {
2032
+ dropDescendants(path);
2033
+ frame.mode = frame.joinHold === false ? "continue" : "step";
2034
+ frame.joinHold = void 0;
2035
+ frame.forkMode = void 0;
2036
+ }
2037
+ if (info.signal?.aborted === true) return { patches: [], halt: true };
2038
+ let reason;
2039
+ let condition;
2040
+ if (frame.mode !== "continue") {
2041
+ reason = frame.mode;
2042
+ } else {
2043
+ const breakpoint = breakpoints.get(next);
2044
+ if (breakpoint !== void 0) {
2045
+ try {
2046
+ if (breakpoint.when === void 0 || breakpoint.when(state)) reason = "breakpoint";
2047
+ } catch (error) {
2048
+ reason = "breakpoint";
2049
+ condition = { error };
2050
+ }
2051
+ }
2052
+ }
2053
+ const enter = () => {
2054
+ frame.before = snapshotOf(state);
2055
+ if (info.fork) {
2056
+ frame.status = "in-fork";
2057
+ frame.forkMode ??= frame.mode === "continue" ? "continue" : "over";
2058
+ seedPausedFork(frame, next);
2059
+ } else {
2060
+ frame.status = "running";
2061
+ }
2062
+ };
2063
+ if (reason === void 0) {
2064
+ enter();
2065
+ return { patches: [], halt: false };
2066
+ }
2067
+ frame.status = "held";
2068
+ frame.next = next;
2069
+ frame.isFork = info.fork;
2070
+ frame.live = state;
2071
+ frame.forkMode = void 0;
2072
+ if (info.touchedKeys !== void 0) frame.touched = info.touchedKeys;
2073
+ const last = lastByFrame.get(keyOf(path));
2074
+ const stop = {
2075
+ kind: "step",
2076
+ frame: path,
2077
+ reason,
2078
+ runId: handle.runId,
2079
+ next,
2080
+ ...last !== void 0 ? { last } : {},
2081
+ state: snapshotOf(state),
2082
+ ...condition !== void 0 ? { conditionError: condition.error } : {}
2083
+ };
2084
+ frame.stop = stop;
2085
+ const released = new Promise((resolve) => {
2086
+ frame.release = resolve;
2087
+ });
2088
+ const onHalt = () => {
2089
+ frame.release?.({ patches: [], halt: true });
2090
+ };
2091
+ info.signal?.addEventListener("abort", onHalt);
2092
+ updateRenewal();
2093
+ offerStop(stop);
2094
+ const result = await released;
2095
+ info.signal?.removeEventListener("abort", onHalt);
2096
+ frame.release = void 0;
2097
+ frame.live = void 0;
2098
+ if (!result.halt) enter();
2099
+ updateRenewal();
2100
+ return result;
2101
+ };
2102
+ const release = (frame, how, halt = false) => {
2103
+ if (!halt) {
2104
+ frame.mode = how === "next" ? "step" : "continue";
2105
+ frame.lastRelease = how === "next" || how === "stepInto" ? "hold" : "continue";
2106
+ if (frame.isFork === true) frame.forkMode = how === "stepInto" ? "fork-entry" : how === "next" ? "over" : "continue";
2107
+ frame.status = frame.isFork === true ? "in-fork" : "running";
2108
+ }
2109
+ const patches = frame.patches;
2110
+ frame.patches = [];
2111
+ const r = frame.release;
2112
+ frame.release = void 0;
2113
+ r?.({ patches, halt });
2114
+ };
2115
+ const observer = {
2116
+ onStepSettled: (ctx, e) => {
2117
+ const path = ctx.branchPath ?? [];
2118
+ if (path.length === 0) {
2119
+ topInterrupt = e.interrupt !== void 0 ? { interruptId: e.interrupt.interruptId, prompt: e.interrupt.prompt, branchPath: [] } : void 0;
2120
+ }
2121
+ lastByFrame.set(keyOf(path), {
2122
+ name: ctx.stepName,
2123
+ outcome: e.outcome,
2124
+ ...e.update !== void 0 ? { update: snapshotOf(e.update) } : {},
2125
+ ...e.signal !== void 0 ? { signal: e.signal } : {},
2126
+ next: e.next,
2127
+ ...e.error !== void 0 ? { error: e.error } : {},
2128
+ before: frameOf(path)?.before ?? { values: {}, shared: [] },
2129
+ durationMs: e.durationMs,
2130
+ ...e.fork !== void 0 ? { fork: e.fork } : {}
2131
+ });
2132
+ },
2133
+ onInterrupt: (ctx, e) => {
2134
+ interrupts.push({ interruptId: e.interruptId, prompt: e.prompt, branchPath: ctx.branchPath ?? [] });
2135
+ },
2136
+ onRunEnd: (ctx, e) => {
2137
+ if (ctx.branchPath !== void 0) onFrameEnd(ctx.branchPath, e.signal);
2138
+ }
2139
+ };
2140
+ const refuse = (name) => {
2141
+ if (status === "ended") return new DebugCommandError("ended", name);
2142
+ if (status === "starting" || !started || command !== void 0) return new DebugCommandError("busy", name);
2143
+ if (status === "interrupt" && name !== "answer") return new DebugCommandError("not-held", name);
2144
+ if (status === "active" && name === "answer") return new DebugCommandError("not-held", name);
2145
+ return void 0;
2146
+ };
2147
+ const issue = (target) => {
2148
+ const result = deferred();
2149
+ command = { target, result };
2150
+ return result.promise;
2151
+ };
2152
+ const drive = (how) => {
2153
+ const refused = refuse(how);
2154
+ if (refused !== void 0) return Promise.reject(refused);
2155
+ const frame = frameOf(focus);
2156
+ if (frame === void 0 || frame.status !== "held") return Promise.reject(new DebugCommandError("not-held", how));
2157
+ if (how === "stepInto" && frame.isFork !== true) return Promise.reject(new DebugCommandError("not-a-fork", how));
2158
+ const p = issue(frame.path);
2159
+ release(frame, how);
2160
+ updateRenewal();
2161
+ return p;
2162
+ };
2163
+ const session = {
2164
+ get sessionId() {
2165
+ return handle.sessionId;
2166
+ },
2167
+ get runId() {
2168
+ return handle.runId;
2169
+ },
2170
+ get current() {
2171
+ return current;
2172
+ },
2173
+ get done() {
2174
+ return done.promise;
2175
+ },
2176
+ get breakpoints() {
2177
+ return [...breakpoints.values()];
2178
+ },
2179
+ get frames() {
2180
+ return sortedFrames().map((f) => ({ frame: f.path, status: f.status, ...f.status === "held" && f.next !== void 0 ? { next: f.next } : {} }));
2181
+ },
2182
+ focus: (path) => {
2183
+ const frame = frameOf(path);
2184
+ if (status !== "active" || frame === void 0 || frame.status !== "held" || frame.stop === void 0) {
2185
+ throw new DebugCommandError("not-held", "focus");
2186
+ }
2187
+ focus = frame.path;
2188
+ setCurrent(frame.stop);
2189
+ return frame.stop;
2190
+ },
2191
+ next: () => drive("next"),
2192
+ continue: () => drive("continue"),
2193
+ stepInto: () => drive("stepInto"),
2194
+ continueAll: () => {
2195
+ const refused = refuse("continueAll");
2196
+ if (refused !== void 0) return Promise.reject(refused);
2197
+ const p = issue("any");
2198
+ for (const frame of sortedFrames()) if (frame.status === "held") release(frame, "continueAll");
2199
+ updateRenewal();
2200
+ return p;
2201
+ },
2202
+ answer: (response, id) => {
2203
+ const at = paused;
2204
+ const refused = refuse("answer") ?? (at === void 0 ? new DebugCommandError("not-held", "answer") : void 0);
2205
+ if (refused !== void 0 || at === void 0) return Promise.reject(refused);
2206
+ const target = id ?? at.pending[0].interruptId;
2207
+ if (!at.pending.some((p2) => p2.interruptId === target)) return Promise.reject(new NoInterruptError());
2208
+ let resumed;
2209
+ try {
2210
+ resumed = handle.resume(response, target);
2211
+ } catch (error) {
2212
+ return Promise.reject(error);
2213
+ }
2214
+ pausedForks = new Map([...lastByFrame].filter(([, s]) => s.fork !== void 0 && (s.outcome === "interrupt" || s.outcome === "stopped")));
2215
+ handle = resumed;
2216
+ paused = void 0;
2217
+ status = "active";
2218
+ topMode = "resume";
2219
+ frames = /* @__PURE__ */ new Map();
2220
+ focus = [];
2221
+ lastByFrame = /* @__PURE__ */ new Map();
2222
+ topInterrupt = void 0;
2223
+ interrupts = [];
2224
+ lease = {};
2225
+ const p = issue([]);
2226
+ attach(handle);
2227
+ return p;
2228
+ },
2229
+ setState: (patch) => {
2230
+ if (status === "ended") throw new DebugCommandError("ended", "setState");
2231
+ const frame = frameOf(focus);
2232
+ if (status !== "active" || frame === void 0 || frame.status !== "held" || frame.live === void 0) {
2233
+ throw new DebugCommandError("not-held", "setState");
2234
+ }
2235
+ const reserved = Object.keys(patch).find((k) => k.startsWith("$"));
2236
+ if (reserved !== void 0) throw new DebugCommandError("reserved-key", "setState", `framework key "${reserved}" cannot be set`);
2237
+ const reported = {};
2238
+ for (const [key, value] of Object.entries(patch)) {
2239
+ frame.live[key] = cloneOrShare(value).value;
2240
+ reported[key] = cloneOrShare(value).value;
2241
+ frame.touched?.add(key);
2242
+ }
2243
+ frame.patches.push(reported);
2244
+ return snapshotOf(frame.live);
2245
+ },
2246
+ setBreakpoint: (step, when) => {
2247
+ breakpoints.set(step, { step, ...when !== void 0 ? { when } : {} });
2248
+ },
2249
+ clearBreakpoint: (step) => {
2250
+ breakpoints.delete(step);
2251
+ },
2252
+ stop: () => {
2253
+ if (status === "ended") return ended.promise;
2254
+ stopRequested = true;
2255
+ if (status === "interrupt" && paused !== void 0) {
2256
+ finish(paused.outcome);
2257
+ return ended.promise;
2258
+ }
2259
+ handle.stop();
2260
+ for (const frame of frames.values()) if (frame.status === "held") release(frame, "continueAll", true);
2261
+ return ended.promise;
2262
+ }
2263
+ };
2264
+ handle = args.start({ gate, observer, onLease: (l) => {
2265
+ lease = l;
2266
+ } });
2267
+ status = "active";
2268
+ attach(handle);
2269
+ if (signal !== void 0) {
2270
+ signal.addEventListener("abort", onAbort);
2271
+ if (signal.aborted) onAbort();
2272
+ }
2273
+ return session;
2274
+ }
2275
+
1620
2276
  // src/agent/create-agent.ts
1621
2277
  import { randomUUID } from "crypto";
1622
2278
 
@@ -1738,13 +2394,26 @@ var InvalidClaimOptionsError = class extends Error {
1738
2394
  this.ttlMs = ttlMs;
1739
2395
  }
1740
2396
  };
2397
+ var AGENT_OPTION_EXPECTED = { observer: "an object", onObserverError: "a function", checkpoint: "'off' or 'step'" };
2398
+ var InvalidAgentOptionError = class extends Error {
2399
+ /** The option that was rejected. */
2400
+ key;
2401
+ /** The rejected value, as given. */
2402
+ value;
2403
+ constructor(key, value) {
2404
+ super(`${key} must be ${AGENT_OPTION_EXPECTED[key]} \u2014 got ${describeValue(value)} in createAgent options`);
2405
+ this.name = "InvalidAgentOptionError";
2406
+ this.key = key;
2407
+ this.value = value;
2408
+ }
2409
+ };
1741
2410
  var InvalidRunResourceError = class extends Error {
1742
2411
  /** The resource key that was rejected. */
1743
2412
  key;
1744
2413
  /** The rejected value, as given. */
1745
2414
  value;
1746
2415
  constructor(key, value) {
1747
- super(`${key} must be a non-empty string \u2014 got ${describeValue(value)} in agent.run() resources`);
2416
+ super(key === "checkpoint" ? `checkpoint must be 'off' or 'step' \u2014 got ${describeValue(value)} in the call's resources` : `${key} must be a non-empty string \u2014 got ${describeValue(value)} in agent.run() resources`);
1748
2417
  this.name = "InvalidRunResourceError";
1749
2418
  this.key = key;
1750
2419
  this.value = value;
@@ -1756,6 +2425,12 @@ function readIdResource(resources, key) {
1756
2425
  if (typeof value !== "string" || value.length === 0) throw new InvalidRunResourceError(key, value);
1757
2426
  return value;
1758
2427
  }
2428
+ function readCheckpointResource(resources) {
2429
+ const value = resources["checkpoint"];
2430
+ if (value === void 0) return void 0;
2431
+ if (!isCheckpointMode(value)) throw new InvalidRunResourceError("checkpoint", value);
2432
+ return value;
2433
+ }
1759
2434
  var _agentInternals = /* @__PURE__ */ Symbol("_agentInternals");
1760
2435
  function createAgent(id, h, slots, agentOptions) {
1761
2436
  const internals = getInternals(h);
@@ -1793,6 +2468,27 @@ function createAgent(id, h, slots, agentOptions) {
1793
2468
  agentClaimOptions = { ttlMs };
1794
2469
  }
1795
2470
  const fallbackClaimOptions = () => agentClaimOptions ?? { ttlMs: defaultClaimTtlMs() };
2471
+ const agentObserver = agentOptions?.observer;
2472
+ if (agentObserver !== void 0 && (agentObserver === null || typeof agentObserver !== "object" || Array.isArray(agentObserver))) {
2473
+ throw new InvalidAgentOptionError("observer", agentObserver);
2474
+ }
2475
+ const agentErrorSink = agentOptions?.onObserverError;
2476
+ if (agentErrorSink !== void 0 && typeof agentErrorSink !== "function") {
2477
+ throw new InvalidAgentOptionError("onObserverError", agentErrorSink);
2478
+ }
2479
+ const resolveObserver = (resources) => {
2480
+ const runObserver = extractRunObserver(resources);
2481
+ const onObserverError = extractRunErrorSink(resources) ?? agentErrorSink;
2482
+ const observer = agentObserver === void 0 ? runObserver : runObserver === void 0 || runObserver === agentObserver ? agentObserver : composeObservers([agentObserver, runObserver], onObserverError);
2483
+ return {
2484
+ ...observer !== void 0 ? { observer } : {},
2485
+ ...onObserverError !== void 0 ? { onObserverError } : {}
2486
+ };
2487
+ };
2488
+ const agentCheckpoint = agentOptions?.checkpoint;
2489
+ if (agentCheckpoint !== void 0 && !isCheckpointMode(agentCheckpoint)) {
2490
+ throw new InvalidAgentOptionError("checkpoint", agentCheckpoint);
2491
+ }
1796
2492
  const resolvedProviders = /* @__PURE__ */ new Map();
1797
2493
  const storeEntries = [];
1798
2494
  const runtimeKeys = /* @__PURE__ */ new Set();
@@ -1842,12 +2538,13 @@ function createAgent(id, h, slots, agentOptions) {
1842
2538
  runtimeKeys,
1843
2539
  requiredKeys
1844
2540
  };
1845
- const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "requestId", "signal", "events", "listeners", "observer", "onObserverError", "claimOptions", "parentRunId"]);
2541
+ const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "requestId", "signal", "events", "listeners", "observer", "onObserverError", "claimOptions", "parentRunId", "checkpoint"]);
1846
2542
  const inFlightSessions = /* @__PURE__ */ new Set();
2543
+ const debugSessions = /* @__PURE__ */ new Set();
1847
2544
  const interruptPendingSessions = /* @__PURE__ */ new Set();
1848
2545
  const resumeFailState = () => initializeState(null, {}, agentInternals.stateSchema);
1849
2546
  const makeAgentResumeHandle = (resp, sId, iId, resumeResources) => {
1850
- const { onStoreError, observer, onObserverError, telemetrySlots, parentRunId, claimOptions } = resumeResources;
2547
+ const { onStoreError, observer, onObserverError, telemetrySlots, parentRunId, claimOptions, checkpoint } = resumeResources;
1851
2548
  let _stopped = false;
1852
2549
  const abortController = new AbortController();
1853
2550
  const flag = {
@@ -1880,6 +2577,7 @@ function createAgent(id, h, slots, agentOptions) {
1880
2577
  sessionId: sId,
1881
2578
  interruptId: iId,
1882
2579
  response: resp,
2580
+ ...heldLease(lease),
1883
2581
  ...onStoreError !== void 0 ? { onStoreError } : {},
1884
2582
  failState: resumeFailState,
1885
2583
  run: async () => {
@@ -1902,6 +2600,7 @@ function createAgent(id, h, slots, agentOptions) {
1902
2600
  agentCtx,
1903
2601
  {
1904
2602
  mode: "resume",
2603
+ checkpoint,
1905
2604
  shouldStop: () => flag.stopped,
1906
2605
  onBeforeStep: (n) => {
1907
2606
  ref.current = n;
@@ -1933,266 +2632,280 @@ function createAgent(id, h, slots, agentOptions) {
1933
2632
  };
1934
2633
  return createRunHandle(sId, rId, exec, flag, ref, resumeFn);
1935
2634
  };
1936
- const agent = {
1937
- id,
1938
- run: (initialState, resources) => {
1939
- for (const key of Object.keys(resources)) {
1940
- if (reservedRunKeys.has(key)) continue;
1941
- if (!agentInternals.runtimeKeys.has(key) && !agentInternals.requiredKeys.has(key)) {
1942
- throw new UnknownRunSlotError(key);
1943
- }
2635
+ const startRun = (initialState, resources, debug) => {
2636
+ for (const key of Object.keys(resources)) {
2637
+ if (reservedRunKeys.has(key)) continue;
2638
+ if (!agentInternals.runtimeKeys.has(key) && !agentInternals.requiredKeys.has(key)) {
2639
+ throw new UnknownRunSlotError(key);
1944
2640
  }
1945
- for (const key of Object.keys(resources)) {
1946
- if (reservedRunKeys.has(key)) continue;
1947
- if (agentInternals.requiredKeys.has(key)) {
1948
- throw new RequiredSlotInRunError(key);
1949
- }
2641
+ }
2642
+ for (const key of Object.keys(resources)) {
2643
+ if (reservedRunKeys.has(key)) continue;
2644
+ if (agentInternals.requiredKeys.has(key)) {
2645
+ throw new RequiredSlotInRunError(key);
1950
2646
  }
1951
- for (const key of agentInternals.runtimeKeys) {
1952
- if (!(key in resources)) {
1953
- throw new MissingRuntimeSlotError(key);
1954
- }
2647
+ }
2648
+ for (const key of agentInternals.runtimeKeys) {
2649
+ if (!(key in resources)) {
2650
+ throw new MissingRuntimeSlotError(key);
1955
2651
  }
1956
- const sessionId = readIdResource(resources, "sessionId") ?? randomUUID();
1957
- const requestId = readIdResource(resources, "requestId");
1958
- const runId = randomUUID();
1959
- if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
1960
- if (capturedStore === void 0 && interruptPendingSessions.has(sessionId)) throw new SessionPendingInterruptError(sessionId);
1961
- inFlightSessions.add(sessionId);
1962
- let _stopped = false;
1963
- const abortController = new AbortController();
1964
- const stopFlag = {
1965
- get stopped() {
1966
- return _stopped;
1967
- },
1968
- set stopped(v) {
1969
- _stopped = v;
1970
- if (v) abortController.abort();
1971
- }
1972
- };
1973
- const rawSignal = resources["signal"];
1974
- let ctxSignal = abortController.signal;
1975
- if (rawSignal instanceof AbortSignal) {
1976
- ctxSignal = rawSignal;
1977
- rawSignal.addEventListener("abort", () => {
1978
- stopFlag.stopped = true;
1979
- abortController.abort();
1980
- }, { once: true });
1981
- if (rawSignal.aborted) stopFlag.stopped = true;
1982
- }
1983
- const stepRef = { current: null };
1984
- const runtimeSlots = {};
1985
- for (const key of agentInternals.runtimeKeys) {
1986
- if (reservedRunKeys.has(key)) continue;
1987
- runtimeSlots[key] = resources[key];
1988
- }
1989
- const ctx = {
1990
- ...Object.fromEntries(agentInternals.resolvedProviders),
1991
- ...runtimeSlots,
1992
- agentId: id,
1993
- sessionId,
1994
- runId,
1995
- signal: ctxSignal,
1996
- ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {}
1997
- };
1998
- const events = extractRunEvents(resources);
1999
- const listeners = extractRunListeners(resources);
2000
- const observer = extractRunObserver(resources);
2001
- const onObserverError = extractRunErrorSink(resources);
2002
- const telemetrySlots = buildTelemetrySlots([
2003
- ...agentInternals.resolvedProviders.entries(),
2004
- ...Object.entries(runtimeSlots)
2005
- ]);
2006
- const parentRunId = typeof resources["parentRunId"] === "string" ? resources["parentRunId"] : void 0;
2007
- const claimOptions = parseClaimOptions(resources["claimOptions"], fallbackClaimOptions());
2008
- const options = {
2009
- mode: "run",
2010
- ...requestId !== void 0 ? { requestId } : {},
2011
- shouldStop: () => stopFlag.stopped,
2012
- onBeforeStep: (name, state) => {
2013
- stepRef.current = name;
2014
- events.onBeforeStep?.(name, state);
2015
- },
2016
- // spread optional event callbacks only when defined (exactOptionalPropertyTypes requires omission, not undefined)
2017
- ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2018
- ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2019
- ...events.onError !== void 0 ? { onError: events.onError } : {},
2020
- ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2021
- ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2022
- ...Object.keys(listeners).length > 0 ? { listeners } : {},
2023
- ...observer !== void 0 ? { observer } : {},
2024
- ...onObserverError !== void 0 ? { onObserverError } : {},
2025
- ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
2026
- ...parentRunId !== void 0 ? { parentRunId } : {},
2027
- ...telemetrySlots.length > 0 ? { telemetrySlots } : {}
2028
- };
2029
- let lastResult = null;
2030
- const execution = (async () => {
2031
- await Promise.resolve();
2032
- try {
2033
- return await runClaimed({
2034
- store: capturedStore,
2035
- agentId: id,
2036
- sessionId,
2037
- claimOptions,
2038
- ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2039
- failState: () => initializeState(null, initialState, agentInternals.stateSchema),
2040
- body: async (lease) => {
2041
- const r = await runWithSession(
2042
- capturedStore,
2043
- id,
2652
+ }
2653
+ const sessionId = readIdResource(resources, "sessionId") ?? randomUUID();
2654
+ const requestId = readIdResource(resources, "requestId");
2655
+ const checkpoint = readCheckpointResource(resources) ?? agentCheckpoint ?? "off";
2656
+ const runId = randomUUID();
2657
+ if (debugSessions.has(sessionId)) throw new SessionInDebugError(sessionId);
2658
+ if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
2659
+ if (capturedStore === void 0 && interruptPendingSessions.has(sessionId)) throw new SessionPendingInterruptError(sessionId);
2660
+ inFlightSessions.add(sessionId);
2661
+ let _stopped = false;
2662
+ const abortController = new AbortController();
2663
+ const stopFlag = {
2664
+ get stopped() {
2665
+ return _stopped;
2666
+ },
2667
+ set stopped(v) {
2668
+ _stopped = v;
2669
+ if (v) abortController.abort();
2670
+ }
2671
+ };
2672
+ const rawSignal = debug === void 0 ? resources["signal"] : void 0;
2673
+ let ctxSignal = abortController.signal;
2674
+ if (rawSignal instanceof AbortSignal) {
2675
+ ctxSignal = rawSignal;
2676
+ rawSignal.addEventListener("abort", () => {
2677
+ stopFlag.stopped = true;
2678
+ abortController.abort();
2679
+ }, { once: true });
2680
+ if (rawSignal.aborted) stopFlag.stopped = true;
2681
+ }
2682
+ const stepRef = { current: null };
2683
+ const runtimeSlots = {};
2684
+ for (const key of agentInternals.runtimeKeys) {
2685
+ if (reservedRunKeys.has(key)) continue;
2686
+ runtimeSlots[key] = resources[key];
2687
+ }
2688
+ const ctx = {
2689
+ ...Object.fromEntries(agentInternals.resolvedProviders),
2690
+ ...runtimeSlots,
2691
+ agentId: id,
2692
+ sessionId,
2693
+ runId,
2694
+ signal: ctxSignal,
2695
+ ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {}
2696
+ };
2697
+ const events = extractRunEvents(resources);
2698
+ const listeners = extractRunListeners(resources);
2699
+ const resolved = resolveObserver(resources);
2700
+ const onObserverError = resolved.onObserverError;
2701
+ const observer = debug === void 0 ? resolved.observer : resolved.observer === void 0 ? debug.observer : composeObservers([resolved.observer, debug.observer], onObserverError);
2702
+ const telemetrySlots = buildTelemetrySlots([
2703
+ ...agentInternals.resolvedProviders.entries(),
2704
+ ...Object.entries(runtimeSlots)
2705
+ ]);
2706
+ const parentRunId = typeof resources["parentRunId"] === "string" ? resources["parentRunId"] : void 0;
2707
+ const claimOptions = parseClaimOptions(resources["claimOptions"], fallbackClaimOptions());
2708
+ const options = {
2709
+ mode: "run",
2710
+ checkpoint,
2711
+ ...requestId !== void 0 ? { requestId } : {},
2712
+ shouldStop: () => stopFlag.stopped,
2713
+ onBeforeStep: (name, state) => {
2714
+ stepRef.current = name;
2715
+ events.onBeforeStep?.(name, state);
2716
+ },
2717
+ // spread optional event callbacks only when defined (exactOptionalPropertyTypes requires omission, not undefined)
2718
+ ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2719
+ ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2720
+ ...events.onError !== void 0 ? { onError: events.onError } : {},
2721
+ ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2722
+ ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2723
+ ...Object.keys(listeners).length > 0 ? { listeners } : {},
2724
+ ...observer !== void 0 ? { observer } : {},
2725
+ ...onObserverError !== void 0 ? { onObserverError } : {},
2726
+ ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
2727
+ ...parentRunId !== void 0 ? { parentRunId } : {},
2728
+ ...telemetrySlots.length > 0 ? { telemetrySlots } : {},
2729
+ ...debug !== void 0 ? { debugGate: debug.gate } : {}
2730
+ };
2731
+ let lastResult = null;
2732
+ const execution = (async () => {
2733
+ await Promise.resolve();
2734
+ try {
2735
+ return await runClaimed({
2736
+ store: capturedStore,
2737
+ agentId: id,
2738
+ sessionId,
2739
+ claimOptions,
2740
+ ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2741
+ failState: () => initializeState(null, initialState, agentInternals.stateSchema),
2742
+ body: async (lease) => {
2743
+ debug?.onLease(lease);
2744
+ const r = await runWithSession(
2745
+ capturedStore,
2746
+ id,
2747
+ sessionId,
2748
+ runId,
2749
+ agentInternals.loopDef,
2750
+ initialState,
2751
+ agentInternals.stateSchema,
2752
+ ctx,
2753
+ { ...options, ...lease }
2754
+ );
2755
+ if (capturedStore === void 0 && r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
2756
+ lastResult = { state: r.state, cursor: r.cursor, runId, ...r.carrier !== void 0 ? { carrier: r.carrier } : {} };
2757
+ return { state: r.state, signal: r.signal };
2758
+ }
2759
+ });
2760
+ } finally {
2761
+ inFlightSessions.delete(sessionId);
2762
+ }
2763
+ })();
2764
+ const buildResumeFn = () => {
2765
+ return (response, interruptId) => {
2766
+ if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
2767
+ interruptPendingSessions.delete(sessionId);
2768
+ inFlightSessions.add(sessionId);
2769
+ let _resumeStopped = false;
2770
+ const resumeAbortController = new AbortController();
2771
+ const resumeStopFlag = {
2772
+ get stopped() {
2773
+ return _resumeStopped;
2774
+ },
2775
+ set stopped(v) {
2776
+ _resumeStopped = v;
2777
+ if (v) resumeAbortController.abort();
2778
+ }
2779
+ };
2780
+ const resumeStepRef = { current: null };
2781
+ const resumeRunId = randomUUID();
2782
+ const resumeExecution = (async () => {
2783
+ await Promise.resolve();
2784
+ try {
2785
+ const resumeCtx = {
2786
+ ...ctx,
2787
+ runId: resumeRunId,
2788
+ signal: resumeAbortController.signal
2789
+ };
2790
+ if (capturedStore !== void 0) {
2791
+ const store = capturedStore;
2792
+ const onStoreError = events.onStoreError;
2793
+ return await runClaimed({
2794
+ store,
2795
+ agentId: id,
2044
2796
  sessionId,
2045
- runId,
2046
- agentInternals.loopDef,
2047
- initialState,
2048
- agentInternals.stateSchema,
2049
- ctx,
2050
- { ...options, ...lease }
2051
- );
2052
- if (capturedStore === void 0 && r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
2053
- lastResult = { state: r.state, cursor: r.cursor, runId, ...r.carrier !== void 0 ? { carrier: r.carrier } : {} };
2054
- return { state: r.state, signal: r.signal };
2055
- }
2056
- });
2057
- } finally {
2058
- inFlightSessions.delete(sessionId);
2059
- }
2060
- })();
2061
- const buildResumeFn = () => {
2062
- return (response, interruptId) => {
2063
- if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
2064
- interruptPendingSessions.delete(sessionId);
2065
- inFlightSessions.add(sessionId);
2066
- let _resumeStopped = false;
2067
- const resumeAbortController = new AbortController();
2068
- const resumeStopFlag = {
2069
- get stopped() {
2070
- return _resumeStopped;
2071
- },
2072
- set stopped(v) {
2073
- _resumeStopped = v;
2074
- if (v) resumeAbortController.abort();
2075
- }
2076
- };
2077
- const resumeStepRef = { current: null };
2078
- const resumeRunId = randomUUID();
2079
- const resumeExecution = (async () => {
2080
- await Promise.resolve();
2081
- try {
2082
- const resumeCtx = {
2083
- ...ctx,
2084
- runId: resumeRunId,
2085
- signal: resumeAbortController.signal
2086
- };
2087
- if (capturedStore !== void 0) {
2088
- const store = capturedStore;
2089
- const onStoreError = events.onStoreError;
2090
- return await runClaimed({
2797
+ claimOptions,
2798
+ ...onStoreError !== void 0 ? { onStoreError } : {},
2799
+ failState: resumeFailState,
2800
+ body: (lease) => injectThenRun({
2091
2801
  store,
2092
2802
  agentId: id,
2093
2803
  sessionId,
2094
- claimOptions,
2804
+ interruptId,
2805
+ response,
2806
+ ...heldLease(lease),
2095
2807
  ...onStoreError !== void 0 ? { onStoreError } : {},
2096
2808
  failState: resumeFailState,
2097
- body: (lease) => injectThenRun({
2098
- store,
2099
- agentId: id,
2100
- sessionId,
2101
- interruptId,
2102
- response,
2103
- ...onStoreError !== void 0 ? { onStoreError } : {},
2104
- failState: resumeFailState,
2105
- run: async () => {
2106
- const r2 = await runWithSession(
2107
- store,
2108
- id,
2109
- sessionId,
2110
- resumeRunId,
2111
- agentInternals.loopDef,
2112
- {},
2113
- agentInternals.stateSchema,
2114
- resumeCtx,
2115
- {
2116
- mode: "resume",
2117
- shouldStop: () => resumeStopFlag.stopped,
2118
- onBeforeStep: (n, s) => {
2119
- resumeStepRef.current = n;
2120
- events.onBeforeStep?.(n, s);
2121
- },
2122
- // spread optional event callbacks only when defined (exactOptionalPropertyTypes requires omission, not undefined)
2123
- ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2124
- ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2125
- ...events.onError !== void 0 ? { onError: events.onError } : {},
2126
- ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2127
- ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2128
- ...Object.keys(listeners).length > 0 ? { listeners } : {},
2129
- ...observer !== void 0 ? { observer } : {},
2130
- ...onObserverError !== void 0 ? { onObserverError } : {},
2131
- ...telemetrySlots.length > 0 ? { telemetrySlots } : {},
2132
- ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
2133
- ...lease
2134
- }
2135
- );
2136
- lastResult = { state: r2.state, cursor: r2.cursor, runId: resumeRunId, ...r2.carrier !== void 0 ? { carrier: r2.carrier } : {} };
2137
- return { state: r2.state, signal: r2.signal };
2138
- }
2139
- })
2140
- });
2141
- }
2142
- const prev = lastResult;
2143
- if (prev === null) throw new NoInterruptError();
2144
- const injected = injectInterruptResponseIntoState(prev.cursor ?? void 0, prev.state, interruptId, response);
2145
- if (!injected.found) throw new NoInterruptError();
2146
- const state = injected.state;
2147
- const cursor = injected.cursor;
2148
- const r = await runLoop(
2149
- agentInternals.loopDef,
2150
- state,
2151
- resumeCtx,
2152
- agentInternals.stateSchema,
2153
- () => resumeStopFlag.stopped,
2154
- cursor,
2155
- {
2156
- runId: resumeRunId,
2157
- resumedFrom: { runId: prev.runId, ...prev.carrier !== void 0 ? { carrier: prev.carrier } : {} },
2158
- onBeforeStep: (n, s) => {
2159
- resumeStepRef.current = n;
2160
- events.onBeforeStep?.(n, s);
2161
- },
2162
- ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2163
- ...events.onError !== void 0 ? { onError: events.onError } : {},
2164
- ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2165
- ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2166
- ...Object.keys(listeners).length > 0 ? { listeners } : {},
2167
- ...observer !== void 0 ? { observer } : {},
2168
- ...onObserverError !== void 0 ? { onObserverError } : {},
2169
- ...telemetrySlots.length > 0 ? { telemetrySlots } : {}
2170
- }
2171
- );
2172
- if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
2173
- lastResult = { state: r.state, cursor: r.cursor, runId: resumeRunId, ...r.carrier !== void 0 ? { carrier: r.carrier } : {} };
2174
- return { state: r.state, signal: r.signal };
2175
- } finally {
2176
- inFlightSessions.delete(sessionId);
2809
+ run: async () => {
2810
+ debug?.onLease(lease);
2811
+ const r2 = await runWithSession(
2812
+ store,
2813
+ id,
2814
+ sessionId,
2815
+ resumeRunId,
2816
+ agentInternals.loopDef,
2817
+ {},
2818
+ agentInternals.stateSchema,
2819
+ resumeCtx,
2820
+ {
2821
+ mode: "resume",
2822
+ checkpoint,
2823
+ shouldStop: () => resumeStopFlag.stopped,
2824
+ onBeforeStep: (n, s) => {
2825
+ resumeStepRef.current = n;
2826
+ events.onBeforeStep?.(n, s);
2827
+ },
2828
+ // spread optional event callbacks only when defined (exactOptionalPropertyTypes requires omission, not undefined)
2829
+ ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2830
+ ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2831
+ ...events.onError !== void 0 ? { onError: events.onError } : {},
2832
+ ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2833
+ ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2834
+ ...Object.keys(listeners).length > 0 ? { listeners } : {},
2835
+ ...observer !== void 0 ? { observer } : {},
2836
+ ...onObserverError !== void 0 ? { onObserverError } : {},
2837
+ ...telemetrySlots.length > 0 ? { telemetrySlots } : {},
2838
+ ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
2839
+ ...debug !== void 0 ? { debugGate: debug.gate } : {},
2840
+ ...lease
2841
+ }
2842
+ );
2843
+ lastResult = { state: r2.state, cursor: r2.cursor, runId: resumeRunId, ...r2.carrier !== void 0 ? { carrier: r2.carrier } : {} };
2844
+ return { state: r2.state, signal: r2.signal };
2845
+ }
2846
+ })
2847
+ });
2177
2848
  }
2178
- })();
2179
- return createRunHandle(sessionId, resumeRunId, resumeExecution, resumeStopFlag, resumeStepRef, buildResumeFn());
2180
- };
2849
+ const prev = lastResult;
2850
+ if (prev === null) throw new NoInterruptError();
2851
+ const injected = injectInterruptResponseIntoState(prev.cursor ?? void 0, prev.state, interruptId, response);
2852
+ if (!injected.found) throw new NoInterruptError();
2853
+ const state = injected.state;
2854
+ const cursor = injected.cursor;
2855
+ const r = await runLoop(
2856
+ agentInternals.loopDef,
2857
+ state,
2858
+ resumeCtx,
2859
+ agentInternals.stateSchema,
2860
+ () => resumeStopFlag.stopped,
2861
+ cursor,
2862
+ {
2863
+ runId: resumeRunId,
2864
+ resumedFrom: { runId: prev.runId, ...prev.carrier !== void 0 ? { carrier: prev.carrier } : {} },
2865
+ onBeforeStep: (n, s) => {
2866
+ resumeStepRef.current = n;
2867
+ events.onBeforeStep?.(n, s);
2868
+ },
2869
+ ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2870
+ ...events.onError !== void 0 ? { onError: events.onError } : {},
2871
+ ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2872
+ ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2873
+ ...Object.keys(listeners).length > 0 ? { listeners } : {},
2874
+ ...observer !== void 0 ? { observer } : {},
2875
+ ...onObserverError !== void 0 ? { onObserverError } : {},
2876
+ ...telemetrySlots.length > 0 ? { telemetrySlots } : {},
2877
+ ...debug !== void 0 ? { debugGate: debug.gate } : {}
2878
+ }
2879
+ );
2880
+ if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
2881
+ lastResult = { state: r.state, cursor: r.cursor, runId: resumeRunId, ...r.carrier !== void 0 ? { carrier: r.carrier } : {} };
2882
+ return { state: r.state, signal: r.signal };
2883
+ } finally {
2884
+ inFlightSessions.delete(sessionId);
2885
+ }
2886
+ })();
2887
+ return createRunHandle(sessionId, resumeRunId, resumeExecution, resumeStopFlag, resumeStepRef, buildResumeFn());
2181
2888
  };
2182
- return createRunHandle(sessionId, runId, execution, stopFlag, stepRef, buildResumeFn());
2183
- },
2889
+ };
2890
+ return createRunHandle(sessionId, runId, execution, stopFlag, stepRef, buildResumeFn());
2891
+ };
2892
+ const agent = {
2893
+ id,
2894
+ run: (initialState, resources) => startRun(initialState, resources),
2184
2895
  resume: (response, sessionId, interruptId, resources) => {
2896
+ if (debugSessions.has(sessionId)) throw new SessionInDebugError(sessionId);
2185
2897
  if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
2898
+ const checkpoint = readCheckpointResource(resources ?? {}) ?? agentCheckpoint ?? "off";
2186
2899
  interruptPendingSessions.delete(sessionId);
2187
2900
  inFlightSessions.add(sessionId);
2188
2901
  const events = extractRunEvents(resources ?? {});
2189
- const observer = extractRunObserver(resources ?? {});
2190
- const onObserverError = extractRunErrorSink(resources ?? {});
2902
+ const { observer, onObserverError } = resolveObserver(resources ?? {});
2191
2903
  const telemetrySlots = buildTelemetrySlots(agentInternals.resolvedProviders.entries());
2192
2904
  const parentRunId = resources?.["parentRunId"];
2193
2905
  const claimOptions = parseClaimOptions(resources?.["claimOptions"], fallbackClaimOptions());
2194
2906
  return makeAgentResumeHandle(response, sessionId, interruptId, {
2195
2907
  claimOptions,
2908
+ checkpoint,
2196
2909
  ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2197
2910
  ...observer !== void 0 ? { observer } : {},
2198
2911
  ...onObserverError !== void 0 ? { onObserverError } : {},
@@ -2200,12 +2913,33 @@ function createAgent(id, h, slots, agentOptions) {
2200
2913
  ...typeof parentRunId === "string" ? { parentRunId } : {}
2201
2914
  });
2202
2915
  },
2916
+ debug: (initialState, resources) => {
2917
+ const rawSignal = resources["signal"];
2918
+ let sessionId;
2919
+ const session = createDebugSession({
2920
+ start: (hooks) => {
2921
+ const handle = startRun(initialState, resources, hooks);
2922
+ sessionId = handle.sessionId;
2923
+ return handle;
2924
+ },
2925
+ store: capturedStore,
2926
+ signal: rawSignal instanceof AbortSignal ? rawSignal : void 0,
2927
+ onEnd: () => {
2928
+ if (sessionId !== void 0) debugSessions.delete(sessionId);
2929
+ }
2930
+ });
2931
+ debugSessions.add(session.sessionId);
2932
+ return session;
2933
+ },
2203
2934
  status: (sessionId) => querySessionPhase(capturedStore, id, sessionId),
2204
2935
  [_agentInternals]: agentInternals
2205
2936
  };
2206
2937
  return agent;
2207
2938
  }
2208
2939
  export {
2940
+ DebugCommandError,
2941
+ InvalidAgentOptionError,
2942
+ InvalidClaimOptionsError,
2209
2943
  InvalidRunResourceError,
2210
2944
  LeaseExpiredError,
2211
2945
  LoopNotDefinedError,
@@ -2213,6 +2947,7 @@ export {
2213
2947
  REQUIRED_TAG,
2214
2948
  RUNTIME_TAG,
2215
2949
  SessionBusyError,
2950
+ SessionInDebugError,
2216
2951
  SessionInFlightError,
2217
2952
  SessionPendingInterruptError,
2218
2953
  StoreLoadError,