@retaw106/mmc-oc 2.4.0 → 2.5.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.
Files changed (132) hide show
  1. package/dist/{context-c72brxe5.js → context-xx09sh1g.js} +1279 -408
  2. package/dist/features/magic-context/message-index-async.d.ts +6 -2
  3. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  4. package/dist/features/magic-context/message-index.d.ts +5 -8
  5. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  6. package/dist/features/magic-context/search.d.ts +5 -1
  7. package/dist/features/magic-context/search.d.ts.map +1 -1
  8. package/dist/features/magic-context/storage-db.d.ts +2 -0
  9. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  10. package/dist/features/magic-context/storage-host-instruction-retention.d.ts +4 -0
  11. package/dist/features/magic-context/storage-host-instruction-retention.d.ts.map +1 -0
  12. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  13. package/dist/features/magic-context/storage-meta-shared.d.ts +2 -2
  14. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  15. package/dist/features/magic-context/storage-session-tables.d.ts +9 -1
  16. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  17. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  18. package/dist/hooks/magic-context/auto-search-hint.d.ts +3 -0
  19. package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
  20. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  21. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  22. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -2
  23. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  24. package/dist/hooks/magic-context/diagnostic-log-state.d.ts +4 -0
  25. package/dist/hooks/magic-context/diagnostic-log-state.d.ts.map +1 -0
  26. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  27. package/dist/hooks/magic-context/file-token-coverage.d.ts +11 -0
  28. package/dist/hooks/magic-context/file-token-coverage.d.ts.map +1 -0
  29. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/host-served-rows.d.ts +10 -0
  31. package/dist/hooks/magic-context/host-served-rows.d.ts.map +1 -1
  32. package/dist/hooks/magic-context/inject-compartments.d.ts +1 -1
  33. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  36. package/dist/hooks/magic-context/lkg-slot.d.ts +1 -1
  37. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts +3 -0
  39. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts.map +1 -0
  40. package/dist/hooks/magic-context/pass-outcome.d.ts +2 -0
  41. package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +2 -0
  44. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +3 -3
  47. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/system-date-refresh.d.ts +3 -2
  49. package/dist/hooks/magic-context/system-date-refresh.d.ts.map +1 -1
  50. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts +4 -0
  52. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts.map +1 -0
  53. package/dist/hooks/magic-context/tag-content-primitives.d.ts +1 -1
  54. package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/tag-messages.d.ts +15 -2
  56. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/text-complete.d.ts +1 -1
  58. package/dist/hooks/magic-context/text-complete.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/todo-view.d.ts +2 -2
  60. package/dist/hooks/magic-context/tool-drop-target.d.ts +3 -2
  61. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  62. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -0
  63. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  64. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +6 -0
  65. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/transform-stage-logger.d.ts +3 -0
  67. package/dist/hooks/magic-context/transform-stage-logger.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/transform.d.ts +4 -2
  69. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  70. package/dist/{index-kahkxcqw.js → index-0d40b4q8.js} +14740 -14292
  71. package/dist/{index-48e9znrc.js → index-1vxffj5j.js} +75 -22
  72. package/dist/{index-ykq24x1n.js → index-bpjjcdy9.js} +1 -1
  73. package/dist/{index-r7s7d350.js → index-k25thxq7.js} +1 -1
  74. package/dist/{index-27ddyx39.js → index-mjf0p7yq.js} +1 -1
  75. package/dist/{index-dwh99z66.js → index-pte3cfs9.js} +194 -5
  76. package/dist/index.js +2 -2
  77. package/dist/{message-time-backfill-j96x1sab.js → message-time-backfill-g9py24yt.js} +1 -1
  78. package/dist/plugin/subagent-tool-policy.d.ts +4 -0
  79. package/dist/plugin/subagent-tool-policy.d.ts.map +1 -1
  80. package/dist/{read-session-chunk-t8bg6wkz.js → read-session-chunk-eb3fy45y.js} +3 -3
  81. package/dist/{recomp-orchestrator-k760qy1n.js → recomp-orchestrator-mmpy5cb7.js} +6 -6
  82. package/dist/{send-session-notification-njjf3b4s.js → send-session-notification-zpqs213d.js} +3 -3
  83. package/dist/shared/model-suggestion-retry.d.ts +2 -0
  84. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  85. package/dist/shared/rpc-discovery-cleanup.d.ts +3 -0
  86. package/dist/shared/rpc-discovery-cleanup.d.ts.map +1 -0
  87. package/dist/shared/rpc-server.d.ts +2 -0
  88. package/dist/shared/rpc-server.d.ts.map +1 -1
  89. package/dist/shared/search-text.d.ts +8 -0
  90. package/dist/shared/search-text.d.ts.map +1 -0
  91. package/dist/shared/sqlite.d.ts +6 -1
  92. package/dist/shared/sqlite.d.ts.map +1 -1
  93. package/dist/shared/storage-file-mutex.d.ts.map +1 -1
  94. package/dist/shared/system-directive.d.ts +2 -0
  95. package/dist/shared/system-directive.d.ts.map +1 -1
  96. package/dist/v2/fold/native-replay.d.ts +11 -2
  97. package/dist/v2/fold/native-replay.d.ts.map +1 -1
  98. package/dist/v2/fold/policy.d.ts.map +1 -1
  99. package/dist/v2/fold/restore.d.ts.map +1 -1
  100. package/dist/v2/hooks/context.d.ts +1 -1
  101. package/dist/v2/hooks/context.d.ts.map +1 -1
  102. package/dist/v2/hooks/generate.d.ts +36 -1
  103. package/dist/v2/hooks/generate.d.ts.map +1 -1
  104. package/dist/v2/hooks/lkg-system.d.ts +35 -4
  105. package/dist/v2/hooks/lkg-system.d.ts.map +1 -1
  106. package/dist/v2/hooks/payload.d.ts +10 -1
  107. package/dist/v2/hooks/payload.d.ts.map +1 -1
  108. package/dist/v2/hooks/store.d.ts +2 -0
  109. package/dist/v2/hooks/store.d.ts.map +1 -1
  110. package/dist/v2/hooks/types.d.ts +12 -0
  111. package/dist/v2/hooks/types.d.ts.map +1 -1
  112. package/dist/v2/server.js +9033 -7461
  113. package/dist/v2/store-reader.d.ts +11 -0
  114. package/dist/v2/store-reader.d.ts.map +1 -1
  115. package/dist/web/main.js +229 -8
  116. package/dist/{wrapup-orchestrator-b2gswatj.js → wrapup-orchestrator-jq589pgr.js} +6 -6
  117. package/package.json +1 -1
  118. package/src/config/latch-permanence-guard.test.ts +4 -0
  119. package/src/shared/model-suggestion-retry.test.ts +52 -0
  120. package/src/shared/model-suggestion-retry.ts +8 -3
  121. package/src/shared/rpc-discovery-cleanup.test.ts +125 -0
  122. package/src/shared/rpc-discovery-cleanup.ts +57 -0
  123. package/src/shared/rpc-server.ts +36 -13
  124. package/src/shared/search-text.test.ts +30 -0
  125. package/src/shared/search-text.ts +62 -0
  126. package/src/shared/sqlite-turn-deadline.test.ts +286 -0
  127. package/src/shared/sqlite.ts +237 -9
  128. package/src/shared/storage-file-mutex.test.ts +51 -2
  129. package/src/shared/storage-file-mutex.ts +11 -1
  130. package/src/shared/system-directive.test.ts +37 -0
  131. package/src/shared/system-directive.ts +19 -1
  132. package/src/shared/tag-transcript.ts +16 -4
@@ -71,7 +71,6 @@ import {
71
71
  searchMemoriesFTSUnion,
72
72
  clearMemoryVerifications,
73
73
  queueMemoryMutation,
74
- scheduleAfterBootQuiet,
75
74
  BoundedSessionMap,
76
75
  registerOwnRpcServerInstance,
77
76
  rpcPortDir,
@@ -81,6 +80,12 @@ import {
81
80
  dirtyLkgRecoveryRevision,
82
81
  ownsLkgDirtyFence,
83
82
  invalidateCleanLkgRecoveryFence,
83
+ cleanSearchText,
84
+ keywordRelevance,
85
+ matchedSearchSnippet,
86
+ gaDatabasePath,
87
+ RAW_MESSAGE_TYPES,
88
+ V2StoreReaderPool,
84
89
  getLastIndexedOrdinal,
85
90
  getIndexedMessageIdAtOrdinal,
86
91
  getIndexedMessageCorpusSize,
@@ -88,6 +93,8 @@ import {
88
93
  isMessageIndexReconciledThrough,
89
94
  clearIndexedMessages,
90
95
  indexMessagesAfterOrdinal,
96
+ sweepOrphanedOpenCodeMessageIndexesCooperatively,
97
+ scheduleAfterBootQuiet,
91
98
  acquireCompartmentLease,
92
99
  releaseCompartmentLeaseBestEffort,
93
100
  isCompartmentLeaseHeld,
@@ -95,6 +102,7 @@ import {
95
102
  getMaxM0MutationId,
96
103
  ensureSessionMetaRow,
97
104
  clearCachedM0M1,
105
+ clearCachedM0,
98
106
  getCompartments,
99
107
  getLastCompartmentEndMessage,
100
108
  getLastCompartmentEndMessageId,
@@ -187,9 +195,6 @@ import {
187
195
  getUnpublishedAutoSearchNoHint,
188
196
  forgetUnpublishedAutoSearchNoHint,
189
197
  registerAutoSearchWork,
190
- gaDatabasePath,
191
- RAW_MESSAGE_TYPES,
192
- V2StoreReaderPool,
193
198
  getOrCreateSessionMeta,
194
199
  updateSessionMeta,
195
200
  advanceToolReclaimWatermark,
@@ -292,6 +297,7 @@ import {
292
297
  prepareCachedM0M1Replay,
293
298
  hasCompleteCachedM0M1,
294
299
  injectM0M1,
300
+ omitIncompleteFileTokenTotals,
295
301
  RECOVERY_NO_HEAD_LIMIT,
296
302
  deriveProtectedTailTokenTarget,
297
303
  selectPerRunCap,
@@ -301,7 +307,7 @@ import {
301
307
  recordHighPressureNoEligibleHead,
302
308
  getActiveCompartmentRun,
303
309
  startCompartmentAgent
304
- } from "./index-kahkxcqw.js";
310
+ } from "./index-0d40b4q8.js";
305
311
  import {
306
312
  getHarness,
307
313
  getDataDir,
@@ -429,12 +435,16 @@ import {
429
435
  pickNearestPriorOwner,
430
436
  expandToolPart,
431
437
  markHostUnservedRow,
438
+ isHostRenderedSystemMessage,
439
+ markCoveredInstructionRow,
440
+ isCoveredInstructionRow,
441
+ takeCoveredInstructionRows,
442
+ cloneKeepingCoveredInstructionMarks,
432
443
  estimateTrueRawMessageTokens,
433
444
  stripSystemInjection,
434
445
  isTextPart,
435
446
  isToolPartWithOutput,
436
447
  isFilePart,
437
- buildFileSourceContent,
438
448
  toolPartHasUserAnswer,
439
449
  recordToolParameters,
440
450
  createDroppedInputGuard,
@@ -477,12 +487,13 @@ import {
477
487
  hasRawSessionMessageById2,
478
488
  readRawSessionMessageById2,
479
489
  readSessionChunk2
480
- } from "./index-48e9znrc.js";
490
+ } from "./index-1vxffj5j.js";
481
491
  import {
482
492
  normalizeModelEntry2,
483
493
  resolveHistorianModel2
484
494
  } from "./index-azbmnekv.js";
485
495
  import {
496
+ Database,
486
497
  getSqliteMemoryStats,
487
498
  withSqliteBackgroundWriter,
488
499
  withSqliteTransformPass,
@@ -492,7 +503,7 @@ import {
492
503
  withAsyncPrivilegedWriter,
493
504
  indexCoordinationInput,
494
505
  withIndexChunk
495
- } from "./index-dwh99z66.js";
506
+ } from "./index-pte3cfs9.js";
496
507
  import {
497
508
  canonicalModelIdentity,
498
509
  piModelRefToCanonical,
@@ -509,7 +520,7 @@ import {
509
520
  latestRealUserTurnIdFromOpenCodeDb,
510
521
  getMessageTimesFromOpenCodeDb,
511
522
  findLastAssistantModelFromOpenCodeDb
512
- } from "./index-ykq24x1n.js";
523
+ } from "./index-bpjjcdy9.js";
513
524
  import {
514
525
  registerNotificationSink2,
515
526
  pushNotification2,
@@ -522,11 +533,14 @@ import {
522
533
  getErrorMessage,
523
534
  flushIgnoredMessages2,
524
535
  sendStatusNotification2
525
- } from "./index-r7s7d350.js";
536
+ } from "./index-k25thxq7.js";
526
537
  import {
527
538
  logSlowWriteTransaction
528
539
  } from "./index-yjv8dpht.js";
529
540
 
541
+ // src/v2/hooks/context.ts
542
+ import { setTimeout as delay } from "node:timers/promises";
543
+
530
544
  // src/config/index.ts
531
545
  import { existsSync as existsSync4 } from "node:fs";
532
546
 
@@ -5041,6 +5055,8 @@ var RECONCILIATION_BATCH_SIZE = 100;
5041
5055
 
5042
5056
  class MagicContextMessageIndexHeapHolder {
5043
5057
  reconciledSessions = new Set;
5058
+ reconciledSnapshots = new Map;
5059
+ stalledSessions = new Set;
5044
5060
  reconciliationScheduledSessions = new Set;
5045
5061
  clearAndReindexScheduledSessions = new Map;
5046
5062
  sessionLocks = new Map;
@@ -5123,23 +5139,32 @@ function detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMess
5123
5139
  return null;
5124
5140
  return `indexed id '${indexedId}' at ordinal ${cursor} but projection has '${projectedId}'`;
5125
5141
  }
5142
+ function logReconciliationStall(sessionId, reason) {
5143
+ if (heapHolder.stalledSessions.has(sessionId))
5144
+ return;
5145
+ heapHolder.stalledSessions.add(sessionId);
5146
+ sessionLog(sessionId, `message FTS reconciliation stalled: ${reason}; will retry`);
5147
+ }
5126
5148
  async function reconcileSessionIndex(db, sessionId, readMessages) {
5127
5149
  if (!await sourceReady(readMessages, sessionId))
5128
5150
  return false;
5129
5151
  await runWithSessionLock(sessionId, async () => {
5130
- if (heapHolder.reconciledSessions.has(sessionId))
5152
+ if (!readMessages.getRevision && heapHolder.reconciledSessions.has(sessionId))
5131
5153
  return;
5132
5154
  let fallbackSnapshot = null;
5133
5155
  try {
5134
5156
  const fullReader = typeof readMessages === "function" ? readMessages : null;
5135
- const finalWatermark = readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = fullReader?.(sessionId) ?? []).length;
5157
+ const revision = readMessages.getRevision?.(sessionId);
5158
+ const previous = heapHolder.reconciledSnapshots.get(sessionId);
5159
+ const finalWatermark = previous && revision === previous.revision ? previous.count : revision !== undefined && readMessages.getCountAfterRevision ? previous && revision > previous.revision ? previous.count + readMessages.getCountAfterRevision(sessionId, previous.revision, revision) : readMessages.getCountAfterRevision(sessionId, -1, revision) : readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = fullReader?.(sessionId) ?? []).length;
5136
5160
  let cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
5137
- let after;
5138
- const misalignment = detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMessages, fallbackSnapshot);
5161
+ let after = cursor === previous?.count ? previous.after : undefined;
5162
+ const misalignment = revision !== undefined && previous && revision >= previous.revision ? null : detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMessages, fallbackSnapshot);
5139
5163
  if (misalignment !== null) {
5140
5164
  sessionLog(sessionId, `message FTS index misaligned (${misalignment}); clearing for full re-index`);
5141
5165
  withSqliteBackgroundWriter(() => clearIndexedMessages(db, sessionId));
5142
5166
  cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
5167
+ after = undefined;
5143
5168
  }
5144
5169
  while (cursor < finalWatermark) {
5145
5170
  const pageEnd = Math.min(finalWatermark, cursor + RECONCILIATION_BATCH_SIZE);
@@ -5159,6 +5184,22 @@ async function reconcileSessionIndex(db, sessionId, readMessages) {
5159
5184
  }
5160
5185
  if (isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
5161
5186
  heapHolder.reconciledSessions.add(sessionId);
5187
+ heapHolder.stalledSessions.delete(sessionId);
5188
+ if (revision !== undefined) {
5189
+ if (!after && finalWatermark > 0 && readMessages.readPage) {
5190
+ const last = readMessages.readPage(sessionId, finalWatermark - 1, 1, finalWatermark).at(-1);
5191
+ if (last?.ordinal === finalWatermark && typeof last.createdAt === "number")
5192
+ after = { timeCreated: last.createdAt, id: last.id };
5193
+ }
5194
+ heapHolder.reconciledSnapshots.set(sessionId, {
5195
+ revision,
5196
+ count: finalWatermark,
5197
+ after
5198
+ });
5199
+ }
5200
+ } else {
5201
+ heapHolder.reconciledSessions.delete(sessionId);
5202
+ logReconciliationStall(sessionId, `gap after ordinal ${cursor} (store count ${finalWatermark})`);
5162
5203
  }
5163
5204
  } finally {
5164
5205
  heapHolder.activeReconcilerBuffers.delete(sessionId);
@@ -5167,30 +5208,42 @@ async function reconcileSessionIndex(db, sessionId, readMessages) {
5167
5208
  return true;
5168
5209
  }
5169
5210
  function scheduleReconciliation(db, sessionId, readMessages) {
5170
- if (heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
5211
+ if (!readMessages.getRevision && heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
5171
5212
  return;
5172
5213
  }
5173
5214
  heapHolder.reconciliationScheduledSessions.add(sessionId);
5174
5215
  scheduleAfterBootQuiet(() => {
5175
5216
  defer(() => {
5217
+ let appendedDuringReconciliation = false;
5218
+ const previousSnapshot = heapHolder.reconciledSnapshots.get(sessionId);
5176
5219
  reconcileSessionIndex(db, sessionId, readMessages).then((ran) => {
5177
- if (ran)
5220
+ if (ran) {
5221
+ const snapshot = heapHolder.reconciledSnapshots.get(sessionId);
5222
+ appendedDuringReconciliation = snapshot !== undefined && snapshot !== previousSnapshot && readMessages.getRevision !== undefined && readMessages.getRevision(sessionId) !== snapshot.revision;
5178
5223
  return;
5224
+ }
5179
5225
  setTimeout(() => {
5180
5226
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5181
5227
  scheduleReconciliation(db, sessionId, readMessages);
5182
5228
  }, PREPARE_RETRY_MS).unref?.();
5183
5229
  }).catch((error) => {
5184
- logIndexingError(sessionId, "reconciliation", error);
5230
+ heapHolder.reconciledSessions.delete(sessionId);
5231
+ logReconciliationStall(sessionId, error instanceof Error ? error.message : String(error));
5185
5232
  if (isDatabaseLockedError(error))
5186
5233
  setTimeout(() => scheduleReconciliation(db, sessionId, readMessages), 1000).unref();
5187
5234
  }).finally(() => {
5188
5235
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5236
+ if (appendedDuringReconciliation)
5237
+ scheduleReconciliation(db, sessionId, readMessages);
5189
5238
  });
5190
5239
  });
5191
5240
  });
5192
5241
  }
5193
5242
  function scheduleReconciliationCatchup(db, sessionId, readMessages) {
5243
+ if (readMessages.getRevision) {
5244
+ scheduleReconciliation(db, sessionId, readMessages);
5245
+ return;
5246
+ }
5194
5247
  if (typeof readMessages.getCount !== "function") {
5195
5248
  scheduleReconciliation(db, sessionId, readMessages);
5196
5249
  return;
@@ -5208,6 +5261,7 @@ function scheduleReconciliationCatchup(db, sessionId, readMessages) {
5208
5261
  }
5209
5262
  function scheduleClearAndReindex(db, sessionId, readMessages) {
5210
5263
  heapHolder.reconciledSessions.delete(sessionId);
5264
+ heapHolder.reconciledSnapshots.delete(sessionId);
5211
5265
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5212
5266
  clearCompletedIncrementalKeys(sessionId);
5213
5267
  const existing = heapHolder.clearAndReindexScheduledSessions.get(sessionId);
@@ -5225,6 +5279,7 @@ function scheduleClearAndReindex(db, sessionId, readMessages) {
5225
5279
  return;
5226
5280
  heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
5227
5281
  heapHolder.reconciledSessions.delete(sessionId);
5282
+ heapHolder.reconciledSnapshots.delete(sessionId);
5228
5283
  clearCompletedIncrementalKeys(sessionId);
5229
5284
  clearIndexedMessages(db, sessionId);
5230
5285
  cleared = true;
@@ -7200,7 +7255,7 @@ function searchMessagesInSnapshot(args, sessionFirst) {
7200
7255
  const filtered = rows.slice(0, limit);
7201
7256
  return filtered.map((row, rank) => ({
7202
7257
  source: "message",
7203
- content: previewText(row.content),
7258
+ content: matchedSearchSnippet(row.content, args.query) || previewText(row.content),
7204
7259
  score: linearDecayScore(rank, filtered.length),
7205
7260
  messageOrdinal: row.messageOrdinal,
7206
7261
  messageId: row.messageId,
@@ -7275,7 +7330,7 @@ function searchMessagesInSnapshot(args, sessionFirst) {
7275
7330
  const ranked = [...fused.values()].sort((a, b) => b.score !== a.score ? b.score - a.score : a.row.messageOrdinal - b.row.messageOrdinal).slice(0, resultLimit);
7276
7331
  return ranked.map((entry, rank) => ({
7277
7332
  source: "message",
7278
- content: previewText(entry.row.content),
7333
+ content: matchedSearchSnippet(entry.row.content, args.query) || previewText(entry.row.content),
7279
7334
  score: linearDecayScore(rank, ranked.length),
7280
7335
  messageOrdinal: entry.row.messageOrdinal,
7281
7336
  messageId: entry.row.messageId,
@@ -7592,7 +7647,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
7592
7647
  if (options.diagnostics) {
7593
7648
  options.diagnostics.suppressedLiveMessageMatches = outcome.suppressedLiveMessageMatches;
7594
7649
  }
7595
- messageResults = outcome.results;
7650
+ messageResults = outcome.results.filter((result) => result.messageId !== options.excludeMessageId);
7596
7651
  }
7597
7652
  const workspace = resolveSearchWorkspaceContext(db, projectPath);
7598
7653
  const [memoryOutcome, primerResults, noteResults] = await Promise.all([
@@ -7647,6 +7702,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
7647
7702
  }).immediate();
7648
7703
  }
7649
7704
  }
7705
+ if (options.autoHint) {
7706
+ return results.map((result) => ({
7707
+ ...result,
7708
+ relevanceScore: cleanSearchText(result.content).length === 0 ? 0 : keywordRelevance(trimmedQuery, result.content)
7709
+ }));
7710
+ }
7650
7711
  return results;
7651
7712
  }
7652
7713
  var SEARCH_NOTE_EXPAND_HINT = "Use mmc_expand(start=N-10, end=N) around any note @msg anchor above to read the surrounding conversation context.";
@@ -8266,22 +8327,22 @@ function truncate(text, limit) {
8266
8327
  return normalized;
8267
8328
  return `${normalized.slice(0, Math.max(0, limit - 1)).trimEnd()}…`;
8268
8329
  }
8269
- function renderFragment(result, charCap, wordRules) {
8330
+ function renderFragment(result, charCap, wordRules, query) {
8270
8331
  switch (result.source) {
8271
8332
  case "memory": {
8272
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8333
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8273
8334
  return truncate(compressed, charCap);
8274
8335
  }
8275
8336
  case "message": {
8276
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8337
+ const compressed = cavemanCompress(query ? matchedSearchSnippet(result.content, query, charCap) : cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8277
8338
  return truncate(compressed, charCap);
8278
8339
  }
8279
8340
  case "primer": {
8280
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8341
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8281
8342
  return truncate(compressed, charCap);
8282
8343
  }
8283
8344
  case "note": {
8284
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8345
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8285
8346
  return truncate(compressed, charCap);
8286
8347
  }
8287
8348
  }
@@ -8292,7 +8353,7 @@ function buildAutoSearchHint(results, options = {}) {
8292
8353
  const picks = results.slice(0, maxFragments);
8293
8354
  const lines = [];
8294
8355
  for (const result of picks) {
8295
- const fragment = renderFragment(result, fragmentCharCap, options.wordRules ?? "english");
8356
+ const fragment = renderFragment(result, fragmentCharCap, options.wordRules ?? "english", options.query ?? "");
8296
8357
  if (fragment.length === 0)
8297
8358
  continue;
8298
8359
  lines.push(`- ${fragment}`);
@@ -8315,6 +8376,10 @@ ${trimmedBody}…
8315
8376
  }
8316
8377
  return wrapped;
8317
8378
  }
8379
+ function selectAutoSearchResults(results, threshold) {
8380
+ const relevance = (result) => result.relevanceScore ?? result.score;
8381
+ return results.filter((result) => relevance(result) >= threshold).sort((left, right) => relevance(right) - relevance(left));
8382
+ }
8318
8383
 
8319
8384
  // src/hooks/magic-context/transform-message-helpers.ts
8320
8385
  function isMeaningfulUserMessage(msg) {
@@ -8591,6 +8656,9 @@ async function runAutoSearchHint(args) {
8591
8656
  return null;
8592
8657
  const searchOptions = {
8593
8658
  limit: 10,
8659
+ autoHint: true,
8660
+ maxMessageOrdinal: Math.max(0, getLastCompartmentEndMessage(db, sessionId)),
8661
+ excludeMessageId: userMsgId,
8594
8662
  memoryEnabled: options.memoryEnabled,
8595
8663
  visibleMemoryIds: options.visibleMemoryIds ?? null,
8596
8664
  sources: ["memory", "message"]
@@ -8615,11 +8683,15 @@ async function runAutoSearchHint(args) {
8615
8683
  if (results.length === 0) {
8616
8684
  return writeNoHintAndReconcile("empty");
8617
8685
  }
8618
- if (results[0].score < options.scoreThreshold) {
8619
- sessionLog(sessionId, `auto-search: top score ${results[0].score.toFixed(3)} below threshold ${options.scoreThreshold}`);
8686
+ results = selectAutoSearchResults(results, options.scoreThreshold);
8687
+ if (results.length === 0) {
8688
+ sessionLog(sessionId, `auto-search: no fragment meets relevance threshold ${options.scoreThreshold}`);
8620
8689
  return writeNoHintAndReconcile("below-threshold");
8621
8690
  }
8622
- const hintText = buildAutoSearchHint(results, { wordRules: options.wordRules });
8691
+ const hintText = buildAutoSearchHint(results, {
8692
+ wordRules: options.wordRules,
8693
+ query: rawPrompt
8694
+ });
8623
8695
  if (!hintText) {
8624
8696
  return writeNoHintAndReconcile("empty");
8625
8697
  }
@@ -8683,6 +8755,30 @@ function getSessionErrorInfo(properties) {
8683
8755
  };
8684
8756
  }
8685
8757
 
8758
+ // src/hooks/magic-context/diagnostic-log-state.ts
8759
+ var states = new BoundedSessionMap(1000);
8760
+ var scope = (sessionId) => `${getMagicContextStorageDir()}\x00${getHarness()}\x00${sessionId}`;
8761
+ function diagnosticStateChanged(sessionId, category, state) {
8762
+ const key = scope(sessionId);
8763
+ const previous = states.get(key) ?? new Map;
8764
+ if (previous.get(category) === state)
8765
+ return false;
8766
+ previous.set(category, state);
8767
+ states.set(key, previous);
8768
+ return true;
8769
+ }
8770
+ function clearDiagnosticLogState(sessionId) {
8771
+ states.delete(scope(sessionId));
8772
+ }
8773
+
8774
+ // src/hooks/magic-context/nudge-evaluation-log.ts
8775
+ function logNudgeEvaluation(sessionId, phase, line) {
8776
+ const category = `${phase}:${line.split(":", 1)[0]}`;
8777
+ const state = line.split(" ").filter((field) => /^(ctx_reduce|band|dampening|verdict|reason|lease)=/.test(field)).join(" ");
8778
+ if (diagnosticStateChanged(sessionId, category, state))
8779
+ sessionLog(sessionId, line);
8780
+ }
8781
+
8686
8782
  // src/hooks/magic-context/stripped-command.ts
8687
8783
  function matchStrippedMagicContextCommand(parts) {
8688
8784
  if (parts.length !== 1)
@@ -8871,7 +8967,7 @@ function maybeInjectChannel1Nudge(args, sessionId, tool, output) {
8871
8967
  evaluable: state.evaluable,
8872
8968
  generationInvalidated: state.generationInvalidated
8873
8969
  });
8874
- sessionLog(sessionId, formatChannel1Evaluation(decision));
8970
+ logNudgeEvaluation(sessionId, "tool-completion", formatChannel1Evaluation(decision));
8875
8971
  setLastNudgeUndropped(args.db, sessionId, decision.nextLastNudge);
8876
8972
  const nextNudgeState = {
8877
8973
  ...nudgeState,
@@ -10358,6 +10454,35 @@ function systemPromptDates(prompt, sticky) {
10358
10454
  return { live: values.length ? JSON.stringify(values) : undefined, stable };
10359
10455
  }
10360
10456
 
10457
+ // src/hooks/magic-context/system-prompt-sticky-date.ts
10458
+ var STICKY_DATE_KEY = "systemPromptStickyDate";
10459
+ function readPersistedSystemPromptStickyDate(db, sessionId) {
10460
+ try {
10461
+ const saved = readReplayEnvelope(db, sessionId, "read")[STICKY_DATE_KEY];
10462
+ return typeof saved === "string" && saved.length > 0 ? saved : undefined;
10463
+ } catch (error) {
10464
+ sessionLog(sessionId, "system prompt sticky date record unreadable:", error);
10465
+ return;
10466
+ }
10467
+ }
10468
+ function persistSystemPromptStickyDate(db, sessionId, stickyDate) {
10469
+ try {
10470
+ const written = updateReplayDocument(db, sessionId, (doc) => {
10471
+ if (doc[STICKY_DATE_KEY] === stickyDate)
10472
+ return false;
10473
+ doc.version = 2;
10474
+ doc[STICKY_DATE_KEY] = stickyDate;
10475
+ return true;
10476
+ });
10477
+ if (!written)
10478
+ sessionLog(sessionId, "system prompt sticky date record not written");
10479
+ return written;
10480
+ } catch (error) {
10481
+ sessionLog(sessionId, "system prompt sticky date record write failed:", error);
10482
+ return false;
10483
+ }
10484
+ }
10485
+
10361
10486
  // src/hooks/magic-context/system-date-refresh.ts
10362
10487
  var channels = new WeakMap;
10363
10488
  var outputUpdates = new WeakMap;
@@ -10428,6 +10553,7 @@ function beginSystemDateRequest(history, sessionId, stage, turnId, identity) {
10428
10553
  systemDone: false,
10429
10554
  messagesSeen: false,
10430
10555
  permitted: undefined,
10556
+ signedThinkingKept: undefined,
10431
10557
  ambiguous: identity === undefined && (turnId === undefined || sameTurn)
10432
10558
  };
10433
10559
  const blocked = [...requests.values()].filter((candidate) => !candidate.explicit && candidate.ambiguous && !(candidate.systemSeen && candidate.messagesSeen) && candidate.turnId === turnId).length;
@@ -10450,6 +10576,10 @@ function systemDateRefreshPermission(history, request) {
10450
10576
  const current = state(history, request);
10451
10577
  return current?.ambiguous ? undefined : current?.permitted;
10452
10578
  }
10579
+ function systemDateSignedThinkingKept(history, request) {
10580
+ const current = state(history, request);
10581
+ return current?.ambiguous ? undefined : current?.signedThinkingKept;
10582
+ }
10453
10583
  function waitForSystemDateRefresh(history, request, apply) {
10454
10584
  const current = state(history, request);
10455
10585
  if (!current)
@@ -10464,7 +10594,7 @@ function retire(history, current) {
10464
10594
  if (unpairable) {
10465
10595
  const apply = current.waiting;
10466
10596
  current.waiting = undefined;
10467
- apply?.(false);
10597
+ apply?.(false, undefined);
10468
10598
  }
10469
10599
  const channel = channels.get(history);
10470
10600
  const requests = channel?.get(current.sessionId);
@@ -10472,14 +10602,15 @@ function retire(history, current) {
10472
10602
  if (requests?.size === 0)
10473
10603
  channel?.delete(current.sessionId);
10474
10604
  }
10475
- function finishSystemDateRefresh(history, request, permitted) {
10605
+ function finishSystemDateRefresh(history, request, permitted, signedThinkingKept) {
10476
10606
  const current = state(history, request);
10477
10607
  if (!current)
10478
10608
  return;
10479
10609
  current.permitted = current.ambiguous ? false : permitted;
10610
+ current.signedThinkingKept = current.ambiguous ? undefined : signedThinkingKept;
10480
10611
  const apply = current.waiting;
10481
10612
  current.waiting = undefined;
10482
- apply?.(current.permitted);
10613
+ apply?.(current.permitted, current.signedThinkingKept);
10483
10614
  retire(history, current);
10484
10615
  }
10485
10616
  function finishSystemDateHook(history, request) {
@@ -10515,6 +10646,15 @@ function createSystemPromptHashHandler(deps) {
10515
10646
  });
10516
10647
  const guidanceEpochs = createPromptSurfaceGuidanceEpochCache(promptSurfaceRuntime);
10517
10648
  const stickyDateBySession = new Map;
10649
+ const recordedStickyDateBySession = new Map;
10650
+ const recordedStickyDate = (sessionId) => {
10651
+ let recorded = recordedStickyDateBySession.get(sessionId);
10652
+ if (recorded === undefined) {
10653
+ recorded = readPersistedSystemPromptStickyDate(deps.db, sessionId) ?? null;
10654
+ recordedStickyDateBySession.set(sessionId, recorded);
10655
+ }
10656
+ return recorded ?? undefined;
10657
+ };
10518
10658
  const processSystemPrompt = async (input, output) => {
10519
10659
  const sessionId = input.sessionID;
10520
10660
  if (!sessionId)
@@ -10583,18 +10723,37 @@ function createSystemPromptHashHandler(deps) {
10583
10723
  const hasPersistedHash = previousHash !== "" && previousHash !== "0";
10584
10724
  if (!hasPersistedHash)
10585
10725
  stickyDateBySession.delete(sessionId);
10586
- const stickyDate = stickyDateBySession.get(sessionId);
10726
+ let stickyDate = stickyDateBySession.get(sessionId);
10727
+ if (stickyDate === undefined && hasPersistedHash) {
10728
+ const recorded = recordedStickyDate(sessionId);
10729
+ const live = systemPromptDates(liveSystemContent).live;
10730
+ if (recorded !== undefined && live !== undefined && recorded !== live && systemPromptFingerprint(systemPromptDates(liveSystemContent, recorded).stable, promptSurface.preset) === previousHash) {
10731
+ stickyDate = recorded;
10732
+ stickyDateBySession.set(sessionId, recorded);
10733
+ }
10734
+ }
10735
+ const setStickyDate = (value) => {
10736
+ stickyDateBySession.set(sessionId, value);
10737
+ if (value !== recordedStickyDate(sessionId)) {
10738
+ if (persistSystemPromptStickyDate(deps.db, sessionId, value))
10739
+ recordedStickyDateBySession.set(sessionId, value);
10740
+ }
10741
+ };
10587
10742
  const dates = systemPromptDates(liveSystemContent, stickyDate);
10588
10743
  const currentDate = dates.live;
10589
10744
  const stableCandidate = dates.stable;
10590
10745
  const stableCandidateHash = systemPromptFingerprint(stableCandidate, promptSurface.preset);
10591
10746
  const contentOrPresetChanged = hasPersistedHash && stableCandidateHash !== previousHash;
10592
10747
  const rewritePermission = systemDateRefreshPermission(deps.historyRefreshSessions, dateRequest);
10748
+ const signedThinkingKept = systemDateSignedThinkingKept(deps.historyRefreshSessions, dateRequest);
10749
+ const prefixBoundModel = isPrefixBoundThinkingModel(liveModel?.providerID, liveModel?.modelID);
10750
+ const thinkingAllowsDate = (kept) => prefixBoundModel ? kept === false : kept !== true;
10751
+ const systemDateMayMove = (rewrite, kept) => (rewrite || idleCacheExpired) && thinkingAllowsDate(kept);
10593
10752
  let deferredDateRefresh = false;
10594
- if (currentDate && stickyDate && currentDate !== stickyDate && isCacheBusting && !idleCacheExpired && !contentOrPresetChanged && !requestMessagesFinal) {
10753
+ if (currentDate && stickyDate && currentDate !== stickyDate && (isCacheBusting || idleCacheExpired && isPrefixBoundThinkingModel(liveModel?.providerID, liveModel?.modelID)) && rewritePermission === undefined && !contentOrPresetChanged && !requestMessagesFinal) {
10595
10754
  const liveElements = [...output.system];
10596
- deferredDateRefresh = waitForSystemDateRefresh(deps.historyRefreshSessions, dateRequest, (permitted) => {
10597
- if (!permitted) {
10755
+ deferredDateRefresh = waitForSystemDateRefresh(deps.historyRefreshSessions, dateRequest, (permitted, keptSignedThinking) => {
10756
+ if (!systemDateMayMove(permitted, keptSignedThinking)) {
10598
10757
  deps.systemPromptRefreshSessions.add(sessionId);
10599
10758
  return;
10600
10759
  }
@@ -10607,7 +10766,7 @@ function createSystemPromptHashHandler(deps) {
10607
10766
  cachedM0SystemHash: hash,
10608
10767
  systemPromptTokens: estimateTokens(content)
10609
10768
  });
10610
- stickyDateBySession.set(sessionId, currentDate);
10769
+ setStickyDate(currentDate);
10611
10770
  output.system.splice(0, output.system.length, ...liveElements);
10612
10771
  publishSystemDateOutput(output.system);
10613
10772
  deps.systemPromptRefreshSessions.delete(sessionId);
@@ -10618,12 +10777,12 @@ function createSystemPromptHashHandler(deps) {
10618
10777
  }
10619
10778
  });
10620
10779
  }
10621
- const dateMayAdvance = idleCacheExpired || contentOrPresetChanged || isCacheBusting && !deferredDateRefresh && (dateRequest ? rewritePermission === true : rewritePermission !== false);
10780
+ const dateMayAdvance = thinkingAllowsDate(signedThinkingKept) && (contentOrPresetChanged || !deferredDateRefresh && systemDateMayMove(isCacheBusting && (dateRequest ? rewritePermission === true : rewritePermission !== false), signedThinkingKept));
10622
10781
  if (currentDate && !stickyDate) {
10623
- stickyDateBySession.set(sessionId, currentDate);
10782
+ setStickyDate(currentDate);
10624
10783
  } else if (currentDate && stickyDate && currentDate !== stickyDate) {
10625
10784
  if (dateMayAdvance) {
10626
- stickyDateBySession.set(sessionId, currentDate);
10785
+ setStickyDate(currentDate);
10627
10786
  sessionLog(sessionId, `system prompt date updated: ${stickyDate} → ${currentDate} (cache-busting pass)`);
10628
10787
  } else {
10629
10788
  let offset = 0;
@@ -10678,7 +10837,7 @@ function createSystemPromptHashHandler(deps) {
10678
10837
  sessionLog(sessionId, "system prompt meta persist failed (fail-open):", error);
10679
10838
  }
10680
10839
  }
10681
- if (isCacheBusting && !deferredDateRefresh && (contentOrPresetChanged || !currentDate || currentDate === stickyDate || !dateRequest || rewritePermission === true)) {
10840
+ if (isCacheBusting && !deferredDateRefresh && (contentOrPresetChanged && thinkingAllowsDate(signedThinkingKept) || !currentDate || currentDate === stickyDate || !dateRequest && thinkingAllowsDate(signedThinkingKept) || rewritePermission === true && thinkingAllowsDate(signedThinkingKept))) {
10682
10841
  deps.systemPromptRefreshSessions.delete(sessionId);
10683
10842
  }
10684
10843
  };
@@ -10692,6 +10851,7 @@ function createSystemPromptHashHandler(deps) {
10692
10851
  return {
10693
10852
  handler,
10694
10853
  clearSession: (sessionId) => {
10854
+ recordedStickyDateBySession.delete(sessionId);
10695
10855
  clearSystemDateRefresh(deps.historyRefreshSessions, sessionId);
10696
10856
  guidanceEpochs.clear(sessionId);
10697
10857
  clearSystemPromptHashSession(sessionId, {
@@ -11867,6 +12027,8 @@ var PASS_DEGRADATION_EFFECTS = {
11867
12027
  "stale-reduce-strip-exception": "changes-request",
11868
12028
  "image-strip-exception": "changes-request",
11869
12029
  "m0-m1-injection-degradation": "changes-request",
12030
+ "host-instruction-retention-read-failure": "changes-request",
12031
+ "host-instruction-retention-persistence-failure": "changes-request",
11870
12032
  "m0-m1-fallback-failure": "changes-request",
11871
12033
  "compaction-marker-drain-failure": "changes-request",
11872
12034
  "auto-search-timeout": "served",
@@ -12165,7 +12327,7 @@ async function runCompartmentPhaseImpl(args) {
12165
12327
  justAwaitedPublication = activeRun.published;
12166
12328
  published = published || activeRun.published;
12167
12329
  const historyReprepareShouldBust = activeRun.published && args.deferredHistoryRefreshSessions.has(args.sessionId);
12168
- pendingCompartmentInjection = prepareCompartmentInjection(args.db, args.resolvedSessionId, args.messages, historyReprepareShouldBust, args.projectPath, args.injectionBudgetTokens, args.experimentalTemporalAwareness);
12330
+ pendingCompartmentInjection = prepareCompartmentInjection(args.db, args.resolvedSessionId, args.messages, historyReprepareShouldBust, args.projectPath, args.injectionBudgetTokens, args.experimentalTemporalAwareness, args.coveredHostInstructions);
12169
12331
  if (historyReprepareShouldBust) {
12170
12332
  rebuiltHistoryThisPass = true;
12171
12333
  }
@@ -12382,7 +12544,7 @@ function capturePendingDropEligibility(targets, protectedTagIds) {
12382
12544
  eligible.add(number);
12383
12545
  } else {
12384
12546
  const content = target.getContent?.();
12385
- if (typeof content === "string" && content.length > `[dropped §${number}§]`.length)
12547
+ if (typeof content === "string" && content.length > `[dropped §${number}§]`.length && target.canSetContent?.(`[dropped §${number}§]`) !== false)
12386
12548
  eligible.add(number);
12387
12549
  }
12388
12550
  }
@@ -12440,27 +12602,43 @@ function buildReplacementContent(tagId) {
12440
12602
  return `[dropped §${tagId}§]`;
12441
12603
  }
12442
12604
  function applyNewToolDrop(target, options) {
12443
- if (options.persist && (target?.prepareDrop?.() ?? target?.canDrop?.()) === false) {
12605
+ const plan = planNewToolDrop(target, options, !!options.persist);
12606
+ if (!plan)
12444
12607
  return { result: "incomplete", mode: "full" };
12608
+ options.persist?.(plan.mode);
12609
+ return plan.apply();
12610
+ }
12611
+ function planNewToolDrop(target, options, prepare, plannedRemovals) {
12612
+ if (prepare && (target?.prepareDrop?.() ?? target?.canDrop?.()) === false) {
12613
+ return;
12445
12614
  }
12446
12615
  if (!target) {
12447
- options.persist?.("full");
12448
- return { result: "absent", mode: "full" };
12616
+ return { mode: "full", apply: () => ({ result: "absent", mode: "full" }) };
12449
12617
  }
12450
- if (options.inWindow && hasSmallToolInput(target) || options.keepSkeleton === true || target.cannotRemove?.() === true || target.wouldStrandConversationEnd?.() === true) {
12618
+ if (options.inWindow && hasSmallToolInput(target) || options.keepSkeleton === true || target.cannotRemove?.() === true || target.wouldStrandConversationEnd?.(plannedRemovals) === true) {
12451
12619
  const strip = target.hasAttachments?.() === true;
12452
- options.persist?.(strip ? "skeleton_stripped" : "skeleton_real");
12620
+ const mode = strip ? "skeleton_stripped" : "skeleton_real";
12453
12621
  return {
12454
- result: (strip ? target.skeletonStripped?.() : target.skeletonReal?.()) ?? "absent",
12455
- mode: strip ? "skeleton_stripped" : "skeleton_real"
12622
+ mode,
12623
+ apply: () => ({
12624
+ result: (strip ? target.skeletonStripped?.() : target.skeletonReal?.()) ?? "absent",
12625
+ mode
12626
+ })
12456
12627
  };
12457
12628
  }
12458
- options.persist?.("full");
12459
- const result = target.drop?.() ?? "absent";
12460
- if (result === "truncated" && target.hasAttachments?.() === true) {
12461
- return { result: target.skeletonStripped?.() ?? "absent", mode: "skeleton_stripped" };
12462
- }
12463
- return { result, mode: result === "truncated" ? "skeleton_real" : "full" };
12629
+ return {
12630
+ mode: "full",
12631
+ apply: () => {
12632
+ const result = target.drop?.() ?? "absent";
12633
+ if (result === "truncated" && target.hasAttachments?.() === true) {
12634
+ return {
12635
+ result: target.skeletonStripped?.() ?? "absent",
12636
+ mode: "skeleton_stripped"
12637
+ };
12638
+ }
12639
+ return { result, mode: result === "truncated" ? "skeleton_real" : "full" };
12640
+ }
12641
+ };
12464
12642
  }
12465
12643
  function hasSmallToolInput(target) {
12466
12644
  const bytes = target?.inputStringBytes?.() ?? null;
@@ -12542,6 +12720,7 @@ function renderConvertedToolSkeletons(targets, converted) {
12542
12720
  }
12543
12721
  return didMutate;
12544
12722
  }
12723
+ var PENDING_OPERATION_CHUNK_SIZE = 64;
12545
12724
  function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set, onTagReduced, onBatchComplete, onEligibilitySnapshot) {
12546
12725
  let didMutateMessage = false;
12547
12726
  let diagnostics;
@@ -12551,159 +12730,188 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12551
12730
  diagnostics.reasons[reason] = (diagnostics.reasons[reason] ?? 0) + 1;
12552
12731
  };
12553
12732
  let admitted = false;
12554
- try {
12555
- db.transaction(() => {
12556
- admitted = true;
12557
- }).immediate();
12558
- {
12559
- const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
12560
- onEligibilitySnapshot?.(capturePendingDropEligibility(targets, protectedTagIds));
12561
- const neededTagNumbers = new Set(pendingOps.map((op) => op.tagId));
12562
- for (const op of syntheticPendingOps)
12563
- neededTagNumbers.add(op.tagId);
12564
- const tags = preloadedTags ?? getTagsByNumbers(db, sessionId, (() => {
12565
- const newest = getNewestToolTagNumbers(db, sessionId, RECENT_TOOL_SKELETON_WINDOW);
12566
- const numbers = [...neededTagNumbers];
12567
- for (const tagNumber of newest) {
12568
- if (!neededTagNumbers.has(tagNumber))
12569
- numbers.push(tagNumber);
12570
- }
12571
- return numbers;
12572
- })());
12573
- const tagById = new Map(tags.map((tag) => [tag.tagNumber, tag]));
12574
- const tagStatusById = new Map(tags.map((tag) => [tag.tagNumber, tag.status]));
12575
- const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
12576
- const opsToApply = [
12577
- ...pendingOps.map((op) => ({ op, synthetic: false })),
12578
- ...syntheticPendingOps.map((op) => ({ op, synthetic: true }))
12579
- ];
12580
- diagnostics = {
12581
- source: pendingOps.length > 0 && syntheticPendingOps.length > 0 ? "mixed" : syntheticPendingOps.length > 0 ? "synthetic" : "pending",
12582
- total: opsToApply.length,
12583
- mutated: 0,
12584
- persistedWithoutMutation: 0,
12585
- reasons: {}
12586
- };
12587
- const skeletonWindow = new Set(getNewestToolTagNumbers(db, sessionId, RECENT_TOOL_SKELETON_WINDOW));
12588
- for (const { op: pendingOp, synthetic } of opsToApply) {
12589
- let operationMutated = false;
12590
- const tagStatus = tagStatusById.get(pendingOp.tagId);
12591
- if (tagStatus === "compacted" || tagStatus === "dropped") {
12592
- reject("already_reduced");
12593
- if (!synthetic)
12594
- removePendingOp(db, sessionId, pendingOp.tagId);
12595
- continue;
12596
- }
12597
- const target = targets.get(pendingOp.tagId);
12598
- const veto = pendingDropVeto(pendingOp.tagId, target, protectedTagIds);
12599
- if (veto) {
12600
- reject(veto);
12601
- continue;
12602
- }
12603
- const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
12604
- if (synthetic) {
12605
- if (!isToolTag) {
12606
- reject("synthetic_non_tool");
12607
- continue;
12608
- }
12609
- if (target?.canDrop?.() !== true) {
12610
- reject("synthetic_target_not_droppable");
12611
- continue;
12612
- }
12733
+ let startedAt = 0;
12734
+ const mutations = [];
12735
+ let drainChunk;
12736
+ let hasMore = false;
12737
+ do {
12738
+ admitted = false;
12739
+ startedAt = 0;
12740
+ try {
12741
+ db.transaction(() => {
12742
+ admitted = true;
12743
+ startedAt = performance.now();
12744
+ if (drainChunk) {
12745
+ drainChunk();
12746
+ return;
12613
12747
  }
12614
- let shouldPersistDrop = false;
12615
- const persistDrop = (mode) => {
12616
- let startedAt = 0;
12617
- try {
12618
- db.transaction(() => {
12619
- startedAt = performance.now();
12620
- markTagDropped(db, sessionId, pendingOp.tagId, mode);
12748
+ const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
12749
+ onEligibilitySnapshot?.(capturePendingDropEligibility(targets, protectedTagIds));
12750
+ const tags = preloadedTags ?? getTagsByNumbers(db, sessionId, [
12751
+ ...new Set([
12752
+ ...pendingOps.map((op) => op.tagId),
12753
+ ...syntheticPendingOps.map((op) => op.tagId)
12754
+ ])
12755
+ ]);
12756
+ const tagById = new Map(tags.map((tag) => [tag.tagNumber, tag]));
12757
+ const tagStatusById = new Map(tags.map((tag) => [tag.tagNumber, tag.status]));
12758
+ const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
12759
+ const opsToApply = [
12760
+ ...pendingOps.map((op) => ({ op, synthetic: false })),
12761
+ ...syntheticPendingOps.map((op) => ({ op, synthetic: true }))
12762
+ ];
12763
+ diagnostics = {
12764
+ source: pendingOps.length > 0 && syntheticPendingOps.length > 0 ? "mixed" : syntheticPendingOps.length > 0 ? "synthetic" : "pending",
12765
+ total: opsToApply.length,
12766
+ mutated: 0,
12767
+ persistedWithoutMutation: 0,
12768
+ reasons: {}
12769
+ };
12770
+ const skeletonWindow = new Set(preloadedTags ? tags.filter((tag) => tag.type === "tool").map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, RECENT_TOOL_SKELETON_WINDOW) : getNewestToolTagNumbers(db, sessionId, RECENT_TOOL_SKELETON_WINDOW));
12771
+ const plannedRemovals = new Set;
12772
+ const removedTagIds = new Set;
12773
+ const record = (mutated) => {
12774
+ if (!diagnostics)
12775
+ return;
12776
+ if (mutated) {
12777
+ didMutateMessage = true;
12778
+ diagnostics.mutated += 1;
12779
+ } else
12780
+ diagnostics.persistedWithoutMutation += 1;
12781
+ };
12782
+ let cursor = 0;
12783
+ drainChunk = () => {
12784
+ const chunk = opsToApply.slice(cursor, cursor + PENDING_OPERATION_CHUNK_SIZE);
12785
+ cursor += chunk.length;
12786
+ hasMore = cursor < opsToApply.length;
12787
+ for (const { op: pendingOp, synthetic } of chunk) {
12788
+ const tagStatus = tagStatusById.get(pendingOp.tagId);
12789
+ if (tagStatus === "compacted" || tagStatus === "dropped") {
12790
+ reject("already_reduced");
12621
12791
  if (!synthetic)
12622
12792
  removePendingOp(db, sessionId, pendingOp.tagId);
12623
- }).immediate();
12624
- } finally {
12625
- if (startedAt)
12626
- logSlowWriteTransaction("apply_pending_operation", startedAt);
12627
- }
12628
- };
12629
- if (isToolTag) {
12630
- if (editMarkerTagIds.has(pendingOp.tagId)) {
12631
- const strip = target?.hasAttachments?.() === true;
12632
- if (target?.canDrop?.() === false || target?.prepareDrop?.() === false || !target) {
12633
- reject("edit_marker_incomplete");
12634
12793
  continue;
12635
12794
  }
12636
- persistDrop(strip ? "edit_marker_stripped" : "edit_marker");
12637
- const markResult = (strip ? target?.editMarkerStripped?.() : target?.editMarker?.()) ?? "absent";
12638
- if (markResult === "incomplete" || markResult === "absent") {
12639
- reject(`edit_marker_${markResult}`);
12795
+ if (removedTagIds.has(pendingOp.tagId)) {
12796
+ reject("drop_incomplete");
12640
12797
  continue;
12641
12798
  }
12642
- didMutateMessage = true;
12643
- operationMutated = true;
12644
- onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "edit_marker" });
12645
- shouldPersistDrop = true;
12646
- } else {
12647
- const { result: dropResult, mode: appliedMode } = applyNewToolDrop(target, {
12648
- inWindow: skeletonWindow.has(pendingOp.tagId),
12649
- persist: persistDrop
12650
- });
12651
- if (dropResult === "incomplete" || synthetic && dropResult !== "removed" && dropResult !== "truncated") {
12652
- reject(`drop_${dropResult}`);
12799
+ const target = targets.get(pendingOp.tagId);
12800
+ const veto = pendingDropVeto(pendingOp.tagId, target, protectedTagIds);
12801
+ if (veto) {
12802
+ reject(veto);
12653
12803
  continue;
12654
12804
  }
12655
- if (dropResult === "removed" || dropResult === "truncated") {
12656
- didMutateMessage = true;
12657
- operationMutated = true;
12658
- onTagReduced?.({
12659
- tagNumber: pendingOp.tagId,
12660
- mode: appliedMode === "full" ? "full" : "truncated"
12805
+ const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
12806
+ if (synthetic) {
12807
+ if (!isToolTag) {
12808
+ reject("synthetic_non_tool");
12809
+ continue;
12810
+ }
12811
+ if (target?.canDrop?.() !== true) {
12812
+ reject("synthetic_target_not_droppable");
12813
+ continue;
12814
+ }
12815
+ }
12816
+ const persistDrop = (mode) => {
12817
+ markTagDropped(db, sessionId, pendingOp.tagId, mode);
12818
+ if (!synthetic)
12819
+ removePendingOp(db, sessionId, pendingOp.tagId);
12820
+ };
12821
+ if (isToolTag) {
12822
+ if (editMarkerTagIds.has(pendingOp.tagId)) {
12823
+ const strip = target?.hasAttachments?.() === true;
12824
+ if (target?.canDrop?.() === false || target?.prepareDrop?.() === false || !target) {
12825
+ reject("edit_marker_incomplete");
12826
+ continue;
12827
+ }
12828
+ persistDrop(strip ? "edit_marker_stripped" : "edit_marker");
12829
+ mutations.push(() => {
12830
+ const markResult = (strip ? target?.editMarkerStripped?.() : target?.editMarker?.()) ?? "absent";
12831
+ if (markResult === "incomplete" || markResult === "absent") {
12832
+ reject(`edit_marker_${markResult}`);
12833
+ return;
12834
+ }
12835
+ record(true);
12836
+ onTagReduced?.({
12837
+ tagNumber: pendingOp.tagId,
12838
+ mode: "edit_marker"
12839
+ });
12840
+ });
12841
+ } else {
12842
+ const plan = planNewToolDrop(target, { inWindow: skeletonWindow.has(pendingOp.tagId) }, true, plannedRemovals);
12843
+ if (!plan) {
12844
+ reject("drop_incomplete");
12845
+ continue;
12846
+ }
12847
+ persistDrop(plan.mode);
12848
+ if (plan.mode === "full" && target?.drop) {
12849
+ target.notePlannedRemoval?.(plannedRemovals);
12850
+ removedTagIds.add(pendingOp.tagId);
12851
+ }
12852
+ mutations.push(() => {
12853
+ const { result: dropResult, mode: appliedMode } = plan.apply();
12854
+ if (dropResult === "incomplete" || synthetic && dropResult !== "removed" && dropResult !== "truncated") {
12855
+ reject(`drop_${dropResult}`);
12856
+ return;
12857
+ }
12858
+ if (dropResult === "removed" || dropResult === "truncated") {
12859
+ record(true);
12860
+ onTagReduced?.({
12861
+ tagNumber: pendingOp.tagId,
12862
+ mode: appliedMode === "full" ? "full" : "truncated"
12863
+ });
12864
+ } else {
12865
+ reject(`drop_${dropResult}`);
12866
+ record(false);
12867
+ }
12868
+ });
12869
+ }
12870
+ } else if (target) {
12871
+ const replacement = buildReplacementContent(pendingOp.tagId);
12872
+ if (target.canSetContent?.(replacement) === false) {
12873
+ reject("content_unchanged");
12874
+ continue;
12875
+ }
12876
+ persistDrop();
12877
+ mutations.push(() => {
12878
+ const priorContent = target.getContent?.();
12879
+ const changed = target.setContent(replacement);
12880
+ record(changed);
12881
+ if (changed) {
12882
+ const originalCharacters = typeof priorContent === "string" ? priorContent.length : tagById.get(pendingOp.tagId)?.byteSize ?? replacement.length;
12883
+ onTagReduced?.({
12884
+ tagNumber: pendingOp.tagId,
12885
+ mode: "partial",
12886
+ removedCharacters: Math.max(0, originalCharacters - replacement.length)
12887
+ });
12888
+ } else {
12889
+ reject("content_unchanged");
12890
+ }
12661
12891
  });
12662
- } else {
12663
- reject(`drop_${dropResult}`);
12892
+ } else if (!synthetic) {
12893
+ reject("target_absent");
12894
+ persistDrop();
12895
+ mutations.push(() => record(false));
12664
12896
  }
12665
- shouldPersistDrop = true;
12666
12897
  }
12667
- } else if (target) {
12668
- const replacement = buildReplacementContent(pendingOp.tagId);
12669
- const priorContent = target.getContent?.();
12670
- persistDrop();
12671
- const changed = target.setContent(replacement);
12672
- if (changed) {
12673
- didMutateMessage = true;
12674
- operationMutated = true;
12675
- const originalCharacters = typeof priorContent === "string" ? priorContent.length : tagById.get(pendingOp.tagId)?.byteSize ?? replacement.length;
12676
- onTagReduced?.({
12677
- tagNumber: pendingOp.tagId,
12678
- mode: "partial",
12679
- removedCharacters: Math.max(0, originalCharacters - replacement.length)
12680
- });
12681
- } else {
12682
- reject("content_unchanged");
12683
- }
12684
- shouldPersistDrop = true;
12685
- } else if (!synthetic) {
12686
- reject("target_absent");
12687
- persistDrop();
12688
- shouldPersistDrop = true;
12689
- }
12690
- if (!shouldPersistDrop) {
12691
- reject("not_persisted");
12692
- continue;
12693
- }
12694
- if (operationMutated)
12695
- diagnostics.mutated += 1;
12696
- else
12697
- diagnostics.persistedWithoutMutation += 1;
12898
+ };
12899
+ drainChunk();
12900
+ }).immediate();
12901
+ } catch (error) {
12902
+ if (!admitted && /database (?:table )?is locked|sqlite_(busy|locked)/i.test(String(error))) {
12903
+ sessionLog(sessionId, "pending operations write admission busy; retaining remaining operations for retry");
12904
+ hasMore = false;
12905
+ } else {
12906
+ throw error;
12698
12907
  }
12908
+ } finally {
12909
+ if (startedAt)
12910
+ logSlowWriteTransaction("apply_pending_operations", startedAt);
12699
12911
  }
12700
- } catch (error) {
12701
- if (!admitted && /database (?:table )?is locked|sqlite_(busy|locked)/i.test(String(error))) {
12702
- sessionLog(sessionId, "pending operations write admission busy; retaining prior bytes for retry");
12703
- return false;
12704
- }
12705
- throw error;
12706
- }
12912
+ for (const mutate of mutations.splice(0))
12913
+ mutate();
12914
+ } while (hasMore);
12707
12915
  if (diagnostics) {
12708
12916
  onBatchComplete?.(diagnostics);
12709
12917
  if (diagnostics.total > 0 && diagnostics.mutated === 0) {
@@ -12937,10 +13145,41 @@ function createExistingTagResolver(sessionId, tagger, db) {
12937
13145
  }
12938
13146
 
12939
13147
  // src/hooks/magic-context/transform-stage-logger.ts
12940
- function logTransformTiming(sessionId, stage, startMs, extra) {
12941
- const elapsed = (performance.now() - startMs).toFixed(1);
13148
+ import { AsyncLocalStorage } from "node:async_hooks";
13149
+ var SLOW_STAGE_MS = 100;
13150
+ var passes = new AsyncLocalStorage;
13151
+ async function withTransformTimingSummary(run) {
13152
+ const pass = {
13153
+ stages: [],
13154
+ slow: [],
13155
+ closed: false,
13156
+ sessionId: undefined
13157
+ };
13158
+ return passes.run(pass, async () => {
13159
+ try {
13160
+ return await run();
13161
+ } finally {
13162
+ pass.closed = true;
13163
+ if (pass.sessionId)
13164
+ sessionLog(pass.sessionId, `transform stages: ${pass.stages.join(" ")} slow>=${SLOW_STAGE_MS}ms=[${pass.slow.join(",")}]`);
13165
+ }
13166
+ });
13167
+ }
13168
+ function logTransformElapsed(sessionId, stage, elapsedMs, extra) {
13169
+ const elapsed = elapsedMs.toFixed(1);
12942
13170
  const suffix = extra ? ` ${extra}` : "";
12943
- sessionLog(sessionId, `transform stage: stage=${stage} elapsed=${elapsed}ms${suffix}`);
13171
+ const pass = passes.getStore();
13172
+ if (pass && !pass.closed) {
13173
+ pass.sessionId = sessionId;
13174
+ pass.stages.push(`${stage}=${elapsed}ms${extra ? `(${extra})` : ""}`);
13175
+ if (elapsedMs >= SLOW_STAGE_MS)
13176
+ pass.slow.push(stage);
13177
+ }
13178
+ if (elapsedMs >= SLOW_STAGE_MS)
13179
+ sessionLog(sessionId, `transform stage: stage=${stage} elapsed=${elapsed}ms${suffix}`);
13180
+ }
13181
+ function logTransformTiming(sessionId, stage, startMs, extra) {
13182
+ logTransformElapsed(sessionId, stage, performance.now() - startMs, extra);
12944
13183
  }
12945
13184
 
12946
13185
  // src/hooks/magic-context/tag-messages.ts
@@ -13318,13 +13557,19 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13318
13557
  }));
13319
13558
  accAssignTag += performance.now() - _tAssignText;
13320
13559
  const persistedSource = sourceContents.get(tagId);
13321
- if (persistedSource !== undefined) {
13322
- textPart.text = options.normalizeRestoredAssistantText && message.info.role === "assistant" ? options.normalizeRestoredAssistantText(persistedSource) : persistedSource;
13560
+ if (persistedSource !== undefined && !options.refreshSourceContents) {
13561
+ textPart.text = options.normalizeRestoredAssistantText && message.info.role === "assistant" ? options.normalizeRestoredAssistantText(persistedSource, message.info.providerID) : persistedSource;
13323
13562
  } else {
13324
13563
  const sourceContent = stripTagPrefix(textPart.text);
13325
- if (sourceContent.trim().length > 0) {
13564
+ if (sourceContent.trim().length > 0 || options.refreshSourceContents) {
13326
13565
  const _tSaveText = performance.now();
13327
- saveSourceContent(db, sessionId, tagId, sourceContent);
13566
+ if (options.refreshSourceContents) {
13567
+ db.transaction(() => {
13568
+ replaceSourceContent(db, sessionId, tagId, sourceContent);
13569
+ db.prepare("UPDATE tags SET byte_size = ?, token_count = ? WHERE session_id = ? AND tag_number = ?").run(byteSize(sourceContent), estimateTextTagTokenCount(sourceContent), sessionId, tagId);
13570
+ }).immediate();
13571
+ } else
13572
+ saveSourceContent(db, sessionId, tagId, sourceContent);
13328
13573
  accSaveSource += performance.now() - _tSaveText;
13329
13574
  }
13330
13575
  }
@@ -13343,6 +13588,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13343
13588
  dropReasoningParts: thinkingParts,
13344
13589
  mutationParts: [{ message, part: textPart }],
13345
13590
  textPrefix: skipPrefixInjection ? "" : prependTag(tagId, ""),
13591
+ canSetContent: (content) => textPart.text !== content,
13346
13592
  setContent: (content, options) => {
13347
13593
  if (textPart.text === content)
13348
13594
  return false;
@@ -13400,26 +13646,20 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13400
13646
  const filePart = part;
13401
13647
  const messageParts = message.parts;
13402
13648
  const contentId = `${messageId}:file${partIndex}`;
13403
- const existingTagId = resolver.resolve(messageId, "file", contentId, fileOrdinal);
13404
- const _tAssignFile = performance.now();
13405
- const tagId = existingTagId ?? tagger.assignTag(sessionId, contentId, "file", byteSize(filePart.url), db, 0, null, 0, null, () => ({
13406
- tokenCount: estimateTextTagTokenCount(filePart.url),
13407
- inputTokenCount: null,
13408
- reasoningTokenCount: null
13409
- }));
13410
- accAssignTag += performance.now() - _tAssignFile;
13411
- if (existingTagId === undefined) {
13412
- const sourceContent = buildFileSourceContent(message.parts);
13413
- if (sourceContent) {
13414
- const _tSaveFile = performance.now();
13415
- saveSourceContent(db, sessionId, tagId, sourceContent);
13416
- accSaveSource += performance.now() - _tSaveFile;
13417
- }
13418
- }
13649
+ const existingTagId = resolver.resolve(messageId, "file", contentId, fileOrdinal) ?? getTagNumberByMessageId(db, sessionId, contentId) ?? undefined;
13650
+ fileOrdinal += 1;
13651
+ if (existingTagId === undefined)
13652
+ continue;
13653
+ const tagId = existingTagId;
13654
+ tagger.bindTag(sessionId, contentId, tagId);
13419
13655
  messageTagNumbers.set(message, Math.max(messageTagNumbers.get(message) ?? 0, tagId));
13420
13656
  targets.set(tagId, {
13421
13657
  message,
13422
13658
  mutationParts: [{ message, part: filePart }],
13659
+ canSetContent: (content) => {
13660
+ const current = messageParts[partIndex];
13661
+ return !(typeof current === "object" && current !== null && ("text" in current) && current.text === content);
13662
+ },
13423
13663
  setContent: (content) => {
13424
13664
  const prev = messageParts[partIndex];
13425
13665
  const prevText = typeof prev === "object" && prev !== null && "text" in prev ? prev.text : "";
@@ -13432,7 +13672,6 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13432
13672
  return true;
13433
13673
  }
13434
13674
  });
13435
- fileOrdinal += 1;
13436
13675
  }
13437
13676
  }
13438
13677
  if (message.info.role === "assistant" && !messageHasTextPart) {
@@ -13461,6 +13700,23 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13461
13700
  normalizationTargets
13462
13701
  };
13463
13702
  }
13703
+ // src/features/magic-context/storage-host-instruction-retention.ts
13704
+ var NAMESPACE3 = "hostInstructionRetention";
13705
+ function isHostInstructionRetentionOn(db, sessionId) {
13706
+ const lane = readReplayEnvelope(db, sessionId)[NAMESPACE3];
13707
+ return typeof lane === "object" && lane !== null && lane.on === true;
13708
+ }
13709
+ function markHostInstructionRetention(db, sessionId) {
13710
+ return updateReplayDocument(db, sessionId, (doc) => {
13711
+ const lane = doc[NAMESPACE3];
13712
+ if (typeof lane === "object" && lane !== null && lane.on === true)
13713
+ return false;
13714
+ doc.version = 2;
13715
+ doc[NAMESPACE3] = { on: true };
13716
+ return true;
13717
+ });
13718
+ }
13719
+
13464
13720
  // src/hooks/magic-context/channel2-cycle.ts
13465
13721
  function rearmChannel2AfterCoverageAdvancingHardFold(input) {
13466
13722
  if (input.compactionOff || !input.foldExecuted || input.previousCoverage === null || input.currentCoverage === null || input.currentCoverage <= input.previousCoverage) {
@@ -14374,6 +14630,28 @@ function freezeReasoningOnBustingPass(args) {
14374
14630
  sessionLog(args.sessionId, `proactive thinking strip: busting pass froze reasoning of ${messageIds.length} assistant(s) [${messageIds.join(",")}]`);
14375
14631
  return { strip: { messageIds }, persistenceFailed: false };
14376
14632
  }
14633
+ function servesThinkingBlock(messages) {
14634
+ for (const message of messages) {
14635
+ if (message.info.role !== "assistant")
14636
+ continue;
14637
+ for (const part of message.parts) {
14638
+ if (!isRecord(part) || part.ignored === true)
14639
+ continue;
14640
+ if (part.type === "redacted_thinking")
14641
+ return true;
14642
+ if (part.type !== "reasoning" && part.type !== "thinking")
14643
+ continue;
14644
+ const anthropic = isRecord(part.metadata) ? part.metadata.anthropic : undefined;
14645
+ if (!isRecord(anthropic))
14646
+ continue;
14647
+ if (anthropic.redactedData !== undefined)
14648
+ return true;
14649
+ if (typeof part.text === "string" && part.text !== "")
14650
+ return true;
14651
+ }
14652
+ }
14653
+ return false;
14654
+ }
14377
14655
  function dropMarkerSummaryTag(db, sessionId, summaryMessageId) {
14378
14656
  const tagNumber = getTagNumberByMessageId(db, sessionId, `${summaryMessageId}:p0`);
14379
14657
  if (tagNumber !== null)
@@ -14537,7 +14815,7 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
14537
14815
  clearedParts = stripClearedReasoning(targetedMessages.filter((message) => !restoredMessages.has(message)));
14538
14816
  }
14539
14817
  }
14540
- const bindingRecoveryParts = options?.skipMergedReasoningStrip ? 0 : stripReasoningFromAssistantIds(messages, resolvedProviderID, options?.frozenThinkingBindingMessageIds ?? new Set, restoredMessages);
14818
+ const bindingRecoveryParts = stripReasoningFromAssistantIds(messages, resolvedProviderID, options?.frozenThinkingBindingMessageIds ?? new Set, restoredMessages);
14541
14819
  const mergedReasoningParts = bindingRecoveryParts + (options?.skipMergedReasoningStrip ? 0 : stripReasoningFromMergedAssistants(messages, resolvedProviderID, {
14542
14820
  mutationExemptMessage: options?.reasoningMutationExemptMessage,
14543
14821
  frozenMessageIds: options?.mergedReasoningStrippedIds,
@@ -14614,7 +14892,7 @@ async function runPostTransformPhase(args) {
14614
14892
  let deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
14615
14893
  let materializationRequested = isExplicitFlush || deferredMaterialize;
14616
14894
  const m0M1EnabledForFold = args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory) && (args.fullFeatureMode || compactionOff);
14617
- const frozenThinking = new Set(args.activeThinkingTurn ? getMergedReasoningStrippedIds(args.db, args.sessionId) : []);
14895
+ const frozenThinking = new Set(getMergedReasoningStrippedIds(args.db, args.sessionId));
14618
14896
  const bindingThinking = new Set([...frozenThinking].filter((id) => id.startsWith(THINKING_BINDING_RECOVERY_FROZEN_PREFIX)).map((id) => id.slice(THINKING_BINDING_RECOVERY_FROZEN_PREFIX.length)));
14619
14897
  const retainedThinking = args.activeThinkingTurn ? retainedActiveThinkingParts({
14620
14898
  messages: args.messages,
@@ -14640,6 +14918,7 @@ async function runPostTransformPhase(args) {
14640
14918
  let freezeM0M1 = args.freezeM0M1 === true || activeThinkingPrefixHold;
14641
14919
  let rewritingSignedPrefix = false;
14642
14920
  let thinkingReleasedForFit = false;
14921
+ let thinkingOmissionPersistenceFailed = false;
14643
14922
  const releaseThinkingForRewrite = (forFit = false) => {
14644
14923
  const stripped = freezeReasoningOnBustingPass({
14645
14924
  db: args.db,
@@ -14647,8 +14926,12 @@ async function runPostTransformPhase(args) {
14647
14926
  messages: args.messages,
14648
14927
  alreadyFrozen: bindingThinking
14649
14928
  });
14650
- if (stripped.persistenceFailed)
14929
+ if (stripped.persistenceFailed) {
14930
+ thinkingOmissionPersistenceFailed = true;
14651
14931
  throw new Error("Cannot persist signed thinking omission before prefix rewrite");
14932
+ }
14933
+ for (const id of stripped.strip?.messageIds ?? [])
14934
+ bindingThinking.add(id);
14652
14935
  retainedThinking.clear();
14653
14936
  protectedThinkingMessages.clear();
14654
14937
  activeThinkingTurn = false;
@@ -14658,6 +14941,9 @@ async function runPostTransformPhase(args) {
14658
14941
  rewritingSignedPrefix = true;
14659
14942
  thinkingReleasedForFit ||= forFit;
14660
14943
  };
14944
+ if (args.compactionModeTransition && args.thinkingBindingRecoveryEnabledForModel) {
14945
+ releaseThinkingForRewrite();
14946
+ }
14661
14947
  const foldDueDecision = m0M1EnabledForFold && args.m0M1 && !freezeM0M1 ? mustMaterialize({
14662
14948
  db: args.db,
14663
14949
  sessionId: args.sessionId,
@@ -14693,6 +14979,8 @@ async function runPostTransformPhase(args) {
14693
14979
  };
14694
14980
  if ((foldDueDecision.value || softRefreshOpportunity || firstRenderBust && activeThinkingPrefixHold) && m0M1EnabledForFold && args.m0M1) {
14695
14981
  let committedFoldBustsServedPrefix;
14982
+ let committedFoldChangesHead = false;
14983
+ let committedFoldThinkingIds = [];
14696
14984
  try {
14697
14985
  const previousM1 = args.sessionMeta.cachedM1Bytes?.toString("utf8");
14698
14986
  const foldResult = injectM0M1({
@@ -14719,6 +15007,24 @@ async function runPostTransformPhase(args) {
14719
15007
  m0Text: rendered.m0Bytes.toString(),
14720
15008
  m1Text: rendered.m1Bytes.toString()
14721
15009
  }) : foldBustsServedPrefix(foldDueDecision.reason, servedPrefixBeforeFold, rendered);
15010
+ committedFoldChangesHead = firstRenderBust ? !servedPrefixMatches({
15011
+ messages: servedBeforeFirstRender,
15012
+ m0Text: rendered.m0Bytes.toString(),
15013
+ m1Text: rendered.m1Bytes.toString()
15014
+ }) : foldChangesServedPrefix(servedPrefixBeforeFold, rendered);
15015
+ if (args.thinkingBindingRecoveryEnabledForModel && (compactionOff && !activeThinkingPrefixHold && committedFoldChangesHead || activeThinkingPrefixHold && firstRenderBust && bustsPrefix)) {
15016
+ const omission = freezeReasoningOnBustingPass({
15017
+ db,
15018
+ sessionId: args.sessionId,
15019
+ messages: args.messages,
15020
+ alreadyFrozen: bindingThinking
15021
+ });
15022
+ if (omission.persistenceFailed) {
15023
+ thinkingOmissionPersistenceFailed = true;
15024
+ throw new Error("Cannot persist signed thinking omission before prefix rewrite");
15025
+ }
15026
+ committedFoldThinkingIds = omission.strip?.messageIds ?? [];
15027
+ }
14722
15028
  if (bustsPrefix) {
14723
15029
  if (!conversions.isCurrent(db)) {
14724
15030
  throw new MaterializeContentionError({
@@ -14735,7 +15041,13 @@ async function runPostTransformPhase(args) {
14735
15041
  }
14736
15042
  });
14737
15043
  preparedPrefix = foldResult;
14738
- if (activeThinkingPrefixHold && firstRenderBust && committedFoldBustsServedPrefix) {
15044
+ if (foldResult.m0RematerializedThisPass) {
15045
+ for (const id of committedFoldThinkingIds)
15046
+ bindingThinking.add(id);
15047
+ }
15048
+ if (foldResult.m0RematerializedThisPass && activeThinkingPrefixHold && firstRenderBust && committedFoldBustsServedPrefix) {
15049
+ releaseThinkingForRewrite();
15050
+ } else if (compactionOff && foldResult.m0RematerializedThisPass && !activeThinkingPrefixHold && args.thinkingBindingRecoveryEnabledForModel && committedFoldChangesHead) {
14739
15051
  releaseThinkingForRewrite();
14740
15052
  }
14741
15053
  prefixPreflightFailed = foldResult.materializationContentionRetryExhausted === true;
@@ -14764,6 +15076,8 @@ async function runPostTransformPhase(args) {
14764
15076
  sessionLog(args.sessionId, "channel2 fold-cycle reset failed (ignored):", error);
14765
15077
  }
14766
15078
  } catch (error) {
15079
+ if (thinkingOmissionPersistenceFailed)
15080
+ throw error;
14767
15081
  preparedPrefix = cachedPrefixBeforePreflight;
14768
15082
  prefixPreflightFailed = true;
14769
15083
  failPass("m0-m1-fold-preexecution-degradation", error);
@@ -14881,17 +15195,28 @@ async function runPostTransformPhase(args) {
14881
15195
  throw new EmergencyFailClosedError("Magic Context could not read its saved reasoning-removal state for this session", { cause: error });
14882
15196
  }
14883
15197
  }
15198
+ const heuristicsLogChanged = diagnosticStateChanged(args.sessionId, "heuristics", JSON.stringify([
15199
+ args.currentTurnId,
15200
+ shouldRunHeuristics,
15201
+ shouldRunHeuristics ? null : args.schedulerDeferReason
15202
+ ]));
15203
+ const pendingLogChanged = diagnosticStateChanged(args.sessionId, "pending-ops", JSON.stringify([
15204
+ args.currentTurnId,
15205
+ shouldApplyPendingOps,
15206
+ shouldApplyPendingOps ? null : args.schedulerDeferReason,
15207
+ shouldApplyPendingOps ? null : (getPendingOpsCount(args.db, args.sessionId) ?? 0) > 0
15208
+ ]));
14884
15209
  if (shouldRunHeuristics) {
14885
15210
  const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
14886
15211
  const reason = isExplicitFlush ? `pending_materialization origin=${pendingOrigin}` : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : foldBustsServedPrefixThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : subagentRerun ? `${reclaimRideLabel(rideSignals)} subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `${reclaimRideLabel(rideSignals)} (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
14887
15212
  sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
14888
- } else if (args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
15213
+ } else if (heuristicsLogChanged && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
14889
15214
  sessionLog(args.sessionId, `heuristics WILL NOT RUN — reason=${args.schedulerDeferReason}`);
14890
15215
  }
14891
15216
  if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
14892
15217
  sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
14893
15218
  }
14894
- if (!shouldApplyPendingOps && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
15219
+ if (!shouldApplyPendingOps && pendingLogChanged && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
14895
15220
  sessionLog(args.sessionId, `pending ops WILL NOT APPLY — reason=${args.schedulerDeferReason} pendingOps=${formatPendingOpsDepth()} context=${args.contextUsage.percentage.toFixed(1)}%`);
14896
15221
  }
14897
15222
  if (hasPendingUserOps && !shouldApplyPendingOps) {
@@ -15278,6 +15603,30 @@ async function runPostTransformPhase(args) {
15278
15603
  }
15279
15604
  }
15280
15605
  const m0M1Enabled = m0M1EnabledForFold;
15606
+ let retainCoveredInstructions = false;
15607
+ if (m0M1Enabled && args.m0M1 && !compactionOff && args.hostInstructionRows) {
15608
+ const covered = args.coveredHostInstructions ?? [];
15609
+ if (covered.length > 0 || canEditWholePrefix) {
15610
+ let retain = false;
15611
+ try {
15612
+ retain = isHostInstructionRetentionOn(args.db, args.sessionId);
15613
+ } catch (error) {
15614
+ failPass("host-instruction-retention-read-failure", error);
15615
+ }
15616
+ if (!retain && canEditWholePrefix) {
15617
+ let written = false;
15618
+ try {
15619
+ written = markHostInstructionRetention(args.db, args.sessionId);
15620
+ } catch (error) {
15621
+ failPass("host-instruction-retention-persistence-failure", error);
15622
+ }
15623
+ if (!written)
15624
+ failPass("host-instruction-retention-persistence-failure");
15625
+ retain = true;
15626
+ }
15627
+ retainCoveredInstructions = retain;
15628
+ }
15629
+ }
15281
15630
  if (m0M1Enabled && args.m0M1) {
15282
15631
  if (freezeM0M1 && !preparedPrefix) {
15283
15632
  preparedPrefix = prepareCachedM0M1Replay(args.db, args.sessionId);
@@ -15305,6 +15654,17 @@ async function runPostTransformPhase(args) {
15305
15654
  compactionOff
15306
15655
  });
15307
15656
  deliveredPrefix = result;
15657
+ if (retainCoveredInstructions) {
15658
+ const retained = new Set(args.messages);
15659
+ const covered = [...args.coveredHostInstructions ?? []];
15660
+ for (const message of messagesBeforeInjection) {
15661
+ if (!retained.has(message) && isHostRenderedSystemMessage(message)) {
15662
+ markCoveredInstructionRow(message.info);
15663
+ covered.push(message);
15664
+ }
15665
+ }
15666
+ args.messages.splice(result.prependedMessageCount, 0, ...covered);
15667
+ }
15308
15668
  if (result.prefixTrimStatus === "applied") {
15309
15669
  const retainedMessages = new Set(args.messages);
15310
15670
  const trimmedMessageIds = messagesBeforeInjection.filter((message) => !retainedMessages.has(message)).map((message) => message.info.id).filter((id) => typeof id === "string");
@@ -15575,7 +15935,7 @@ async function runPostTransformPhase(args) {
15575
15935
  }
15576
15936
  }
15577
15937
  const mergedReasoningStrippedIds = new Set(replaySnapshot?.mergedReasoningStrippedIds ?? []);
15578
- const thinkingBindingRecoveryMessageIds = new Set;
15938
+ const thinkingBindingRecoveryMessageIds = new Set(bindingThinking);
15579
15939
  let thinkingBindingRecovery = null;
15580
15940
  let proactiveThinkingStrip = null;
15581
15941
  if (!compactionOff) {
@@ -16080,7 +16440,9 @@ function createTransform(deps) {
16080
16440
  const loadedSessions = new Set;
16081
16441
  const prefixHoldLogTurnIds = new Map;
16082
16442
  const thinkingFitRetries = new Set;
16443
+ const compactionModeTransitionPending = new Set;
16083
16444
  const clearSessionLogState = (sessionId) => {
16445
+ clearDiagnosticLogState(sessionId);
16084
16446
  prefixHoldLogTurnIds.delete(sessionId);
16085
16447
  };
16086
16448
  const unmanagedOverWindowSessions = new Set;
@@ -16101,7 +16463,8 @@ function createTransform(deps) {
16101
16463
  const startTime = performance.now();
16102
16464
  const historianRun = deps.resolveHistorianRun?.();
16103
16465
  const messages = output.messages;
16104
- const originalForThinkingFit = messages.some((message) => message.parts.some((part) => isRecord(part) && ["reasoning", "thinking", "redacted_thinking"].includes(String(part.type)))) ? structuredClone(messages) : null;
16466
+ const originalForThinkingFit = messages.some((message) => message.parts.some((part) => isRecord(part) && ["reasoning", "thinking", "redacted_thinking"].includes(String(part.type)))) ? cloneKeepingCoveredInstructionMarks(messages) : null;
16467
+ const coveredHostInstructions = takeCoveredInstructionRows(messages);
16105
16468
  const passOutcome = createPassOutcome();
16106
16469
  const tSessionId = performance.now();
16107
16470
  const sessionId = findSessionId(messages);
@@ -16199,6 +16562,7 @@ function createTransform(deps) {
16199
16562
  const hasTransitionEffects = transition.recordToWrite !== null || transition.notice !== null || transition.invalidatedM0Baseline || transition.clearedCompartmentInProgress || transition.historianCatchUpSignaled;
16200
16563
  if (hasTransitionEffects) {
16201
16564
  if (transition.invalidatedM0Baseline) {
16565
+ compactionModeTransitionPending.add(sessionId);
16202
16566
  sessionMeta = {
16203
16567
  ...sessionMeta,
16204
16568
  cachedM0Bytes: null,
@@ -16627,8 +16991,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16627
16991
  recordedSessionProjectIdentity.set(sessionId, sessionIdentityForBinding);
16628
16992
  }
16629
16993
  const taggerFloor = compactionOff ? 0 : deriveTaggerLoadFloor(messages, sessionId, db);
16630
- if (!compactionOff && taggerFloor === 0 && messages.length > 0) {
16631
- sessionLog(sessionId, `tag floor: 0 (full-scan fallback) — no leading wire message resolved a tag across ${messages.length} msgs`);
16994
+ const tagFloorMode = compactionOff || messages.length === 0 ? "inactive" : taggerFloor === 0 ? "fallback" : "scoped";
16995
+ if (diagnosticStateChanged(sessionId, "tag-floor", tagFloorMode) && tagFloorMode !== "inactive") {
16996
+ sessionLog(sessionId, taggerFloor === 0 ? `tag floor: 0 (full-scan fallback) — no scoped floor above the safety margin across ${messages.length} msgs` : `tag floor: ${taggerFloor} (scoped load)`);
16632
16997
  }
16633
16998
  const ownerRatio = sessionDecisionCalibration(db, sessionId).proseRatio;
16634
16999
  prewarmTagOwners(db, sessionId, ownerRatio);
@@ -16677,7 +17042,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16677
17042
  const messagesBeforeInitialPrepare = isCacheBusting && deferredHistoryWasPendingAtPassStart ? [...messages] : null;
16678
17043
  if (fullFeatureMode && !compactionOff) {
16679
17044
  const tInj = performance.now();
16680
- pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness);
17045
+ pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness, coveredHostInstructions);
16681
17046
  if (messagesBeforeInitialPrepare) {
16682
17047
  const skippedVisibleMessages = pendingCompartmentInjection?.skippedVisibleMessages ?? 0;
16683
17048
  trimmedMessagesAtCompactionBoundary = messagesBeforeInitialPrepare.slice(0, skippedVisibleMessages);
@@ -16707,6 +17072,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16707
17072
  logTransformTiming(sessionId, "injectTemporalMarkers", tTemporal);
16708
17073
  }
16709
17074
  let taggingSucceeded = false;
17075
+ const refreshSourceContents = deps.storeGeneration === "v2" && fullFeatureMode && !compactionOff && !!(projectIdentity || sessionDirectory) && !unresolvedDirectoryHold && !recovery.prefix && sessionMeta.cachedM0Bytes == null && sessionMeta.cachedM1Bytes == null && deps.refreshSourceContents?.(sessionId) === true;
16710
17076
  let recoveryBatch = null;
16711
17077
  let recoveryNormalized = false;
16712
17078
  const normalizeRecoveryTail = recovery.prefix ? () => {
@@ -16742,7 +17108,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16742
17108
  scopedToolSweep,
16743
17109
  servedMessages: messages,
16744
17110
  protectedThinkingMessages: protectedThinkingMessagesForPass,
16745
- normalizeRestoredAssistantText: deps.normalizeRestoredAssistantText
17111
+ normalizeRestoredAssistantText: deps.normalizeRestoredAssistantText,
17112
+ refreshSourceContents
16746
17113
  });
16747
17114
  targets = result.targets;
16748
17115
  if (thinkingRecovery.restore)
@@ -16823,6 +17190,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16823
17190
  const rawGetNotifParams = runNotificationParams;
16824
17191
  const tCompartmentPhase = performance.now();
16825
17192
  const compartmentPhase = await runCompartmentPhase({
17193
+ coveredHostInstructions,
16826
17194
  hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
16827
17195
  compactionMarkerStrategy: deps.compactionMarkerStrategy,
16828
17196
  canRunCompartments,
@@ -16989,6 +17357,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16989
17357
  fullFeatureMode,
16990
17358
  compactionOff,
16991
17359
  canRunCompartments,
17360
+ hostInstructionRows: deps.storeGeneration === "v2",
16992
17361
  awaitedCompartmentRun,
16993
17362
  phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
16994
17363
  compartmentInProgress,
@@ -16997,6 +17366,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16997
17366
  activeThinkingPrefixHold,
16998
17367
  directoryPrefixHold: unresolvedDirectoryHold,
16999
17368
  forceSignedRebuildForFit: thinkingFitRetries.has(sessionId) || !!recovery.rebuildReason,
17369
+ compactionModeTransition: compactionModeTransitionPending.has(sessionId),
17000
17370
  readLastServedMessages: () => {
17001
17371
  const slot = getInMemorySlot(sessionId) ?? loadPersistedLkgSlot(db, sessionId);
17002
17372
  try {
@@ -17026,6 +17396,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17026
17396
  emergencyCeilingTokens,
17027
17397
  pendingCompartmentInjection,
17028
17398
  prefixTrimSourceOrder,
17399
+ coveredHostInstructions,
17029
17400
  hiddenMessagesAtCompactionSeam,
17030
17401
  trimmedMessagesAtCompactionBoundary,
17031
17402
  didMutateFromFlushedStatuses,
@@ -17220,7 +17591,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17220
17591
  if (!finalWireEstimate) {
17221
17592
  sessionLog(sessionId, `transform: final-wire telemetry estimate=unavailable trusted=false conversation=unknown tools=unknown system=unknown toolDefinitions=unknown tail=${finalWireTail}`);
17222
17593
  }
17223
- finishSystemDateRefresh(deps.historyRefreshSessions, dateRequest, postTransformResult.bustedThisPass && !activeThinkingPrefixHold || postTransformResult.thinkingReleasedForFit === true);
17594
+ const signedThinkingServed = isPrefixBoundThinkingModel(modelForBudget?.providerID, modelForBudget?.modelID) && servesThinkingBlock(messages);
17595
+ finishSystemDateRefresh(deps.historyRefreshSessions, dateRequest, postTransformResult.bustedThisPass && !activeThinkingPrefixHold && !signedThinkingServed || postTransformResult.thinkingReleasedForFit === true, signedThinkingServed);
17596
+ compactionModeTransitionPending.delete(sessionId);
17224
17597
  if (activeThinkingPrefixHold && !postTransformResult.thinkingReleasedForFit && sessionMeta.cachedM0Bytes != null && sessionMeta.cachedM1Bytes != null) {
17225
17598
  recordHeldHeadForRequest(sessionId, currentLkgRequestIdentity(sessionId), (ownsHistory) => deferDeliveredSystemRefresh(deps, sessionId, ownsHistory));
17226
17599
  }
@@ -17322,6 +17695,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17322
17695
  if (uncachedMessageIds.length > 0) {
17323
17696
  try {
17324
17697
  storedByMessage = getActiveTagTokenTotalsByMessage(db, sessionId, uncachedMessageIds);
17698
+ omitIncompleteFileTokenTotals(db, sessionId, messages.flatMap((message) => typeof message.info.id === "string" ? [{ id: message.info.id, parts: message.parts }] : []), storedByMessage);
17325
17699
  } catch {
17326
17700
  storedByMessage = new Map;
17327
17701
  }
@@ -17378,7 +17752,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17378
17752
  postReduceGraceBaselineU: channel1State.postReduceGraceBaselineU,
17379
17753
  postReduceGracePreLevel: channel1State.postReduceGracePreLevel
17380
17754
  });
17381
- sessionLog(sessionId, formatChannel1Evaluation(channel1Decision));
17755
+ logNudgeEvaluation(sessionId, "transform", formatChannel1Evaluation(channel1Decision));
17382
17756
  const channel2Evaluation = evaluateChannel2(channelBaseline);
17383
17757
  const leaseBefore = getChannel2NudgeState(db, sessionId);
17384
17758
  if (channelBaseline.evaluable && !channelBaseline.generationInvalidated && !channelBaseline.reducedSinceRefresh) {
@@ -17389,7 +17763,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17389
17763
  }
17390
17764
  }
17391
17765
  const leaseAfter = getChannel2NudgeState(db, sessionId);
17392
- sessionLog(sessionId, formatChannel2Evaluation(channel2Evaluation, {
17766
+ logNudgeEvaluation(sessionId, "transform", formatChannel2Evaluation(channel2Evaluation, {
17393
17767
  leaseBefore,
17394
17768
  leaseAfter,
17395
17769
  gateHoldReason: channelBaseline.reducedSinceRefresh ? "recent-reduce-refresh" : undefined
@@ -17428,7 +17802,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17428
17802
  sessionLog(sessionId, "memory maintenance launch probe failed (ignored):", error);
17429
17803
  }
17430
17804
  };
17431
- return Object.assign(transform, {
17805
+ const timedTransform = (input, output) => withTransformTimingSummary(() => transform(input, output));
17806
+ return Object.assign(timedTransform, {
17432
17807
  clearSessionLogState(sessionId) {
17433
17808
  clearSessionLogState(sessionId);
17434
17809
  }
@@ -18702,8 +19077,8 @@ function registerRpcHandlers(rpcServer, args) {
18702
19077
  const db = readDatabase();
18703
19078
  if (!db)
18704
19079
  return { ok: false, error: "db unavailable" };
18705
- const { runManagedRecomp } = await import("./recomp-orchestrator-k760qy1n.js");
18706
- const { sendIgnoredMessage } = await import("./send-session-notification-njjf3b4s.js");
19080
+ const { runManagedRecomp } = await import("./recomp-orchestrator-mmpy5cb7.js");
19081
+ const { sendIgnoredMessage } = await import("./send-session-notification-zpqs213d.js");
18707
19082
  log(`[rpc] recomp requested for session ${sessionId}`);
18708
19083
  if (!args.client && !args.hiddenCompletionExecutor) {
18709
19084
  return {
@@ -18752,7 +19127,7 @@ function registerRpcHandlers(rpcServer, args) {
18752
19127
  const db = readDatabase();
18753
19128
  if (!db)
18754
19129
  return { ok: false, error: "db unavailable" };
18755
- const { runManagedWrapup } = await import("./wrapup-orchestrator-b2gswatj.js");
19130
+ const { runManagedWrapup } = await import("./wrapup-orchestrator-jq589pgr.js");
18756
19131
  const model = liveSessionState.liveModelBySession.get(sessionId);
18757
19132
  const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
18758
19133
  const ctx = {
@@ -18840,8 +19215,17 @@ function subagentToolRefusal(db, toolId, sessionId, isInternalChild = () => fals
18840
19215
  function hideSubagentTools(draft, db) {
18841
19216
  if (!getOrCreateSessionMeta(db, draft.sessionID).isSubagent)
18842
19217
  return;
19218
+ removePrimaryOnlyTools(draft.tools);
19219
+ }
19220
+ function removePrimaryOnlyTools(tools) {
18843
19221
  for (const id of PRIMARY_ONLY_TOOLS)
18844
- delete draft.tools[id];
19222
+ delete tools[id];
19223
+ }
19224
+ function storedSubagentMode(db, sessionId) {
19225
+ const row = db.prepare("SELECT is_subagent FROM session_meta WHERE session_id = ?").get(sessionId);
19226
+ if (!row || typeof row.is_subagent !== "number")
19227
+ return;
19228
+ return row.is_subagent === 1;
18845
19229
  }
18846
19230
 
18847
19231
  // src/shared/conflict-detector.ts
@@ -19099,7 +19483,58 @@ function readOmoDisabledHooks(directory) {
19099
19483
 
19100
19484
  // src/shared/rpc-server.ts
19101
19485
  import { randomBytes, timingSafeEqual } from "node:crypto";
19102
- import { readdirSync, readFileSync as readFileSync6, unlinkSync } from "node:fs";
19486
+ import { readdirSync, readFileSync as readFileSync6, rmdirSync, unlinkSync } from "node:fs";
19487
+
19488
+ // src/shared/rpc-discovery-cleanup.ts
19489
+ import { promises as fs } from "node:fs";
19490
+ import { join as join4 } from "node:path";
19491
+ async function reapDeadRpcDiscovery(storageDir) {
19492
+ const root = join4(storageDir, "rpc");
19493
+ let directories;
19494
+ try {
19495
+ directories = await fs.readdir(root, { withFileTypes: true });
19496
+ } catch {
19497
+ return;
19498
+ }
19499
+ const records = [];
19500
+ const projectDirs = [];
19501
+ for (const entry of directories) {
19502
+ if (!entry.isDirectory() || !/^[0-9a-f]{16}$/.test(entry.name))
19503
+ continue;
19504
+ const directory = join4(root, entry.name);
19505
+ projectDirs.push(directory);
19506
+ try {
19507
+ for (const name of await fs.readdir(directory)) {
19508
+ const match = /^port-(\d+)(?:-[0-9a-f]+)?\.json$/.exec(name);
19509
+ if (!match)
19510
+ continue;
19511
+ const path = join4(directory, name);
19512
+ try {
19513
+ const content = await fs.readFile(path, "utf8");
19514
+ const record = parseRpcPortFile(content, Number(match[1]));
19515
+ if (record && record.pid === Number(match[1]))
19516
+ records.push({ path, content, pid: record.pid });
19517
+ } catch {}
19518
+ }
19519
+ } catch {}
19520
+ }
19521
+ const processes = records.length ? await inspectProcessesAsync(true) : undefined;
19522
+ for (const record of records) {
19523
+ if (processes?.liveness(record.pid) !== "dead")
19524
+ continue;
19525
+ try {
19526
+ if (await fs.readFile(record.path, "utf8") === record.content)
19527
+ await fs.unlink(record.path);
19528
+ } catch {}
19529
+ }
19530
+ for (const directory of projectDirs) {
19531
+ try {
19532
+ await fs.rmdir(directory);
19533
+ } catch {}
19534
+ }
19535
+ }
19536
+
19537
+ // src/shared/rpc-server.ts
19103
19538
  var MAX_BODY_BYTES = 1048576;
19104
19539
  var WS_AUTH_TIMEOUT_MS = 5000;
19105
19540
  var WS_CLOSE_UNAUTHORIZED = 4401;
@@ -19122,17 +19557,20 @@ function websocketToken(req) {
19122
19557
  }
19123
19558
 
19124
19559
  class MagicContextRpcServer {
19560
+ storageDir;
19125
19561
  server = null;
19126
19562
  port = 0;
19127
19563
  handlers = new Map;
19128
19564
  portFilePath;
19129
19565
  portDir;
19130
19566
  startedAt = Date.now();
19567
+ stopped = false;
19131
19568
  instanceId = randomBytes(8).toString("hex");
19132
19569
  unregisterOwnInstance = null;
19133
19570
  sockets = new Set;
19134
19571
  token = randomBytes(32).toString("hex");
19135
19572
  constructor(storageDir, directory) {
19573
+ this.storageDir = storageDir;
19136
19574
  this.portFilePath = rpcPortFilePath(storageDir, directory, process.pid, this.instanceId);
19137
19575
  this.portDir = rpcPortDir(storageDir, directory);
19138
19576
  }
@@ -19150,6 +19588,10 @@ class MagicContextRpcServer {
19150
19588
  log("rpc server skipped: Bun runtime not available (no TUI consumer)");
19151
19589
  return 0;
19152
19590
  }
19591
+ this.stopped = false;
19592
+ await reapDeadRpcDiscovery(this.storageDir);
19593
+ if (this.stopped)
19594
+ return 0;
19153
19595
  this.startedAt = Date.now();
19154
19596
  const self = this;
19155
19597
  const server = Bun.serve({
@@ -19181,7 +19623,7 @@ class MagicContextRpcServer {
19181
19623
  try {
19182
19624
  this.warnIfOtherLiveInstance();
19183
19625
  this.unregisterOwnInstance ??= registerOwnRpcServerInstance(this.instanceId);
19184
- writeStorageFileAtomicSync(this.portFilePath, JSON.stringify({
19626
+ const publish = () => writeStorageFileAtomicSync(this.portFilePath, JSON.stringify({
19185
19627
  port: this.port,
19186
19628
  pid: process.pid,
19187
19629
  started_at: this.startedAt,
@@ -19189,6 +19631,13 @@ class MagicContextRpcServer {
19189
19631
  token: this.token,
19190
19632
  instance_id: this.instanceId
19191
19633
  }));
19634
+ try {
19635
+ publish();
19636
+ } catch (error) {
19637
+ if (error.code !== "ENOENT")
19638
+ throw error;
19639
+ publish();
19640
+ }
19192
19641
  log(`[rpc] server listening on 127.0.0.1:${this.port}`);
19193
19642
  } catch (err) {
19194
19643
  log(`[rpc] failed to write port file: ${err}`);
@@ -19196,6 +19645,7 @@ class MagicContextRpcServer {
19196
19645
  return this.port;
19197
19646
  }
19198
19647
  stop() {
19648
+ this.stopped = true;
19199
19649
  for (const ws of this.sockets) {
19200
19650
  try {
19201
19651
  if (ws.data.authTimer)
@@ -19212,6 +19662,9 @@ class MagicContextRpcServer {
19212
19662
  try {
19213
19663
  unlinkSync(this.portFilePath);
19214
19664
  } catch {}
19665
+ try {
19666
+ rmdirSync(this.portDir);
19667
+ } catch {}
19215
19668
  this.unregisterOwnInstance?.();
19216
19669
  this.unregisterOwnInstance = null;
19217
19670
  }
@@ -19945,18 +20398,56 @@ function containsHostInstance(value) {
19945
20398
  return false;
19946
20399
  }
19947
20400
  function clonePreservingInstances(value) {
19948
- if (isHostInstance(value))
20401
+ return cloneCounting(value, undefined);
20402
+ }
20403
+ function clonePreservingInstancesMeasured(value) {
20404
+ const meter = { bytes: 0 };
20405
+ const copy = cloneCounting(value, meter);
20406
+ return { copy, bytes: meter.bytes };
20407
+ }
20408
+ function cloneCounting(value, meter) {
20409
+ if (isHostInstance(value)) {
20410
+ if (meter)
20411
+ meter.bytes += instanceBytes(value, new WeakSet);
19949
20412
  return value;
19950
- if (Array.isArray(value))
19951
- return value.map(clonePreservingInstances);
20413
+ }
20414
+ if (Array.isArray(value)) {
20415
+ if (meter)
20416
+ meter.bytes += 16 + 8 * value.length;
20417
+ return value.map((entry) => cloneCounting(entry, meter));
20418
+ }
19952
20419
  if (value && typeof value === "object") {
19953
20420
  const copy = {};
19954
- for (const [key, entry] of Object.entries(value))
19955
- copy[key] = clonePreservingInstances(entry);
20421
+ if (meter)
20422
+ meter.bytes += 32;
20423
+ for (const [key, entry] of Object.entries(value)) {
20424
+ if (meter)
20425
+ meter.bytes += 16;
20426
+ copy[key] = cloneCounting(entry, meter);
20427
+ }
19956
20428
  return copy;
19957
20429
  }
20430
+ if (meter)
20431
+ meter.bytes += typeof value === "string" ? 2 * value.length : 8;
19958
20432
  return value;
19959
20433
  }
20434
+ function instanceBytes(value, seen) {
20435
+ if (typeof value === "string")
20436
+ return 2 * value.length;
20437
+ if (!value || typeof value !== "object")
20438
+ return 8;
20439
+ if (seen.has(value))
20440
+ return 0;
20441
+ seen.add(value);
20442
+ if (ArrayBuffer.isView(value))
20443
+ return value.byteLength;
20444
+ if (value instanceof ArrayBuffer)
20445
+ return value.byteLength;
20446
+ let bytes = 32;
20447
+ for (const entry of Object.values(value))
20448
+ bytes += 16 + instanceBytes(entry, seen);
20449
+ return bytes;
20450
+ }
19960
20451
  function contentKey(value) {
19961
20452
  const plain = (entry) => {
19962
20453
  if (ArrayBuffer.isView(entry)) {
@@ -20012,7 +20503,7 @@ function rebuildFileContent(value, output, attachments) {
20012
20503
  rebuilt.unshift({ type: "text", text: output });
20013
20504
  return { type: "content", value: rebuilt };
20014
20505
  }
20015
- function adaptPayload(draft, admittedIDs = new Set) {
20506
+ function adaptPayload(draft, admittedIDs = new Set, messageTimes = new Map, hiddenTimes = false) {
20016
20507
  const existingHeads = new Map(draft.messages.filter((m) => HEAD_IDS.some((id) => m.id === id)).map((m) => [m.id, m]));
20017
20508
  const source = draft.messages.filter((m) => !existingHeads.has(m.id));
20018
20509
  const results = new Map;
@@ -20122,6 +20613,7 @@ function adaptPayload(draft, admittedIDs = new Set) {
20122
20613
  id: message.id,
20123
20614
  sessionID: draft.sessionID,
20124
20615
  role: message.role,
20616
+ time: message.id ? messageTimes.get(message.id) : undefined,
20125
20617
  ...{
20126
20618
  providerID: draft.model.providerID,
20127
20619
  modelID: draft.model.id,
@@ -20130,7 +20622,19 @@ function adaptPayload(draft, admittedIDs = new Set) {
20130
20622
  },
20131
20623
  parts
20132
20624
  };
20625
+ if (hiddenTimes && mapped.info.time !== undefined) {
20626
+ const time = mapped.info.time;
20627
+ delete mapped.info.time;
20628
+ Object.defineProperty(mapped.info, "time", {
20629
+ value: time,
20630
+ enumerable: false,
20631
+ configurable: true,
20632
+ writable: true
20633
+ });
20634
+ }
20133
20635
  originals.set(mapped, message);
20636
+ if (isCoveredInstructionRow(message))
20637
+ markCoveredInstructionRow(mapped.info);
20134
20638
  if (typeof message.id !== "string")
20135
20639
  bridgesByCarrier.set(mapped, byCallID);
20136
20640
  messages.push(mapped);
@@ -20487,24 +20991,31 @@ ${data.output?.output ?? ""}`
20487
20991
  const sameModel = sameProvider && previousModel?.id === model.id;
20488
20992
  const reuse = sameModel && data.error === undefined;
20489
20993
  const metadata = (state) => state === undefined ? undefined : { [model.providerID]: state };
20994
+ const reasoningInterrupted = data.content?.some((part) => part.type === "reasoning" && part.time !== undefined && part.time.completed === undefined);
20490
20995
  const content = [];
20491
20996
  const results = [];
20492
20997
  for (const part of data.content ?? []) {
20998
+ let native = "native" in part ? part.native : part.type === "tool" ? part.providerState : part.state;
20999
+ if (part.type === "tool" && part.providerResultState !== null && typeof part.providerResultState === "object" && !Array.isArray(part.providerResultState))
21000
+ native = {
21001
+ ...native !== null && typeof native === "object" && !Array.isArray(native) ? native : {},
21002
+ ...part.providerResultState
21003
+ };
20493
21004
  if (part.type === "text") {
20494
21005
  if (part.text !== "")
20495
21006
  content.push({
20496
21007
  type: "text",
20497
21008
  text: part.text,
20498
- providerMetadata: reuse ? metadata(part.state) : undefined
21009
+ providerMetadata: reuse ? metadata(native) : undefined
20499
21010
  });
20500
21011
  continue;
20501
21012
  }
20502
21013
  if (part.type === "reasoning") {
20503
- if (part.text !== "" || reuse && part.state !== undefined)
21014
+ if (part.text !== "" || reuse && !reasoningInterrupted && native !== undefined)
20504
21015
  content.push({
20505
- type: reuse || data.error === undefined ? "reasoning" : "text",
21016
+ type: data.error === undefined && !reasoningInterrupted ? "reasoning" : "text",
20506
21017
  text: part.text,
20507
- providerMetadata: reuse ? metadata(part.state) : undefined
21018
+ providerMetadata: reuse && !reasoningInterrupted ? metadata(native) : undefined
20508
21019
  });
20509
21020
  continue;
20510
21021
  }
@@ -20523,7 +21034,7 @@ ${data.output?.output ?? ""}`
20523
21034
  name: part.name,
20524
21035
  input,
20525
21036
  providerExecuted: part.executed,
20526
- providerMetadata: toolReuse ? metadata(part.providerState) : undefined
21037
+ providerMetadata: toolReuse ? metadata(native) : undefined
20527
21038
  });
20528
21039
  if (!completed)
20529
21040
  continue;
@@ -20534,7 +21045,7 @@ ${data.output?.output ?? ""}`
20534
21045
  id: part.id,
20535
21046
  name: part.name,
20536
21047
  providerExecuted: part.executed,
20537
- providerMetadata: toolReuse ? metadata(part.providerResultState ?? part.providerState) : sameProvider ? metadata(part.providerResultState) : undefined,
21048
+ providerMetadata: (part.executed === true ? sameProvider : reuse) ? metadata(native) : undefined,
20538
21049
  result: state.status === "error" ? { error: state.error, content: toolContent } : single?.type === "text" ? { type: "text", value: single.text } : { type: "content", value: toolContent },
20539
21050
  ...state.status === "error" ? { resultType: "error" } : {}
20540
21051
  };
@@ -20562,13 +21073,50 @@ function copyNativeInput(messages) {
20562
21073
  return copies;
20563
21074
  }
20564
21075
  function isLocalCheckpoint(row) {
20565
- return row.type === "compaction" && row.data.status === "completed" && row.data.providerContext === undefined;
21076
+ return row.type === "compaction" && row.data.status === "completed" && row.data.providerContext === undefined && row.data.native?.messages === undefined;
21077
+ }
21078
+ function isAdmittedLocalCheckpoint(storage, sessionID, cut) {
21079
+ if (!isLocalCheckpoint(cut) || cut.session_id !== sessionID)
21080
+ return false;
21081
+ const admission = storage.admission(sessionID, cut.id);
21082
+ if (!admission?.payload || admission.digest !== foldDigest(admission.payload))
21083
+ return false;
21084
+ try {
21085
+ const snapshot = JSON.parse(admission.payload);
21086
+ return snapshot.source === storage.sourceID && snapshot.sessionID === sessionID && snapshot.admissionID === cut.id && snapshot.summary === cut.data.summary;
21087
+ } catch {
21088
+ return false;
21089
+ }
20566
21090
  }
20567
21091
  var conversational = (row) => RAW_MESSAGE_TYPES.includes(row.type) || row.type === "location-switched";
21092
+ var historyDigest = (reader, sessionID, through) => foldDigest(JSON.stringify(reader.range(sessionID, -1, through).filter(conversational)));
21093
+ var admissionKey = (sessionID) => `native-fold/v2/${encodeURIComponent(sessionID)}`;
21094
+ async function forgetNativeFoldProvenance(storage, sessionID, legacyOnly = false) {
21095
+ const remove = async (key) => {
21096
+ if (storage.remove)
21097
+ await storage.remove(key);
21098
+ else
21099
+ await storage.set(key, null);
21100
+ };
21101
+ if (!legacyOnly)
21102
+ await remove(admissionKey(sessionID));
21103
+ if (!storage.scan)
21104
+ return;
21105
+ let after;
21106
+ do {
21107
+ const page = await storage.scan({ prefix: "native-fold/v1/", after, limit: 100 });
21108
+ for (const { key } of page.entries) {
21109
+ if (key.slice("native-fold/v1/".length).split("/").slice(1).join("/") === sessionID)
21110
+ await remove(key);
21111
+ }
21112
+ after = page.next;
21113
+ } while (after);
21114
+ }
20568
21115
 
20569
21116
  class NativeFoldReplay {
20570
21117
  storage;
20571
21118
  openReader;
21119
+ admissions;
20572
21120
  changed = new Set;
20573
21121
  dirty = new Set;
20574
21122
  unavailable = new Set;
@@ -20576,9 +21124,11 @@ class NativeFoldReplay {
20576
21124
  metadataThrough = new Map;
20577
21125
  loaded = new Map;
20578
21126
  sources = new Map;
20579
- constructor(storage, openReader) {
21127
+ staleHeads = new Set;
21128
+ constructor(storage, openReader, admissions) {
20580
21129
  this.storage = storage;
20581
21130
  this.openReader = openReader;
21131
+ this.admissions = admissions;
20582
21132
  storage.onEvict((sessionID) => this.clear(sessionID));
20583
21133
  }
20584
21134
  account(sessionID) {
@@ -20617,6 +21167,51 @@ class NativeFoldReplay {
20617
21167
  async baseline(sessionID) {
20618
21168
  return this.tail(sessionID)?.baseline;
20619
21169
  }
21170
+ admissionKey(sessionID) {
21171
+ return admissionKey(sessionID);
21172
+ }
21173
+ async removeAdmission(key) {
21174
+ if (this.admissions?.remove)
21175
+ await this.admissions.remove(key);
21176
+ else
21177
+ await this.admissions?.set(key, null);
21178
+ }
21179
+ async removeLegacyAdmissions(sessionID) {
21180
+ if (this.admissions)
21181
+ await forgetNativeFoldProvenance(this.admissions, sessionID, true);
21182
+ }
21183
+ async admits(sessionID, cut, reader) {
21184
+ if (!isLocalCheckpoint(cut) || cut.session_id !== sessionID)
21185
+ return false;
21186
+ if (isAdmittedLocalCheckpoint(this.storage, sessionID, cut))
21187
+ return true;
21188
+ if (!this.admissions)
21189
+ return false;
21190
+ try {
21191
+ const source = reader.hostIdentity();
21192
+ const saved = await this.admissions.get(this.admissionKey(sessionID));
21193
+ if (!saved?.payload || saved.digest !== foldDigest(saved.payload))
21194
+ return false;
21195
+ const snapshot = JSON.parse(saved.payload);
21196
+ if (snapshot.sourceDigest !== foldDigest(source) || snapshot.sessionID !== sessionID || snapshot.admissionID !== cut.id || snapshot.summaryDigest !== foldDigest(cut.data.summary ?? ""))
21197
+ return false;
21198
+ if (snapshot.historyDigest !== historyDigest(reader, sessionID, cut.seq - 1)) {
21199
+ this.staleHeads.add(sessionID);
21200
+ this.invalidate(sessionID);
21201
+ await this.removeAdmission(this.admissionKey(sessionID));
21202
+ return false;
21203
+ }
21204
+ await this.storage.supply(sessionID, cut.id, JSON.stringify({
21205
+ source: this.storage.sourceID,
21206
+ sessionID,
21207
+ admissionID: cut.id,
21208
+ summary: cut.data.summary
21209
+ }));
21210
+ return true;
21211
+ } catch {
21212
+ return false;
21213
+ }
21214
+ }
20620
21215
  rendered(row, model) {
20621
21216
  return restoreRow(row, model, hostUsesMediaAssets() ? {
20622
21217
  asset: hostMediaAsset,
@@ -20694,6 +21289,7 @@ class NativeFoldReplay {
20694
21289
  this.loaded.set(draft.sessionID, through);
20695
21290
  this.unavailable.delete(draft.sessionID);
20696
21291
  this.changed.delete(draft.sessionID);
21292
+ this.staleHeads.delete(draft.sessionID);
20697
21293
  } finally {
20698
21294
  reader.close();
20699
21295
  }
@@ -20720,7 +21316,8 @@ class NativeFoldReplay {
20720
21316
  async supplyHeld(args) {
20721
21317
  const { draft, reader, summary } = args;
20722
21318
  const tail = this.tail(draft.sessionID);
20723
- const id = reader.latestRunningCompaction(draft.sessionID)?.id;
21319
+ const running = reader.latestRunningCompaction(draft.sessionID);
21320
+ const id = running?.id;
20724
21321
  if (!id || !tail || tail.model !== `${draft.model.providerID}/${draft.model.id}`)
20725
21322
  return false;
20726
21323
  const through = reader.latestSequence(draft.sessionID);
@@ -20744,6 +21341,21 @@ class NativeFoldReplay {
20744
21341
  summary
20745
21342
  };
20746
21343
  await this.storage.supply(draft.sessionID, id, JSON.stringify(snapshot));
21344
+ if (this.admissions) {
21345
+ const provenance = {
21346
+ sourceDigest: foldDigest(reader.hostIdentity()),
21347
+ sessionID: draft.sessionID,
21348
+ admissionID: id,
21349
+ summaryDigest: foldDigest(summary),
21350
+ historyDigest: historyDigest(reader, draft.sessionID, (running?.seq ?? through) - 1)
21351
+ };
21352
+ const payload = JSON.stringify(provenance);
21353
+ await this.admissions.set(this.admissionKey(draft.sessionID), {
21354
+ payload,
21355
+ digest: foldDigest(payload)
21356
+ });
21357
+ await this.removeLegacyAdmissions(draft.sessionID);
21358
+ }
20747
21359
  return true;
20748
21360
  }
20749
21361
  async restore(sessionID, cut, model, options = {}) {
@@ -20828,6 +21440,9 @@ class NativeFoldReplay {
20828
21440
  sourceChanged(sessionID) {
20829
21441
  return this.changed.has(sessionID);
20830
21442
  }
21443
+ needsHeadRebuild(sessionID) {
21444
+ return this.staleHeads.has(sessionID);
21445
+ }
20831
21446
  clear(sessionID) {
20832
21447
  this.sources.delete(sessionID);
20833
21448
  this.metadata.delete(sessionID);
@@ -20836,8 +21451,11 @@ class NativeFoldReplay {
20836
21451
  this.unavailable.delete(sessionID);
20837
21452
  this.dirty.delete(sessionID);
20838
21453
  this.changed.delete(sessionID);
21454
+ this.staleHeads.delete(sessionID);
20839
21455
  }
20840
21456
  async forget(sessionID) {
21457
+ if (this.admissions)
21458
+ await forgetNativeFoldProvenance(this.admissions, sessionID);
20841
21459
  await this.storage.forget(sessionID);
20842
21460
  }
20843
21461
  }
@@ -20852,11 +21470,7 @@ class HostFoldPolicy {
20852
21470
  this.deps = deps;
20853
21471
  }
20854
21472
  owned(sessionID, cut, id) {
20855
- const row = this.deps.storage.admission(sessionID, id);
20856
- if (!isLocalCheckpoint(cut) || cut.id !== id || !row?.payload || row.digest !== foldDigest(row.payload))
20857
- return false;
20858
- const snapshot = JSON.parse(row.payload);
20859
- return snapshot.summary === cut.data.summary && snapshot.source === this.deps.storage.sourceID && snapshot.sessionID === sessionID && snapshot.admissionID === id;
21473
+ return cut.id === id && isAdmittedLocalCheckpoint(this.deps.storage, sessionID, cut);
20860
21474
  }
20861
21475
  async idle(sessionID) {
20862
21476
  const { storage, session, threshold } = this.deps;
@@ -22038,26 +22652,70 @@ function generateReplayAnchor(messages) {
22038
22652
  return;
22039
22653
  return { id, tail: clonePreservingInstances(messages.slice(index + 1)) };
22040
22654
  }
22655
+ var DEFAULT_GENERATE_REPLAY_LIMITS = Object.freeze({
22656
+ maxSessions: 16,
22657
+ sessionMaxBytes: 128 * 1024 * 1024,
22658
+ totalMaxBytes: 256 * 1024 * 1024
22659
+ });
22041
22660
 
22042
22661
  class V2GenerateReplay {
22043
22662
  prefixes = new Map;
22663
+ totalBytes = 0;
22664
+ limits;
22665
+ constructor(limits = DEFAULT_GENERATE_REPLAY_LIMITS) {
22666
+ if (!Number.isSafeInteger(limits.maxSessions) || limits.maxSessions < 1 || !Number.isSafeInteger(limits.sessionMaxBytes) || limits.sessionMaxBytes < 1 || !Number.isSafeInteger(limits.totalMaxBytes) || limits.totalMaxBytes < 1)
22667
+ throw new Error("Generate replay limits must be positive integers");
22668
+ this.limits = { ...limits };
22669
+ }
22044
22670
  capture(draft, anchor) {
22671
+ this.forget(draft.sessionID);
22045
22672
  if (!anchor) {
22046
- this.prefixes.delete(draft.sessionID);
22047
22673
  sessionLog(draft.sessionID, "generate replay capture skipped: no-anchor");
22048
22674
  return;
22049
22675
  }
22676
+ const parts = {
22677
+ anchor: clonePreservingInstancesMeasured(anchor),
22678
+ system: clonePreservingInstancesMeasured(draft.system),
22679
+ messages: clonePreservingInstancesMeasured(draft.messages),
22680
+ tools: clonePreservingInstancesMeasured(draft.tools)
22681
+ };
22682
+ const bytes = 256 + parts.anchor.bytes + parts.system.bytes + parts.messages.bytes + parts.tools.bytes;
22683
+ if (bytes > this.limits.sessionMaxBytes || bytes > this.limits.totalMaxBytes) {
22684
+ sessionLog(draft.sessionID, `generate replay capture skipped: over-session-cap (${bytes} > ${Math.min(this.limits.sessionMaxBytes, this.limits.totalMaxBytes)} bytes)`);
22685
+ return;
22686
+ }
22687
+ while (this.prefixes.size > 0 && (this.prefixes.size >= this.limits.maxSessions || this.totalBytes + bytes > this.limits.totalMaxBytes)) {
22688
+ const oldest = this.prefixes.keys().next().value;
22689
+ if (oldest === undefined)
22690
+ break;
22691
+ this.forget(oldest);
22692
+ }
22050
22693
  this.prefixes.set(draft.sessionID, {
22051
- anchor: clonePreservingInstances(anchor),
22694
+ anchor: parts.anchor.copy,
22052
22695
  model: `${draft.model.providerID}/${draft.model.id}`,
22053
22696
  agent: draft.agent,
22054
- system: clonePreservingInstances(draft.system),
22055
- messages: clonePreservingInstances(draft.messages),
22056
- tools: clonePreservingInstances(draft.tools)
22697
+ system: parts.system.copy,
22698
+ messages: parts.messages.copy,
22699
+ tools: parts.tools.copy,
22700
+ bytes
22057
22701
  });
22702
+ this.totalBytes += bytes;
22058
22703
  }
22059
22704
  forget(sessionID) {
22705
+ const prefix = this.prefixes.get(sessionID);
22706
+ if (!prefix)
22707
+ return;
22060
22708
  this.prefixes.delete(sessionID);
22709
+ this.totalBytes -= prefix.bytes;
22710
+ }
22711
+ stats() {
22712
+ return {
22713
+ totalBytes: this.totalBytes,
22714
+ sessions: [...this.prefixes].map(([sessionId, prefix]) => ({
22715
+ sessionId,
22716
+ bytes: prefix.bytes
22717
+ }))
22718
+ };
22061
22719
  }
22062
22720
  apply(draft) {
22063
22721
  const prefix = this.prefixes.get(draft.sessionID);
@@ -22067,6 +22725,8 @@ class V2GenerateReplay {
22067
22725
  };
22068
22726
  if (!prefix)
22069
22727
  return skip("no-prefix");
22728
+ this.prefixes.delete(draft.sessionID);
22729
+ this.prefixes.set(draft.sessionID, prefix);
22070
22730
  if (prefix.model !== `${draft.model.providerID}/${draft.model.id}`)
22071
22731
  return skip("model-mismatch");
22072
22732
  if (prefix.agent !== draft.agent)
@@ -22110,21 +22770,25 @@ function identity(slot) {
22110
22770
 
22111
22771
  class V2LkgSystemReplay {
22112
22772
  systems = new BoundedSessionMap(1000);
22113
- capture(sessionId, slot, input, served) {
22773
+ capture(sessionId, slot, input, served, head) {
22114
22774
  this.systems.set(sessionId, {
22115
22775
  slot: identity(slot),
22116
- input: JSON.stringify(input),
22117
- served: structuredClone(served)
22776
+ input: hostInputKey(input),
22777
+ served: structuredClone(served),
22778
+ head: head ? structuredClone(head) : null
22118
22779
  });
22119
22780
  }
22120
22781
  restore(sessionId, slot, input, target) {
22121
22782
  const saved = this.systems.get(sessionId);
22122
- if (!slot || !saved || saved.slot !== identity(slot) || saved.input !== JSON.stringify(input))
22123
- return false;
22783
+ if (!slot || !saved || saved.slot !== identity(slot) || saved.input !== hostInputKey(input))
22784
+ return;
22124
22785
  target.splice(0, target.length, ...structuredClone(saved.served));
22125
- return true;
22786
+ return { head: saved.head ? structuredClone(saved.head) : null };
22126
22787
  }
22127
22788
  }
22789
+ function hostInputKey(input) {
22790
+ return JSON.stringify({ system: input.system, checkpoint: input.checkpoint });
22791
+ }
22128
22792
 
22129
22793
  // src/v2/hooks/model-limit-cache.ts
22130
22794
  var warmStarted = false;
@@ -22785,6 +23449,22 @@ function* readV2RawMessagePagesForConversion(openReader, sessionID, pageRows = C
22785
23449
  function createV2RawMessageReader(openReader) {
22786
23450
  const servedBoundaryCache = new Map;
22787
23451
  return {
23452
+ getRevision: (sessionID) => {
23453
+ const reader = openReader();
23454
+ try {
23455
+ return reader.latestSequence(sessionID);
23456
+ } finally {
23457
+ reader.close();
23458
+ }
23459
+ },
23460
+ getCountAfterRevision: (sessionID, after, through) => {
23461
+ const reader = openReader();
23462
+ try {
23463
+ return reader.messageCountAfterSequence(sessionID, after, through);
23464
+ } finally {
23465
+ reader.close();
23466
+ }
23467
+ },
22788
23468
  readPage: (sessionID, afterOrdinal, limit, finalWatermark, after) => {
22789
23469
  const reader = openReader();
22790
23470
  try {
@@ -24252,7 +24932,7 @@ function createCtxReduceTool(deps) {
24252
24932
  args = unwrapImitatedReducedArgs(args, ["drop"], { drop: "string" });
24253
24933
  const sessionId = toolContext.sessionID;
24254
24934
  if (!args.drop) {
24255
- return "Error: 'drop' must be provided.";
24935
+ return `Error: 'drop' must be provided as a string of tag numbers, for example {"drop": "3-5,8"}.`;
24256
24936
  }
24257
24937
  let dropIds = [];
24258
24938
  try {
@@ -24634,6 +25314,26 @@ function persistV2UsageReading(args) {
24634
25314
  }
24635
25315
 
24636
25316
  // src/v2/hooks/context.ts
25317
+ function applyCheckpointHead(draft, head) {
25318
+ const { checkpoint, submitted } = head;
25319
+ const first = draft.messages.find((message) => message.id === HEAD_IDS[0]);
25320
+ const baseline = first?.content.find((part) => part.type === "text")?.text;
25321
+ if (typeof baseline !== "string")
25322
+ return false;
25323
+ for (const part of checkpoint.content)
25324
+ if (part.type === "text" && typeof part.text === "string") {
25325
+ part.text = part.text.replace(`<summary>
25326
+ ${submitted}
25327
+ </summary>`, `<summary>
25328
+ ${baseline}
25329
+ </summary>`);
25330
+ }
25331
+ const volatile = draft.messages.find((message) => message.id === HEAD_IDS[1]);
25332
+ if (volatile && first)
25333
+ volatile.content.push(...first.content.filter((part) => part.type !== "text"));
25334
+ draft.messages.splice(0, draft.messages.length, checkpoint, ...draft.messages.filter((message) => message !== first));
25335
+ return true;
25336
+ }
24637
25337
  var HIDDEN_SESSION_ERROR_GRACE_MS = 50;
24638
25338
  var STORE_POOL_DISPOSE_WAIT_MS = 1000;
24639
25339
 
@@ -24857,11 +25557,12 @@ async function registerContext(context) {
24857
25557
  }
24858
25558
  const folds = new FoldOwner(context.storage);
24859
25559
  const nativeFoldMemory = !compactionOff && process.env.MMC_OC2_INVISIBLE_FOLD === "1" ? nativeFoldCache(() => storage.require()) : undefined;
24860
- const nativeFoldReplay = nativeFoldMemory ? new NativeFoldReplay(nativeFoldMemory, () => openStoreReader()) : undefined;
25560
+ const nativeFoldReplay = nativeFoldMemory ? new NativeFoldReplay(nativeFoldMemory, () => openStoreReader(), context.storage) : undefined;
24861
25561
  setOutputReserveConfig(config.output_reserve);
24862
25562
  const queriedModels = new Set;
24863
25563
  const rawLimits = new Map;
24864
25564
  const hiddenSessionErrors = new Map;
25565
+ const committedSourceRefreshes = new Map;
24865
25566
  const liveModels = new Map;
24866
25567
  const promptSurfaceRuntime = createPromptSurfaceRuntime({
24867
25568
  harness: "opencode2",
@@ -25061,11 +25762,17 @@ async function registerContext(context) {
25061
25762
  }
25062
25763
  });
25063
25764
  const pagedRead = createV2RawMessageReader(openStoreReader);
25765
+ let orphanSweep;
25766
+ let orphanSweepTimer;
25064
25767
  const prepareHistorySession = (sessionID) => {
25065
25768
  if (!rawProviders.has(sessionID))
25066
25769
  rawProviders.set(sessionID, setBoundedRawMessageProvider2(sessionID, createV2RawMessageProvider(pagedRead, sessionID)));
25067
25770
  };
25068
25771
  if (db && isDatabasePersisted(db)) {
25772
+ const sweepDb = db;
25773
+ orphanSweepTimer = scheduleAfterBootQuiet(() => {
25774
+ orphanSweep = sweepOrphanedOpenCodeMessageIndexesCooperatively(sweepDb, () => new Database(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"), { readonly: true, fileMustExist: true })).catch((error) => log("[magic-context] v2 orphan sweep failed:", error));
25775
+ });
25069
25776
  const backfillDb = db;
25070
25777
  scheduleAfterBootQuiet(() => {
25071
25778
  runV2SessionProjectBackfill(backfillDb, openStoreReader, config.allow_home_project).catch((error) => log("[session-project-backfill] OpenCode 2 backfill failed:", error));
@@ -25184,88 +25891,122 @@ async function registerContext(context) {
25184
25891
  }) : undefined;
25185
25892
  const usageController = new AbortController;
25186
25893
  const usageDone = (async () => {
25187
- try {
25188
- for await (const value of context.event.subscribe({ signal: usageController.signal })) {
25189
- if (usageController.signal.aborted)
25190
- break;
25191
- const event = value;
25192
- if (!event.data?.sessionID)
25193
- continue;
25194
- const sessionID = event.data.sessionID;
25195
- if (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated") {
25196
- nativeFoldReplay?.onEvent(event);
25197
- restoredRows.forget(sessionID);
25198
- }
25199
- if (event.type?.startsWith("session.revert.") && db) {
25200
- const database = db;
25201
- withoutSqliteTransformPass(() => scheduleClearAndReindex(database, sessionID, pagedRead));
25202
- }
25203
- if (event.type === "session.error" || event.type === "session.execution.failed") {
25204
- const error = hiddenTerminalError(event);
25205
- if (error !== undefined)
25206
- hiddenSessionErrors.set(sessionID, error);
25207
- if (error !== undefined && db && !compactionOff) {
25894
+ let retry = 0;
25895
+ while (!usageController.signal.aborted) {
25896
+ const subscribedAt = Date.now();
25897
+ try {
25898
+ for await (const value of context.event.subscribe({
25899
+ signal: usageController.signal
25900
+ })) {
25901
+ if (usageController.signal.aborted)
25902
+ break;
25903
+ const event = value;
25904
+ try {
25905
+ if (event.type === "provider.updated" || event.type === "model.updated") {
25906
+ queriedModels.clear();
25907
+ continue;
25908
+ }
25909
+ if (!event.data?.sessionID)
25910
+ continue;
25911
+ const sessionID = event.data.sessionID;
25912
+ if (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated") {
25913
+ nativeFoldReplay?.onEvent(event);
25914
+ restoredRows.forget(sessionID);
25915
+ }
25916
+ if (event.type === "session.revert.committed") {
25917
+ committedSourceRefreshes.set(sessionID, {});
25918
+ const database = db;
25919
+ if (database)
25920
+ withoutSqliteTransformPass(() => scheduleClearAndReindex(database, sessionID, pagedRead));
25921
+ }
25922
+ if (event.type === "session.error" || event.type === "session.execution.failed") {
25923
+ const error = hiddenTerminalError(event);
25924
+ if (error !== undefined)
25925
+ hiddenSessionErrors.set(sessionID, error);
25926
+ if (error !== undefined && db && !compactionOff) {
25927
+ const model = liveModels.get(sessionID);
25928
+ try {
25929
+ armLatestThinkingRecoveryFromError({
25930
+ db,
25931
+ sessionId: sessionID,
25932
+ error,
25933
+ providerID: model?.providerID,
25934
+ modelID: model?.modelID
25935
+ });
25936
+ } catch (armError) {
25937
+ log("[magic-context] v2 latest-thinking recovery arm failed", armError);
25938
+ }
25939
+ }
25940
+ continue;
25941
+ }
25942
+ if (event.type === "session.deleted") {
25943
+ committedSourceRefreshes.delete(sessionID);
25944
+ clearLkgMeasuredRequest(sessionID);
25945
+ deletedSessions.add(sessionID);
25946
+ transform?.clearSessionLogState(sessionID);
25947
+ if (db) {
25948
+ markSessionCleanupPending(db, sessionID);
25949
+ clearSession(db, sessionID, false, true);
25950
+ }
25951
+ rawProviders.get(sessionID)?.();
25952
+ rawProviders.delete(sessionID);
25953
+ usage.delete(sessionID);
25954
+ hiddenSessionErrors.delete(sessionID);
25955
+ storageNoticeBySession.delete(sessionID);
25956
+ liveModels.delete(sessionID);
25957
+ variants.delete(sessionID);
25958
+ agents.delete(sessionID);
25959
+ channel1.delete(sessionID);
25960
+ historyRefreshSessions.delete(sessionID);
25961
+ clearPendingMaterialization(pendingMaterializationSessions, sessionID);
25962
+ lastHeuristicsTurnId.delete(sessionID);
25963
+ restoredRows.forget(sessionID);
25964
+ if (nativeFoldReplay)
25965
+ await nativeFoldReplay.forget(sessionID);
25966
+ else
25967
+ await forgetNativeFoldProvenance(context.storage, sessionID);
25968
+ generateReplay.forget(sessionID);
25969
+ systemPromptRefreshSessions.delete(sessionID);
25970
+ systemPrompt?.clearSession(sessionID);
25971
+ clearMaintenanceSystemSnapshot(sessionID);
25972
+ tagger.cleanup(sessionID);
25973
+ sessionDirectories.delete(sessionID);
25974
+ forkSeedSettled.delete(sessionID);
25975
+ continue;
25976
+ }
25977
+ if (event.type !== "session.execution.succeeded")
25978
+ continue;
25208
25979
  const model = liveModels.get(sessionID);
25209
- try {
25210
- armLatestThinkingRecoveryFromError({
25211
- db,
25212
- sessionId: sessionID,
25213
- error,
25214
- providerID: model?.providerID,
25215
- modelID: model?.modelID
25980
+ if (model) {
25981
+ await recordUsage({
25982
+ sessionID,
25983
+ model: { providerID: model.providerID, id: model.modelID }
25216
25984
  });
25217
- } catch (armError) {
25218
- log("[magic-context] v2 latest-thinking recovery arm failed", armError);
25985
+ if (!compactionOff && typeof await nativeFoldReplay?.baseline(sessionID) === "string")
25986
+ hostFolds?.idle(sessionID);
25219
25987
  }
25988
+ } catch (error) {
25989
+ log(`[magic-context] v2 event handler failed (type=${event.type ?? "unknown"}, session=${event.data?.sessionID ?? "none"})`, error);
25220
25990
  }
25221
- continue;
25222
- }
25223
- if (event.type === "session.deleted") {
25224
- clearLkgMeasuredRequest(sessionID);
25225
- deletedSessions.add(sessionID);
25226
- transform?.clearSessionLogState(sessionID);
25227
- if (db) {
25228
- markSessionCleanupPending(db, sessionID);
25229
- clearSession(db, sessionID);
25230
- }
25231
- rawProviders.get(sessionID)?.();
25232
- rawProviders.delete(sessionID);
25233
- usage.delete(sessionID);
25234
- hiddenSessionErrors.delete(sessionID);
25235
- storageNoticeBySession.delete(sessionID);
25236
- liveModels.delete(sessionID);
25237
- variants.delete(sessionID);
25238
- agents.delete(sessionID);
25239
- channel1.delete(sessionID);
25240
- historyRefreshSessions.delete(sessionID);
25241
- clearPendingMaterialization(pendingMaterializationSessions, sessionID);
25242
- lastHeuristicsTurnId.delete(sessionID);
25243
- restoredRows.forget(sessionID);
25244
- await nativeFoldReplay?.forget(sessionID);
25245
- generateReplay.forget(sessionID);
25246
- systemPromptRefreshSessions.delete(sessionID);
25247
- systemPrompt?.clearSession(sessionID);
25248
- clearMaintenanceSystemSnapshot(sessionID);
25249
- tagger.cleanup(sessionID);
25250
- sessionDirectories.delete(sessionID);
25251
- forkSeedSettled.delete(sessionID);
25252
- continue;
25253
- }
25254
- if (event.type !== "session.execution.succeeded")
25255
- continue;
25256
- const model = liveModels.get(sessionID);
25257
- if (model) {
25258
- await recordUsage({
25259
- sessionID,
25260
- model: { providerID: model.providerID, id: model.modelID }
25261
- });
25262
- if (!compactionOff && typeof await nativeFoldReplay?.baseline(sessionID) === "string")
25263
- hostFolds?.idle(sessionID);
25264
25991
  }
25992
+ } catch (error) {
25993
+ if (!usageController.signal.aborted)
25994
+ log("[magic-context] v2 usage subscription failed", error);
25995
+ }
25996
+ if (usageController.signal.aborted)
25997
+ break;
25998
+ if (Date.now() - subscribedAt >= 30000)
25999
+ retry = 0;
26000
+ const ceiling = Math.min(30000, 250 * 2 ** retry);
26001
+ retry = Math.min(retry + 1, 7);
26002
+ try {
26003
+ await delay(ceiling * (0.5 + Math.random() * 0.5), undefined, {
26004
+ signal: usageController.signal
26005
+ });
26006
+ } catch (error) {
26007
+ if (!usageController.signal.aborted)
26008
+ throw error;
25265
26009
  }
25266
- } catch (error) {
25267
- if (!usageController.signal.aborted)
25268
- log("[magic-context] v2 usage subscription failed", error);
25269
26010
  }
25270
26011
  })();
25271
26012
  const materialize = (draft) => {
@@ -25338,20 +26079,57 @@ async function registerContext(context) {
25338
26079
  reader.close();
25339
26080
  }
25340
26081
  });
26082
+ const restoreAfterCheckpoint = (args) => {
26083
+ const { db, reader, draft, cut, boundaryRepair } = args;
26084
+ const boundaryID = db.prepare("SELECT cached_m0_last_baseline_end_message_id AS id FROM session_meta WHERE session_id = ?").get(draft.sessionID)?.id ?? (boundaryRepair?.kind === "repaired" || boundaryRepair?.kind === "baseline-reset" ? boundaryRepair.anchorEndMessageId : null);
26085
+ const servedBoundary = boundaryID ? servedBoundaryRow(reader, draft.sessionID, boundaryID) : null;
26086
+ const boundary = servedBoundary?.seq ?? reader.sequenceForId(draft.sessionID, boundaryID) ?? (reader.earliestSequence(draft.sessionID) ?? 0) - 1;
26087
+ const present = new Set(args.messages.map((message) => message.id));
26088
+ const restored = restoredRows.rows(reader, draft.sessionID, boundary, cut.seq).filter((row) => !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model, hostUsesMediaAssets() ? {
26089
+ asset: hostMediaAsset,
26090
+ unavailable: (detail) => sessionLog(draft.sessionID, `v2 restore: attachment replaced by a note row=${detail.rowID} name=${JSON.stringify(detail.name ?? null)} mediaType=${detail.mediaType} reason=${JSON.stringify(detail.reason)}`)
26091
+ } : undefined));
26092
+ const covered = reader.instructionRowsThrough(draft.sessionID, Math.min(boundary, cut.seq)).flatMap((row) => restoreRow(row, draft.model)).map((message) => markCoveredInstructionRow(message));
26093
+ return [
26094
+ ...covered,
26095
+ ...restored,
26096
+ ...args.messages.filter((message) => message !== args.incoming)
26097
+ ];
26098
+ };
26099
+ const temporalTimes = config.temporal_awareness === true;
26100
+ const anchorTimesOnly = !temporalTimes;
26101
+ const timeIds = (messages) => {
26102
+ if (temporalTimes)
26103
+ return messages.flatMap((message) => message.id ? [message.id] : []);
26104
+ const ids = [];
26105
+ for (const message of [...messages].reverse()) {
26106
+ if (message.id)
26107
+ ids.push(message.id);
26108
+ if (message.role === "assistant")
26109
+ break;
26110
+ }
26111
+ return ids;
26112
+ };
25341
26113
  const runManagedContext = async (draft) => {
25342
26114
  rememberHostMedia(draft.messages);
25343
26115
  if (hiddenChildHook.apply(draft))
25344
26116
  return;
25345
26117
  if (deletedSessions.has(draft.sessionID))
25346
26118
  return;
25347
- const systemAtEntry = structuredClone(draft.system);
26119
+ let systemAtEntry = structuredClone(draft.system);
25348
26120
  const slotAtEntry = getSlot(draft.sessionID);
26121
+ let checkpointAtEntry;
26122
+ let replayHead;
26123
+ const hostInput = () => checkpointAtEntry === undefined ? undefined : { system: systemAtEntry, checkpoint: checkpointAtEntry };
25349
26124
  const restoreLkgSystem = () => {
25350
26125
  retirePendingSystemPromptDelivery(draft.sessionID);
25351
- if (!lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), systemAtEntry, draft.system)) {
26126
+ const input = hostInput();
26127
+ const restored = input && lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), input, draft.system);
26128
+ if (!restored) {
25352
26129
  sessionLog(draft.sessionID, "lkg_system_state_mismatch");
25353
26130
  throw new Error("LKG system identity is unavailable or changed");
25354
26131
  }
26132
+ replayHead = restored.head;
25355
26133
  };
25356
26134
  const isMagicContextSynthetic = (id) => isAdmittedSynthetic(context, draft.sessionID, id);
25357
26135
  const newest = draft.messages.at(-1);
@@ -25360,6 +26138,24 @@ async function registerContext(context) {
25360
26138
  return;
25361
26139
  }
25362
26140
  await dropStorageNotices(draft.messages, isMagicContextSynthetic);
26141
+ let hostMessagesAtEntry = [...draft.messages];
26142
+ const passTimes = new Map;
26143
+ const readTimes = (reader, messages) => {
26144
+ const ids = timeIds(messages);
26145
+ const missing = ids.filter((id) => !passTimes.has(id));
26146
+ if (missing.length) {
26147
+ const read = reader.messageTimes(draft.sessionID, missing);
26148
+ for (const id of missing)
26149
+ passTimes.set(id, read.get(id) ?? null);
26150
+ }
26151
+ const times = new Map;
26152
+ for (const id of ids) {
26153
+ const time = passTimes.get(id);
26154
+ if (time)
26155
+ times.set(id, time);
26156
+ }
26157
+ return times;
26158
+ };
25363
26159
  liveModels.set(draft.sessionID, {
25364
26160
  providerID: draft.model.providerID,
25365
26161
  modelID: draft.model.id
@@ -25371,8 +26167,9 @@ async function registerContext(context) {
25371
26167
  applyV2PromptSurfaceTools(draft, promptSurfaceRuntime, config.prompt_surface);
25372
26168
  const admissionDb = db ?? storage.current();
25373
26169
  const replayFits = (messages) => {
25374
- const system = structuredClone(draft.system);
25375
- if (!admissionDb || !draft.tools || !lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), draft.system, system))
26170
+ const system = [];
26171
+ const input = hostInput();
26172
+ if (!admissionDb || !draft.tools || !input || !lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), input, system))
25376
26173
  return false;
25377
26174
  const limit = lkgReplayLimit({
25378
26175
  db: admissionDb,
@@ -25407,15 +26204,75 @@ async function registerContext(context) {
25407
26204
  })
25408
26205
  }).fit === "under";
25409
26206
  };
26207
+ const buildReplayInput = async () => {
26208
+ let messages = [...hostMessagesAtEntry];
26209
+ const admitted = new Set;
26210
+ let times;
26211
+ try {
26212
+ const reader = openStoreReader();
26213
+ try {
26214
+ const cut = reader.latestCompaction(draft.sessionID);
26215
+ const localCut = cut && isLocalCheckpoint(cut) ? cut : undefined;
26216
+ const incoming = localCut && messages.find((message) => message.id === localCut.id);
26217
+ if (localCut && !incoming || cut && nativeFoldReplay)
26218
+ return;
26219
+ checkpointAtEntry = incoming || null;
26220
+ const modeDb = db ?? storage.current();
26221
+ const subagent = modeDb ? storedSubagentMode(modeDb, draft.sessionID) : undefined;
26222
+ if (subagent === undefined)
26223
+ return;
26224
+ if (subagent)
26225
+ removePrimaryOnlyTools(draft.tools);
26226
+ const candidates = syntheticCandidates(context, draft.sessionID, reader.syntheticMessageIDs(draft.sessionID));
26227
+ for (const message of messages)
26228
+ if (message.id && candidates.has(message.id) && await isAdmittedSynthetic(context, draft.sessionID, message.id))
26229
+ admitted.add(message.id);
26230
+ const replayDb = db ?? storage.current();
26231
+ if (localCut && incoming && replayDb)
26232
+ messages = restoreAfterCheckpoint({
26233
+ db: replayDb,
26234
+ reader,
26235
+ draft,
26236
+ messages,
26237
+ cut: localCut,
26238
+ incoming,
26239
+ boundaryRepair: undefined
26240
+ });
26241
+ else if (localCut)
26242
+ return;
26243
+ times = readTimes(reader, messages);
26244
+ } finally {
26245
+ reader.close();
26246
+ }
26247
+ } catch (error) {
26248
+ sessionLog(draft.sessionID, "lkg replay input unavailable", error);
26249
+ return;
26250
+ }
26251
+ const replayDraft = { ...draft, messages };
26252
+ return {
26253
+ draft: replayDraft,
26254
+ mapped: adaptPayload(replayDraft, admitted, times, anchorTimesOnly)
26255
+ };
26256
+ };
26257
+ const adoptReplay = (replayed) => {
26258
+ draft.messages.splice(0, draft.messages.length, ...replayed.messages);
26259
+ if (replayHead)
26260
+ applyCheckpointHead(draft, replayHead);
26261
+ };
25410
26262
  let postFold = false;
25411
26263
  try {
25412
26264
  if (!compactionOff && admissionDb)
25413
26265
  await withAsyncPrivilegedWriter(admissionDb, () => {
25414
26266
  return;
25415
26267
  }, {
25416
- beforeRetry: (_error) => {
26268
+ beforeRetry: async (_error) => {
26269
+ hostMessagesAtEntry = [...draft.messages];
26270
+ systemAtEntry = structuredClone(draft.system);
25417
26271
  let replayBlocked = false;
25418
- const mapped = adaptPayload(draft);
26272
+ const input = await buildReplayInput();
26273
+ if (!input)
26274
+ return;
26275
+ const { mapped } = input;
25419
26276
  try {
25420
26277
  const overflowDb = db;
25421
26278
  if (overflowDb !== undefined && overflowDb !== null && (isEmergencyRecoveryArmed(draft.sessionID) || getOverflowState(overflowDb, draft.sessionID).needsEmergencyRecovery)) {
@@ -25436,6 +26293,7 @@ async function registerContext(context) {
25436
26293
  restoreLkgSystem();
25437
26294
  mapped.messages.splice(0, mapped.messages.length, ...replay.messages);
25438
26295
  mapped.commit();
26296
+ adoptReplay(input.draft);
25439
26297
  sessionLog(draft.sessionID, "lkg_replay_served");
25440
26298
  throw new V2LkgAdmissionReplay;
25441
26299
  } else {
@@ -25452,6 +26310,8 @@ async function registerContext(context) {
25452
26310
  sessionLog(draft.sessionID, "lkg_replay_declined");
25453
26311
  }
25454
26312
  });
26313
+ hostMessagesAtEntry = [...draft.messages];
26314
+ systemAtEntry = structuredClone(draft.system);
25455
26315
  if (admissionDb)
25456
26316
  hideSubagentTools(draft, admissionDb);
25457
26317
  recordV2ToolDefinitions(draft);
@@ -25555,7 +26415,11 @@ async function registerContext(context) {
25555
26415
  contextUsageMap: usage,
25556
26416
  compactionOff,
25557
26417
  storeGeneration: "v2",
25558
- normalizeRestoredAssistantText: stripCopiedTagNotation,
26418
+ normalizeRestoredAssistantText: (text, providerID) => {
26419
+ const normalized = stripCopiedTagNotation(text);
26420
+ return normalized === "" && !modelAcceptsEmptyContent(providerID) ? text : normalized;
26421
+ },
26422
+ refreshSourceContents: (sessionID) => committedSourceRefreshes.has(sessionID),
25559
26423
  hostCleanupCompactionMarkers: () => ({
25560
26424
  verified: true,
25561
26425
  removedLineages: 0,
@@ -25600,8 +26464,14 @@ async function registerContext(context) {
25600
26464
  },
25601
26465
  ...createHostSeams(context, readAllForConversion, pagedRead, liveModels)
25602
26466
  });
26467
+ const refreshToken = committedSourceRefreshes.get(draft.sessionID);
26468
+ if (refreshToken) {
26469
+ clearCachedM0(db, draft.sessionID);
26470
+ restoredRows.forget(draft.sessionID);
26471
+ }
25603
26472
  const admitted = new Set;
25604
26473
  const reader = openStoreReader();
26474
+ let messageTimes;
25605
26475
  let checkpoint;
25606
26476
  let submitted;
25607
26477
  try {
@@ -25616,12 +26486,14 @@ async function registerContext(context) {
25616
26486
  historyRefreshSessions.add(draft.sessionID);
25617
26487
  requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "boundary_repair");
25618
26488
  }
25619
- const incoming = cut && draft.messages.find((message) => message.id === cut.id);
26489
+ const localCut = cut && isLocalCheckpoint(cut) ? cut : undefined;
26490
+ const incoming = localCut && draft.messages.find((message) => message.id === localCut.id);
25620
26491
  postFold = cut !== undefined;
25621
- if (cut && !incoming)
26492
+ checkpointAtEntry = incoming || null;
26493
+ if (localCut && !incoming)
25622
26494
  throw new Error("The host checkpoint disappeared from the context draft");
25623
26495
  let nativeRestored;
25624
- if (cut && nativeFoldReplay && isLocalCheckpoint(cut)) {
26496
+ if (cut && nativeFoldReplay && await nativeFoldReplay.admits(draft.sessionID, cut, reader)) {
25625
26497
  try {
25626
26498
  nativeRestored = await nativeFoldReplay.restore(draft.sessionID, cut, `${draft.model.providerID}/${draft.model.id}`, { bounded: true });
25627
26499
  } catch (error) {
@@ -25630,7 +26502,7 @@ async function registerContext(context) {
25630
26502
  nativeRestored = await nativeFoldReplay.restoreRead(draft.sessionID, cut, draft.model);
25631
26503
  }
25632
26504
  }
25633
- if (nativeRestored && nativeFoldReplay?.sourceChanged(draft.sessionID)) {
26505
+ if (cut && nativeFoldReplay?.sourceChanged(draft.sessionID)) {
25634
26506
  historyRefreshSessions.add(draft.sessionID);
25635
26507
  requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "host_history_change");
25636
26508
  }
@@ -25641,30 +26513,33 @@ async function registerContext(context) {
25641
26513
  return !id || !present.has(id);
25642
26514
  });
25643
26515
  draft.messages.splice(0, draft.messages.length, ...hidden, ...draft.messages.filter((message) => message !== incoming));
25644
- } else if (cut && incoming) {
25645
- const identity = await folds.observe({
25646
- sessionID: draft.sessionID,
25647
- cutSeq: cut.seq,
25648
- summary: cut.data.summary ?? "",
25649
- rendered: incoming,
25650
- onHard: (reason) => {
25651
- log(`[magic-context] HARD reason=${reason} session=${draft.sessionID}`);
25652
- materialize(draft);
25653
- requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "host_compaction");
25654
- }
25655
- });
25656
- checkpoint = structuredClone(identity.rendered ?? incoming);
25657
- submitted = identity.rendered ? identity.renderedSummary ?? identity.submitted : cut.data.summary ?? "";
25658
- const boundaryID = db.prepare("SELECT cached_m0_last_baseline_end_message_id AS id FROM session_meta WHERE session_id = ?").get(draft.sessionID)?.id ?? (boundaryRepair?.kind === "repaired" || boundaryRepair?.kind === "baseline-reset" ? boundaryRepair.anchorEndMessageId : null);
25659
- const servedBoundary = boundaryID ? servedBoundaryRow(reader, draft.sessionID, boundaryID) : null;
25660
- const boundary = servedBoundary?.seq ?? reader.sequenceForId(draft.sessionID, boundaryID) ?? (reader.earliestSequence(draft.sessionID) ?? 0) - 1;
25661
- const present = new Set(draft.messages.map((message) => message.id));
25662
- const restored = restoredRows.rows(reader, draft.sessionID, boundary, cut.seq).filter((row) => !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model, hostUsesMediaAssets() ? {
25663
- asset: hostMediaAsset,
25664
- unavailable: (detail) => sessionLog(draft.sessionID, `v2 restore: attachment replaced by a note row=${detail.rowID} name=${JSON.stringify(detail.name ?? null)} mediaType=${detail.mediaType} reason=${JSON.stringify(detail.reason)}`)
25665
- } : undefined));
25666
- draft.messages.splice(0, draft.messages.length, ...restored, ...draft.messages.filter((message) => message !== incoming));
26516
+ } else if (localCut && cut && incoming) {
26517
+ if (!nativeFoldReplay) {
26518
+ const identity = await folds.observe({
26519
+ sessionID: draft.sessionID,
26520
+ cutSeq: cut.seq,
26521
+ summary: cut.data.summary ?? "",
26522
+ rendered: incoming,
26523
+ onHard: (reason) => {
26524
+ log(`[magic-context] HARD reason=${reason} session=${draft.sessionID}`);
26525
+ materialize(draft);
26526
+ requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "host_compaction");
26527
+ }
26528
+ });
26529
+ checkpoint = structuredClone(identity.rendered ?? incoming);
26530
+ submitted = identity.rendered ? identity.renderedSummary ?? identity.submitted : cut.data.summary ?? "";
26531
+ }
26532
+ draft.messages.splice(0, draft.messages.length, ...restoreAfterCheckpoint({
26533
+ db,
26534
+ reader,
26535
+ draft,
26536
+ messages: draft.messages,
26537
+ cut: localCut,
26538
+ incoming,
26539
+ boundaryRepair
26540
+ }));
25667
26541
  }
26542
+ messageTimes = readTimes(reader, draft.messages);
25668
26543
  } finally {
25669
26544
  reader.close();
25670
26545
  }
@@ -25676,31 +26551,18 @@ async function registerContext(context) {
25676
26551
  nativeFoldReplay.invalidate(draft.sessionID, true);
25677
26552
  }
25678
26553
  }
25679
- const mapped = adaptPayload(draft, admitted);
26554
+ const mapped = adaptPayload(draft, admitted, messageTimes, anchorTimesOnly);
25680
26555
  bindSystemDateRequestIdentity(mapped, draft);
25681
26556
  await transform({}, mapped);
25682
26557
  mapped.commit();
26558
+ if (refreshToken && committedSourceRefreshes.get(draft.sessionID) === refreshToken)
26559
+ committedSourceRefreshes.delete(draft.sessionID);
25683
26560
  if (db) {
25684
26561
  await deliverPendingChannel2(context, db, draft.sessionID, channel1.get(draft.sessionID));
25685
26562
  }
25686
- if (checkpoint && submitted !== undefined) {
25687
- const head = draft.messages.find((message) => message.id === HEAD_IDS[0]);
25688
- const baseline = head?.content.find((part) => part.type === "text")?.text;
25689
- if (typeof baseline === "string") {
25690
- for (const part of checkpoint.content)
25691
- if (part.type === "text" && typeof part.text === "string") {
25692
- part.text = part.text.replace(`<summary>
25693
- ${submitted}
25694
- </summary>`, `<summary>
25695
- ${baseline}
25696
- </summary>`);
25697
- }
25698
- const volatile = draft.messages.find((message) => message.id === HEAD_IDS[1]);
25699
- if (volatile && head)
25700
- volatile.content.push(...head.content.filter((part) => part.type !== "text"));
25701
- draft.messages.splice(0, draft.messages.length, checkpoint, ...draft.messages.filter((message) => message !== head));
25702
- }
25703
- }
26563
+ const head = replayHead !== undefined ? replayHead : checkpoint && submitted !== undefined ? { checkpoint, submitted } : null;
26564
+ const servedHead = head && structuredClone(head);
26565
+ const headApplied = head ? applyCheckpointHead(draft, head) : false;
25704
26566
  if (nativeMessages && !checkpoint) {
25705
26567
  try {
25706
26568
  await nativeFoldReplay?.capture(draft, nativeMessages);
@@ -25711,7 +26573,7 @@ ${baseline}
25711
26573
  }
25712
26574
  const capturedSlot = getSlot(draft.sessionID);
25713
26575
  if (capturedSlot && (!slotAtEntry || capturedSlot.capturedAt !== slotAtEntry.capturedAt || capturedSlot.captureSequence !== slotAtEntry.captureSequence || capturedSlot.jsonPrefix !== slotAtEntry.jsonPrefix)) {
25714
- lkgSystems.capture(draft.sessionID, capturedSlot, systemAtEntry, draft.system);
26576
+ lkgSystems.capture(draft.sessionID, capturedSlot, { system: systemAtEntry, checkpoint: checkpointAtEntry ?? null }, draft.system, headApplied ? servedHead : null);
25715
26577
  }
25716
26578
  } catch (error) {
25717
26579
  if (error instanceof V2ContextRefusal)
@@ -25737,7 +26599,10 @@ ${baseline}
25737
26599
  replayBlocked = true;
25738
26600
  sessionLog(draft.sessionID, "lkg_emergency_armed");
25739
26601
  } else {
25740
- const replayMapped = adaptPayload(draft);
26602
+ const input = await buildReplayInput();
26603
+ if (!input)
26604
+ throw new StorageBusyRefusalError(error, "v2-context");
26605
+ const replayMapped = input.mapped;
25741
26606
  const keys = resolveLkgModelKeys(replayMapped.messages);
25742
26607
  const replay = replayLkg({
25743
26608
  sessionId: draft.sessionID,
@@ -25751,6 +26616,8 @@ ${baseline}
25751
26616
  restoreLkgSystem();
25752
26617
  replayMapped.messages.splice(0, replayMapped.messages.length, ...replay.messages);
25753
26618
  replayMapped.commit();
26619
+ adoptReplay(input.draft);
26620
+ sessionLog(draft.sessionID, "lkg_replay_served");
25754
26621
  return;
25755
26622
  } else {
25756
26623
  sessionLog(draft.sessionID, replay.reason);
@@ -25895,13 +26762,17 @@ ${baseline}
25895
26762
  }, 0);
25896
26763
  return {
25897
26764
  async dispose() {
26765
+ usageController.abort();
26766
+ if (orphanSweepTimer)
26767
+ clearTimeout(orphanSweepTimer);
25898
26768
  await hiddenCompletionExecutor?.dispose();
26769
+ await usageDone;
26770
+ await orphanSweep;
25899
26771
  rpcStopped = true;
25900
26772
  rpcServer.stop();
25901
26773
  tools?.dispose();
25902
- usageController.abort();
25903
- await usageDone;
25904
26774
  deletedSessions.clear();
26775
+ committedSourceRefreshes.clear();
25905
26776
  for (const release of rawProviders.values())
25906
26777
  release();
25907
26778
  rawProviders.clear();