( input: CommitOrCreateTerminalRunFactInput, )
| 171 | } |
| 172 | |
| 173 | export async function commitOrCreateTerminalRunFact( |
| 174 | input: CommitOrCreateTerminalRunFactInput, |
| 175 | ): Promise<CommitOrCreateTerminalRunFactResult> { |
| 176 | const createdTerminalEvent = !input.terminalEvent; |
| 177 | const effectiveAbortSource = |
| 178 | input.fallbackStatus === 'cancelled' ? (input.abortSource ?? 'user_stop') : input.abortSource; |
| 179 | const terminalEvent = |
| 180 | input.terminalEvent ?? |
| 181 | buildSyntheticTerminalRuntimeEvent({ |
| 182 | id: input.newId(), |
| 183 | invocationId: input.fallbackInvocationId, |
| 184 | run: { |
| 185 | sessionId: input.sessionId, |
| 186 | runId: input.runId, |
| 187 | turnId: input.turnId, |
| 188 | }, |
| 189 | status: input.fallbackStatus, |
| 190 | ts: input.ts, |
| 191 | ...(input.fallbackFailureClass ? { failureClass: input.fallbackFailureClass } : {}), |
| 192 | ...(effectiveAbortSource ? { abortSource: effectiveAbortSource } : {}), |
| 193 | ...((input.fallbackFailureMessage ?? input.failureMessage) |
| 194 | ? { message: input.fallbackFailureMessage ?? input.failureMessage } |
| 195 | : {}), |
| 196 | }); |
| 197 | const status = terminalRunStatusFromRuntimeEvent(terminalEvent); |
| 198 | if (!status) { |
| 199 | throw new Error('terminal RuntimeEvent must carry a terminal status'); |
| 200 | } |
| 201 | if (isPartialRuntimeEvent(terminalEvent)) { |
| 202 | throw new Error('terminal RuntimeEvent must be final before terminal run header'); |
| 203 | } |
| 204 | if ( |
| 205 | terminalEvent.sessionId !== input.sessionId || |
| 206 | terminalEvent.runId !== input.runId || |
| 207 | terminalEvent.turnId !== input.turnId |
| 208 | ) { |
| 209 | throw new Error('terminal RuntimeEvent identity does not match run header commit'); |
| 210 | } |
| 211 | const failureClass = |
| 212 | status === 'failed' |
| 213 | ? (runtimeEventFailureClass(terminalEvent) ?? input.failureClass ?? 'unknown') |
| 214 | : undefined; |
| 215 | await input.runtimeEventStore.ensureTerminalRuntimeEventDurable( |
| 216 | input.sessionId, |
| 217 | input.runId, |
| 218 | terminalEvent, |
| 219 | ); |
| 220 | // Between the terminal durability barrier and the header commit: the one |
| 221 | // point where "the terminal fact is durable" is true and nothing else has |
| 222 | // been projected yet. Callers that must order a crash boundary against |
| 223 | // the barrier itself hang it here (#2313 corruption recovery, where the |
| 224 | // claimed event's own write never ran). |
| 225 | await input.afterTerminalDurable?.(); |
| 226 | let headerCommitted = false; |
| 227 | let headerCommitError: unknown; |
| 228 | try { |
| 229 | await commitTerminalRunProjection({ |
| 230 | ...input, |
no test coverage detected