@noetaris/harness 0.11.0 → 0.12.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
@@ -634,16 +634,14 @@ function extractRunListeners(resources) {
634
634
  // src/agent/ctx-within.ts
635
635
  function createWithinFn(observer, currentStep, onObserverError) {
636
636
  return (type, payload, fn) => {
637
- const wrap = observer?.wrap;
638
637
  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);
638
+ if (observer?.wrap === void 0 || stepCtx === null) return fn();
639
+ return runWrapped((inner) => observer.wrap?.(stepCtx, { kind: "event", type, payload }, inner), fn, onObserverError);
641
640
  };
642
641
  }
643
642
  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);
643
+ if (observer?.wrap === void 0) return fn();
644
+ return runWrapped((inner) => observer.wrap?.(stepCtx, { kind: "step" }, inner), fn, onObserverError);
647
645
  }
648
646
 
649
647
  // src/loop/loop-executor.ts
@@ -707,10 +705,9 @@ function applyUpdate(state, update, schema, touchedKeys) {
707
705
  }
708
706
  }
709
707
  function fireSettled(obs, stepCtx, stepStart, fields, onObserverError) {
710
- const hook = obs?.onStepSettled;
711
- if (hook === void 0) return;
708
+ if (obs?.onStepSettled === void 0) return;
712
709
  const event = { ...fields, durationMs: Date.now() - stepStart };
713
- safeInvoke("onStepSettled", () => hook(stepCtx, event), onObserverError);
710
+ safeInvoke("onStepSettled", () => obs.onStepSettled?.(stepCtx, event), onObserverError);
714
711
  }
715
712
  function stepContextOf(runCtx, stepName) {
716
713
  return {
@@ -775,6 +772,24 @@ async function runLoop(graph, state, ctx, schema, shouldStop, startCursor, callb
775
772
  endRun("$stopped");
776
773
  return withCarrier({ state, signal: null, cursor, paused: true });
777
774
  }
775
+ if (callbacks?.debugGate !== void 0) {
776
+ const next = isForkCursor(cursor) ? cursor.fork : cursor;
777
+ const fork = isForkCursor(cursor) || graph.steps.some((s) => s.name === next && isForkDef(s));
778
+ const { patches, halt } = await callbacks.debugGate(next, state, {
779
+ branchPath: branchPath ?? [],
780
+ fork,
781
+ ...callbacks.touchedKeys !== void 0 ? { touchedKeys: callbacks.touchedKeys } : {},
782
+ ...ctx.signal !== void 0 ? { signal: ctx.signal } : {}
783
+ });
784
+ const nextCtx = stepContextOf(runCtx, next);
785
+ for (const patch of patches) {
786
+ safeInvoke("onEvent", () => obs?.onEvent?.(nextCtx, "debug.setState", { patch }), onObserverError);
787
+ }
788
+ if (halt || shouldStop?.()) {
789
+ endRun("$stopped");
790
+ return withCarrier({ state, signal: null, cursor, paused: true });
791
+ }
792
+ }
778
793
  if (isForkCursor(cursor)) {
779
794
  const forkCursor = cursor;
780
795
  const forkNode = graph.steps.find((s) => s.name === forkCursor.fork);
@@ -1028,6 +1043,7 @@ async function dispatchFork(forkNode, priorBranches, outerState, outerCtx, schem
1028
1043
  } else {
1029
1044
  outerState[key] = outcome.result.state[key];
1030
1045
  }
1046
+ callbacks?.touchedKeys?.add(key);
1031
1047
  }
1032
1048
  }
1033
1049
  return {
@@ -1183,6 +1199,15 @@ var SessionInFlightError = class extends Error {
1183
1199
  this.sessionId = sessionId;
1184
1200
  }
1185
1201
  };
1202
+ var SessionInDebugError = class extends Error {
1203
+ /** The session being debugged. */
1204
+ sessionId;
1205
+ constructor(sessionId) {
1206
+ super(`session "${sessionId}" is being debugged`);
1207
+ this.name = "SessionInDebugError";
1208
+ this.sessionId = sessionId;
1209
+ }
1210
+ };
1186
1211
  var SessionPendingInterruptError = class extends Error {
1187
1212
  /** The session that is awaiting an interrupt response. */
1188
1213
  sessionId;
@@ -1617,6 +1642,572 @@ function createRunHandle(sessionId, runId, execution, stopFlag, stepRef, resumeF
1617
1642
  return handle;
1618
1643
  }
1619
1644
 
1645
+ // src/agent/debug-session.ts
1646
+ var DebugCommandError = class extends Error {
1647
+ /**
1648
+ * - `busy`: another command is still running
1649
+ * - `not-held`: the focused frame is not held at a step stop (or, for `answer`, the session is not at
1650
+ * an interrupt stop; for `focus`, the frame is not held)
1651
+ * - `not-a-fork`: `stepInto` where the next step is not a fork node
1652
+ * - `reserved-key`: `setState` was given a framework key (`$…`)
1653
+ * - `ended`: the session is over
1654
+ */
1655
+ reason;
1656
+ /** The command that was refused. */
1657
+ command;
1658
+ constructor(reason, command, detail) {
1659
+ super(`${command}(): ${detail ?? describeReason(reason)}`);
1660
+ this.name = "DebugCommandError";
1661
+ this.reason = reason;
1662
+ this.command = command;
1663
+ }
1664
+ };
1665
+ function describeReason(reason) {
1666
+ switch (reason) {
1667
+ case "busy":
1668
+ return "another debug command is still running";
1669
+ case "not-held":
1670
+ return "the debug session is not stopped where this command applies";
1671
+ case "not-a-fork":
1672
+ return "the next step is not a fork";
1673
+ case "reserved-key":
1674
+ return "framework keys ($\u2026) cannot be set";
1675
+ case "ended":
1676
+ return "the debug session has ended";
1677
+ }
1678
+ }
1679
+ function cloneOrShare(value) {
1680
+ try {
1681
+ return { value: structuredClone(value), shared: false };
1682
+ } catch {
1683
+ return { value, shared: true };
1684
+ }
1685
+ }
1686
+ function snapshotOf(source) {
1687
+ const values = {};
1688
+ const shared = [];
1689
+ for (const [key, raw] of Object.entries(source)) {
1690
+ const copy = cloneOrShare(raw);
1691
+ values[key] = copy.value;
1692
+ if (copy.shared) shared.push(key);
1693
+ }
1694
+ return { values, shared };
1695
+ }
1696
+ function deferred() {
1697
+ let resolve;
1698
+ let reject;
1699
+ const promise = new Promise((res, rej) => {
1700
+ resolve = res;
1701
+ reject = rej;
1702
+ });
1703
+ promise.catch(() => {
1704
+ });
1705
+ return { promise, resolve, reject };
1706
+ }
1707
+ var keyOf = (path) => JSON.stringify(path);
1708
+ var samePath = (a, b) => a.length === b.length && a.every((s, i) => s === b[i]);
1709
+ var within = (path, root) => path.length >= root.length && root.every((s, i) => s === path[i]);
1710
+ function branchStart(parentForkMode) {
1711
+ return {
1712
+ mode: parentForkMode === "fork-entry" ? "fork-entry" : "continue",
1713
+ lastRelease: parentForkMode === "continue" || parentForkMode === void 0 ? "continue" : "hold"
1714
+ };
1715
+ }
1716
+ function createDebugSession(args) {
1717
+ const { store, signal, onEnd } = args;
1718
+ let status = "starting";
1719
+ let handle;
1720
+ let topMode = "start";
1721
+ let frames = /* @__PURE__ */ new Map();
1722
+ let seq = 0;
1723
+ let focus = [];
1724
+ let lastByFrame = /* @__PURE__ */ new Map();
1725
+ let topInterrupt;
1726
+ let interrupts = [];
1727
+ let pausedForks = /* @__PURE__ */ new Map();
1728
+ let paused;
1729
+ let stopRequested = false;
1730
+ let lease = {};
1731
+ let renewal;
1732
+ const breakpoints = /* @__PURE__ */ new Map();
1733
+ let command;
1734
+ let idle;
1735
+ const first = deferred();
1736
+ let current = first.promise;
1737
+ let started = false;
1738
+ const ended = deferred();
1739
+ const done = deferred();
1740
+ const anyHeld = () => [...frames.values()].some((f) => f.status === "held");
1741
+ const updateRenewal = () => {
1742
+ if (!anyHeld()) {
1743
+ if (renewal !== void 0) clearInterval(renewal);
1744
+ renewal = void 0;
1745
+ return;
1746
+ }
1747
+ if (renewal !== void 0) return;
1748
+ const { leaseRef, claimTtlMs } = lease;
1749
+ const extendClaim = store?.extendClaim;
1750
+ if (leaseRef === void 0 || claimTtlMs === void 0 || typeof extendClaim !== "function") return;
1751
+ const renew = () => {
1752
+ const held = leaseRef.current;
1753
+ if (held === null) return;
1754
+ extendClaim.call(store, held, { ttlMs: claimTtlMs }).then((renewed) => {
1755
+ leaseRef.current = renewed;
1756
+ }, () => {
1757
+ });
1758
+ };
1759
+ renew();
1760
+ renewal = setInterval(renew, claimTtlMs / 3);
1761
+ renewal.unref?.();
1762
+ };
1763
+ const frameOf = (path) => frames.get(keyOf(path));
1764
+ const addFrame = (path, init) => {
1765
+ const frame = { path, seq: seq++, patches: [], ...init };
1766
+ frames.set(keyOf(path), frame);
1767
+ return frame;
1768
+ };
1769
+ const treeOrder = (a, b) => {
1770
+ const n = Math.min(a.path.length, b.path.length);
1771
+ for (let i = 0; i < n; i++) {
1772
+ if (a.path[i] !== b.path[i]) {
1773
+ const sa = frameOf(a.path.slice(0, i + 1))?.seq ?? 0;
1774
+ const sb = frameOf(b.path.slice(0, i + 1))?.seq ?? 0;
1775
+ return sa - sb;
1776
+ }
1777
+ }
1778
+ return a.path.length - b.path.length;
1779
+ };
1780
+ const sortedFrames = () => [...frames.values()].sort(treeOrder);
1781
+ const dropDescendants = (root) => {
1782
+ for (const [key, frame] of frames) {
1783
+ if (frame.path.length > root.length && within(frame.path, root)) frames.delete(key);
1784
+ }
1785
+ };
1786
+ const seedPausedFork = (frame, forkName) => {
1787
+ const settled = pausedForks.get(keyOf(frame.path));
1788
+ if (settled?.fork === void 0 || settled.name !== forkName) return;
1789
+ pausedForks.delete(keyOf(frame.path));
1790
+ for (const branch of settled.fork.branches) {
1791
+ addFrame([...frame.path, branch.name], { status: branch.status === "done" ? "ended" : "running", ...branchStart(frame.forkMode) });
1792
+ }
1793
+ };
1794
+ const setCurrent = (stop) => {
1795
+ current = Promise.resolve(stop);
1796
+ if (!started) {
1797
+ started = true;
1798
+ first.resolve(stop);
1799
+ }
1800
+ };
1801
+ const deliver = (stop, frame) => {
1802
+ focus = frame;
1803
+ setCurrent(stop);
1804
+ const c = command;
1805
+ command = void 0;
1806
+ c?.result.resolve(stop);
1807
+ const w = idle;
1808
+ idle = void 0;
1809
+ w?.resolve(stop);
1810
+ };
1811
+ const offerStop = (stop) => {
1812
+ if (!started) return deliver(stop, stop.frame);
1813
+ if (command !== void 0) {
1814
+ const { target, orphan } = command;
1815
+ if (target === "any" || orphan !== void 0 || within(stop.frame, target)) deliver(stop, stop.frame);
1816
+ return;
1817
+ }
1818
+ if (idle !== void 0) deliver(stop, stop.frame);
1819
+ };
1820
+ const branchEndStop = (frame, endedFrame) => {
1821
+ const held = frame.stop;
1822
+ const stop = {
1823
+ kind: "step",
1824
+ frame: frame.path,
1825
+ reason: "branch-end",
1826
+ ended: endedFrame,
1827
+ runId: held.runId,
1828
+ next: held.next,
1829
+ ...held.last !== void 0 ? { last: held.last } : {},
1830
+ state: held.state
1831
+ };
1832
+ frame.stop = stop;
1833
+ return stop;
1834
+ };
1835
+ const afterFrameEnd = (endedFrame) => {
1836
+ setTimeout(() => {
1837
+ if (status !== "active") return;
1838
+ const heldFrame = sortedFrames().find((f) => f.status === "held");
1839
+ if (command !== void 0) {
1840
+ if (command.orphan !== endedFrame) return;
1841
+ if (heldFrame !== void 0) deliver(branchEndStop(heldFrame, endedFrame), heldFrame.path);
1842
+ return;
1843
+ }
1844
+ if (!samePath(focus, endedFrame.frame)) return;
1845
+ if (heldFrame !== void 0) {
1846
+ focus = heldFrame.path;
1847
+ setCurrent(branchEndStop(heldFrame, endedFrame));
1848
+ } else {
1849
+ idle ??= deferred();
1850
+ current = idle.promise;
1851
+ }
1852
+ }, 0);
1853
+ };
1854
+ const onFrameEnd = (path, signal2) => {
1855
+ const frame = frameOf(path);
1856
+ if (frame === void 0) return;
1857
+ frame.status = "ended";
1858
+ const parent = frameOf(path.slice(0, -1));
1859
+ if (parent !== void 0) parent.joinHold = frame.lastRelease === "hold";
1860
+ const outcome = signal2 === "$interrupt" ? "interrupt" : signal2 === "$error" ? "error" : signal2 === "$stopped" ? "stopped" : "done";
1861
+ const last = lastByFrame.get(keyOf(path));
1862
+ const endedFrame = { frame: path, outcome, ...last !== void 0 ? { last } : {} };
1863
+ updateRenewal();
1864
+ if (command !== void 0) {
1865
+ if (command.target !== "any" && samePath(command.target, path)) {
1866
+ command.orphan = endedFrame;
1867
+ afterFrameEnd(endedFrame);
1868
+ }
1869
+ return;
1870
+ }
1871
+ if (samePath(focus, path)) afterFrameEnd(endedFrame);
1872
+ };
1873
+ const onAbort = () => {
1874
+ void session.stop();
1875
+ };
1876
+ const cleanup = () => {
1877
+ for (const frame of frames.values()) if (frame.status === "held") frame.status = "ended";
1878
+ updateRenewal();
1879
+ signal?.removeEventListener("abort", onAbort);
1880
+ onEnd();
1881
+ };
1882
+ const topLast = () => lastByFrame.get(keyOf([]));
1883
+ const finish = (outcome) => {
1884
+ const last = topLast();
1885
+ const stop = { kind: "end", runId: handle.runId, ...last !== void 0 ? { last } : {}, outcome };
1886
+ status = "ended";
1887
+ cleanup();
1888
+ done.resolve(outcome);
1889
+ deliver(stop, []);
1890
+ ended.resolve(stop);
1891
+ };
1892
+ const fail = (error) => {
1893
+ status = "ended";
1894
+ cleanup();
1895
+ done.reject(error);
1896
+ const c = command;
1897
+ command = void 0;
1898
+ c?.result.reject(error);
1899
+ const w = idle;
1900
+ idle = void 0;
1901
+ w?.reject(error);
1902
+ if (!started) first.reject(error);
1903
+ else current = done.promise.then(() => {
1904
+ throw error;
1905
+ });
1906
+ current.catch(() => {
1907
+ });
1908
+ ended.reject(error);
1909
+ };
1910
+ const pendingInterrupts = () => {
1911
+ const pending = [];
1912
+ const walk = (path) => {
1913
+ const settled = lastByFrame.get(keyOf(path));
1914
+ if (settled?.fork === void 0) return;
1915
+ for (const branch of settled.fork.branches) {
1916
+ if (branch.status !== "paused") continue;
1917
+ const branchPath = [...path, branch.name];
1918
+ const raised = interrupts.find((i) => samePath(i.branchPath, branchPath));
1919
+ if (raised !== void 0) pending.push({ interruptId: raised.interruptId, prompt: raised.prompt, frame: branchPath });
1920
+ else walk(branchPath);
1921
+ }
1922
+ };
1923
+ if (topInterrupt !== void 0 && topLast()?.fork === void 0) {
1924
+ pending.push({ interruptId: topInterrupt.interruptId, prompt: topInterrupt.prompt, frame: [] });
1925
+ } else {
1926
+ walk([]);
1927
+ }
1928
+ return pending;
1929
+ };
1930
+ const attach = (h) => {
1931
+ h.then((outcome) => {
1932
+ const last = topLast();
1933
+ if (outcome.signal === "$interrupt" && !stopRequested && last !== void 0) {
1934
+ const pending = pendingInterrupts();
1935
+ const head = pending[0];
1936
+ if (head !== void 0) {
1937
+ status = "interrupt";
1938
+ paused = { outcome, pending };
1939
+ for (const frame of frames.values()) if (frame.status === "held") frame.status = "ended";
1940
+ updateRenewal();
1941
+ deliver({
1942
+ kind: "interrupt",
1943
+ frame: head.frame,
1944
+ runId: h.runId,
1945
+ last,
1946
+ interruptId: head.interruptId,
1947
+ prompt: head.prompt,
1948
+ pending,
1949
+ state: snapshotOf(outcome.state)
1950
+ }, head.frame);
1951
+ return;
1952
+ }
1953
+ }
1954
+ finish(outcome);
1955
+ }, fail);
1956
+ };
1957
+ const gate = async (next, state, info) => {
1958
+ const path = info.branchPath;
1959
+ let frame = frameOf(path);
1960
+ if (frame === void 0) {
1961
+ if (path.length === 0) {
1962
+ frame = addFrame(path, { status: "running", mode: topMode, lastRelease: "hold" });
1963
+ } else {
1964
+ frame = addFrame(path, { status: "running", ...branchStart(frameOf(path.slice(0, -1))?.forkMode) });
1965
+ }
1966
+ } else if (frame.status === "in-fork") {
1967
+ dropDescendants(path);
1968
+ frame.mode = frame.joinHold === false ? "continue" : "step";
1969
+ frame.joinHold = void 0;
1970
+ frame.forkMode = void 0;
1971
+ }
1972
+ if (info.signal?.aborted === true) return { patches: [], halt: true };
1973
+ let reason;
1974
+ let condition;
1975
+ if (frame.mode !== "continue") {
1976
+ reason = frame.mode;
1977
+ } else {
1978
+ const breakpoint = breakpoints.get(next);
1979
+ if (breakpoint !== void 0) {
1980
+ try {
1981
+ if (breakpoint.when === void 0 || breakpoint.when(state)) reason = "breakpoint";
1982
+ } catch (error) {
1983
+ reason = "breakpoint";
1984
+ condition = { error };
1985
+ }
1986
+ }
1987
+ }
1988
+ const enter = () => {
1989
+ frame.before = snapshotOf(state);
1990
+ if (info.fork) {
1991
+ frame.status = "in-fork";
1992
+ frame.forkMode ??= frame.mode === "continue" ? "continue" : "over";
1993
+ seedPausedFork(frame, next);
1994
+ } else {
1995
+ frame.status = "running";
1996
+ }
1997
+ };
1998
+ if (reason === void 0) {
1999
+ enter();
2000
+ return { patches: [], halt: false };
2001
+ }
2002
+ frame.status = "held";
2003
+ frame.next = next;
2004
+ frame.isFork = info.fork;
2005
+ frame.live = state;
2006
+ frame.forkMode = void 0;
2007
+ if (info.touchedKeys !== void 0) frame.touched = info.touchedKeys;
2008
+ const last = lastByFrame.get(keyOf(path));
2009
+ const stop = {
2010
+ kind: "step",
2011
+ frame: path,
2012
+ reason,
2013
+ runId: handle.runId,
2014
+ next,
2015
+ ...last !== void 0 ? { last } : {},
2016
+ state: snapshotOf(state),
2017
+ ...condition !== void 0 ? { conditionError: condition.error } : {}
2018
+ };
2019
+ frame.stop = stop;
2020
+ const released = new Promise((resolve) => {
2021
+ frame.release = resolve;
2022
+ });
2023
+ const onHalt = () => {
2024
+ frame.release?.({ patches: [], halt: true });
2025
+ };
2026
+ info.signal?.addEventListener("abort", onHalt);
2027
+ updateRenewal();
2028
+ offerStop(stop);
2029
+ const result = await released;
2030
+ info.signal?.removeEventListener("abort", onHalt);
2031
+ frame.release = void 0;
2032
+ frame.live = void 0;
2033
+ if (!result.halt) enter();
2034
+ updateRenewal();
2035
+ return result;
2036
+ };
2037
+ const release = (frame, how, halt = false) => {
2038
+ if (!halt) {
2039
+ frame.mode = how === "next" ? "step" : "continue";
2040
+ frame.lastRelease = how === "next" || how === "stepInto" ? "hold" : "continue";
2041
+ if (frame.isFork === true) frame.forkMode = how === "stepInto" ? "fork-entry" : how === "next" ? "over" : "continue";
2042
+ frame.status = frame.isFork === true ? "in-fork" : "running";
2043
+ }
2044
+ const patches = frame.patches;
2045
+ frame.patches = [];
2046
+ const r = frame.release;
2047
+ frame.release = void 0;
2048
+ r?.({ patches, halt });
2049
+ };
2050
+ const observer = {
2051
+ onStepSettled: (ctx, e) => {
2052
+ const path = ctx.branchPath ?? [];
2053
+ if (path.length === 0) {
2054
+ topInterrupt = e.interrupt !== void 0 ? { interruptId: e.interrupt.interruptId, prompt: e.interrupt.prompt, branchPath: [] } : void 0;
2055
+ }
2056
+ lastByFrame.set(keyOf(path), {
2057
+ name: ctx.stepName,
2058
+ outcome: e.outcome,
2059
+ ...e.update !== void 0 ? { update: snapshotOf(e.update) } : {},
2060
+ ...e.signal !== void 0 ? { signal: e.signal } : {},
2061
+ next: e.next,
2062
+ ...e.error !== void 0 ? { error: e.error } : {},
2063
+ before: frameOf(path)?.before ?? { values: {}, shared: [] },
2064
+ durationMs: e.durationMs,
2065
+ ...e.fork !== void 0 ? { fork: e.fork } : {}
2066
+ });
2067
+ },
2068
+ onInterrupt: (ctx, e) => {
2069
+ interrupts.push({ interruptId: e.interruptId, prompt: e.prompt, branchPath: ctx.branchPath ?? [] });
2070
+ },
2071
+ onRunEnd: (ctx, e) => {
2072
+ if (ctx.branchPath !== void 0) onFrameEnd(ctx.branchPath, e.signal);
2073
+ }
2074
+ };
2075
+ const refuse = (name) => {
2076
+ if (status === "ended") return new DebugCommandError("ended", name);
2077
+ if (status === "starting" || !started || command !== void 0) return new DebugCommandError("busy", name);
2078
+ if (status === "interrupt" && name !== "answer") return new DebugCommandError("not-held", name);
2079
+ if (status === "active" && name === "answer") return new DebugCommandError("not-held", name);
2080
+ return void 0;
2081
+ };
2082
+ const issue = (target) => {
2083
+ const result = deferred();
2084
+ command = { target, result };
2085
+ return result.promise;
2086
+ };
2087
+ const drive = (how) => {
2088
+ const refused = refuse(how);
2089
+ if (refused !== void 0) return Promise.reject(refused);
2090
+ const frame = frameOf(focus);
2091
+ if (frame === void 0 || frame.status !== "held") return Promise.reject(new DebugCommandError("not-held", how));
2092
+ if (how === "stepInto" && frame.isFork !== true) return Promise.reject(new DebugCommandError("not-a-fork", how));
2093
+ const p = issue(frame.path);
2094
+ release(frame, how);
2095
+ updateRenewal();
2096
+ return p;
2097
+ };
2098
+ const session = {
2099
+ get sessionId() {
2100
+ return handle.sessionId;
2101
+ },
2102
+ get runId() {
2103
+ return handle.runId;
2104
+ },
2105
+ get current() {
2106
+ return current;
2107
+ },
2108
+ get done() {
2109
+ return done.promise;
2110
+ },
2111
+ get breakpoints() {
2112
+ return [...breakpoints.values()];
2113
+ },
2114
+ get frames() {
2115
+ return sortedFrames().map((f) => ({ frame: f.path, status: f.status, ...f.status === "held" && f.next !== void 0 ? { next: f.next } : {} }));
2116
+ },
2117
+ focus: (path) => {
2118
+ const frame = frameOf(path);
2119
+ if (status !== "active" || frame === void 0 || frame.status !== "held" || frame.stop === void 0) {
2120
+ throw new DebugCommandError("not-held", "focus");
2121
+ }
2122
+ focus = frame.path;
2123
+ setCurrent(frame.stop);
2124
+ return frame.stop;
2125
+ },
2126
+ next: () => drive("next"),
2127
+ continue: () => drive("continue"),
2128
+ stepInto: () => drive("stepInto"),
2129
+ continueAll: () => {
2130
+ const refused = refuse("continueAll");
2131
+ if (refused !== void 0) return Promise.reject(refused);
2132
+ const p = issue("any");
2133
+ for (const frame of sortedFrames()) if (frame.status === "held") release(frame, "continueAll");
2134
+ updateRenewal();
2135
+ return p;
2136
+ },
2137
+ answer: (response, id) => {
2138
+ const at = paused;
2139
+ const refused = refuse("answer") ?? (at === void 0 ? new DebugCommandError("not-held", "answer") : void 0);
2140
+ if (refused !== void 0 || at === void 0) return Promise.reject(refused);
2141
+ const target = id ?? at.pending[0].interruptId;
2142
+ if (!at.pending.some((p2) => p2.interruptId === target)) return Promise.reject(new NoInterruptError());
2143
+ let resumed;
2144
+ try {
2145
+ resumed = handle.resume(response, target);
2146
+ } catch (error) {
2147
+ return Promise.reject(error);
2148
+ }
2149
+ pausedForks = new Map([...lastByFrame].filter(([, s]) => s.fork !== void 0 && (s.outcome === "interrupt" || s.outcome === "stopped")));
2150
+ handle = resumed;
2151
+ paused = void 0;
2152
+ status = "active";
2153
+ topMode = "resume";
2154
+ frames = /* @__PURE__ */ new Map();
2155
+ focus = [];
2156
+ lastByFrame = /* @__PURE__ */ new Map();
2157
+ topInterrupt = void 0;
2158
+ interrupts = [];
2159
+ lease = {};
2160
+ const p = issue([]);
2161
+ attach(handle);
2162
+ return p;
2163
+ },
2164
+ setState: (patch) => {
2165
+ if (status === "ended") throw new DebugCommandError("ended", "setState");
2166
+ const frame = frameOf(focus);
2167
+ if (status !== "active" || frame === void 0 || frame.status !== "held" || frame.live === void 0) {
2168
+ throw new DebugCommandError("not-held", "setState");
2169
+ }
2170
+ const reserved = Object.keys(patch).find((k) => k.startsWith("$"));
2171
+ if (reserved !== void 0) throw new DebugCommandError("reserved-key", "setState", `framework key "${reserved}" cannot be set`);
2172
+ const reported = {};
2173
+ for (const [key, value] of Object.entries(patch)) {
2174
+ frame.live[key] = cloneOrShare(value).value;
2175
+ reported[key] = cloneOrShare(value).value;
2176
+ frame.touched?.add(key);
2177
+ }
2178
+ frame.patches.push(reported);
2179
+ return snapshotOf(frame.live);
2180
+ },
2181
+ setBreakpoint: (step, when) => {
2182
+ breakpoints.set(step, { step, ...when !== void 0 ? { when } : {} });
2183
+ },
2184
+ clearBreakpoint: (step) => {
2185
+ breakpoints.delete(step);
2186
+ },
2187
+ stop: () => {
2188
+ if (status === "ended") return ended.promise;
2189
+ stopRequested = true;
2190
+ if (status === "interrupt" && paused !== void 0) {
2191
+ finish(paused.outcome);
2192
+ return ended.promise;
2193
+ }
2194
+ handle.stop();
2195
+ for (const frame of frames.values()) if (frame.status === "held") release(frame, "continueAll", true);
2196
+ return ended.promise;
2197
+ }
2198
+ };
2199
+ handle = args.start({ gate, observer, onLease: (l) => {
2200
+ lease = l;
2201
+ } });
2202
+ status = "active";
2203
+ attach(handle);
2204
+ if (signal !== void 0) {
2205
+ signal.addEventListener("abort", onAbort);
2206
+ if (signal.aborted) onAbort();
2207
+ }
2208
+ return session;
2209
+ }
2210
+
1620
2211
  // src/agent/create-agent.ts
1621
2212
  import { randomUUID } from "crypto";
1622
2213
 
@@ -1738,6 +2329,18 @@ var InvalidClaimOptionsError = class extends Error {
1738
2329
  this.ttlMs = ttlMs;
1739
2330
  }
1740
2331
  };
2332
+ var InvalidAgentOptionError = class extends Error {
2333
+ /** The option that was rejected. */
2334
+ key;
2335
+ /** The rejected value, as given. */
2336
+ value;
2337
+ constructor(key, value) {
2338
+ super(`${key} must be ${key === "observer" ? "an object" : "a function"} \u2014 got ${describeValue(value)} in createAgent options`);
2339
+ this.name = "InvalidAgentOptionError";
2340
+ this.key = key;
2341
+ this.value = value;
2342
+ }
2343
+ };
1741
2344
  var InvalidRunResourceError = class extends Error {
1742
2345
  /** The resource key that was rejected. */
1743
2346
  key;
@@ -1793,6 +2396,23 @@ function createAgent(id, h, slots, agentOptions) {
1793
2396
  agentClaimOptions = { ttlMs };
1794
2397
  }
1795
2398
  const fallbackClaimOptions = () => agentClaimOptions ?? { ttlMs: defaultClaimTtlMs() };
2399
+ const agentObserver = agentOptions?.observer;
2400
+ if (agentObserver !== void 0 && (agentObserver === null || typeof agentObserver !== "object" || Array.isArray(agentObserver))) {
2401
+ throw new InvalidAgentOptionError("observer", agentObserver);
2402
+ }
2403
+ const agentErrorSink = agentOptions?.onObserverError;
2404
+ if (agentErrorSink !== void 0 && typeof agentErrorSink !== "function") {
2405
+ throw new InvalidAgentOptionError("onObserverError", agentErrorSink);
2406
+ }
2407
+ const resolveObserver = (resources) => {
2408
+ const runObserver = extractRunObserver(resources);
2409
+ const onObserverError = extractRunErrorSink(resources) ?? agentErrorSink;
2410
+ const observer = agentObserver === void 0 ? runObserver : runObserver === void 0 || runObserver === agentObserver ? agentObserver : composeObservers([agentObserver, runObserver], onObserverError);
2411
+ return {
2412
+ ...observer !== void 0 ? { observer } : {},
2413
+ ...onObserverError !== void 0 ? { onObserverError } : {}
2414
+ };
2415
+ };
1796
2416
  const resolvedProviders = /* @__PURE__ */ new Map();
1797
2417
  const storeEntries = [];
1798
2418
  const runtimeKeys = /* @__PURE__ */ new Set();
@@ -1844,6 +2464,7 @@ function createAgent(id, h, slots, agentOptions) {
1844
2464
  };
1845
2465
  const reservedRunKeys = /* @__PURE__ */ new Set(["sessionId", "requestId", "signal", "events", "listeners", "observer", "onObserverError", "claimOptions", "parentRunId"]);
1846
2466
  const inFlightSessions = /* @__PURE__ */ new Set();
2467
+ const debugSessions = /* @__PURE__ */ new Set();
1847
2468
  const interruptPendingSessions = /* @__PURE__ */ new Set();
1848
2469
  const resumeFailState = () => initializeState(null, {}, agentInternals.stateSchema);
1849
2470
  const makeAgentResumeHandle = (resp, sId, iId, resumeResources) => {
@@ -1933,261 +2554,269 @@ function createAgent(id, h, slots, agentOptions) {
1933
2554
  };
1934
2555
  return createRunHandle(sId, rId, exec, flag, ref, resumeFn);
1935
2556
  };
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
- }
2557
+ const startRun = (initialState, resources, debug) => {
2558
+ for (const key of Object.keys(resources)) {
2559
+ if (reservedRunKeys.has(key)) continue;
2560
+ if (!agentInternals.runtimeKeys.has(key) && !agentInternals.requiredKeys.has(key)) {
2561
+ throw new UnknownRunSlotError(key);
1944
2562
  }
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
- }
2563
+ }
2564
+ for (const key of Object.keys(resources)) {
2565
+ if (reservedRunKeys.has(key)) continue;
2566
+ if (agentInternals.requiredKeys.has(key)) {
2567
+ throw new RequiredSlotInRunError(key);
1950
2568
  }
1951
- for (const key of agentInternals.runtimeKeys) {
1952
- if (!(key in resources)) {
1953
- throw new MissingRuntimeSlotError(key);
1954
- }
2569
+ }
2570
+ for (const key of agentInternals.runtimeKeys) {
2571
+ if (!(key in resources)) {
2572
+ throw new MissingRuntimeSlotError(key);
1955
2573
  }
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;
2574
+ }
2575
+ const sessionId = readIdResource(resources, "sessionId") ?? randomUUID();
2576
+ const requestId = readIdResource(resources, "requestId");
2577
+ const runId = randomUUID();
2578
+ if (debugSessions.has(sessionId)) throw new SessionInDebugError(sessionId);
2579
+ if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
2580
+ if (capturedStore === void 0 && interruptPendingSessions.has(sessionId)) throw new SessionPendingInterruptError(sessionId);
2581
+ inFlightSessions.add(sessionId);
2582
+ let _stopped = false;
2583
+ const abortController = new AbortController();
2584
+ const stopFlag = {
2585
+ get stopped() {
2586
+ return _stopped;
2587
+ },
2588
+ set stopped(v) {
2589
+ _stopped = v;
2590
+ if (v) abortController.abort();
1982
2591
  }
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];
2592
+ };
2593
+ const rawSignal = debug === void 0 ? resources["signal"] : void 0;
2594
+ let ctxSignal = abortController.signal;
2595
+ if (rawSignal instanceof AbortSignal) {
2596
+ ctxSignal = rawSignal;
2597
+ rawSignal.addEventListener("abort", () => {
2598
+ stopFlag.stopped = true;
2599
+ abortController.abort();
2600
+ }, { once: true });
2601
+ if (rawSignal.aborted) stopFlag.stopped = true;
2602
+ }
2603
+ const stepRef = { current: null };
2604
+ const runtimeSlots = {};
2605
+ for (const key of agentInternals.runtimeKeys) {
2606
+ if (reservedRunKeys.has(key)) continue;
2607
+ runtimeSlots[key] = resources[key];
2608
+ }
2609
+ const ctx = {
2610
+ ...Object.fromEntries(agentInternals.resolvedProviders),
2611
+ ...runtimeSlots,
2612
+ agentId: id,
2613
+ sessionId,
2614
+ runId,
2615
+ signal: ctxSignal,
2616
+ ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {}
2617
+ };
2618
+ const events = extractRunEvents(resources);
2619
+ const listeners = extractRunListeners(resources);
2620
+ const resolved = resolveObserver(resources);
2621
+ const onObserverError = resolved.onObserverError;
2622
+ const observer = debug === void 0 ? resolved.observer : resolved.observer === void 0 ? debug.observer : composeObservers([resolved.observer, debug.observer], onObserverError);
2623
+ const telemetrySlots = buildTelemetrySlots([
2624
+ ...agentInternals.resolvedProviders.entries(),
2625
+ ...Object.entries(runtimeSlots)
2626
+ ]);
2627
+ const parentRunId = typeof resources["parentRunId"] === "string" ? resources["parentRunId"] : void 0;
2628
+ const claimOptions = parseClaimOptions(resources["claimOptions"], fallbackClaimOptions());
2629
+ const options = {
2630
+ mode: "run",
2631
+ ...requestId !== void 0 ? { requestId } : {},
2632
+ shouldStop: () => stopFlag.stopped,
2633
+ onBeforeStep: (name, state) => {
2634
+ stepRef.current = name;
2635
+ events.onBeforeStep?.(name, state);
2636
+ },
2637
+ // spread optional event callbacks only when defined (exactOptionalPropertyTypes requires omission, not undefined)
2638
+ ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2639
+ ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2640
+ ...events.onError !== void 0 ? { onError: events.onError } : {},
2641
+ ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2642
+ ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2643
+ ...Object.keys(listeners).length > 0 ? { listeners } : {},
2644
+ ...observer !== void 0 ? { observer } : {},
2645
+ ...onObserverError !== void 0 ? { onObserverError } : {},
2646
+ ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
2647
+ ...parentRunId !== void 0 ? { parentRunId } : {},
2648
+ ...telemetrySlots.length > 0 ? { telemetrySlots } : {},
2649
+ ...debug !== void 0 ? { debugGate: debug.gate } : {}
2650
+ };
2651
+ let lastResult = null;
2652
+ const execution = (async () => {
2653
+ await Promise.resolve();
2654
+ try {
2655
+ return await runClaimed({
2656
+ store: capturedStore,
2657
+ agentId: id,
2658
+ sessionId,
2659
+ claimOptions,
2660
+ ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2661
+ failState: () => initializeState(null, initialState, agentInternals.stateSchema),
2662
+ body: async (lease) => {
2663
+ debug?.onLease(lease);
2664
+ const r = await runWithSession(
2665
+ capturedStore,
2666
+ id,
2667
+ sessionId,
2668
+ runId,
2669
+ agentInternals.loopDef,
2670
+ initialState,
2671
+ agentInternals.stateSchema,
2672
+ ctx,
2673
+ { ...options, ...lease }
2674
+ );
2675
+ if (capturedStore === void 0 && r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
2676
+ lastResult = { state: r.state, cursor: r.cursor, runId, ...r.carrier !== void 0 ? { carrier: r.carrier } : {} };
2677
+ return { state: r.state, signal: r.signal };
2678
+ }
2679
+ });
2680
+ } finally {
2681
+ inFlightSessions.delete(sessionId);
1988
2682
  }
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,
2683
+ })();
2684
+ const buildResumeFn = () => {
2685
+ return (response, interruptId) => {
2686
+ if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
2687
+ interruptPendingSessions.delete(sessionId);
2688
+ inFlightSessions.add(sessionId);
2689
+ let _resumeStopped = false;
2690
+ const resumeAbortController = new AbortController();
2691
+ const resumeStopFlag = {
2692
+ get stopped() {
2693
+ return _resumeStopped;
2694
+ },
2695
+ set stopped(v) {
2696
+ _resumeStopped = v;
2697
+ if (v) resumeAbortController.abort();
2698
+ }
2699
+ };
2700
+ const resumeStepRef = { current: null };
2701
+ const resumeRunId = randomUUID();
2702
+ const resumeExecution = (async () => {
2703
+ await Promise.resolve();
2704
+ try {
2705
+ const resumeCtx = {
2706
+ ...ctx,
2707
+ runId: resumeRunId,
2708
+ signal: resumeAbortController.signal
2709
+ };
2710
+ if (capturedStore !== void 0) {
2711
+ const store = capturedStore;
2712
+ const onStoreError = events.onStoreError;
2713
+ return await runClaimed({
2714
+ store,
2715
+ agentId: id,
2044
2716
  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({
2717
+ claimOptions,
2718
+ ...onStoreError !== void 0 ? { onStoreError } : {},
2719
+ failState: resumeFailState,
2720
+ body: (lease) => injectThenRun({
2091
2721
  store,
2092
2722
  agentId: id,
2093
2723
  sessionId,
2094
- claimOptions,
2724
+ interruptId,
2725
+ response,
2095
2726
  ...onStoreError !== void 0 ? { onStoreError } : {},
2096
2727
  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);
2728
+ run: async () => {
2729
+ debug?.onLease(lease);
2730
+ const r2 = await runWithSession(
2731
+ store,
2732
+ id,
2733
+ sessionId,
2734
+ resumeRunId,
2735
+ agentInternals.loopDef,
2736
+ {},
2737
+ agentInternals.stateSchema,
2738
+ resumeCtx,
2739
+ {
2740
+ mode: "resume",
2741
+ shouldStop: () => resumeStopFlag.stopped,
2742
+ onBeforeStep: (n, s) => {
2743
+ resumeStepRef.current = n;
2744
+ events.onBeforeStep?.(n, s);
2745
+ },
2746
+ // spread optional event callbacks only when defined (exactOptionalPropertyTypes requires omission, not undefined)
2747
+ ...events.onStoreError !== void 0 ? { onStoreError: events.onStoreError } : {},
2748
+ ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2749
+ ...events.onError !== void 0 ? { onError: events.onError } : {},
2750
+ ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2751
+ ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2752
+ ...Object.keys(listeners).length > 0 ? { listeners } : {},
2753
+ ...observer !== void 0 ? { observer } : {},
2754
+ ...onObserverError !== void 0 ? { onObserverError } : {},
2755
+ ...telemetrySlots.length > 0 ? { telemetrySlots } : {},
2756
+ ...agentOptions?.instanceId !== void 0 ? { instanceId: agentOptions.instanceId } : {},
2757
+ ...debug !== void 0 ? { debugGate: debug.gate } : {},
2758
+ ...lease
2759
+ }
2760
+ );
2761
+ lastResult = { state: r2.state, cursor: r2.cursor, runId: resumeRunId, ...r2.carrier !== void 0 ? { carrier: r2.carrier } : {} };
2762
+ return { state: r2.state, signal: r2.signal };
2763
+ }
2764
+ })
2765
+ });
2177
2766
  }
2178
- })();
2179
- return createRunHandle(sessionId, resumeRunId, resumeExecution, resumeStopFlag, resumeStepRef, buildResumeFn());
2180
- };
2767
+ const prev = lastResult;
2768
+ if (prev === null) throw new NoInterruptError();
2769
+ const injected = injectInterruptResponseIntoState(prev.cursor ?? void 0, prev.state, interruptId, response);
2770
+ if (!injected.found) throw new NoInterruptError();
2771
+ const state = injected.state;
2772
+ const cursor = injected.cursor;
2773
+ const r = await runLoop(
2774
+ agentInternals.loopDef,
2775
+ state,
2776
+ resumeCtx,
2777
+ agentInternals.stateSchema,
2778
+ () => resumeStopFlag.stopped,
2779
+ cursor,
2780
+ {
2781
+ runId: resumeRunId,
2782
+ resumedFrom: { runId: prev.runId, ...prev.carrier !== void 0 ? { carrier: prev.carrier } : {} },
2783
+ onBeforeStep: (n, s) => {
2784
+ resumeStepRef.current = n;
2785
+ events.onBeforeStep?.(n, s);
2786
+ },
2787
+ ...events.onAfterStep !== void 0 ? { onAfterStep: events.onAfterStep } : {},
2788
+ ...events.onError !== void 0 ? { onError: events.onError } : {},
2789
+ ...events.onComplete !== void 0 ? { onComplete: events.onComplete } : {},
2790
+ ...events.onInterrupt !== void 0 ? { onInterrupt: events.onInterrupt } : {},
2791
+ ...Object.keys(listeners).length > 0 ? { listeners } : {},
2792
+ ...observer !== void 0 ? { observer } : {},
2793
+ ...onObserverError !== void 0 ? { onObserverError } : {},
2794
+ ...telemetrySlots.length > 0 ? { telemetrySlots } : {},
2795
+ ...debug !== void 0 ? { debugGate: debug.gate } : {}
2796
+ }
2797
+ );
2798
+ if (r.signal === "$interrupt") interruptPendingSessions.add(sessionId);
2799
+ lastResult = { state: r.state, cursor: r.cursor, runId: resumeRunId, ...r.carrier !== void 0 ? { carrier: r.carrier } : {} };
2800
+ return { state: r.state, signal: r.signal };
2801
+ } finally {
2802
+ inFlightSessions.delete(sessionId);
2803
+ }
2804
+ })();
2805
+ return createRunHandle(sessionId, resumeRunId, resumeExecution, resumeStopFlag, resumeStepRef, buildResumeFn());
2181
2806
  };
2182
- return createRunHandle(sessionId, runId, execution, stopFlag, stepRef, buildResumeFn());
2183
- },
2807
+ };
2808
+ return createRunHandle(sessionId, runId, execution, stopFlag, stepRef, buildResumeFn());
2809
+ };
2810
+ const agent = {
2811
+ id,
2812
+ run: (initialState, resources) => startRun(initialState, resources),
2184
2813
  resume: (response, sessionId, interruptId, resources) => {
2814
+ if (debugSessions.has(sessionId)) throw new SessionInDebugError(sessionId);
2185
2815
  if (inFlightSessions.has(sessionId)) throw new SessionInFlightError(sessionId);
2186
2816
  interruptPendingSessions.delete(sessionId);
2187
2817
  inFlightSessions.add(sessionId);
2188
2818
  const events = extractRunEvents(resources ?? {});
2189
- const observer = extractRunObserver(resources ?? {});
2190
- const onObserverError = extractRunErrorSink(resources ?? {});
2819
+ const { observer, onObserverError } = resolveObserver(resources ?? {});
2191
2820
  const telemetrySlots = buildTelemetrySlots(agentInternals.resolvedProviders.entries());
2192
2821
  const parentRunId = resources?.["parentRunId"];
2193
2822
  const claimOptions = parseClaimOptions(resources?.["claimOptions"], fallbackClaimOptions());
@@ -2200,12 +2829,33 @@ function createAgent(id, h, slots, agentOptions) {
2200
2829
  ...typeof parentRunId === "string" ? { parentRunId } : {}
2201
2830
  });
2202
2831
  },
2832
+ debug: (initialState, resources) => {
2833
+ const rawSignal = resources["signal"];
2834
+ let sessionId;
2835
+ const session = createDebugSession({
2836
+ start: (hooks) => {
2837
+ const handle = startRun(initialState, resources, hooks);
2838
+ sessionId = handle.sessionId;
2839
+ return handle;
2840
+ },
2841
+ store: capturedStore,
2842
+ signal: rawSignal instanceof AbortSignal ? rawSignal : void 0,
2843
+ onEnd: () => {
2844
+ if (sessionId !== void 0) debugSessions.delete(sessionId);
2845
+ }
2846
+ });
2847
+ debugSessions.add(session.sessionId);
2848
+ return session;
2849
+ },
2203
2850
  status: (sessionId) => querySessionPhase(capturedStore, id, sessionId),
2204
2851
  [_agentInternals]: agentInternals
2205
2852
  };
2206
2853
  return agent;
2207
2854
  }
2208
2855
  export {
2856
+ DebugCommandError,
2857
+ InvalidAgentOptionError,
2858
+ InvalidClaimOptionsError,
2209
2859
  InvalidRunResourceError,
2210
2860
  LeaseExpiredError,
2211
2861
  LoopNotDefinedError,
@@ -2213,6 +2863,7 @@ export {
2213
2863
  REQUIRED_TAG,
2214
2864
  RUNTIME_TAG,
2215
2865
  SessionBusyError,
2866
+ SessionInDebugError,
2216
2867
  SessionInFlightError,
2217
2868
  SessionPendingInterruptError,
2218
2869
  StoreLoadError,