@opengeni/db 0.36.0 → 0.36.1

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/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  canonicalSessionVisibilityTransitionHash,
4
4
  forkSessionContent,
5
5
  transitionSessionVisibility
6
- } from "./chunk-F32YT7MP.js";
6
+ } from "./chunk-FPVAD4CO.js";
7
7
  import {
8
8
  migrate,
9
9
  runMigrations
@@ -39,7 +39,7 @@ import {
39
39
  getCanonicalHumanIdentityProjection,
40
40
  synchronizeCanonicalHumanLoginBindings,
41
41
  validateCanonicalHumanSession
42
- } from "./chunk-TAUTWOS5.js";
42
+ } from "./chunk-GYO7ED2Q.js";
43
43
  import {
44
44
  EDITABLE_ARTIFACT_INTENT_MAX_BYTES,
45
45
  EDITABLE_ARTIFACT_KERNEL_TAIL_MAX_BYTES,
@@ -50,7 +50,7 @@ import {
50
50
  PostgresEditableArtifactStore,
51
51
  listEditableArtifactIdsForSession,
52
52
  touchEditableArtifactSessionLink
53
- } from "./chunk-P3RE4D2B.js";
53
+ } from "./chunk-HSOWSYOX.js";
54
54
  import {
55
55
  ACTIVE_VIDEO_GENERATION_STATUSES,
56
56
  VideoGenerationCapacityError,
@@ -82,7 +82,7 @@ import {
82
82
  settleVideoGenerationFailure,
83
83
  settleVideoGenerationReady,
84
84
  updateWorkspaceVideoGenerationPolicy
85
- } from "./chunk-CQZ4QSP5.js";
85
+ } from "./chunk-VTPRIXKG.js";
86
86
  import {
87
87
  SandboxProviderReadLockUnavailableError,
88
88
  SessionEventPersistenceError,
@@ -90,6 +90,7 @@ import {
90
90
  databaseFailureCode,
91
91
  dbBindingFor,
92
92
  isDatabasePersistenceFailure,
93
+ isRetryableDatabaseTransportFailure,
93
94
  isRetryablePersistenceSqlState,
94
95
  isSessionEventPersistenceError,
95
96
  nestedPostgresSqlState,
@@ -116,7 +117,7 @@ import {
116
117
  withWorkspaceSubjectRls,
117
118
  withWorkspaceSubjectSessionActivityRls,
118
119
  withWorkspaceUsageLock
119
- } from "./chunk-JC5QPLUM.js";
120
+ } from "./chunk-Z7VYMNPZ.js";
120
121
  import {
121
122
  LOSSLESS_CONTENT_CODEC_VERSION,
122
123
  LOSSLESS_TEXT_PREFIX,
@@ -59876,7 +59877,7 @@ async function materializeGoalContinuation(db, input) {
59876
59877
  eq43(sessionGoals.sessionId, input.sessionId)
59877
59878
  )
59878
59879
  ).for("update").limit(1);
59879
- if (!goalRead || goalRead.status !== "active" || session.status === "cancelled" || effectiveControl.state !== "active") {
59880
+ if (!goalRead || goalRead.status !== "active" || session.status === "failed" || session.status === "cancelled" || effectiveControl.state !== "active") {
59880
59881
  return { action: "none", events: [] };
59881
59882
  }
59882
59883
  const malformedGoalVersionEvidence = sql39`
@@ -60870,9 +60871,14 @@ async function goalSnapshotForAcceptedTurnInTransaction(tx, row) {
60870
60871
  }
60871
60872
  async function claimSessionWorkForAttempt(db, workspaceId, input) {
60872
60873
  const { sessionId, workflowId } = input;
60873
- return await withWorkspaceSessionActivityRls(
60874
+ return await retrySessionActivityRls(
60874
60875
  db,
60875
60876
  workspaceId,
60877
+ {
60878
+ stage: "session_attempts.claim",
60879
+ eventTypes: ["session.turn.attempt_claimed"],
60880
+ maxAttempts: 3
60881
+ },
60876
60882
  async (scopedDb) => await withSessionActivitySavepoint(scopedDb, async (tx) => {
60877
60883
  const deliverPendingUpdates = async (accountId, turnId, turnGeneration, nextSequence, occurredAt, triggerEventId, expectedXaiAuthority) => {
60878
60884
  const [agentSteer] = await tx.select().from(sessionSystemUpdates).where(
@@ -63026,6 +63032,317 @@ async function peekSessionWork(db, workspaceId, sessionId) {
63026
63032
  return pendingAgentSteer ? { kind: "runnable" } : { kind: "idle" };
63027
63033
  });
63028
63034
  }
63035
+ async function failSessionWorkBeforeAttemptClaim(db, workspaceId, input) {
63036
+ return await retrySessionActivityRls(
63037
+ db,
63038
+ workspaceId,
63039
+ {
63040
+ stage: "session_lifecycle_outbox.fail_before_attempt_claim",
63041
+ eventTypes: ["child_terminal_result", "session.status.changed", "turn.failed"],
63042
+ maxAttempts: 3
63043
+ },
63044
+ async (scopedDb) => await scopedDb.transaction(async (tx) => {
63045
+ const baseLocks = await lockChildLifecycleOutboxWriteRowsTx(
63046
+ tx,
63047
+ workspaceId,
63048
+ { sessionId: input.sessionId }
63049
+ );
63050
+ const session = baseLocks.session;
63051
+ if (session.accountId !== input.accountId) {
63052
+ throw new SessionControlInvariantError(
63053
+ `Session ${input.sessionId} does not belong to account ${input.accountId}`
63054
+ );
63055
+ }
63056
+ if (session.status === "failed" || session.status === "cancelled") {
63057
+ return { action: "terminal", turnId: null, events: [] };
63058
+ }
63059
+ if (session.temporalWorkflowId !== null && session.temporalWorkflowId !== input.workflowId) {
63060
+ return { action: "stale", turnId: null, events: [] };
63061
+ }
63062
+ const effectiveControl = await evaluateSessionControl(
63063
+ tx,
63064
+ workspaceId,
63065
+ input.sessionId,
63066
+ { workspaceControl: baseLocks.control ?? void 0 }
63067
+ );
63068
+ if (!baseLocks.workspace || effectiveControl.state !== "active") {
63069
+ return { action: "stale", turnId: null, events: [] };
63070
+ }
63071
+ const [liveAttempt] = await tx.select({ id: sessionTurnAttempts.id }).from(sessionTurnAttempts).where(
63072
+ and42(
63073
+ eq43(sessionTurnAttempts.workspaceId, workspaceId),
63074
+ eq43(sessionTurnAttempts.sessionId, input.sessionId),
63075
+ inArray25(sessionTurnAttempts.state, ["claimed", "running"])
63076
+ )
63077
+ ).limit(1);
63078
+ if (liveAttempt) {
63079
+ return { action: "stale", turnId: null, events: [] };
63080
+ }
63081
+ let turn = null;
63082
+ if (session.activeTurnId) {
63083
+ const exactLocks = await lockSessionEventWriteRows(tx, {
63084
+ workspaceId,
63085
+ controlLock: "already_locked",
63086
+ workspaceLock: "already_locked",
63087
+ turnIds: [session.activeTurnId]
63088
+ });
63089
+ turn = exactLocks.turns[0] ?? null;
63090
+ if (!turn || turn.accountId !== session.accountId || turn.sessionId !== input.sessionId) {
63091
+ turn = null;
63092
+ }
63093
+ if (turn && isTerminalSessionTurnStatus(turn.status)) {
63094
+ turn = null;
63095
+ } else if (turn && input.trigger.kind === "approval") {
63096
+ if (turn.status !== "requires_action" || !await isNewerApprovalTrigger(
63097
+ tx,
63098
+ workspaceId,
63099
+ input.sessionId,
63100
+ turn.triggerEventId,
63101
+ input.trigger.triggerEventId
63102
+ )) {
63103
+ return { action: "stale", turnId: null, events: [] };
63104
+ }
63105
+ } else if (turn) {
63106
+ if (turn.status === "requires_action") {
63107
+ return { action: "stale", turnId: null, events: [] };
63108
+ }
63109
+ if (turn.status === "waiting_capacity") {
63110
+ const [codexWaiter] = await tx.select({ id: codexCapacityWaiters.id }).from(codexCapacityWaiters).where(
63111
+ and42(
63112
+ eq43(codexCapacityWaiters.workspaceId, workspaceId),
63113
+ eq43(codexCapacityWaiters.sessionId, input.sessionId),
63114
+ eq43(codexCapacityWaiters.status, "waiting")
63115
+ )
63116
+ ).limit(1);
63117
+ const xaiWaiter = await getXaiCapacityWaitForSessionInTransaction(
63118
+ tx,
63119
+ workspaceId,
63120
+ input.sessionId
63121
+ );
63122
+ if (codexWaiter || xaiWaiter) {
63123
+ return { action: "stale", turnId: null, events: [] };
63124
+ }
63125
+ }
63126
+ }
63127
+ } else {
63128
+ if (input.trigger.kind === "approval") {
63129
+ return { action: "stale", turnId: null, events: [] };
63130
+ }
63131
+ const [pendingAgentSteer] = await tx.select({ id: sessionSystemUpdates.id }).from(sessionSystemUpdates).where(
63132
+ and42(
63133
+ eq43(sessionSystemUpdates.workspaceId, workspaceId),
63134
+ eq43(sessionSystemUpdates.sessionId, input.sessionId),
63135
+ eq43(sessionSystemUpdates.kind, "agent_steer_instruction"),
63136
+ eq43(sessionSystemUpdates.state, "pending")
63137
+ )
63138
+ ).orderBy(
63139
+ desc17(sessionSystemUpdates.createdAt),
63140
+ desc17(sessionSystemUpdates.id)
63141
+ ).limit(1);
63142
+ const queuedRows = await rawRows(
63143
+ tx,
63144
+ sql39`select id from session_turns
63145
+ where workspace_id = ${workspaceId} and session_id = ${input.sessionId}
63146
+ and status = 'queued' and source in ('user', 'api')
63147
+ and (
63148
+ ${Boolean(pendingAgentSteer)} = false
63149
+ or metadata->>'delivery' = 'steer'
63150
+ )
63151
+ order by position asc, created_at asc, id asc
63152
+ limit 1`
63153
+ );
63154
+ const queuedPreview = queuedRows[0];
63155
+ if (queuedPreview) {
63156
+ const exactLocks = await lockSessionEventWriteRows(tx, {
63157
+ workspaceId,
63158
+ controlLock: "already_locked",
63159
+ workspaceLock: "already_locked",
63160
+ turnIds: [queuedPreview.id]
63161
+ });
63162
+ turn = exactLocks.turns[0] ?? null;
63163
+ if (!turn || turn.accountId !== session.accountId || turn.sessionId !== input.sessionId || turn.status !== "queued" || turn.activeAttemptId !== null) {
63164
+ return { action: "stale", turnId: null, events: [] };
63165
+ }
63166
+ } else if (!session.compactRequested) {
63167
+ if (!pendingAgentSteer && await latestFinishedTurnHasFailureCodeTx(
63168
+ tx,
63169
+ workspaceId,
63170
+ input.sessionId,
63171
+ "context_compaction_failed"
63172
+ )) {
63173
+ return { action: "stale", turnId: null, events: [] };
63174
+ }
63175
+ const [pendingUpdate] = await tx.select({ id: sessionSystemUpdates.id }).from(sessionSystemUpdates).where(
63176
+ and42(
63177
+ eq43(sessionSystemUpdates.workspaceId, workspaceId),
63178
+ eq43(sessionSystemUpdates.sessionId, input.sessionId),
63179
+ eq43(sessionSystemUpdates.state, "pending")
63180
+ )
63181
+ ).limit(1).for("update");
63182
+ if (!pendingUpdate) {
63183
+ return { action: "stale", turnId: null, events: [] };
63184
+ }
63185
+ }
63186
+ }
63187
+ const now = /* @__PURE__ */ new Date();
63188
+ let sequence = session.lastSequence;
63189
+ let closedToolEvents = [];
63190
+ if (turn) {
63191
+ await cancelTurnInteractionInterventionsInTransaction(tx, {
63192
+ accountId: session.accountId,
63193
+ workspaceId,
63194
+ sessionId: input.sessionId,
63195
+ turnId: turn.id
63196
+ });
63197
+ const closedTools = await closePendingSessionToolCallsInTransaction(
63198
+ tx,
63199
+ {
63200
+ accountId: session.accountId,
63201
+ workspaceId,
63202
+ sessionId: input.sessionId,
63203
+ turnId: turn.id,
63204
+ reason: "turn_failed",
63205
+ sequence,
63206
+ now
63207
+ }
63208
+ );
63209
+ sequence = closedTools.sequence;
63210
+ closedToolEvents = closedTools.events;
63211
+ await tx.update(sessionHumanInputRequests).set({
63212
+ status: "cancelled",
63213
+ response: { outcome: "cancelled" },
63214
+ respondedBy: "system:turn_failed",
63215
+ respondedAt: now,
63216
+ updatedAt: now
63217
+ }).where(
63218
+ and42(
63219
+ eq43(sessionHumanInputRequests.workspaceId, workspaceId),
63220
+ eq43(sessionHumanInputRequests.sessionId, input.sessionId),
63221
+ eq43(sessionHumanInputRequests.turnId, turn.id),
63222
+ eq43(sessionHumanInputRequests.status, "pending")
63223
+ )
63224
+ );
63225
+ }
63226
+ await settleSessionMaintenanceInTransaction(tx, {
63227
+ accountId: session.accountId,
63228
+ workspaceId,
63229
+ sessionId: input.sessionId
63230
+ });
63231
+ if (!turn) {
63232
+ await tx.update(sessionSystemUpdates).set({ state: "failed" }).where(
63233
+ and42(
63234
+ eq43(sessionSystemUpdates.workspaceId, workspaceId),
63235
+ eq43(sessionSystemUpdates.sessionId, input.sessionId),
63236
+ eq43(sessionSystemUpdates.state, "pending")
63237
+ )
63238
+ );
63239
+ }
63240
+ const values = [
63241
+ ...turn ? [
63242
+ {
63243
+ accountId: session.accountId,
63244
+ workspaceId,
63245
+ sessionId: input.sessionId,
63246
+ sequence: ++sequence,
63247
+ type: "turn.failed",
63248
+ payload: {
63249
+ triggerEventId: turn.triggerEventId,
63250
+ code: "pre_claim_failure",
63251
+ error: input.error
63252
+ },
63253
+ turnId: turn.id,
63254
+ turnGeneration: turn.executionGeneration,
63255
+ turnAttemptId: null,
63256
+ turnAssociation: "current",
63257
+ occurredAt: now
63258
+ }
63259
+ ] : [],
63260
+ {
63261
+ accountId: session.accountId,
63262
+ workspaceId,
63263
+ sessionId: input.sessionId,
63264
+ sequence: ++sequence,
63265
+ type: "session.status.changed",
63266
+ payload: { status: "failed", code: "pre_claim_failure" },
63267
+ turnId: turn?.id ?? null,
63268
+ turnGeneration: turn?.executionGeneration ?? null,
63269
+ turnAttemptId: null,
63270
+ turnAssociation: turn ? "current" : null,
63271
+ occurredAt: now
63272
+ }
63273
+ ];
63274
+ const inserted = await tx.insert(sessionEvents).values(withLosslessContentWriteVersion(values, "payload", "payloadCodecVersion")).returning();
63275
+ if (turn) {
63276
+ const failedEvent = inserted.find((event) => event.type === "turn.failed");
63277
+ if (!failedEvent) {
63278
+ throw new SessionControlInvariantError(
63279
+ `Pre-claim failure for turn ${turn.id} has no terminal event`
63280
+ );
63281
+ }
63282
+ await projectSessionRealtimeDelegationTerminalInTransaction(tx, {
63283
+ accountId: session.accountId,
63284
+ workspaceId,
63285
+ sessionId: input.sessionId,
63286
+ turnId: turn.id,
63287
+ turnStatus: "failed",
63288
+ terminalEvent: {
63289
+ id: failedEvent.id,
63290
+ type: "turn.failed",
63291
+ payload: sessionEventPayloadRecord(
63292
+ failedEvent.payload,
63293
+ failedEvent.payloadCodecVersion
63294
+ )
63295
+ },
63296
+ now
63297
+ });
63298
+ await tx.update(sessionTurns).set({
63299
+ status: "failed",
63300
+ activeAttemptId: null,
63301
+ version: turn.version + 1,
63302
+ finishedAt: now,
63303
+ updatedAt: now
63304
+ }).where(
63305
+ and42(
63306
+ eq43(sessionTurns.workspaceId, workspaceId),
63307
+ eq43(sessionTurns.sessionId, input.sessionId),
63308
+ eq43(sessionTurns.id, turn.id)
63309
+ )
63310
+ );
63311
+ await enqueueFailedChildOutboxForTurnTx(
63312
+ tx,
63313
+ workspaceId,
63314
+ session,
63315
+ turn
63316
+ );
63317
+ } else {
63318
+ await enqueueFailedChildOutboxWithoutTurnTx(
63319
+ tx,
63320
+ workspaceId,
63321
+ session,
63322
+ sequence
63323
+ );
63324
+ }
63325
+ await tx.update(sessions).set({
63326
+ status: "failed",
63327
+ activeTurnId: null,
63328
+ compactRequested: false,
63329
+ lastSequence: sequence,
63330
+ queueVersion: session.queueVersion + 1,
63331
+ updatedAt: now
63332
+ }).where(
63333
+ and42(
63334
+ eq43(sessions.workspaceId, workspaceId),
63335
+ eq43(sessions.id, input.sessionId)
63336
+ )
63337
+ );
63338
+ return {
63339
+ action: "failed",
63340
+ turnId: turn?.id ?? null,
63341
+ events: [...closedToolEvents, ...inserted.map(mapEvent2)]
63342
+ };
63343
+ })
63344
+ );
63345
+ }
63029
63346
  async function lockChildLifecycleOutboxWriteRowsTx(tx, workspaceId, input) {
63030
63347
  const prefix = await lockSessionEventWriteRows(tx, {
63031
63348
  workspaceId,
@@ -65004,9 +65321,8 @@ function queuedSteerReplacementAttemptId(metadata) {
65004
65321
  }
65005
65322
  return null;
65006
65323
  }
65007
- async function enqueueFailedChildOutboxForTurnTx(tx, workspaceId, session, turn) {
65324
+ async function enqueueFailedChildOutboxTx(tx, workspaceId, session, input) {
65008
65325
  if (!session.parentSessionId) return;
65009
- const dedupeKey = `child-completion:${turn.sessionId}:turn:${turn.id}`;
65010
65326
  const personalConnectionDelegations = session.parentTurnId ? await personalConnectionDelegationsForTurnInTransaction(
65011
65327
  tx,
65012
65328
  workspaceId,
@@ -65038,26 +65354,26 @@ async function enqueueFailedChildOutboxForTurnTx(tx, workspaceId, session, turn)
65038
65354
  withLosslessContentWriteVersion(
65039
65355
  withLosslessContentWriteVersion(
65040
65356
  {
65041
- accountId: turn.accountId,
65357
+ accountId: session.accountId,
65042
65358
  workspaceId,
65043
- sourceSessionId: turn.sessionId,
65359
+ sourceSessionId: session.id,
65044
65360
  targetSessionId: session.parentSessionId,
65045
- dedupeKey,
65361
+ dedupeKey: input.dedupeKey,
65046
65362
  kind: "child_terminal_result",
65047
65363
  classification: "failure",
65048
- sourceId: turn.sessionId,
65364
+ sourceId: session.id,
65049
65365
  summary: "Child session failed; inspect the durable child timeline.",
65050
65366
  payload: {
65051
65367
  type: "child_terminal_result",
65052
- childSessionId: turn.sessionId,
65368
+ childSessionId: session.id,
65053
65369
  status: "failed",
65054
- turnId: turn.id
65370
+ ...input.turnId ? { turnId: input.turnId } : {}
65055
65371
  },
65056
65372
  lineage: {
65057
- childSessionId: turn.sessionId,
65373
+ childSessionId: session.id,
65058
65374
  parentSessionId: session.parentSessionId,
65059
65375
  ...session.parentTurnId ? { parentTurnId: session.parentTurnId } : {},
65060
- turnId: turn.id,
65376
+ ...input.turnId ? { turnId: input.turnId } : {},
65061
65377
  ...xaiAuthoritySubjectId ? { xaiAuthoritySubjectId } : {}
65062
65378
  },
65063
65379
  personalConnectionDelegations,
@@ -65076,6 +65392,23 @@ async function enqueueFailedChildOutboxForTurnTx(tx, workspaceId, session, turn)
65076
65392
  ]
65077
65393
  });
65078
65394
  }
65395
+ async function enqueueFailedChildOutboxForTurnTx(tx, workspaceId, session, turn) {
65396
+ if (turn.accountId !== session.accountId || turn.sessionId !== session.id) {
65397
+ throw new SessionControlInvariantError(
65398
+ `Failed child turn ${turn.id} lost session ${session.id} ownership`
65399
+ );
65400
+ }
65401
+ await enqueueFailedChildOutboxTx(tx, workspaceId, session, {
65402
+ turnId: turn.id,
65403
+ dedupeKey: `child-completion:${turn.sessionId}:turn:${turn.id}`
65404
+ });
65405
+ }
65406
+ async function enqueueFailedChildOutboxWithoutTurnTx(tx, workspaceId, session, terminalSequence) {
65407
+ await enqueueFailedChildOutboxTx(tx, workspaceId, session, {
65408
+ turnId: null,
65409
+ dedupeKey: `child-completion:${session.id}:pre-claim:${terminalSequence}`
65410
+ });
65411
+ }
65079
65412
  function parseChildTerminalResultPayload(input) {
65080
65413
  const payload = SessionSystemUpdatePayload.parse(input);
65081
65414
  if (payload.type !== "child_terminal_result") {
@@ -65177,10 +65510,19 @@ async function enqueueSessionWorkflowWakeInTransaction(tx, input) {
65177
65510
  controlRevision: input.controlRequested ? sql39`${sessionWorkflowWakeOutbox.wakeRevision} + 1` : sql39`${sessionWorkflowWakeOutbox.controlRevision}`,
65178
65511
  reason: input.reason,
65179
65512
  attempts: 0,
65180
- // Coalescing a delayed retry must never postpone an already-due wake
65181
- // owned by another producer. A later revision makes the batch richer;
65182
- // it does not revoke the earlier delivery obligation.
65183
- nextAttemptAt: sql39`least(${sessionWorkflowWakeOutbox.nextAttemptAt}, ${nextAttemptAt.toISOString()}::timestamptz)`,
65513
+ // Coalescing a delayed retry must never postpone an undelivered wake
65514
+ // owned by another producer. Once every prior revision is delivered,
65515
+ // however, this is a new obligation and must honor its own deadline;
65516
+ // retaining the old (usually past) deadline would defeat backoff.
65517
+ nextAttemptAt: sql39`case
65518
+ when ${sessionWorkflowWakeOutbox.wakeRevision}
65519
+ > ${sessionWorkflowWakeOutbox.deliveredRevision}
65520
+ then least(
65521
+ ${sessionWorkflowWakeOutbox.nextAttemptAt},
65522
+ ${nextAttemptAt.toISOString()}::timestamptz
65523
+ )
65524
+ else ${nextAttemptAt.toISOString()}::timestamptz
65525
+ end`,
65184
65526
  lastError: null,
65185
65527
  updatedAt: now
65186
65528
  }
@@ -68019,6 +68361,7 @@ export {
68019
68361
  failMemorySlackPublication,
68020
68362
  failSandboxRematerialization,
68021
68363
  failSessionRealtimeConnectionInTransaction,
68364
+ failSessionWorkBeforeAttemptClaim,
68022
68365
  failTranscriptionRecordingAssembly,
68023
68366
  failTranscriptionRecordingSegment,
68024
68367
  failWarmingToCold,
@@ -68243,6 +68586,7 @@ export {
68243
68586
  isMemoryScopeApplicable,
68244
68587
  isMemoryTextTooLong,
68245
68588
  isPrivateAddress,
68589
+ isRetryableDatabaseTransportFailure,
68246
68590
  isRetryablePersistenceSqlState,
68247
68591
  isSessionCompactionRequested,
68248
68592
  isSessionEventPersistenceError,