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-cjs/graph/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.START = exports.Send = exports.END = exports.Command = exports.interruptKey = exports.GraphValidationError = exports.GraphThreadNotFoundError = exports.GraphStepLimitError = exports.GraphNotInterruptedError = exports.GraphNodeTimeoutError = exports.GraphNodeError = exports.GraphInterrupt = exports.GraphError = exports.OperationStoreCheckpointer = exports.MemoryGraphCheckpointer = exports.reducerChannel = exports.mergeObject = exports.lastValue = exports.counter = exports.appendSet = exports.appendList = exports.toCheckpoint = exports.migrateCheckpoint = exports.createGraph = exports.StateGraph = exports.CompiledGraph = void 0;
|
|
3
|
+
exports.START = exports.Send = exports.END = exports.Command = exports.GraphStreamOverflowError = exports.GraphEventStream = exports.RunControl = exports.interruptKey = exports.GraphValidationError = exports.GraphThreadNotFoundError = exports.GraphStepLimitError = exports.GraphNotInterruptedError = exports.GraphNodeTimeoutError = exports.GraphNodeError = exports.GraphInterrupt = exports.GraphError = exports.GraphDrainedError = exports.OperationStoreCheckpointer = exports.MemoryGraphCheckpointer = exports.reducerChannel = exports.mergeObject = exports.lastValue = exports.counter = exports.appendSet = exports.appendList = exports.toCheckpoint = exports.migrateCheckpoint = exports.createGraph = exports.StateGraph = exports.CompiledGraph = void 0;
|
|
4
4
|
var graph_js_1 = require("./graph.js");
|
|
5
5
|
Object.defineProperty(exports, "CompiledGraph", { enumerable: true, get: function () { return graph_js_1.CompiledGraph; } });
|
|
6
6
|
Object.defineProperty(exports, "StateGraph", { enumerable: true, get: function () { return graph_js_1.StateGraph; } });
|
|
@@ -19,6 +19,7 @@ var checkpointer_js_1 = require("./checkpointer.js");
|
|
|
19
19
|
Object.defineProperty(exports, "MemoryGraphCheckpointer", { enumerable: true, get: function () { return checkpointer_js_1.MemoryGraphCheckpointer; } });
|
|
20
20
|
Object.defineProperty(exports, "OperationStoreCheckpointer", { enumerable: true, get: function () { return checkpointer_js_1.OperationStoreCheckpointer; } });
|
|
21
21
|
var errors_js_1 = require("./errors.js");
|
|
22
|
+
Object.defineProperty(exports, "GraphDrainedError", { enumerable: true, get: function () { return errors_js_1.GraphDrainedError; } });
|
|
22
23
|
Object.defineProperty(exports, "GraphError", { enumerable: true, get: function () { return errors_js_1.GraphError; } });
|
|
23
24
|
Object.defineProperty(exports, "GraphInterrupt", { enumerable: true, get: function () { return errors_js_1.GraphInterrupt; } });
|
|
24
25
|
Object.defineProperty(exports, "GraphNodeError", { enumerable: true, get: function () { return errors_js_1.GraphNodeError; } });
|
|
@@ -28,6 +29,11 @@ Object.defineProperty(exports, "GraphStepLimitError", { enumerable: true, get: f
|
|
|
28
29
|
Object.defineProperty(exports, "GraphThreadNotFoundError", { enumerable: true, get: function () { return errors_js_1.GraphThreadNotFoundError; } });
|
|
29
30
|
Object.defineProperty(exports, "GraphValidationError", { enumerable: true, get: function () { return errors_js_1.GraphValidationError; } });
|
|
30
31
|
Object.defineProperty(exports, "interruptKey", { enumerable: true, get: function () { return errors_js_1.interruptKey; } });
|
|
32
|
+
var run_control_js_1 = require("./run-control.js");
|
|
33
|
+
Object.defineProperty(exports, "RunControl", { enumerable: true, get: function () { return run_control_js_1.RunControl; } });
|
|
34
|
+
var event_stream_js_1 = require("./event-stream.js");
|
|
35
|
+
Object.defineProperty(exports, "GraphEventStream", { enumerable: true, get: function () { return event_stream_js_1.GraphEventStream; } });
|
|
36
|
+
Object.defineProperty(exports, "GraphStreamOverflowError", { enumerable: true, get: function () { return event_stream_js_1.GraphStreamOverflowError; } });
|
|
31
37
|
var graph_js_2 = require("../types/graph.js");
|
|
32
38
|
Object.defineProperty(exports, "Command", { enumerable: true, get: function () { return graph_js_2.Command; } });
|
|
33
39
|
Object.defineProperty(exports, "END", { enumerable: true, get: function () { return graph_js_2.END; } });
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { GraphDescription } from '../types/graph.js';
|
|
2
|
+
/** How much a lint finding matters: `error` fails `nexus graph lint`, the others only report. */
|
|
3
|
+
export type GraphLintSeverity = 'error' | 'warning' | 'info';
|
|
4
|
+
/** The rules `lintGraph()` checks. */
|
|
5
|
+
export type GraphLintCode = 'UNBOUNDED_CYCLE' | 'RETRY_WITHOUT_IDEMPOTENCY' | 'RETRY_WITHOUT_TIMEOUT' | 'DEFERRED_DURABILITY_WITH_SIDE_EFFECTS' | 'MEMORY_CHECKPOINTER' | 'NO_CHECKPOINTER' | 'UNBOUNDED_CONCURRENCY' | 'DYNAMIC_ROUTE';
|
|
6
|
+
/** One design problem `lintGraph()` found. */
|
|
7
|
+
export interface GraphLintFinding {
|
|
8
|
+
/** Which rule found it. */
|
|
9
|
+
code: GraphLintCode;
|
|
10
|
+
/** How much it matters. */
|
|
11
|
+
severity: GraphLintSeverity;
|
|
12
|
+
/** The node it is about, as a path through subgraphs such as `review/approve`. Absent for the graph itself. */
|
|
13
|
+
node?: string;
|
|
14
|
+
/** What is wrong. */
|
|
15
|
+
message: string;
|
|
16
|
+
/** What to do about it. */
|
|
17
|
+
fix: string;
|
|
18
|
+
}
|
|
19
|
+
/** Options for `lintGraph()`. */
|
|
20
|
+
export interface GraphLintOptions {
|
|
21
|
+
/**
|
|
22
|
+
* The graph runs where a restart, a second replica, or a hand-off is normal: under the agent
|
|
23
|
+
* server, a job queue, or more than one process. An in-process checkpointer is then an error, not
|
|
24
|
+
* a note.
|
|
25
|
+
*/
|
|
26
|
+
deployed?: boolean;
|
|
27
|
+
/** Rules to skip, by code. */
|
|
28
|
+
ignore?: GraphLintCode[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Finds designs that work in a demo and fail in production, by reading a compiled graph's shape.
|
|
32
|
+
*
|
|
33
|
+
* It needs no run and calls no node: it reads `describe()`, so it also works on a description saved
|
|
34
|
+
* as JSON. The checks:
|
|
35
|
+
*
|
|
36
|
+
* | Code | Severity | Finds |
|
|
37
|
+
* | --- | --- | --- |
|
|
38
|
+
* | `UNBOUNDED_CYCLE` | error | A cycle of static edges, which only the step limit can stop |
|
|
39
|
+
* | `RETRY_WITHOUT_IDEMPOTENCY` | warning | A retried node not declared `idempotent`, whose side effects can repeat |
|
|
40
|
+
* | `RETRY_WITHOUT_TIMEOUT` | warning | A retried node with no timeout, whose hung attempt is never retried |
|
|
41
|
+
* | `DEFERRED_DURABILITY_WITH_SIDE_EFFECTS` | warning | `async` or `exit` durability with nodes not declared `idempotent` |
|
|
42
|
+
* | `MEMORY_CHECKPOINTER` | warning, or error when `deployed` | The in-process default, which a restart loses |
|
|
43
|
+
* | `NO_CHECKPOINTER` | info | No checkpoints, so no interrupt, resume, or recovery |
|
|
44
|
+
* | `UNBOUNDED_CONCURRENCY` | warning | A fan-out with no limit on tasks at once |
|
|
45
|
+
* | `DYNAMIC_ROUTE` | info | A router with no mapping or `ends`, so routes cannot be checked |
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { lintGraph } from 'nexus-ai-pro/graph/lint';
|
|
50
|
+
*
|
|
51
|
+
* const findings = lintGraph(graph, { deployed: true });
|
|
52
|
+
* for (const finding of findings) console.log(finding.severity, finding.code, finding.message);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function lintGraph(graph: {
|
|
56
|
+
describe(): GraphDescription;
|
|
57
|
+
} | GraphDescription, options?: GraphLintOptions): GraphLintFinding[];
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lintGraph = lintGraph;
|
|
4
|
+
function lintGraph(graph, options = {}) {
|
|
5
|
+
const description = 'describe' in graph && typeof graph.describe === 'function' ? graph.describe() : graph;
|
|
6
|
+
const findings = [];
|
|
7
|
+
lintDescription(description, '', options, findings, true);
|
|
8
|
+
const ignored = new Set(options.ignore ?? []);
|
|
9
|
+
return findings.filter((finding) => !ignored.has(finding.code));
|
|
10
|
+
}
|
|
11
|
+
function lintDescription(description, prefix, options, findings, top) {
|
|
12
|
+
const at = (node) => `${prefix}${node}`;
|
|
13
|
+
for (const cycle of staticCycles(description)) {
|
|
14
|
+
findings.push({
|
|
15
|
+
code: 'UNBOUNDED_CYCLE',
|
|
16
|
+
severity: 'error',
|
|
17
|
+
node: at(cycle[0]),
|
|
18
|
+
message: `${cycle.map((node) => `"${at(node)}"`).join(' → ')} loop through static edges only, so the run can only stop at the step limit.`,
|
|
19
|
+
fix: 'Route out of the loop with a conditional edge, a Command with declared ends, or an edge to END.',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const sideEffecting = [];
|
|
23
|
+
for (const node of description.nodes) {
|
|
24
|
+
if (!node.idempotent)
|
|
25
|
+
sideEffecting.push(node.id);
|
|
26
|
+
if (node.retry && !node.idempotent) {
|
|
27
|
+
findings.push({
|
|
28
|
+
code: 'RETRY_WITHOUT_IDEMPOTENCY',
|
|
29
|
+
severity: 'warning',
|
|
30
|
+
node: at(node.id),
|
|
31
|
+
message: `"${at(node.id)}" is retried up to ${node.maxAttempts ?? 'several'} times but is not declared idempotent, so a side effect can happen more than once.`,
|
|
32
|
+
fix: 'Give its side effects an idempotency key and declare `idempotent: true`, or stop retrying it.',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const timed = node.timeoutMs !== undefined || node.timeout?.runMs !== undefined || node.timeout?.idleMs !== undefined;
|
|
36
|
+
if (node.retry && !timed) {
|
|
37
|
+
findings.push({
|
|
38
|
+
code: 'RETRY_WITHOUT_TIMEOUT',
|
|
39
|
+
severity: 'warning',
|
|
40
|
+
node: at(node.id),
|
|
41
|
+
message: `"${at(node.id)}" is retried but has no timeout, so an attempt that hangs is never retried.`,
|
|
42
|
+
fix: 'Set `timeout: { runMs }`, or `idleMs` with `context.heartbeat()` for long work.',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if (node.subgraph)
|
|
46
|
+
lintDescription(node.subgraph, `${at(node.id)}/`, options, findings, false);
|
|
47
|
+
}
|
|
48
|
+
if (!top)
|
|
49
|
+
return;
|
|
50
|
+
if ((description.durability === 'async' || description.durability === 'exit') && sideEffecting.length > 0) {
|
|
51
|
+
findings.push({
|
|
52
|
+
code: 'DEFERRED_DURABILITY_WITH_SIDE_EFFECTS',
|
|
53
|
+
severity: 'warning',
|
|
54
|
+
message: `Durability is "${description.durability}", so a crash can repeat supersteps, and ${sideEffecting.map((node) => `"${node}"`).join(', ')} ${sideEffecting.length === 1 ? 'is' : 'are'} not declared idempotent.`,
|
|
55
|
+
fix: 'Use `sync` durability for graphs with side effects, or make those nodes idempotent and declare it.',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (description.checkpointer === 'memory') {
|
|
59
|
+
findings.push({
|
|
60
|
+
code: 'MEMORY_CHECKPOINTER',
|
|
61
|
+
severity: options.deployed ? 'error' : 'warning',
|
|
62
|
+
message: 'Checkpoints go to the in-process default, so a restart loses every thread, and another process cannot resume one.',
|
|
63
|
+
fix: 'Pass a persistent checkpointer, such as an OperationStoreCheckpointer over Postgres, SQLite, or Redis.',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (description.checkpointer === 'none') {
|
|
67
|
+
findings.push({
|
|
68
|
+
code: 'NO_CHECKPOINTER',
|
|
69
|
+
severity: 'info',
|
|
70
|
+
message: 'The graph writes no checkpoints, so it cannot interrupt, resume, drain, or recover after a crash.',
|
|
71
|
+
fix: 'Pass a checkpointer if any of those is needed.',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (description.maxConcurrency !== undefined && !Number.isFinite(description.maxConcurrency)) {
|
|
75
|
+
findings.push({
|
|
76
|
+
code: 'UNBOUNDED_CONCURRENCY',
|
|
77
|
+
severity: 'warning',
|
|
78
|
+
message: 'Tasks in a superstep run with no limit, so a large Send fan-out starts all of them at once.',
|
|
79
|
+
fix: 'Set `maxConcurrency` to what the services behind the nodes can take.',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
for (const node of description.dynamic) {
|
|
83
|
+
findings.push({
|
|
84
|
+
code: 'DYNAMIC_ROUTE',
|
|
85
|
+
severity: 'info',
|
|
86
|
+
node: at(node),
|
|
87
|
+
message: `The router after "${at(node)}" has no mapping and the node declares no ends, so its routes cannot be checked or drawn.`,
|
|
88
|
+
fix: "Give the conditional edge a mapping, or declare the node's `ends`.",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function staticCycles(description) {
|
|
93
|
+
const deciding = new Set(description.dynamic);
|
|
94
|
+
for (const node of description.nodes)
|
|
95
|
+
if (node.ends?.length)
|
|
96
|
+
deciding.add(node.id);
|
|
97
|
+
for (const edge of description.edges)
|
|
98
|
+
if (edge.conditional)
|
|
99
|
+
deciding.add(edge.from);
|
|
100
|
+
const next = new Map();
|
|
101
|
+
for (const edge of description.edges) {
|
|
102
|
+
if (edge.conditional || deciding.has(edge.from))
|
|
103
|
+
continue;
|
|
104
|
+
next.set(edge.from, [...(next.get(edge.from) ?? []), edge.to]);
|
|
105
|
+
}
|
|
106
|
+
const cycles = [];
|
|
107
|
+
const index = new Map();
|
|
108
|
+
const low = new Map();
|
|
109
|
+
const stack = [];
|
|
110
|
+
const onStack = new Set();
|
|
111
|
+
let counter = 0;
|
|
112
|
+
const visit = (node) => {
|
|
113
|
+
index.set(node, counter);
|
|
114
|
+
low.set(node, counter);
|
|
115
|
+
counter += 1;
|
|
116
|
+
stack.push(node);
|
|
117
|
+
onStack.add(node);
|
|
118
|
+
for (const to of next.get(node) ?? []) {
|
|
119
|
+
if (!index.has(to)) {
|
|
120
|
+
visit(to);
|
|
121
|
+
low.set(node, Math.min(low.get(node), low.get(to)));
|
|
122
|
+
}
|
|
123
|
+
else if (onStack.has(to)) {
|
|
124
|
+
low.set(node, Math.min(low.get(node), index.get(to)));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (low.get(node) !== index.get(node))
|
|
128
|
+
return;
|
|
129
|
+
const component = [];
|
|
130
|
+
let member;
|
|
131
|
+
do {
|
|
132
|
+
member = stack.pop();
|
|
133
|
+
onStack.delete(member);
|
|
134
|
+
component.push(member);
|
|
135
|
+
} while (member !== node);
|
|
136
|
+
const selfLoop = component.length === 1 && (next.get(node) ?? []).includes(node);
|
|
137
|
+
if (component.length > 1 || selfLoop)
|
|
138
|
+
cycles.push(component.reverse());
|
|
139
|
+
};
|
|
140
|
+
for (const node of description.nodes)
|
|
141
|
+
if (!index.has(node.id))
|
|
142
|
+
visit(node.id);
|
|
143
|
+
return cycles;
|
|
144
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RunControlLike } from '../types/graph.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stops graph runs cleanly: each finishes its current superstep, writes its checkpoint, and ends with
|
|
4
|
+
* `GraphDrainedError`, so another worker can `continue()` it.
|
|
5
|
+
*
|
|
6
|
+
* An abort signal stops a run in the middle of a superstep, cancelling the nodes in flight. A drain
|
|
7
|
+
* waits for them, which is what a rolling deploy, a spot eviction, or a scale-down wants: nothing
|
|
8
|
+
* half done, nothing lost. One control can drain any number of runs at once.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const control = new RunControl();
|
|
13
|
+
* process.on('SIGTERM', () => control.drain('sigterm'));
|
|
14
|
+
* await graph.invoke(input, { threadId, control });
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare class RunControl implements RunControlLike {
|
|
18
|
+
private requested;
|
|
19
|
+
private readonly listeners;
|
|
20
|
+
/** True once `drain()` was called. */
|
|
21
|
+
get draining(): boolean;
|
|
22
|
+
/** Why the drain was requested. */
|
|
23
|
+
get reason(): string | undefined;
|
|
24
|
+
/** Asks every run using this control to stop after its current superstep. A second call is ignored. */
|
|
25
|
+
drain(reason?: string): void;
|
|
26
|
+
/** Calls `listener` when a drain is requested. Returns a function that removes it. */
|
|
27
|
+
onDrain(listener: (reason?: string) => void): () => void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RunControl = void 0;
|
|
4
|
+
class RunControl {
|
|
5
|
+
requested;
|
|
6
|
+
listeners = new Set();
|
|
7
|
+
get draining() {
|
|
8
|
+
return this.requested !== undefined;
|
|
9
|
+
}
|
|
10
|
+
get reason() {
|
|
11
|
+
return this.requested?.reason;
|
|
12
|
+
}
|
|
13
|
+
drain(reason) {
|
|
14
|
+
if (this.requested)
|
|
15
|
+
return;
|
|
16
|
+
this.requested = { reason };
|
|
17
|
+
for (const listener of this.listeners) {
|
|
18
|
+
try {
|
|
19
|
+
listener(reason);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
onDrain(listener) {
|
|
26
|
+
this.listeners.add(listener);
|
|
27
|
+
return () => this.listeners.delete(listener);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.RunControl = RunControl;
|
package/dist-cjs/images/evals.js
CHANGED
|
@@ -38,6 +38,7 @@ exports.perceptualSimilarity = perceptualSimilarity;
|
|
|
38
38
|
exports.textAccuracy = textAccuracy;
|
|
39
39
|
exports.stats = stats;
|
|
40
40
|
const node_crypto_1 = require("node:crypto");
|
|
41
|
+
const signals_js_1 = require("../utils/signals.js");
|
|
41
42
|
const errors_js_1 = require("./errors.js");
|
|
42
43
|
class MemoryReviewQueue {
|
|
43
44
|
items = [];
|
|
@@ -72,7 +73,8 @@ class MediaEvalRunner {
|
|
|
72
73
|
const runsOf = new Map(examples.map((example, index) => [example.id, runCounts[index]]));
|
|
73
74
|
const outcomes = new Map();
|
|
74
75
|
const stop = new AbortController();
|
|
75
|
-
const
|
|
76
|
+
const linked = (0, signals_js_1.linkSignals)([stop.signal, runOptions.signal]);
|
|
77
|
+
const signal = linked.signal;
|
|
76
78
|
const { evaluate } = await Promise.resolve().then(() => __importStar(require('../evaluate/run.js')));
|
|
77
79
|
const experiment = await evaluate(async (evalCase, { example, run }) => {
|
|
78
80
|
try {
|
|
@@ -97,7 +99,7 @@ class MediaEvalRunner {
|
|
|
97
99
|
signal,
|
|
98
100
|
...(runOptions.store ? { store: runOptions.store } : {}),
|
|
99
101
|
...(runOptions.metadata ? { metadata: runOptions.metadata } : {}),
|
|
100
|
-
});
|
|
102
|
+
}).finally(linked.dispose);
|
|
101
103
|
const caseReports = [];
|
|
102
104
|
const allScores = {};
|
|
103
105
|
const safety = { truePositives: 0, falsePositives: 0, trueNegatives: 0, falseNegatives: 0 };
|
|
@@ -3,7 +3,8 @@ import type { OperationDispatcher, OperationRecord, OperationStore, OperationSto
|
|
|
3
3
|
* The Redis commands the operation store needs.
|
|
4
4
|
*
|
|
5
5
|
* Structural rather than tied to one client, so `ioredis`, `node-redis`, or a cluster proxy all
|
|
6
|
-
* satisfy it without this package depending on any of them.
|
|
6
|
+
* satisfy it without this package depending on any of them. The sorted-set commands are needed only
|
|
7
|
+
* with `index: true`; `ioredis` has them all.
|
|
7
8
|
*/
|
|
8
9
|
export interface RedisOperationLikeClient {
|
|
9
10
|
/** Reads a hash field. */
|
|
@@ -16,6 +17,14 @@ export interface RedisOperationLikeClient {
|
|
|
16
17
|
hvals(key: string): Promise<string[]> | string[];
|
|
17
18
|
/** Optional CAS primitive. When absent the store falls back to a read-compare-write. */
|
|
18
19
|
eval?(script: string, numKeys: number, ...args: string[]): Promise<unknown> | unknown;
|
|
20
|
+
/** Reads several hash fields in one round trip. Used by the index when present. */
|
|
21
|
+
hmget?(key: string, ...fields: string[]): Promise<Array<string | null>> | Array<string | null>;
|
|
22
|
+
/** Adds a sorted-set member. Needed with `index: true`. */
|
|
23
|
+
zadd?(key: string, score: number, member: string): Promise<unknown> | unknown;
|
|
24
|
+
/** Removes a sorted-set member. Needed with `index: true`. */
|
|
25
|
+
zrem?(key: string, member: string): Promise<unknown> | unknown;
|
|
26
|
+
/** Members by score, as `ZRANGEBYSCORE key min max LIMIT offset count`. Needed with `index: true`. */
|
|
27
|
+
zrangebyscore?(key: string, min: number | string, max: number | string, limit: 'LIMIT', offset: number, count: number): Promise<string[]> | string[];
|
|
19
28
|
}
|
|
20
29
|
/** Options for the Redis operation store. */
|
|
21
30
|
export interface RedisOperationStoreOptions {
|
|
@@ -23,6 +32,19 @@ export interface RedisOperationStoreOptions {
|
|
|
23
32
|
prefix?: string;
|
|
24
33
|
/** Disables the Lua compare-and-set even when the client exposes `eval`. */
|
|
25
34
|
useEval?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Keeps queued work in a sorted set by age, and leased work in one by lease expiry, so
|
|
37
|
+
* `listQueued()` and `claimExpired()` read the oldest few records instead of every one: a claim
|
|
38
|
+
* costs the same with 100,000 operations queued as with 1,000. The records stay the source of
|
|
39
|
+
* truth; an index entry only says where to look, and one that no longer matches its record is
|
|
40
|
+
* skipped and removed.
|
|
41
|
+
*
|
|
42
|
+
* Off by default, because a 2.1 worker writes records without index entries. Turn it on once every
|
|
43
|
+
* worker sharing the prefix runs 2.2, then call `reindex()` once to index what is already there.
|
|
44
|
+
* Needs `zadd`, `zrem`, and `zrangebyscore`; with `eval`, a record and its index entries change in
|
|
45
|
+
* one step.
|
|
46
|
+
*/
|
|
47
|
+
index?: boolean;
|
|
26
48
|
}
|
|
27
49
|
/**
|
|
28
50
|
* Redis-backed operation storage, so a submitted operation survives a restart.
|
|
@@ -36,8 +58,13 @@ export declare class RedisOperationStore<TResult = unknown> implements Operation
|
|
|
36
58
|
private readonly client;
|
|
37
59
|
private readonly prefix;
|
|
38
60
|
private readonly useEval;
|
|
61
|
+
private readonly indexed;
|
|
39
62
|
constructor(client: RedisOperationLikeClient, options?: RedisOperationStoreOptions);
|
|
40
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Stores a new record and indexes its idempotency key. Throws `OperationDuplicateError` when another
|
|
65
|
+
* record holds the key, checked in the same Lua call as the write when the client has `eval`.
|
|
66
|
+
* Refuses records carrying raw bytes.
|
|
67
|
+
*/
|
|
41
68
|
create(record: OperationRecord<TResult>): Promise<void>;
|
|
42
69
|
/** Reads a record. */
|
|
43
70
|
read(id: string): Promise<OperationRecord<TResult> | undefined>;
|
|
@@ -50,19 +77,40 @@ export declare class RedisOperationStore<TResult = unknown> implements Operation
|
|
|
50
77
|
delete(id: string): Promise<boolean>;
|
|
51
78
|
/**
|
|
52
79
|
* Records whose lease has expired, or running records without one, up to `limit`, for another
|
|
53
|
-
* worker to take over.
|
|
80
|
+
* worker to take over. With the index, reads only records whose lease has lapsed.
|
|
54
81
|
*/
|
|
55
82
|
claimExpired(now: string, limit: number): Promise<Array<OperationRecord<TResult>>>;
|
|
56
83
|
/** Finds the record that claimed an idempotency key. */
|
|
57
84
|
findByIdempotencyKey(key: string): Promise<OperationRecord<TResult> | undefined>;
|
|
58
85
|
/** Every record. */
|
|
59
86
|
list(): Promise<Array<OperationRecord<TResult>>>;
|
|
60
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Queued records no worker holds, oldest first. With the index, reads them oldest first from the
|
|
89
|
+
* sorted set and stops at `limit`; without it, reads every record, as `list()` does.
|
|
90
|
+
*/
|
|
61
91
|
listQueued(limit: number, filter?: OperationStoreFilter): Promise<Array<OperationRecord<TResult>>>;
|
|
62
92
|
/** Counts unfinished records by status. Reads every record, as `list()` does. */
|
|
63
93
|
stats(now: string, filter?: OperationStoreFilter): Promise<OperationStoreStats>;
|
|
94
|
+
/**
|
|
95
|
+
* Indexes every record already stored, for turning `index` on over existing data. Safe to run
|
|
96
|
+
* while workers are busy, and to run again: it only adds entries, then removes those that no
|
|
97
|
+
* longer match their record, checking each record as it does. Resolves to how many records it read.
|
|
98
|
+
*/
|
|
99
|
+
reindex(): Promise<number>;
|
|
100
|
+
/**
|
|
101
|
+
* Reads one index in score order up to `max`, a page at a time, keeping records that pass `keep`
|
|
102
|
+
* until `limit`. Entries whose record is gone or no longer `belongs` are removed afterwards.
|
|
103
|
+
*/
|
|
104
|
+
private scanIndex;
|
|
105
|
+
private readMany;
|
|
106
|
+
/** Removes index entries that no longer describe their record. Only with `eval`, where the check is atomic. */
|
|
107
|
+
private prune;
|
|
108
|
+
/** Writes a record's index entries without `eval`, after the record itself. */
|
|
109
|
+
private place;
|
|
64
110
|
private recordsKey;
|
|
65
111
|
private idempotencyKey;
|
|
112
|
+
private queuedKey;
|
|
113
|
+
private leasesKey;
|
|
66
114
|
}
|
|
67
115
|
/** The part of a BullMQ `Queue` the dispatcher needs. */
|
|
68
116
|
export interface BullMQLikeOperationQueue {
|