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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { GraphStreamProjection } from '../types/graph.js';
|
|
1
2
|
import type { AssistantRunContext, ServerAssistant } from '../types/server.js';
|
|
2
3
|
/**
|
|
3
4
|
* The part of a compiled graph the adapter uses.
|
|
@@ -11,11 +12,15 @@ export interface GraphLike {
|
|
|
11
12
|
threadId?: string;
|
|
12
13
|
signal?: AbortSignal;
|
|
13
14
|
metadata?: Record<string, unknown>;
|
|
15
|
+
tenantId?: string;
|
|
16
|
+
control?: DrainSwitch;
|
|
14
17
|
}): AsyncIterable<unknown>;
|
|
15
18
|
/** Answers an interrupt and continues the thread. */
|
|
16
19
|
resume(threadId: string, value: unknown, options: {
|
|
17
20
|
signal?: AbortSignal;
|
|
18
21
|
metadata?: Record<string, unknown>;
|
|
22
|
+
tenantId?: string;
|
|
23
|
+
control?: DrainSwitch;
|
|
19
24
|
}): AsyncIterable<unknown>;
|
|
20
25
|
/** The thread's checkpoint, at its latest step or at one given. */
|
|
21
26
|
state(threadId: string, step?: number): Promise<{
|
|
@@ -28,18 +33,56 @@ export interface GraphLike {
|
|
|
28
33
|
continue?(threadId: string, options: {
|
|
29
34
|
signal?: AbortSignal;
|
|
30
35
|
metadata?: Record<string, unknown>;
|
|
36
|
+
tenantId?: string;
|
|
37
|
+
control?: DrainSwitch;
|
|
31
38
|
}): AsyncIterable<unknown>;
|
|
32
39
|
/** Writes values into a thread's state, which is how a rollback is applied. */
|
|
33
40
|
updateState?(threadId: string, values: Record<string, unknown>, options?: {
|
|
34
41
|
asNode?: string;
|
|
35
42
|
}): Promise<unknown>;
|
|
43
|
+
/** Runs an input as a stream of typed events. Used when the assistant serves `events`. */
|
|
44
|
+
events?(input: unknown, options: GraphEventOptionsLike): GraphEventsLike;
|
|
45
|
+
/** Like `events()`, answering an interrupt. */
|
|
46
|
+
resumeEvents?(threadId: string, value: unknown, options: GraphEventOptionsLike): GraphEventsLike;
|
|
47
|
+
/** Like `events()`, continuing a thread from its latest checkpoint. */
|
|
48
|
+
continueEvents?(threadId: string, options: GraphEventOptionsLike): GraphEventsLike;
|
|
36
49
|
}
|
|
50
|
+
/** The options of a graph's `events()` the adapter passes. */
|
|
51
|
+
type GraphEventOptionsLike = {
|
|
52
|
+
threadId?: string;
|
|
53
|
+
tenantId?: string;
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
metadata?: Record<string, unknown>;
|
|
56
|
+
control?: DrainSwitch;
|
|
57
|
+
include?: GraphStreamProjection[];
|
|
58
|
+
};
|
|
59
|
+
/** A graph's event stream, as the adapter reads it: the events, then the run's result. */
|
|
60
|
+
type GraphEventsLike = AsyncIterable<unknown> & {
|
|
61
|
+
result: Promise<{
|
|
62
|
+
status: string;
|
|
63
|
+
state: unknown;
|
|
64
|
+
interrupt?: unknown;
|
|
65
|
+
interrupts?: unknown[];
|
|
66
|
+
}>;
|
|
67
|
+
};
|
|
68
|
+
/** Asks a graph to stop after its current superstep. A graph's `RunControl` has this shape. */
|
|
69
|
+
type DrainSwitch = {
|
|
70
|
+
readonly draining: boolean;
|
|
71
|
+
readonly reason?: string;
|
|
72
|
+
};
|
|
37
73
|
/** Options for `graphAssistant()`. */
|
|
38
74
|
export interface GraphAssistantOptions {
|
|
39
75
|
/** What the assistant is, reported by the assistants endpoint. */
|
|
40
76
|
description?: string;
|
|
41
77
|
/** Metadata recorded on every checkpoint the server's runs create. */
|
|
42
78
|
metadata?: Record<string, unknown>;
|
|
79
|
+
/**
|
|
80
|
+
* Records these projections of the graph's event stream on each run, such as `messages` and
|
|
81
|
+
* `tools`, so a client following the run sees model output and tool calls as they happen. The
|
|
82
|
+
* run's last event still carries its state and any question, as without it. Defaults to none: one
|
|
83
|
+
* event per superstep.
|
|
84
|
+
*/
|
|
85
|
+
events?: GraphStreamProjection[];
|
|
43
86
|
}
|
|
44
87
|
/**
|
|
45
88
|
* Serves a compiled graph as an assistant.
|
|
@@ -61,3 +104,4 @@ export declare function graphAssistant(graph: GraphLike, options?: GraphAssistan
|
|
|
61
104
|
export declare function functionAssistant(run: (input: unknown, context: AssistantRunContext) => AsyncIterable<unknown> | Promise<unknown> | unknown, options?: {
|
|
62
105
|
description?: string;
|
|
63
106
|
}): ServerAssistant;
|
|
107
|
+
export {};
|
package/dist/server/assistant.js
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
export function graphAssistant(graph, options = {}) {
|
|
2
|
+
const projections = options.events?.length ? options.events : undefined;
|
|
3
|
+
const eventOptions = (context, threadId) => ({
|
|
4
|
+
...(threadId ? { threadId } : {}),
|
|
5
|
+
signal: context.signal,
|
|
6
|
+
metadata: { ...options.metadata, runId: context.runId },
|
|
7
|
+
...tenantOf(context),
|
|
8
|
+
...(context.control ? { control: context.control } : {}),
|
|
9
|
+
include: [...(projections ?? []), 'values'],
|
|
10
|
+
});
|
|
2
11
|
return {
|
|
3
12
|
description: options.description,
|
|
4
13
|
stream(input, context) {
|
|
14
|
+
if (projections && graph.events) {
|
|
15
|
+
return withResult(graph.events(input ?? {}, eventOptions(context, context.threadId)));
|
|
16
|
+
}
|
|
5
17
|
return graph.stream(input ?? {}, {
|
|
6
18
|
threadId: context.threadId,
|
|
7
19
|
signal: context.signal,
|
|
8
20
|
metadata: { ...options.metadata, runId: context.runId },
|
|
21
|
+
...tenantOf(context),
|
|
22
|
+
...(context.control ? { control: context.control } : {}),
|
|
9
23
|
});
|
|
10
24
|
},
|
|
11
25
|
resume(threadId, value, context) {
|
|
26
|
+
if (projections && graph.resumeEvents) {
|
|
27
|
+
return withResult(graph.resumeEvents(threadId, value, eventOptions(context)));
|
|
28
|
+
}
|
|
12
29
|
return graph.resume(threadId, value, {
|
|
13
30
|
signal: context.signal,
|
|
14
31
|
metadata: { ...options.metadata, runId: context.runId },
|
|
32
|
+
...tenantOf(context),
|
|
33
|
+
...(context.control ? { control: context.control } : {}),
|
|
15
34
|
});
|
|
16
35
|
},
|
|
17
36
|
async state(threadId) {
|
|
@@ -29,9 +48,13 @@ export function graphAssistant(graph, options = {}) {
|
|
|
29
48
|
if (checkpoint.status !== 'running' && checkpoint.status !== 'failed' && checkpoint.status !== 'interrupted') {
|
|
30
49
|
return undefined;
|
|
31
50
|
}
|
|
51
|
+
if (projections && graph.continueEvents)
|
|
52
|
+
return withResult(graph.continueEvents(threadId, eventOptions(context)));
|
|
32
53
|
return graph.continue(threadId, {
|
|
33
54
|
signal: context.signal,
|
|
34
55
|
metadata: { ...options.metadata, runId: context.runId },
|
|
56
|
+
...tenantOf(context),
|
|
57
|
+
...(context.control ? { control: context.control } : {}),
|
|
35
58
|
});
|
|
36
59
|
},
|
|
37
60
|
async restore(threadId, step) {
|
|
@@ -57,3 +80,19 @@ export function functionAssistant(run, options = {}) {
|
|
|
57
80
|
},
|
|
58
81
|
};
|
|
59
82
|
}
|
|
83
|
+
function tenantOf(context) {
|
|
84
|
+
const tenantId = context.principal?.tenantId;
|
|
85
|
+
return tenantId ? { tenantId } : {};
|
|
86
|
+
}
|
|
87
|
+
async function* withResult(events) {
|
|
88
|
+
for await (const event of events)
|
|
89
|
+
yield event;
|
|
90
|
+
const result = await events.result;
|
|
91
|
+
yield {
|
|
92
|
+
type: result.status === 'awaiting_input' ? 'interrupt' : 'done',
|
|
93
|
+
status: result.status,
|
|
94
|
+
state: result.state,
|
|
95
|
+
...(result.interrupt === undefined ? {} : { interrupt: result.interrupt }),
|
|
96
|
+
...(result.interrupts === undefined ? {} : { interrupts: result.interrupts }),
|
|
97
|
+
};
|
|
98
|
+
}
|
package/dist/server/errors.d.ts
CHANGED
|
@@ -32,6 +32,18 @@ export declare class ForbiddenError extends ServerError {
|
|
|
32
32
|
/** The scope the route required. */
|
|
33
33
|
scope: string);
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Thrown by an assistant to hand its run to another worker while this replica drains: the server puts
|
|
37
|
+
* the run back on the queue as its next attempt instead of failing it. A function assistant checks
|
|
38
|
+
* `context.control?.draining` between its own steps, saves where it got with `context.saveProgress()`,
|
|
39
|
+
* and throws this; the next worker reads `context.progress`. Thrown when the replica is not draining,
|
|
40
|
+
* it fails the run like any error.
|
|
41
|
+
*/
|
|
42
|
+
export declare class RunHandOffError extends Error {
|
|
43
|
+
/** Always `RUN_HANDED_OFF`. */
|
|
44
|
+
readonly code = "RUN_HANDED_OFF";
|
|
45
|
+
constructor(message?: string);
|
|
46
|
+
}
|
|
35
47
|
/** Raised when a thread is already running something and the busy policy is `reject`. */
|
|
36
48
|
export declare class ThreadBusyError extends ServerError {
|
|
37
49
|
/** The thread. */
|
package/dist/server/errors.js
CHANGED
|
@@ -35,6 +35,13 @@ export class ForbiddenError extends ServerError {
|
|
|
35
35
|
this.name = 'ForbiddenError';
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
export class RunHandOffError extends Error {
|
|
39
|
+
code = 'RUN_HANDED_OFF';
|
|
40
|
+
constructor(message = 'Handed to another worker while this one drains') {
|
|
41
|
+
super(message);
|
|
42
|
+
this.name = 'RunHandOffError';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
38
45
|
export class ThreadBusyError extends ServerError {
|
|
39
46
|
threadId;
|
|
40
47
|
runId;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export { functionAssistant, type GraphAssistantOptions, graphAssistant, type GraphLike, } from './assistant.js';
|
|
11
11
|
export { CronScheduler, type CronSchedulerOptions, type DueCronJob, parseCron } from './cron.js';
|
|
12
|
-
export { AssistantCapabilityError, BadRequestError, ForbiddenError, NotFoundError, ServerError, type TenantLimit, TenantLimitError, ThreadBusyError, UnauthorizedError, } from './errors.js';
|
|
12
|
+
export { AssistantCapabilityError, BadRequestError, ForbiddenError, NotFoundError, RunHandOffError, ServerError, type TenantLimit, TenantLimitError, ThreadBusyError, UnauthorizedError, } from './errors.js';
|
|
13
13
|
export { MemoryRunEventLog, type MemoryRunEventLogOptions, type RedisEventLogLikeClient, RedisRunEventLog, type RedisRunEventLogOptions, } from './events.js';
|
|
14
14
|
export { type NodeListenerOptions, type NodeRequestLike, type NodeResponseLike, toNodeListener, } from './node.js';
|
|
15
15
|
export { type DrainResult, RunManager, type RunManagerOptions, type RunQueueOptions, type StartRunOptions, } from './runs.js';
|
package/dist/server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { functionAssistant, graphAssistant, } from './assistant.js';
|
|
2
2
|
export { CronScheduler, parseCron } from './cron.js';
|
|
3
|
-
export { AssistantCapabilityError, BadRequestError, ForbiddenError, NotFoundError, ServerError, TenantLimitError, ThreadBusyError, UnauthorizedError, } from './errors.js';
|
|
3
|
+
export { AssistantCapabilityError, BadRequestError, ForbiddenError, NotFoundError, RunHandOffError, ServerError, TenantLimitError, ThreadBusyError, UnauthorizedError, } from './errors.js';
|
|
4
4
|
export { MemoryRunEventLog, RedisRunEventLog, } from './events.js';
|
|
5
5
|
export { toNodeListener, } from './node.js';
|
|
6
6
|
export { RunManager, } from './runs.js';
|
package/dist/server/runs.d.ts
CHANGED
|
@@ -97,6 +97,10 @@ export declare class RunManager {
|
|
|
97
97
|
private readonly local;
|
|
98
98
|
/** Runs holding one of this replica's execution slots. */
|
|
99
99
|
private readonly slots;
|
|
100
|
+
/** The drain switch of each run this replica is executing, so `drain()` can reach graph runs. */
|
|
101
|
+
private readonly controls;
|
|
102
|
+
/** Runs handed back to the queue during a drain, as each graph run stopped at a boundary. */
|
|
103
|
+
private readonly drainedRuns;
|
|
100
104
|
private readonly state;
|
|
101
105
|
private readonly events;
|
|
102
106
|
private readonly now;
|
|
@@ -155,6 +159,8 @@ export declare class RunManager {
|
|
|
155
159
|
* it with a `TenantLimitError`.
|
|
156
160
|
*/
|
|
157
161
|
start(options: StartRunOptions): Promise<RunRecord>;
|
|
162
|
+
/** The rest of `start()`, once the thread, if any, is this run's. */
|
|
163
|
+
private startClaimed;
|
|
158
164
|
/** Cancels a run, including one another replica is executing. */
|
|
159
165
|
cancel(runId: string, principal?: Principal, reason?: string): Promise<RunRecord>;
|
|
160
166
|
/**
|
|
@@ -206,8 +212,29 @@ export declare class RunManager {
|
|
|
206
212
|
private freeSlot;
|
|
207
213
|
private schedule;
|
|
208
214
|
private tick;
|
|
209
|
-
/**
|
|
215
|
+
/**
|
|
216
|
+
* Applies the busy policy, returning the thread once this run holds it. The thread is claimed
|
|
217
|
+
* atomically, so of several replicas starting runs on one thread at once, exactly one proceeds and
|
|
218
|
+
* the rest meet the policy; a thread still busy after the policy has run its course is refused.
|
|
219
|
+
*/
|
|
210
220
|
private settleBusyThread;
|
|
221
|
+
/**
|
|
222
|
+
* Claims a thread for a run. The claim is a record in the operation store under a unique
|
|
223
|
+
* idempotency key, moved from run to run by compare-and-set, so two replicas cannot both take a free
|
|
224
|
+
* thread: creating it races on the key, and taking it over races on the sequence. Resolves
|
|
225
|
+
* undefined once this run holds the thread, or the id of the unfinished run that does.
|
|
226
|
+
*
|
|
227
|
+
* A store without `findByIdempotencyKey` falls back to the thread record's `activeRunId`, which is
|
|
228
|
+
* what every release before 2.2 used, and which two replicas racing can both see empty.
|
|
229
|
+
*/
|
|
230
|
+
private claimThread;
|
|
231
|
+
/**
|
|
232
|
+
* Whether a thread's holder no longer needs it: its run finished, or it was never recorded and its
|
|
233
|
+
* claim is old enough that the replica starting it must have died.
|
|
234
|
+
*/
|
|
235
|
+
private runIsFree;
|
|
236
|
+
/** Frees a thread this run holds. Losing the compare-and-set means another run took it over, which is fine. */
|
|
237
|
+
private releaseClaim;
|
|
211
238
|
/** Waits for a run to finish, for the `enqueue` policy. */
|
|
212
239
|
private waitForRun;
|
|
213
240
|
private releaseThread;
|
package/dist/server/runs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OperationReleasedError } from '../operations/errors.js';
|
|
1
|
+
import { OperationDuplicateError, OperationReleasedError } from '../operations/errors.js';
|
|
2
2
|
import { OperationRunner } from '../operations/runner.js';
|
|
3
3
|
import { operationStats } from '../operations/stats.js';
|
|
4
4
|
import { MemoryOperationStore } from '../operations/store.js';
|
|
@@ -9,6 +9,8 @@ import { MemoryServerStore, RUNS_NAMESPACE } from './state.js';
|
|
|
9
9
|
const THREADS = ['nexus', 'server', 'threads'];
|
|
10
10
|
const RUNS = RUNS_NAMESPACE;
|
|
11
11
|
const KIND_PREFIX = 'assistant:';
|
|
12
|
+
const THREAD_CLAIM = 'nexus-thread:';
|
|
13
|
+
const UNRECORDED_CLAIM_MS = 60_000;
|
|
12
14
|
const DEFAULT_CONCURRENCY = 10;
|
|
13
15
|
const DEFAULT_POLL_MS = 1_000;
|
|
14
16
|
const DEFAULT_RECOVER_MS = 30_000;
|
|
@@ -26,6 +28,8 @@ export class RunManager {
|
|
|
26
28
|
store;
|
|
27
29
|
local = new Map();
|
|
28
30
|
slots = new Set();
|
|
31
|
+
controls = new Map();
|
|
32
|
+
drainedRuns = new Set();
|
|
29
33
|
state;
|
|
30
34
|
events;
|
|
31
35
|
now;
|
|
@@ -118,12 +122,22 @@ export class RunManager {
|
|
|
118
122
|
}
|
|
119
123
|
async start(options) {
|
|
120
124
|
const base = this.assistant(options.assistant);
|
|
125
|
+
const runId = `run-${randomId()}`;
|
|
121
126
|
let thread;
|
|
122
127
|
if (options.threadId) {
|
|
123
128
|
thread = await this.thread(options.threadId, options.principal);
|
|
124
|
-
thread = await this.settleBusyThread(thread, options);
|
|
129
|
+
thread = await this.settleBusyThread(thread, options, runId);
|
|
125
130
|
}
|
|
126
|
-
|
|
131
|
+
try {
|
|
132
|
+
return await this.startClaimed(runId, base, thread, options);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (thread)
|
|
136
|
+
await this.releaseClaim(thread.id, runId).catch((cause) => this.report(cause, { runId }));
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async startClaimed(runId, base, thread, options) {
|
|
127
141
|
let assistant = base;
|
|
128
142
|
let revision;
|
|
129
143
|
if (base.route) {
|
|
@@ -217,11 +231,18 @@ export class RunManager {
|
|
|
217
231
|
async drain(options = {}) {
|
|
218
232
|
this.draining = true;
|
|
219
233
|
this.stopWorking();
|
|
234
|
+
if (this.options.queue) {
|
|
235
|
+
for (const control of this.controls.values()) {
|
|
236
|
+
control.draining = true;
|
|
237
|
+
control.reason = 'replica draining';
|
|
238
|
+
}
|
|
239
|
+
}
|
|
220
240
|
const running = [...this.slots];
|
|
221
241
|
const deadline = Date.now() + (options.timeoutMs ?? 25_000);
|
|
222
242
|
while (this.slots.size > 0 && Date.now() < deadline)
|
|
223
243
|
await pause(Math.min(50, deadline - Date.now()));
|
|
224
|
-
const released = [];
|
|
244
|
+
const released = [...this.drainedRuns];
|
|
245
|
+
this.drainedRuns.clear();
|
|
225
246
|
if (this.options.queue) {
|
|
226
247
|
for (const id of [...this.slots]) {
|
|
227
248
|
if (this.runner.release(id))
|
|
@@ -341,6 +362,8 @@ export class RunManager {
|
|
|
341
362
|
acceptedId = (await this.runner.enqueue(submit)).id;
|
|
342
363
|
}
|
|
343
364
|
if (acceptedId !== runId) {
|
|
365
|
+
if (thread)
|
|
366
|
+
await this.releaseClaim(thread.id, runId);
|
|
344
367
|
await this.state.delete(RUNS, runId);
|
|
345
368
|
await this.releaseTenant(runId, options.principal?.tenantId);
|
|
346
369
|
return (await this.state.get(RUNS, acceptedId)) ?? run;
|
|
@@ -374,14 +397,18 @@ export class RunManager {
|
|
|
374
397
|
async execute(plan, context) {
|
|
375
398
|
const runId = context.operationId;
|
|
376
399
|
let cost = 0;
|
|
400
|
+
const control = { draining: false };
|
|
377
401
|
const runContext = {
|
|
378
402
|
runId,
|
|
379
403
|
threadId: plan.threadId,
|
|
380
404
|
signal: context.signal,
|
|
405
|
+
control,
|
|
381
406
|
principal: plan.principal,
|
|
382
407
|
metadata: plan.metadata,
|
|
383
408
|
attempt: context.attempt,
|
|
384
409
|
...(plan.revision ? { revision: plan.revision.id } : {}),
|
|
410
|
+
saveProgress: (details) => context.heartbeat(details),
|
|
411
|
+
...(context.previousHeartbeat === undefined ? {} : { progress: context.previousHeartbeat }),
|
|
385
412
|
recordCost: async (usd) => {
|
|
386
413
|
if (!Number.isFinite(usd) || usd <= 0)
|
|
387
414
|
return;
|
|
@@ -411,6 +438,7 @@ export class RunManager {
|
|
|
411
438
|
? plan.assistant.resume(plan.threadId, plan.resume, runContext)
|
|
412
439
|
: plan.assistant.stream(plan.input, runContext));
|
|
413
440
|
let last;
|
|
441
|
+
this.controls.set(runId, control);
|
|
414
442
|
try {
|
|
415
443
|
for await (const event of stream) {
|
|
416
444
|
last = event;
|
|
@@ -419,6 +447,8 @@ export class RunManager {
|
|
|
419
447
|
}
|
|
420
448
|
}
|
|
421
449
|
catch (error) {
|
|
450
|
+
if (control.draining && isDrained(error) && this.runner.release(runId))
|
|
451
|
+
this.drainedRuns.add(runId);
|
|
422
452
|
if (context.signal.aborted && context.signal.reason instanceof OperationReleasedError) {
|
|
423
453
|
await this.record(runId, 'status', { status: 'queued', reason: 'handed to another worker' });
|
|
424
454
|
await this.settle(runId, 'queued', { addCost: cost });
|
|
@@ -439,6 +469,9 @@ export class RunManager {
|
|
|
439
469
|
await this.releaseTenant(runId, plan.principal?.tenantId);
|
|
440
470
|
throw error;
|
|
441
471
|
}
|
|
472
|
+
finally {
|
|
473
|
+
this.controls.delete(runId);
|
|
474
|
+
}
|
|
442
475
|
const interrupt = interruptOf(last);
|
|
443
476
|
const status = interrupt ? 'awaiting_input' : 'succeeded';
|
|
444
477
|
const output = outputOf(last);
|
|
@@ -517,21 +550,21 @@ export class RunManager {
|
|
|
517
550
|
const pollMs = this.options.queue?.pollMs ?? DEFAULT_POLL_MS;
|
|
518
551
|
this.schedule(claimed > 0 && this.freeSlots() > 0 ? 0 : Math.min(pollMs, this.options.recoverEveryMs ?? pollMs));
|
|
519
552
|
}
|
|
520
|
-
async settleBusyThread(thread, options) {
|
|
553
|
+
async settleBusyThread(thread, options, runId) {
|
|
521
554
|
const policy = options.onBusy ?? this.options.onBusy ?? 'reject';
|
|
522
555
|
let current = thread;
|
|
523
|
-
|
|
524
|
-
|
|
556
|
+
const deadline = this.now().getTime() + (this.options.queueTimeoutMs ?? 30_000);
|
|
557
|
+
for (let attempt = 0; attempt < 4 || (policy === 'enqueue' && this.now().getTime() < deadline); attempt += 1) {
|
|
558
|
+
const activeId = await this.claimThread(current, runId);
|
|
525
559
|
if (!activeId)
|
|
526
560
|
return current;
|
|
527
561
|
const active = await this.state.get(RUNS, activeId);
|
|
528
|
-
if (!active || isFinished(active.status)) {
|
|
529
|
-
current = { ...current, activeRunId: undefined };
|
|
530
|
-
await this.state.put(THREADS, current.id, current);
|
|
531
|
-
return current;
|
|
532
|
-
}
|
|
533
562
|
if (policy === 'reject')
|
|
534
563
|
throw new ThreadBusyError(current.id, activeId);
|
|
564
|
+
if (!active) {
|
|
565
|
+
await delay(50);
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
535
568
|
if (policy === 'enqueue') {
|
|
536
569
|
await this.waitForRun(activeId);
|
|
537
570
|
current = await this.thread(current.id, options.principal);
|
|
@@ -548,9 +581,67 @@ export class RunManager {
|
|
|
548
581
|
}
|
|
549
582
|
current = { ...current, activeRunId: undefined };
|
|
550
583
|
await this.state.put(THREADS, current.id, current);
|
|
551
|
-
return current;
|
|
552
584
|
}
|
|
553
|
-
|
|
585
|
+
throw new ThreadBusyError(current.id, current.activeRunId ?? 'another run');
|
|
586
|
+
}
|
|
587
|
+
async claimThread(thread, runId) {
|
|
588
|
+
if (!this.store.findByIdempotencyKey) {
|
|
589
|
+
const activeId = thread.activeRunId;
|
|
590
|
+
return activeId && !(await this.runIsFree(activeId, undefined)) ? activeId : undefined;
|
|
591
|
+
}
|
|
592
|
+
const key = `${THREAD_CLAIM}${thread.id}`;
|
|
593
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
594
|
+
const claim = await this.store.findByIdempotencyKey(key);
|
|
595
|
+
const at = this.now().toISOString();
|
|
596
|
+
if (!claim) {
|
|
597
|
+
try {
|
|
598
|
+
await this.store.create({
|
|
599
|
+
id: `${key}:${runId}`,
|
|
600
|
+
status: 'succeeded',
|
|
601
|
+
attempt: 1,
|
|
602
|
+
maxAttempts: 1,
|
|
603
|
+
sequence: 0,
|
|
604
|
+
createdAt: at,
|
|
605
|
+
updatedAt: at,
|
|
606
|
+
kind: 'server.thread',
|
|
607
|
+
idempotencyKey: key,
|
|
608
|
+
result: { runId },
|
|
609
|
+
});
|
|
610
|
+
return undefined;
|
|
611
|
+
}
|
|
612
|
+
catch (error) {
|
|
613
|
+
if (error instanceof OperationDuplicateError)
|
|
614
|
+
continue;
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
const holder = claim.result?.runId;
|
|
619
|
+
if (holder === runId)
|
|
620
|
+
return undefined;
|
|
621
|
+
if (holder && !(await this.runIsFree(holder, claim.updatedAt)))
|
|
622
|
+
return holder;
|
|
623
|
+
const taken = await this.store.update({ ...claim, result: { runId }, sequence: claim.sequence + 1, updatedAt: at }, claim.sequence);
|
|
624
|
+
if (taken)
|
|
625
|
+
return undefined;
|
|
626
|
+
}
|
|
627
|
+
const holder = (await this.store.findByIdempotencyKey(key))?.result?.runId;
|
|
628
|
+
return holder ?? 'another run';
|
|
629
|
+
}
|
|
630
|
+
async runIsFree(runId, claimedAt) {
|
|
631
|
+
const run = await this.state.get(RUNS, runId);
|
|
632
|
+
if (run)
|
|
633
|
+
return isFinished(run.status);
|
|
634
|
+
if (claimedAt === undefined)
|
|
635
|
+
return true;
|
|
636
|
+
return this.now().getTime() - Date.parse(claimedAt) > UNRECORDED_CLAIM_MS;
|
|
637
|
+
}
|
|
638
|
+
async releaseClaim(threadId, runId) {
|
|
639
|
+
if (!this.store.findByIdempotencyKey)
|
|
640
|
+
return;
|
|
641
|
+
const claim = await this.store.findByIdempotencyKey(`${THREAD_CLAIM}${threadId}`);
|
|
642
|
+
if (!claim || claim.result?.runId !== runId)
|
|
643
|
+
return;
|
|
644
|
+
await this.store.update({ ...claim, result: {}, sequence: claim.sequence + 1, updatedAt: this.now().toISOString() }, claim.sequence);
|
|
554
645
|
}
|
|
555
646
|
async waitForRun(runId) {
|
|
556
647
|
const deadline = this.now().getTime() + (this.options.queueTimeoutMs ?? 30_000);
|
|
@@ -567,6 +658,7 @@ export class RunManager {
|
|
|
567
658
|
async releaseThread(threadId, runId) {
|
|
568
659
|
if (!threadId)
|
|
569
660
|
return;
|
|
661
|
+
await this.releaseClaim(threadId, runId).catch((error) => this.report(error, { runId }));
|
|
570
662
|
const thread = await this.state.get(THREADS, threadId);
|
|
571
663
|
if (!thread || thread.activeRunId !== runId)
|
|
572
664
|
return;
|
|
@@ -660,3 +752,7 @@ function delay(ms) {
|
|
|
660
752
|
timer.unref?.();
|
|
661
753
|
});
|
|
662
754
|
}
|
|
755
|
+
function isDrained(error) {
|
|
756
|
+
const code = typeof error === 'object' && error !== null ? error.code : undefined;
|
|
757
|
+
return code === 'GRAPH_DRAINED' || code === 'RUN_HANDED_OFF';
|
|
758
|
+
}
|
package/dist/sqlite/index.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
+
import type { SchemaMigration } from '../utils/schema-migrations.js';
|
|
2
|
+
export { type AppliedMigration, type MigrationResult, type MigrationStatus, migrationChecksum, type SchemaMigration, SchemaMigrationError, } from '../utils/schema-migrations.js';
|
|
1
3
|
export { fromLibsql, fromSqliteDatabase, type LibsqlLikeClient, type SqliteDatabaseLike, type SqliteLikeClient, type SqliteValue, } from './client.js';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
4
|
+
export { applySqliteMigrations, type SqliteMigrateOptions, sqliteMigrationStatus } from './migrations.js';
|
|
5
|
+
export { SqliteOperationStore, type SqliteOperationStoreOptions, sqliteOperationStoreMigration, sqliteOperationStoreMigrations, } from './operations.js';
|
|
6
|
+
export { SqliteStore, type SqliteStoreOptions, sqliteStoreMigration, sqliteStoreMigrations } from './store.js';
|
|
7
|
+
export { SqliteVectorStore, type SqliteVectorStoreOptions, sqliteVectorStoreMigration, sqliteVectorStoreMigrations, } from './vectors.js';
|
|
8
|
+
/** The SQLite adapters a migration can include. */
|
|
9
|
+
export type SqliteAdapter = 'operations' | 'store' | 'vectors';
|
|
10
|
+
/**
|
|
11
|
+
* The versioned migrations of the chosen adapters on their default tables, for
|
|
12
|
+
* `applySqliteMigrations()`, `sqliteMigrationStatus()`, and `nexus db migrate`. Defaults to every
|
|
13
|
+
* adapter. A store on a custom table migrates through its own `migrate()`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sqliteMigrations(options?: {
|
|
16
|
+
adapters?: readonly SqliteAdapter[];
|
|
17
|
+
}): SchemaMigration[];
|
package/dist/sqlite/index.js
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
|
+
import { sqliteOperationStoreMigrations } from './operations.js';
|
|
2
|
+
import { sqliteStoreMigrations } from './store.js';
|
|
3
|
+
import { sqliteVectorStoreMigrations } from './vectors.js';
|
|
4
|
+
export { migrationChecksum, SchemaMigrationError, } from '../utils/schema-migrations.js';
|
|
1
5
|
export { fromLibsql, fromSqliteDatabase, } from './client.js';
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
6
|
+
export { applySqliteMigrations, sqliteMigrationStatus } from './migrations.js';
|
|
7
|
+
export { SqliteOperationStore, sqliteOperationStoreMigration, sqliteOperationStoreMigrations, } from './operations.js';
|
|
8
|
+
export { SqliteStore, sqliteStoreMigration, sqliteStoreMigrations } from './store.js';
|
|
9
|
+
export { SqliteVectorStore, sqliteVectorStoreMigration, sqliteVectorStoreMigrations, } from './vectors.js';
|
|
10
|
+
export function sqliteMigrations(options = {}) {
|
|
11
|
+
const adapters = new Set(options.adapters ?? ['operations', 'store', 'vectors']);
|
|
12
|
+
return [
|
|
13
|
+
...(adapters.has('operations') ? sqliteOperationStoreMigrations() : []),
|
|
14
|
+
...(adapters.has('store') ? sqliteStoreMigrations() : []),
|
|
15
|
+
...(adapters.has('vectors') ? sqliteVectorStoreMigrations() : []),
|
|
16
|
+
];
|
|
17
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type MigrationResult, type MigrationStatus, type SchemaMigration } from '../utils/schema-migrations.js';
|
|
2
|
+
import { type SqliteDatabaseLike, type SqliteLikeClient } from './client.js';
|
|
3
|
+
export { type AppliedMigration, type MigrationResult, type MigrationStatus, migrationChecksum, type SchemaMigration, SchemaMigrationError, } from '../utils/schema-migrations.js';
|
|
4
|
+
/** Options for applying or inspecting SQLite migrations. */
|
|
5
|
+
export interface SqliteMigrateOptions {
|
|
6
|
+
/** Plans without writing anything, not even the table that records migrations. */
|
|
7
|
+
dryRun?: boolean;
|
|
8
|
+
/** The table that records applied migrations. Defaults to `nexus_schema_migrations`. */
|
|
9
|
+
table?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Where a SQLite database stands against a list of migrations. Reads only: on a database that has
|
|
13
|
+
* never been migrated, everything is pending.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sqliteMigrationStatus(database: SqliteLikeClient | SqliteDatabaseLike, migrations: readonly SchemaMigration[], options?: Pick<SqliteMigrateOptions, 'table'>): Promise<MigrationStatus>;
|
|
16
|
+
/**
|
|
17
|
+
* Applies the pending migrations in order, recording each with a checksum.
|
|
18
|
+
*
|
|
19
|
+
* Each migration runs inside `BEGIN IMMEDIATE`, which takes SQLite's write lock: its statements and
|
|
20
|
+
* the row recording it land together or not at all, and a second process migrating the same file
|
|
21
|
+
* waits for the first instead of interleaving with it. A migration whose statements changed after it
|
|
22
|
+
* ran is refused before anything is written.
|
|
23
|
+
*/
|
|
24
|
+
export declare function applySqliteMigrations(database: SqliteLikeClient | SqliteDatabaseLike, migrations: readonly SchemaMigration[], options?: SqliteMigrateOptions): Promise<MigrationResult>;
|
|
25
|
+
/** The statement that creates the migrations table, which `migrate()` runs first. */
|
|
26
|
+
export declare function sqliteMigrationsTableStatement(table?: string): string;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { assertUnchanged, MIGRATIONS_TABLE, migrationChecksum, planMigrations, sqlLiteral, } from '../utils/schema-migrations.js';
|
|
2
|
+
import { quoteSqliteTable, toSqliteClient } from './client.js';
|
|
3
|
+
export { migrationChecksum, SchemaMigrationError, } from '../utils/schema-migrations.js';
|
|
4
|
+
export async function sqliteMigrationStatus(database, migrations, options = {}) {
|
|
5
|
+
return planMigrations(migrations, await readApplied(toSqliteClient(database), options.table ?? MIGRATIONS_TABLE));
|
|
6
|
+
}
|
|
7
|
+
export async function applySqliteMigrations(database, migrations, options = {}) {
|
|
8
|
+
const client = toSqliteClient(database);
|
|
9
|
+
const tableName = options.table ?? MIGRATIONS_TABLE;
|
|
10
|
+
if (options.dryRun) {
|
|
11
|
+
const status = await sqliteMigrationStatus(client, migrations, options);
|
|
12
|
+
assertUnchanged(status);
|
|
13
|
+
return { applied: status.pending, statements: status.pending.flatMap((m) => [...m.statements]), dryRun: true };
|
|
14
|
+
}
|
|
15
|
+
planMigrations(migrations, []);
|
|
16
|
+
await client.exec(sqliteMigrationsTableStatement(tableName));
|
|
17
|
+
const status = planMigrations(migrations, await readApplied(client, tableName));
|
|
18
|
+
assertUnchanged(status);
|
|
19
|
+
const table = quoteSqliteTable(tableName);
|
|
20
|
+
const statements = [];
|
|
21
|
+
for (const migration of status.pending) {
|
|
22
|
+
const record = `INSERT OR IGNORE INTO ${table} (component, version, name, checksum, applied_at) VALUES (${sqlLiteral(migration.component)}, ${migration.version}, ${sqlLiteral(migration.name)}, ${sqlLiteral(migrationChecksum(migration))}, ${sqlLiteral(new Date().toISOString())})`;
|
|
23
|
+
const script = ['BEGIN IMMEDIATE', ...migration.statements, record, 'COMMIT'].join(';\n');
|
|
24
|
+
try {
|
|
25
|
+
await client.exec(`${script};`);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
try {
|
|
29
|
+
await client.exec('ROLLBACK');
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
statements.push(...migration.statements);
|
|
36
|
+
}
|
|
37
|
+
return { applied: status.pending, statements, dryRun: false };
|
|
38
|
+
}
|
|
39
|
+
export function sqliteMigrationsTableStatement(table = MIGRATIONS_TABLE) {
|
|
40
|
+
return `CREATE TABLE IF NOT EXISTS ${quoteSqliteTable(table)} (
|
|
41
|
+
component TEXT NOT NULL,
|
|
42
|
+
version INTEGER NOT NULL,
|
|
43
|
+
name TEXT NOT NULL,
|
|
44
|
+
checksum TEXT NOT NULL,
|
|
45
|
+
applied_at TEXT NOT NULL,
|
|
46
|
+
PRIMARY KEY (component, version)
|
|
47
|
+
)`;
|
|
48
|
+
}
|
|
49
|
+
async function readApplied(client, table) {
|
|
50
|
+
const exists = (await client.all(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?`, [
|
|
51
|
+
table,
|
|
52
|
+
]));
|
|
53
|
+
if (exists.length === 0)
|
|
54
|
+
return [];
|
|
55
|
+
const rows = (await client.all(`SELECT component, version, name, checksum, applied_at FROM ${quoteSqliteTable(table)} ORDER BY applied_at, component, version`, []));
|
|
56
|
+
return rows.map((row) => ({
|
|
57
|
+
component: String(row.component),
|
|
58
|
+
version: Number(row.version),
|
|
59
|
+
name: String(row.name),
|
|
60
|
+
checksum: String(row.checksum),
|
|
61
|
+
appliedAt: String(row.applied_at),
|
|
62
|
+
}));
|
|
63
|
+
}
|