@noetaris/harness 0.9.0 → 0.11.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
@@ -745,11 +745,13 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
745
745
  sessionId: ctx.sessionId,
746
746
  runId: typeof callbacks?.runId === "string" ? callbacks.runId : "",
747
747
  ...typeof callbacks?.parentRunId === "string" ? { parentRunId: callbacks.parentRunId } : {},
748
+ ...typeof callbacks?.requestId === "string" ? { requestId: callbacks.requestId } : {},
748
749
  ...typeof ctx.instanceId === "string" ? { instanceId: ctx.instanceId } : {},
749
750
  ...isBranch ? { branchPath } : {},
750
751
  // Branch runLoops receive the outer callbacks by spread, so the refs are dropped here.
751
752
  ...!isBranch && callbacks?.resumedFrom !== void 0 ? { resumedFrom: callbacks.resumedFrom } : {},
752
- ...!isBranch && callbacks?.branchedFrom !== void 0 ? { branchedFrom: callbacks.branchedFrom } : {}
753
+ ...!isBranch && callbacks?.branchedFrom !== void 0 ? { branchedFrom: callbacks.branchedFrom } : {},
754
+ ...!isBranch && callbacks?.continuedFrom !== void 0 ? { continuedFrom: callbacks.continuedFrom } : {}
753
755
  };
754
756
  safeInvoke("onRunStart", () => obs?.onRunStart?.(runCtx), onObserverError);
755
757
  const carrier = isBranch ? void 0 : normalizeCarrier(safeCall("carry", () => obs?.carry?.(runCtx), onObserverError));
@@ -1084,6 +1086,13 @@ async function handleFork(forkNode, priorBranches, state, ctx, schema, shouldSto
1084
1086
  }
1085
1087
 
1086
1088
  // src/agent/session-store.ts
1089
+ function isValidTtlMs(value) {
1090
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
1091
+ }
1092
+ function defaultClaimTtlMs() {
1093
+ const ttlMs = Number(process.env["HARNESS_CLAIM_TTL_MS"]);
1094
+ return isValidTtlMs(ttlMs) ? ttlMs : 3e4;
1095
+ }
1087
1096
  function collectPendingInterrupts(cursor, state) {
1088
1097
  if (cursor !== void 0 && isForkCursor(cursor)) {
1089
1098
  const result = [];
@@ -1280,15 +1289,35 @@ async function querySessionPhase(store, agentId, sessionId) {
1280
1289
  return storedSessionToPhase(loaded);
1281
1290
  }
1282
1291
  function runRefsOf(loaded) {
1283
- if (loaded === null || loaded.phase !== "paused") return {};
1284
- if (loaded.step !== void 0) {
1285
- return { resumedFrom: { runId: loaded.runId, ...loaded.carrier !== void 0 ? { carrier: loaded.carrier } : {} } };
1286
- }
1292
+ if (loaded === null) return {};
1293
+ const ref = { runId: loaded.runId, ...loaded.carrier !== void 0 ? { carrier: loaded.carrier } : {} };
1294
+ if (loaded.phase === "completed") return { continuedFrom: ref };
1295
+ if (loaded.step !== void 0) return { resumedFrom: ref };
1287
1296
  return loaded.branchedFrom !== void 0 ? { branchedFrom: loaded.branchedFrom } : {};
1288
1297
  }
1298
+ function decideRun(args) {
1299
+ const { loaded, older, mode, requestId, sessionId } = args;
1300
+ if (loaded === null) return { action: "start" };
1301
+ const pending = loaded.phase === "paused" && collectPendingInterrupts(loaded.step, loaded.finalState).length > 0;
1302
+ if (mode === "resume") {
1303
+ return loaded.phase === "completed" ? { action: "replay", row: loaded } : { action: "continue", mergeInput: false };
1304
+ }
1305
+ if (requestId !== void 0 && loaded.requestId === requestId) {
1306
+ if (loaded.phase === "completed" || pending) return { action: "replay", row: loaded };
1307
+ return { action: "continue", mergeInput: false };
1308
+ }
1309
+ if (older !== null) return { action: "replay", row: older };
1310
+ if (loaded.phase === "completed") return { action: "new-turn" };
1311
+ if (pending) return { action: "reject", error: new SessionPendingInterruptError(sessionId) };
1312
+ return { action: "continue", mergeInput: true };
1313
+ }
1314
+ function withoutSystemFields(loaded) {
1315
+ const { $error: _error, $interrupt: _interrupt, $interruptResponses: _responses, ...finalState } = loaded.finalState;
1316
+ return { ...loaded, finalState };
1317
+ }
1289
1318
  async function runWithSession(store, agentId, sessionId, runId, graph, initialStateArg, schema, ctx, options) {
1290
1319
  const leaseRef = options?.leaseRef ?? { current: null };
1291
- const keepAlive = createKeepAliveFn(leaseRef, store, options?.claimTtlMs ?? 3e4);
1320
+ const keepAlive = createKeepAliveFn(leaseRef, store, options?.claimTtlMs ?? defaultClaimTtlMs());
1292
1321
  ctx["keepAlive"] = keepAlive;
1293
1322
  let leaseExpired = false;
1294
1323
  const composedShouldStop = () => {
@@ -1299,10 +1328,11 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1299
1328
  }
1300
1329
  return false;
1301
1330
  };
1331
+ const { mode = "run", requestId: callerRequestId, ...loopOptions } = options ?? {};
1302
1332
  if (store === void 0) {
1303
1333
  const state2 = initializeState(null, initialStateArg, schema);
1304
1334
  const result2 = await runLoop(graph, state2, ctx, schema, composedShouldStop, void 0, {
1305
- ...options,
1335
+ ...loopOptions,
1306
1336
  runId,
1307
1337
  ...options?.parentRunId !== void 0 ? { parentRunId: options.parentRunId } : {}
1308
1338
  });
@@ -1313,31 +1343,46 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1313
1343
  }
1314
1344
  return result2;
1315
1345
  }
1346
+ const requestId = mode === "run" ? callerRequestId : void 0;
1347
+ const fail = (error) => {
1348
+ const failState = initializeState(null, initialStateArg, schema);
1349
+ failState["$error"] = error;
1350
+ return { state: failState, signal: "$error", paused: false, cursor: null };
1351
+ };
1316
1352
  let loaded;
1353
+ let older = null;
1317
1354
  try {
1318
1355
  loaded = await store.load(agentId, sessionId);
1356
+ if (requestId !== void 0 && loaded !== null && loaded.requestId !== requestId && typeof store.findRequest === "function") {
1357
+ older = await store.findRequest(agentId, sessionId, requestId);
1358
+ }
1319
1359
  } catch (error) {
1320
1360
  const storeError = new StoreLoadError(error);
1321
1361
  options?.onStoreError?.(storeError, "load");
1322
- const failState = initializeState(null, initialStateArg, schema);
1323
- failState["$error"] = storeError;
1324
- return { state: failState, signal: "$error", paused: false, cursor: null };
1362
+ return fail(storeError);
1325
1363
  }
1326
- if (loaded !== null && loaded.phase === "completed") {
1364
+ const decision = decideRun({ loaded, older, mode, requestId, sessionId });
1365
+ if (decision.action === "reject") return fail(decision.error);
1366
+ if (decision.action === "replay") {
1367
+ const { row } = decision;
1327
1368
  return {
1328
- state: loaded.finalState,
1329
- signal: loaded.signal ?? null,
1330
- cursor: null,
1331
- paused: false
1369
+ state: row.finalState,
1370
+ signal: row.signal ?? null,
1371
+ cursor: row.step ?? null,
1372
+ paused: row.phase === "paused"
1332
1373
  };
1333
1374
  }
1334
- const state = initializeState(loaded, initialStateArg, schema);
1375
+ const segmentRequestId = mode === "run" ? requestId : loaded?.requestId;
1376
+ const base = decision.action === "new-turn" && loaded !== null ? withoutSystemFields(loaded) : loaded;
1377
+ const input = decision.action === "continue" && !decision.mergeInput ? {} : initialStateArg;
1378
+ const state = initializeState(base, input, schema);
1335
1379
  const initialStateSnapshot = { ...state };
1336
1380
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
1337
1381
  const result = await runLoop(graph, state, ctx, schema, composedShouldStop, loaded?.step, {
1338
- ...options,
1382
+ ...loopOptions,
1339
1383
  runId,
1340
1384
  ...options?.parentRunId !== void 0 ? { parentRunId: options.parentRunId } : {},
1385
+ ...segmentRequestId !== void 0 ? { requestId: segmentRequestId } : {},
1341
1386
  ...runRefsOf(loaded)
1342
1387
  });
1343
1388
  if (leaseExpired) {
@@ -1363,7 +1408,8 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1363
1408
  step: result.cursor,
1364
1409
  ...result.signal !== null ? { signal: result.signal } : {},
1365
1410
  ...metadata !== void 0 ? { metadata } : {},
1366
- ...result.carrier !== void 0 ? { carrier: result.carrier } : {}
1411
+ ...result.carrier !== void 0 ? { carrier: result.carrier } : {},
1412
+ ...segmentRequestId !== void 0 ? { requestId: segmentRequestId } : {}
1367
1413
  };
1368
1414
  await store.save(agentId, sessionId, saved);
1369
1415
  } else {
@@ -1379,7 +1425,8 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1379
1425
  finalState: result.state,
1380
1426
  ...result.signal !== null ? { signal: result.signal } : {},
1381
1427
  ...metadata !== void 0 ? { metadata } : {},
1382
- ...result.carrier !== void 0 ? { carrier: result.carrier } : {}
1428
+ ...result.carrier !== void 0 ? { carrier: result.carrier } : {},
1429
+ ...segmentRequestId !== void 0 ? { requestId: segmentRequestId } : {}
1383
1430
  };
1384
1431
  await store.save(agentId, sessionId, saved);
1385
1432
  }
@@ -1389,6 +1436,50 @@ async function runWithSession(store, agentId, sessionId, runId, graph, initialSt
1389
1436
  return result;
1390
1437
  }
1391
1438
 
1439
+ // src/agent/claim-scope.ts
1440
+ function failOutcome(failState, error) {
1441
+ const state = failState();
1442
+ state["$error"] = error;
1443
+ return { state, signal: "$error" };
1444
+ }
1445
+ async function runClaimed(args) {
1446
+ const { store, agentId, sessionId, claimOptions, onStoreError, failState, body } = args;
1447
+ const fail = (error) => failOutcome(failState, error);
1448
+ let leaseRef = void 0;
1449
+ if (typeof store?.claim === "function") {
1450
+ let lease;
1451
+ try {
1452
+ lease = await store.claim(agentId, sessionId, claimOptions);
1453
+ } catch (claimError) {
1454
+ const loadError = new StoreLoadError(claimError);
1455
+ onStoreError?.(loadError, "claim");
1456
+ return fail(loadError);
1457
+ }
1458
+ if (lease === null) {
1459
+ const busyError = new SessionBusyError(sessionId);
1460
+ onStoreError?.(busyError, "claim");
1461
+ return fail(busyError);
1462
+ }
1463
+ leaseRef = { current: lease };
1464
+ }
1465
+ try {
1466
+ return await body(leaseRef !== void 0 ? { leaseRef, claimTtlMs: claimOptions.ttlMs } : {});
1467
+ } catch (error) {
1468
+ if (error instanceof LeaseExpiredError) return fail(error);
1469
+ throw error;
1470
+ } finally {
1471
+ if (leaseRef !== void 0 && typeof store?.release === "function") {
1472
+ try {
1473
+ await store.release(leaseRef.current);
1474
+ } catch {
1475
+ }
1476
+ }
1477
+ }
1478
+ }
1479
+ function parseClaimOptions(raw, fallback) {
1480
+ return typeof raw === "object" && raw !== null && typeof raw["ttlMs"] === "number" ? raw : fallback;
1481
+ }
1482
+
1392
1483
  // src/agent/interrupt-resume.ts
1393
1484
  var NoInterruptError = class extends Error {
1394
1485
  constructor() {
@@ -1459,10 +1550,23 @@ async function injectInterruptResponse(store, agentId, sessionId, interruptId, r
1459
1550
  ...loaded.signal !== void 0 ? { signal: loaded.signal } : {},
1460
1551
  ...loaded.metadata !== void 0 ? { metadata: loaded.metadata } : {},
1461
1552
  ...loaded.carrier !== void 0 ? { carrier: loaded.carrier } : {},
1462
- ...loaded.branchedFrom !== void 0 ? { branchedFrom: loaded.branchedFrom } : {}
1553
+ ...loaded.branchedFrom !== void 0 ? { branchedFrom: loaded.branchedFrom } : {},
1554
+ ...loaded.requestId !== void 0 ? { requestId: loaded.requestId } : {}
1463
1555
  };
1464
1556
  await store.save(agentId, sessionId, updated);
1465
1557
  }
1558
+ async function injectThenRun(args) {
1559
+ const { store, agentId, sessionId, interruptId, response, onStoreError, failState, run } = args;
1560
+ try {
1561
+ await injectInterruptResponse(store, agentId, sessionId, interruptId, response);
1562
+ } catch (injectError) {
1563
+ if (injectError instanceof NoInterruptError) throw injectError;
1564
+ const storeError = new StoreLoadError(injectError);
1565
+ onStoreError?.(storeError, "claim");
1566
+ return failOutcome(failState, storeError);
1567
+ }
1568
+ return run();
1569
+ }
1466
1570
 
1467
1571
  // src/agent/run-handle.ts
1468
1572
  function createRunHandle(sessionId, runId, execution, stopFlag, stepRef, resumeFn) {
@@ -1622,6 +1726,36 @@ var UnexpectedStoreSlotError = class extends Error {
1622
1726
  this.key = key;
1623
1727
  }
1624
1728
  };
1729
+ function describeValue(value) {
1730
+ return typeof value === "string" ? JSON.stringify(value) : String(value);
1731
+ }
1732
+ var InvalidClaimOptionsError = class extends Error {
1733
+ /** The rejected `ttlMs` value, as given. */
1734
+ ttlMs;
1735
+ constructor(ttlMs) {
1736
+ super(`claimOptions.ttlMs must be a finite number of milliseconds greater than 0 \u2014 got ${describeValue(ttlMs)} in createAgent options`);
1737
+ this.name = "InvalidClaimOptionsError";
1738
+ this.ttlMs = ttlMs;
1739
+ }
1740
+ };
1741
+ var InvalidRunResourceError = class extends Error {
1742
+ /** The resource key that was rejected. */
1743
+ key;
1744
+ /** The rejected value, as given. */
1745
+ value;
1746
+ constructor(key, value) {
1747
+ super(`${key} must be a non-empty string \u2014 got ${describeValue(value)} in agent.run() resources`);
1748
+ this.name = "InvalidRunResourceError";
1749
+ this.key = key;
1750
+ this.value = value;
1751
+ }
1752
+ };
1753
+ function readIdResource(resources, key) {
1754
+ const value = resources[key];
1755
+ if (value === void 0) return void 0;
1756
+ if (typeof value !== "string" || value.length === 0) throw new InvalidRunResourceError(key, value);
1757
+ return value;
1758
+ }
1625
1759
  var _agentInternals = /* @__PURE__ */ Symbol("_agentInternals");
1626
1760
  function createAgent(id, h, slots, agentOptions) {
1627
1761
  const internals = getInternals(h);
@@ -1652,6 +1786,13 @@ function createAgent(id, h, slots, agentOptions) {
1652
1786
  }
1653
1787
  }
1654
1788
  }
1789
+ let agentClaimOptions = void 0;
1790
+ if (agentOptions?.claimOptions !== void 0) {
1791
+ const ttlMs = agentOptions.claimOptions?.ttlMs;
1792
+ if (!isValidTtlMs(ttlMs)) throw new InvalidClaimOptionsError(ttlMs);
1793
+ agentClaimOptions = { ttlMs };
1794
+ }
1795
+ const fallbackClaimOptions = () => agentClaimOptions ?? { ttlMs: defaultClaimTtlMs() };
1655
1796
  const resolvedProviders = /* @__PURE__ */ new Map();
1656
1797
  const storeEntries = [];
1657
1798
  const runtimeKeys = /* @__PURE__ */ new Set();
@@ -1701,11 +1842,12 @@ function createAgent(id, h, slots, agentOptions) {
1701
1842
  runtimeKeys,
1702
1843
  requiredKeys
1703
1844
  };
1704
- const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "signal", "events", "listeners", "observer", "onObserverError", "claimOptions", "parentRunId"]);
1845
+ const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "requestId", "signal", "events", "listeners", "observer", "onObserverError", "claimOptions", "parentRunId"]);
1705
1846
  const inFlightSessions = /* @__PURE__ */ new Set();
1706
1847
  const interruptPendingSessions = /* @__PURE__ */ new Set();
1707
- const makeAgentResumeHandle = (resp, sId, iId, resumeResources = {}) => {
1708
- const { onStoreError, observer, onObserverError, telemetrySlots, parentRunId } = resumeResources;
1848
+ const resumeFailState = () => initializeState(null, {}, agentInternals.stateSchema);
1849
+ const makeAgentResumeHandle = (resp, sId, iId, resumeResources) => {
1850
+ const { onStoreError, observer, onObserverError, telemetrySlots, parentRunId, claimOptions } = resumeResources;
1709
1851
  let _stopped = false;
1710
1852
  const abortController = new AbortController();
1711
1853
  const flag = {
@@ -1721,89 +1863,63 @@ function createAgent(id, h, slots, agentOptions) {
1721
1863
  const rId = randomUUID();
1722
1864
  const exec = (async () => {
1723
1865
  await Promise.resolve();
1724
- const claimOptions = { ttlMs: 3e4 };
1725
- let leaseRef = void 0;
1726
1866
  try {
1727
- if (typeof capturedStore?.claim === "function") {
1728
- let lease;
1729
- try {
1730
- lease = await capturedStore.claim(id, sId, claimOptions);
1731
- } catch (claimError) {
1732
- const loadError = new StoreLoadError(claimError);
1733
- onStoreError?.(loadError, "claim");
1734
- const failState = initializeState(null, {}, agentInternals.stateSchema);
1735
- failState["$error"] = loadError;
1736
- return { state: failState, signal: "$error" };
1737
- }
1738
- if (lease === null) {
1739
- const busyError = new SessionBusyError(sId);
1740
- onStoreError?.(busyError, "claim");
1741
- const failState = initializeState(null, {}, agentInternals.stateSchema);
1742
- failState["$error"] = busyError;
1743
- return { state: failState, signal: "$error" };
1744
- }
1745
- leaseRef = { current: lease };
1746
- }
1747
- try {
1748
- if (capturedStore === void 0) throw new NoInterruptError();
1749
- try {
1750
- await injectInterruptResponse(capturedStore, id, sId, iId, resp);
1751
- } catch (injectError) {
1752
- if (injectError instanceof NoInterruptError) throw injectError;
1753
- const storeError = new StoreLoadError(injectError);
1754
- onStoreError?.(storeError, "claim");
1755
- const failState = initializeState(null, {}, agentInternals.stateSchema);
1756
- failState["$error"] = storeError;
1757
- return { state: failState, signal: "$error" };
1758
- }
1759
- const agentCtx = {
1760
- ...Object.fromEntries(agentInternals.resolvedProviders),
1761
- agentId: id,
1762
- sessionId: sId,
1763
- runId: rId,
1764
- signal: abortController.signal,
1765
- ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {}
1766
- };
1767
- const r = await runWithSession(
1768
- capturedStore,
1769
- id,
1770
- sId,
1771
- rId,
1772
- agentInternals.loopDef,
1773
- {},
1774
- agentInternals.stateSchema,
1775
- agentCtx,
1776
- {
1777
- shouldStop: () => flag.stopped,
1778
- onBeforeStep: (n) => {
1779
- ref.current = n;
1780
- },
1867
+ return await runClaimed({
1868
+ store: capturedStore,
1869
+ agentId: id,
1870
+ sessionId: sId,
1871
+ claimOptions,
1872
+ ...onStoreError !== void 0 ? { onStoreError } : {},
1873
+ failState: resumeFailState,
1874
+ body: async (lease) => {
1875
+ if (capturedStore === void 0) throw new NoInterruptError();
1876
+ const store = capturedStore;
1877
+ return injectThenRun({
1878
+ store,
1879
+ agentId: id,
1880
+ sessionId: sId,
1881
+ interruptId: iId,
1882
+ response: resp,
1781
1883
  ...onStoreError !== void 0 ? { onStoreError } : {},
1782
- ...leaseRef !== void 0 ? { leaseRef, claimTtlMs: claimOptions.ttlMs } : {},
1783
- ...observer !== void 0 ? { observer } : {},
1784
- ...onObserverError !== void 0 ? { onObserverError } : {},
1785
- ...telemetrySlots !== void 0 && telemetrySlots.length > 0 ? { telemetrySlots } : {},
1786
- ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
1787
- ...parentRunId !== void 0 ? { parentRunId } : {}
1788
- }
1789
- );
1790
- if (r.signal === "$interrupt") interruptPendingSessions.add(sId);
1791
- return { state: r.state, signal: r.signal };
1792
- } catch (error) {
1793
- if (error instanceof LeaseExpiredError) {
1794
- const failState = initializeState(null, {}, agentInternals.stateSchema);
1795
- failState["$error"] = error;
1796
- return { state: failState, signal: "$error" };
1797
- }
1798
- throw error;
1799
- } finally {
1800
- if (leaseRef !== void 0 && typeof capturedStore?.release === "function") {
1801
- try {
1802
- await capturedStore.release(leaseRef.current);
1803
- } catch {
1804
- }
1884
+ failState: resumeFailState,
1885
+ run: async () => {
1886
+ const agentCtx = {
1887
+ ...Object.fromEntries(agentInternals.resolvedProviders),
1888
+ agentId: id,
1889
+ sessionId: sId,
1890
+ runId: rId,
1891
+ signal: abortController.signal,
1892
+ ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {}
1893
+ };
1894
+ const r = await runWithSession(
1895
+ store,
1896
+ id,
1897
+ sId,
1898
+ rId,
1899
+ agentInternals.loopDef,
1900
+ {},
1901
+ agentInternals.stateSchema,
1902
+ agentCtx,
1903
+ {
1904
+ mode: "resume",
1905
+ shouldStop: () => flag.stopped,
1906
+ onBeforeStep: (n) => {
1907
+ ref.current = n;
1908
+ },
1909
+ ...onStoreError !== void 0 ? { onStoreError } : {},
1910
+ ...lease,
1911
+ ...observer !== void 0 ? { observer } : {},
1912
+ ...onObserverError !== void 0 ? { onObserverError } : {},
1913
+ ...telemetrySlots !== void 0 && telemetrySlots.length > 0 ? { telemetrySlots } : {},
1914
+ ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
1915
+ ...parentRunId !== void 0 ? { parentRunId } : {}
1916
+ }
1917
+ );
1918
+ return { state: r.state, signal: r.signal };
1919
+ }
1920
+ });
1805
1921
  }
1806
- }
1922
+ });
1807
1923
  } finally {
1808
1924
  inFlightSessions.delete(sId);
1809
1925
  }
@@ -1837,10 +1953,11 @@ function createAgent(id, h, slots, agentOptions) {
1837
1953
  throw new MissingRuntimeSlotError(key);
1838
1954
  }
1839
1955
  }
1840
- const sessionId = typeof resources["sessionId"] === "string" ? resources["sessionId"] : randomUUID();
1956
+ const sessionId = readIdResource(resources, "sessionId") ?? randomUUID();
1957
+ const requestId = readIdResource(resources, "requestId");
1841
1958
  const runId = randomUUID();
1842
1959
  if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
1843
- if (interruptPendingSessions.has(sessionId)) throw new SessionPendingInterruptError(sessionId);
1960
+ if (capturedStore === void 0 && interruptPendingSessions.has(sessionId)) throw new SessionPendingInterruptError(sessionId);
1844
1961
  inFlightSessions.add(sessionId);
1845
1962
  let _stopped = false;
1846
1963
  const abortController = new AbortController();
@@ -1887,7 +2004,10 @@ function createAgent(id, h, slots, agentOptions) {
1887
2004
  ...Object.entries(runtimeSlots)
1888
2005
  ]);
1889
2006
  const parentRunId = typeof resources["parentRunId"] === "string" ? resources["parentRunId"] : void 0;
2007
+ const claimOptions = parseClaimOptions(resources["claimOptions"], fallbackClaimOptions());
1890
2008
  const options = {
2009
+ mode: "run",
2010
+ ...requestId !== void 0 ? { requestId } : {},
1891
2011
  shouldStop: () => stopFlag.stopped,
1892
2012
  onBeforeStep: (name, state) => {
1893
2013
  stepRef.current = name;
@@ -1909,63 +2029,31 @@ function createAgent(id, h, slots, agentOptions) {
1909
2029
  let lastResult = null;
1910
2030
  const execution = (async () => {
1911
2031
  await Promise.resolve();
1912
- const rawClaimOpts = resources["claimOptions"];
1913
- const claimOptions = typeof rawClaimOpts === "object" && rawClaimOpts !== null && typeof rawClaimOpts["ttlMs"] === "number" ? rawClaimOpts : { ttlMs: 3e4 };
1914
- let leaseRef = void 0;
1915
2032
  try {
1916
- if (typeof capturedStore?.claim === "function") {
1917
- let lease;
1918
- try {
1919
- lease = await capturedStore.claim(id, sessionId, claimOptions);
1920
- } catch (claimError) {
1921
- const loadError = new StoreLoadError(claimError);
1922
- events.onStoreError?.(loadError, "claim");
1923
- const failState = initializeState(null, initialState, agentInternals.stateSchema);
1924
- failState["$error"] = loadError;
1925
- return { state: failState, signal: "$error" };
1926
- }
1927
- if (lease === null) {
1928
- const busyError = new SessionBusyError(sessionId);
1929
- events.onStoreError?.(busyError, "claim");
1930
- const failState = initializeState(null, initialState, agentInternals.stateSchema);
1931
- failState["$error"] = busyError;
1932
- return { state: failState, signal: "$error" };
1933
- }
1934
- leaseRef = { current: lease };
1935
- }
1936
- try {
1937
- const r = await runWithSession(
1938
- capturedStore,
1939
- id,
1940
- sessionId,
1941
- runId,
1942
- agentInternals.loopDef,
1943
- initialState,
1944
- agentInternals.stateSchema,
1945
- ctx,
1946
- {
1947
- ...options,
1948
- ...leaseRef !== void 0 ? { leaseRef, claimTtlMs: claimOptions.ttlMs } : {}
1949
- }
1950
- );
1951
- if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
1952
- lastResult = { state: r.state, cursor: r.cursor, runId, ...r.carrier !== void 0 ? { carrier: r.carrier } : {} };
1953
- return { state: r.state, signal: r.signal };
1954
- } catch (error) {
1955
- if (error instanceof LeaseExpiredError) {
1956
- const failState = initializeState(null, initialState, agentInternals.stateSchema);
1957
- failState["$error"] = error;
1958
- return { state: failState, signal: "$error" };
1959
- }
1960
- throw error;
1961
- } finally {
1962
- if (leaseRef !== void 0 && typeof capturedStore?.release === "function") {
1963
- try {
1964
- await capturedStore.release(leaseRef.current);
1965
- } catch {
1966
- }
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,
2044
+ 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 };
1967
2055
  }
1968
- }
2056
+ });
1969
2057
  } finally {
1970
2058
  inFlightSessions.delete(sessionId);
1971
2059
  }
@@ -1997,38 +2085,59 @@ function createAgent(id, h, slots, agentOptions) {
1997
2085
  signal: resumeAbortController.signal
1998
2086
  };
1999
2087
  if (capturedStore !== void 0) {
2000
- await injectInterruptResponse(capturedStore, id, sessionId, interruptId, response);
2001
- const r2 = await runWithSession(
2002
- capturedStore,
2003
- id,
2088
+ const store = capturedStore;
2089
+ const onStoreError = events.onStoreError;
2090
+ return await runClaimed({
2091
+ store,
2092
+ agentId: id,
2004
2093
  sessionId,
2005
- resumeRunId,
2006
- agentInternals.loopDef,
2007
- {},
2008
- agentInternals.stateSchema,
2009
- resumeCtx,
2010
- {
2011
- shouldStop: () => resumeStopFlag.stopped,
2012
- onBeforeStep: (n, s) => {
2013
- resumeStepRef.current = n;
2014
- events.onBeforeStep?.(n, s);
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
- ...telemetrySlots.length > 0 ? { telemetrySlots } : {},
2026
- ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {}
2027
- }
2028
- );
2029
- if (r2.signal === "$interrupt") interruptPendingSessions.add(sessionId);
2030
- lastResult = { state: r2.state, cursor: r2.cursor, runId: resumeRunId, ...r2.carrier !== void 0 ? { carrier: r2.carrier } : {} };
2031
- return { state: r2.state, signal: r2.signal };
2094
+ claimOptions,
2095
+ ...onStoreError !== void 0 ? { onStoreError } : {},
2096
+ 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
+ });
2032
2141
  }
2033
2142
  const prev = lastResult;
2034
2143
  if (prev === null) throw new NoInterruptError();
@@ -2063,13 +2172,6 @@ function createAgent(id, h, slots, agentOptions) {
2063
2172
  if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
2064
2173
  lastResult = { state: r.state, cursor: r.cursor, runId: resumeRunId, ...r.carrier !== void 0 ? { carrier: r.carrier } : {} };
2065
2174
  return { state: r.state, signal: r.signal };
2066
- } catch (error) {
2067
- if (error instanceof LeaseExpiredError) {
2068
- const failState = initializeState(null, initialState, agentInternals.stateSchema);
2069
- failState["$error"] = error;
2070
- return { state: failState, signal: "$error" };
2071
- }
2072
- throw error;
2073
2175
  } finally {
2074
2176
  inFlightSessions.delete(sessionId);
2075
2177
  }
@@ -2088,7 +2190,9 @@ function createAgent(id, h, slots, agentOptions) {
2088
2190
  const onObserverError = extractRunErrorSink(resources ?? {});
2089
2191
  const telemetrySlots = buildTelemetrySlots(agentInternals.resolvedProviders.entries());
2090
2192
  const parentRunId = resources?.["parentRunId"];
2193
+ const claimOptions = parseClaimOptions(resources?.["claimOptions"], fallbackClaimOptions());
2091
2194
  return makeAgentResumeHandle(response, sessionId, interruptId, {
2195
+ claimOptions,
2092
2196
  ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2093
2197
  ...observer !== void 0 ? { observer } : {},
2094
2198
  ...onObserverError !== void 0 ? { onObserverError } : {},
@@ -2102,6 +2206,7 @@ function createAgent(id, h, slots, agentOptions) {
2102
2206
  return agent;
2103
2207
  }
2104
2208
  export {
2209
+ InvalidRunResourceError,
2105
2210
  LeaseExpiredError,
2106
2211
  LoopNotDefinedError,
2107
2212
  NoInterruptError,