@tenetkit/pg 0.40.1 → 0.41.2
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/dist/postgres/{event-stream.d.ts → events/event-stream.d.ts} +2 -2
- package/dist/postgres/{event-stream.js → events/event-stream.js} +2 -2
- package/dist/postgres/{transaction-events.d.ts → events/transaction-events.d.ts} +2 -2
- package/dist/postgres/{transaction-events.js → events/transaction-events.js} +4 -4
- package/dist/postgres/run-schema.js +6 -6
- package/dist/postgres/{claims.d.ts → runs/claims.d.ts} +2 -2
- package/dist/postgres/{claims.js → runs/claims.js} +1 -1
- package/dist/postgres/{locks.d.ts → runs/locks.d.ts} +1 -1
- package/dist/postgres/{locks.js → runs/locks.js} +2 -2
- package/dist/postgres/runtime-layer.d.ts +4 -5
- package/dist/postgres/runtime-layer.js +9 -9
- package/dist/postgres/{session-cancellation.js → sessions/session-cancellation.js} +1 -1
- package/dist/postgres/{session-storage.d.ts → sessions/session-storage.d.ts} +4 -3
- package/dist/postgres/{session-storage.js → sessions/session-storage.js} +1 -1
- package/dist/postgres/{session-store.d.ts → sessions/session-store.d.ts} +5 -5
- package/dist/postgres/{session-store.js → sessions/session-store.js} +46 -40
- package/dist/postgres/{store-admit.d.ts → store/admit.d.ts} +2 -2
- package/dist/postgres/{store-admit.js → store/admit.js} +6 -6
- package/dist/postgres/{store-cancel.d.ts → store/cancel.d.ts} +1 -1
- package/dist/postgres/{store-cancel.js → store/cancel.js} +42 -46
- package/dist/postgres/{store-claims.d.ts → store/claims.d.ts} +3 -3
- package/dist/postgres/{store-claims.js → store/claims.js} +9 -7
- package/dist/postgres/{store-fan-out.d.ts → store/fan-out.d.ts} +2 -2
- package/dist/postgres/{store-fan-out.js → store/fan-out.js} +2 -2
- package/dist/postgres/{store.d.ts → store/index.d.ts} +7 -4
- package/dist/postgres/{store.js → store/index.js} +56 -54
- package/dist/postgres/{store-inspection.d.ts → store/inspection.d.ts} +3 -3
- package/dist/postgres/{store-inspection.js → store/inspection.js} +10 -10
- package/dist/postgres/{store-messaging.d.ts → store/messaging.d.ts} +2 -2
- package/dist/postgres/{store-messaging.js → store/messaging.js} +1 -1
- package/dist/postgres/{store-model-response.d.ts → store/model-response.d.ts} +4 -4
- package/dist/postgres/{store-model-response.js → store/model-response.js} +46 -38
- package/dist/postgres/{store-ops.d.ts → store/ops.d.ts} +4 -4
- package/dist/postgres/{store-ops.js → store/ops.js} +102 -94
- package/dist/postgres/{store-program.d.ts → store/program.d.ts} +2 -2
- package/dist/postgres/{store-program.js → store/program.js} +5 -5
- package/dist/postgres/{pg-helpers.d.ts → store/runtime.d.ts} +18 -12
- package/dist/postgres/{pg-helpers.js → store/runtime.js} +49 -48
- package/dist/postgres/{store-suspend.d.ts → store/suspend.d.ts} +1 -1
- package/dist/postgres/{store-suspend.js → store/suspend.js} +14 -14
- package/package.json +2 -2
- /package/dist/postgres/{session-cancellation.d.ts → sessions/session-cancellation.d.ts} +0 -0
|
@@ -2,10 +2,10 @@ import { Effect, Stream } from "effect";
|
|
|
2
2
|
import type { PgClient } from "@effect/sql-pg";
|
|
3
3
|
import type { Cursor } from "tenetkit/runtime/driver/cursor";
|
|
4
4
|
import type { CursorExpired, RunNotFound, RuntimeUnavailable, SubscriberLagged } from "tenetkit/runtime/driver/errors";
|
|
5
|
-
import type { RunEvent } from "tenetkit/runtime/driver/run
|
|
5
|
+
import type { RunEvent } from "tenetkit/runtime/driver/run/event";
|
|
6
6
|
import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
|
|
7
7
|
type EventsError = CursorExpired | RunNotFound | RuntimeUnavailable | SubscriberLagged;
|
|
8
|
-
export declare const
|
|
8
|
+
export declare const eventStream: (input: {
|
|
9
9
|
readonly hub: EventHub;
|
|
10
10
|
readonly pg: PgClient.PgClient;
|
|
11
11
|
readonly runId: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, Schedule, Stream, SynchronizedRef } from "effect";
|
|
2
|
-
import { NOTIFY_CHANNEL } from "
|
|
3
|
-
export const
|
|
2
|
+
import { NOTIFY_CHANNEL } from "../schema.js";
|
|
3
|
+
export const eventStream = (input) => Stream.unwrap(Effect.gen(function* () {
|
|
4
4
|
const cursor = yield* SynchronizedRef.make(input.cursor);
|
|
5
5
|
const catchUp = SynchronizedRef.modifyEffect(cursor, (current) => input.loadAfter(current).pipe(Effect.flatMap((events) => Effect.forEach(events, (event) => input.hub.publish(input.runId, event)).pipe(Effect.as(events.at(-1)?.sequence ?? current))), Effect.map((last) => [last, last]))).pipe(Effect.ignore);
|
|
6
6
|
return input.hub.subscribe({
|
|
@@ -2,8 +2,8 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { PgClient } from "@effect/sql-pg";
|
|
3
3
|
import { SqlClient } from "effect/unstable/sql";
|
|
4
4
|
import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
|
|
5
|
-
import type { RunFn } from "
|
|
6
|
-
export declare const
|
|
5
|
+
import type { RunFn } from "../store/ops.js";
|
|
6
|
+
export declare const transactionRunner: (input: {
|
|
7
7
|
readonly sql: SqlClient.SqlClient;
|
|
8
8
|
readonly pg: PgClient.PgClient;
|
|
9
9
|
readonly hub: EventHub;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Context, Effect, Random } from "effect";
|
|
2
2
|
import { PgClient } from "@effect/sql-pg";
|
|
3
3
|
import { SqlClient } from "effect/unstable/sql";
|
|
4
|
-
import { withSql } from "tenetkit/runtime/driver/sql/
|
|
5
|
-
import { NOTIFY_CHANNEL } from "
|
|
6
|
-
const TransactionEvents = Context.Reference("tenetkit/runtime/sql/postgres/TransactionEvents", { defaultValue: () => [] });
|
|
7
|
-
export const
|
|
4
|
+
import { withSql } from "tenetkit/runtime/driver/sql/effect";
|
|
5
|
+
import { NOTIFY_CHANNEL } from "../schema.js";
|
|
6
|
+
const TransactionEvents = Context.Reference("tenetkit/runtime/driver/sql/postgres/TransactionEvents", { defaultValue: () => [] });
|
|
7
|
+
export const transactionRunner = (input) => {
|
|
8
8
|
const transactionHub = {
|
|
9
9
|
...input.hub,
|
|
10
10
|
publish: (runId, event) => Effect.flatMap(TransactionEvents, (events) => Effect.sync(() => void events.push([runId, event]))),
|
|
@@ -2,11 +2,11 @@ import { Cause, DateTime, Effect, Layer, Redacted } from "effect";
|
|
|
2
2
|
import { Migrator, SqlClient } from "effect/unstable/sql";
|
|
3
3
|
import { PgClient } from "@effect/sql-pg";
|
|
4
4
|
import { SchemaChecksumMismatch, SchemaDirty, SchemaMigrationFailed, SchemaUpgradeRequired, SchemaVersionUnsupported, } from "tenetkit/runtime/driver/sql/errors";
|
|
5
|
-
import { mapSqlError } from "tenetkit/runtime/driver/sql/
|
|
5
|
+
import { mapSqlError } from "tenetkit/runtime/driver/sql/effect";
|
|
6
6
|
import { MIGRATION_NAME, MIGRATIONS_TABLE, SCHEMA_META_TABLE, SCHEMA_STATEMENTS, SCHEMA_TABLES, SCHEMA_VERSION, schemaChecksum, } from "./schema.js";
|
|
7
7
|
const migrationFailure = (source, fallback) => (error) => SchemaMigrationFailed.make({
|
|
8
8
|
source,
|
|
9
|
-
message:
|
|
9
|
+
message: error.message || fallback,
|
|
10
10
|
});
|
|
11
11
|
const readMeta = (source) => mapSqlError(Effect.gen(function* () {
|
|
12
12
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -24,10 +24,10 @@ const readMeta = (source) => mapSqlError(Effect.gen(function* () {
|
|
|
24
24
|
const row = rows[0];
|
|
25
25
|
if (row === undefined)
|
|
26
26
|
return { version: 0, checksum: "", dirty: false, present: false };
|
|
27
|
-
return { version:
|
|
27
|
+
return { version: row.version, checksum: row.checksum, dirty: row.dirty, present: true };
|
|
28
28
|
})).pipe(Effect.mapError((error) => SchemaMigrationFailed.make({
|
|
29
29
|
source,
|
|
30
|
-
message: "message" in error ?
|
|
30
|
+
message: "message" in error ? error.message : "schema meta read failed",
|
|
31
31
|
})));
|
|
32
32
|
const verifyMigrationIdentity = (source) => Effect.gen(function* () {
|
|
33
33
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -90,7 +90,7 @@ export const apply = (source) => Effect.gen(function* () {
|
|
|
90
90
|
SELECT COUNT(*) AS present FROM information_schema.tables
|
|
91
91
|
WHERE table_schema = current_schema() AND table_name IN ${sql.in(SCHEMA_TABLES)}
|
|
92
92
|
`;
|
|
93
|
-
if (
|
|
93
|
+
if ((existing[0]?.present ?? 0) > 0) {
|
|
94
94
|
return yield* SchemaMigrationFailed.make({
|
|
95
95
|
source,
|
|
96
96
|
message: "cannot create the baseline over an existing TenetKit schema",
|
|
@@ -104,7 +104,7 @@ export const markDirty = (source) => mapSqlError(Effect.gen(function* () {
|
|
|
104
104
|
yield* sql `UPDATE ${sql(SCHEMA_META_TABLE)} SET dirty = TRUE WHERE id = 1`;
|
|
105
105
|
})).pipe(Effect.mapError((error) => SchemaMigrationFailed.make({
|
|
106
106
|
source,
|
|
107
|
-
message: "message" in error ?
|
|
107
|
+
message: "message" in error ? error.message : "failed to mark schema dirty",
|
|
108
108
|
})));
|
|
109
109
|
export const RunSchema = { plan, check, apply, markDirty };
|
|
110
110
|
export const layerClient = (url) => PgClient.layer({ url: Redacted.make(url) });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Duration, Effect } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/unstable/sql";
|
|
3
3
|
import { StaleClaim } from "tenetkit/runtime/driver/sql/errors";
|
|
4
|
-
import type { ClaimedRun } from "tenetkit/runtime/driver/sql/run
|
|
4
|
+
import type { ClaimedRun } from "tenetkit/runtime/driver/sql/run/claims";
|
|
5
5
|
export interface ClaimOptions {
|
|
6
6
|
readonly workerId: string;
|
|
7
7
|
readonly limit: number;
|
|
@@ -19,7 +19,7 @@ export declare const requireClaim: (input: {
|
|
|
19
19
|
readonly runId: string;
|
|
20
20
|
readonly workerId: string;
|
|
21
21
|
readonly attemptFence: number;
|
|
22
|
-
}) => Effect.Effect<import("tenetkit/runtime/driver/sql/rows").DecodedRun, import("tenetkit/runtime/driver/errors").RuntimeUnavailable | import("effect/unstable/sql/SqlError").SqlError | StaleClaim, SqlClient.SqlClient>;
|
|
22
|
+
}) => Effect.Effect<import("tenetkit/runtime/driver/sql/codec/rows").DecodedRun, import("tenetkit/runtime/driver/errors").RuntimeUnavailable | import("effect/unstable/sql/SqlError").SqlError | StaleClaim, SqlClient.SqlClient>;
|
|
23
23
|
export declare const releaseClaim: (input: {
|
|
24
24
|
readonly runId: string;
|
|
25
25
|
readonly workerId: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Clock, DateTime, Duration, Effect } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/unstable/sql";
|
|
3
3
|
import { StaleClaim } from "tenetkit/runtime/driver/sql/errors";
|
|
4
|
-
import { decodeRunEffect, loadRun } from "tenetkit/runtime/driver/sql/store
|
|
4
|
+
import { decodeRunEffect, loadRun } from "tenetkit/runtime/driver/sql/store/statements";
|
|
5
5
|
export const claimReadyRuns = (options) => Effect.gen(function* () {
|
|
6
6
|
const sql = yield* SqlClient.SqlClient;
|
|
7
7
|
const leaseMs = Duration.toMillis(options.lease);
|
|
@@ -15,4 +15,4 @@ export declare const lockRunHierarchy: (runId: string) => Effect.Effect<void, im
|
|
|
15
15
|
* on the target rather than on any one sender's Run.
|
|
16
16
|
*/
|
|
17
17
|
export declare const lockMailbox: (targetSessionId: string) => Effect.Effect<void, import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
|
|
18
|
-
export declare const lockSpawnParent: (runId: string) => Effect.Effect<import("tenetkit/runtime/driver/sql/rows").DecodedRun, RunNotFound | RunTerminal | import("tenetkit/runtime/driver/errors").RuntimeUnavailable | import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
|
|
18
|
+
export declare const lockSpawnParent: (runId: string) => Effect.Effect<import("tenetkit/runtime/driver/sql/codec/rows").DecodedRun, RunNotFound | RunTerminal | import("tenetkit/runtime/driver/errors").RuntimeUnavailable | import("effect/unstable/sql/SqlError").SqlError, SqlClient.SqlClient>;
|
|
@@ -2,7 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { SqlClient } from "effect/unstable/sql";
|
|
3
3
|
import { RunNotFound, RunTerminal } from "tenetkit/runtime/driver/errors";
|
|
4
4
|
import { isTerminal } from "tenetkit/runtime/driver/run";
|
|
5
|
-
import { loadRun } from "
|
|
5
|
+
import { loadRun } from "../store/runtime.js";
|
|
6
6
|
/**
|
|
7
7
|
* One Run-level lock serializing admission, steering, response, resume, timeout,
|
|
8
8
|
* cancellation, and terminal settlement. Always taken advisory-first, then row,
|
|
@@ -26,7 +26,7 @@ export const lockRunHierarchy = (runId) => Effect.gen(function* () {
|
|
|
26
26
|
hierarchy.push(row.parent_run_id);
|
|
27
27
|
current = row.parent_run_id;
|
|
28
28
|
}
|
|
29
|
-
for (const id of hierarchy.
|
|
29
|
+
for (const id of hierarchy.toReversed())
|
|
30
30
|
yield* lockRun(id);
|
|
31
31
|
});
|
|
32
32
|
/**
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Layer } from "effect";
|
|
2
2
|
import type { SqlError } from "effect/unstable/sql/SqlError";
|
|
3
|
-
import { Runtime } from "tenetkit/runtime/driver/
|
|
4
|
-
import { RunStore } from "tenetkit/runtime/driver/run
|
|
5
|
-
import { RunClaims } from "tenetkit/runtime/driver/sql/run
|
|
6
|
-
import { ExecutionHost } from "tenetkit/runtime/driver/execution
|
|
7
|
-
import type { LayerOptions } from "tenetkit/runtime/driver/runtime";
|
|
3
|
+
import { Runtime, type LayerOptions } from "tenetkit/runtime/driver/service";
|
|
4
|
+
import { RunStore } from "tenetkit/runtime/driver/run/store";
|
|
5
|
+
import { RunClaims } from "tenetkit/runtime/driver/sql/run/claims";
|
|
6
|
+
import { ExecutionHost } from "tenetkit/runtime/driver/execution/host";
|
|
8
7
|
import { SchemaMigrationFailed, type SchemaChecksumMismatch, type SchemaDirty, type SchemaUpgradeRequired, type SchemaVersionUnsupported } from "tenetkit/runtime/driver/sql/errors";
|
|
9
8
|
export interface PostgresStoreOptions extends LayerOptions {
|
|
10
9
|
readonly url: string;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Context, Effect, Layer, Redacted } from "effect";
|
|
2
2
|
import { PgClient } from "@effect/sql-pg";
|
|
3
|
-
import { makeRuntime } from "tenetkit/runtime/driver/memory/
|
|
4
|
-
import { Runtime } from "tenetkit/runtime/driver/
|
|
5
|
-
import { RunStore } from "tenetkit/runtime/driver/run
|
|
6
|
-
import { RunClaims } from "tenetkit/runtime/driver/sql/run
|
|
7
|
-
import {
|
|
8
|
-
import { ExecutionHost, make as makeExecutionHost } from "tenetkit/runtime/driver/execution
|
|
9
|
-
import { layer as activeExecutionsLayer } from "tenetkit/runtime/driver/active-executions";
|
|
10
|
-
import { layer as modelPreviewLayer } from "tenetkit/runtime/driver/model-preview";
|
|
3
|
+
import { makeRuntime } from "tenetkit/runtime/driver/memory/layer";
|
|
4
|
+
import { Runtime } from "tenetkit/runtime/driver/service";
|
|
5
|
+
import { RunStore } from "tenetkit/runtime/driver/run/store";
|
|
6
|
+
import { RunClaims } from "tenetkit/runtime/driver/sql/run/claims";
|
|
7
|
+
import { postgresServices } from "./store/index.js";
|
|
8
|
+
import { ExecutionHost, make as makeExecutionHost } from "tenetkit/runtime/driver/execution/host";
|
|
9
|
+
import { layer as activeExecutionsLayer } from "tenetkit/runtime/driver/execution/active-executions";
|
|
10
|
+
import { layer as modelPreviewLayer } from "tenetkit/runtime/driver/execution/model-response/preview";
|
|
11
11
|
import { SchemaMigrationFailed, } from "tenetkit/runtime/driver/sql/errors";
|
|
12
12
|
export const layerPostgres = (options) => {
|
|
13
13
|
const maxConnections = options.maxConnections ?? 10;
|
|
@@ -20,7 +20,7 @@ export const layerPostgres = (options) => {
|
|
|
20
20
|
}
|
|
21
21
|
return PgClient.layer({ url: Redacted.make(options.url), maxConnections });
|
|
22
22
|
}));
|
|
23
|
-
const services = Layer.effectContext(
|
|
23
|
+
const services = Layer.effectContext(postgresServices(options).pipe(Effect.map(({ store, claims }) => Context.make(RunStore, store).pipe(Context.add(RunClaims, claims))))).pipe(Layer.provide(client));
|
|
24
24
|
const dependencies = Layer.mergeAll(services, activeExecutionsLayer, modelPreviewLayer);
|
|
25
25
|
const runtime = Layer.effect(Runtime, makeRuntime(options)).pipe(Layer.provide(dependencies));
|
|
26
26
|
const host = Layer.effect(ExecutionHost, makeExecutionHost({ workerId: "postgres", resolver: options.resolver })).pipe(Layer.provide(dependencies));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
import { activeSessionRuns, sessionRoots, sessionRuns } from "tenetkit/runtime/driver/sql/session
|
|
2
|
+
import { activeSessionRuns, sessionRoots, sessionRuns } from "tenetkit/runtime/driver/sql/session/lifecycle";
|
|
3
3
|
export const cancelSessionRuns = (input) => Effect.gen(function* () {
|
|
4
4
|
const roots = yield* sessionRoots(input.sessionId);
|
|
5
5
|
const runs = yield* sessionRuns(input.sessionId);
|
|
@@ -2,7 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { Session } from "tenetkit";
|
|
3
3
|
import { SqlClient } from "effect/unstable/sql";
|
|
4
4
|
import type { SqlError } from "effect/unstable/sql/SqlError";
|
|
5
|
-
import { type EntryRow, type SessionRow } from "tenetkit/runtime/driver/sql/session
|
|
5
|
+
import { type EntryRow, type SessionRow } from "tenetkit/runtime/driver/sql/session/store";
|
|
6
6
|
declare const insertEntry: (input: {
|
|
7
7
|
readonly sessionId: string;
|
|
8
8
|
readonly id: string;
|
|
@@ -17,7 +17,7 @@ declare const advanceSession: (input: {
|
|
|
17
17
|
readonly nextSeq: number;
|
|
18
18
|
readonly ownerToken?: string;
|
|
19
19
|
}) => Effect.Effect<void, SqlError, SqlClient.SqlClient>;
|
|
20
|
-
|
|
20
|
+
interface PostgresSessionStorage {
|
|
21
21
|
readonly encodePayload: (payload: Session.EntryPayload) => string;
|
|
22
22
|
readonly entryPayloadEquivalence: (self: Session.EntryPayload, that: Session.EntryPayload) => boolean;
|
|
23
23
|
readonly storeError: (message: string) => Session.SessionStoreError;
|
|
@@ -28,5 +28,6 @@ export declare const PostgresSessionStorage: {
|
|
|
28
28
|
readonly requireActive: (rows: ReadonlyArray<EntryRow>, leaf: string | null, entryId: string, reason?: "stale-leaf" | "checkpoint-not-on-active-path") => Session.SessionConflict | undefined;
|
|
29
29
|
readonly insertEntry: typeof insertEntry;
|
|
30
30
|
readonly advanceSession: typeof advanceSession;
|
|
31
|
-
}
|
|
31
|
+
}
|
|
32
|
+
export declare const PostgresSessionStorage: PostgresSessionStorage;
|
|
32
33
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { Session } from "tenetkit";
|
|
3
3
|
import { SqlClient } from "effect/unstable/sql";
|
|
4
|
-
import { SessionStorage } from "tenetkit/runtime/driver/sql/session
|
|
4
|
+
import { SessionStorage } from "tenetkit/runtime/driver/sql/session/store";
|
|
5
5
|
const { encodePayload, entryPayloadEquivalence, pathFromRows, requireActive, storeError, toEntry } = SessionStorage;
|
|
6
6
|
const lockSession = (sessionId) => Effect.gen(function* () {
|
|
7
7
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -2,10 +2,10 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { Session } from "tenetkit";
|
|
3
3
|
import { SqlClient } from "effect/unstable/sql";
|
|
4
4
|
import type { SqlError } from "effect/unstable/sql/SqlError";
|
|
5
|
-
import type { CompletedSessionEntry } from "tenetkit/runtime/driver/model-response
|
|
6
|
-
import type { InterruptedSessionEntry } from "tenetkit/runtime/driver/agent
|
|
7
|
-
import { type HandoffSessionEntry } from "tenetkit/runtime/driver/handoff
|
|
8
|
-
import type { RunFn } from "
|
|
5
|
+
import type { CompletedSessionEntry } from "tenetkit/runtime/driver/execution/model-response/commit";
|
|
6
|
+
import type { InterruptedSessionEntry } from "tenetkit/runtime/driver/execution/agent/event";
|
|
7
|
+
import { type HandoffSessionEntry } from "tenetkit/runtime/driver/session/handoff";
|
|
8
|
+
import type { RunFn } from "../store/ops.js";
|
|
9
9
|
/** Append or verify one exact completed assistant projection in the caller's PostgreSQL transaction. */
|
|
10
10
|
export declare const appendCompletedSessionEntry: (input: CompletedSessionEntry) => Effect.Effect<Session.Entry, Session.SessionConflict | Session.SessionStoreError | SqlError, SqlClient.SqlClient>;
|
|
11
11
|
/** Verify an exact completed assistant projection in the caller's PostgreSQL transaction. */
|
|
@@ -17,7 +17,7 @@ export declare const verifyInterruptedSessionEntry: (input: InterruptedSessionEn
|
|
|
17
17
|
export declare const appendHandoffSessionEntry: (input: HandoffSessionEntry) => Effect.Effect<Session.HandoffEntry, Session.SessionConflict | Session.SessionStoreError | SqlError, SqlClient.SqlClient>;
|
|
18
18
|
export declare const verifyHandoffSessionEntry: (input: HandoffSessionEntry) => Effect.Effect<void, Session.SessionConflict | Session.SessionStoreError | SqlError, SqlClient.SqlClient>;
|
|
19
19
|
/** Dialect-native durable PostgreSQL Session authority bound to one session identity. */
|
|
20
|
-
export declare const
|
|
20
|
+
export declare const postgresSessionStore: (options: {
|
|
21
21
|
readonly sessionId: string;
|
|
22
22
|
readonly run: RunFn;
|
|
23
23
|
readonly runNoTxn: RunFn;
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
2
|
import { Session } from "tenetkit";
|
|
3
3
|
import { SqlClient } from "effect/unstable/sql";
|
|
4
|
-
import { handoffPayload } from "tenetkit/runtime/driver/handoff
|
|
5
|
-
import {} from "tenetkit/runtime/driver/sql/session-store";
|
|
4
|
+
import { handoffPayload } from "tenetkit/runtime/driver/session/handoff";
|
|
6
5
|
import { PostgresSessionStorage } from "./session-storage.js";
|
|
7
6
|
const { advanceSession, entryPayloadEquivalence, insertEntry, loadEntries, lockSession, pathFromRows, requireActive, storeError, toEntry, } = PostgresSessionStorage;
|
|
8
7
|
const appendMatches = (entry, input, parentId) => entry.parentId === parentId && entryPayloadEquivalence(entry, input);
|
|
8
|
+
const nextGeneratedId = (sql, sessionId, firstSequence) => Effect.gen(function* () {
|
|
9
|
+
let sequence = firstSequence;
|
|
10
|
+
while (true) {
|
|
11
|
+
const collision = yield* sql `
|
|
12
|
+
SELECT entry_id FROM tenetkit_session_entries
|
|
13
|
+
WHERE session_id = ${sessionId} AND entry_id = ${String(sequence)}
|
|
14
|
+
`;
|
|
15
|
+
if (collision[0] === undefined)
|
|
16
|
+
return { id: String(sequence), sequence };
|
|
17
|
+
sequence += 1;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
9
20
|
const completedPayload = (input) => ({
|
|
10
21
|
_tag: "ModelResponse",
|
|
11
22
|
content: input.content,
|
|
@@ -27,8 +38,7 @@ export const appendCompletedSessionEntry = (input) => Effect.gen(function* () {
|
|
|
27
38
|
const existing = rows[0];
|
|
28
39
|
const payload = completedPayload(input);
|
|
29
40
|
if (existing !== undefined) {
|
|
30
|
-
if (existing.parent_id !== input.parentId ||
|
|
31
|
-
!entryPayloadEquivalence(toEntry(existing), payload)) {
|
|
41
|
+
if (existing.parent_id !== input.parentId || !entryPayloadEquivalence(toEntry(existing), payload)) {
|
|
32
42
|
return yield* Session.SessionConflict.make({
|
|
33
43
|
reason: "entry-id-reused",
|
|
34
44
|
message: `Session entry id ${input.entryId} does not match the completed response`,
|
|
@@ -49,14 +59,14 @@ export const appendCompletedSessionEntry = (input) => Effect.gen(function* () {
|
|
|
49
59
|
sessionId: input.sessionId,
|
|
50
60
|
id: input.entryId,
|
|
51
61
|
parentId: input.parentId,
|
|
52
|
-
seq:
|
|
62
|
+
seq: session.next_seq,
|
|
53
63
|
tag: "ModelResponse",
|
|
54
|
-
payload
|
|
64
|
+
payload,
|
|
55
65
|
});
|
|
56
66
|
yield* advanceSession({
|
|
57
67
|
sessionId: input.sessionId,
|
|
58
68
|
leafId: input.entryId,
|
|
59
|
-
nextSeq:
|
|
69
|
+
nextSeq: session.next_seq + 1,
|
|
60
70
|
});
|
|
61
71
|
return { ...payload, id: input.entryId, parentId: input.parentId };
|
|
62
72
|
});
|
|
@@ -92,8 +102,7 @@ export const appendInterruptedSessionEntry = (input) => Effect.gen(function* ()
|
|
|
92
102
|
const existing = rows[0];
|
|
93
103
|
const payload = interruptedPayload(input);
|
|
94
104
|
if (existing !== undefined) {
|
|
95
|
-
if (existing.parent_id !== input.parentId ||
|
|
96
|
-
!entryPayloadEquivalence(toEntry(existing), payload)) {
|
|
105
|
+
if (existing.parent_id !== input.parentId || !entryPayloadEquivalence(toEntry(existing), payload)) {
|
|
97
106
|
return yield* Session.SessionConflict.make({
|
|
98
107
|
reason: "entry-id-reused",
|
|
99
108
|
message: `Session entry id ${input.entryId} was reused with different interrupted response content`,
|
|
@@ -114,14 +123,14 @@ export const appendInterruptedSessionEntry = (input) => Effect.gen(function* ()
|
|
|
114
123
|
sessionId: input.sessionId,
|
|
115
124
|
id: input.entryId,
|
|
116
125
|
parentId: input.parentId,
|
|
117
|
-
seq:
|
|
126
|
+
seq: session.next_seq,
|
|
118
127
|
tag: "ModelResponse",
|
|
119
|
-
payload
|
|
128
|
+
payload,
|
|
120
129
|
});
|
|
121
130
|
yield* advanceSession({
|
|
122
131
|
sessionId: input.sessionId,
|
|
123
132
|
leafId: input.entryId,
|
|
124
|
-
nextSeq:
|
|
133
|
+
nextSeq: session.next_seq + 1,
|
|
125
134
|
});
|
|
126
135
|
return { ...payload, id: input.entryId, parentId: input.parentId };
|
|
127
136
|
});
|
|
@@ -156,8 +165,7 @@ export const appendHandoffSessionEntry = (input) => Effect.gen(function* () {
|
|
|
156
165
|
const existing = rows[0];
|
|
157
166
|
const payload = handoffPayload(input);
|
|
158
167
|
if (existing !== undefined) {
|
|
159
|
-
if (existing.parent_id !== input.parentId ||
|
|
160
|
-
!entryPayloadEquivalence(toEntry(existing), payload)) {
|
|
168
|
+
if (existing.parent_id !== input.parentId || !entryPayloadEquivalence(toEntry(existing), payload)) {
|
|
161
169
|
return yield* Session.SessionConflict.make({
|
|
162
170
|
reason: "entry-id-reused",
|
|
163
171
|
message: `Session entry id ${input.entryId} does not match the handoff projection`,
|
|
@@ -166,7 +174,14 @@ export const appendHandoffSessionEntry = (input) => Effect.gen(function* () {
|
|
|
166
174
|
const conflict = requireActive(yield* loadEntries(input.sessionId), session.leaf_id, input.entryId);
|
|
167
175
|
if (conflict !== undefined)
|
|
168
176
|
return yield* conflict;
|
|
169
|
-
|
|
177
|
+
const entry = toEntry(existing);
|
|
178
|
+
if (entry._tag !== "Handoff") {
|
|
179
|
+
return yield* Session.SessionConflict.make({
|
|
180
|
+
reason: "entry-id-reused",
|
|
181
|
+
message: `Session entry id ${input.entryId} does not contain a handoff projection`,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return entry;
|
|
170
185
|
}
|
|
171
186
|
if (session.leaf_id !== input.parentId) {
|
|
172
187
|
return yield* Session.SessionConflict.make({
|
|
@@ -178,14 +193,14 @@ export const appendHandoffSessionEntry = (input) => Effect.gen(function* () {
|
|
|
178
193
|
sessionId: input.sessionId,
|
|
179
194
|
id: input.entryId,
|
|
180
195
|
parentId: input.parentId,
|
|
181
|
-
seq:
|
|
196
|
+
seq: session.next_seq,
|
|
182
197
|
tag: "Handoff",
|
|
183
198
|
payload,
|
|
184
199
|
});
|
|
185
200
|
yield* advanceSession({
|
|
186
201
|
sessionId: input.sessionId,
|
|
187
202
|
leafId: input.entryId,
|
|
188
|
-
nextSeq:
|
|
203
|
+
nextSeq: session.next_seq + 1,
|
|
189
204
|
});
|
|
190
205
|
return { ...payload, id: input.entryId, parentId: input.parentId };
|
|
191
206
|
});
|
|
@@ -214,7 +229,7 @@ const mapSessionError = (effect) => Effect.mapError(effect, (error) => Schema.is
|
|
|
214
229
|
: storeError(String(error)));
|
|
215
230
|
const mapReadError = (effect) => Effect.mapError(effect, (error) => (Schema.is(Session.SessionStoreError)(error) ? error : storeError(String(error))));
|
|
216
231
|
/** Dialect-native durable PostgreSQL Session authority bound to one session identity. */
|
|
217
|
-
export const
|
|
232
|
+
export const postgresSessionStore = (options) => {
|
|
218
233
|
const { sessionId, run, runNoTxn } = options;
|
|
219
234
|
const append = (entry, appendOptions) => Effect.gen(function* () {
|
|
220
235
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -245,32 +260,23 @@ export const makePostgresSessionStore = (options) => {
|
|
|
245
260
|
message: `Expected Session leaf ${String(appendOptions.expectedLeafId)} but found ${String(session.leaf_id)}`,
|
|
246
261
|
});
|
|
247
262
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
SELECT entry_id FROM tenetkit_session_entries
|
|
253
|
-
WHERE session_id = ${sessionId} AND entry_id = ${String(generatedSequence)}
|
|
254
|
-
`;
|
|
255
|
-
if (collision[0] === undefined)
|
|
256
|
-
break;
|
|
257
|
-
generatedSequence += 1;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
const id = appendOptions?.id ?? String(generatedSequence);
|
|
263
|
+
const generated = appendOptions?.id === undefined
|
|
264
|
+
? yield* nextGeneratedId(sql, sessionId, session.next_seq)
|
|
265
|
+
: { id: appendOptions.id, sequence: session.next_seq };
|
|
266
|
+
const id = generated.id;
|
|
261
267
|
yield* insertEntry({
|
|
262
268
|
sessionId,
|
|
263
269
|
id,
|
|
264
270
|
parentId: session.leaf_id,
|
|
265
|
-
seq:
|
|
271
|
+
seq: session.next_seq,
|
|
266
272
|
tag: entry._tag,
|
|
267
273
|
payload: entry,
|
|
268
274
|
});
|
|
269
275
|
yield* advanceSession({
|
|
270
276
|
sessionId,
|
|
271
277
|
leafId: id,
|
|
272
|
-
nextSeq:
|
|
273
|
-
...(appendOptions?.ownerToken === undefined ?
|
|
278
|
+
nextSeq: generated.sequence + 1,
|
|
279
|
+
...(appendOptions?.ownerToken === undefined ? undefined : { ownerToken: appendOptions.ownerToken }),
|
|
274
280
|
});
|
|
275
281
|
return { ...entry, id, parentId: session.leaf_id };
|
|
276
282
|
});
|
|
@@ -317,22 +323,22 @@ export const makePostgresSessionStore = (options) => {
|
|
|
317
323
|
parentId: prepared.parentId,
|
|
318
324
|
projectedHistory: prepared.projectedHistory,
|
|
319
325
|
telemetry: prepared.telemetry,
|
|
320
|
-
...(prepared.compactionCommit === undefined ?
|
|
321
|
-
...(prepared.summary === undefined ?
|
|
326
|
+
...(prepared.compactionCommit === undefined ? undefined : { compactionCommit: prepared.compactionCommit }),
|
|
327
|
+
...(prepared.summary === undefined ? undefined : { summary: prepared.summary }),
|
|
322
328
|
};
|
|
323
329
|
yield* insertEntry({
|
|
324
330
|
sessionId,
|
|
325
331
|
id: checkpoint.id,
|
|
326
332
|
parentId: checkpoint.parentId,
|
|
327
|
-
seq:
|
|
333
|
+
seq: session.next_seq,
|
|
328
334
|
tag: "Compaction",
|
|
329
335
|
payload: checkpoint,
|
|
330
336
|
});
|
|
331
337
|
yield* advanceSession({
|
|
332
338
|
sessionId,
|
|
333
339
|
leafId: checkpoint.id,
|
|
334
|
-
nextSeq:
|
|
335
|
-
...(prepared.ownerToken === undefined ?
|
|
340
|
+
nextSeq: session.next_seq + 1,
|
|
341
|
+
...(prepared.ownerToken === undefined ? undefined : { ownerToken: prepared.ownerToken }),
|
|
336
342
|
});
|
|
337
343
|
return { _tag: "Appended", checkpoint, leafId: checkpoint.id };
|
|
338
344
|
});
|
|
@@ -340,7 +346,7 @@ export const makePostgresSessionStore = (options) => {
|
|
|
340
346
|
reserveEntryId: run(Effect.gen(function* () {
|
|
341
347
|
const sql = yield* SqlClient.SqlClient;
|
|
342
348
|
const session = yield* lockSession(sessionId);
|
|
343
|
-
let sequence =
|
|
349
|
+
let sequence = session.next_seq;
|
|
344
350
|
while (true) {
|
|
345
351
|
const collision = yield* sql `
|
|
346
352
|
SELECT entry_id FROM tenetkit_session_entries
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/unstable/sql";
|
|
3
3
|
import { AddressNotFound, IdempotencyConflict, RunIdConflict, TreePolicyInvalid } from "tenetkit/runtime/driver/errors";
|
|
4
|
-
import type
|
|
5
|
-
import type { AdmitSendInput } from "tenetkit/runtime/driver/run
|
|
4
|
+
import { type PinnedExecutable } from "tenetkit/runtime/driver/executable/manifest";
|
|
5
|
+
import type { AdmitSendInput } from "tenetkit/runtime/driver/run/store";
|
|
6
6
|
import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
|
|
7
7
|
/** Exact addressed admission for the PostgreSQL store. */
|
|
8
8
|
export declare const admitSend: {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Effect, Function } from "effect";
|
|
2
2
|
import { SqlClient } from "effect/unstable/sql";
|
|
3
3
|
import { AddressNotFound, IdempotencyConflict, RunIdConflict, TreePolicyInvalid } from "tenetkit/runtime/driver/errors";
|
|
4
|
-
import { equals } from "tenetkit/runtime/driver/executable
|
|
4
|
+
import { equals } from "tenetkit/runtime/driver/executable/manifest";
|
|
5
5
|
import { rootDigest } from "tenetkit/runtime/driver/memory/digest";
|
|
6
|
-
import { appendEvent, enqueueLane, insertRun, loadRun } from "./
|
|
7
|
-
import { associateRegistrations, persistRegistrations } from "tenetkit/runtime/driver/sql/executable
|
|
8
|
-
import { decodePinnedEffect, decodeStoredPinnedEffect } from "tenetkit/runtime/driver/sql/codecs";
|
|
9
|
-
import { normalize as normalizeTreePolicy } from "tenetkit/runtime/driver/tree
|
|
6
|
+
import { appendEvent, enqueueLane, insertRun, loadRun } from "./runtime.js";
|
|
7
|
+
import { associateRegistrations, persistRegistrations } from "tenetkit/runtime/driver/sql/executable/registrations";
|
|
8
|
+
import { decodePinnedEffect, decodeStoredPinnedEffect } from "tenetkit/runtime/driver/sql/codec/codecs";
|
|
9
|
+
import { normalize as normalizeTreePolicy } from "tenetkit/runtime/driver/tree/policy";
|
|
10
10
|
/** Exact addressed admission for the PostgreSQL store. */
|
|
11
11
|
export const admitSend = Function.dual(4, (hub, addressBindings, nextId, input) => Effect.gen(function* () {
|
|
12
12
|
const sql = yield* SqlClient.SqlClient;
|
|
@@ -50,7 +50,7 @@ export const admitSend = Function.dual(4, (hub, addressBindings, nextId, input)
|
|
|
50
50
|
return {
|
|
51
51
|
runId: prior.run_id,
|
|
52
52
|
messageId: prior.message_id,
|
|
53
|
-
acceptedSequence:
|
|
53
|
+
acceptedSequence: prior.accepted_sequence,
|
|
54
54
|
duplicate: true,
|
|
55
55
|
};
|
|
56
56
|
}
|
|
@@ -8,7 +8,7 @@ export declare const deferCancelledFanOutParent: {
|
|
|
8
8
|
(runId: string): (sql: SqlClient.SqlClient) => Effect.Effect<boolean, SqlError, SqlClient.SqlClient>;
|
|
9
9
|
(sql: SqlClient.SqlClient, runId: string): Effect.Effect<boolean, SqlError, SqlClient.SqlClient>;
|
|
10
10
|
};
|
|
11
|
-
export declare const
|
|
11
|
+
export declare const cancelRunFor: (input: {
|
|
12
12
|
readonly sql: SqlClient.SqlClient;
|
|
13
13
|
readonly hub: EventHub;
|
|
14
14
|
}) => (runId: string, reason: string | undefined) => Effect.Effect<void, RunNotFound | RuntimeUnavailable | SqlError, SqlClient.SqlClient | PgClient.PgClient>;
|