@opengeni/db 4.3.3-canary.0 → 4.3.3-canary.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.
@@ -0,0 +1,12 @@
1
+ /** Observations about this session, never allocator inputs or failover policy. */
2
+ export declare function codexSelectionDiagnostics(input: {
3
+ previousCredentialId: string | null;
4
+ credentialId: string;
5
+ reusedLease: boolean;
6
+ pinnedCredentialId: string | null;
7
+ pinSource?: "manual" | "policy" | null;
8
+ }): {
9
+ transition: "assigned" | "switched" | "unchanged";
10
+ source: "allocator" | "manual_pin";
11
+ reason: "affinity_reused" | "assigned" | "lease_reused" | "switched";
12
+ };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { codexSelectionDiagnostics } from "./codex-selection-diagnostics.js";
2
+ export { codexSelectionDiagnostics } from "./codex-selection-diagnostics.js";
1
3
  import { type ModelConnectionAccess, type ModelConnectionTarget } from "./model-connection-access.js";
2
4
  export { assertModelConnectionAllowsTurn, modelAllowedByConnections, type ConnectionModelRestrictions, } from "./workspace-model-connection-access.js";
3
5
  export * from "./model-connection-access.js";
@@ -4884,6 +4886,27 @@ export declare function switchSessionCodexAccount(db: Database, input: {
4884
4886
  }>>;
4885
4887
  export declare function setSessionCodexPin(db: Database, workspaceId: string, sessionId: string, pinnedCredentialId: string | null, source?: CodexPinSource, options?: SetSessionCodexPinOptions): Promise<boolean>;
4886
4888
  /** Written by the worker at the turn boundary; drives the in-session indicator. */
4889
+ /** Commit observed assignment and its events together under the exact live attempt.
4890
+ * Allocation still uses its frozen policy snapshot; this is observation only.
4891
+ * Replays return the same receipt and never manufacture a second switch.
4892
+ */
4893
+ export declare function recordSessionCodexSelectionForTurnAttempt(db: Database, input: {
4894
+ workspaceId: string;
4895
+ sessionId: string;
4896
+ turnId: string;
4897
+ attemptId: string;
4898
+ executionGeneration: number;
4899
+ credentialId: string;
4900
+ strategy: string;
4901
+ reusedLease: boolean;
4902
+ pinnedCredentialId: string | null;
4903
+ pinSource: "manual" | "policy" | null;
4904
+ eligibleCount: number;
4905
+ connectedCount: number;
4906
+ }): Promise<{
4907
+ events: SessionEvent[];
4908
+ diagnostics: ReturnType<typeof codexSelectionDiagnostics>;
4909
+ }>;
4887
4910
  export declare function recordSessionActiveCodexCredential(db: Database, workspaceId: string, sessionId: string, credentialId: string): Promise<void>;
4888
4911
  /**
4889
4912
  * Disconnect ONE account. DELETE WHERE id = credentialId AND workspace_id. If it
@@ -5471,7 +5494,6 @@ export declare function reapExpiredSessionListSnapshots(db: Database, limit?: nu
5471
5494
  * lifecycle/title and authorization data.
5472
5495
  */
5473
5496
  export declare function listSessionsForSubject(db: Database, workspaceId: string, options: ListSessionsForSubjectOptions): Promise<SessionListResponse>;
5474
- /** Read a session with the caller subject's personal pin projection. */
5475
5497
  export declare function getSessionForSubject(db: Database, workspaceId: string, sessionId: string, subjectId: string, relatedSessionAccess?: "target" | "root"): Promise<Session | null>;
5476
5498
  /**
5477
5499
  * Idempotently set a member's pin without mutating the session's lifecycle or
package/dist/index.js CHANGED
@@ -494,6 +494,14 @@ import {
494
494
  } from "./chunk-6TKL3GQO.js";
495
495
  import "./chunk-PZ5AY32C.js";
496
496
 
497
+ // src/codex-selection-diagnostics.ts
498
+ function codexSelectionDiagnostics(input) {
499
+ const transition = input.previousCredentialId === input.credentialId ? "unchanged" : input.previousCredentialId === null ? "assigned" : "switched";
500
+ const source = input.pinnedCredentialId === input.credentialId && input.pinSource !== "policy" ? "manual_pin" : "allocator";
501
+ const reason = input.reusedLease ? "lease_reused" : transition === "unchanged" ? "affinity_reused" : transition;
502
+ return { transition, source, reason };
503
+ }
504
+
497
505
  // src/session-execution-policy.ts
498
506
  import { and, desc, eq, inArray, sql } from "drizzle-orm";
499
507
  function latestStartedSessionTurnQuery(db, workspaceId, sessionId) {
@@ -9272,14 +9280,41 @@ import {
9272
9280
  } from "@opengeni/contracts";
9273
9281
  import {
9274
9282
  environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes2,
9275
- SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS,
9276
- SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS,
9283
+ SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS as SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS2,
9277
9284
  WORKSPACE_OPENROUTER_CONNECTION_DOMAIN as WORKSPACE_OPENROUTER_CONNECTION_DOMAIN2,
9278
9285
  WORKSPACE_OPENROUTER_CONNECTION_ROLE,
9279
9286
  VERCEL_AI_GATEWAY_CONNECTION_DOMAIN as VERCEL_AI_GATEWAY_CONNECTION_DOMAIN2,
9280
9287
  VERCEL_AI_GATEWAY_CONNECTION_ROLE
9281
9288
  } from "@opengeni/config";
9282
9289
 
9290
+ // src/sandbox-transition-wait.ts
9291
+ import {
9292
+ SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS,
9293
+ SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS
9294
+ } from "@opengeni/config";
9295
+ var SandboxTransitionWaitBudget = class {
9296
+ constructor(waitMs, startedAt) {
9297
+ this.waitMs = waitMs;
9298
+ this.hardDeadline = startedAt + SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS;
9299
+ this.currentDeadline = Math.min(this.hardDeadline, startedAt + waitMs);
9300
+ }
9301
+ observedCapture = false;
9302
+ currentDeadline;
9303
+ hardDeadline;
9304
+ get deadline() {
9305
+ return this.currentDeadline;
9306
+ }
9307
+ observeCapture(remainingMs, now) {
9308
+ if (this.waitMs === 0 || this.observedCapture || remainingMs === null || remainingMs === void 0 || !Number.isSafeInteger(remainingMs) || remainingMs < 0 || remainingMs > SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS)
9309
+ return;
9310
+ this.observedCapture = true;
9311
+ this.currentDeadline = Math.min(
9312
+ this.hardDeadline,
9313
+ Math.max(this.currentDeadline, now + remainingMs + SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS)
9314
+ );
9315
+ }
9316
+ };
9317
+
9283
9318
  // src/workspace-membership-permissions.ts
9284
9319
  import { Permission as PermissionSchema } from "@opengeni/contracts";
9285
9320
  function normalizeWorkspaceMembershipPermissions(value) {
@@ -10205,7 +10240,12 @@ import {
10205
10240
  // src/session-mcp-progress.ts
10206
10241
  import { sql as sql22 } from "drizzle-orm";
10207
10242
  var SESSION_MCP_PROGRESS_CHARS = 600;
10208
- var SESSION_MCP_PROGRESS_STORAGE_CHARS = LOSSLESS_JSON_STRING_PREFIX.length + Math.ceil((SESSION_MCP_PROGRESS_CHARS + 1) * 2 / 3) * 8;
10243
+ function sessionTextStoragePrefixChars(maxChars) {
10244
+ return LOSSLESS_JSON_STRING_PREFIX.length + Math.ceil((maxChars + 1) * 2 / 3) * 8;
10245
+ }
10246
+ var SESSION_MCP_PROGRESS_STORAGE_CHARS = sessionTextStoragePrefixChars(
10247
+ SESSION_MCP_PROGRESS_CHARS
10248
+ );
10209
10249
  var SESSION_MCP_PROGRESS_UTF16_BASE64_PATTERN = "([A-Za-z0-9+/]{8})*([A-Za-z0-9+/]{8}|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=|[A-Za-z0-9+/]{5}[AQgw]==)";
10210
10250
  function sessionMcpProgressScalarIsEncodedSql(value, codecVersion) {
10211
10251
  return sql22`coalesce(
@@ -10216,18 +10256,27 @@ function sessionMcpProgressScalarIsEncodedSql(value, codecVersion) {
10216
10256
  false
10217
10257
  )`;
10218
10258
  }
10219
- function projectSessionMcpProgressText(storedPrefix, storedChars, codecVersion, scalarIsEncoded) {
10259
+ function projectSessionTextPrefix(storedPrefix, storedChars, codecVersion, scalarIsEncoded, maxChars) {
10220
10260
  if (storedPrefix === null) return { text: null, originalChars: null };
10221
10261
  const decoded = scalarIsEncoded ? fromPostgresLosslessJson(storedPrefix, codecVersion) : storedPrefix;
10222
10262
  const chars = Array.from(decoded);
10223
10263
  const encodedPrefixWasCut = decoded !== storedPrefix && (storedChars ?? 0) > Array.from(storedPrefix).length;
10224
10264
  const originalChars = encodedPrefixWasCut ? null : decoded === storedPrefix ? storedChars : chars.length;
10225
10265
  return {
10226
- text: chars.slice(0, SESSION_MCP_PROGRESS_CHARS).join(""),
10266
+ text: chars.slice(0, maxChars).join(""),
10227
10267
  originalChars,
10228
10268
  ...encodedPrefixWasCut ? { textTruncated: true } : {}
10229
10269
  };
10230
10270
  }
10271
+ function projectSessionMcpProgressText(storedPrefix, storedChars, codecVersion, scalarIsEncoded) {
10272
+ return projectSessionTextPrefix(
10273
+ storedPrefix,
10274
+ storedChars,
10275
+ codecVersion,
10276
+ scalarIsEncoded,
10277
+ SESSION_MCP_PROGRESS_CHARS
10278
+ );
10279
+ }
10231
10280
 
10232
10281
  // src/new-session-drafts.ts
10233
10282
  import {
@@ -34161,6 +34210,7 @@ async function listInstalledPluginPackages(db, workspaceId) {
34161
34210
  return rows.map((row) => {
34162
34211
  const manifest = objectValue3(row.manifest);
34163
34212
  const sourceUrl = stringValue5(manifest.sourceUrl);
34213
+ const logoUrl = stringValue5(objectValue3(manifest.discovery).logoUrl);
34164
34214
  const bom = pluginBom(manifest);
34165
34215
  if (row.status !== "active" && row.status !== "needs_attention") {
34166
34216
  throw new Error(`Unknown installed Plugin status: ${row.status}`);
@@ -34173,6 +34223,7 @@ async function listInstalledPluginPackages(db, workspaceId) {
34173
34223
  category: row.category,
34174
34224
  tags: stringArray3(manifest.tags).length > 0 ? stringArray3(manifest.tags) : stringArray3(row.tags),
34175
34225
  sourceUrl: sourceUrl && safeHttpUrl(sourceUrl) ? sourceUrl : null,
34226
+ logoUrl: logoUrl && safeHttpUrl(logoUrl) ? logoUrl : null,
34176
34227
  manifestDigest: row.manifestDigest,
34177
34228
  installationVersion: row.installationVersion,
34178
34229
  componentCount: bom.length,
@@ -40521,7 +40572,7 @@ async function prepareComputerSessionCreate(db, input) {
40521
40572
  requestDigest: digest2,
40522
40573
  state: "prepared",
40523
40574
  actorSubjectId: input.actorSubjectId
40524
- }).onConflictDoNothing({ target: interactionOperations.operationId }).returning();
40575
+ }).onConflictDoNothing().returning();
40525
40576
  if (!insertedOperation) {
40526
40577
  const existing = await loadOperation3(tx, input.workspaceId, input.operationId);
40527
40578
  if (!existing) {
@@ -61548,6 +61599,86 @@ async function setSessionCodexPin(db, workspaceId, sessionId, pinnedCredentialId
61548
61599
  )
61549
61600
  );
61550
61601
  }
61602
+ async function recordSessionCodexSelectionForTurnAttempt(db, input) {
61603
+ return await withWorkspaceSessionEventActivityRls(db, input.workspaceId, true, async (tx) => {
61604
+ const fence = await lockTurnAttemptWriteFenceTx(tx, {
61605
+ workspaceId: input.workspaceId,
61606
+ sessionId: input.sessionId,
61607
+ turnId: input.turnId,
61608
+ executionGeneration: input.executionGeneration,
61609
+ attemptId: input.attemptId,
61610
+ sessionLock: "no_key_update"
61611
+ });
61612
+ if (!fence.allowed || !fence.session) throw new CodexCredentialLeaseAttemptFencedError();
61613
+ const key2 = `opengeni:codex-selection:${input.attemptId}`;
61614
+ const prior = await tx.select().from(sessionEvents).where(
61615
+ and56(
61616
+ eq57(sessionEvents.workspaceId, input.workspaceId),
61617
+ eq57(sessionEvents.sessionId, input.sessionId),
61618
+ inArray31(sessionEvents.clientEventId, [key2, `${key2}:switch`])
61619
+ )
61620
+ ).orderBy(asc22(sessionEvents.sequence));
61621
+ if (prior.length) {
61622
+ const receipt2 = prior.find((event) => event.type === "codex.credential.selected");
61623
+ if (!receipt2) throw new Error("Codex selection receipt missing");
61624
+ const payload = sessionEventPayloadRecord(receipt2.payload, receipt2.payloadCodecVersion);
61625
+ if (payload.credentialId !== input.credentialId)
61626
+ throw new Error("An attempt cannot record two different Codex selections");
61627
+ return {
61628
+ events: prior.map(mapEvent2),
61629
+ diagnostics: {
61630
+ transition: payload.transition,
61631
+ source: payload.source,
61632
+ reason: payload.reason
61633
+ }
61634
+ };
61635
+ }
61636
+ const previousCredentialId = fence.session.codexLastCredentialId;
61637
+ const diagnostics = codexSelectionDiagnostics({ ...input, previousCredentialId });
61638
+ const events = [];
61639
+ if (previousCredentialId !== null && previousCredentialId !== input.credentialId) {
61640
+ events.push({
61641
+ type: "codex.account.switched",
61642
+ clientEventId: `${key2}:switch`,
61643
+ payload: {
61644
+ fromAccountId: previousCredentialId,
61645
+ toAccountId: input.credentialId,
61646
+ reason: diagnostics.source === "manual_pin" ? "manual" : "rotation"
61647
+ }
61648
+ });
61649
+ }
61650
+ events.push({
61651
+ type: "codex.credential.selected",
61652
+ clientEventId: key2,
61653
+ payload: {
61654
+ credentialId: input.credentialId,
61655
+ strategy: input.strategy,
61656
+ ...diagnostics,
61657
+ previousCredentialId,
61658
+ eligibleCount: input.eligibleCount,
61659
+ connectedCount: input.connectedCount,
61660
+ reused: input.reusedLease
61661
+ }
61662
+ });
61663
+ await tx.update(sessions).set({ codexLastCredentialId: input.credentialId }).where(
61664
+ and56(
61665
+ eq57(sessions.workspaceId, input.workspaceId),
61666
+ eq57(sessions.id, input.sessionId)
61667
+ )
61668
+ );
61669
+ const appended = await appendSessionEventsForTurnAttempt(
61670
+ tx,
61671
+ input.workspaceId,
61672
+ input.sessionId,
61673
+ input.turnId,
61674
+ input.executionGeneration,
61675
+ input.attemptId,
61676
+ events
61677
+ );
61678
+ if (!appended.accepted) throw new CodexCredentialLeaseAttemptFencedError();
61679
+ return { events: appended.events, diagnostics };
61680
+ });
61681
+ }
61551
61682
  async function recordSessionActiveCodexCredential(db, workspaceId, sessionId, credentialId) {
61552
61683
  await withWorkspaceSessionActivityRls(db, workspaceId, async (scopedDb) => {
61553
61684
  await scopedDb.update(sessions).set({ codexLastCredentialId: credentialId }).where(
@@ -64990,9 +65121,95 @@ async function listSessionsForSubject(db, workspaceId, options) {
64990
65121
  }
64991
65122
  throw new Error("unreachable session list retry state");
64992
65123
  }
65124
+ async function sessionFailureDiagnostics(db, workspaceId, session) {
65125
+ if (session.status !== "failed") return null;
65126
+ const scope = and56(
65127
+ eq57(sessionEvents.workspaceId, workspaceId),
65128
+ eq57(sessionEvents.sessionId, session.id),
65129
+ lte4(sessionEvents.sequence, session.lastSequence),
65130
+ isNull16(sessionEvents.duplicateOfEventId),
65131
+ or12(
65132
+ isNull16(sessionEvents.turnAssociation),
65133
+ eq57(sessionEvents.turnAssociation, "current")
65134
+ )
65135
+ );
65136
+ const maxChars = 1024;
65137
+ const storageChars = sessionTextStoragePrefixChars(maxChars);
65138
+ const diagnosticFields = ["error", "message", "detail", "lastRetryableError", "code", "status"];
65139
+ const boundedFields = diagnosticFields.flatMap((field) => {
65140
+ const scalar = sql81`case when jsonb_typeof(${sessionEvents.payload}->${field}::text) = 'string'
65141
+ then ${sessionEvents.payload}->>${field}::text else null end`;
65142
+ return [
65143
+ sql81`${field}::text`,
65144
+ sql81`jsonb_build_object(
65145
+ 'prefix', left(${scalar}, ${storageChars}), 'chars', char_length(${scalar}),
65146
+ 'encoded', ${sessionMcpProgressScalarIsEncodedSql(scalar, sessionEvents.payloadCodecVersion)})`
65147
+ ];
65148
+ });
65149
+ const projectedPayload = sql81`jsonb_build_object(
65150
+ ${sql81.join(boundedFields, sql81`, `)},
65151
+ 'providerRecoveryCount', case when jsonb_typeof(${sessionEvents.payload}->'providerRecoveryCount') = 'number'
65152
+ and length((${sessionEvents.payload}->'providerRecoveryCount')::text) <= 16
65153
+ then ${sessionEvents.payload}->'providerRecoveryCount' else 'null'::jsonb end)`;
65154
+ const latest = async (type) => {
65155
+ const [row] = await db.select({
65156
+ id: sessionEvents.id,
65157
+ sequence: sessionEvents.sequence,
65158
+ turnId: sessionEvents.turnId,
65159
+ occurredAt: sessionEvents.occurredAt,
65160
+ codecVersion: sessionEvents.payloadCodecVersion,
65161
+ payload: projectedPayload
65162
+ }).from(sessionEvents).where(and56(scope, eq57(sessionEvents.type, type))).orderBy(desc22(sessionEvents.sequence)).limit(1);
65163
+ if (!row) return null;
65164
+ const payload = {
65165
+ providerRecoveryCount: row.payload.providerRecoveryCount
65166
+ };
65167
+ const truncatedFields = [];
65168
+ for (const field of diagnosticFields) {
65169
+ const stored = row.payload[field];
65170
+ const projected = projectSessionTextPrefix(
65171
+ stored.prefix,
65172
+ stored.chars,
65173
+ row.codecVersion,
65174
+ stored.encoded,
65175
+ maxChars
65176
+ );
65177
+ payload[field] = projected.text;
65178
+ if (projected.textTruncated || (projected.originalChars ?? 0) > maxChars)
65179
+ truncatedFields.push(field);
65180
+ }
65181
+ payload.projection = { fieldsOnly: true, fieldLimitChars: maxChars, truncatedFields };
65182
+ return { ...row, payload, occurredAt: row.occurredAt.toISOString() };
65183
+ };
65184
+ const turnFailure = await latest("turn.failed");
65185
+ const latestStatus = await latest("session.status.changed");
65186
+ const statusPayload = latestStatus?.payload;
65187
+ if (latestStatus && (!turnFailure || latestStatus.sequence > turnFailure.sequence) && typeof statusPayload?.status === "string" && statusPayload.status !== "failed")
65188
+ return null;
65189
+ const preClaimFailure = statusPayload?.status === "failed" && statusPayload.code === "pre_claim_failure" ? latestStatus : null;
65190
+ const failure = preClaimFailure && (!turnFailure || preClaimFailure.sequence > turnFailure.sequence && (!preClaimFailure.turnId || preClaimFailure.turnId !== turnFailure.turnId)) ? preClaimFailure : turnFailure;
65191
+ if (!failure) return null;
65192
+ return {
65193
+ eventId: failure.id,
65194
+ sequence: failure.sequence,
65195
+ turnId: failure.turnId ?? null,
65196
+ occurredAt: failure.occurredAt,
65197
+ payload: failure.payload
65198
+ };
65199
+ }
64993
65200
  async function getSessionForSubject(db, workspaceId, sessionId, subjectId, relatedSessionAccess = "root") {
64994
65201
  return await withWorkspaceSubjectRls(db, workspaceId, subjectId, async (scopedDb) => {
64995
- const [row] = await scopedDb.select({ session: sessions, pin: sessionPins }).from(sessions).leftJoin(
65202
+ const [row] = await scopedDb.select({
65203
+ session: sessions,
65204
+ pin: sessionPins,
65205
+ cursor: sessionEventCursors
65206
+ }).from(sessions).leftJoin(
65207
+ sessionEventCursors,
65208
+ and56(
65209
+ eq57(sessionEventCursors.workspaceId, sessions.workspaceId),
65210
+ eq57(sessionEventCursors.sessionId, sessions.id)
65211
+ )
65212
+ ).leftJoin(
64996
65213
  sessionPins,
64997
65214
  and56(
64998
65215
  eq57(sessionPins.workspaceId, workspaceId),
@@ -65014,25 +65231,36 @@ async function getSessionForSubject(db, workspaceId, sessionId, subjectId, relat
65014
65231
  )
65015
65232
  ).limit(1);
65016
65233
  if (!row) return null;
65017
- const [session] = await canonicalSessionRowsFromEventCursors(scopedDb, workspaceId, [
65018
- row.session
65019
- ]);
65234
+ if (!row.cursor || row.cursor.accountId !== row.session.accountId || row.cursor.lastSequence < row.session.lastSequence) {
65235
+ throw new Error(`Session event cursor invariant failed for session ${sessionId}`);
65236
+ }
65237
+ const [session] = await withLatestStartedSessionPolicy(
65238
+ scopedDb,
65239
+ workspaceId,
65240
+ await withCurrentSessionInputWait(scopedDb, workspaceId, [
65241
+ { ...row.session, lastSequence: row.cursor.lastSequence }
65242
+ ])
65243
+ );
65020
65244
  if (!session) throw new Error(`Session event cursor missing for session ${sessionId}`);
65021
65245
  const mcpServers = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, [
65022
65246
  sessionId
65023
65247
  ]);
65024
65248
  const tenancyActivated = await sessionTenancyProductActivated(scopedDb, workspaceId);
65249
+ const failureDiagnostics = await sessionFailureDiagnostics(scopedDb, workspaceId, session);
65025
65250
  return projectSessionForRelatedAccess(
65026
- await mapSessionWithControl(
65027
- scopedDb,
65028
- session,
65029
- mcpServers.get(sessionId) ?? [],
65030
- mapSessionPin(row.pin),
65031
- mapSessionAttention(session, row.pin),
65032
- mapSessionArchive(row.pin),
65033
- void 0,
65034
- { subjectId, activated: tenancyActivated }
65035
- ),
65251
+ {
65252
+ ...await mapSessionWithControl(
65253
+ scopedDb,
65254
+ session,
65255
+ mcpServers.get(sessionId) ?? [],
65256
+ mapSessionPin(row.pin),
65257
+ mapSessionAttention(session, row.pin),
65258
+ mapSessionArchive(row.pin),
65259
+ void 0,
65260
+ { subjectId, activated: tenancyActivated }
65261
+ ),
65262
+ failureDiagnostics
65263
+ },
65036
65264
  relatedSessionAccess
65037
65265
  );
65038
65266
  });
@@ -69869,14 +70097,7 @@ function archiveCaptureRemainingMs(row) {
69869
70097
  return null;
69870
70098
  }
69871
70099
  const remainingMs = Number(row.archive_capture_remaining_ms);
69872
- return Number.isSafeInteger(remainingMs) && remainingMs >= 0 && remainingMs <= SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS ? remainingMs : null;
69873
- }
69874
- function extendSandboxTransitionDeadline(currentDeadline, hardDeadline, remainingCaptureMs, now) {
69875
- if (remainingCaptureMs === null || remainingCaptureMs === void 0) return currentDeadline;
69876
- return Math.min(
69877
- hardDeadline,
69878
- Math.max(currentDeadline, now + remainingCaptureMs + SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS)
69879
- );
70100
+ return Number.isSafeInteger(remainingMs) && remainingMs >= 0 && remainingMs <= SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS2 ? remainingMs : null;
69880
70101
  }
69881
70102
  function providerlessLeaseBackendPredicateSql() {
69882
70103
  const providerlessBackends = Object.entries(SANDBOX_PROVIDER_INSTANCE_ID_FIELDS_BY_BACKEND).filter(([, fields]) => fields.length === 0).map(([backend]) => backend);
@@ -70352,25 +70573,19 @@ async function acquireLease(db, input) {
70352
70573
  throw new Error("Sandbox lease archive capture wait is invalid");
70353
70574
  }
70354
70575
  const startedAt = performance.now();
70355
- const hardDeadline = startedAt + SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS;
70356
- let deadline = Math.min(hardDeadline, startedAt + captureWaitMs);
70576
+ const waitBudget = new SandboxTransitionWaitBudget(captureWaitMs, startedAt);
70357
70577
  let delayMs = 25;
70358
70578
  for (; ; ) {
70359
70579
  const result = await acquireLeaseOnce(db, input);
70360
70580
  const now = performance.now();
70361
70581
  if (captureWaitMs > 0 && result.role === "fenced" && result.reason === "capture_in_progress") {
70362
- deadline = extendSandboxTransitionDeadline(
70363
- deadline,
70364
- hardDeadline,
70365
- result.captureRemainingMs,
70366
- now
70367
- );
70582
+ waitBudget.observeCapture(result.captureRemainingMs, now);
70368
70583
  }
70369
- if (result.role !== "fenced" || result.reason === "superseded" || result.reason === "rotation_in_progress" || now >= deadline) {
70584
+ if (result.role !== "fenced" || result.reason === "superseded" || result.reason === "rotation_in_progress" || now >= waitBudget.deadline) {
70370
70585
  return result;
70371
70586
  }
70372
70587
  await waitForSandboxTransition(
70373
- Math.min(delayMs, Math.max(1, deadline - now)),
70588
+ Math.min(delayMs, Math.max(1, waitBudget.deadline - now)),
70374
70589
  input.waitSignal,
70375
70590
  "Sandbox lease transition wait cancelled"
70376
70591
  );
@@ -74146,8 +74361,7 @@ async function advanceWorkspaceGenerationForAuthority(db, authority, operationIn
74146
74361
  throw new Error("Workspace archive capture wait is invalid");
74147
74362
  }
74148
74363
  const startedAt = performance.now();
74149
- const hardDeadline = startedAt + SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS;
74150
- let deadline = Math.min(hardDeadline, startedAt + captureWaitMs);
74364
+ const waitBudget = new SandboxTransitionWaitBudget(captureWaitMs, startedAt);
74151
74365
  let delayMs = 25;
74152
74366
  let captureWaitStartedAt;
74153
74367
  let captureWaitOutcome = "failed";
@@ -74164,19 +74378,14 @@ async function advanceWorkspaceGenerationForAuthority(db, authority, operationIn
74164
74378
  } catch (error) {
74165
74379
  const now = performance.now();
74166
74380
  if (captureWaitMs > 0 && error instanceof SandboxWorkspaceMutationFencedError && error.code === "capture_in_progress") {
74167
- deadline = extendSandboxTransitionDeadline(
74168
- deadline,
74169
- hardDeadline,
74170
- error.captureRemainingMs,
74171
- now
74172
- );
74381
+ waitBudget.observeCapture(error.captureRemainingMs, now);
74173
74382
  }
74174
- if (!(error instanceof SandboxWorkspaceMutationFencedError) || error.code !== "capture_in_progress" || now >= deadline) {
74383
+ if (!(error instanceof SandboxWorkspaceMutationFencedError) || error.code !== "capture_in_progress" || now >= waitBudget.deadline) {
74175
74384
  throw error;
74176
74385
  }
74177
74386
  captureWaitStartedAt ??= performance.now();
74178
74387
  await waitForSandboxTransition(
74179
- Math.min(delayMs, Math.max(1, deadline - now)),
74388
+ Math.min(delayMs, Math.max(1, waitBudget.deadline - now)),
74180
74389
  waitSignal,
74181
74390
  "Sandbox workspace mutation wait cancelled"
74182
74391
  );
@@ -75422,7 +75631,7 @@ async function claimWorkspaceArchiveCapture(db, input) {
75422
75631
  throw new Error("Workspace archive capture timeout is invalid");
75423
75632
  }
75424
75633
  const operationId = input.operationId ?? input.captureId;
75425
- const providerRequestId = operationId;
75634
+ const providerRequestId = randomUUID12();
75426
75635
  const captureAttempt = input.attempt ?? 1;
75427
75636
  const providerReplaySafe = input.providerReplaySafe === true;
75428
75637
  const takeoverSafe = input.takeoverSafe === true;
@@ -93323,6 +93532,7 @@ export {
93323
93532
  closeSessionTurnAttemptInTransaction,
93324
93533
  closeSlackInteractionDelivery,
93325
93534
  codexCapacityRefreshBackoffMs,
93535
+ codexSelectionDiagnostics,
93326
93536
  commitBrowserRevisionPublication,
93327
93537
  commitBrowserSessionSuspension,
93328
93538
  commitBrowserStateUploadInTransaction,
@@ -94293,6 +94503,7 @@ export {
94293
94503
  recordRetainedProcessReconciliationProof,
94294
94504
  recordRetainedScreenshotArtifactError,
94295
94505
  recordSessionActiveCodexCredential,
94506
+ recordSessionCodexSelectionForTurnAttempt,
94296
94507
  recordSessionGoalProgressWithEvent,
94297
94508
  recordSkippedContextCompaction,
94298
94509
  recordSlackBotInstallCallbackFailure,