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/cli/db.js
CHANGED
|
@@ -1,31 +1,211 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.runDbCommand = runDbCommand;
|
|
4
37
|
const index_js_1 = require("../postgres/index.js");
|
|
5
38
|
const args_js_1 = require("./args.js");
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
'
|
|
9
|
-
|
|
10
|
-
'
|
|
11
|
-
|
|
12
|
-
'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (subcommand !== 'sql')
|
|
17
|
-
throw new args_js_1.CliUsageError(`Unknown db command "${subcommand ?? ''}". Use sql.`);
|
|
18
|
-
const adapters = (0, args_js_1.listFlag)(flags, 'adapters');
|
|
19
|
-
const unknown = adapters?.filter((adapter) => !ADAPTERS.includes(adapter));
|
|
20
|
-
if (unknown?.length) {
|
|
21
|
-
throw new args_js_1.CliUsageError(`Unknown adapter ${unknown.join(', ')}. Choose from ${ADAPTERS.join(', ')}.`);
|
|
22
|
-
}
|
|
39
|
+
const SQLITE_ADAPTERS = ['operations', 'store', 'vectors'];
|
|
40
|
+
async function runDbCommand(subcommand, args) {
|
|
41
|
+
if (subcommand === 'sql')
|
|
42
|
+
return printSql(args);
|
|
43
|
+
if (subcommand === 'status' || subcommand === 'migrate')
|
|
44
|
+
return withDatabase(subcommand, args);
|
|
45
|
+
throw new args_js_1.CliUsageError(`Unknown db command "${subcommand ?? ''}". Use sql, status, or migrate.`);
|
|
46
|
+
}
|
|
47
|
+
function printSql({ flags }) {
|
|
48
|
+
const adapters = postgresAdapters(flags);
|
|
23
49
|
const vectorDimensions = (0, args_js_1.numberFlag)(flags, 'vector-dimensions');
|
|
24
|
-
if (adapters?.includes('vectors') && vectorDimensions === undefined) {
|
|
25
|
-
throw new args_js_1.CliUsageError('The vectors adapter needs --vector-dimensions.');
|
|
26
|
-
}
|
|
27
50
|
process.stdout.write((0, index_js_1.postgresMigration)({
|
|
28
51
|
...(adapters ? { adapters } : {}),
|
|
29
52
|
...(vectorDimensions === undefined ? {} : { vectorDimensions }),
|
|
53
|
+
...((0, args_js_1.flagBool)(flags, 'record') ? { record: true } : {}),
|
|
30
54
|
}));
|
|
31
55
|
}
|
|
56
|
+
function postgresAdapters(flags) {
|
|
57
|
+
const adapters = (0, args_js_1.listFlag)(flags, 'adapters');
|
|
58
|
+
const unknown = adapters?.filter((adapter) => !index_js_1.POSTGRES_ADAPTERS.includes(adapter));
|
|
59
|
+
if (unknown?.length) {
|
|
60
|
+
throw new args_js_1.CliUsageError(`Unknown adapter ${unknown.join(', ')}. Choose from ${index_js_1.POSTGRES_ADAPTERS.join(', ')}.`);
|
|
61
|
+
}
|
|
62
|
+
if (adapters?.includes('vectors') && (0, args_js_1.numberFlag)(flags, 'vector-dimensions') === undefined) {
|
|
63
|
+
throw new args_js_1.CliUsageError('The vectors adapter needs --vector-dimensions.');
|
|
64
|
+
}
|
|
65
|
+
return adapters;
|
|
66
|
+
}
|
|
67
|
+
async function withDatabase(command, { flags }) {
|
|
68
|
+
const location = (0, args_js_1.stringFlag)(flags, 'client');
|
|
69
|
+
if (!location)
|
|
70
|
+
throw new args_js_1.CliUsageError(`nexus db ${command} needs --client <db.mjs>, a module exporting \`client\`.`);
|
|
71
|
+
const database = await openDatabase(location, (0, args_js_1.stringFlag)(flags, 'dialect'));
|
|
72
|
+
try {
|
|
73
|
+
const migrations = database.migrations ?? (await bundledMigrations(database.dialect, flags));
|
|
74
|
+
const table = (0, args_js_1.stringFlag)(flags, 'table');
|
|
75
|
+
if (command === 'status') {
|
|
76
|
+
const status = await statusOf(database, migrations, table);
|
|
77
|
+
if ((0, args_js_1.flagBool)(flags, 'json'))
|
|
78
|
+
(0, args_js_1.writeJson)(status);
|
|
79
|
+
else
|
|
80
|
+
printStatus(status);
|
|
81
|
+
if ((0, args_js_1.flagBool)(flags, 'check') && !status.current)
|
|
82
|
+
process.exitCode = 1;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const result = await migrate(database, migrations, { dryRun: (0, args_js_1.flagBool)(flags, 'dry-run'), table });
|
|
86
|
+
if ((0, args_js_1.flagBool)(flags, 'json'))
|
|
87
|
+
(0, args_js_1.writeJson)(result);
|
|
88
|
+
else
|
|
89
|
+
printResult(result);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
await database.close?.();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function openDatabase(location, dialectFlag) {
|
|
96
|
+
const loaded = await (0, args_js_1.loadModule)(location);
|
|
97
|
+
const client = loaded.client ?? loaded.default;
|
|
98
|
+
if (!client || typeof client !== 'object') {
|
|
99
|
+
throw new args_js_1.CliUsageError(`${location} must export a database client as \`client\`.`);
|
|
100
|
+
}
|
|
101
|
+
const candidate = client;
|
|
102
|
+
const dialect = (dialectFlag ?? loaded.dialect);
|
|
103
|
+
const detected = dialect ??
|
|
104
|
+
(typeof candidate.query === 'function'
|
|
105
|
+
? 'postgres'
|
|
106
|
+
: typeof candidate.prepare === 'function' || typeof candidate.exec === 'function'
|
|
107
|
+
? 'sqlite'
|
|
108
|
+
: undefined);
|
|
109
|
+
if (detected !== 'postgres' && detected !== 'sqlite') {
|
|
110
|
+
throw new args_js_1.CliUsageError(`${location} exports a client this CLI cannot recognize. Export \`dialect\` as "postgres" or "sqlite".`);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
dialect: detected,
|
|
114
|
+
client,
|
|
115
|
+
...(typeof loaded.transaction === 'function'
|
|
116
|
+
? { transaction: loaded.transaction }
|
|
117
|
+
: {}),
|
|
118
|
+
...(Array.isArray(loaded.migrations) ? { migrations: loaded.migrations } : {}),
|
|
119
|
+
...(typeof loaded.close === 'function' ? { close: loaded.close } : {}),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
async function bundledMigrations(dialect, flags) {
|
|
123
|
+
if (dialect === 'postgres') {
|
|
124
|
+
const adapters = postgresAdapters(flags);
|
|
125
|
+
const vectorDimensions = (0, args_js_1.numberFlag)(flags, 'vector-dimensions');
|
|
126
|
+
return (0, index_js_1.postgresMigrations)({
|
|
127
|
+
...(adapters ? { adapters } : {}),
|
|
128
|
+
...(vectorDimensions === undefined ? {} : { vectorDimensions }),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
const adapters = (0, args_js_1.listFlag)(flags, 'adapters');
|
|
132
|
+
const unknown = adapters?.filter((adapter) => !SQLITE_ADAPTERS.includes(adapter));
|
|
133
|
+
if (unknown?.length) {
|
|
134
|
+
throw new args_js_1.CliUsageError(`Unknown SQLite adapter ${unknown.join(', ')}. Choose from ${SQLITE_ADAPTERS.join(', ')}.`);
|
|
135
|
+
}
|
|
136
|
+
const { sqliteMigrations } = await Promise.resolve().then(() => __importStar(require('../sqlite/index.js')));
|
|
137
|
+
return sqliteMigrations(adapters ? { adapters } : {});
|
|
138
|
+
}
|
|
139
|
+
async function statusOf(database, migrations, table) {
|
|
140
|
+
const options = table ? { table } : {};
|
|
141
|
+
if (database.dialect === 'postgres') {
|
|
142
|
+
const { postgresMigrationStatus } = await Promise.resolve().then(() => __importStar(require('../postgres/migrations.js')));
|
|
143
|
+
return postgresMigrationStatus(database.client, migrations, options);
|
|
144
|
+
}
|
|
145
|
+
const { sqliteMigrationStatus } = await Promise.resolve().then(() => __importStar(require('../sqlite/migrations.js')));
|
|
146
|
+
return sqliteMigrationStatus(database.client, migrations, options);
|
|
147
|
+
}
|
|
148
|
+
async function migrate(database, migrations, options) {
|
|
149
|
+
const common = { dryRun: options.dryRun, ...(options.table ? { table: options.table } : {}) };
|
|
150
|
+
if (database.dialect === 'postgres') {
|
|
151
|
+
const { applyPostgresMigrations } = await Promise.resolve().then(() => __importStar(require('../postgres/migrations.js')));
|
|
152
|
+
return applyPostgresMigrations(database.client, migrations, {
|
|
153
|
+
...common,
|
|
154
|
+
...(database.transaction ? { transaction: database.transaction } : {}),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const { applySqliteMigrations } = await Promise.resolve().then(() => __importStar(require('../sqlite/migrations.js')));
|
|
158
|
+
return applySqliteMigrations(database.client, migrations, common);
|
|
159
|
+
}
|
|
160
|
+
function printStatus(status) {
|
|
161
|
+
const changed = new Set(status.changed.map(({ migration }) => `${migration.component}@${migration.version}`));
|
|
162
|
+
const rows = [
|
|
163
|
+
...status.applied
|
|
164
|
+
.filter((row) => !status.unknown.includes(row))
|
|
165
|
+
.map((row) => {
|
|
166
|
+
const key = `${row.component}@${row.version}`;
|
|
167
|
+
return {
|
|
168
|
+
component: row.component,
|
|
169
|
+
version: String(row.version),
|
|
170
|
+
name: row.name,
|
|
171
|
+
state: changed.has(key) ? 'changed' : 'applied',
|
|
172
|
+
applied: row.appliedAt,
|
|
173
|
+
};
|
|
174
|
+
}),
|
|
175
|
+
...status.unknown.map((row) => ({
|
|
176
|
+
component: row.component,
|
|
177
|
+
version: String(row.version),
|
|
178
|
+
name: row.name,
|
|
179
|
+
state: 'newer release',
|
|
180
|
+
applied: row.appliedAt,
|
|
181
|
+
})),
|
|
182
|
+
...status.pending.map((migration) => ({
|
|
183
|
+
component: migration.component,
|
|
184
|
+
version: String(migration.version),
|
|
185
|
+
name: migration.name,
|
|
186
|
+
state: 'pending',
|
|
187
|
+
applied: '',
|
|
188
|
+
})),
|
|
189
|
+
];
|
|
190
|
+
if (rows.length === 0) {
|
|
191
|
+
console.log('No migrations known or recorded.');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
(0, args_js_1.printTable)(rows, ['component', 'version', 'name', 'state', 'applied']);
|
|
195
|
+
console.log(status.current
|
|
196
|
+
? '\nUp to date.'
|
|
197
|
+
: `\n${status.pending.length} pending${status.changed.length ? `, ${status.changed.length} changed after they ran` : ''}. Run: nexus db migrate`);
|
|
198
|
+
}
|
|
199
|
+
function printResult(result) {
|
|
200
|
+
if (result.applied.length === 0) {
|
|
201
|
+
console.log('Nothing to apply: the database is up to date.');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const verb = result.dryRun ? 'Would apply' : 'Applied';
|
|
205
|
+
for (const migration of result.applied)
|
|
206
|
+
console.log(`${verb} ${migration.component} v${migration.version}: ${migration.name}`);
|
|
207
|
+
if (result.dryRun) {
|
|
208
|
+
console.log('\n-- The statements, in order:\n');
|
|
209
|
+
console.log(`${result.statements.join(';\n\n')};`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ParsedArgs } from './args.js';
|
|
2
|
+
/**
|
|
3
|
+
* `nexus doctor` checks a deployment and exits 1 when a check fails, or with `--strict` when one
|
|
4
|
+
* warns. Without `--module` it checks what it can see from the shell: Node.js, packages, credentials,
|
|
5
|
+
* and the model registry. A module reaches the rest, exporting any of:
|
|
6
|
+
*
|
|
7
|
+
* ```js
|
|
8
|
+
* // doctor.mjs
|
|
9
|
+
* export const database = { client: pool }; // or `client` alone, as for nexus db
|
|
10
|
+
* export const redis = new Redis(process.env.REDIS_URL);
|
|
11
|
+
* export const operations = new PostgresOperationStore(pool);
|
|
12
|
+
* export const ai = client;
|
|
13
|
+
* export const deployment = { replicas: 3, stores: { checkpointer, state, tenantUsage } };
|
|
14
|
+
* export const close = async () => { await pool.end(); redis.disconnect(); };
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare function runDoctorCommand({ flags }: ParsedArgs): Promise<void>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runDoctorCommand = runDoctorCommand;
|
|
4
|
+
const index_js_1 = require("../doctor/index.js");
|
|
5
|
+
const args_js_1 = require("./args.js");
|
|
6
|
+
const LABELS = { ok: 'ok ', warn: 'warn', fail: 'FAIL', skip: 'skip' };
|
|
7
|
+
async function runDoctorCommand({ flags }) {
|
|
8
|
+
const location = (0, args_js_1.stringFlag)(flags, 'module');
|
|
9
|
+
const loaded = location ? await (0, args_js_1.loadModule)(location) : {};
|
|
10
|
+
const options = {};
|
|
11
|
+
const source = (0, args_js_1.isRecord)(loaded.database) ? loaded.database : loaded.client ? loaded : undefined;
|
|
12
|
+
if (source?.client) {
|
|
13
|
+
options.database = {
|
|
14
|
+
client: source.client,
|
|
15
|
+
...(source.dialect === 'postgres' || source.dialect === 'sqlite' ? { dialect: source.dialect } : {}),
|
|
16
|
+
...(Array.isArray(source.migrations) ? { migrations: source.migrations } : {}),
|
|
17
|
+
...(typeof source.table === 'string' ? { table: source.table } : {}),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (loaded.redis)
|
|
21
|
+
options.redis = loaded.redis;
|
|
22
|
+
if (loaded.operations)
|
|
23
|
+
options.operations = loaded.operations;
|
|
24
|
+
if (loaded.ai)
|
|
25
|
+
options.ai = loaded.ai;
|
|
26
|
+
if ((0, args_js_1.isRecord)(loaded.deployment))
|
|
27
|
+
options.deployment = loaded.deployment;
|
|
28
|
+
const replicas = (0, args_js_1.numberFlag)(flags, 'replicas');
|
|
29
|
+
if (replicas !== undefined)
|
|
30
|
+
options.deployment = { ...options.deployment, replicas };
|
|
31
|
+
const maxQueueAgeMs = (0, args_js_1.numberFlag)(flags, 'max-queue-age-ms');
|
|
32
|
+
if (maxQueueAgeMs !== undefined)
|
|
33
|
+
options.maxQueueAgeMs = maxQueueAgeMs;
|
|
34
|
+
let report;
|
|
35
|
+
try {
|
|
36
|
+
report = await (0, index_js_1.diagnose)(options);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
if (typeof loaded.close === 'function')
|
|
40
|
+
await loaded.close();
|
|
41
|
+
}
|
|
42
|
+
if ((0, args_js_1.flagBool)(flags, 'json'))
|
|
43
|
+
(0, args_js_1.writeJson)(report);
|
|
44
|
+
else
|
|
45
|
+
print(report);
|
|
46
|
+
if (!report.ok || ((0, args_js_1.flagBool)(flags, 'strict') && report.warnings > 0))
|
|
47
|
+
process.exitCode = 1;
|
|
48
|
+
}
|
|
49
|
+
function print(report) {
|
|
50
|
+
for (const check of report.checks) {
|
|
51
|
+
console.log(`${LABELS[check.status]} ${check.title}: ${check.detail}`);
|
|
52
|
+
if (check.hint && (check.status === 'fail' || check.status === 'warn'))
|
|
53
|
+
console.log(` ${check.hint}`);
|
|
54
|
+
}
|
|
55
|
+
console.log(`\n${report.failures} failed, ${report.warnings} warned, ${report.checks.length - report.failures - report.warnings} passed or skipped.`);
|
|
56
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ParsedArgs } from './args.js';
|
|
2
|
+
/**
|
|
3
|
+
* `nexus graph lint <module>[#export]`.
|
|
4
|
+
*
|
|
5
|
+
* The module exports a compiled graph, or a description of one as `describe()` returns it, as the
|
|
6
|
+
* named export, as `graph`, or as its default. Exits 1 when a finding is an error, or with `--strict`
|
|
7
|
+
* when any finding is a warning too.
|
|
8
|
+
*/
|
|
9
|
+
export declare function runGraphCommand(subcommand: string | undefined, args: ParsedArgs): Promise<void>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runGraphCommand = runGraphCommand;
|
|
4
|
+
const lint_js_1 = require("../graph/lint.js");
|
|
5
|
+
const args_js_1 = require("./args.js");
|
|
6
|
+
async function runGraphCommand(subcommand, args) {
|
|
7
|
+
if (subcommand !== 'lint') {
|
|
8
|
+
throw new args_js_1.CliUsageError(`Unknown graph command "${subcommand ?? ''}". Use lint.`);
|
|
9
|
+
}
|
|
10
|
+
const [target] = args.positionals;
|
|
11
|
+
if (!target)
|
|
12
|
+
throw new args_js_1.CliUsageError('nexus graph lint needs a module: nexus graph lint ./graph.mjs[#exportName].');
|
|
13
|
+
const [file, exportName] = target.split('#');
|
|
14
|
+
const loaded = await (0, args_js_1.loadModule)(file);
|
|
15
|
+
const graph = (exportName ? loaded[exportName] : (loaded.graph ?? loaded.default ?? loaded));
|
|
16
|
+
if (!isLintable(graph)) {
|
|
17
|
+
throw new args_js_1.CliUsageError(`${target} must export a compiled graph, or a graph description, ${exportName ? `as "${exportName}"` : 'as `graph` or its default'}.`);
|
|
18
|
+
}
|
|
19
|
+
const findings = (0, lint_js_1.lintGraph)(graph, {
|
|
20
|
+
deployed: (0, args_js_1.flagBool)(args.flags, 'deployed'),
|
|
21
|
+
ignore: (0, args_js_1.listFlag)(args.flags, 'ignore'),
|
|
22
|
+
});
|
|
23
|
+
const failing = findings.filter((finding) => finding.severity === 'error' || ((0, args_js_1.flagBool)(args.flags, 'strict') && finding.severity === 'warning'));
|
|
24
|
+
if ((0, args_js_1.flagBool)(args.flags, 'json')) {
|
|
25
|
+
(0, args_js_1.writeJson)({ findings, failed: failing.length > 0 });
|
|
26
|
+
}
|
|
27
|
+
else if (findings.length === 0) {
|
|
28
|
+
console.log('No findings.');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
(0, args_js_1.printTable)(findings.map((finding) => ({
|
|
32
|
+
severity: finding.severity,
|
|
33
|
+
code: finding.code,
|
|
34
|
+
node: finding.node ?? '',
|
|
35
|
+
message: finding.message,
|
|
36
|
+
})), ['severity', 'code', 'node', 'message']);
|
|
37
|
+
console.log('');
|
|
38
|
+
for (const finding of findings)
|
|
39
|
+
console.log(`${finding.code}: ${finding.fix}`);
|
|
40
|
+
}
|
|
41
|
+
if (failing.length > 0)
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
}
|
|
44
|
+
function isLintable(value) {
|
|
45
|
+
if (!(0, args_js_1.isRecord)(value))
|
|
46
|
+
return false;
|
|
47
|
+
if (typeof value.describe === 'function')
|
|
48
|
+
return true;
|
|
49
|
+
return Array.isArray(value.nodes) && Array.isArray(value.edges) && Array.isArray(value.dynamic);
|
|
50
|
+
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.OperationLifecycle = exports.BudgetExceededError = exports.OperationDeniedError = exports.LIFECYCLE_STAGES = void 0;
|
|
4
4
|
const rate_limiter_js_1 = require("../ops/rate-limiter.js");
|
|
5
5
|
const ids_js_1 = require("../utils/ids.js");
|
|
6
|
+
const signals_js_1 = require("../utils/signals.js");
|
|
6
7
|
exports.LIFECYCLE_STAGES = [
|
|
7
8
|
'validate',
|
|
8
9
|
'authorize',
|
|
@@ -48,14 +49,15 @@ class OperationLifecycle {
|
|
|
48
49
|
const startedAt = Date.now();
|
|
49
50
|
const timeoutMs = options.timeoutMs ?? this.runtime.timeoutMs;
|
|
50
51
|
const deadline = timeoutMs !== undefined && Number.isFinite(timeoutMs) && timeoutMs > 0 ? startedAt + timeoutMs : undefined;
|
|
52
|
+
const call = callSignal(options.signal, deadline === undefined ? undefined : deadline - startedAt);
|
|
51
53
|
const context = {
|
|
52
54
|
requestId: descriptor.requestId,
|
|
53
|
-
signal:
|
|
55
|
+
signal: call.signal,
|
|
54
56
|
...(deadline !== undefined ? { deadline } : {}),
|
|
55
57
|
...(options.traceContext ? { traceContext: options.traceContext } : {}),
|
|
56
58
|
...(options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}),
|
|
57
59
|
};
|
|
58
|
-
const ticket = new Ticket(this.runtime, descriptor, context, startedAt);
|
|
60
|
+
const ticket = new Ticket(this.runtime, descriptor, context, startedAt, call.dispose);
|
|
59
61
|
try {
|
|
60
62
|
await this.runtime.metrics?.recordRequest(labelsOf(descriptor));
|
|
61
63
|
await this.checkRateLimit(descriptor);
|
|
@@ -110,6 +112,7 @@ class OperationLifecycle {
|
|
|
110
112
|
const bucket = {
|
|
111
113
|
model: descriptor.model ?? `${descriptor.family}:${descriptor.operation}`,
|
|
112
114
|
userId: descriptor.userId,
|
|
115
|
+
tenantId: descriptor.tenantId,
|
|
113
116
|
};
|
|
114
117
|
if (rateLimit.store)
|
|
115
118
|
await rateLimiter.checkAsync(bucket, rateLimit);
|
|
@@ -141,13 +144,15 @@ class Ticket {
|
|
|
141
144
|
descriptor;
|
|
142
145
|
context;
|
|
143
146
|
startedAt;
|
|
147
|
+
release;
|
|
144
148
|
reservation;
|
|
145
149
|
finished = false;
|
|
146
|
-
constructor(runtime, descriptor, context, startedAt) {
|
|
150
|
+
constructor(runtime, descriptor, context, startedAt, release = () => undefined) {
|
|
147
151
|
this.runtime = runtime;
|
|
148
152
|
this.descriptor = descriptor;
|
|
149
153
|
this.context = context;
|
|
150
154
|
this.startedAt = startedAt;
|
|
155
|
+
this.release = release;
|
|
151
156
|
}
|
|
152
157
|
async reserve(estimate) {
|
|
153
158
|
const budget = this.runtime.config?.budget;
|
|
@@ -217,14 +222,14 @@ class Ticket {
|
|
|
217
222
|
});
|
|
218
223
|
}
|
|
219
224
|
async finish(outcome) {
|
|
225
|
+
this.release();
|
|
220
226
|
await runHook(() => this.runtime.config?.hooks?.onFinish?.(this.descriptor, outcome));
|
|
221
227
|
}
|
|
222
228
|
}
|
|
223
229
|
function callSignal(signal, timeoutMs) {
|
|
224
230
|
if (timeoutMs === undefined)
|
|
225
|
-
return signal ?? new AbortController().signal;
|
|
226
|
-
|
|
227
|
-
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
231
|
+
return { signal: signal ?? new AbortController().signal, dispose: () => undefined };
|
|
232
|
+
return (0, signals_js_1.linkSignals)([signal, AbortSignal.timeout(timeoutMs)]);
|
|
228
233
|
}
|
|
229
234
|
function outcomeOf(error, signal) {
|
|
230
235
|
if (error instanceof OperationDeniedError ||
|
package/dist-cjs/core/nexus.d.ts
CHANGED
|
@@ -248,9 +248,13 @@ export declare class NexusAI {
|
|
|
248
248
|
/** Health of every provider seen so far, when health tracking is on. */
|
|
249
249
|
getProviderHealth(): import("../ops/health.js").ProviderHealthSnapshot[];
|
|
250
250
|
/**
|
|
251
|
-
* Calls each provider's health check and records the result.
|
|
251
|
+
* Calls each provider's health check and records the result. With `staleOnly`, only the providers
|
|
252
|
+
* whose health is `unknown` are checked: never called, or not since `health.observationTtlMs`. Run
|
|
253
|
+
* it on a schedule to keep an idle provider's health current.
|
|
252
254
|
*/
|
|
253
|
-
checkProviders(
|
|
255
|
+
checkProviders(options?: {
|
|
256
|
+
staleOnly?: boolean;
|
|
257
|
+
}): Promise<Array<{
|
|
254
258
|
providerName: string;
|
|
255
259
|
ok: boolean;
|
|
256
260
|
error?: string;
|
|
@@ -314,6 +318,12 @@ export declare class NexusAI {
|
|
|
314
318
|
private attachTrace;
|
|
315
319
|
private usesSemanticCache;
|
|
316
320
|
private loadSemanticCache;
|
|
321
|
+
/**
|
|
322
|
+
* Where a request's cached response lives: its key, its namespace, and the scope a semantic match
|
|
323
|
+
* must share, which is always at least the request's tenant.
|
|
324
|
+
*/
|
|
325
|
+
private cachePlan;
|
|
326
|
+
/** Looks a request up in the cache. A cache that fails is reported as an `error` outcome and treated as a miss. */
|
|
317
327
|
private getCachedResponse;
|
|
318
328
|
private setCachedResponse;
|
|
319
329
|
private estimateRequestCost;
|
package/dist-cjs/core/nexus.js
CHANGED
|
@@ -190,13 +190,26 @@ class NexusAI {
|
|
|
190
190
|
}
|
|
191
191
|
await this.applyBudgets(context, ticket);
|
|
192
192
|
const responseFormat = context.request.responseFormat || this.config.responseFormat;
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
const cachePlan = this.isCacheEnabled() ? this.cachePlan(context.request, responseFormat) : undefined;
|
|
194
|
+
let cacheOutcome;
|
|
195
|
+
if (cachePlan && !cachePlan.read) {
|
|
196
|
+
cacheOutcome = {
|
|
197
|
+
outcome: 'bypass',
|
|
198
|
+
reason: context.request.responseCache === 'refresh'
|
|
199
|
+
? 'the request asked for a fresh answer'
|
|
200
|
+
: 'the request skipped the cache',
|
|
201
|
+
...(cachePlan.namespace ? { namespace: cachePlan.namespace } : {}),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
if (cachePlan?.read) {
|
|
205
|
+
const plan = cachePlan;
|
|
206
|
+
const lookup = await this.pipeline.trace(context, 'cacheLookup', () => this.getCachedResponse(plan, context.request));
|
|
207
|
+
cacheOutcome = lookup.outcome;
|
|
208
|
+
const cached = lookup.response;
|
|
196
209
|
if (cached) {
|
|
197
210
|
let cachedResponse = this.attachTrace({
|
|
198
211
|
...cached,
|
|
199
|
-
meta: { ...cached.meta, requestId: ticket.descriptor.requestId, cacheHit: true },
|
|
212
|
+
meta: { ...cached.meta, requestId: ticket.descriptor.requestId, cacheHit: true, cache: lookup.outcome },
|
|
200
213
|
}, this.pipeline.finish(context));
|
|
201
214
|
if (this.isSecurityEnabled()) {
|
|
202
215
|
const outputResult = this.security.protectOutput(cachedResponse);
|
|
@@ -258,12 +271,24 @@ class NexusAI {
|
|
|
258
271
|
});
|
|
259
272
|
context.response = formattedResponse;
|
|
260
273
|
}
|
|
261
|
-
if (
|
|
274
|
+
if (cachePlan?.write) {
|
|
262
275
|
const responseToCache = context.response;
|
|
263
276
|
if (!responseToCache) {
|
|
264
277
|
throw new Error('Cannot cache an empty response.');
|
|
265
278
|
}
|
|
266
|
-
|
|
279
|
+
const plan = cachePlan;
|
|
280
|
+
try {
|
|
281
|
+
await this.pipeline.trace(context, 'cacheWrite', () => this.setCachedResponse(plan, context.request, responseToCache));
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
cacheOutcome = {
|
|
285
|
+
...(cacheOutcome ?? { outcome: 'miss', reason: 'no entry for this request' }),
|
|
286
|
+
writeError: error instanceof Error ? error.message : String(error),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (cacheOutcome && context.response) {
|
|
291
|
+
context.response = { ...context.response, meta: { ...context.response.meta, cache: cacheOutcome } };
|
|
267
292
|
}
|
|
268
293
|
context = await this.pipeline.runHook('beforeReturn', context);
|
|
269
294
|
let responseToReturn = context.response;
|
|
@@ -583,9 +608,11 @@ class NexusAI {
|
|
|
583
608
|
getProviderHealth() {
|
|
584
609
|
return this.health.snapshot();
|
|
585
610
|
}
|
|
586
|
-
async checkProviders() {
|
|
611
|
+
async checkProviders(options = {}) {
|
|
587
612
|
const results = [];
|
|
588
613
|
for (const [providerName, provider] of this.providers) {
|
|
614
|
+
if (options.staleOnly && !this.health.isUnknown(providerName))
|
|
615
|
+
continue;
|
|
589
616
|
const started = Date.now();
|
|
590
617
|
try {
|
|
591
618
|
const ok = await provider.healthCheck();
|
|
@@ -828,35 +855,86 @@ class NexusAI {
|
|
|
828
855
|
});
|
|
829
856
|
return this.semanticCacheLoading;
|
|
830
857
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
858
|
+
cachePlan(request, responseFormat) {
|
|
859
|
+
const configured = this.config.cache?.namespace;
|
|
860
|
+
const chosen = typeof configured === 'function' ? configured(request) : configured;
|
|
861
|
+
const namespace = chosen ? namespaceKey({ ...chosen, tenant: chosen.tenant ?? request.tenantId }) : undefined;
|
|
862
|
+
const base = (0, memory_cache_js_1.createCacheKey)({ request: { ...request, responseCache: undefined }, responseFormat });
|
|
863
|
+
return {
|
|
864
|
+
key: namespace ? `${namespace}\u0000${base}` : base,
|
|
865
|
+
...(namespace ? { namespace } : {}),
|
|
866
|
+
scope: namespace ?? namespaceKey({ tenant: request.tenantId }),
|
|
867
|
+
read: request.responseCache === undefined,
|
|
868
|
+
write: request.responseCache !== 'bypass',
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
async getCachedResponse(plan, request) {
|
|
872
|
+
const namespace = plan.namespace ? { namespace: plan.namespace } : {};
|
|
873
|
+
const cache = this.config.cache ?? {};
|
|
874
|
+
let layer = this.usesSemanticCache() ? 'semantic' : 'exact';
|
|
875
|
+
try {
|
|
876
|
+
if (this.usesSemanticCache()) {
|
|
877
|
+
const semantic = await (await this.loadSemanticCache()).get(request, plan.scope);
|
|
878
|
+
if (semantic) {
|
|
879
|
+
return {
|
|
880
|
+
response: semantic,
|
|
881
|
+
outcome: { outcome: 'hit', layer: 'semantic', reason: 'a similar request was answered', ...namespace },
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
if (cache.strategy === 'semantic') {
|
|
885
|
+
return {
|
|
886
|
+
outcome: {
|
|
887
|
+
outcome: 'miss',
|
|
888
|
+
layer: 'semantic',
|
|
889
|
+
reason: 'no similar request above the threshold',
|
|
890
|
+
...namespace,
|
|
891
|
+
},
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
layer = 'exact';
|
|
896
|
+
if (cache.adapter) {
|
|
897
|
+
const value = (await cache.adapter.get(plan.key));
|
|
898
|
+
return value
|
|
899
|
+
? { response: value, outcome: { outcome: 'hit', layer, reason: 'this request was answered', ...namespace } }
|
|
900
|
+
: { outcome: { outcome: 'miss', layer, reason: 'no entry for this request', ...namespace } };
|
|
901
|
+
}
|
|
902
|
+
const { value, stale } = this.cache.lookup(plan.key);
|
|
903
|
+
if (value) {
|
|
904
|
+
return {
|
|
905
|
+
response: value,
|
|
906
|
+
outcome: { outcome: 'hit', layer, reason: 'this request was answered', ...namespace },
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
return stale
|
|
910
|
+
? { outcome: { outcome: 'stale', layer, reason: 'the entry for this request had expired', ...namespace } }
|
|
911
|
+
: { outcome: { outcome: 'miss', layer, reason: 'no entry for this request', ...namespace } };
|
|
838
912
|
}
|
|
839
|
-
|
|
840
|
-
return
|
|
841
|
-
|
|
842
|
-
|
|
913
|
+
catch (error) {
|
|
914
|
+
return {
|
|
915
|
+
outcome: {
|
|
916
|
+
outcome: 'error',
|
|
917
|
+
layer,
|
|
918
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
919
|
+
...namespace,
|
|
920
|
+
},
|
|
921
|
+
};
|
|
843
922
|
}
|
|
844
|
-
return this.cache.get(cacheKey);
|
|
845
923
|
}
|
|
846
|
-
async setCachedResponse(
|
|
924
|
+
async setCachedResponse(plan, request, response) {
|
|
847
925
|
if (!this.config.cache?.enabled)
|
|
848
926
|
return;
|
|
849
927
|
const ttl = this.config.cache.ttlSeconds || 300;
|
|
850
928
|
if (this.usesSemanticCache()) {
|
|
851
|
-
await (await this.loadSemanticCache()).set(
|
|
929
|
+
await (await this.loadSemanticCache()).set(plan.key, request, response, plan.scope);
|
|
852
930
|
}
|
|
853
931
|
if (this.config.cache.strategy === 'semantic')
|
|
854
932
|
return;
|
|
855
933
|
if (this.config.cache.adapter) {
|
|
856
|
-
await this.config.cache.adapter.set(
|
|
934
|
+
await this.config.cache.adapter.set(plan.key, response, ttl);
|
|
857
935
|
return;
|
|
858
936
|
}
|
|
859
|
-
this.cache.set(
|
|
937
|
+
this.cache.set(plan.key, response, ttl);
|
|
860
938
|
}
|
|
861
939
|
estimateRequestCost(request) {
|
|
862
940
|
return (0, cost_js_1.estimateCost)({
|
|
@@ -891,3 +969,8 @@ function streamStopped() {
|
|
|
891
969
|
error.name = 'AbortError';
|
|
892
970
|
return error;
|
|
893
971
|
}
|
|
972
|
+
function namespaceKey(namespace) {
|
|
973
|
+
return [namespace.tenant, namespace.environment, namespace.modelRevision, namespace.contextVersion]
|
|
974
|
+
.map((part) => encodeURIComponent(part ?? ''))
|
|
975
|
+
.join('/');
|
|
976
|
+
}
|