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.
- package/API_STABILITY.md +65 -0
- package/CHANGELOG.md +267 -1
- package/MIGRATING.md +1 -1
- package/README.md +17 -8
- package/dist/agent/create-agent.d.ts +9 -1
- package/dist/agent/create-agent.js +40 -1
- package/dist/cache/memory-cache.d.ts +8 -0
- package/dist/cache/memory-cache.js +9 -0
- package/dist/cache/semantic-cache.d.ts +6 -3
- package/dist/cache/semantic-cache.js +5 -2
- package/dist/cli/args.js +3 -0
- package/dist/cli/db.d.ts +16 -4
- package/dist/cli/db.js +169 -22
- package/dist/cli/doctor.d.ts +17 -0
- package/dist/cli/doctor.js +53 -0
- package/dist/cli/graph.d.ts +9 -0
- package/dist/cli/graph.js +47 -0
- package/dist/cli.js +21 -2
- package/dist/core/lifecycle.js +11 -6
- package/dist/core/nexus.d.ts +12 -2
- package/dist/core/nexus.js +106 -23
- package/dist/doctor/index.d.ts +90 -0
- package/dist/doctor/index.js +237 -0
- package/dist/evals/judge.d.ts +11 -0
- package/dist/evals/judge.js +33 -0
- package/dist/evaluate/index.d.ts +1 -0
- package/dist/evaluate/index.js +1 -0
- package/dist/evaluate/provenance.d.ts +22 -0
- package/dist/evaluate/provenance.js +10 -0
- package/dist/evaluate/run.js +20 -4
- package/dist/graph/durability.d.ts +27 -0
- package/dist/graph/durability.js +66 -0
- package/dist/graph/errors.d.ts +30 -4
- package/dist/graph/errors.js +18 -2
- package/dist/graph/event-stream.d.ts +75 -0
- package/dist/graph/event-stream.js +289 -0
- package/dist/graph/functional.d.ts +80 -7
- package/dist/graph/functional.js +138 -35
- package/dist/graph/graph.d.ts +56 -8
- package/dist/graph/graph.js +331 -49
- package/dist/graph/index.d.ts +4 -2
- package/dist/graph/index.js +3 -1
- package/dist/graph/lint.d.ts +57 -0
- package/dist/graph/lint.js +141 -0
- package/dist/graph/run-control.d.ts +28 -0
- package/dist/graph/run-control.js +26 -0
- package/dist/images/evals.js +4 -2
- package/dist/operations/adapters.d.ts +52 -4
- package/dist/operations/adapters.js +194 -7
- package/dist/operations/runner.js +14 -15
- package/dist/operations/stats.js +8 -1
- package/dist/operations/store.d.ts +5 -1
- package/dist/operations/store.js +7 -0
- package/dist/ops/circuit-breaker.d.ts +52 -0
- package/dist/ops/circuit-breaker.js +4 -0
- package/dist/ops/circuit-store.d.ts +13 -2
- package/dist/ops/circuit-store.js +68 -0
- package/dist/ops/circuit-sync.d.ts +17 -0
- package/dist/ops/circuit-sync.js +86 -0
- package/dist/ops/health.d.ts +24 -0
- package/dist/ops/health.js +38 -10
- package/dist/ops/index.d.ts +1 -1
- package/dist/ops/index.js +1 -1
- package/dist/ops/rate-limit-adapters.d.ts +23 -0
- package/dist/ops/rate-limit-adapters.js +34 -0
- package/dist/ops/rate-limiter.d.ts +14 -2
- package/dist/ops/rate-limiter.js +31 -0
- package/dist/postgres/circuits.d.ts +21 -4
- package/dist/postgres/circuits.js +65 -4
- package/dist/postgres/client.d.ts +0 -2
- package/dist/postgres/client.js +0 -4
- package/dist/postgres/evaluate.d.ts +16 -4
- package/dist/postgres/evaluate.js +17 -5
- package/dist/postgres/index.d.ts +32 -11
- package/dist/postgres/index.js +65 -31
- package/dist/postgres/migrations.d.ts +60 -0
- package/dist/postgres/migrations.js +121 -0
- package/dist/postgres/operations.d.ts +14 -3
- package/dist/postgres/operations.js +45 -15
- package/dist/postgres/prompts.d.ts +11 -2
- package/dist/postgres/prompts.js +14 -3
- package/dist/postgres/rollups.d.ts +35 -0
- package/dist/postgres/rollups.js +129 -0
- package/dist/postgres/store.d.ts +11 -2
- package/dist/postgres/store.js +14 -3
- package/dist/postgres/traces.d.ts +13 -3
- package/dist/postgres/traces.js +25 -3
- package/dist/postgres/vectors.d.ts +11 -2
- package/dist/postgres/vectors.js +14 -3
- package/dist/router/auto-router.d.ts +34 -7
- package/dist/router/auto-router.js +201 -68
- package/dist/server/assistant.d.ts +44 -0
- package/dist/server/assistant.js +39 -0
- package/dist/server/errors.d.ts +12 -0
- package/dist/server/errors.js +7 -0
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/runs.d.ts +28 -1
- package/dist/server/runs.js +110 -14
- package/dist/sqlite/index.d.ts +16 -3
- package/dist/sqlite/index.js +16 -3
- package/dist/sqlite/migrations.d.ts +26 -0
- package/dist/sqlite/migrations.js +63 -0
- package/dist/sqlite/operations.d.ts +14 -3
- package/dist/sqlite/operations.js +42 -15
- package/dist/sqlite/store.d.ts +9 -2
- package/dist/sqlite/store.js +13 -3
- package/dist/sqlite/vectors.d.ts +11 -2
- package/dist/sqlite/vectors.js +13 -2
- package/dist/store/tenant.d.ts +12 -0
- package/dist/store/tenant.js +29 -0
- package/dist/tenancy/index.d.ts +113 -0
- package/dist/tenancy/index.js +233 -0
- package/dist/testing/record.d.ts +42 -0
- package/dist/testing/record.js +57 -5
- package/dist/tracing/index.d.ts +3 -3
- package/dist/tracing/index.js +2 -2
- package/dist/tracing/instrument.js +30 -0
- package/dist/tracing/otlp.d.ts +91 -0
- package/dist/tracing/otlp.js +124 -0
- package/dist/tracing/rollups.d.ts +100 -0
- package/dist/tracing/rollups.js +139 -0
- package/dist/tracing/stores.d.ts +17 -0
- package/dist/tracing/stores.js +23 -0
- package/dist/tracing/tracer.d.ts +50 -4
- package/dist/tracing/tracer.js +85 -6
- package/dist/types/config.d.ts +33 -2
- package/dist/types/evaluate.d.ts +37 -0
- package/dist/types/graph.d.ts +354 -9
- package/dist/types/graph.js +3 -1
- package/dist/types/messages.d.ts +5 -0
- package/dist/types/operations.d.ts +22 -2
- package/dist/types/response.d.ts +20 -0
- package/dist/types/server.d.ts +18 -0
- package/dist/types/tracing.d.ts +11 -0
- package/dist/utils/schema-migrations.d.ts +97 -0
- package/dist/utils/schema-migrations.js +91 -0
- package/dist/utils/signals.d.ts +17 -0
- package/dist/utils/signals.js +26 -0
- package/dist/utils/tenant.d.ts +14 -0
- package/dist/utils/tenant.js +16 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +1 -0
- package/dist-cjs/agent/create-agent.d.ts +9 -1
- package/dist-cjs/agent/create-agent.js +40 -1
- package/dist-cjs/cache/memory-cache.d.ts +8 -0
- package/dist-cjs/cache/memory-cache.js +9 -0
- package/dist-cjs/cache/semantic-cache.d.ts +6 -3
- package/dist-cjs/cache/semantic-cache.js +5 -2
- package/dist-cjs/cli/args.js +3 -0
- package/dist-cjs/cli/db.d.ts +16 -4
- package/dist-cjs/cli/db.js +200 -20
- package/dist-cjs/cli/doctor.d.ts +17 -0
- package/dist-cjs/cli/doctor.js +56 -0
- package/dist-cjs/cli/graph.d.ts +9 -0
- package/dist-cjs/cli/graph.js +50 -0
- package/dist-cjs/core/lifecycle.js +11 -6
- package/dist-cjs/core/nexus.d.ts +12 -2
- package/dist-cjs/core/nexus.js +106 -23
- package/dist-cjs/doctor/index.d.ts +90 -0
- package/dist-cjs/doctor/index.js +276 -0
- package/dist-cjs/evals/judge.d.ts +11 -0
- package/dist-cjs/evals/judge.js +33 -0
- package/dist-cjs/evaluate/index.d.ts +1 -0
- package/dist-cjs/evaluate/index.js +3 -1
- package/dist-cjs/evaluate/provenance.d.ts +22 -0
- package/dist-cjs/evaluate/provenance.js +14 -0
- package/dist-cjs/evaluate/run.js +20 -4
- package/dist-cjs/graph/durability.d.ts +27 -0
- package/dist-cjs/graph/durability.js +70 -0
- package/dist-cjs/graph/errors.d.ts +30 -4
- package/dist-cjs/graph/errors.js +20 -3
- package/dist-cjs/graph/event-stream.d.ts +75 -0
- package/dist-cjs/graph/event-stream.js +295 -0
- package/dist-cjs/graph/functional.d.ts +80 -7
- package/dist-cjs/graph/functional.js +137 -34
- package/dist-cjs/graph/graph.d.ts +56 -8
- package/dist-cjs/graph/graph.js +330 -48
- package/dist-cjs/graph/index.d.ts +4 -2
- package/dist-cjs/graph/index.js +7 -1
- package/dist-cjs/graph/lint.d.ts +57 -0
- package/dist-cjs/graph/lint.js +144 -0
- package/dist-cjs/graph/run-control.d.ts +28 -0
- package/dist-cjs/graph/run-control.js +30 -0
- package/dist-cjs/images/evals.js +4 -2
- package/dist-cjs/operations/adapters.d.ts +52 -4
- package/dist-cjs/operations/adapters.js +193 -6
- package/dist-cjs/operations/runner.js +14 -15
- package/dist-cjs/operations/stats.js +8 -1
- package/dist-cjs/operations/store.d.ts +5 -1
- package/dist-cjs/operations/store.js +7 -0
- package/dist-cjs/ops/circuit-breaker.d.ts +52 -0
- package/dist-cjs/ops/circuit-breaker.js +4 -0
- package/dist-cjs/ops/circuit-store.d.ts +13 -2
- package/dist-cjs/ops/circuit-store.js +68 -0
- package/dist-cjs/ops/circuit-sync.d.ts +17 -0
- package/dist-cjs/ops/circuit-sync.js +87 -0
- package/dist-cjs/ops/health.d.ts +24 -0
- package/dist-cjs/ops/health.js +38 -10
- package/dist-cjs/ops/index.d.ts +1 -1
- package/dist-cjs/ops/rate-limit-adapters.d.ts +23 -0
- package/dist-cjs/ops/rate-limit-adapters.js +35 -1
- package/dist-cjs/ops/rate-limiter.d.ts +14 -2
- package/dist-cjs/ops/rate-limiter.js +32 -0
- package/dist-cjs/postgres/circuits.d.ts +21 -4
- package/dist-cjs/postgres/circuits.js +98 -3
- package/dist-cjs/postgres/client.d.ts +0 -2
- package/dist-cjs/postgres/client.js +0 -5
- package/dist-cjs/postgres/evaluate.d.ts +16 -4
- package/dist-cjs/postgres/evaluate.js +50 -4
- package/dist-cjs/postgres/index.d.ts +32 -11
- package/dist-cjs/postgres/index.js +69 -20
- package/dist-cjs/postgres/migrations.d.ts +60 -0
- package/dist-cjs/postgres/migrations.js +129 -0
- package/dist-cjs/postgres/operations.d.ts +14 -3
- package/dist-cjs/postgres/operations.js +78 -14
- package/dist-cjs/postgres/prompts.d.ts +11 -2
- package/dist-cjs/postgres/prompts.js +47 -2
- package/dist-cjs/postgres/rollups.d.ts +35 -0
- package/dist-cjs/postgres/rollups.js +168 -0
- package/dist-cjs/postgres/store.d.ts +11 -2
- package/dist-cjs/postgres/store.js +47 -2
- package/dist-cjs/postgres/traces.d.ts +13 -3
- package/dist-cjs/postgres/traces.js +58 -2
- package/dist-cjs/postgres/vectors.d.ts +11 -2
- package/dist-cjs/postgres/vectors.js +47 -2
- package/dist-cjs/router/auto-router.d.ts +34 -7
- package/dist-cjs/router/auto-router.js +201 -68
- package/dist-cjs/server/assistant.d.ts +44 -0
- package/dist-cjs/server/assistant.js +39 -0
- package/dist-cjs/server/errors.d.ts +12 -0
- package/dist-cjs/server/errors.js +9 -1
- package/dist-cjs/server/index.d.ts +1 -1
- package/dist-cjs/server/index.js +2 -1
- package/dist-cjs/server/runs.d.ts +28 -1
- package/dist-cjs/server/runs.js +109 -13
- package/dist-cjs/sqlite/index.d.ts +16 -3
- package/dist-cjs/sqlite/index.js +31 -10
- package/dist-cjs/sqlite/migrations.d.ts +26 -0
- package/dist-cjs/sqlite/migrations.js +71 -0
- package/dist-cjs/sqlite/operations.d.ts +14 -3
- package/dist-cjs/sqlite/operations.js +76 -15
- package/dist-cjs/sqlite/store.d.ts +9 -2
- package/dist-cjs/sqlite/store.js +47 -3
- package/dist-cjs/sqlite/vectors.d.ts +11 -2
- package/dist-cjs/sqlite/vectors.js +47 -2
- package/dist-cjs/store/tenant.d.ts +12 -0
- package/dist-cjs/store/tenant.js +33 -0
- package/dist-cjs/tenancy/index.d.ts +113 -0
- package/dist-cjs/tenancy/index.js +250 -0
- package/dist-cjs/testing/record.d.ts +42 -0
- package/dist-cjs/testing/record.js +57 -5
- package/dist-cjs/tracing/index.d.ts +3 -3
- package/dist-cjs/tracing/index.js +4 -1
- package/dist-cjs/tracing/instrument.js +30 -0
- package/dist-cjs/tracing/otlp.d.ts +91 -0
- package/dist-cjs/tracing/otlp.js +129 -0
- package/dist-cjs/tracing/rollups.d.ts +100 -0
- package/dist-cjs/tracing/rollups.js +147 -0
- package/dist-cjs/tracing/stores.d.ts +17 -0
- package/dist-cjs/tracing/stores.js +24 -0
- package/dist-cjs/tracing/tracer.d.ts +50 -4
- package/dist-cjs/tracing/tracer.js +87 -6
- package/dist-cjs/types/config.d.ts +33 -2
- package/dist-cjs/types/evaluate.d.ts +37 -0
- package/dist-cjs/types/graph.d.ts +354 -9
- package/dist-cjs/types/graph.js +3 -1
- package/dist-cjs/types/messages.d.ts +5 -0
- package/dist-cjs/types/operations.d.ts +22 -2
- package/dist-cjs/types/response.d.ts +20 -0
- package/dist-cjs/types/server.d.ts +18 -0
- package/dist-cjs/types/tracing.d.ts +11 -0
- package/dist-cjs/utils/schema-migrations.d.ts +97 -0
- package/dist-cjs/utils/schema-migrations.js +102 -0
- package/dist-cjs/utils/signals.d.ts +17 -0
- package/dist-cjs/utils/signals.js +29 -0
- package/dist-cjs/utils/tenant.d.ts +14 -0
- package/dist-cjs/utils/tenant.js +22 -0
- package/dist-cjs/version.d.ts +5 -0
- package/dist-cjs/version.js +4 -0
- package/llms.txt +4 -3
- package/package.json +110 -2
package/dist/graph/graph.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import { Command, END, Send, START } from '../types/graph.js';
|
|
3
|
+
import { tenantStore } from '../store/tenant.js';
|
|
4
|
+
import { linkSignals } from '../utils/signals.js';
|
|
3
5
|
import { MemoryGraphCheckpointer } from './checkpointer.js';
|
|
4
6
|
import { migrateCheckpoint, toCheckpoint } from './checkpoint-migration.js';
|
|
5
|
-
import {
|
|
7
|
+
import { CheckpointWriter } from './durability.js';
|
|
8
|
+
import { GraphEventStream, streamSettings } from './event-stream.js';
|
|
9
|
+
import { GraphDrainedError, GraphInterrupt, GraphNodeError, GraphNodeTimeoutError, GraphNotInterruptedError, GraphStepLimitError, GraphThreadNotFoundError, GraphValidationError, interruptKey, } from './errors.js';
|
|
6
10
|
const DEFAULT_MAX_STEPS = 25;
|
|
7
11
|
const DEFAULT_MAX_CONCURRENCY = 16;
|
|
8
12
|
const DEFAULT_RETRY = {
|
|
@@ -13,6 +17,7 @@ const DEFAULT_RETRY = {
|
|
|
13
17
|
jitter: true,
|
|
14
18
|
};
|
|
15
19
|
const SUBGRAPH = Symbol('nexus.graph.subgraph');
|
|
20
|
+
const FORWARD_EVENT = Symbol('nexus.graph.forwardEvent');
|
|
16
21
|
const FOLLOWING_UPDATES = Symbol('nexus.graph.followingUpdates');
|
|
17
22
|
export class StateGraph {
|
|
18
23
|
channels;
|
|
@@ -123,6 +128,7 @@ export class CompiledGraph {
|
|
|
123
128
|
now;
|
|
124
129
|
store;
|
|
125
130
|
nodeCache;
|
|
131
|
+
writers = new Set();
|
|
126
132
|
constructor(channels, nodes, edges, options, scope = {}) {
|
|
127
133
|
this.channels = channels;
|
|
128
134
|
this.nodes = nodes;
|
|
@@ -132,6 +138,9 @@ export class CompiledGraph {
|
|
|
132
138
|
this.now = options.now ?? (() => new Date());
|
|
133
139
|
this.store = options.checkpointer === false ? undefined : (options.checkpointer ?? new MemoryGraphCheckpointer());
|
|
134
140
|
}
|
|
141
|
+
async flush() {
|
|
142
|
+
await Promise.all([...this.writers].map((writer) => writer.flush()));
|
|
143
|
+
}
|
|
135
144
|
async invoke(input = {}, runOptions = {}) {
|
|
136
145
|
const threadId = resolveThreadId(runOptions.threadId);
|
|
137
146
|
let last;
|
|
@@ -143,11 +152,42 @@ export class CompiledGraph {
|
|
|
143
152
|
const threadId = resolveThreadId(runOptions.threadId);
|
|
144
153
|
return this.run(threadId, runOptions, async () => {
|
|
145
154
|
this.assertInput(input);
|
|
155
|
+
if (runOptions.tenantId !== undefined) {
|
|
156
|
+
const existing = await this.checkpointer()?.get(threadId);
|
|
157
|
+
if (existing && !ownedBy(existing, runOptions.tenantId)) {
|
|
158
|
+
throw new GraphValidationError(`Thread "${threadId}" cannot be used by this tenant; choose another id`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
146
161
|
const state = this.seedState(input);
|
|
147
162
|
const next = this.entryNodes();
|
|
148
163
|
return { threadId, step: 0, state, next, status: 'running', createdAt: this.now().toISOString() };
|
|
149
164
|
});
|
|
150
165
|
}
|
|
166
|
+
events(input = {}, options = {}) {
|
|
167
|
+
const threadId = resolveThreadId(options.threadId);
|
|
168
|
+
return this.eventStream(threadId, options, (runOptions) => this.stream(input, runOptions));
|
|
169
|
+
}
|
|
170
|
+
resumeEvents(threadId, value, options = {}) {
|
|
171
|
+
return this.eventStream(threadId, options, (runOptions) => this.resume(threadId, value, runOptions));
|
|
172
|
+
}
|
|
173
|
+
continueEvents(threadId, options = {}) {
|
|
174
|
+
return this.eventStream(threadId, options, (runOptions) => this.continue(threadId, runOptions));
|
|
175
|
+
}
|
|
176
|
+
eventStream(threadId, options, run) {
|
|
177
|
+
return new GraphEventStream((onEvent, signal) => {
|
|
178
|
+
const linked = linkSignals([options.signal, signal]);
|
|
179
|
+
return releasing(run({
|
|
180
|
+
...options,
|
|
181
|
+
threadId,
|
|
182
|
+
signal: linked.signal,
|
|
183
|
+
...(options.subgraphs ? { subgraphEvents: true } : {}),
|
|
184
|
+
onEvent: (event) => {
|
|
185
|
+
options.onEvent?.(event);
|
|
186
|
+
onEvent(event);
|
|
187
|
+
},
|
|
188
|
+
}), linked.dispose);
|
|
189
|
+
}, (last) => this.toResult(threadId, last), streamSettings(options));
|
|
190
|
+
}
|
|
151
191
|
resume(threadId, value, runOptions = {}) {
|
|
152
192
|
return this.run(threadId, runOptions, async () => {
|
|
153
193
|
const checkpoint = await this.requireCheckpoint(threadId);
|
|
@@ -197,7 +237,7 @@ export class CompiledGraph {
|
|
|
197
237
|
continue(threadId, runOptions = {}) {
|
|
198
238
|
return this.run(threadId, runOptions, async () => {
|
|
199
239
|
const checkpoint = await this.requireCheckpoint(threadId);
|
|
200
|
-
return { ...checkpoint, status: 'running', error: undefined };
|
|
240
|
+
return { ...checkpoint, status: 'running', error: undefined, drained: undefined };
|
|
201
241
|
});
|
|
202
242
|
}
|
|
203
243
|
resumeFrom(threadId, step, runOptions = {}) {
|
|
@@ -208,19 +248,25 @@ export class CompiledGraph {
|
|
|
208
248
|
return { ...migrateCheckpoint(stored), status: 'running' };
|
|
209
249
|
});
|
|
210
250
|
}
|
|
211
|
-
async state(threadId, step) {
|
|
251
|
+
async state(threadId, step, options = {}) {
|
|
212
252
|
const stored = await this.checkpointer()?.get(threadId, step);
|
|
213
|
-
|
|
253
|
+
if (!stored || !ownedBy(stored, options.tenantId))
|
|
254
|
+
return undefined;
|
|
255
|
+
return migrateCheckpoint(stored);
|
|
214
256
|
}
|
|
215
|
-
async history(threadId, limit) {
|
|
257
|
+
async history(threadId, limit, options = {}) {
|
|
216
258
|
const stored = (await this.checkpointer()?.history(threadId, limit)) ?? [];
|
|
259
|
+
if (stored[0] && !ownedBy(stored[0], options.tenantId))
|
|
260
|
+
return [];
|
|
217
261
|
return stored.map((item) => migrateCheckpoint(item));
|
|
218
262
|
}
|
|
219
263
|
asNode() {
|
|
220
264
|
const node = async (context) => {
|
|
265
|
+
const forward = context[FORWARD_EVENT];
|
|
221
266
|
const runOptions = {
|
|
222
267
|
threadId: `${context.threadId}:${context.taskId}`,
|
|
223
268
|
signal: context.signal,
|
|
269
|
+
...(forward ? { onEvent: forward, subgraphEvents: true } : {}),
|
|
224
270
|
};
|
|
225
271
|
const paused = await this.state(runOptions.threadId);
|
|
226
272
|
let result;
|
|
@@ -263,13 +309,18 @@ export class CompiledGraph {
|
|
|
263
309
|
describe() {
|
|
264
310
|
const nodes = [...this.nodes.entries()].map(([id, definition]) => {
|
|
265
311
|
const subgraph = definition.fn[SUBGRAPH];
|
|
266
|
-
const { ends, defer,
|
|
312
|
+
const { ends, defer, timeoutMs, cache, idempotent } = definition.options;
|
|
313
|
+
const maxAttempts = this.retryPolicy(definition).maxAttempts;
|
|
314
|
+
const timeout = this.timeoutOf(definition);
|
|
267
315
|
return {
|
|
268
316
|
id,
|
|
269
317
|
...(ends?.length ? { ends: [...ends] } : {}),
|
|
270
318
|
...(defer ? { defer } : {}),
|
|
271
|
-
...(
|
|
319
|
+
...(maxAttempts > 1 ? { retry: true, maxAttempts } : {}),
|
|
272
320
|
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
321
|
+
...(timeout.runMs !== undefined || timeout.idleMs !== undefined ? { timeout } : {}),
|
|
322
|
+
...(this.errorHandler(definition) ? { onError: true } : {}),
|
|
323
|
+
...(idempotent ? { idempotent: true } : {}),
|
|
273
324
|
...(cache ? { cache: true } : {}),
|
|
274
325
|
...(subgraph ? { subgraph: subgraph.describe() } : {}),
|
|
275
326
|
};
|
|
@@ -304,10 +355,13 @@ export class CompiledGraph {
|
|
|
304
355
|
dynamic: [...dynamic],
|
|
305
356
|
...(this.scope.input ? { input: [...this.scope.input] } : {}),
|
|
306
357
|
...(this.scope.output ? { output: [...this.scope.output] } : {}),
|
|
358
|
+
durability: this.options.durability ?? 'sync',
|
|
359
|
+
checkpointer: this.options.checkpointer === false ? 'none' : this.options.checkpointer === undefined ? 'memory' : 'custom',
|
|
360
|
+
maxConcurrency: this.options.maxConcurrency ?? DEFAULT_MAX_CONCURRENCY,
|
|
307
361
|
};
|
|
308
362
|
}
|
|
309
363
|
async updateState(threadId, update, options = {}) {
|
|
310
|
-
const checkpoint = await this.requireCheckpoint(threadId);
|
|
364
|
+
const checkpoint = await this.requireCheckpoint(threadId, options.tenantId);
|
|
311
365
|
const state = this.reduce(checkpoint.state, [update]);
|
|
312
366
|
const createdAt = this.now().toISOString();
|
|
313
367
|
if (!options.asNode) {
|
|
@@ -342,8 +396,9 @@ export class CompiledGraph {
|
|
|
342
396
|
if (!store)
|
|
343
397
|
throw new GraphValidationError('fork() needs a checkpointer to copy history from');
|
|
344
398
|
const history = (await store.history(threadId, Number.MAX_SAFE_INTEGER)).map((item) => migrateCheckpoint(item));
|
|
345
|
-
if (history.length === 0)
|
|
399
|
+
if (history.length === 0 || !ownedBy(history[0], options.tenantId)) {
|
|
346
400
|
throw new GraphThreadNotFoundError(threadId);
|
|
401
|
+
}
|
|
347
402
|
const cutoff = options.step ?? history[0].step;
|
|
348
403
|
const lineage = history.filter((item) => item.step <= cutoff).reverse();
|
|
349
404
|
if (lineage.at(-1)?.step !== cutoff) {
|
|
@@ -394,22 +449,69 @@ export class CompiledGraph {
|
|
|
394
449
|
}
|
|
395
450
|
}
|
|
396
451
|
async *runSteps(threadId, runOptions, seed) {
|
|
452
|
+
const mode = runOptions.durability ?? this.options.durability ?? 'sync';
|
|
453
|
+
const writer = new CheckpointWriter(async (written) => {
|
|
454
|
+
await this.save(written);
|
|
455
|
+
notify(runOptions, { type: 'checkpoint', step: written.step, status: written.status, next: written.next });
|
|
456
|
+
}, mode, this.options.maxPendingWrites);
|
|
457
|
+
this.writers.add(writer);
|
|
458
|
+
let failed = false;
|
|
459
|
+
try {
|
|
460
|
+
yield* this.steps(threadId, runOptions, seed, (written, durable) => writer.persist(written, durable));
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
failed = true;
|
|
464
|
+
throw error;
|
|
465
|
+
}
|
|
466
|
+
finally {
|
|
467
|
+
this.writers.delete(writer);
|
|
468
|
+
if (failed)
|
|
469
|
+
await writer.flush().catch(() => undefined);
|
|
470
|
+
else
|
|
471
|
+
await writer.flush();
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
async *steps(threadId, runOptions, seed, persist) {
|
|
397
475
|
const maxSteps = runOptions.maxSteps ?? this.options.maxSteps ?? DEFAULT_MAX_STEPS;
|
|
398
476
|
const stopBefore = runOptions.interruptBefore ?? this.options.interruptBefore ?? [];
|
|
399
477
|
const stopAfter = runOptions.interruptAfter ?? this.options.interruptAfter ?? [];
|
|
400
|
-
const persist = async (written) => {
|
|
401
|
-
await this.save(written);
|
|
402
|
-
notify(runOptions, { type: 'checkpoint', step: written.step, status: written.status, next: written.next });
|
|
403
|
-
};
|
|
404
478
|
let checkpoint = await seed();
|
|
479
|
+
const owner = tenantOf(checkpoint);
|
|
480
|
+
if (runOptions.tenantId !== undefined && owner !== undefined && owner !== runOptions.tenantId) {
|
|
481
|
+
throw new GraphThreadNotFoundError(threadId);
|
|
482
|
+
}
|
|
483
|
+
const tenantId = runOptions.tenantId ?? owner;
|
|
484
|
+
if (tenantId !== undefined) {
|
|
485
|
+
runOptions = { ...runOptions, tenantId, metadata: { ...runOptions.metadata, tenantId } };
|
|
486
|
+
if (owner === undefined)
|
|
487
|
+
checkpoint = { ...checkpoint, metadata: { ...checkpoint.metadata, tenantId } };
|
|
488
|
+
}
|
|
405
489
|
let passBreakpoint = checkpoint.breakpoint?.when === 'before';
|
|
406
490
|
if (checkpoint.breakpoint)
|
|
407
491
|
checkpoint = { ...checkpoint, breakpoint: undefined };
|
|
492
|
+
if (checkpoint.next.length === 0) {
|
|
493
|
+
if (checkpoint.status === 'running')
|
|
494
|
+
checkpoint = { ...checkpoint, status: 'completed' };
|
|
495
|
+
await persist(checkpoint, true);
|
|
496
|
+
yield this.toEvent(checkpoint, []);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
408
499
|
await persist(checkpoint);
|
|
409
500
|
while (checkpoint.next.length > 0) {
|
|
501
|
+
if (runOptions.control?.draining) {
|
|
502
|
+
const at = this.now().toISOString();
|
|
503
|
+
checkpoint = {
|
|
504
|
+
...checkpoint,
|
|
505
|
+
status: 'interrupted',
|
|
506
|
+
drained: { ...(runOptions.control.reason ? { reason: runOptions.control.reason } : {}), at },
|
|
507
|
+
createdAt: at,
|
|
508
|
+
};
|
|
509
|
+
await persist(checkpoint, true);
|
|
510
|
+
throw new GraphDrainedError(threadId, checkpoint.step, runOptions.control.reason);
|
|
511
|
+
}
|
|
410
512
|
if (runOptions.signal?.aborted) {
|
|
411
513
|
checkpoint = { ...checkpoint, status: 'interrupted', createdAt: this.now().toISOString() };
|
|
412
|
-
await persist(checkpoint);
|
|
514
|
+
await persist(checkpoint, true);
|
|
413
515
|
yield this.toEvent(checkpoint, []);
|
|
414
516
|
return;
|
|
415
517
|
}
|
|
@@ -434,7 +536,7 @@ export class CompiledGraph {
|
|
|
434
536
|
breakpoint: { when: 'before', nodes: breakBefore },
|
|
435
537
|
createdAt: this.now().toISOString(),
|
|
436
538
|
};
|
|
437
|
-
await persist(checkpoint);
|
|
539
|
+
await persist(checkpoint, true);
|
|
438
540
|
yield this.toEvent(checkpoint, []);
|
|
439
541
|
return;
|
|
440
542
|
}
|
|
@@ -454,6 +556,7 @@ export class CompiledGraph {
|
|
|
454
556
|
const gotos = { ...(checkpoint.gotos ?? {}) };
|
|
455
557
|
let parentCommand;
|
|
456
558
|
let failure;
|
|
559
|
+
const recovered = [];
|
|
457
560
|
for (const [index, task] of pendingTasks.entries()) {
|
|
458
561
|
const outcome = outcomes[index];
|
|
459
562
|
if (!outcome)
|
|
@@ -465,6 +568,8 @@ export class CompiledGraph {
|
|
|
465
568
|
if (outcome.goto?.length)
|
|
466
569
|
gotos[task.id] = outcome.goto;
|
|
467
570
|
parentCommand ??= outcome.parent;
|
|
571
|
+
if (outcome.recovered)
|
|
572
|
+
recovered.push(outcome.recovered);
|
|
468
573
|
finished.push(task.id);
|
|
469
574
|
}
|
|
470
575
|
else if (outcome.kind === 'interrupt') {
|
|
@@ -480,6 +585,7 @@ export class CompiledGraph {
|
|
|
480
585
|
const ranNodes = distinctNodes(allTasks.filter((task) => completed.includes(task.id)));
|
|
481
586
|
const ranTasks = pendingTasks;
|
|
482
587
|
const routeFields = Object.keys(gotos).length > 0 ? { gotos } : {};
|
|
588
|
+
const recoveryFields = recovered.length > 0 ? { recovered } : {};
|
|
483
589
|
if (failure) {
|
|
484
590
|
const failed = {
|
|
485
591
|
...checkpoint,
|
|
@@ -487,6 +593,7 @@ export class CompiledGraph {
|
|
|
487
593
|
...pausedFields(allTasks, unfinished),
|
|
488
594
|
completed,
|
|
489
595
|
...routeFields,
|
|
596
|
+
...recoveryFields,
|
|
490
597
|
status: 'failed',
|
|
491
598
|
error: {
|
|
492
599
|
name: failure.error instanceof Error ? failure.error.name : 'Error',
|
|
@@ -494,7 +601,7 @@ export class CompiledGraph {
|
|
|
494
601
|
},
|
|
495
602
|
createdAt: this.now().toISOString(),
|
|
496
603
|
};
|
|
497
|
-
await persist(failed);
|
|
604
|
+
await persist(failed, true);
|
|
498
605
|
throw failure.error instanceof GraphNodeError
|
|
499
606
|
? failure.error
|
|
500
607
|
: new GraphNodeError(failure.task.node, step, failure.error);
|
|
@@ -507,11 +614,12 @@ export class CompiledGraph {
|
|
|
507
614
|
...pausedFields(allTasks, unfinished),
|
|
508
615
|
completed,
|
|
509
616
|
...routeFields,
|
|
617
|
+
...recoveryFields,
|
|
510
618
|
status: asking ? 'awaiting_input' : 'interrupted',
|
|
511
619
|
interrupts,
|
|
512
620
|
createdAt: this.now().toISOString(),
|
|
513
621
|
};
|
|
514
|
-
await persist(checkpoint);
|
|
622
|
+
await persist(checkpoint, true);
|
|
515
623
|
yield this.toEvent(checkpoint, ranNodes, ranTasks, attempts);
|
|
516
624
|
return;
|
|
517
625
|
}
|
|
@@ -523,10 +631,11 @@ export class CompiledGraph {
|
|
|
523
631
|
next: [],
|
|
524
632
|
status: 'completed',
|
|
525
633
|
resolved: checkpoint.resolved,
|
|
634
|
+
...recoveryFields,
|
|
526
635
|
createdAt: this.now().toISOString(),
|
|
527
636
|
...(runOptions.metadata ? { metadata: runOptions.metadata } : {}),
|
|
528
637
|
};
|
|
529
|
-
await persist(checkpoint);
|
|
638
|
+
await persist(checkpoint, true);
|
|
530
639
|
yield { ...this.toEvent(checkpoint, ranNodes, ranTasks, attempts), parentCommand };
|
|
531
640
|
return;
|
|
532
641
|
}
|
|
@@ -545,10 +654,11 @@ export class CompiledGraph {
|
|
|
545
654
|
status: breakAfter.length > 0 ? 'interrupted' : next.length > 0 ? 'running' : 'completed',
|
|
546
655
|
...(breakAfter.length > 0 ? { breakpoint: { when: 'after', nodes: breakAfter } } : {}),
|
|
547
656
|
resolved: checkpoint.resolved,
|
|
657
|
+
...recoveryFields,
|
|
548
658
|
createdAt: this.now().toISOString(),
|
|
549
659
|
...(runOptions.metadata ? { metadata: runOptions.metadata } : {}),
|
|
550
660
|
};
|
|
551
|
-
await persist(checkpoint);
|
|
661
|
+
await persist(checkpoint, recovered.length > 0 || next.length === 0 || breakAfter.length > 0);
|
|
552
662
|
yield this.toEvent(checkpoint, ranNodes, ranTasks, attempts);
|
|
553
663
|
if (breakAfter.length > 0)
|
|
554
664
|
return;
|
|
@@ -558,8 +668,8 @@ export class CompiledGraph {
|
|
|
558
668
|
const definition = this.nodes.get(task.node);
|
|
559
669
|
if (!definition)
|
|
560
670
|
throw new GraphValidationError(`Node "${task.node}" disappeared before it could run`);
|
|
561
|
-
const policy =
|
|
562
|
-
const
|
|
671
|
+
const policy = this.retryPolicy(definition);
|
|
672
|
+
const limits = { ...this.timeoutOf(definition), ...task.timeout };
|
|
563
673
|
const cachePolicy = definition.options.cache;
|
|
564
674
|
const cache = cachePolicy ? await this.loadNodeCache() : undefined;
|
|
565
675
|
const cacheKey = cachePolicy && cache ? cache.key(cachePolicy, task.node, checkpoint.state, task.input) : undefined;
|
|
@@ -581,22 +691,18 @@ export class CompiledGraph {
|
|
|
581
691
|
}
|
|
582
692
|
}
|
|
583
693
|
let attempts = 0;
|
|
694
|
+
const firstAttemptAt = this.now().toISOString();
|
|
584
695
|
while (true) {
|
|
585
696
|
attempts += 1;
|
|
586
697
|
notify(runOptions, { type: 'task_start', step, taskId: task.id, node: task.node, attempt: attempts });
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
const signal =
|
|
698
|
+
const timer = attemptTimer(task.node, limits);
|
|
699
|
+
const linked = linkSignals([stepSignal, runOptions.signal, timer?.signal]);
|
|
700
|
+
const signal = linked.signal;
|
|
590
701
|
try {
|
|
591
|
-
const running = this.runNode(definition.fn, task, step, threadId, checkpoint, runOptions, signal, attempts);
|
|
592
|
-
if (
|
|
702
|
+
const running = this.runNode(definition.fn, task, step, threadId, checkpoint, runOptions, signal, attempts, timer?.touch);
|
|
703
|
+
if (timer)
|
|
593
704
|
running.catch(() => undefined);
|
|
594
|
-
const output =
|
|
595
|
-
? await Promise.race([
|
|
596
|
-
running,
|
|
597
|
-
rejectWhenAborted(timeout, () => new GraphNodeTimeoutError(task.node, timeoutMs)),
|
|
598
|
-
])
|
|
599
|
-
: await running;
|
|
705
|
+
const output = timer ? await Promise.race([running, timer.expired]) : await running;
|
|
600
706
|
const parent = output.command?.graph === Command.PARENT ? output.command : undefined;
|
|
601
707
|
const goto = parent ? undefined : toRouteRecords(output.command?.goto);
|
|
602
708
|
const updates = parent ? [] : output.updates;
|
|
@@ -614,6 +720,7 @@ export class CompiledGraph {
|
|
|
614
720
|
return { kind: 'ok', updates, goto, parent, attempts };
|
|
615
721
|
}
|
|
616
722
|
catch (error) {
|
|
723
|
+
timer?.stop();
|
|
617
724
|
if (error instanceof GraphInterrupt) {
|
|
618
725
|
return {
|
|
619
726
|
kind: 'interrupt',
|
|
@@ -631,10 +738,24 @@ export class CompiledGraph {
|
|
|
631
738
|
}
|
|
632
739
|
if (runOptions.signal?.aborted || stepSignal.aborted)
|
|
633
740
|
return { kind: 'aborted', attempts };
|
|
634
|
-
const failure =
|
|
741
|
+
const failure = timer?.error() ?? error;
|
|
635
742
|
const retryable = policy.retryOn ? policy.retryOn(failure, attempts) : isRetryable(failure);
|
|
636
743
|
if (attempts >= Math.max(1, policy.maxAttempts) || !retryable) {
|
|
637
|
-
return
|
|
744
|
+
return this.recover(definition, task, step, checkpoint, runOptions, {
|
|
745
|
+
node: task.node,
|
|
746
|
+
taskId: task.id,
|
|
747
|
+
step,
|
|
748
|
+
attempts,
|
|
749
|
+
firstAttemptAt,
|
|
750
|
+
failedAt: this.now().toISOString(),
|
|
751
|
+
error: failure,
|
|
752
|
+
retryExhausted: retryable,
|
|
753
|
+
...(failure instanceof GraphNodeTimeoutError
|
|
754
|
+
? { timeout: { type: failure.kind, limitMs: failure.timeoutMs } }
|
|
755
|
+
: {}),
|
|
756
|
+
...(task.input === undefined ? {} : { input: task.input }),
|
|
757
|
+
threadId,
|
|
758
|
+
});
|
|
638
759
|
}
|
|
639
760
|
notify(runOptions, {
|
|
640
761
|
type: 'task_retry',
|
|
@@ -646,9 +767,81 @@ export class CompiledGraph {
|
|
|
646
767
|
});
|
|
647
768
|
await delay(backoffDelay(policy, attempts), runOptions.signal);
|
|
648
769
|
}
|
|
770
|
+
finally {
|
|
771
|
+
timer?.stop();
|
|
772
|
+
linked.dispose();
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
async recover(definition, task, step, checkpoint, runOptions, failure) {
|
|
777
|
+
const handler = this.errorHandler(definition);
|
|
778
|
+
const event = {
|
|
779
|
+
type: 'task_failed',
|
|
780
|
+
step,
|
|
781
|
+
taskId: task.id,
|
|
782
|
+
node: task.node,
|
|
783
|
+
attempts: failure.attempts,
|
|
784
|
+
error: describe(failure.error),
|
|
785
|
+
};
|
|
786
|
+
if (!handler || failure.error instanceof GraphValidationError) {
|
|
787
|
+
notify(runOptions, { ...event, recovered: false });
|
|
788
|
+
return { kind: 'failed', error: failure.error, attempts: failure.attempts };
|
|
789
|
+
}
|
|
790
|
+
let decided;
|
|
791
|
+
try {
|
|
792
|
+
decided = await handler(failure, { state: Object.freeze({ ...checkpoint.state }) });
|
|
649
793
|
}
|
|
794
|
+
catch (error) {
|
|
795
|
+
notify(runOptions, { ...event, recovered: false });
|
|
796
|
+
return { kind: 'failed', error, attempts: failure.attempts };
|
|
797
|
+
}
|
|
798
|
+
const command = decided instanceof Command ? decided : undefined;
|
|
799
|
+
const parent = command?.graph === Command.PARENT ? command : undefined;
|
|
800
|
+
const goto = parent ? undefined : toRouteRecords(command?.goto);
|
|
801
|
+
const own = command ? command.update : decided;
|
|
802
|
+
const updates = parent || !own ? [] : [own];
|
|
803
|
+
notify(runOptions, { ...event, recovered: true });
|
|
804
|
+
return {
|
|
805
|
+
kind: 'ok',
|
|
806
|
+
updates,
|
|
807
|
+
goto,
|
|
808
|
+
parent,
|
|
809
|
+
attempts: failure.attempts,
|
|
810
|
+
recovered: {
|
|
811
|
+
node: failure.node,
|
|
812
|
+
taskId: failure.taskId,
|
|
813
|
+
step,
|
|
814
|
+
attempts: failure.attempts,
|
|
815
|
+
error: {
|
|
816
|
+
name: failure.error instanceof Error ? failure.error.name : 'Error',
|
|
817
|
+
message: describe(failure.error),
|
|
818
|
+
},
|
|
819
|
+
failedAt: failure.failedAt,
|
|
820
|
+
retryExhausted: failure.retryExhausted,
|
|
821
|
+
...(failure.timeout ? { timeout: failure.timeout } : {}),
|
|
822
|
+
...(goto?.length ? { goto: goto.map(routeName) } : {}),
|
|
823
|
+
},
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
retryPolicy(definition) {
|
|
827
|
+
return {
|
|
828
|
+
...DEFAULT_RETRY,
|
|
829
|
+
...this.options.retry,
|
|
830
|
+
...this.options.nodeDefaults?.retry,
|
|
831
|
+
...definition.options.retry,
|
|
832
|
+
};
|
|
650
833
|
}
|
|
651
|
-
|
|
834
|
+
timeoutOf(definition) {
|
|
835
|
+
const defaults = this.options.nodeDefaults?.timeout;
|
|
836
|
+
const own = definition.options;
|
|
837
|
+
const runMs = own.timeout?.runMs ?? own.timeoutMs ?? defaults?.runMs;
|
|
838
|
+
const idleMs = own.timeout?.idleMs ?? defaults?.idleMs;
|
|
839
|
+
return { ...(runMs === undefined ? {} : { runMs }), ...(idleMs === undefined ? {} : { idleMs }) };
|
|
840
|
+
}
|
|
841
|
+
errorHandler(definition) {
|
|
842
|
+
return definition.options.onError ?? this.options.nodeDefaults?.onError;
|
|
843
|
+
}
|
|
844
|
+
async runNode(fn, task, step, threadId, checkpoint, runOptions, signal, attempt, touch = noop) {
|
|
652
845
|
const node = task.node;
|
|
653
846
|
let interruptIndex = 0;
|
|
654
847
|
const context = {
|
|
@@ -656,11 +849,18 @@ export class CompiledGraph {
|
|
|
656
849
|
node,
|
|
657
850
|
step,
|
|
658
851
|
threadId,
|
|
852
|
+
...(runOptions.tenantId !== undefined ? { tenantId: runOptions.tenantId } : {}),
|
|
659
853
|
taskId: task.id,
|
|
660
854
|
input: task.input,
|
|
661
855
|
attempt,
|
|
662
856
|
signal,
|
|
663
|
-
...(this.options.store
|
|
857
|
+
...(this.options.store
|
|
858
|
+
? {
|
|
859
|
+
store: runOptions.tenantId !== undefined
|
|
860
|
+
? tenantStore(this.options.store, runOptions.tenantId)
|
|
861
|
+
: this.options.store,
|
|
862
|
+
}
|
|
863
|
+
: {}),
|
|
664
864
|
interrupt: (request) => {
|
|
665
865
|
const index = interruptIndex++;
|
|
666
866
|
const key = interruptKey({ node, taskId: task.id, step, index });
|
|
@@ -672,8 +872,21 @@ export class CompiledGraph {
|
|
|
672
872
|
}
|
|
673
873
|
throw new GraphInterrupt(request, node, step, index, task.id);
|
|
674
874
|
},
|
|
675
|
-
emit: (data) =>
|
|
875
|
+
emit: (data) => {
|
|
876
|
+
touch();
|
|
877
|
+
notify(runOptions, { type: 'custom', step, taskId: task.id, node, data });
|
|
878
|
+
},
|
|
879
|
+
heartbeat: touch,
|
|
880
|
+
message: (chunk) => {
|
|
881
|
+
touch();
|
|
882
|
+
notify(runOptions, { type: 'message', step, taskId: task.id, node, chunk });
|
|
883
|
+
},
|
|
884
|
+
tool: (event) => {
|
|
885
|
+
touch();
|
|
886
|
+
notify(runOptions, { type: 'tool', step, taskId: task.id, node, tool: event });
|
|
887
|
+
},
|
|
676
888
|
report: (progress) => {
|
|
889
|
+
touch();
|
|
677
890
|
if (!runOptions.onProgress)
|
|
678
891
|
return;
|
|
679
892
|
try {
|
|
@@ -683,6 +896,11 @@ export class CompiledGraph {
|
|
|
683
896
|
}
|
|
684
897
|
},
|
|
685
898
|
};
|
|
899
|
+
if (runOptions.subgraphEvents) {
|
|
900
|
+
Object.defineProperty(context, FORWARD_EVENT, {
|
|
901
|
+
value: (event) => notify(runOptions, { ...event, namespace: [node, ...(event.namespace ?? [])] }),
|
|
902
|
+
});
|
|
903
|
+
}
|
|
686
904
|
const result = await fn(context);
|
|
687
905
|
const interrupted = interruptIndex > 0;
|
|
688
906
|
if (result instanceof Command) {
|
|
@@ -742,7 +960,12 @@ export class CompiledGraph {
|
|
|
742
960
|
if (!this.nodes.has(target.node)) {
|
|
743
961
|
throw new GraphValidationError(`Send from "${from}" targets unknown node "${target.node}"`);
|
|
744
962
|
}
|
|
745
|
-
tasks.push({
|
|
963
|
+
tasks.push({
|
|
964
|
+
id: `${target.node}#${step + 1}.${sends++}`,
|
|
965
|
+
node: target.node,
|
|
966
|
+
input: target.input,
|
|
967
|
+
...(target.options?.timeout ? { timeout: target.options.timeout } : {}),
|
|
968
|
+
});
|
|
746
969
|
return;
|
|
747
970
|
}
|
|
748
971
|
if (target === END)
|
|
@@ -769,7 +992,9 @@ export class CompiledGraph {
|
|
|
769
992
|
}
|
|
770
993
|
}
|
|
771
994
|
for (const { from, target } of routes) {
|
|
772
|
-
add(typeof target === 'string'
|
|
995
|
+
add(typeof target === 'string'
|
|
996
|
+
? target
|
|
997
|
+
: new Send(target.node, target.input, target.timeout ? { timeout: target.timeout } : undefined), from);
|
|
773
998
|
}
|
|
774
999
|
return tasks;
|
|
775
1000
|
}
|
|
@@ -785,9 +1010,9 @@ export class CompiledGraph {
|
|
|
785
1010
|
}
|
|
786
1011
|
return this.reduce(state, [input]);
|
|
787
1012
|
}
|
|
788
|
-
async requireCheckpoint(threadId) {
|
|
1013
|
+
async requireCheckpoint(threadId, tenantId) {
|
|
789
1014
|
const checkpoint = await this.checkpointer()?.get(threadId);
|
|
790
|
-
if (!checkpoint)
|
|
1015
|
+
if (!checkpoint || !ownedBy(checkpoint, tenantId))
|
|
791
1016
|
throw new GraphThreadNotFoundError(threadId);
|
|
792
1017
|
return migrateCheckpoint(checkpoint);
|
|
793
1018
|
}
|
|
@@ -837,6 +1062,7 @@ export class CompiledGraph {
|
|
|
837
1062
|
? { interrupt: checkpoint.interrupts[0], interrupts: checkpoint.interrupts }
|
|
838
1063
|
: {}),
|
|
839
1064
|
...(checkpoint.breakpoint ? { breakpoint: checkpoint.breakpoint } : {}),
|
|
1065
|
+
...(checkpoint.recovered?.length ? { recovered: checkpoint.recovered } : {}),
|
|
840
1066
|
};
|
|
841
1067
|
}
|
|
842
1068
|
toResult(threadId, last) {
|
|
@@ -932,21 +1158,77 @@ function toRouteRecords(goto) {
|
|
|
932
1158
|
if (goto === undefined)
|
|
933
1159
|
return undefined;
|
|
934
1160
|
return (Array.isArray(goto) ? goto : [goto]).map((target) => target instanceof Send
|
|
935
|
-
? {
|
|
1161
|
+
? {
|
|
1162
|
+
node: target.node,
|
|
1163
|
+
...(target.input === undefined ? {} : { input: target.input }),
|
|
1164
|
+
...(target.options?.timeout ? { timeout: target.options.timeout } : {}),
|
|
1165
|
+
}
|
|
936
1166
|
: target);
|
|
937
1167
|
}
|
|
938
1168
|
function routeName(route) {
|
|
939
1169
|
return typeof route === 'string' ? route : route.node;
|
|
940
1170
|
}
|
|
941
|
-
function
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1171
|
+
function noop() { }
|
|
1172
|
+
function attemptTimer(node, limits) {
|
|
1173
|
+
const { runMs, idleMs } = limits;
|
|
1174
|
+
if (runMs === undefined && idleMs === undefined)
|
|
1175
|
+
return undefined;
|
|
1176
|
+
const controller = new AbortController();
|
|
1177
|
+
let reached;
|
|
1178
|
+
let reject = noop;
|
|
1179
|
+
const expired = new Promise((_, fail) => {
|
|
1180
|
+
reject = fail;
|
|
948
1181
|
});
|
|
1182
|
+
expired.catch(noop);
|
|
1183
|
+
const fire = (error) => {
|
|
1184
|
+
if (reached)
|
|
1185
|
+
return;
|
|
1186
|
+
reached = error;
|
|
1187
|
+
controller.abort(error);
|
|
1188
|
+
reject(error);
|
|
1189
|
+
};
|
|
1190
|
+
const runTimer = runMs === undefined ? undefined : setTimeout(() => fire(new GraphNodeTimeoutError(node, runMs)), runMs);
|
|
1191
|
+
let idleTimer;
|
|
1192
|
+
const armIdle = () => {
|
|
1193
|
+
if (idleMs === undefined || reached)
|
|
1194
|
+
return;
|
|
1195
|
+
if (idleTimer)
|
|
1196
|
+
clearTimeout(idleTimer);
|
|
1197
|
+
idleTimer = setTimeout(() => fire(new GraphNodeTimeoutError(node, idleMs, 'idle')), idleMs);
|
|
1198
|
+
};
|
|
1199
|
+
armIdle();
|
|
1200
|
+
return {
|
|
1201
|
+
signal: controller.signal,
|
|
1202
|
+
expired,
|
|
1203
|
+
touch: armIdle,
|
|
1204
|
+
error: () => reached,
|
|
1205
|
+
stop: () => {
|
|
1206
|
+
if (runTimer)
|
|
1207
|
+
clearTimeout(runTimer);
|
|
1208
|
+
if (idleTimer)
|
|
1209
|
+
clearTimeout(idleTimer);
|
|
1210
|
+
idleTimer = undefined;
|
|
1211
|
+
},
|
|
1212
|
+
};
|
|
949
1213
|
}
|
|
950
1214
|
function isRetryable(error) {
|
|
951
1215
|
return !(error instanceof GraphValidationError);
|
|
952
1216
|
}
|
|
1217
|
+
function tenantOf(checkpoint) {
|
|
1218
|
+
const tenantId = checkpoint.metadata?.tenantId;
|
|
1219
|
+
return typeof tenantId === 'string' ? tenantId : undefined;
|
|
1220
|
+
}
|
|
1221
|
+
function ownedBy(checkpoint, tenantId) {
|
|
1222
|
+
if (tenantId === undefined)
|
|
1223
|
+
return true;
|
|
1224
|
+
const owner = tenantOf(checkpoint);
|
|
1225
|
+
return owner === undefined || owner === tenantId;
|
|
1226
|
+
}
|
|
1227
|
+
async function* releasing(source, release) {
|
|
1228
|
+
try {
|
|
1229
|
+
yield* source;
|
|
1230
|
+
}
|
|
1231
|
+
finally {
|
|
1232
|
+
release();
|
|
1233
|
+
}
|
|
1234
|
+
}
|
package/dist/graph/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ export { CompiledGraph, StateGraph, createGraph } from './graph.js';
|
|
|
2
2
|
export { type CheckpointDraft, type GraphCheckpointV2, migrateCheckpoint, toCheckpoint, } from './checkpoint-migration.js';
|
|
3
3
|
export { appendList, appendSet, counter, lastValue, mergeObject, reducerChannel, } from './channels.js';
|
|
4
4
|
export { MemoryGraphCheckpointer, OperationStoreCheckpointer, type MemoryGraphCheckpointerOptions, type OperationStoreCheckpointerOptions, } from './checkpointer.js';
|
|
5
|
-
export { GraphError, GraphInterrupt, GraphNodeError, GraphNodeTimeoutError, GraphNotInterruptedError, GraphStepLimitError, GraphThreadNotFoundError, GraphValidationError, interruptKey, } from './errors.js';
|
|
5
|
+
export { GraphDrainedError, GraphError, GraphInterrupt, GraphNodeError, GraphNodeTimeoutError, GraphNotInterruptedError, GraphStepLimitError, GraphThreadNotFoundError, GraphValidationError, interruptKey, } from './errors.js';
|
|
6
|
+
export { RunControl } from './run-control.js';
|
|
7
|
+
export { GraphEventStream, GraphStreamOverflowError } from './event-stream.js';
|
|
6
8
|
export { Command, END, Send, START } from '../types/graph.js';
|
|
7
|
-
export type { Channel, ChannelSchema, CommandTarget, CompileOptions, EdgeRouter, GraphBreakpoint, GraphCheckpoint, GraphCheckpointV1, GraphCheckpointer, GraphDescription, GraphEvent, GraphInput, GraphProgress, GraphResult, GraphRunOptions, GraphRouteTarget, GraphStatus, GraphStepEvent, GraphTask, InterruptRequest, NodeCacheEntry, NodeCachePolicy, NodeContext, NodeFn, NodeOptions, NodeResult, PendingInterrupt, RetryPolicy, StateOf, StateUpdate, StoredGraphCheckpoint, } from '../types/graph.js';
|
|
9
|
+
export type { Channel, ChannelSchema, CommandTarget, CompileOptions, DurabilityMode, EdgeRouter, GraphBreakpoint, GraphCheckpoint, GraphCheckpointV1, GraphCheckpointer, GraphDescription, GraphEvent, GraphEventsOptions, GraphInput, GraphProgress, GraphResult, GraphRunOptions, GraphRouteTarget, GraphStatus, GraphStepEvent, GraphMessageChunk, GraphStreamEvent, GraphStreamOverflow, GraphStreamProjection, GraphStreamStats, GraphToolEvent, GraphTask, InterruptRequest, NodeCacheEntry, NodeCachePolicy, NodeContext, NodeErrorHandler, NodeFailure, NodeFn, NodeOptions, NodeResult, NodeTimeout, PendingInterrupt, RecoveredFailure, RetryPolicy, RunControlLike, SendOptions, StateOf, StateUpdate, StoredGraphCheckpoint, } from '../types/graph.js';
|