@opengeni/db 0.13.4 → 0.14.3

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-DW24CKCT.js";
80
80
  import {
81
81
  migrate,
82
82
  runMigrations
@@ -100,7 +100,10 @@ import {
100
100
  import "./chunk-PZ5AY32C.js";
101
101
 
102
102
  // src/index.ts
103
- import { SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS } from "@opengeni/contracts";
103
+ import {
104
+ DEFAULT_FIRST_PARTY_MCP_TOOLS,
105
+ SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS
106
+ } from "@opengeni/contracts";
104
107
  import {
105
108
  approvalIdentifier,
106
109
  boundWorkspaceControlEvent as boundWorkspaceControlEvent2,
@@ -119,6 +122,7 @@ import {
119
122
  RigChange as RigChangeContract,
120
123
  SessionGoal as SessionGoalContract,
121
124
  SessionSystemUpdatePayload,
125
+ sessionSystemUpdateBatchHistoryItem,
122
126
  HostEventExport as HostEventExportContract,
123
127
  HostEventExportBatch as HostEventExportBatchContract,
124
128
  HostExportConsumerId,
@@ -2759,7 +2763,6 @@ import { sql as sql5 } from "drizzle-orm";
2759
2763
  import {
2760
2764
  metadataWithTurnExecutionPolicyV1,
2761
2765
  mergeResourceRefs,
2762
- mergeToolRefs,
2763
2766
  turnExecutionPolicyAuditMetadata
2764
2767
  } from "@opengeni/contracts";
2765
2768
  import { and as and5, asc as asc2, eq as eq5, inArray as inArray2, sql as sql3 } from "drizzle-orm";
@@ -2892,14 +2895,6 @@ async function supersedeSessionCurrentDirectionInTransaction(db, input) {
2892
2895
  finishedAt: now,
2893
2896
  updatedAt: now
2894
2897
  }).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
2898
  if (current.status === "waiting_capacity") {
2904
2899
  await db.update(codexCapacityWaiters).set({ status: "superseded", updatedAt: now }).where(
2905
2900
  and5(
@@ -2965,7 +2960,7 @@ async function normalizeQueuePositions(db, workspaceId, sessionId, orderedIds) {
2965
2960
  }).where(and5(eq5(sessions.workspaceId, workspaceId), eq5(sessions.id, sessionId)));
2966
2961
  }
2967
2962
  function draftIsNonEmpty(draft) {
2968
- return draft.text.length > 0 || draft.resources.length > 0 || draft.tools.length > 0 || draft.toolsProvided || draft.sourceTurnId !== null;
2963
+ return draft.text.length > 0 || draft.resources.length > 0 || draft.sourceTurnId !== null;
2969
2964
  }
2970
2965
  async function getComposerDraftInTransaction(db, input) {
2971
2966
  const query = db.select().from(composerDrafts).where(
@@ -3005,8 +3000,8 @@ async function saveComposerDraftInTransaction(db, input) {
3005
3000
  revision,
3006
3001
  text: input.text,
3007
3002
  resources: input.resources,
3008
- tools: input.tools,
3009
- toolsProvided: input.toolsProvided,
3003
+ tools: [],
3004
+ toolsProvided: false,
3010
3005
  model: input.model,
3011
3006
  reasoningEffort: input.reasoningEffort,
3012
3007
  // A queue edit is still the same accepted work item. Preserve its frozen
@@ -3305,8 +3300,8 @@ async function editQueuedTurnInTransaction(db, input) {
3305
3300
  revision: nextDraftRevision,
3306
3301
  text: turn.prompt,
3307
3302
  resources: turn.resources,
3308
- tools: turn.tools,
3309
- toolsProvided: turn.toolsProvided,
3303
+ tools: [],
3304
+ toolsProvided: false,
3310
3305
  model: turn.model,
3311
3306
  reasoningEffort: turn.reasoningEffort,
3312
3307
  sourceTurnId: turn.id,
@@ -3572,8 +3567,6 @@ async function submitHumanPromptInTransaction(db, input) {
3572
3567
  text: input.text,
3573
3568
  turnInstructions: input.turnInstructions ?? null,
3574
3569
  resources: input.resources,
3575
- tools: input.tools,
3576
- toolsProvided: input.toolsProvided === true,
3577
3570
  model: input.model ?? null,
3578
3571
  reasoningEffort: input.reasoningEffort ?? null,
3579
3572
  source: input.source,
@@ -3656,15 +3649,11 @@ async function submitHumanPromptInTransaction(db, input) {
3656
3649
  if (draft && canonicalSessionCommandHash({
3657
3650
  text: draft.text,
3658
3651
  resources: draft.resources,
3659
- tools: draft.tools,
3660
- toolsProvided: draft.toolsProvided,
3661
3652
  model: draft.model,
3662
3653
  reasoningEffort: draft.reasoningEffort
3663
3654
  }) !== canonicalSessionCommandHash({
3664
3655
  text: input.text,
3665
3656
  resources: input.resources,
3666
- tools: input.tools,
3667
- toolsProvided: input.toolsProvided === true,
3668
3657
  model: input.model ?? session.model,
3669
3658
  reasoningEffort: input.reasoningEffort ?? input.reasoningEffortFallback
3670
3659
  })) {
@@ -3758,7 +3747,6 @@ async function submitHumanPromptInTransaction(db, input) {
3758
3747
  payload: sanitizeEventPayload({
3759
3748
  text: input.text,
3760
3749
  ...input.resources.length ? { resources: input.resources } : {},
3761
- ...input.toolsProvided === true ? { tools: input.tools } : input.tools.length ? { tools: input.tools } : {},
3762
3750
  ...input.model ? { model: input.model } : {},
3763
3751
  ...input.reasoningEffort ? { reasoningEffort: input.reasoningEffort } : {},
3764
3752
  delivery: input.delivery,
@@ -3781,8 +3769,8 @@ async function submitHumanPromptInTransaction(db, input) {
3781
3769
  prompt: input.text,
3782
3770
  turnInstructions: editedSourceTurnInstructions !== void 0 ? editedSourceTurnInstructions : input.turnInstructions ?? null,
3783
3771
  resources: input.resources,
3784
- tools: input.tools,
3785
- toolsProvided: input.toolsProvided === true,
3772
+ tools: [],
3773
+ toolsProvided: false,
3786
3774
  model: input.model ?? session.model,
3787
3775
  reasoningEffort: input.reasoningEffort ?? input.reasoningEffortFallback,
3788
3776
  sandboxBackend: session.sandboxBackend,
@@ -3902,7 +3890,7 @@ async function submitHumanPromptInTransaction(db, input) {
3902
3890
  const queueVersion = session.queueVersion + 1;
3903
3891
  await db.update(sessions).set({
3904
3892
  resources: mergeResourceRefs(session.resources, input.resources),
3905
- tools: sessionToolPolicyIsFixed(session.toolPolicy) ? session.tools : mergeToolRefs(session.tools, input.tools),
3893
+ tools: session.tools,
3906
3894
  activeTurnId: input.delivery === "steer" ? liveCurrentTurnId : session.activeTurnId,
3907
3895
  status: nextStatus,
3908
3896
  queueVersion,
@@ -3966,11 +3954,6 @@ async function submitHumanPromptInTransaction(db, input) {
3966
3954
  replay: false
3967
3955
  };
3968
3956
  }
3969
- function sessionToolPolicyIsFixed(value) {
3970
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
3971
- const mode = value.mode;
3972
- return mode === "workspace_default" || mode === "explicit" || mode === "inherited";
3973
- }
3974
3957
  async function sendAgentMessageInTransaction(db, input) {
3975
3958
  const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "share");
3976
3959
  await lockSessionEventWriteRows(db, {
@@ -4186,14 +4169,14 @@ async function steerAgentSessionInTransaction(db, input) {
4186
4169
  controlRevision: resumed.revision,
4187
4170
  lastSequence: session.lastSequence
4188
4171
  });
4189
- await db.update(sessionSystemUpdates).set({ state: "superseded" }).where(
4172
+ const supersededUpdates = await db.update(sessionSystemUpdates).set({ state: "superseded" }).where(
4190
4173
  and5(
4191
4174
  eq5(sessionSystemUpdates.workspaceId, input.workspaceId),
4192
4175
  eq5(sessionSystemUpdates.sessionId, input.targetSessionId),
4193
4176
  eq5(sessionSystemUpdates.kind, "agent_steer_instruction"),
4194
- inArray2(sessionSystemUpdates.state, ["pending", "deferred"])
4177
+ eq5(sessionSystemUpdates.state, "pending")
4195
4178
  )
4196
- );
4179
+ ).returning({ id: sessionSystemUpdates.id });
4197
4180
  const now = /* @__PURE__ */ new Date();
4198
4181
  const [update] = await db.insert(sessionSystemUpdates).values({
4199
4182
  accountId: input.accountId,
@@ -4252,6 +4235,22 @@ async function steerAgentSessionInTransaction(db, input) {
4252
4235
  },
4253
4236
  occurredAt: now
4254
4237
  },
4238
+ ...supersededUpdates.length > 0 ? [
4239
+ {
4240
+ accountId: input.accountId,
4241
+ workspaceId: input.workspaceId,
4242
+ sessionId: input.targetSessionId,
4243
+ sequence: ++sequence,
4244
+ type: "system.update.superseded",
4245
+ payload: {
4246
+ updateIds: supersededUpdates.map((entry) => entry.id),
4247
+ count: supersededUpdates.length,
4248
+ replacementUpdateId: update.id,
4249
+ reason: "newer_agent_steer"
4250
+ },
4251
+ occurredAt: now
4252
+ }
4253
+ ] : [],
4255
4254
  {
4256
4255
  accountId: input.accountId,
4257
4256
  workspaceId: input.workspaceId,
@@ -13736,7 +13735,10 @@ async function createSessionInTransaction(tx, input, id) {
13736
13735
  resources: input.resources,
13737
13736
  skills: input.skills ?? [],
13738
13737
  tools: input.tools ?? [],
13739
- toolPolicy: input.toolPolicy ?? null,
13738
+ toolPolicy: input.toolPolicy ?? {
13739
+ mode: "explicit",
13740
+ inheritedFromSessionId: input.parentSessionId ?? null
13741
+ },
13740
13742
  metadata: input.metadata,
13741
13743
  ...creatorColumns(frozenCreator),
13742
13744
  model: input.model,
@@ -13747,6 +13749,7 @@ async function createSessionInTransaction(tx, input, id) {
13747
13749
  rigId: input.rigId ?? null,
13748
13750
  rigVersionId: input.rigVersionId ?? null,
13749
13751
  firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
13752
+ firstPartyMcpTools: input.firstPartyMcpTools ?? [...DEFAULT_FIRST_PARTY_MCP_TOOLS],
13750
13753
  instructions: input.instructions ?? null,
13751
13754
  parentSessionId: input.parentSessionId ?? null,
13752
13755
  createIdempotencyKey,
@@ -20246,6 +20249,56 @@ async function latestWorkspaceCapture(db, workspaceId, sessionId) {
20246
20249
  return rows.length ? mapWorkspaceCaptureRow(rows[0]) : null;
20247
20250
  });
20248
20251
  }
20252
+ async function sessionLatestWorkspaceCapture(db, workspaceId, sessionId) {
20253
+ return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
20254
+ const rows = await scopedDb.execute(sql4`
20255
+ select
20256
+ sessions.id as found_session_id,
20257
+ capture.id as capture_id,
20258
+ capture.session_id as capture_session_id,
20259
+ capture.turn_id as capture_turn_id,
20260
+ capture.revision as capture_revision,
20261
+ capture.lease_epoch as capture_lease_epoch,
20262
+ capture.state as capture_state,
20263
+ capture.manifest_key as capture_manifest_key,
20264
+ capture.tree_index_key as capture_tree_index_key,
20265
+ capture.blob_keys as capture_blob_keys,
20266
+ capture.size_bytes as capture_size_bytes,
20267
+ capture.stats as capture_stats,
20268
+ capture.captured_at as capture_captured_at
20269
+ from sessions
20270
+ left join lateral (
20271
+ select ${WORKSPACE_CAPTURE_COLUMNS}
20272
+ from workspace_captures
20273
+ where workspace_captures.session_id = sessions.id
20274
+ order by workspace_captures.revision desc
20275
+ limit 1
20276
+ ) capture on true
20277
+ where sessions.workspace_id = ${workspaceId} and sessions.id = ${sessionId}
20278
+ limit 1
20279
+ `);
20280
+ const row = rows[0];
20281
+ if (!row) return { sessionExists: false, capture: null };
20282
+ if (!row.capture_id) return { sessionExists: true, capture: null };
20283
+ return {
20284
+ sessionExists: true,
20285
+ capture: mapWorkspaceCaptureRow({
20286
+ id: row.capture_id,
20287
+ session_id: row.capture_session_id,
20288
+ turn_id: row.capture_turn_id,
20289
+ revision: row.capture_revision,
20290
+ lease_epoch: row.capture_lease_epoch,
20291
+ state: row.capture_state,
20292
+ manifest_key: row.capture_manifest_key,
20293
+ tree_index_key: row.capture_tree_index_key,
20294
+ blob_keys: row.capture_blob_keys,
20295
+ size_bytes: row.capture_size_bytes,
20296
+ stats: row.capture_stats,
20297
+ captured_at: row.capture_captured_at
20298
+ })
20299
+ };
20300
+ });
20301
+ }
20249
20302
  async function workspaceCaptureAtRevision(db, workspaceId, sessionId, revision) {
20250
20303
  return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
20251
20304
  const rows = await scopedDb.execute(sql4`
@@ -22213,7 +22266,7 @@ async function materializeGoalContinuation(db, input) {
22213
22266
  eq7(sessionSystemUpdates.workspaceId, input.workspaceId),
22214
22267
  eq7(sessionSystemUpdates.sessionId, input.sessionId),
22215
22268
  eq7(sessionSystemUpdates.kind, "agent_steer_instruction"),
22216
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"])
22269
+ eq7(sessionSystemUpdates.state, "pending")
22217
22270
  )
22218
22271
  ).limit(1);
22219
22272
  if (pendingSteer) {
@@ -22336,6 +22389,7 @@ async function materializeGoalContinuation(db, input) {
22336
22389
  idempotencyKey: `agent_run.created:goal:${input.workspaceId}:${decision.goal.id}:${goalWakeRevision}`,
22337
22390
  occurredAt: now
22338
22391
  }).onConflictDoNothing({ target: usageEvents.idempotencyKey });
22392
+ const eventPreview = internalUpdateEventMember(update);
22339
22393
  const insertedEvents = await tx.insert(sessionEvents).values([
22340
22394
  {
22341
22395
  accountId: session.accountId,
@@ -22344,11 +22398,13 @@ async function materializeGoalContinuation(db, input) {
22344
22398
  sequence: session.lastSequence + 1,
22345
22399
  type: "system.update.pending",
22346
22400
  payload: sanitizeEventPayload({
22347
- updateId: update.id,
22348
- kind: update.kind,
22349
- classification: update.classification,
22350
- sourceId: update.sourceId,
22351
- summary: update.summary
22401
+ updateId: eventPreview.id,
22402
+ kind: eventPreview.kind,
22403
+ classification: eventPreview.classification,
22404
+ sourceId: eventPreview.sourceId,
22405
+ sourceIdTruncated: eventPreview.sourceIdTruncated,
22406
+ summary: eventPreview.summary,
22407
+ summaryTruncated: eventPreview.summaryTruncated
22352
22408
  }),
22353
22409
  occurredAt: now
22354
22410
  },
@@ -22729,6 +22785,62 @@ async function enqueueSessionTurn(db, input) {
22729
22785
  var MAX_INTERNAL_UPDATE_BYTES = 64 * 1024;
22730
22786
  var MAX_INTERNAL_UPDATE_BATCH_MEMBERS = 100;
22731
22787
  var MAX_INTERNAL_UPDATE_BATCH_BYTES = 256 * 1024;
22788
+ var MAX_INTERNAL_UPDATE_EVENT_SUMMARY_BYTES = 512;
22789
+ var MAX_INTERNAL_UPDATE_EVENT_SOURCE_BYTES = 256;
22790
+ function boundedInternalUpdateEventText(value, maxBytes) {
22791
+ if (Buffer.byteLength(value) <= maxBytes) return { text: value, truncated: false };
22792
+ const suffix = "\u2026";
22793
+ const bodyBudget = maxBytes - Buffer.byteLength(suffix);
22794
+ const bytes = Buffer.from(value);
22795
+ let text = bytes.subarray(0, bodyBudget).toString("utf8");
22796
+ if (text.endsWith("\uFFFD")) text = text.slice(0, -1);
22797
+ return { text: `${text}${suffix}`, truncated: true };
22798
+ }
22799
+ function internalUpdateEventMember(update) {
22800
+ const summary = boundedInternalUpdateEventText(
22801
+ update.summary,
22802
+ MAX_INTERNAL_UPDATE_EVENT_SUMMARY_BYTES
22803
+ );
22804
+ const source = boundedInternalUpdateEventText(
22805
+ update.sourceId,
22806
+ MAX_INTERNAL_UPDATE_EVENT_SOURCE_BYTES
22807
+ );
22808
+ return {
22809
+ id: update.id,
22810
+ kind: update.kind,
22811
+ classification: update.classification,
22812
+ sourceId: source.text,
22813
+ sourceIdTruncated: source.truncated,
22814
+ summary: summary.text,
22815
+ summaryTruncated: summary.truncated
22816
+ };
22817
+ }
22818
+ function selectBoundedSystemUpdateBatch(updates) {
22819
+ const selected = [];
22820
+ let selectedBytes = 0;
22821
+ for (const update of updates) {
22822
+ const updateBytes = Buffer.byteLength(
22823
+ JSON.stringify({
22824
+ id: update.id,
22825
+ kind: update.kind,
22826
+ classification: update.classification,
22827
+ sourceId: update.sourceId,
22828
+ summary: update.summary,
22829
+ payload: update.payload,
22830
+ lineage: update.lineage
22831
+ })
22832
+ );
22833
+ if (selected.length >= MAX_INTERNAL_UPDATE_BATCH_MEMBERS || // One individually large canonical input must still make progress. The
22834
+ // model/context boundary may reject it explicitly, but the queue cannot
22835
+ // wedge forever merely because the coalescing target is smaller.
22836
+ selected.length > 0 && selectedBytes + updateBytes > MAX_INTERNAL_UPDATE_BATCH_BYTES) {
22837
+ break;
22838
+ }
22839
+ selected.push(update);
22840
+ selectedBytes += updateBytes;
22841
+ }
22842
+ return selected;
22843
+ }
22732
22844
  async function claimSessionWorkForAttempt(db, workspaceId, input) {
22733
22845
  const { sessionId, workflowId } = input;
22734
22846
  return await withWorkspaceRls(
@@ -22740,29 +22852,18 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22740
22852
  and7(
22741
22853
  eq7(sessionSystemUpdates.workspaceId, workspaceId),
22742
22854
  eq7(sessionSystemUpdates.sessionId, sessionId),
22743
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"]),
22855
+ eq7(sessionSystemUpdates.state, "pending"),
22744
22856
  eq7(sessionSystemUpdates.kind, "agent_steer_instruction")
22745
22857
  )
22746
22858
  ).orderBy(
22747
22859
  desc2(sessionSystemUpdates.createdAt),
22748
22860
  desc2(sessionSystemUpdates.id)
22749
22861
  ).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
22862
  const ordinary = await tx.select().from(sessionSystemUpdates).where(
22762
22863
  and7(
22763
22864
  eq7(sessionSystemUpdates.workspaceId, workspaceId),
22764
22865
  eq7(sessionSystemUpdates.sessionId, sessionId),
22765
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"]),
22866
+ eq7(sessionSystemUpdates.state, "pending"),
22766
22867
  ne(sessionSystemUpdates.kind, "agent_steer_instruction")
22767
22868
  )
22768
22869
  ).orderBy(
@@ -22775,12 +22876,15 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22775
22876
  count: 0,
22776
22877
  lastSequence: nextSequence - 1,
22777
22878
  triggerEventId: null,
22879
+ historyItemId: null,
22880
+ historyItem: null,
22778
22881
  updates: [],
22882
+ events: [],
22779
22883
  event: null
22780
22884
  };
22781
22885
  }
22782
- const deliverable = [];
22783
- let deliveredBytes = 0;
22886
+ const validUpdates = [];
22887
+ const cancelledUpdateIds = [];
22784
22888
  for (const update of updates) {
22785
22889
  const payload = update.payload;
22786
22890
  if (payload.type === "goal_continuation") {
@@ -22798,38 +22902,56 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22798
22902
  ).for("update").limit(1) : [];
22799
22903
  if (!goal || goal.status !== "active" || goal.version !== goalVersion) {
22800
22904
  await tx.update(sessionSystemUpdates).set({ state: "cancelled" }).where(eq7(sessionSystemUpdates.id, update.id));
22905
+ cancelledUpdateIds.push(update.id);
22801
22906
  continue;
22802
22907
  }
22803
22908
  }
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;
22909
+ validUpdates.push(update);
22820
22910
  }
22911
+ const deliverable = selectBoundedSystemUpdateBatch(validUpdates);
22821
22912
  if (deliverable.length === 0) {
22913
+ const cancellationEvent = cancelledUpdateIds.length > 0 ? {
22914
+ accountId,
22915
+ workspaceId,
22916
+ sessionId,
22917
+ // No receiving turn exists when every candidate was
22918
+ // cancelled before a model batch could be persisted.
22919
+ turnId: null,
22920
+ turnGeneration: null,
22921
+ turnAttemptId: null,
22922
+ turnAssociation: null,
22923
+ sequence: nextSequence,
22924
+ type: "system.update.cancelled",
22925
+ payload: sanitizeEventPayload({
22926
+ updateIds: cancelledUpdateIds,
22927
+ count: cancelledUpdateIds.length,
22928
+ reason: "stale_goal_continuation"
22929
+ }),
22930
+ occurredAt
22931
+ } : null;
22822
22932
  return {
22823
22933
  count: 0,
22824
- lastSequence: nextSequence - 1,
22934
+ lastSequence: cancellationEvent ? nextSequence : nextSequence - 1,
22825
22935
  triggerEventId: null,
22936
+ historyItemId: null,
22937
+ historyItem: null,
22826
22938
  updates: [],
22939
+ events: cancellationEvent ? [cancellationEvent] : [],
22827
22940
  event: null
22828
22941
  };
22829
22942
  }
22943
+ const modelOrdered = [
22944
+ ...deliverable.filter((update) => update.kind !== "agent_steer_instruction"),
22945
+ ...deliverable.filter((update) => update.kind === "agent_steer_instruction")
22946
+ ];
22947
+ const historyItemId = crypto.randomUUID();
22948
+ const historyItem = sessionSystemUpdateBatchHistoryItem(
22949
+ modelOrdered.map((update) => mapSessionSystemUpdate(update))
22950
+ );
22830
22951
  await tx.update(sessionSystemUpdates).set({
22831
22952
  state: "delivered",
22832
22953
  deliveredTurnId: turnId,
22954
+ deliveredHistoryItemId: historyItemId,
22833
22955
  deliveredAt: occurredAt
22834
22956
  }).where(
22835
22957
  and7(
@@ -22842,6 +22964,27 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22842
22964
  )
22843
22965
  );
22844
22966
  const eventId = triggerEventId ?? crypto.randomUUID();
22967
+ let sequence = nextSequence - 1;
22968
+ const events = [];
22969
+ if (cancelledUpdateIds.length > 0) {
22970
+ events.push({
22971
+ accountId,
22972
+ workspaceId,
22973
+ sessionId,
22974
+ turnId,
22975
+ turnGeneration,
22976
+ turnAttemptId: input.attemptId,
22977
+ turnAssociation: "current",
22978
+ sequence: ++sequence,
22979
+ type: "system.update.cancelled",
22980
+ payload: sanitizeEventPayload({
22981
+ updateIds: cancelledUpdateIds,
22982
+ count: cancelledUpdateIds.length,
22983
+ reason: "stale_goal_continuation"
22984
+ }),
22985
+ occurredAt
22986
+ });
22987
+ }
22845
22988
  const event = {
22846
22989
  id: eventId,
22847
22990
  accountId,
@@ -22851,23 +22994,55 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
22851
22994
  turnGeneration,
22852
22995
  turnAttemptId: input.attemptId,
22853
22996
  turnAssociation: "current",
22854
- sequence: nextSequence,
22997
+ sequence: ++sequence,
22855
22998
  type: "system.update.delivered",
22856
22999
  payload: sanitizeEventPayload({
22857
23000
  updateIds: deliverable.map((update) => update.id),
23001
+ historyItemId,
22858
23002
  count: deliverable.length,
22859
- classifications: [...new Set(deliverable.map((update) => update.classification))]
23003
+ classifications: [...new Set(deliverable.map((update) => update.classification))],
23004
+ members: modelOrdered.map(internalUpdateEventMember)
22860
23005
  }),
22861
23006
  occurredAt
22862
23007
  };
23008
+ events.push(event);
22863
23009
  return {
22864
23010
  count: deliverable.length,
22865
- lastSequence: nextSequence,
23011
+ lastSequence: sequence,
22866
23012
  triggerEventId: eventId,
23013
+ historyItemId,
23014
+ historyItem,
22867
23015
  updates: deliverable,
23016
+ events,
22868
23017
  event
22869
23018
  };
22870
23019
  };
23020
+ const persistDeliveredUpdateBatch = async (delivered2, accountId, turnId) => {
23021
+ if (!delivered2.historyItemId || !delivered2.historyItem) {
23022
+ if (delivered2.count !== 0) {
23023
+ throw new Error("Delivered machine-input batch has no model-memory item");
23024
+ }
23025
+ return;
23026
+ }
23027
+ const [{ position } = { position: 0 }] = await tx.select({
23028
+ position: sql4`coalesce(max(${sessionHistoryItems.position}), -1) + 1`
23029
+ }).from(sessionHistoryItems).where(
23030
+ and7(
23031
+ eq7(sessionHistoryItems.workspaceId, workspaceId),
23032
+ eq7(sessionHistoryItems.sessionId, sessionId)
23033
+ )
23034
+ );
23035
+ await tx.insert(sessionHistoryItems).values({
23036
+ id: delivered2.historyItemId,
23037
+ accountId,
23038
+ workspaceId,
23039
+ sessionId,
23040
+ turnId,
23041
+ position: Number(position),
23042
+ item: sanitizeModelPayload(delivered2.historyItem),
23043
+ producerCodexCredentialId: null
23044
+ });
23045
+ };
22871
23046
  const workspaceControl = await lockWorkspaceInferenceControl(
22872
23047
  tx,
22873
23048
  workspaceId,
@@ -23113,7 +23288,7 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
23113
23288
  eq7(sessionSystemUpdates.workspaceId, workspaceId),
23114
23289
  eq7(sessionSystemUpdates.sessionId, sessionId),
23115
23290
  eq7(sessionSystemUpdates.kind, "agent_steer_instruction"),
23116
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"])
23291
+ eq7(sessionSystemUpdates.state, "pending")
23117
23292
  )
23118
23293
  ).orderBy(
23119
23294
  desc2(sessionSystemUpdates.createdAt),
@@ -23291,6 +23466,19 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
23291
23466
  triggerEventId
23292
23467
  );
23293
23468
  if (delivered2.count === 0) {
23469
+ if (delivered2.events.length > 0) {
23470
+ await tx.insert(sessionEvents).values(delivered2.events);
23471
+ await tx.update(sessions).set({
23472
+ status: "idle",
23473
+ lastSequence: delivered2.lastSequence,
23474
+ updatedAt: now2
23475
+ }).where(
23476
+ and7(
23477
+ eq7(sessions.workspaceId, workspaceId),
23478
+ eq7(sessions.id, sessionId)
23479
+ )
23480
+ );
23481
+ }
23294
23482
  return { action: "unclaimed", reason: "no-work" };
23295
23483
  }
23296
23484
  const goalUpdate = delivered2.updates.find(
@@ -23429,9 +23617,10 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
23429
23617
  startedAt: now2
23430
23618
  }).returning();
23431
23619
  if (!internalTurn) throw new Error("Failed to create internal update inference");
23620
+ await persistDeliveredUpdateBatch(delivered2, session.accountId, internalTurn.id);
23432
23621
  await registerAttempt(internalTurn);
23433
23622
  if (!delivered2.event) throw new Error("Delivered update batch has no durable event");
23434
- await tx.insert(sessionEvents).values(delivered2.event);
23623
+ await tx.insert(sessionEvents).values(delivered2.events);
23435
23624
  if (goalUpdate && typeof goalUpdate.payload.goalId === "string") {
23436
23625
  await tx.update(sessionGoals).set({ lastContinuationTurnId: internalTurn.id, updatedAt: now2 }).where(
23437
23626
  and7(
@@ -23528,8 +23717,9 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
23528
23717
  session.lastSequence + 1,
23529
23718
  now
23530
23719
  );
23531
- if (delivered.event) {
23532
- await tx.insert(sessionEvents).values(delivered.event);
23720
+ await persistDeliveredUpdateBatch(delivered, session.accountId, row.id);
23721
+ if (delivered.events.length > 0) {
23722
+ await tx.insert(sessionEvents).values(delivered.events);
23533
23723
  }
23534
23724
  await tx.update(sessions).set({
23535
23725
  status: "running",
@@ -23673,6 +23863,127 @@ async function markSessionAttemptQuiesced(db, input) {
23673
23863
  return [mapEvent2(event)];
23674
23864
  });
23675
23865
  }
23866
+ async function getSessionAttemptActivityRef(db, input) {
23867
+ return await withRlsContext(
23868
+ db,
23869
+ { accountId: input.accountId, workspaceId: input.workspaceId },
23870
+ async (scopedDb) => {
23871
+ const [attempt] = await scopedDb.select({
23872
+ workflowId: sessionTurnAttempts.temporalWorkflowId,
23873
+ workflowRunId: sessionTurnAttempts.temporalWorkflowRunId,
23874
+ activityId: sessionTurnAttempts.temporalActivityId,
23875
+ quiescedAt: sessionTurnAttempts.quiescedAt
23876
+ }).from(sessionTurnAttempts).where(
23877
+ and7(
23878
+ eq7(sessionTurnAttempts.accountId, input.accountId),
23879
+ eq7(sessionTurnAttempts.workspaceId, input.workspaceId),
23880
+ eq7(sessionTurnAttempts.sessionId, input.sessionId),
23881
+ eq7(sessionTurnAttempts.id, input.attemptId),
23882
+ eq7(sessionTurnAttempts.temporalWorkflowId, input.temporalWorkflowId)
23883
+ )
23884
+ ).limit(1);
23885
+ return attempt ? {
23886
+ workflowId: attempt.workflowId,
23887
+ workflowRunId: attempt.workflowRunId,
23888
+ activityId: attempt.activityId,
23889
+ quiesced: attempt.quiescedAt !== null
23890
+ } : null;
23891
+ }
23892
+ );
23893
+ }
23894
+ async function reconcileSessionAttemptQuiescence(db, input) {
23895
+ const eligibility = await withRlsContext(
23896
+ db,
23897
+ { accountId: input.accountId, workspaceId: input.workspaceId },
23898
+ async (scopedDb) => {
23899
+ const rows = await scopedDb.execute(sql4`
23900
+ select
23901
+ attempt.account_id,
23902
+ attempt.state,
23903
+ attempt.quiesced_at,
23904
+ attempt.temporal_workflow_id,
23905
+ attempt.temporal_workflow_run_id,
23906
+ attempt.temporal_activity_id,
23907
+ exists (
23908
+ select 1
23909
+ from session_attempt_interruptions interruption
23910
+ where interruption.workspace_id = attempt.workspace_id
23911
+ and interruption.session_id = attempt.session_id
23912
+ and interruption.attempt_id = attempt.id
23913
+ and interruption.state in ('settled', 'rejected_stale')
23914
+ ) as interruption_settled,
23915
+ exists (
23916
+ select 1
23917
+ from session_attempt_interruptions interruption
23918
+ where interruption.workspace_id = attempt.workspace_id
23919
+ and interruption.session_id = attempt.session_id
23920
+ and interruption.attempt_id = attempt.id
23921
+ and interruption.state in ('pending', 'delivered', 'acknowledged')
23922
+ ) as interruption_pending,
23923
+ (
23924
+ exists (
23925
+ select 1
23926
+ from sandbox_workspace_mutation_admissions admission
23927
+ where admission.account_id = attempt.account_id
23928
+ and admission.workspace_id = attempt.workspace_id
23929
+ and admission.session_id = attempt.session_id
23930
+ and admission.settled_at is null
23931
+ and (
23932
+ admission.attempt_id = attempt.id
23933
+ or (
23934
+ admission.actor_kind = 'process'
23935
+ and exists (
23936
+ select 1
23937
+ from sandbox_retained_processes process
23938
+ where process.account_id = attempt.account_id
23939
+ and process.workspace_id = attempt.workspace_id
23940
+ and process.session_id = attempt.session_id
23941
+ and process.id = admission.actor_id
23942
+ and process.owner_attempt_id = attempt.id
23943
+ )
23944
+ )
23945
+ )
23946
+ )
23947
+ or exists (
23948
+ select 1
23949
+ from sandbox_retained_processes process
23950
+ where process.account_id = attempt.account_id
23951
+ and process.workspace_id = attempt.workspace_id
23952
+ and process.session_id = attempt.session_id
23953
+ and process.owner_attempt_id = attempt.id
23954
+ and process.state = 'active'
23955
+ )
23956
+ ) as writer_pending
23957
+ from session_turn_attempts attempt
23958
+ where attempt.account_id = ${input.accountId}
23959
+ and attempt.workspace_id = ${input.workspaceId}
23960
+ and attempt.session_id = ${input.sessionId}
23961
+ and attempt.id = ${input.attemptId}
23962
+ limit 1
23963
+ `);
23964
+ return rows[0] ?? null;
23965
+ }
23966
+ );
23967
+ 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) {
23968
+ return { action: "stale", events: [] };
23969
+ }
23970
+ if (eligibility.quiesced_at) {
23971
+ return { action: "quiesced", events: [] };
23972
+ }
23973
+ if (!input.activitySettled || eligibility.writer_pending) {
23974
+ return { action: "pending", events: [] };
23975
+ }
23976
+ const events = await markSessionAttemptQuiesced(db, {
23977
+ accountId: input.accountId,
23978
+ workspaceId: input.workspaceId,
23979
+ sessionId: input.sessionId,
23980
+ attemptId: input.attemptId,
23981
+ temporalWorkflowId: input.temporalWorkflowId,
23982
+ temporalWorkflowRunId: input.temporalWorkflowRunId,
23983
+ temporalActivityId: input.temporalActivityId
23984
+ });
23985
+ return { action: "quiesced", events };
23986
+ }
23676
23987
  async function settleSessionAttemptInterruptions(db, workspaceId, sessionId, attemptId) {
23677
23988
  return await withWorkspaceRls(
23678
23989
  db,
@@ -23801,12 +24112,6 @@ async function settleSessionAttemptInterruptions(db, workspaceId, sessionId, att
23801
24112
  outcome,
23802
24113
  closedAt: now
23803
24114
  });
23804
- await requeueInterruptedSessionSystemUpdatesForTurnTx(
23805
- tx,
23806
- workspaceId,
23807
- sessionId,
23808
- turn.id
23809
- );
23810
24115
  const eventValues = steer ? [
23811
24116
  {
23812
24117
  accountId: session.accountId,
@@ -24676,10 +24981,36 @@ async function applySessionTurnSettlement(db, workspaceId, input) {
24676
24981
  }
24677
24982
  })
24678
24983
  );
24984
+ const settledMachineInputs = ["completed", "failed", "cancelled", "superseded"].includes(
24985
+ input.turnStatus
24986
+ ) ? await tx.select({
24987
+ id: sessionSystemUpdates.id,
24988
+ historyItemId: sessionSystemUpdates.deliveredHistoryItemId
24989
+ }).from(sessionSystemUpdates).where(
24990
+ and7(
24991
+ eq7(sessionSystemUpdates.workspaceId, workspaceId),
24992
+ eq7(sessionSystemUpdates.sessionId, input.sessionId),
24993
+ eq7(sessionSystemUpdates.deliveredTurnId, input.turnId),
24994
+ eq7(sessionSystemUpdates.state, "delivered")
24995
+ )
24996
+ ).orderBy(
24997
+ asc4(sessionSystemUpdates.createdAt),
24998
+ asc4(sessionSystemUpdates.id)
24999
+ ) : [];
25000
+ const machineInputSettlementEvent = settledMachineInputs.length > 0 ? {
25001
+ type: "system.update.settled",
25002
+ payload: {
25003
+ updateIds: settledMachineInputs.map((update) => update.id),
25004
+ count: settledMachineInputs.length,
25005
+ historyItemId: settledMachineInputs[0].historyItemId,
25006
+ outcome: input.turnStatus
25007
+ }
25008
+ } : null;
24679
25009
  const settlementEvents = [
24680
25010
  ...recordingEvent ? [recordingEvent] : [],
24681
25011
  ...compactionRequestEvent ? [compactionRequestEvent] : [],
24682
25012
  ...terminalHumanInputEvents,
25013
+ ...machineInputSettlementEvent ? [machineInputSettlementEvent] : [],
24683
25014
  ...input.events
24684
25015
  ];
24685
25016
  const values = settlementEvents.map((event) => {
@@ -24735,21 +25066,6 @@ async function applySessionTurnSettlement(db, workspaceId, input) {
24735
25066
  turn
24736
25067
  );
24737
25068
  }
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
25069
  await tx.update(sessions).set({
24754
25070
  status: effectiveSessionStatus,
24755
25071
  activeTurnId: input.activeTurnId,
@@ -24947,14 +25263,6 @@ async function settleCodexCredentialLeaseLoss(db, input) {
24947
25263
  eq7(sessions.activeTurnId, input.turnId)
24948
25264
  )
24949
25265
  );
24950
- if (!input.checkpointDurable) {
24951
- await deferFailedSessionSystemUpdatesForTurnTx(
24952
- tx,
24953
- input.workspaceId,
24954
- input.sessionId,
24955
- input.turnId
24956
- );
24957
- }
24958
25266
  await tx.execute(sql4`
24959
25267
  delete from codex_credential_leases
24960
25268
  where account_id = ${input.accountId}
@@ -25625,16 +25933,49 @@ async function getSessionQueueSnapshot(db, workspaceId, sessionId) {
25625
25933
  inArray3(sessionTurns.source, ["user", "api"])
25626
25934
  )
25627
25935
  ).orderBy(asc4(sessionTurns.position), asc4(sessionTurns.createdAt));
25936
+ const pendingInputs = await scopedDb.select().from(sessionSystemUpdates).where(
25937
+ and7(
25938
+ eq7(sessionSystemUpdates.workspaceId, workspaceId),
25939
+ eq7(sessionSystemUpdates.sessionId, sessionId),
25940
+ eq7(sessionSystemUpdates.state, "pending")
25941
+ )
25942
+ ).orderBy(
25943
+ sql4`case when ${sessionSystemUpdates.kind} = 'agent_steer_instruction' then 0 else 1 end`,
25944
+ asc4(sessionSystemUpdates.createdAt),
25945
+ asc4(sessionSystemUpdates.id)
25946
+ );
25628
25947
  const latestInterruption = await latestSessionAttemptInterruption(
25629
25948
  scopedDb,
25630
25949
  workspaceId,
25631
25950
  sessionId
25632
25951
  );
25952
+ const items = rows.map(mapSessionTurn);
25953
+ const nextInputBatch = selectBoundedSystemUpdateBatch(pendingInputs);
25954
+ const hasPendingAgentSteer = pendingInputs.some(
25955
+ (update) => update.kind === "agent_steer_instruction"
25956
+ );
25957
+ const attachmentTurn = hasPendingAgentSteer ? items.find((turn) => turn.metadata.delivery === "steer") : items[0];
25633
25958
  return {
25634
25959
  version: session.queueVersion,
25635
25960
  effectiveControl: serializeEffectiveSessionControl(effectiveControl),
25636
25961
  stoppingPreviousAttempt: latestInterruption !== null && latestInterruption.interruptionState !== "rejected_stale" && latestInterruption.quiescedAt === null,
25637
- items: rows.map(mapSessionTurn)
25962
+ items,
25963
+ pendingInputs: pendingInputs.map((update) => {
25964
+ const canonical = mapSessionSystemUpdate(update);
25965
+ return {
25966
+ id: canonical.id,
25967
+ sessionId: canonical.sessionId,
25968
+ kind: canonical.kind,
25969
+ classification: canonical.classification,
25970
+ sourceId: boundedInternalUpdateEventText(canonical.sourceId, 256).text,
25971
+ summary: boundedInternalUpdateEventText(canonical.summary, 512).text,
25972
+ createdAt: canonical.createdAt
25973
+ };
25974
+ }),
25975
+ pendingInputAttachment: attachmentTurn && nextInputBatch.length > 0 ? {
25976
+ turnId: attachmentTurn.id,
25977
+ inputIds: nextInputBatch.map((update) => update.id)
25978
+ } : null
25638
25979
  };
25639
25980
  });
25640
25981
  }
@@ -25843,6 +26184,30 @@ async function markSessionWorkflowWakeDelivered(db, input) {
25843
26184
  if (pendingAgentSteer) {
25844
26185
  return { action: "pending_admission", blocker: "pending_agent_steer" };
25845
26186
  }
26187
+ const [pendingQuiescence] = await tx.select({ id: sessionTurnAttempts.id }).from(sessionTurnAttempts).innerJoin(
26188
+ sessionAttemptInterruptions,
26189
+ and7(
26190
+ eq7(
26191
+ sessionAttemptInterruptions.workspaceId,
26192
+ sessionTurnAttempts.workspaceId
26193
+ ),
26194
+ eq7(
26195
+ sessionAttemptInterruptions.sessionId,
26196
+ sessionTurnAttempts.sessionId
26197
+ ),
26198
+ eq7(sessionAttemptInterruptions.attemptId, sessionTurnAttempts.id)
26199
+ )
26200
+ ).where(
26201
+ and7(
26202
+ eq7(sessionTurnAttempts.workspaceId, input.workspaceId),
26203
+ eq7(sessionTurnAttempts.sessionId, input.sessionId),
26204
+ isNull2(sessionTurnAttempts.quiescedAt),
26205
+ inArray3(sessionAttemptInterruptions.state, ["settled", "rejected_stale"])
26206
+ )
26207
+ ).limit(1);
26208
+ if (pendingQuiescence) {
26209
+ return { action: "pending_admission", blocker: "pending_quiescence" };
26210
+ }
25846
26211
  }
25847
26212
  const [row] = await tx.update(sessionWorkflowWakeOutbox).set({
25848
26213
  deliveredRevision: sql4`greatest(${sessionWorkflowWakeOutbox.deliveredRevision}, ${input.wakeRevision})`,
@@ -25998,30 +26363,6 @@ async function addSessionSystemUpdate(db, input) {
25998
26363
  }
25999
26364
  return await addSessionSystemUpdateWithSourceMutation(db, input, async () => void 0);
26000
26365
  }
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
26366
  async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource) {
26026
26367
  if (Buffer.byteLength(JSON.stringify(input.payload)) > MAX_INTERNAL_UPDATE_BYTES) {
26027
26368
  throw new Error(`Internal update payload exceeds ${MAX_INTERNAL_UPDATE_BYTES} bytes`);
@@ -26100,6 +26441,7 @@ async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource)
26100
26441
  };
26101
26442
  }
26102
26443
  const now = /* @__PURE__ */ new Date();
26444
+ const eventPreview = internalUpdateEventMember(inserted);
26103
26445
  const [event] = await tx.insert(sessionEvents).values({
26104
26446
  accountId: session.accountId,
26105
26447
  workspaceId: input.workspaceId,
@@ -26107,11 +26449,13 @@ async function addSessionSystemUpdateWithSourceMutation(db, input, mutateSource)
26107
26449
  sequence: session.lastSequence + 1,
26108
26450
  type: "system.update.pending",
26109
26451
  payload: sanitizeEventPayload({
26110
- updateId: inserted.id,
26111
- kind: input.kind,
26112
- classification: input.classification,
26113
- sourceId: input.sourceId,
26114
- summary: input.summary
26452
+ updateId: eventPreview.id,
26453
+ kind: eventPreview.kind,
26454
+ classification: eventPreview.classification,
26455
+ sourceId: eventPreview.sourceId,
26456
+ sourceIdTruncated: eventPreview.sourceIdTruncated,
26457
+ summary: eventPreview.summary,
26458
+ summaryTruncated: eventPreview.summaryTruncated
26115
26459
  }),
26116
26460
  occurredAt: now
26117
26461
  }).returning();
@@ -26148,7 +26492,7 @@ async function listOutstandingSessionSystemUpdates(db, workspaceId, sessionId) {
26148
26492
  and7(
26149
26493
  eq7(sessionSystemUpdates.workspaceId, workspaceId),
26150
26494
  eq7(sessionSystemUpdates.sessionId, sessionId),
26151
- inArray3(sessionSystemUpdates.state, ["pending", "deferred"])
26495
+ eq7(sessionSystemUpdates.state, "pending")
26152
26496
  )
26153
26497
  ).orderBy(asc4(sessionSystemUpdates.createdAt), asc4(sessionSystemUpdates.id));
26154
26498
  return rows.map(mapSessionSystemUpdate);
@@ -26189,6 +26533,7 @@ function mapSessionSystemUpdate(row) {
26189
26533
  lineage: row.lineage,
26190
26534
  state: row.state,
26191
26535
  deliveredTurnId: row.deliveredTurnId,
26536
+ deliveredHistoryItemId: row.deliveredHistoryItemId,
26192
26537
  deliveredAt: row.deliveredAt?.toISOString() ?? null,
26193
26538
  createdAt: row.createdAt.toISOString()
26194
26539
  };
@@ -26732,6 +27077,7 @@ async function appendSessionEventsWithLockedSessionUpdate(db, workspaceId, sessi
26732
27077
  lastSequence: sequence,
26733
27078
  ...update.resources !== void 0 ? { resources: update.resources } : {},
26734
27079
  ...update.tools !== void 0 ? { tools: update.tools } : {},
27080
+ ...update.firstPartyMcpTools !== void 0 ? { firstPartyMcpTools: update.firstPartyMcpTools } : {},
26735
27081
  ...update.toolPolicy !== void 0 ? { toolPolicy: update.toolPolicy } : {},
26736
27082
  ...update.toolPolicyVersion !== void 0 ? { toolPolicyVersion: update.toolPolicyVersion } : {},
26737
27083
  ...update.model !== void 0 ? { model: update.model } : {},
@@ -26791,11 +27137,8 @@ function mapSession(row, effectiveControl, mcpServers = [], pin = mapSessionPin(
26791
27137
  resources: row.resources,
26792
27138
  skills: row.skills ?? [],
26793
27139
  tools: row.tools,
26794
- toolPolicy: row.toolPolicy ?? {
26795
- mode: "legacy",
26796
- inheritedFromSessionId: null
26797
- },
26798
- toolPolicyVersion: Number(row.toolPolicyVersion ?? 1),
27140
+ toolPolicy: row.toolPolicy,
27141
+ toolPolicyVersion: Number(row.toolPolicyVersion),
26799
27142
  metadata: row.metadata,
26800
27143
  createdBy: initiatorFromStorage(
26801
27144
  row.createdByKind,
@@ -26819,6 +27162,7 @@ function mapSession(row, effectiveControl, mcpServers = [], pin = mapSessionPin(
26819
27162
  rigId: row.rigId ?? null,
26820
27163
  rigVersionId: row.rigVersionId ?? null,
26821
27164
  firstPartyMcpPermissions: row.firstPartyMcpPermissions ?? null,
27165
+ firstPartyMcpTools: row.firstPartyMcpTools,
26822
27166
  mcpServers,
26823
27167
  parentSessionId: row.parentSessionId ?? null,
26824
27168
  rootSessionId: row.rootSessionId,
@@ -27764,6 +28108,7 @@ export {
27764
28108
  getSandboxSessionEnvelope,
27765
28109
  getScheduledTask,
27766
28110
  getSession,
28111
+ getSessionAttemptActivityRef,
27767
28112
  getSessionByCreateIdempotencyKey,
27768
28113
  getSessionCodexState,
27769
28114
  getSessionEvent,
@@ -27935,6 +28280,7 @@ export {
27935
28280
  reapStaleLeaseHoldersGlobal,
27936
28281
  reconcileCodexCapacityWait,
27937
28282
  reconcileColdLostLeaseInstanceBlockers,
28283
+ reconcileSessionAttemptQuiescence,
27938
28284
  recordAuditEvent,
27939
28285
  recordCodexAccountConnectors,
27940
28286
  recordCodexAccountUsage,
@@ -28012,6 +28358,7 @@ export {
28012
28358
  sendAgentMessageInTransaction,
28013
28359
  serializeEffectiveSessionControl,
28014
28360
  sessionAuthorizationScopeFilter,
28361
+ sessionLatestWorkspaceCapture,
28015
28362
  sessionSubject,
28016
28363
  sessionTreeStatsForSessions,
28017
28364
  sessionsWithActiveOpOnEnrollment,