@opengeni/db 0.13.4 → 0.14.0

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
@@ -76,7 +76,7 @@ import {
76
76
  workspaceVariableSetVariables,
77
77
  workspaceVariableSets,
78
78
  workspaces
79
- } from "./chunk-IQOXTFKA.js";
79
+ } from "./chunk-PQKVUWQW.js";
80
80
  import {
81
81
  migrate,
82
82
  runMigrations
@@ -119,6 +119,7 @@ import {
119
119
  RigChange as RigChangeContract,
120
120
  SessionGoal as SessionGoalContract,
121
121
  SessionSystemUpdatePayload,
122
+ sessionSystemUpdateBatchHistoryItem,
122
123
  HostEventExport as HostEventExportContract,
123
124
  HostEventExportBatch as HostEventExportBatchContract,
124
125
  HostExportConsumerId,
@@ -2892,14 +2893,6 @@ async function supersedeSessionCurrentDirectionInTransaction(db, input) {
2892
2893
  finishedAt: now,
2893
2894
  updatedAt: now
2894
2895
  }).where(eq5(sessionTurns.id, current.id));
2895
- await db.update(sessionSystemUpdates).set({ state: "pending", deliveredTurnId: null, deliveredAt: null }).where(
2896
- and5(
2897
- eq5(sessionSystemUpdates.workspaceId, input.workspaceId),
2898
- eq5(sessionSystemUpdates.sessionId, input.sessionId),
2899
- eq5(sessionSystemUpdates.deliveredTurnId, current.id),
2900
- eq5(sessionSystemUpdates.state, "delivered")
2901
- )
2902
- );
2903
2896
  if (current.status === "waiting_capacity") {
2904
2897
  await db.update(codexCapacityWaiters).set({ status: "superseded", updatedAt: now }).where(
2905
2898
  and5(
@@ -4186,14 +4179,14 @@ async function steerAgentSessionInTransaction(db, input) {
4186
4179
  controlRevision: resumed.revision,
4187
4180
  lastSequence: session.lastSequence
4188
4181
  });
4189
- await db.update(sessionSystemUpdates).set({ state: "superseded" }).where(
4182
+ const supersededUpdates = await db.update(sessionSystemUpdates).set({ state: "superseded" }).where(
4190
4183
  and5(
4191
4184
  eq5(sessionSystemUpdates.workspaceId, input.workspaceId),
4192
4185
  eq5(sessionSystemUpdates.sessionId, input.targetSessionId),
4193
4186
  eq5(sessionSystemUpdates.kind, "agent_steer_instruction"),
4194
- inArray2(sessionSystemUpdates.state, ["pending", "deferred"])
4187
+ eq5(sessionSystemUpdates.state, "pending")
4195
4188
  )
4196
- );
4189
+ ).returning({ id: sessionSystemUpdates.id });
4197
4190
  const now = /* @__PURE__ */ new Date();
4198
4191
  const [update] = await db.insert(sessionSystemUpdates).values({
4199
4192
  accountId: input.accountId,
@@ -4252,6 +4245,22 @@ async function steerAgentSessionInTransaction(db, input) {
4252
4245
  },
4253
4246
  occurredAt: now
4254
4247
  },
4248
+ ...supersededUpdates.length > 0 ? [
4249
+ {
4250
+ accountId: input.accountId,
4251
+ workspaceId: input.workspaceId,
4252
+ sessionId: input.targetSessionId,
4253
+ sequence: ++sequence,
4254
+ type: "system.update.superseded",
4255
+ payload: {
4256
+ updateIds: supersededUpdates.map((entry) => entry.id),
4257
+ count: supersededUpdates.length,
4258
+ replacementUpdateId: update.id,
4259
+ reason: "newer_agent_steer"
4260
+ },
4261
+ occurredAt: now
4262
+ }
4263
+ ] : [],
4255
4264
  {
4256
4265
  accountId: input.accountId,
4257
4266
  workspaceId: input.workspaceId,
@@ -13747,6 +13756,7 @@ async function createSessionInTransaction(tx, input, id) {
13747
13756
  rigId: input.rigId ?? null,
13748
13757
  rigVersionId: input.rigVersionId ?? null,
13749
13758
  firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
13759
+ firstPartyMcpTools: input.firstPartyMcpTools ?? null,
13750
13760
  instructions: input.instructions ?? null,
13751
13761
  parentSessionId: input.parentSessionId ?? null,
13752
13762
  createIdempotencyKey,
@@ -22213,7 +22223,7 @@ async function materializeGoalContinuation(db, input) {
22213
22223
  eq7(sessionSystemUpdates.workspaceId, input.workspaceId),
22214
22224
  eq7(sessionSystemUpdates.sessionId, input.sessionId),
22215
22225
  eq7(sessionSystemUpdates.kind, "agent_steer_instruction"),
22216
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"])
22226
+ eq7(sessionSystemUpdates.state, "pending")
22217
22227
  )
22218
22228
  ).limit(1);
22219
22229
  if (pendingSteer) {
@@ -22336,6 +22346,7 @@ async function materializeGoalContinuation(db, input) {
22336
22346
  idempotencyKey: `agent_run.created:goal:${input.workspaceId}:${decision.goal.id}:${goalWakeRevision}`,
22337
22347
  occurredAt: now
22338
22348
  }).onConflictDoNothing({ target: usageEvents.idempotencyKey });
22349
+ const eventPreview = internalUpdateEventMember(update);
22339
22350
  const insertedEvents = await tx.insert(sessionEvents).values([
22340
22351
  {
22341
22352
  accountId: session.accountId,
@@ -22344,11 +22355,13 @@ async function materializeGoalContinuation(db, input) {
22344
22355
  sequence: session.lastSequence + 1,
22345
22356
  type: "system.update.pending",
22346
22357
  payload: sanitizeEventPayload({
22347
- updateId: update.id,
22348
- kind: update.kind,
22349
- classification: update.classification,
22350
- sourceId: update.sourceId,
22351
- summary: update.summary
22358
+ updateId: eventPreview.id,
22359
+ kind: eventPreview.kind,
22360
+ classification: eventPreview.classification,
22361
+ sourceId: eventPreview.sourceId,
22362
+ sourceIdTruncated: eventPreview.sourceIdTruncated,
22363
+ summary: eventPreview.summary,
22364
+ summaryTruncated: eventPreview.summaryTruncated
22352
22365
  }),
22353
22366
  occurredAt: now
22354
22367
  },
@@ -22729,6 +22742,62 @@ async function enqueueSessionTurn(db, input) {
22729
22742
  var MAX_INTERNAL_UPDATE_BYTES = 64 * 1024;
22730
22743
  var MAX_INTERNAL_UPDATE_BATCH_MEMBERS = 100;
22731
22744
  var MAX_INTERNAL_UPDATE_BATCH_BYTES = 256 * 1024;
22745
+ var MAX_INTERNAL_UPDATE_EVENT_SUMMARY_BYTES = 512;
22746
+ var MAX_INTERNAL_UPDATE_EVENT_SOURCE_BYTES = 256;
22747
+ function boundedInternalUpdateEventText(value, maxBytes) {
22748
+ if (Buffer.byteLength(value) <= maxBytes) return { text: value, truncated: false };
22749
+ const suffix = "\u2026";
22750
+ const bodyBudget = maxBytes - Buffer.byteLength(suffix);
22751
+ const bytes = Buffer.from(value);
22752
+ let text = bytes.subarray(0, bodyBudget).toString("utf8");
22753
+ if (text.endsWith("\uFFFD")) text = text.slice(0, -1);
22754
+ return { text: `${text}${suffix}`, truncated: true };
22755
+ }
22756
+ function internalUpdateEventMember(update) {
22757
+ const summary = boundedInternalUpdateEventText(
22758
+ update.summary,
22759
+ MAX_INTERNAL_UPDATE_EVENT_SUMMARY_BYTES
22760
+ );
22761
+ const source = boundedInternalUpdateEventText(
22762
+ update.sourceId,
22763
+ MAX_INTERNAL_UPDATE_EVENT_SOURCE_BYTES
22764
+ );
22765
+ return {
22766
+ id: update.id,
22767
+ kind: update.kind,
22768
+ classification: update.classification,
22769
+ sourceId: source.text,
22770
+ sourceIdTruncated: source.truncated,
22771
+ summary: summary.text,
22772
+ summaryTruncated: summary.truncated
22773
+ };
22774
+ }
22775
+ function selectBoundedSystemUpdateBatch(updates) {
22776
+ const selected = [];
22777
+ let selectedBytes = 0;
22778
+ for (const update of updates) {
22779
+ const updateBytes = Buffer.byteLength(
22780
+ JSON.stringify({
22781
+ id: update.id,
22782
+ kind: update.kind,
22783
+ classification: update.classification,
22784
+ sourceId: update.sourceId,
22785
+ summary: update.summary,
22786
+ payload: update.payload,
22787
+ lineage: update.lineage
22788
+ })
22789
+ );
22790
+ if (selected.length >= MAX_INTERNAL_UPDATE_BATCH_MEMBERS || // One individually large canonical input must still make progress. The
22791
+ // model/context boundary may reject it explicitly, but the queue cannot
22792
+ // wedge forever merely because the coalescing target is smaller.
22793
+ selected.length > 0 && selectedBytes + updateBytes > MAX_INTERNAL_UPDATE_BATCH_BYTES) {
22794
+ break;
22795
+ }
22796
+ selected.push(update);
22797
+ selectedBytes += updateBytes;
22798
+ }
22799
+ return selected;
22800
+ }
22732
22801
  async function claimSessionWorkForAttempt(db, workspaceId, input) {
22733
22802
  const { sessionId, workflowId } = input;
22734
22803
  return await withWorkspaceRls(
@@ -22740,29 +22809,18 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22740
22809
  and7(
22741
22810
  eq7(sessionSystemUpdates.workspaceId, workspaceId),
22742
22811
  eq7(sessionSystemUpdates.sessionId, sessionId),
22743
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"]),
22812
+ eq7(sessionSystemUpdates.state, "pending"),
22744
22813
  eq7(sessionSystemUpdates.kind, "agent_steer_instruction")
22745
22814
  )
22746
22815
  ).orderBy(
22747
22816
  desc2(sessionSystemUpdates.createdAt),
22748
22817
  desc2(sessionSystemUpdates.id)
22749
22818
  ).limit(1).for("update");
22750
- if (agentSteer) {
22751
- await tx.update(sessionSystemUpdates).set({ state: "superseded" }).where(
22752
- and7(
22753
- eq7(sessionSystemUpdates.workspaceId, workspaceId),
22754
- eq7(sessionSystemUpdates.sessionId, sessionId),
22755
- eq7(sessionSystemUpdates.kind, "agent_steer_instruction"),
22756
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"]),
22757
- ne(sessionSystemUpdates.id, agentSteer.id)
22758
- )
22759
- );
22760
- }
22761
22819
  const ordinary = await tx.select().from(sessionSystemUpdates).where(
22762
22820
  and7(
22763
22821
  eq7(sessionSystemUpdates.workspaceId, workspaceId),
22764
22822
  eq7(sessionSystemUpdates.sessionId, sessionId),
22765
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"]),
22823
+ eq7(sessionSystemUpdates.state, "pending"),
22766
22824
  ne(sessionSystemUpdates.kind, "agent_steer_instruction")
22767
22825
  )
22768
22826
  ).orderBy(
@@ -22775,12 +22833,15 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22775
22833
  count: 0,
22776
22834
  lastSequence: nextSequence - 1,
22777
22835
  triggerEventId: null,
22836
+ historyItemId: null,
22837
+ historyItem: null,
22778
22838
  updates: [],
22839
+ events: [],
22779
22840
  event: null
22780
22841
  };
22781
22842
  }
22782
- const deliverable = [];
22783
- let deliveredBytes = 0;
22843
+ const validUpdates = [];
22844
+ const cancelledUpdateIds = [];
22784
22845
  for (const update of updates) {
22785
22846
  const payload = update.payload;
22786
22847
  if (payload.type === "goal_continuation") {
@@ -22798,38 +22859,56 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22798
22859
  ).for("update").limit(1) : [];
22799
22860
  if (!goal || goal.status !== "active" || goal.version !== goalVersion) {
22800
22861
  await tx.update(sessionSystemUpdates).set({ state: "cancelled" }).where(eq7(sessionSystemUpdates.id, update.id));
22862
+ cancelledUpdateIds.push(update.id);
22801
22863
  continue;
22802
22864
  }
22803
22865
  }
22804
- const updateBytes = Buffer.byteLength(
22805
- JSON.stringify({
22806
- id: update.id,
22807
- kind: update.kind,
22808
- classification: update.classification,
22809
- sourceId: update.sourceId,
22810
- summary: update.summary,
22811
- payload: update.payload,
22812
- lineage: update.lineage
22813
- })
22814
- );
22815
- if (deliverable.length >= MAX_INTERNAL_UPDATE_BATCH_MEMBERS || deliveredBytes + updateBytes > MAX_INTERNAL_UPDATE_BATCH_BYTES) {
22816
- break;
22817
- }
22818
- deliverable.push(update);
22819
- deliveredBytes += updateBytes;
22866
+ validUpdates.push(update);
22820
22867
  }
22868
+ const deliverable = selectBoundedSystemUpdateBatch(validUpdates);
22821
22869
  if (deliverable.length === 0) {
22870
+ const cancellationEvent = cancelledUpdateIds.length > 0 ? {
22871
+ accountId,
22872
+ workspaceId,
22873
+ sessionId,
22874
+ // No receiving turn exists when every candidate was
22875
+ // cancelled before a model batch could be persisted.
22876
+ turnId: null,
22877
+ turnGeneration: null,
22878
+ turnAttemptId: null,
22879
+ turnAssociation: null,
22880
+ sequence: nextSequence,
22881
+ type: "system.update.cancelled",
22882
+ payload: sanitizeEventPayload({
22883
+ updateIds: cancelledUpdateIds,
22884
+ count: cancelledUpdateIds.length,
22885
+ reason: "stale_goal_continuation"
22886
+ }),
22887
+ occurredAt
22888
+ } : null;
22822
22889
  return {
22823
22890
  count: 0,
22824
- lastSequence: nextSequence - 1,
22891
+ lastSequence: cancellationEvent ? nextSequence : nextSequence - 1,
22825
22892
  triggerEventId: null,
22893
+ historyItemId: null,
22894
+ historyItem: null,
22826
22895
  updates: [],
22896
+ events: cancellationEvent ? [cancellationEvent] : [],
22827
22897
  event: null
22828
22898
  };
22829
22899
  }
22900
+ const modelOrdered = [
22901
+ ...deliverable.filter((update) => update.kind !== "agent_steer_instruction"),
22902
+ ...deliverable.filter((update) => update.kind === "agent_steer_instruction")
22903
+ ];
22904
+ const historyItemId = crypto.randomUUID();
22905
+ const historyItem = sessionSystemUpdateBatchHistoryItem(
22906
+ modelOrdered.map((update) => mapSessionSystemUpdate(update))
22907
+ );
22830
22908
  await tx.update(sessionSystemUpdates).set({
22831
22909
  state: "delivered",
22832
22910
  deliveredTurnId: turnId,
22911
+ deliveredHistoryItemId: historyItemId,
22833
22912
  deliveredAt: occurredAt
22834
22913
  }).where(
22835
22914
  and7(
@@ -22842,6 +22921,27 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22842
22921
  )
22843
22922
  );
22844
22923
  const eventId = triggerEventId ?? crypto.randomUUID();
22924
+ let sequence = nextSequence - 1;
22925
+ const events = [];
22926
+ if (cancelledUpdateIds.length > 0) {
22927
+ events.push({
22928
+ accountId,
22929
+ workspaceId,
22930
+ sessionId,
22931
+ turnId,
22932
+ turnGeneration,
22933
+ turnAttemptId: input.attemptId,
22934
+ turnAssociation: "current",
22935
+ sequence: ++sequence,
22936
+ type: "system.update.cancelled",
22937
+ payload: sanitizeEventPayload({
22938
+ updateIds: cancelledUpdateIds,
22939
+ count: cancelledUpdateIds.length,
22940
+ reason: "stale_goal_continuation"
22941
+ }),
22942
+ occurredAt
22943
+ });
22944
+ }
22845
22945
  const event = {
22846
22946
  id: eventId,
22847
22947
  accountId,
@@ -22851,23 +22951,55 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22851
22951
  turnGeneration,
22852
22952
  turnAttemptId: input.attemptId,
22853
22953
  turnAssociation: "current",
22854
- sequence: nextSequence,
22954
+ sequence: ++sequence,
22855
22955
  type: "system.update.delivered",
22856
22956
  payload: sanitizeEventPayload({
22857
22957
  updateIds: deliverable.map((update) => update.id),
22958
+ historyItemId,
22858
22959
  count: deliverable.length,
22859
- classifications: [...new Set(deliverable.map((update) => update.classification))]
22960
+ classifications: [...new Set(deliverable.map((update) => update.classification))],
22961
+ members: modelOrdered.map(internalUpdateEventMember)
22860
22962
  }),
22861
22963
  occurredAt
22862
22964
  };
22965
+ events.push(event);
22863
22966
  return {
22864
22967
  count: deliverable.length,
22865
- lastSequence: nextSequence,
22968
+ lastSequence: sequence,
22866
22969
  triggerEventId: eventId,
22970
+ historyItemId,
22971
+ historyItem,
22867
22972
  updates: deliverable,
22973
+ events,
22868
22974
  event
22869
22975
  };
22870
22976
  };
22977
+ const persistDeliveredUpdateBatch = async (delivered2, accountId, turnId) => {
22978
+ if (!delivered2.historyItemId || !delivered2.historyItem) {
22979
+ if (delivered2.count !== 0) {
22980
+ throw new Error("Delivered machine-input batch has no model-memory item");
22981
+ }
22982
+ return;
22983
+ }
22984
+ const [{ position } = { position: 0 }] = await tx.select({
22985
+ position: sql4`coalesce(max(${sessionHistoryItems.position}), -1) + 1`
22986
+ }).from(sessionHistoryItems).where(
22987
+ and7(
22988
+ eq7(sessionHistoryItems.workspaceId, workspaceId),
22989
+ eq7(sessionHistoryItems.sessionId, sessionId)
22990
+ )
22991
+ );
22992
+ await tx.insert(sessionHistoryItems).values({
22993
+ id: delivered2.historyItemId,
22994
+ accountId,
22995
+ workspaceId,
22996
+ sessionId,
22997
+ turnId,
22998
+ position: Number(position),
22999
+ item: sanitizeModelPayload(delivered2.historyItem),
23000
+ producerCodexCredentialId: null
23001
+ });
23002
+ };
22871
23003
  const workspaceControl = await lockWorkspaceInferenceControl(
22872
23004
  tx,
22873
23005
  workspaceId,
@@ -23113,7 +23245,7 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
23113
23245
  eq7(sessionSystemUpdates.workspaceId, workspaceId),
23114
23246
  eq7(sessionSystemUpdates.sessionId, sessionId),
23115
23247
  eq7(sessionSystemUpdates.kind, "agent_steer_instruction"),
23116
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"])
23248
+ eq7(sessionSystemUpdates.state, "pending")
23117
23249
  )
23118
23250
  ).orderBy(
23119
23251
  desc2(sessionSystemUpdates.createdAt),
@@ -23291,6 +23423,19 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
23291
23423
  triggerEventId
23292
23424
  );
23293
23425
  if (delivered2.count === 0) {
23426
+ if (delivered2.events.length > 0) {
23427
+ await tx.insert(sessionEvents).values(delivered2.events);
23428
+ await tx.update(sessions).set({
23429
+ status: "idle",
23430
+ lastSequence: delivered2.lastSequence,
23431
+ updatedAt: now2
23432
+ }).where(
23433
+ and7(
23434
+ eq7(sessions.workspaceId, workspaceId),
23435
+ eq7(sessions.id, sessionId)
23436
+ )
23437
+ );
23438
+ }
23294
23439
  return { action: "unclaimed", reason: "no-work" };
23295
23440
  }
23296
23441
  const goalUpdate = delivered2.updates.find(
@@ -23429,9 +23574,10 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
23429
23574
  startedAt: now2
23430
23575
  }).returning();
23431
23576
  if (!internalTurn) throw new Error("Failed to create internal update inference");
23577
+ await persistDeliveredUpdateBatch(delivered2, session.accountId, internalTurn.id);
23432
23578
  await registerAttempt(internalTurn);
23433
23579
  if (!delivered2.event) throw new Error("Delivered update batch has no durable event");
23434
- await tx.insert(sessionEvents).values(delivered2.event);
23580
+ await tx.insert(sessionEvents).values(delivered2.events);
23435
23581
  if (goalUpdate && typeof goalUpdate.payload.goalId === "string") {
23436
23582
  await tx.update(sessionGoals).set({ lastContinuationTurnId: internalTurn.id, updatedAt: now2 }).where(
23437
23583
  and7(
@@ -23528,8 +23674,9 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
23528
23674
  session.lastSequence + 1,
23529
23675
  now
23530
23676
  );
23531
- if (delivered.event) {
23532
- await tx.insert(sessionEvents).values(delivered.event);
23677
+ await persistDeliveredUpdateBatch(delivered, session.accountId, row.id);
23678
+ if (delivered.events.length > 0) {
23679
+ await tx.insert(sessionEvents).values(delivered.events);
23533
23680
  }
23534
23681
  await tx.update(sessions).set({
23535
23682
  status: "running",
@@ -23673,6 +23820,127 @@ async function markSessionAttemptQuiesced(db, input) {
23673
23820
  return [mapEvent2(event)];
23674
23821
  });
23675
23822
  }
23823
+ async function getSessionAttemptActivityRef(db, input) {
23824
+ return await withRlsContext(
23825
+ db,
23826
+ { accountId: input.accountId, workspaceId: input.workspaceId },
23827
+ async (scopedDb) => {
23828
+ const [attempt] = await scopedDb.select({
23829
+ workflowId: sessionTurnAttempts.temporalWorkflowId,
23830
+ workflowRunId: sessionTurnAttempts.temporalWorkflowRunId,
23831
+ activityId: sessionTurnAttempts.temporalActivityId,
23832
+ quiescedAt: sessionTurnAttempts.quiescedAt
23833
+ }).from(sessionTurnAttempts).where(
23834
+ and7(
23835
+ eq7(sessionTurnAttempts.accountId, input.accountId),
23836
+ eq7(sessionTurnAttempts.workspaceId, input.workspaceId),
23837
+ eq7(sessionTurnAttempts.sessionId, input.sessionId),
23838
+ eq7(sessionTurnAttempts.id, input.attemptId),
23839
+ eq7(sessionTurnAttempts.temporalWorkflowId, input.temporalWorkflowId)
23840
+ )
23841
+ ).limit(1);
23842
+ return attempt ? {
23843
+ workflowId: attempt.workflowId,
23844
+ workflowRunId: attempt.workflowRunId,
23845
+ activityId: attempt.activityId,
23846
+ quiesced: attempt.quiescedAt !== null
23847
+ } : null;
23848
+ }
23849
+ );
23850
+ }
23851
+ async function reconcileSessionAttemptQuiescence(db, input) {
23852
+ const eligibility = await withRlsContext(
23853
+ db,
23854
+ { accountId: input.accountId, workspaceId: input.workspaceId },
23855
+ async (scopedDb) => {
23856
+ const rows = await scopedDb.execute(sql4`
23857
+ select
23858
+ attempt.account_id,
23859
+ attempt.state,
23860
+ attempt.quiesced_at,
23861
+ attempt.temporal_workflow_id,
23862
+ attempt.temporal_workflow_run_id,
23863
+ attempt.temporal_activity_id,
23864
+ exists (
23865
+ select 1
23866
+ from session_attempt_interruptions interruption
23867
+ where interruption.workspace_id = attempt.workspace_id
23868
+ and interruption.session_id = attempt.session_id
23869
+ and interruption.attempt_id = attempt.id
23870
+ and interruption.state in ('settled', 'rejected_stale')
23871
+ ) as interruption_settled,
23872
+ exists (
23873
+ select 1
23874
+ from session_attempt_interruptions interruption
23875
+ where interruption.workspace_id = attempt.workspace_id
23876
+ and interruption.session_id = attempt.session_id
23877
+ and interruption.attempt_id = attempt.id
23878
+ and interruption.state in ('pending', 'delivered', 'acknowledged')
23879
+ ) as interruption_pending,
23880
+ (
23881
+ exists (
23882
+ select 1
23883
+ from sandbox_workspace_mutation_admissions admission
23884
+ where admission.account_id = attempt.account_id
23885
+ and admission.workspace_id = attempt.workspace_id
23886
+ and admission.session_id = attempt.session_id
23887
+ and admission.settled_at is null
23888
+ and (
23889
+ admission.attempt_id = attempt.id
23890
+ or (
23891
+ admission.actor_kind = 'process'
23892
+ and exists (
23893
+ select 1
23894
+ from sandbox_retained_processes process
23895
+ where process.account_id = attempt.account_id
23896
+ and process.workspace_id = attempt.workspace_id
23897
+ and process.session_id = attempt.session_id
23898
+ and process.id = admission.actor_id
23899
+ and process.owner_attempt_id = attempt.id
23900
+ )
23901
+ )
23902
+ )
23903
+ )
23904
+ or exists (
23905
+ select 1
23906
+ from sandbox_retained_processes process
23907
+ where process.account_id = attempt.account_id
23908
+ and process.workspace_id = attempt.workspace_id
23909
+ and process.session_id = attempt.session_id
23910
+ and process.owner_attempt_id = attempt.id
23911
+ and process.state = 'active'
23912
+ )
23913
+ ) as writer_pending
23914
+ from session_turn_attempts attempt
23915
+ where attempt.account_id = ${input.accountId}
23916
+ and attempt.workspace_id = ${input.workspaceId}
23917
+ and attempt.session_id = ${input.sessionId}
23918
+ and attempt.id = ${input.attemptId}
23919
+ limit 1
23920
+ `);
23921
+ return rows[0] ?? null;
23922
+ }
23923
+ );
23924
+ if (!eligibility || eligibility.account_id !== input.accountId || eligibility.temporal_workflow_id !== input.temporalWorkflowId || eligibility.temporal_workflow_run_id !== input.temporalWorkflowRunId || eligibility.temporal_activity_id !== input.temporalActivityId || eligibility.state !== "closed" || !eligibility.interruption_settled || eligibility.interruption_pending) {
23925
+ return { action: "stale", events: [] };
23926
+ }
23927
+ if (eligibility.quiesced_at) {
23928
+ return { action: "quiesced", events: [] };
23929
+ }
23930
+ if (!input.activitySettled || eligibility.writer_pending) {
23931
+ return { action: "pending", events: [] };
23932
+ }
23933
+ const events = await markSessionAttemptQuiesced(db, {
23934
+ accountId: input.accountId,
23935
+ workspaceId: input.workspaceId,
23936
+ sessionId: input.sessionId,
23937
+ attemptId: input.attemptId,
23938
+ temporalWorkflowId: input.temporalWorkflowId,
23939
+ temporalWorkflowRunId: input.temporalWorkflowRunId,
23940
+ temporalActivityId: input.temporalActivityId
23941
+ });
23942
+ return { action: "quiesced", events };
23943
+ }
23676
23944
  async function settleSessionAttemptInterruptions(db, workspaceId, sessionId, attemptId) {
23677
23945
  return await withWorkspaceRls(
23678
23946
  db,
@@ -23801,12 +24069,6 @@ async function settleSessionAttemptInterruptions(db, workspaceId, sessionId, att
23801
24069
  outcome,
23802
24070
  closedAt: now
23803
24071
  });
23804
- await requeueInterruptedSessionSystemUpdatesForTurnTx(
23805
- tx,
23806
- workspaceId,
23807
- sessionId,
23808
- turn.id
23809
- );
23810
24072
  const eventValues = steer ? [
23811
24073
  {
23812
24074
  accountId: session.accountId,
@@ -24676,10 +24938,36 @@ async function applySessionTurnSettlement(db, workspaceId, input) {
24676
24938
  }
24677
24939
  })
24678
24940
  );
24941
+ const settledMachineInputs = ["completed", "failed", "cancelled", "superseded"].includes(
24942
+ input.turnStatus
24943
+ ) ? await tx.select({
24944
+ id: sessionSystemUpdates.id,
24945
+ historyItemId: sessionSystemUpdates.deliveredHistoryItemId
24946
+ }).from(sessionSystemUpdates).where(
24947
+ and7(
24948
+ eq7(sessionSystemUpdates.workspaceId, workspaceId),
24949
+ eq7(sessionSystemUpdates.sessionId, input.sessionId),
24950
+ eq7(sessionSystemUpdates.deliveredTurnId, input.turnId),
24951
+ eq7(sessionSystemUpdates.state, "delivered")
24952
+ )
24953
+ ).orderBy(
24954
+ asc4(sessionSystemUpdates.createdAt),
24955
+ asc4(sessionSystemUpdates.id)
24956
+ ) : [];
24957
+ const machineInputSettlementEvent = settledMachineInputs.length > 0 ? {
24958
+ type: "system.update.settled",
24959
+ payload: {
24960
+ updateIds: settledMachineInputs.map((update) => update.id),
24961
+ count: settledMachineInputs.length,
24962
+ historyItemId: settledMachineInputs[0].historyItemId,
24963
+ outcome: input.turnStatus
24964
+ }
24965
+ } : null;
24679
24966
  const settlementEvents = [
24680
24967
  ...recordingEvent ? [recordingEvent] : [],
24681
24968
  ...compactionRequestEvent ? [compactionRequestEvent] : [],
24682
24969
  ...terminalHumanInputEvents,
24970
+ ...machineInputSettlementEvent ? [machineInputSettlementEvent] : [],
24683
24971
  ...input.events
24684
24972
  ];
24685
24973
  const values = settlementEvents.map((event) => {
@@ -24735,21 +25023,6 @@ async function applySessionTurnSettlement(db, workspaceId, input) {
24735
25023
  turn
24736
25024
  );
24737
25025
  }
24738
- if (input.turnStatus === "failed") {
24739
- await deferFailedSessionSystemUpdatesForTurnTx(
24740
- tx,
24741
- workspaceId,
24742
- input.sessionId,
24743
- input.turnId
24744
- );
24745
- } else if (["cancelled", "superseded"].includes(input.turnStatus)) {
24746
- await requeueInterruptedSessionSystemUpdatesForTurnTx(
24747
- tx,
24748
- workspaceId,
24749
- input.sessionId,
24750
- input.turnId
24751
- );
24752
- }
24753
25026
  await tx.update(sessions).set({
24754
25027
  status: effectiveSessionStatus,
24755
25028
  activeTurnId: input.activeTurnId,
@@ -24947,14 +25220,6 @@ async function settleCodexCredentialLeaseLoss(db, input) {
24947
25220
  eq7(sessions.activeTurnId, input.turnId)
24948
25221
  )
24949
25222
  );
24950
- if (!input.checkpointDurable) {
24951
- await deferFailedSessionSystemUpdatesForTurnTx(
24952
- tx,
24953
- input.workspaceId,
24954
- input.sessionId,
24955
- input.turnId
24956
- );
24957
- }
24958
25223
  await tx.execute(sql4`
24959
25224
  delete from codex_credential_leases
24960
25225
  where account_id = ${input.accountId}
@@ -25625,16 +25890,49 @@ async function getSessionQueueSnapshot(db, workspaceId, sessionId) {
25625
25890
  inArray3(sessionTurns.source, ["user", "api"])
25626
25891
  )
25627
25892
  ).orderBy(asc4(sessionTurns.position), asc4(sessionTurns.createdAt));
25893
+ const pendingInputs = await scopedDb.select().from(sessionSystemUpdates).where(
25894
+ and7(
25895
+ eq7(sessionSystemUpdates.workspaceId, workspaceId),
25896
+ eq7(sessionSystemUpdates.sessionId, sessionId),
25897
+ eq7(sessionSystemUpdates.state, "pending")
25898
+ )
25899
+ ).orderBy(
25900
+ sql4`case when ${sessionSystemUpdates.kind} = 'agent_steer_instruction' then 0 else 1 end`,
25901
+ asc4(sessionSystemUpdates.createdAt),
25902
+ asc4(sessionSystemUpdates.id)
25903
+ );
25628
25904
  const latestInterruption = await latestSessionAttemptInterruption(
25629
25905
  scopedDb,
25630
25906
  workspaceId,
25631
25907
  sessionId
25632
25908
  );
25909
+ const items = rows.map(mapSessionTurn);
25910
+ const nextInputBatch = selectBoundedSystemUpdateBatch(pendingInputs);
25911
+ const hasPendingAgentSteer = pendingInputs.some(
25912
+ (update) => update.kind === "agent_steer_instruction"
25913
+ );
25914
+ const attachmentTurn = hasPendingAgentSteer ? items.find((turn) => turn.metadata.delivery === "steer") : items[0];
25633
25915
  return {
25634
25916
  version: session.queueVersion,
25635
25917
  effectiveControl: serializeEffectiveSessionControl(effectiveControl),
25636
25918
  stoppingPreviousAttempt: latestInterruption !== null && latestInterruption.interruptionState !== "rejected_stale" && latestInterruption.quiescedAt === null,
25637
- items: rows.map(mapSessionTurn)
25919
+ items,
25920
+ pendingInputs: pendingInputs.map((update) => {
25921
+ const canonical = mapSessionSystemUpdate(update);
25922
+ return {
25923
+ id: canonical.id,
25924
+ sessionId: canonical.sessionId,
25925
+ kind: canonical.kind,
25926
+ classification: canonical.classification,
25927
+ sourceId: boundedInternalUpdateEventText(canonical.sourceId, 256).text,
25928
+ summary: boundedInternalUpdateEventText(canonical.summary, 512).text,
25929
+ createdAt: canonical.createdAt
25930
+ };
25931
+ }),
25932
+ pendingInputAttachment: attachmentTurn && nextInputBatch.length > 0 ? {
25933
+ turnId: attachmentTurn.id,
25934
+ inputIds: nextInputBatch.map((update) => update.id)
25935
+ } : null
25638
25936
  };
25639
25937
  });
25640
25938
  }
@@ -25843,6 +26141,30 @@ async function markSessionWorkflowWakeDelivered(db, input) {
25843
26141
  if (pendingAgentSteer) {
25844
26142
  return { action: "pending_admission", blocker: "pending_agent_steer" };
25845
26143
  }
26144
+ const [pendingQuiescence] = await tx.select({ id: sessionTurnAttempts.id }).from(sessionTurnAttempts).innerJoin(
26145
+ sessionAttemptInterruptions,
26146
+ and7(
26147
+ eq7(
26148
+ sessionAttemptInterruptions.workspaceId,
26149
+ sessionTurnAttempts.workspaceId
26150
+ ),
26151
+ eq7(
26152
+ sessionAttemptInterruptions.sessionId,
26153
+ sessionTurnAttempts.sessionId
26154
+ ),
26155
+ eq7(sessionAttemptInterruptions.attemptId, sessionTurnAttempts.id)
26156
+ )
26157
+ ).where(
26158
+ and7(
26159
+ eq7(sessionTurnAttempts.workspaceId, input.workspaceId),
26160
+ eq7(sessionTurnAttempts.sessionId, input.sessionId),
26161
+ isNull2(sessionTurnAttempts.quiescedAt),
26162
+ inArray3(sessionAttemptInterruptions.state, ["settled", "rejected_stale"])
26163
+ )
26164
+ ).limit(1);
26165
+ if (pendingQuiescence) {
26166
+ return { action: "pending_admission", blocker: "pending_quiescence" };
26167
+ }
25846
26168
  }
25847
26169
  const [row] = await tx.update(sessionWorkflowWakeOutbox).set({
25848
26170
  deliveredRevision: sql4`greatest(${sessionWorkflowWakeOutbox.deliveredRevision}, ${input.wakeRevision})`,
@@ -25998,30 +26320,6 @@ async function addSessionSystemUpdate(db, input) {
25998
26320
  }
25999
26321
  return await addSessionSystemUpdateWithSourceMutation(db, input, async () => void 0);
26000
26322
  }
26001
- async function requeueInterruptedSessionSystemUpdatesForTurnTx(tx, workspaceId, sessionId, turnId) {
26002
- await tx.update(sessionSystemUpdates).set({ state: "pending", deliveredTurnId: null, deliveredAt: null }).where(
26003
- and7(
26004
- eq7(sessionSystemUpdates.workspaceId, workspaceId),
26005
- eq7(sessionSystemUpdates.sessionId, sessionId),
26006
- eq7(sessionSystemUpdates.deliveredTurnId, turnId),
26007
- eq7(sessionSystemUpdates.state, "delivered")
26008
- )
26009
- );
26010
- }
26011
- async function deferFailedSessionSystemUpdatesForTurnTx(tx, workspaceId, sessionId, turnId) {
26012
- await tx.update(sessionSystemUpdates).set({
26013
- state: sql4`case when ${sessionSystemUpdates.payload} ->> 'type' = 'goal_continuation' then 'failed' else 'deferred' end`,
26014
- deliveredTurnId: null,
26015
- deliveredAt: null
26016
- }).where(
26017
- and7(
26018
- eq7(sessionSystemUpdates.workspaceId, workspaceId),
26019
- eq7(sessionSystemUpdates.sessionId, sessionId),
26020
- eq7(sessionSystemUpdates.deliveredTurnId, turnId),
26021
- eq7(sessionSystemUpdates.state, "delivered")
26022
- )
26023
- );
26024
- }
26025
26323
  async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource) {
26026
26324
  if (Buffer.byteLength(JSON.stringify(input.payload)) > MAX_INTERNAL_UPDATE_BYTES) {
26027
26325
  throw new Error(`Internal update payload exceeds ${MAX_INTERNAL_UPDATE_BYTES} bytes`);
@@ -26100,6 +26398,7 @@ async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource)
26100
26398
  };
26101
26399
  }
26102
26400
  const now = /* @__PURE__ */ new Date();
26401
+ const eventPreview = internalUpdateEventMember(inserted);
26103
26402
  const [event] = await tx.insert(sessionEvents).values({
26104
26403
  accountId: session.accountId,
26105
26404
  workspaceId: input.workspaceId,
@@ -26107,11 +26406,13 @@ async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource)
26107
26406
  sequence: session.lastSequence + 1,
26108
26407
  type: "system.update.pending",
26109
26408
  payload: sanitizeEventPayload({
26110
- updateId: inserted.id,
26111
- kind: input.kind,
26112
- classification: input.classification,
26113
- sourceId: input.sourceId,
26114
- summary: input.summary
26409
+ updateId: eventPreview.id,
26410
+ kind: eventPreview.kind,
26411
+ classification: eventPreview.classification,
26412
+ sourceId: eventPreview.sourceId,
26413
+ sourceIdTruncated: eventPreview.sourceIdTruncated,
26414
+ summary: eventPreview.summary,
26415
+ summaryTruncated: eventPreview.summaryTruncated
26115
26416
  }),
26116
26417
  occurredAt: now
26117
26418
  }).returning();
@@ -26148,7 +26449,7 @@ async function listOutstandingSessionSystemUpdates(db, workspaceId, sessionId) {
26148
26449
  and7(
26149
26450
  eq7(sessionSystemUpdates.workspaceId, workspaceId),
26150
26451
  eq7(sessionSystemUpdates.sessionId, sessionId),
26151
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"])
26452
+ eq7(sessionSystemUpdates.state, "pending")
26152
26453
  )
26153
26454
  ).orderBy(asc4(sessionSystemUpdates.createdAt), asc4(sessionSystemUpdates.id));
26154
26455
  return rows.map(mapSessionSystemUpdate);
@@ -26189,6 +26490,7 @@ function mapSessionSystemUpdate(row) {
26189
26490
  lineage: row.lineage,
26190
26491
  state: row.state,
26191
26492
  deliveredTurnId: row.deliveredTurnId,
26493
+ deliveredHistoryItemId: row.deliveredHistoryItemId,
26192
26494
  deliveredAt: row.deliveredAt?.toISOString() ?? null,
26193
26495
  createdAt: row.createdAt.toISOString()
26194
26496
  };
@@ -26819,6 +27121,7 @@ function mapSession(row, effectiveControl, mcpServers = [], pin = mapSessionPin(
26819
27121
  rigId: row.rigId ?? null,
26820
27122
  rigVersionId: row.rigVersionId ?? null,
26821
27123
  firstPartyMcpPermissions: row.firstPartyMcpPermissions ?? null,
27124
+ firstPartyMcpTools: row.firstPartyMcpTools ?? null,
26822
27125
  mcpServers,
26823
27126
  parentSessionId: row.parentSessionId ?? null,
26824
27127
  rootSessionId: row.rootSessionId,
@@ -27764,6 +28067,7 @@ export {
27764
28067
  getSandboxSessionEnvelope,
27765
28068
  getScheduledTask,
27766
28069
  getSession,
28070
+ getSessionAttemptActivityRef,
27767
28071
  getSessionByCreateIdempotencyKey,
27768
28072
  getSessionCodexState,
27769
28073
  getSessionEvent,
@@ -27935,6 +28239,7 @@ export {
27935
28239
  reapStaleLeaseHoldersGlobal,
27936
28240
  reconcileCodexCapacityWait,
27937
28241
  reconcileColdLostLeaseInstanceBlockers,
28242
+ reconcileSessionAttemptQuiescence,
27938
28243
  recordAuditEvent,
27939
28244
  recordCodexAccountConnectors,
27940
28245
  recordCodexAccountUsage,