@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/canonical-human-identities.js +2 -2
- package/dist/{chunk-F32YT7MP.js → chunk-FPVAD4CO.js} +2 -2
- package/dist/{chunk-TAUTWOS5.js → chunk-GYO7ED2Q.js} +2 -2
- package/dist/{chunk-P3RE4D2B.js → chunk-HSOWSYOX.js} +2 -2
- package/dist/{chunk-CQZ4QSP5.js → chunk-VTPRIXKG.js} +2 -2
- package/dist/{chunk-JC5QPLUM.js → chunk-Z7VYMNPZ.js} +47 -2
- package/dist/chunk-Z7VYMNPZ.js.map +1 -0
- package/dist/editable-artifact-durable-export.js +1 -1
- package/dist/editable-artifacts.js +2 -2
- package/dist/index.d.ts +29 -0
- package/dist/index.js +365 -21
- package/dist/index.js.map +1 -1
- package/dist/persistence-errors.d.ts +8 -0
- package/dist/session-tenancy.js +2 -2
- package/dist/video-generation.js +2 -2
- package/drizzle/0238_recover_unclaimed_session_turns.sql +307 -0
- package/package.json +4 -4
- package/src/index.ts +468 -17
- package/src/persistence-errors.ts +60 -1
- package/dist/chunk-JC5QPLUM.js.map +0 -1
- /package/dist/{chunk-F32YT7MP.js.map → chunk-FPVAD4CO.js.map} +0 -0
- /package/dist/{chunk-TAUTWOS5.js.map → chunk-GYO7ED2Q.js.map} +0 -0
- /package/dist/{chunk-P3RE4D2B.js.map → chunk-HSOWSYOX.js.map} +0 -0
- /package/dist/{chunk-CQZ4QSP5.js.map → chunk-VTPRIXKG.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
canonicalSessionVisibilityTransitionHash,
|
|
4
4
|
forkSessionContent,
|
|
5
5
|
transitionSessionVisibility
|
|
6
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
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:
|
|
65357
|
+
accountId: session.accountId,
|
|
65042
65358
|
workspaceId,
|
|
65043
|
-
sourceSessionId:
|
|
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:
|
|
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:
|
|
65368
|
+
childSessionId: session.id,
|
|
65053
65369
|
status: "failed",
|
|
65054
|
-
turnId:
|
|
65370
|
+
...input.turnId ? { turnId: input.turnId } : {}
|
|
65055
65371
|
},
|
|
65056
65372
|
lineage: {
|
|
65057
|
-
childSessionId:
|
|
65373
|
+
childSessionId: session.id,
|
|
65058
65374
|
parentSessionId: session.parentSessionId,
|
|
65059
65375
|
...session.parentTurnId ? { parentTurnId: session.parentTurnId } : {},
|
|
65060
|
-
turnId:
|
|
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
|
|
65181
|
-
// owned by another producer.
|
|
65182
|
-
//
|
|
65183
|
-
|
|
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,
|