@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.
Files changed (42) hide show
  1. package/dist/postgres/{event-stream.d.ts → events/event-stream.d.ts} +2 -2
  2. package/dist/postgres/{event-stream.js → events/event-stream.js} +2 -2
  3. package/dist/postgres/{transaction-events.d.ts → events/transaction-events.d.ts} +2 -2
  4. package/dist/postgres/{transaction-events.js → events/transaction-events.js} +4 -4
  5. package/dist/postgres/run-schema.js +6 -6
  6. package/dist/postgres/{claims.d.ts → runs/claims.d.ts} +2 -2
  7. package/dist/postgres/{claims.js → runs/claims.js} +1 -1
  8. package/dist/postgres/{locks.d.ts → runs/locks.d.ts} +1 -1
  9. package/dist/postgres/{locks.js → runs/locks.js} +2 -2
  10. package/dist/postgres/runtime-layer.d.ts +4 -5
  11. package/dist/postgres/runtime-layer.js +9 -9
  12. package/dist/postgres/{session-cancellation.js → sessions/session-cancellation.js} +1 -1
  13. package/dist/postgres/{session-storage.d.ts → sessions/session-storage.d.ts} +4 -3
  14. package/dist/postgres/{session-storage.js → sessions/session-storage.js} +1 -1
  15. package/dist/postgres/{session-store.d.ts → sessions/session-store.d.ts} +5 -5
  16. package/dist/postgres/{session-store.js → sessions/session-store.js} +46 -40
  17. package/dist/postgres/{store-admit.d.ts → store/admit.d.ts} +2 -2
  18. package/dist/postgres/{store-admit.js → store/admit.js} +6 -6
  19. package/dist/postgres/{store-cancel.d.ts → store/cancel.d.ts} +1 -1
  20. package/dist/postgres/{store-cancel.js → store/cancel.js} +42 -46
  21. package/dist/postgres/{store-claims.d.ts → store/claims.d.ts} +3 -3
  22. package/dist/postgres/{store-claims.js → store/claims.js} +9 -7
  23. package/dist/postgres/{store-fan-out.d.ts → store/fan-out.d.ts} +2 -2
  24. package/dist/postgres/{store-fan-out.js → store/fan-out.js} +2 -2
  25. package/dist/postgres/{store.d.ts → store/index.d.ts} +7 -4
  26. package/dist/postgres/{store.js → store/index.js} +56 -54
  27. package/dist/postgres/{store-inspection.d.ts → store/inspection.d.ts} +3 -3
  28. package/dist/postgres/{store-inspection.js → store/inspection.js} +10 -10
  29. package/dist/postgres/{store-messaging.d.ts → store/messaging.d.ts} +2 -2
  30. package/dist/postgres/{store-messaging.js → store/messaging.js} +1 -1
  31. package/dist/postgres/{store-model-response.d.ts → store/model-response.d.ts} +4 -4
  32. package/dist/postgres/{store-model-response.js → store/model-response.js} +46 -38
  33. package/dist/postgres/{store-ops.d.ts → store/ops.d.ts} +4 -4
  34. package/dist/postgres/{store-ops.js → store/ops.js} +102 -94
  35. package/dist/postgres/{store-program.d.ts → store/program.d.ts} +2 -2
  36. package/dist/postgres/{store-program.js → store/program.js} +5 -5
  37. package/dist/postgres/{pg-helpers.d.ts → store/runtime.d.ts} +18 -12
  38. package/dist/postgres/{pg-helpers.js → store/runtime.js} +49 -48
  39. package/dist/postgres/{store-suspend.d.ts → store/suspend.d.ts} +1 -1
  40. package/dist/postgres/{store-suspend.js → store/suspend.js} +14 -14
  41. package/package.json +2 -2
  42. /package/dist/postgres/{session-cancellation.d.ts → sessions/session-cancellation.d.ts} +0 -0
@@ -3,10 +3,10 @@ import type { PgClient } from "@effect/sql-pg";
3
3
  import { SqlClient } from "effect/unstable/sql";
4
4
  import type { SqlError } from "effect/unstable/sql/SqlError";
5
5
  import { RunNotFound, RuntimeUnavailable } from "tenetkit/runtime/driver/errors";
6
- import type { Interface as RunStoreInterface } from "tenetkit/runtime/driver/run-store";
7
- import type { DecodedRun } from "tenetkit/runtime/driver/sql/rows";
6
+ import type { Interface as RunStoreInterface } from "tenetkit/runtime/driver/run/store";
7
+ import type { DecodedRun } from "tenetkit/runtime/driver/sql/codec/rows";
8
8
  import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
9
- import type { WithoutSqlError } from "tenetkit/runtime/driver/sql/sql-effect";
9
+ import type { WithoutSqlError } from "tenetkit/runtime/driver/sql/effect";
10
10
  type SqlR = SqlClient.SqlClient | PgClient.PgClient;
11
11
  export type RunFn = <A, E>(effect: Effect.Effect<A, E | SqlError, SqlR>) => Effect.Effect<A, WithoutSqlError<E | SqlError> | RuntimeUnavailable>;
12
12
  export declare const postgresOperations: (input: {
@@ -15,7 +15,7 @@ export declare const postgresOperations: (input: {
15
15
  readonly run: RunFn;
16
16
  readonly runNoTxn: RunFn;
17
17
  readonly requireRun: (runId: string) => Effect.Effect<DecodedRun, RunNotFound | RuntimeUnavailable | SqlError, SqlR>;
18
- readonly requireClaim: (claim: import("tenetkit/runtime/driver/run-store").ExecutionClaim) => Effect.Effect<void, import("tenetkit/runtime/driver/sql/errors").StaleClaim | RunNotFound | RuntimeUnavailable | SqlError, SqlR>;
18
+ readonly requireClaim: (claim: import("tenetkit/runtime/driver/run/store").ExecutionClaim) => Effect.Effect<void, import("tenetkit/runtime/driver/sql/errors").StaleClaim | RunNotFound | RuntimeUnavailable | SqlError, SqlR>;
19
19
  readonly nextId: (prefix: string) => Effect.Effect<string>;
20
20
  }) => Pick<RunStoreInterface, "recordOperation" | "startOperation" | "completeOperation" | "commitModelResponse" | "commitInterruptedModelResponse" | "expireRunningOperation" | "recoverRunningOperations" | "getOperation" | "getOperationByKey" | "operationCancellations" | "acknowledgeOperationCancellation" | "resolveOperation">;
21
21
  export {};
@@ -1,21 +1,26 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { SqlClient } from "effect/unstable/sql";
3
3
  import { OperationResolutionConflict, RunNotFound, RunTerminal, RuntimeUnavailable, } from "tenetkit/runtime/driver/errors";
4
- import { OperationResolution, digest as resolutionDigest } from "tenetkit/runtime/driver/operation-resolution";
4
+ import { OperationResolution, digest as resolutionDigest } from "tenetkit/runtime/driver/operation/resolution";
5
5
  import { isTerminal } from "tenetkit/runtime/driver/run";
6
- import { ExecutionCheckpoint } from "tenetkit/runtime/driver/execution-state";
7
- import { decodeJson, encodeExecutableRef, encodeJson, encodeJsonValue } from "tenetkit/runtime/driver/sql/codecs";
6
+ import { ExecutionCheckpoint } from "tenetkit/runtime/driver/execution/state";
7
+ import { decodeJson, encodeExecutableRef, encodeJson, encodeJsonValue } from "tenetkit/runtime/driver/sql/codec/codecs";
8
8
  import { canBlindRetry } from "tenetkit/runtime/driver/sql/operations";
9
- import { appendEvent, toOperationRecord } from "./pg-helpers.js";
10
- import { encodeContinuation } from "tenetkit/runtime/driver/steering";
11
- import { checkpointRef } from "tenetkit/runtime/driver/executable-manifest";
12
- import { getProgramOperation, resolveProgramOperation } from "tenetkit/runtime/driver/sql/store-program";
13
- import { settleAdmittedCancellation } from "tenetkit/runtime/driver/sql/store-control";
14
- import { acknowledgeOperationCancellation, operationCancellations } from "tenetkit/runtime/driver/sql/store-operations";
15
- import { postgresModelResponseOperations } from "./store-model-response.js";
16
- import { appendHandoffSessionEntry, verifyHandoffSessionEntry } from "./session-store.js";
17
- import { handoffSessionEntry, isHandoffCommit, sameHandoffCheckpoint, sameHandoffCommit, } from "tenetkit/runtime/driver/handoff-session";
18
- import { lockRunHierarchy } from "./locks.js";
9
+ import { appendEvent, toOperationRecord } from "./runtime.js";
10
+ import { encodeContinuation } from "tenetkit/runtime/driver/run/steering";
11
+ import { checkpointRef } from "tenetkit/runtime/driver/executable/manifest";
12
+ import { getProgramOperation, resolveProgramOperation } from "tenetkit/runtime/driver/sql/store/program";
13
+ import { settleAdmittedCancellation } from "tenetkit/runtime/driver/sql/store/control";
14
+ import { acknowledgeOperationCancellation, operationCancellations, } from "tenetkit/runtime/driver/sql/store/operation/operations";
15
+ import { postgresModelResponseOperations } from "./model-response.js";
16
+ import { appendHandoffSessionEntry, verifyHandoffSessionEntry } from "../sessions/session-store.js";
17
+ import { handoffSessionEntry, isHandoffCommit, sameHandoffCheckpoint, sameHandoffCommit, } from "tenetkit/runtime/driver/session/handoff";
18
+ import { lockRunHierarchy } from "../runs/locks.js";
19
+ const isCompletedOperationStatus = (status) => status === "cancelling" ||
20
+ status === "cancelled" ||
21
+ status === "succeeded" ||
22
+ status === "failed" ||
23
+ status === "unknown";
19
24
  export const postgresOperations = (input) => {
20
25
  const { sql, hub, run, runNoTxn, requireRun, requireClaim, nextId } = input;
21
26
  const fenced = (claim, effect) => run(sql `SELECT run_id FROM tenetkit_runs WHERE run_id = ${claim.runId} FOR UPDATE`.pipe(Effect.andThen(requireClaim(claim)), Effect.andThen(effect)));
@@ -51,6 +56,82 @@ export const postgresOperations = (input) => {
51
56
  `;
52
57
  return { record: toOperationRecord(next[0]), outcome: "unknown" };
53
58
  });
59
+ const existingOperation = (op, prior) => Effect.gen(function* () {
60
+ const consumed = yield* sql `
61
+ SELECT entry_id FROM tenetkit_run_steering
62
+ WHERE run_id = ${op.runId} AND consumed_operation_id = ${prior.operation_id}
63
+ ORDER BY sequence
64
+ `;
65
+ const retried = op.steeringEntryIds ?? [];
66
+ if (consumed.length !== retried.length || consumed.some((entry, index) => entry.entry_id !== retried[index])) {
67
+ return yield* RuntimeUnavailable.make({ message: "steering consumption does not match operation" });
68
+ }
69
+ return toOperationRecord(prior);
70
+ });
71
+ const verifyPendingSteering = (op) => Effect.gen(function* () {
72
+ const steeringEntryIds = op.steeringEntryIds ?? [];
73
+ const pending = yield* sql `
74
+ SELECT entry_id FROM tenetkit_run_steering
75
+ WHERE run_id = ${op.runId} AND consumed_operation_id IS NULL AND discarded_reason IS NULL
76
+ ORDER BY sequence
77
+ `;
78
+ const selected = pending.slice(0, steeringEntryIds.length);
79
+ if (selected.length !== steeringEntryIds.length ||
80
+ selected.some((entry, index) => entry.entry_id !== steeringEntryIds[index])) {
81
+ return yield* RuntimeUnavailable.make({ message: "steering entries are not the pending prefix" });
82
+ }
83
+ return steeringEntryIds;
84
+ });
85
+ const verifyCompletedOperation = (op, loaded, row) => Effect.gen(function* () {
86
+ const current = toOperationRecord(row);
87
+ if (current.kind === "handoff" && current.status === "succeeded" && isHandoffCommit(current.result)) {
88
+ if (op.outcome._tag !== "Succeeded" ||
89
+ !sameHandoffCommit(current.result, op.outcome.value) ||
90
+ !sameHandoffCheckpoint(loaded.driverCheckpoint, op.checkpoint)) {
91
+ return yield* RuntimeUnavailable.make({ message: "handoff operation has a divergent completion retry" });
92
+ }
93
+ const entry = handoffSessionEntry({
94
+ sessionId: loaded.message.sessionId,
95
+ operationKey: current.operationKey,
96
+ value: op.outcome.value,
97
+ });
98
+ if (Schema.is(RuntimeUnavailable)(entry))
99
+ return yield* entry;
100
+ yield* verifyHandoffSessionEntry(entry).pipe(Effect.mapError((error) => RuntimeUnavailable.make({ message: error.message })));
101
+ }
102
+ return current;
103
+ });
104
+ const verifyOperationSteering = (op) => Effect.gen(function* () {
105
+ for (const entryId of new Set(op.steeringEntryIds ?? [])) {
106
+ const rows = yield* sql `
107
+ SELECT consumed_operation_id FROM tenetkit_run_steering
108
+ WHERE run_id = ${op.runId} AND entry_id = ${entryId}
109
+ `;
110
+ if (rows[0]?.consumed_operation_id !== op.operationId) {
111
+ return yield* RuntimeUnavailable.make({ message: `steering entry ${entryId} does not belong to operation` });
112
+ }
113
+ }
114
+ });
115
+ const persistOperationOutcome = (op) => {
116
+ if (op.outcome._tag === "Succeeded") {
117
+ return sql `
118
+ UPDATE tenetkit_run_operations
119
+ SET status = 'succeeded', result_json = ${encodeJsonValue(op.outcome.value)}, finished_at = NOW()
120
+ WHERE run_id = ${op.runId} AND operation_id = ${op.operationId} AND status IN ('requested', 'running')
121
+ `;
122
+ }
123
+ if (op.outcome._tag === "Failed") {
124
+ return sql `
125
+ UPDATE tenetkit_run_operations
126
+ SET status = 'failed', error_json = ${encodeJsonValue(op.outcome.error)}, finished_at = NOW()
127
+ WHERE run_id = ${op.runId} AND operation_id = ${op.operationId} AND status IN ('requested', 'running')
128
+ `;
129
+ }
130
+ return sql `
131
+ UPDATE tenetkit_run_operations SET status = 'unknown', finished_at = NOW()
132
+ WHERE run_id = ${op.runId} AND operation_id = ${op.operationId} AND status IN ('requested', 'running')
133
+ `;
134
+ };
54
135
  return {
55
136
  recordOperation: (op) => fenced(op, Effect.gen(function* () {
56
137
  const loaded = yield* requireRun(op.runId);
@@ -62,33 +143,12 @@ export const postgresOperations = (input) => {
62
143
  WHERE run_id = ${op.runId} AND operation_key = ${op.operationKey}
63
144
  `;
64
145
  const prior = existing[0];
65
- if (prior !== undefined) {
66
- const consumed = yield* sql `
67
- SELECT entry_id FROM tenetkit_run_steering
68
- WHERE run_id = ${op.runId} AND consumed_operation_id = ${prior.operation_id}
69
- ORDER BY sequence
70
- `;
71
- const retried = op.steeringEntryIds ?? [];
72
- if (consumed.length !== retried.length ||
73
- consumed.some((entry, index) => entry.entry_id !== retried[index])) {
74
- return yield* RuntimeUnavailable.make({ message: "steering consumption does not match operation" });
75
- }
76
- return toOperationRecord(prior);
77
- }
146
+ if (prior !== undefined)
147
+ return yield* existingOperation(op, prior);
78
148
  if (loaded.cancellationRequested) {
79
149
  return yield* RuntimeUnavailable.make({ message: `run ${loaded.runId} is cancelling` });
80
150
  }
81
- const steeringEntryIds = op.steeringEntryIds ?? [];
82
- const pending = yield* sql `
83
- SELECT entry_id FROM tenetkit_run_steering
84
- WHERE run_id = ${op.runId} AND consumed_operation_id IS NULL AND discarded_reason IS NULL
85
- ORDER BY sequence
86
- `;
87
- const selected = pending.slice(0, steeringEntryIds.length);
88
- if (selected.length !== steeringEntryIds.length ||
89
- selected.some((entry, index) => entry.entry_id !== steeringEntryIds[index])) {
90
- return yield* RuntimeUnavailable.make({ message: "steering entries are not the pending prefix" });
91
- }
151
+ const steeringEntryIds = yield* verifyPendingSteering(op);
92
152
  const operationId = yield* nextId("op");
93
153
  const executableRef = yield* Effect.try({
94
154
  try: () => checkpointRef(loaded.executableRef, loaded.executableManifest, op.checkpoint),
@@ -165,40 +225,10 @@ export const postgresOperations = (input) => {
165
225
  const row = existing[0];
166
226
  if (row === undefined)
167
227
  return yield* RuntimeUnavailable.make({ message: "operation missing" });
168
- const current = toOperationRecord(row);
169
- if (row.status === "cancelling" ||
170
- row.status === "cancelled" ||
171
- row.status === "succeeded" ||
172
- row.status === "failed" ||
173
- row.status === "unknown") {
174
- if (current.kind === "handoff" && current.status === "succeeded" && isHandoffCommit(current.result)) {
175
- if (op.outcome._tag !== "Succeeded" ||
176
- !sameHandoffCommit(current.result, op.outcome.value) ||
177
- !sameHandoffCheckpoint(loaded.driverCheckpoint, op.checkpoint)) {
178
- return yield* RuntimeUnavailable.make({ message: "handoff operation has a divergent completion retry" });
179
- }
180
- const entry = handoffSessionEntry({
181
- sessionId: loaded.message.sessionId,
182
- operationKey: current.operationKey,
183
- value: op.outcome.value,
184
- });
185
- if (Schema.is(RuntimeUnavailable)(entry))
186
- return yield* entry;
187
- yield* verifyHandoffSessionEntry(entry).pipe(Effect.mapError((error) => RuntimeUnavailable.make({ message: error.message })));
188
- }
189
- return current;
190
- }
191
- for (const entryId of new Set(op.steeringEntryIds ?? [])) {
192
- const rows = yield* sql `
193
- SELECT consumed_operation_id FROM tenetkit_run_steering
194
- WHERE run_id = ${op.runId} AND entry_id = ${entryId}
195
- `;
196
- if (rows[0]?.consumed_operation_id !== op.operationId) {
197
- return yield* RuntimeUnavailable.make({
198
- message: `steering entry ${entryId} does not belong to operation`,
199
- });
200
- }
228
+ if (isCompletedOperationStatus(row.status)) {
229
+ return yield* verifyCompletedOperation(op, loaded, row);
201
230
  }
231
+ yield* verifyOperationSteering(op);
202
232
  const executableRef = yield* Effect.try({
203
233
  try: () => checkpointRef(loaded.executableRef, loaded.executableManifest, op.checkpoint),
204
234
  catch: (error) => RuntimeUnavailable.make({ message: String(error) }),
@@ -213,29 +243,7 @@ export const postgresOperations = (input) => {
213
243
  return yield* entry;
214
244
  yield* appendHandoffSessionEntry(entry).pipe(Effect.mapError((error) => RuntimeUnavailable.make({ message: error.message })));
215
245
  }
216
- if (op.outcome._tag === "Succeeded") {
217
- yield* sql `
218
- UPDATE tenetkit_run_operations
219
- SET status = 'succeeded', result_json = ${encodeJsonValue(op.outcome.value)}, finished_at = NOW()
220
- WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
221
- AND status IN ('requested', 'running')
222
- `;
223
- }
224
- else if (op.outcome._tag === "Failed") {
225
- yield* sql `
226
- UPDATE tenetkit_run_operations
227
- SET status = 'failed', error_json = ${encodeJsonValue(op.outcome.error)}, finished_at = NOW()
228
- WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
229
- AND status IN ('requested', 'running')
230
- `;
231
- }
232
- else {
233
- yield* sql `
234
- UPDATE tenetkit_run_operations SET status = 'unknown', finished_at = NOW()
235
- WHERE run_id = ${op.runId} AND operation_id = ${op.operationId}
236
- AND status IN ('requested', 'running')
237
- `;
238
- }
246
+ yield* persistOperationOutcome(op);
239
247
  yield* sql `
240
248
  UPDATE tenetkit_runs SET
241
249
  driver_checkpoint_json = COALESCE(${op.checkpoint === undefined ? null : encodeJson(ExecutionCheckpoint, op.checkpoint)}, driver_checkpoint_json),
@@ -348,7 +356,7 @@ export const postgresOperations = (input) => {
348
356
  SELECT COUNT(*)::int AS unresolved FROM tenetkit_run_operations
349
357
  WHERE run_id = ${op.runId} AND status = 'unknown'
350
358
  `;
351
- const runStatus = Number(unresolved[0]?.unresolved ?? 0) > 0
359
+ const runStatus = (unresolved[0]?.unresolved ?? 0) > 0
352
360
  ? sql `'needs-resolution'`
353
361
  : sql `CASE WHEN cancellation_requested THEN 'cancelling' ELSE 'queued' END`;
354
362
  yield* sql `
@@ -2,9 +2,9 @@ import { Effect } from "effect";
2
2
  import type { PgClient } from "@effect/sql-pg";
3
3
  import { SqlClient } from "effect/unstable/sql";
4
4
  import { RuntimeUnavailable } from "tenetkit/runtime/driver/errors";
5
- import type { Interface as RunStore } from "tenetkit/runtime/driver/run-store";
5
+ import type { Interface as RunStore } from "tenetkit/runtime/driver/run/store";
6
6
  import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
7
- import type { WithoutSqlError } from "tenetkit/runtime/driver/sql/sql-effect";
7
+ import type { WithoutSqlError } from "tenetkit/runtime/driver/sql/effect";
8
8
  import type { SqlError } from "effect/unstable/sql/SqlError";
9
9
  type SqlR = SqlClient.SqlClient | PgClient.PgClient;
10
10
  export type Run = <A, E>(effect: Effect.Effect<A, E | SqlError, SqlR>) => Effect.Effect<A, WithoutSqlError<E | SqlError> | RuntimeUnavailable>;
@@ -2,11 +2,11 @@ import { Effect } from "effect";
2
2
  import { ProgramCapabilities } from "tenetkit";
3
3
  import { SqlClient } from "effect/unstable/sql";
4
4
  import { RuntimeUnavailable } from "tenetkit/runtime/driver/errors";
5
- import { requireExecutionClaim } from "tenetkit/runtime/driver/sql/store-execution";
6
- import { loadProgramState, getProgramOperation, reserveProgramOperation, admitProgramAgents, commitProgramLog, settleProgramOperation, suspendProgramOperation, startProgramOperation, } from "tenetkit/runtime/driver/sql/store-program";
7
- import { completeRun, requireRun } from "./pg-helpers.js";
8
- import { suspend } from "./store-suspend.js";
9
- import { admitProgramChild } from "tenetkit/runtime/driver/sql/store-admit";
5
+ import { requireExecutionClaim } from "tenetkit/runtime/driver/sql/store/execution";
6
+ import { loadProgramState, getProgramOperation, reserveProgramOperation, admitProgramAgents, commitProgramLog, settleProgramOperation, suspendProgramOperation, startProgramOperation, } from "tenetkit/runtime/driver/sql/store/program";
7
+ import { completeRun, requireRun } from "./runtime.js";
8
+ import { suspend } from "./suspend.js";
9
+ import { admitProgramChild } from "tenetkit/runtime/driver/sql/store/admit";
10
10
  export const programStoreMethods = (input) => {
11
11
  const fenced = (claim, effect) => input.run(input.sql `SELECT run_id FROM tenetkit_runs WHERE run_id = ${claim.runId} FOR UPDATE`.pipe(Effect.andThen(requireExecutionClaim(claim)), Effect.andThen(effect)));
12
12
  return {
@@ -2,16 +2,16 @@ import { Effect } from "effect";
2
2
  import { SqlClient } from "effect/unstable/sql";
3
3
  import type { SqlError } from "effect/unstable/sql/SqlError";
4
4
  import { PgClient } from "@effect/sql-pg";
5
- import { type RunEvent } from "tenetkit/runtime/driver/run-event";
6
- import type { ExecutableManifest, ExecutableRef } from "tenetkit/runtime/driver/executable-manifest";
7
- import type { Message } from "tenetkit/runtime/driver/message";
5
+ import { type RunEvent } from "tenetkit/runtime/driver/run/event";
6
+ import type { ExecutableManifest, ExecutableRef } from "tenetkit/runtime/driver/executable/manifest";
7
+ import type { Message } from "tenetkit/runtime/driver/messaging/message";
8
8
  import { type RunStatus } from "tenetkit/runtime/driver/run";
9
- import { decodeMessage, decodeQueue, encodeQueue } from "tenetkit/runtime/driver/sql/codecs";
9
+ import { decodeMessage, decodeQueue, encodeQueue } from "tenetkit/runtime/driver/sql/codec/codecs";
10
10
  import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
11
- import type { DecodedRun } from "tenetkit/runtime/driver/sql/rows";
12
- import type { EmittableAgentLoopEvent } from "tenetkit/runtime/driver/agent-event";
13
- import { type ExecutionClaim } from "tenetkit/runtime/driver/run-store";
14
- import type { ExecutionResult } from "tenetkit/runtime/driver/execution-state";
11
+ import type { DecodedRun } from "tenetkit/runtime/driver/sql/codec/rows";
12
+ import type { EmittableAgentLoopEvent } from "tenetkit/runtime/driver/execution/agent/event";
13
+ import { type ExecutionClaim } from "tenetkit/runtime/driver/run/store";
14
+ import type { ExecutionResult } from "tenetkit/runtime/driver/execution/state";
15
15
  import { RunNotFound, RunTerminal, RuntimeUnavailable } from "tenetkit/runtime/driver/errors";
16
16
  import { StaleClaim } from "tenetkit/runtime/driver/sql/errors";
17
17
  type StoreError = RuntimeUnavailable | SqlError;
@@ -26,9 +26,14 @@ type AgentEventError = RunNotFound | RunTerminal | StoreError | StaleClaim;
26
26
  type AgentEventEffect = Effect.Effect<undefined, AgentEventError, SqlClient.SqlClient>;
27
27
  type CompleteRunEffect = Effect.Effect<undefined, RunTerminal | StoreError, SqlClient.SqlClient>;
28
28
  type SettleParentEffect = Effect.Effect<void, StoreError, SqlClient.SqlClient | PgClient.PgClient>;
29
- export type EventPartial = {
29
+ type EventField = RunEvent extends RunEvent ? unknown : never;
30
+ type AppendInput = object & {
30
31
  readonly _tag: string;
31
- } & Record<string, unknown>;
32
+ };
33
+ export interface EventPartial {
34
+ readonly _tag: string;
35
+ readonly [key: string]: EventField;
36
+ }
32
37
  export declare const loadRun: (runId: string) => Effect.Effect<DecodedRun | undefined, RuntimeUnavailable | SqlError, SqlClient.SqlClient>;
33
38
  export declare const requireRun: (runId: string) => Effect.Effect<DecodedRun, RunNotFound | RuntimeUnavailable | SqlError, SqlClient.SqlClient>;
34
39
  export declare const emitAgentEvent: {
@@ -45,7 +50,8 @@ export declare const loadEventsAfter: {
45
50
  };
46
51
  export declare const allocateSequence: (runId: string) => Effect.Effect<number, SqlError, SqlClient.SqlClient>;
47
52
  export declare const appendEvent: {
48
- (run: DecodedRun, partial: EventPartial, nextStatus?: RunStatus): (hub: EventHub) => RunEventEffect;
53
+ <Partial extends AppendInput>(run: DecodedRun, partial: Partial, nextStatus?: RunStatus): (hub: EventHub) => RunEventEffect;
54
+ <Partial extends AppendInput>(hub: EventHub, run: DecodedRun, partial: Partial, nextStatus?: RunStatus): RunEventEffect;
49
55
  (hub: EventHub, run: DecodedRun, partial: EventPartial, nextStatus?: RunStatus): RunEventEffect;
50
56
  };
51
57
  export declare const promoteHead: {
@@ -77,7 +83,7 @@ export declare const insertRun: (input: {
77
83
  readonly executableManifest: ExecutableManifest;
78
84
  readonly rootRunId: string;
79
85
  readonly depth: number;
80
- readonly treePolicy: import("tenetkit/runtime/driver/tree-policy").TreePolicy;
86
+ readonly treePolicy: import("tenetkit/runtime/driver/tree/policy").TreePolicy;
81
87
  readonly parentRunId?: string;
82
88
  readonly invocationId?: string;
83
89
  readonly acceptedSequence: number;
@@ -1,19 +1,37 @@
1
1
  import { Effect, Function } from "effect";
2
2
  import { SqlClient } from "effect/unstable/sql";
3
3
  import { PgClient } from "@effect/sql-pg";
4
- import { eventIdFor } from "tenetkit/runtime/driver/run-event";
4
+ import { eventIdFor } from "tenetkit/runtime/driver/run/event";
5
5
  import { isTerminal } from "tenetkit/runtime/driver/run";
6
- import { StringArray, decodeMessage, decodeQueue, encodeExecutableManifest, encodeExecutableRef, encodeEvent, encodeJson, encodeMessage, encodeQueue, } from "tenetkit/runtime/driver/sql/codecs";
7
- import { reconcileFanOutWith } from "tenetkit/runtime/driver/sql/store-fan-out";
8
- import { decodePersistedEvents, decodeRunEffect, nowIso } from "tenetkit/runtime/driver/sql/store-helpers";
9
- import { NOTIFY_CHANNEL } from "./schema.js";
10
- import { PendingRunOutcome } from "tenetkit/runtime/driver/run-store";
6
+ import { StringArray, decodeMessage, decodeEvent, decodeQueue, encodeExecutableManifest, encodeExecutableRef, encodeEvent, encodeJson, encodeMessage, encodeQueue, } from "tenetkit/runtime/driver/sql/codec/codecs";
7
+ import { reconcileFanOutWith } from "tenetkit/runtime/driver/sql/store/fan-out/service";
8
+ import { decodePersistedEvents, decodeRunEffect, nowIso } from "tenetkit/runtime/driver/sql/store/statements";
9
+ import { NOTIFY_CHANNEL } from "../schema.js";
10
+ import { PendingRunOutcome } from "tenetkit/runtime/driver/run/store";
11
11
  import { RunNotFound, RunTerminal, RuntimeUnavailable } from "tenetkit/runtime/driver/errors";
12
12
  import { StaleClaim } from "tenetkit/runtime/driver/sql/errors";
13
13
  import { admitChildSettlementFromEventId } from "tenetkit/runtime/driver/sql/settlement-notifications";
14
- import { discardPendingSteering } from "tenetkit/runtime/driver/sql/store-steering-disposition";
15
- import { hasPendingOperationCancellation, hasUnsettledChild, loadTerminalEvent, reconcileChildWaitWith, } from "tenetkit/runtime/driver/sql/store-child-settlement";
16
- import { appendTerminalToolResultsForEvent } from "tenetkit/runtime/driver/sql/session-terminalization";
14
+ import { discardPendingSteering } from "tenetkit/runtime/driver/sql/store/steering/disposition";
15
+ import { hasPendingOperationCancellation, hasUnsettledChild, loadTerminalEvent, reconcileChildWaitWith, } from "tenetkit/runtime/driver/sql/store/child/settlement";
16
+ import { appendTerminalToolResultsForEvent } from "tenetkit/runtime/driver/sql/session/terminalization";
17
+ const isTerminalEvent = (event) => event._tag === "RunCompleted" || event._tag === "RunFailed" || event._tag === "RunCancelled";
18
+ const makeEvent = (run, partial, sequence, occurredAt) => {
19
+ const base = {
20
+ specVersion: "1",
21
+ eventId: eventIdFor(run.runId, sequence),
22
+ runId: run.runId,
23
+ sequence,
24
+ executableRef: run.executableRef,
25
+ rootRunId: run.rootRunId,
26
+ depth: run.depth,
27
+ occurredAt,
28
+ };
29
+ Object.assign(base, run.parentRunId === undefined ? {} : { parentRunId: run.parentRunId });
30
+ Object.assign(base, run.message.causationId === undefined ? {} : { causationId: run.message.causationId });
31
+ Object.assign(base, run.message.correlationId === undefined ? {} : { correlationId: run.message.correlationId });
32
+ Object.assign(base, run.attempt > 0 ? { attemptId: `${run.runId}:attempt:${run.attempt}` } : {});
33
+ return decodeEvent(JSON.stringify(Object.assign(base, partial)));
34
+ };
17
35
  export const loadRun = (runId) => Effect.gen(function* () {
18
36
  const sql = yield* SqlClient.SqlClient;
19
37
  const rows = yield* sql `SELECT * FROM tenetkit_runs WHERE run_id = ${runId}`;
@@ -61,7 +79,7 @@ export const allocateSequence = (runId) => Effect.gen(function* () {
61
79
  WHERE run_id = ${runId}
62
80
  RETURNING last_sequence
63
81
  `;
64
- return Number(rows[0].last_sequence);
82
+ return rows[0].last_sequence;
65
83
  });
66
84
  export const appendEvent = Function.dual((args) => args.length >= 4 || (args.length === 3 && !("runId" in args[0])), (_hub, run, partial, nextStatus) => Effect.gen(function* () {
67
85
  const sql = yield* SqlClient.SqlClient;
@@ -74,21 +92,7 @@ export const appendEvent = Function.dual((args) => args.length >= 4 || (args.len
74
92
  yield* appendTerminalToolResultsForEvent({ run, event: partial });
75
93
  const sequence = yield* allocateSequence(run.runId);
76
94
  const occurredAt = yield* nowIso;
77
- const event = {
78
- specVersion: "1",
79
- eventId: eventIdFor(run.runId, sequence),
80
- runId: run.runId,
81
- sequence,
82
- executableRef: run.executableRef,
83
- rootRunId: run.rootRunId,
84
- depth: run.depth,
85
- occurredAt,
86
- ...(run.parentRunId === undefined ? {} : { parentRunId: run.parentRunId }),
87
- ...(run.message.causationId === undefined ? {} : { causationId: run.message.causationId }),
88
- ...(run.message.correlationId === undefined ? {} : { correlationId: run.message.correlationId }),
89
- ...(run.attempt > 0 ? { attemptId: `${run.runId}:attempt:${run.attempt}` } : {}),
90
- ...partial,
91
- };
95
+ const event = makeEvent(run, partial, sequence, occurredAt);
92
96
  yield* sql `
93
97
  INSERT INTO tenetkit_run_events (run_id, sequence, event_id, event_json)
94
98
  VALUES (${run.runId}, ${sequence}, ${event.eventId}, ${encodeEvent(event)})
@@ -99,23 +103,19 @@ export const appendEvent = Function.dual((args) => args.length >= 4 || (args.len
99
103
  `)[0];
100
104
  yield* sql `
101
105
  INSERT INTO tenetkit_tree_event_index (root_run_id, position, run_id, run_sequence, event_id)
102
- VALUES (${run.rootRunId}, ${Number(treeRoot.last_position)}, ${run.runId}, ${sequence}, ${event.eventId})
106
+ VALUES (${run.rootRunId}, ${treeRoot.last_position}, ${run.runId}, ${sequence}, ${event.eventId})
103
107
  `;
104
108
  const status = nextStatus ?? run.status;
105
- const activeWaitId = event._tag === "RunWaiting"
106
- ? event.wait.waitId
107
- : event._tag === "RunResumed"
108
- ? null
109
- : (run.activeWaitId ?? null);
110
- const terminalEventId = event._tag === "RunCompleted" || event._tag === "RunFailed" || event._tag === "RunCancelled"
111
- ? event.eventId
112
- : (run.terminalEventId ?? null);
109
+ let activeWaitId = run.activeWaitId ?? null;
110
+ if (event._tag === "RunWaiting")
111
+ activeWaitId = event.wait.waitId;
112
+ if (event._tag === "RunResumed")
113
+ activeWaitId = null;
114
+ const terminalEventId = isTerminalEvent(event) ? event.eventId : (run.terminalEventId ?? null);
113
115
  const cancellationRequested = event._tag === "RunCancellationRequested" || run.cancellationRequested;
114
- const cancelReason = event._tag === "RunCancellationRequested" && "reason" in event && typeof event.reason === "string"
115
- ? event.reason
116
- : (run.cancelReason ?? null);
116
+ const cancelReason = event._tag === "RunCancellationRequested" ? (event.reason ?? null) : (run.cancelReason ?? null);
117
117
  const attempt = event._tag === "RunAttemptStarted" ? event.attempt : run.attempt;
118
- const terminalPartial = event._tag === "RunCompleted" || event._tag === "RunFailed" || event._tag === "RunCancelled";
118
+ const terminalPartial = isTerminalEvent(event);
119
119
  if (terminalPartial) {
120
120
  yield* sql `
121
121
  UPDATE tenetkit_runs SET
@@ -171,9 +171,7 @@ export const promoteHead = Function.dual(3, (hub, address, sessionId) => Effect.
171
171
  WHERE address = ${address} AND session_id = ${sessionId}
172
172
  `;
173
173
  }
174
- const head = yield* loadRun(headId);
175
- if (head === undefined || head.status !== "queued" || head.cancellationRequested)
176
- return;
174
+ yield* loadRun(headId);
177
175
  }));
178
176
  export const removeFromLane = Function.dual(3, (address, sessionId, runId) => Effect.gen(function* () {
179
177
  const sql = yield* SqlClient.SqlClient;
@@ -217,7 +215,7 @@ export const completeRun = Function.dual(3, (hub, run, result) => Effect.gen(fun
217
215
  `;
218
216
  return;
219
217
  }
220
- const event = yield* appendEvent(hub, run, { _tag: "RunCancelled", ...(run.cancelReason === undefined ? {} : { reason: run.cancelReason }) }, "cancelled");
218
+ const event = yield* appendEvent(hub, run, { _tag: "RunCancelled", ...(run.cancelReason === undefined ? undefined : { reason: run.cancelReason }) }, "cancelled");
221
219
  const settled = (yield* loadRun(run.runId));
222
220
  yield* settleParent(hub, settled, event.eventId);
223
221
  yield* afterTerminal(hub, settled);
@@ -292,10 +290,13 @@ export const settleParent = Function.dual(3, (hub, child, terminalEventId) => Ef
292
290
  yield* sql `UPDATE tenetkit_runs SET attempt_fence = ${attempt} WHERE run_id = ${parent.runId}`;
293
291
  yield* appendEvent(hub, { ...currentParent, attempt }, { _tag: "RunAttemptStarted", attempt }, "running");
294
292
  }
295
- return;
296
293
  }
297
- if (currentParent?.status !== "cancelling" || currentParent.ownerWorkerId !== undefined)
298
- return;
294
+ else if (currentParent?.status === "cancelling" && currentParent.ownerWorkerId === undefined) {
295
+ yield* settleCancelledParent(hub, currentParent);
296
+ }
297
+ }));
298
+ const settleCancelledParent = (hub, parent) => Effect.gen(function* () {
299
+ const sql = yield* SqlClient.SqlClient;
299
300
  const running = yield* sql `
300
301
  SELECT fan_out_id FROM tenetkit_fan_outs WHERE parent_run_id = ${parent.runId} AND status = 'running' LIMIT 1
301
302
  `;
@@ -305,14 +306,14 @@ export const settleParent = Function.dual(3, (hub, child, terminalEventId) => Ef
305
306
  return;
306
307
  if (yield* hasUnsettledChild(parent.runId))
307
308
  return;
308
- const cancelled = yield* appendEvent(hub, currentParent, {
309
+ const cancelled = yield* appendEvent(hub, parent, {
309
310
  _tag: "RunCancelled",
310
- ...(currentParent.cancelReason === undefined ? {} : { reason: currentParent.cancelReason }),
311
+ ...(parent.cancelReason === undefined ? undefined : { reason: parent.cancelReason }),
311
312
  }, "cancelled");
312
313
  const settledParent = (yield* loadRun(parent.runId));
313
314
  yield* settleParent(hub, settledParent, cancelled.eventId);
314
315
  yield* afterTerminal(hub, settledParent);
315
- }));
316
+ });
316
317
  export const insertRun = (input) => Effect.gen(function* () {
317
318
  const sql = yield* SqlClient.SqlClient;
318
319
  yield* sql `
@@ -3,7 +3,7 @@ import { SqlClient } from "effect/unstable/sql";
3
3
  import { RunNotFound, RunTerminal, RuntimeUnavailable } from "tenetkit/runtime/driver/errors";
4
4
  import { StaleClaim } from "tenetkit/runtime/driver/sql/errors";
5
5
  import type { SqlError } from "effect/unstable/sql/SqlError";
6
- import type { Interface as RunStoreInterface } from "tenetkit/runtime/driver/run-store";
6
+ import type { Interface as RunStoreInterface } from "tenetkit/runtime/driver/run/store";
7
7
  import type { EventHub } from "tenetkit/runtime/driver/sql/subscribers";
8
8
  type SuspendEffect = Effect.Effect<undefined, RunNotFound | RunTerminal | RuntimeUnavailable | SqlError | StaleClaim, SqlClient.SqlClient>;
9
9
  export declare const suspend: {
@@ -2,18 +2,18 @@ import { Effect, Function, Option } from "effect";
2
2
  import { SqlClient } from "effect/unstable/sql";
3
3
  import { RunNotFound, RunTerminal, RuntimeUnavailable } from "tenetkit/runtime/driver/errors";
4
4
  import { StaleClaim } from "tenetkit/runtime/driver/sql/errors";
5
- import { checkpointRef } from "tenetkit/runtime/driver/executable-manifest";
5
+ import { checkpointRef } from "tenetkit/runtime/driver/executable/manifest";
6
6
  import { isTerminal } from "tenetkit/runtime/driver/run";
7
- import { encodeContinuation } from "tenetkit/runtime/driver/steering";
8
- import { encodeExecutableRef, encodeJson } from "tenetkit/runtime/driver/sql/codecs";
9
- import { encodeReason, WaitResolution } from "tenetkit/runtime/driver/run-wait";
10
- import { lockRun } from "./locks.js";
11
- import { appendEvent, requireRun } from "./pg-helpers.js";
12
- import { requireExecutionClaim } from "tenetkit/runtime/driver/sql/store-execution";
13
- import { groupIdFromSuspension, resultFromInspection } from "tenetkit/runtime/driver/child-group";
14
- import { inspectFanOut } from "tenetkit/runtime/driver/sql/store-fan-out";
15
- import { ExecutionCheckpoint, ExecutionSuspension } from "tenetkit/runtime/driver/execution-state";
16
- import { loadTerminalEvent, reconcileChildWaitWith } from "tenetkit/runtime/driver/sql/store-child-settlement";
7
+ import { encodeContinuation } from "tenetkit/runtime/driver/run/steering";
8
+ import { encodeExecutableRef, encodeJson } from "tenetkit/runtime/driver/sql/codec/codecs";
9
+ import { encodeReason, WaitResolution } from "tenetkit/runtime/driver/run/wait";
10
+ import { lockRun } from "../runs/locks.js";
11
+ import { appendEvent, requireRun } from "./runtime.js";
12
+ import { requireExecutionClaim } from "tenetkit/runtime/driver/sql/store/execution";
13
+ import { groupIdFromSuspension, resultFromInspection } from "tenetkit/runtime/driver/child/group";
14
+ import { inspectFanOut } from "tenetkit/runtime/driver/sql/store/fan-out/service";
15
+ import { ExecutionCheckpoint, ExecutionSuspension } from "tenetkit/runtime/driver/execution/state";
16
+ import { loadTerminalEvent, reconcileChildWaitWith } from "tenetkit/runtime/driver/sql/store/child/settlement";
17
17
  export const suspend = Function.dual(2, (hub, input) => Effect.gen(function* () {
18
18
  const sql = yield* SqlClient.SqlClient;
19
19
  yield* lockRun(input.runId);
@@ -49,9 +49,9 @@ export const suspend = Function.dual(2, (hub, input) => Effect.gen(function* ()
49
49
  status = 'open', reason = EXCLUDED.reason, response_json = NULL, opened_at = EXCLUDED.opened_at, closed_at = NULL
50
50
  `;
51
51
  yield* appendEvent(hub, loaded, { _tag: "RunWaiting", wait: input.wait }, "waiting");
52
- const child = typeof input.suspension.token === "string"
53
- ? yield* requireRun(input.suspension.token).pipe(Effect.option)
54
- : Option.none();
52
+ const child = input.suspension.token === undefined
53
+ ? Option.none()
54
+ : yield* requireRun(input.suspension.token).pipe(Effect.option);
55
55
  if (child._tag === "Some" && child.value.terminalEventId !== undefined) {
56
56
  const terminalEvent = yield* loadTerminalEvent(child.value.terminalEventId);
57
57
  if (terminalEvent !== undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "0.40.1",
3
+ "version": "0.41.2",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@effect/sql-pg": "4.0.0-rc.111",
42
- "tenetkit": "0.40.1"
42
+ "tenetkit": "0.41.2"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@effect/vitest": "4.0.0-rc.111",