nexus-ai-pro 2.0.0 → 2.2.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.
Files changed (282) hide show
  1. package/API_STABILITY.md +65 -0
  2. package/CHANGELOG.md +267 -1
  3. package/MIGRATING.md +1 -1
  4. package/README.md +17 -8
  5. package/dist/agent/create-agent.d.ts +9 -1
  6. package/dist/agent/create-agent.js +40 -1
  7. package/dist/cache/memory-cache.d.ts +8 -0
  8. package/dist/cache/memory-cache.js +9 -0
  9. package/dist/cache/semantic-cache.d.ts +6 -3
  10. package/dist/cache/semantic-cache.js +5 -2
  11. package/dist/cli/args.js +3 -0
  12. package/dist/cli/db.d.ts +16 -4
  13. package/dist/cli/db.js +169 -22
  14. package/dist/cli/doctor.d.ts +17 -0
  15. package/dist/cli/doctor.js +53 -0
  16. package/dist/cli/graph.d.ts +9 -0
  17. package/dist/cli/graph.js +47 -0
  18. package/dist/cli.js +21 -2
  19. package/dist/core/lifecycle.js +11 -6
  20. package/dist/core/nexus.d.ts +12 -2
  21. package/dist/core/nexus.js +106 -23
  22. package/dist/doctor/index.d.ts +90 -0
  23. package/dist/doctor/index.js +237 -0
  24. package/dist/evals/judge.d.ts +11 -0
  25. package/dist/evals/judge.js +33 -0
  26. package/dist/evaluate/index.d.ts +1 -0
  27. package/dist/evaluate/index.js +1 -0
  28. package/dist/evaluate/provenance.d.ts +22 -0
  29. package/dist/evaluate/provenance.js +10 -0
  30. package/dist/evaluate/run.js +20 -4
  31. package/dist/graph/durability.d.ts +27 -0
  32. package/dist/graph/durability.js +66 -0
  33. package/dist/graph/errors.d.ts +30 -4
  34. package/dist/graph/errors.js +18 -2
  35. package/dist/graph/event-stream.d.ts +75 -0
  36. package/dist/graph/event-stream.js +289 -0
  37. package/dist/graph/functional.d.ts +80 -7
  38. package/dist/graph/functional.js +138 -35
  39. package/dist/graph/graph.d.ts +56 -8
  40. package/dist/graph/graph.js +331 -49
  41. package/dist/graph/index.d.ts +4 -2
  42. package/dist/graph/index.js +3 -1
  43. package/dist/graph/lint.d.ts +57 -0
  44. package/dist/graph/lint.js +141 -0
  45. package/dist/graph/run-control.d.ts +28 -0
  46. package/dist/graph/run-control.js +26 -0
  47. package/dist/images/evals.js +4 -2
  48. package/dist/operations/adapters.d.ts +52 -4
  49. package/dist/operations/adapters.js +194 -7
  50. package/dist/operations/runner.js +14 -15
  51. package/dist/operations/stats.js +8 -1
  52. package/dist/operations/store.d.ts +5 -1
  53. package/dist/operations/store.js +7 -0
  54. package/dist/ops/circuit-breaker.d.ts +52 -0
  55. package/dist/ops/circuit-breaker.js +4 -0
  56. package/dist/ops/circuit-store.d.ts +13 -2
  57. package/dist/ops/circuit-store.js +68 -0
  58. package/dist/ops/circuit-sync.d.ts +17 -0
  59. package/dist/ops/circuit-sync.js +86 -0
  60. package/dist/ops/health.d.ts +24 -0
  61. package/dist/ops/health.js +38 -10
  62. package/dist/ops/index.d.ts +1 -1
  63. package/dist/ops/index.js +1 -1
  64. package/dist/ops/rate-limit-adapters.d.ts +23 -0
  65. package/dist/ops/rate-limit-adapters.js +34 -0
  66. package/dist/ops/rate-limiter.d.ts +14 -2
  67. package/dist/ops/rate-limiter.js +31 -0
  68. package/dist/postgres/circuits.d.ts +21 -4
  69. package/dist/postgres/circuits.js +65 -4
  70. package/dist/postgres/client.d.ts +0 -2
  71. package/dist/postgres/client.js +0 -4
  72. package/dist/postgres/evaluate.d.ts +16 -4
  73. package/dist/postgres/evaluate.js +17 -5
  74. package/dist/postgres/index.d.ts +32 -11
  75. package/dist/postgres/index.js +65 -31
  76. package/dist/postgres/migrations.d.ts +60 -0
  77. package/dist/postgres/migrations.js +121 -0
  78. package/dist/postgres/operations.d.ts +14 -3
  79. package/dist/postgres/operations.js +45 -15
  80. package/dist/postgres/prompts.d.ts +11 -2
  81. package/dist/postgres/prompts.js +14 -3
  82. package/dist/postgres/rollups.d.ts +35 -0
  83. package/dist/postgres/rollups.js +129 -0
  84. package/dist/postgres/store.d.ts +11 -2
  85. package/dist/postgres/store.js +14 -3
  86. package/dist/postgres/traces.d.ts +13 -3
  87. package/dist/postgres/traces.js +25 -3
  88. package/dist/postgres/vectors.d.ts +11 -2
  89. package/dist/postgres/vectors.js +14 -3
  90. package/dist/router/auto-router.d.ts +34 -7
  91. package/dist/router/auto-router.js +201 -68
  92. package/dist/server/assistant.d.ts +44 -0
  93. package/dist/server/assistant.js +39 -0
  94. package/dist/server/errors.d.ts +12 -0
  95. package/dist/server/errors.js +7 -0
  96. package/dist/server/index.d.ts +1 -1
  97. package/dist/server/index.js +1 -1
  98. package/dist/server/runs.d.ts +28 -1
  99. package/dist/server/runs.js +110 -14
  100. package/dist/sqlite/index.d.ts +16 -3
  101. package/dist/sqlite/index.js +16 -3
  102. package/dist/sqlite/migrations.d.ts +26 -0
  103. package/dist/sqlite/migrations.js +63 -0
  104. package/dist/sqlite/operations.d.ts +14 -3
  105. package/dist/sqlite/operations.js +42 -15
  106. package/dist/sqlite/store.d.ts +9 -2
  107. package/dist/sqlite/store.js +13 -3
  108. package/dist/sqlite/vectors.d.ts +11 -2
  109. package/dist/sqlite/vectors.js +13 -2
  110. package/dist/store/tenant.d.ts +12 -0
  111. package/dist/store/tenant.js +29 -0
  112. package/dist/tenancy/index.d.ts +113 -0
  113. package/dist/tenancy/index.js +233 -0
  114. package/dist/testing/record.d.ts +42 -0
  115. package/dist/testing/record.js +57 -5
  116. package/dist/tracing/index.d.ts +3 -3
  117. package/dist/tracing/index.js +2 -2
  118. package/dist/tracing/instrument.js +30 -0
  119. package/dist/tracing/otlp.d.ts +91 -0
  120. package/dist/tracing/otlp.js +124 -0
  121. package/dist/tracing/rollups.d.ts +100 -0
  122. package/dist/tracing/rollups.js +139 -0
  123. package/dist/tracing/stores.d.ts +17 -0
  124. package/dist/tracing/stores.js +23 -0
  125. package/dist/tracing/tracer.d.ts +50 -4
  126. package/dist/tracing/tracer.js +85 -6
  127. package/dist/types/config.d.ts +33 -2
  128. package/dist/types/evaluate.d.ts +37 -0
  129. package/dist/types/graph.d.ts +354 -9
  130. package/dist/types/graph.js +3 -1
  131. package/dist/types/messages.d.ts +5 -0
  132. package/dist/types/operations.d.ts +22 -2
  133. package/dist/types/response.d.ts +20 -0
  134. package/dist/types/server.d.ts +18 -0
  135. package/dist/types/tracing.d.ts +11 -0
  136. package/dist/utils/schema-migrations.d.ts +97 -0
  137. package/dist/utils/schema-migrations.js +91 -0
  138. package/dist/utils/signals.d.ts +17 -0
  139. package/dist/utils/signals.js +26 -0
  140. package/dist/utils/tenant.d.ts +14 -0
  141. package/dist/utils/tenant.js +16 -0
  142. package/dist/version.d.ts +5 -0
  143. package/dist/version.js +1 -0
  144. package/dist-cjs/agent/create-agent.d.ts +9 -1
  145. package/dist-cjs/agent/create-agent.js +40 -1
  146. package/dist-cjs/cache/memory-cache.d.ts +8 -0
  147. package/dist-cjs/cache/memory-cache.js +9 -0
  148. package/dist-cjs/cache/semantic-cache.d.ts +6 -3
  149. package/dist-cjs/cache/semantic-cache.js +5 -2
  150. package/dist-cjs/cli/args.js +3 -0
  151. package/dist-cjs/cli/db.d.ts +16 -4
  152. package/dist-cjs/cli/db.js +200 -20
  153. package/dist-cjs/cli/doctor.d.ts +17 -0
  154. package/dist-cjs/cli/doctor.js +56 -0
  155. package/dist-cjs/cli/graph.d.ts +9 -0
  156. package/dist-cjs/cli/graph.js +50 -0
  157. package/dist-cjs/core/lifecycle.js +11 -6
  158. package/dist-cjs/core/nexus.d.ts +12 -2
  159. package/dist-cjs/core/nexus.js +106 -23
  160. package/dist-cjs/doctor/index.d.ts +90 -0
  161. package/dist-cjs/doctor/index.js +276 -0
  162. package/dist-cjs/evals/judge.d.ts +11 -0
  163. package/dist-cjs/evals/judge.js +33 -0
  164. package/dist-cjs/evaluate/index.d.ts +1 -0
  165. package/dist-cjs/evaluate/index.js +3 -1
  166. package/dist-cjs/evaluate/provenance.d.ts +22 -0
  167. package/dist-cjs/evaluate/provenance.js +14 -0
  168. package/dist-cjs/evaluate/run.js +20 -4
  169. package/dist-cjs/graph/durability.d.ts +27 -0
  170. package/dist-cjs/graph/durability.js +70 -0
  171. package/dist-cjs/graph/errors.d.ts +30 -4
  172. package/dist-cjs/graph/errors.js +20 -3
  173. package/dist-cjs/graph/event-stream.d.ts +75 -0
  174. package/dist-cjs/graph/event-stream.js +295 -0
  175. package/dist-cjs/graph/functional.d.ts +80 -7
  176. package/dist-cjs/graph/functional.js +137 -34
  177. package/dist-cjs/graph/graph.d.ts +56 -8
  178. package/dist-cjs/graph/graph.js +330 -48
  179. package/dist-cjs/graph/index.d.ts +4 -2
  180. package/dist-cjs/graph/index.js +7 -1
  181. package/dist-cjs/graph/lint.d.ts +57 -0
  182. package/dist-cjs/graph/lint.js +144 -0
  183. package/dist-cjs/graph/run-control.d.ts +28 -0
  184. package/dist-cjs/graph/run-control.js +30 -0
  185. package/dist-cjs/images/evals.js +4 -2
  186. package/dist-cjs/operations/adapters.d.ts +52 -4
  187. package/dist-cjs/operations/adapters.js +193 -6
  188. package/dist-cjs/operations/runner.js +14 -15
  189. package/dist-cjs/operations/stats.js +8 -1
  190. package/dist-cjs/operations/store.d.ts +5 -1
  191. package/dist-cjs/operations/store.js +7 -0
  192. package/dist-cjs/ops/circuit-breaker.d.ts +52 -0
  193. package/dist-cjs/ops/circuit-breaker.js +4 -0
  194. package/dist-cjs/ops/circuit-store.d.ts +13 -2
  195. package/dist-cjs/ops/circuit-store.js +68 -0
  196. package/dist-cjs/ops/circuit-sync.d.ts +17 -0
  197. package/dist-cjs/ops/circuit-sync.js +87 -0
  198. package/dist-cjs/ops/health.d.ts +24 -0
  199. package/dist-cjs/ops/health.js +38 -10
  200. package/dist-cjs/ops/index.d.ts +1 -1
  201. package/dist-cjs/ops/rate-limit-adapters.d.ts +23 -0
  202. package/dist-cjs/ops/rate-limit-adapters.js +35 -1
  203. package/dist-cjs/ops/rate-limiter.d.ts +14 -2
  204. package/dist-cjs/ops/rate-limiter.js +32 -0
  205. package/dist-cjs/postgres/circuits.d.ts +21 -4
  206. package/dist-cjs/postgres/circuits.js +98 -3
  207. package/dist-cjs/postgres/client.d.ts +0 -2
  208. package/dist-cjs/postgres/client.js +0 -5
  209. package/dist-cjs/postgres/evaluate.d.ts +16 -4
  210. package/dist-cjs/postgres/evaluate.js +50 -4
  211. package/dist-cjs/postgres/index.d.ts +32 -11
  212. package/dist-cjs/postgres/index.js +69 -20
  213. package/dist-cjs/postgres/migrations.d.ts +60 -0
  214. package/dist-cjs/postgres/migrations.js +129 -0
  215. package/dist-cjs/postgres/operations.d.ts +14 -3
  216. package/dist-cjs/postgres/operations.js +78 -14
  217. package/dist-cjs/postgres/prompts.d.ts +11 -2
  218. package/dist-cjs/postgres/prompts.js +47 -2
  219. package/dist-cjs/postgres/rollups.d.ts +35 -0
  220. package/dist-cjs/postgres/rollups.js +168 -0
  221. package/dist-cjs/postgres/store.d.ts +11 -2
  222. package/dist-cjs/postgres/store.js +47 -2
  223. package/dist-cjs/postgres/traces.d.ts +13 -3
  224. package/dist-cjs/postgres/traces.js +58 -2
  225. package/dist-cjs/postgres/vectors.d.ts +11 -2
  226. package/dist-cjs/postgres/vectors.js +47 -2
  227. package/dist-cjs/router/auto-router.d.ts +34 -7
  228. package/dist-cjs/router/auto-router.js +201 -68
  229. package/dist-cjs/server/assistant.d.ts +44 -0
  230. package/dist-cjs/server/assistant.js +39 -0
  231. package/dist-cjs/server/errors.d.ts +12 -0
  232. package/dist-cjs/server/errors.js +9 -1
  233. package/dist-cjs/server/index.d.ts +1 -1
  234. package/dist-cjs/server/index.js +2 -1
  235. package/dist-cjs/server/runs.d.ts +28 -1
  236. package/dist-cjs/server/runs.js +109 -13
  237. package/dist-cjs/sqlite/index.d.ts +16 -3
  238. package/dist-cjs/sqlite/index.js +31 -10
  239. package/dist-cjs/sqlite/migrations.d.ts +26 -0
  240. package/dist-cjs/sqlite/migrations.js +71 -0
  241. package/dist-cjs/sqlite/operations.d.ts +14 -3
  242. package/dist-cjs/sqlite/operations.js +76 -15
  243. package/dist-cjs/sqlite/store.d.ts +9 -2
  244. package/dist-cjs/sqlite/store.js +47 -3
  245. package/dist-cjs/sqlite/vectors.d.ts +11 -2
  246. package/dist-cjs/sqlite/vectors.js +47 -2
  247. package/dist-cjs/store/tenant.d.ts +12 -0
  248. package/dist-cjs/store/tenant.js +33 -0
  249. package/dist-cjs/tenancy/index.d.ts +113 -0
  250. package/dist-cjs/tenancy/index.js +250 -0
  251. package/dist-cjs/testing/record.d.ts +42 -0
  252. package/dist-cjs/testing/record.js +57 -5
  253. package/dist-cjs/tracing/index.d.ts +3 -3
  254. package/dist-cjs/tracing/index.js +4 -1
  255. package/dist-cjs/tracing/instrument.js +30 -0
  256. package/dist-cjs/tracing/otlp.d.ts +91 -0
  257. package/dist-cjs/tracing/otlp.js +129 -0
  258. package/dist-cjs/tracing/rollups.d.ts +100 -0
  259. package/dist-cjs/tracing/rollups.js +147 -0
  260. package/dist-cjs/tracing/stores.d.ts +17 -0
  261. package/dist-cjs/tracing/stores.js +24 -0
  262. package/dist-cjs/tracing/tracer.d.ts +50 -4
  263. package/dist-cjs/tracing/tracer.js +87 -6
  264. package/dist-cjs/types/config.d.ts +33 -2
  265. package/dist-cjs/types/evaluate.d.ts +37 -0
  266. package/dist-cjs/types/graph.d.ts +354 -9
  267. package/dist-cjs/types/graph.js +3 -1
  268. package/dist-cjs/types/messages.d.ts +5 -0
  269. package/dist-cjs/types/operations.d.ts +22 -2
  270. package/dist-cjs/types/response.d.ts +20 -0
  271. package/dist-cjs/types/server.d.ts +18 -0
  272. package/dist-cjs/types/tracing.d.ts +11 -0
  273. package/dist-cjs/utils/schema-migrations.d.ts +97 -0
  274. package/dist-cjs/utils/schema-migrations.js +102 -0
  275. package/dist-cjs/utils/signals.d.ts +17 -0
  276. package/dist-cjs/utils/signals.js +29 -0
  277. package/dist-cjs/utils/tenant.d.ts +14 -0
  278. package/dist-cjs/utils/tenant.js +22 -0
  279. package/dist-cjs/version.d.ts +5 -0
  280. package/dist-cjs/version.js +4 -0
  281. package/llms.txt +4 -3
  282. package/package.json +110 -2
@@ -5,18 +5,28 @@ exports.workflow = workflow;
5
5
  const checkpointer_js_1 = require("./checkpointer.js");
6
6
  const run_js_1 = require("../lifecycle/run.js");
7
7
  const checkpoint_migration_js_1 = require("./checkpoint-migration.js");
8
+ const tenant_js_1 = require("../store/tenant.js");
8
9
  const errors_js_1 = require("./errors.js");
9
10
  class WorkflowStepTimeoutError extends errors_js_1.GraphError {
10
11
  stepName;
11
12
  timeoutMs;
12
- constructor(stepName, timeoutMs) {
13
- super(`Step "${stepName}" exceeded its ${timeoutMs} ms timeout`, 'WORKFLOW_STEP_TIMEOUT');
13
+ kind;
14
+ constructor(stepName, timeoutMs, kind = 'run') {
15
+ super(kind === 'idle'
16
+ ? `Step "${stepName}" made no progress for ${timeoutMs} ms`
17
+ : `Step "${stepName}" exceeded its ${timeoutMs} ms timeout`, 'WORKFLOW_STEP_TIMEOUT');
14
18
  this.stepName = stepName;
15
19
  this.timeoutMs = timeoutMs;
20
+ this.kind = kind;
16
21
  this.name = 'WorkflowStepTimeoutError';
17
22
  }
18
23
  }
19
24
  exports.WorkflowStepTimeoutError = WorkflowStepTimeoutError;
25
+ class WorkflowDraining extends Error {
26
+ constructor() {
27
+ super('The workflow is draining');
28
+ }
29
+ }
20
30
  class WorkflowSuspended extends Error {
21
31
  pending;
22
32
  constructor(pending) {
@@ -45,10 +55,16 @@ class Workflow {
45
55
  }
46
56
  stream(input, runOptions = {}) {
47
57
  const threadId = runOptions.threadId ?? generatedId();
48
- return this.execute(threadId, runOptions, async () => ({
49
- ...this.fresh(threadId, input),
50
- step: (await this.latest(threadId))?.step ?? 0,
51
- }));
58
+ return this.execute(threadId, runOptions, async () => {
59
+ const latest = await this.latest(threadId);
60
+ if (latest && runOptions.tenantId !== undefined) {
61
+ const owner = latest.metadata?.tenantId;
62
+ if (typeof owner === 'string' && owner !== runOptions.tenantId) {
63
+ throw new errors_js_1.GraphError(`Thread "${threadId}" cannot be used by this tenant; choose another id`, 'GRAPH_VALIDATION_ERROR');
64
+ }
65
+ }
66
+ return { ...this.fresh(threadId, input), step: latest?.step ?? 0 };
67
+ });
52
68
  }
53
69
  resume(threadId, value, runOptions = {}) {
54
70
  return this.execute(threadId, runOptions, async () => {
@@ -142,11 +158,21 @@ class Workflow {
142
158
  }
143
159
  async run(threadId, runOptions, start, queue) {
144
160
  const initial = await start();
161
+ const owner = typeof initial.metadata?.tenantId === 'string' ? initial.metadata.tenantId : undefined;
162
+ if (runOptions.tenantId !== undefined && owner !== undefined && owner !== runOptions.tenantId) {
163
+ throw new errors_js_1.GraphThreadNotFoundError(threadId);
164
+ }
165
+ const tenantId = runOptions.tenantId ?? owner;
145
166
  const checkpointer = this.checkpointer();
146
167
  const state = structuredClone(initial.state);
147
168
  state.steps ??= {};
148
169
  const resolved = { ...initial.resolved };
149
- const metadata = { ...initial.metadata, graph: this.name, ...runOptions.metadata };
170
+ const metadata = {
171
+ ...initial.metadata,
172
+ graph: this.name,
173
+ ...runOptions.metadata,
174
+ ...(tenantId === undefined ? {} : { tenantId }),
175
+ };
150
176
  let stepNumber = initial.step;
151
177
  let writes = Promise.resolve();
152
178
  const persist = (checkpoint) => {
@@ -176,11 +202,16 @@ class Workflow {
176
202
  const inFlight = new Set();
177
203
  const suspended = [];
178
204
  let interruptIndex = 0;
205
+ let drained = false;
179
206
  const limiter = new Limiter(this.options.maxConcurrency ?? 16);
207
+ const defaults = this.options.stepDefaults ?? {};
180
208
  const context = {
181
209
  threadId,
210
+ ...(tenantId === undefined ? {} : { tenantId }),
182
211
  signal: controller.signal,
183
- ...(this.options.store ? { store: this.options.store } : {}),
212
+ ...(this.options.store
213
+ ? { store: tenantId === undefined ? this.options.store : (0, tenant_js_1.tenantStore)(this.options.store, tenantId) }
214
+ : {}),
184
215
  step: (name, run, options = {}) => {
185
216
  const count = (counts.get(name) ?? 0) + 1;
186
217
  counts.set(name, count);
@@ -190,10 +221,22 @@ class Workflow {
190
221
  queue.push({ type: 'step', step: stepNumber, name, key, cached: true, state: snapshot(), status: 'running' });
191
222
  return Promise.resolve(recorded.value);
192
223
  }
224
+ if (runOptions.control?.draining) {
225
+ drained = true;
226
+ return Promise.reject(new WorkflowDraining());
227
+ }
228
+ const merged = {
229
+ ...defaults,
230
+ ...options,
231
+ timeout: { ...defaults.timeout, ...options.timeout },
232
+ };
193
233
  const work = limiter
194
- .run(() => this.runStep(name, key, run, { ...this.options.retry, ...options.retry }, options, controller.signal, runOptions, stepNumber))
195
- .then(async (value) => {
196
- state.steps[key] = value === undefined ? {} : { value: structuredClone(value) };
234
+ .run(() => this.runStep(name, key, run, { ...this.options.retry, ...defaults.retry, ...options.retry }, merged, controller.signal, runOptions, stepNumber))
235
+ .then(async ({ value, recovered }) => {
236
+ state.steps[key] = {
237
+ ...(value === undefined ? {} : { value: structuredClone(value) }),
238
+ ...(recovered ? { recovered } : {}),
239
+ };
197
240
  await persist({ state: state, next: [this.name], status: 'running' });
198
241
  queue.push({
199
242
  type: 'step',
@@ -267,6 +310,18 @@ class Workflow {
267
310
  queue.push({ type: 'interrupt', step: stepNumber, state: snapshot(), status: 'interrupted' });
268
311
  return;
269
312
  }
313
+ if (drained && outcome.kind === 'failed') {
314
+ const reason = runOptions.control?.reason;
315
+ await persist({
316
+ state: state,
317
+ next: [this.name],
318
+ status: 'interrupted',
319
+ resolved,
320
+ drained: { ...(reason ? { reason } : {}), at: this.now().toISOString() },
321
+ });
322
+ await writes;
323
+ throw new errors_js_1.GraphDrainedError(threadId, stepNumber, reason);
324
+ }
270
325
  if (outcome.kind === 'failed') {
271
326
  const error = outcome.error;
272
327
  await persist({
@@ -289,41 +344,87 @@ class Workflow {
289
344
  }
290
345
  async runStep(name, key, run, retry, options, signal, runOptions, step) {
291
346
  const policy = { ...DEFAULT_RETRY, ...retry };
347
+ const runMs = options.timeoutMs ?? options.timeout?.runMs;
348
+ const idleMs = options.timeout?.idleMs;
292
349
  for (let attempt = 1;; attempt += 1) {
293
350
  notify(runOptions, { type: 'task_start', step, taskId: key, node: name, attempt });
294
351
  const stepController = new AbortController();
295
352
  const forward = () => stepController.abort(signal.reason);
296
353
  signal.addEventListener('abort', forward, { once: true });
297
- let timer;
298
- let timedOut = false;
354
+ let runTimer;
355
+ let idleTimer;
356
+ let timedOut;
357
+ let expire = () => undefined;
358
+ const limits = runMs === undefined && idleMs === undefined
359
+ ? undefined
360
+ : new Promise((_, reject) => {
361
+ expire = (error) => {
362
+ if (timedOut)
363
+ return;
364
+ timedOut = error;
365
+ reject(error);
366
+ stepController.abort();
367
+ };
368
+ });
369
+ limits?.catch(() => undefined);
370
+ if (runMs !== undefined)
371
+ runTimer = setTimeout(() => expire(new WorkflowStepTimeoutError(name, runMs)), runMs);
372
+ const armIdle = () => {
373
+ if (idleMs === undefined || timedOut)
374
+ return;
375
+ if (idleTimer)
376
+ clearTimeout(idleTimer);
377
+ idleTimer = setTimeout(() => expire(new WorkflowStepTimeoutError(name, idleMs, 'idle')), idleMs);
378
+ };
379
+ armIdle();
299
380
  try {
300
- const work = Promise.resolve(run({ name, key, attempt, signal: stepController.signal }));
301
- const value = options.timeoutMs === undefined
302
- ? await work
303
- : await Promise.race([
304
- work,
305
- new Promise((_, reject) => {
306
- timer = setTimeout(() => {
307
- timedOut = true;
308
- reject(new WorkflowStepTimeoutError(name, options.timeoutMs));
309
- stepController.abort();
310
- }, options.timeoutMs);
311
- }),
312
- ]);
381
+ const work = Promise.resolve(run({ name, key, attempt, signal: stepController.signal, heartbeat: armIdle }));
382
+ const value = limits ? await Promise.race([work, limits]) : await work;
313
383
  if (timedOut)
314
- throw new WorkflowStepTimeoutError(name, options.timeoutMs);
384
+ throw timedOut;
315
385
  notify(runOptions, { type: 'task_end', step, taskId: key, node: name, update: value });
316
- return value;
386
+ return { value };
317
387
  }
318
388
  catch (error) {
319
389
  if (signal.aborted || error instanceof WorkflowSuspended)
320
390
  throw error;
321
- const failure = timedOut ? new WorkflowStepTimeoutError(name, options.timeoutMs) : error;
391
+ const failure = timedOut ?? error;
322
392
  const retryable = policy.retryOn
323
393
  ? policy.retryOn(failure, attempt)
324
- : !(failure instanceof errors_js_1.GraphError) || timedOut;
325
- if (attempt >= Math.max(1, policy.maxAttempts) || !retryable)
326
- throw failure;
394
+ : !(failure instanceof errors_js_1.GraphError) || timedOut !== undefined;
395
+ if (attempt >= Math.max(1, policy.maxAttempts) || !retryable) {
396
+ if (!options.onError)
397
+ throw failure;
398
+ const failed = (recovered) => notify(runOptions, {
399
+ type: 'task_failed',
400
+ step,
401
+ taskId: key,
402
+ node: name,
403
+ attempts: attempt,
404
+ error: failure instanceof Error ? failure.message : String(failure),
405
+ recovered,
406
+ });
407
+ let value;
408
+ try {
409
+ value = await options.onError({ name, key, attempts: attempt, error: failure });
410
+ }
411
+ catch (decision) {
412
+ failed(false);
413
+ throw decision;
414
+ }
415
+ failed(true);
416
+ notify(runOptions, { type: 'task_end', step, taskId: key, node: name, update: value });
417
+ return {
418
+ value,
419
+ recovered: {
420
+ error: {
421
+ name: failure instanceof Error ? failure.name : 'Error',
422
+ message: failure instanceof Error ? failure.message : String(failure),
423
+ },
424
+ attempts: attempt,
425
+ },
426
+ };
427
+ }
327
428
  notify(runOptions, {
328
429
  type: 'task_retry',
329
430
  step,
@@ -335,8 +436,10 @@ class Workflow {
335
436
  await sleep(backoff(policy, attempt), signal);
336
437
  }
337
438
  finally {
338
- if (timer)
339
- clearTimeout(timer);
439
+ if (runTimer)
440
+ clearTimeout(runTimer);
441
+ if (idleTimer)
442
+ clearTimeout(idleTimer);
340
443
  signal.removeEventListener('abort', forward);
341
444
  }
342
445
  }
@@ -1,7 +1,8 @@
1
- import type { ChannelSchema, CompileOptions, EdgeRouter, GraphCheckpoint, GraphDescription, GraphInput, GraphProgress, GraphResult, GraphRunOptions, GraphStatus, GraphStepEvent, NodeFn, NodeOptions, StateUpdate } from '../types/graph.js';
1
+ import type { ChannelSchema, CompileOptions, EdgeRouter, GraphCheckpoint, GraphDescription, GraphEventsOptions, GraphInput, GraphProgress, GraphResult, GraphRunOptions, GraphStatus, GraphStepEvent, NodeFn, NodeOptions, StateUpdate } from '../types/graph.js';
2
+ import { GraphEventStream } from './event-stream.js';
2
3
  interface GraphNodeDefinition<S extends ChannelSchema> {
3
4
  fn: NodeFn<S>;
4
- options: NodeOptions;
5
+ options: NodeOptions<S>;
5
6
  }
6
7
  /** Which channels a caller may write and read, as `createGraph()` declared them. */
7
8
  interface GraphScope {
@@ -29,7 +30,7 @@ export declare class StateGraph<S extends ChannelSchema, I extends keyof S = key
29
30
  private readonly edges;
30
31
  constructor(channels: S, scope?: GraphScope);
31
32
  /** Adds a node. Returns the graph, for chaining. */
32
- addNode(name: string, fn: NodeFn<S>, options?: NodeOptions): this;
33
+ addNode(name: string, fn: NodeFn<S>, options?: NodeOptions<S>): this;
33
34
  /** Adds an edge that always runs `to` after `from`. Returns the graph, for chaining. */
34
35
  addEdge(from: string, to: string): this;
35
36
  /**
@@ -55,11 +56,33 @@ export declare class CompiledGraph<S extends ChannelSchema, I extends keyof S =
55
56
  private readonly store;
56
57
  /** Loaded the first time a node that declares `cache` runs, and not before. */
57
58
  private nodeCache;
59
+ /** The checkpoint writers of runs in progress, so `flush()` can wait for them. */
60
+ private readonly writers;
58
61
  constructor(channels: S, nodes: Map<string, GraphNodeDefinition<S>>, edges: Array<Edge<S>>, options: CompileOptions, scope?: GraphScope);
62
+ /**
63
+ * Waits until every checkpoint written by runs in progress is in the store. Only `async` and
64
+ * `exit` durability leave any outstanding; a run always waits for its own before it returns.
65
+ */
66
+ flush(): Promise<void>;
59
67
  /** Runs to completion, to an interrupt, or to the step limit. */
60
68
  invoke(input?: GraphInput<S, I>, runOptions?: GraphRunOptions): Promise<GraphResult<S, O>>;
61
69
  /** Yields one event per superstep, so a caller can render progress as it happens. */
62
70
  stream(input?: GraphInput<S, I>, runOptions?: GraphRunOptions): AsyncIterable<GraphStepEvent<S>>;
71
+ /**
72
+ * Runs the graph as one stream of typed events: the state after each superstep, each task's write,
73
+ * model output as nodes stream it, tool calls, task progress, checkpoints, and custom events.
74
+ *
75
+ * Iterate it for everything included, or read one projection with `messages()`, `tools()`,
76
+ * `values()`, or `updates()`. Each reader has its own bounded buffer, and the run waits for the
77
+ * slowest at the end of every superstep, so a slow reader slows the graph rather than filling
78
+ * memory. `result` resolves with the run's result.
79
+ */
80
+ events(input?: GraphInput<S, I>, options?: GraphEventsOptions): GraphEventStream<S, O>;
81
+ /** Like `events()`, answering the question a paused thread is waiting on. */
82
+ resumeEvents(threadId: string, value: unknown, options?: GraphEventsOptions): GraphEventStream<S, O>;
83
+ /** Like `events()`, carrying a thread on from a breakpoint, a drain, or a failure. */
84
+ continueEvents(threadId: string, options?: GraphEventsOptions): GraphEventStream<S, O>;
85
+ private eventStream;
63
86
  /**
64
87
  * Supplies the value a node asked for and continues.
65
88
  *
@@ -88,10 +111,17 @@ export declare class CompiledGraph<S extends ChannelSchema, I extends keyof S =
88
111
  * once the rewound checkpoint is written.
89
112
  */
90
113
  resumeFrom(threadId: string, step: number, runOptions?: GraphRunOptions): AsyncIterable<GraphStepEvent<S>>;
91
- /** Latest checkpoint, or the one at `step`. */
92
- state(threadId: string, step?: number): Promise<GraphCheckpoint<S> | undefined>;
93
- /** Checkpoints for a thread, newest first. */
94
- history(threadId: string, limit?: number): Promise<Array<GraphCheckpoint<S>>>;
114
+ /**
115
+ * Latest checkpoint, or the one at `step`. With a `tenantId`, a thread another tenant owns reads
116
+ * as absent.
117
+ */
118
+ state(threadId: string, step?: number, options?: {
119
+ tenantId?: string;
120
+ }): Promise<GraphCheckpoint<S> | undefined>;
121
+ /** Checkpoints for a thread, newest first. With a `tenantId`, another tenant's thread has none. */
122
+ history(threadId: string, limit?: number, options?: {
123
+ tenantId?: string;
124
+ }): Promise<Array<GraphCheckpoint<S>>>;
95
125
  /**
96
126
  * Wraps this graph as a node in another graph.
97
127
  *
@@ -120,26 +150,44 @@ export declare class CompiledGraph<S extends ChannelSchema, I extends keyof S =
120
150
  */
121
151
  updateState(threadId: string, update: StateUpdate<S>, options?: {
122
152
  asNode?: string;
153
+ tenantId?: string;
123
154
  }): Promise<GraphCheckpoint<S>>;
124
155
  /**
125
156
  * Copies a thread's history up to `step` into a new thread, and returns the new thread's id.
126
157
  *
127
158
  * Rewinding with `resumeFrom()` replaces the original timeline. A fork keeps it: both threads stay
128
159
  * readable and runnable, so two answers to the same question can be compared side by side. Every
129
- * copied checkpoint records `metadata.forkedFrom`.
160
+ * copied checkpoint records `metadata.forkedFrom`, and keeps the tenant of the thread it came from.
161
+ * With a `tenantId`, another tenant's thread is not found.
130
162
  */
131
163
  fork(threadId: string, options?: {
132
164
  step?: number;
133
165
  threadId?: string;
166
+ tenantId?: string;
134
167
  }): Promise<string>;
135
168
  /**
136
169
  * Runs the supersteps, as one operation of the compiled lifecycle when there is one. The run is
137
170
  * admitted before its first superstep and finishes with its last, however it ends.
138
171
  */
139
172
  private run;
173
+ /**
174
+ * Runs the step loop with a checkpoint writer for the run's durability mode. However the run ends,
175
+ * every checkpoint it handed over is in the store before this returns or throws.
176
+ */
140
177
  private runSteps;
178
+ private steps;
141
179
  /** Runs one task to a verdict, applying its retry policy and timeout. */
142
180
  private runTask;
181
+ /**
182
+ * Hands a failure to the node's `onError`, and turns what it decides into the task's result. With
183
+ * no handler, or for a mistake in the graph itself, the task fails as it always did.
184
+ */
185
+ private recover;
186
+ /** The node's retry policy over the graph's defaults. */
187
+ private retryPolicy;
188
+ /** The node's run and idle limits over the graph's defaults. `timeout.runMs` wins over `timeoutMs`. */
189
+ private timeoutOf;
190
+ private errorHandler;
143
191
  private runNode;
144
192
  private loadNodeCache;
145
193
  /** Rejects writes to channels the graph does not accept from a caller. */