@retaw106/mmc-oc 2.4.0 → 2.6.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 (188) hide show
  1. package/dist/{context-c72brxe5.js → context-cfbjrr0n.js} +1636 -513
  2. package/dist/features/magic-context/compaction-marker.d.ts +34 -6
  3. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  4. package/dist/features/magic-context/message-index-async.d.ts +6 -2
  5. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  6. package/dist/features/magic-context/message-index.d.ts +0 -26
  7. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  8. package/dist/features/magic-context/search.d.ts +5 -1
  9. package/dist/features/magic-context/search.d.ts.map +1 -1
  10. package/dist/features/magic-context/session-decision-calibration.d.ts.map +1 -1
  11. package/dist/features/magic-context/session-retention.fixture.d.ts +4 -0
  12. package/dist/features/magic-context/session-retention.fixture.d.ts.map +1 -0
  13. package/dist/features/magic-context/storage-db.d.ts +2 -0
  14. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  15. package/dist/features/magic-context/storage-host-instruction-retention.d.ts +4 -0
  16. package/dist/features/magic-context/storage-host-instruction-retention.d.ts.map +1 -0
  17. package/dist/features/magic-context/storage-meta-persisted.d.ts +21 -1
  18. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  19. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  20. package/dist/features/magic-context/storage-meta-shared.d.ts +2 -2
  21. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  22. package/dist/features/magic-context/storage-native-replay.d.ts +2 -0
  23. package/dist/features/magic-context/storage-native-replay.d.ts.map +1 -1
  24. package/dist/features/magic-context/storage-session-tables.d.ts +5 -4
  25. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  26. package/dist/features/magic-context/tool-definition-tokens.d.ts +113 -58
  27. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  28. package/dist/features/magic-context/work-metrics.d.ts +5 -3
  29. package/dist/features/magic-context/work-metrics.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/apply-operations.d.ts +32 -0
  31. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  32. package/dist/hooks/magic-context/ask-answer-notice.d.ts +25 -0
  33. package/dist/hooks/magic-context/ask-answer-notice.d.ts.map +1 -0
  34. package/dist/hooks/magic-context/auto-search-hint.d.ts +3 -0
  35. package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
  36. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +5 -5
  39. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/compaction-marker-publication.d.ts +14 -0
  41. package/dist/hooks/magic-context/compaction-marker-publication.d.ts.map +1 -0
  42. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -2
  44. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +11 -0
  45. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/diagnostic-log-state.d.ts +4 -0
  49. package/dist/hooks/magic-context/diagnostic-log-state.d.ts.map +1 -0
  50. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/file-token-coverage.d.ts +11 -0
  52. package/dist/hooks/magic-context/file-token-coverage.d.ts.map +1 -0
  53. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +11 -3
  54. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/historian-history-wait.d.ts +16 -0
  56. package/dist/hooks/magic-context/historian-history-wait.d.ts.map +1 -0
  57. package/dist/hooks/magic-context/history-boundary-repair.d.ts +1 -1
  58. package/dist/hooks/magic-context/history-boundary-repair.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/host-served-rows.d.ts +10 -0
  61. package/dist/hooks/magic-context/host-served-rows.d.ts.map +1 -1
  62. package/dist/hooks/magic-context/inject-compartments.d.ts +1 -1
  63. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  64. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts +3 -1
  67. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  70. package/dist/hooks/magic-context/lkg-slot.d.ts +3 -1
  71. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  72. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts +3 -0
  73. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts.map +1 -0
  74. package/dist/hooks/magic-context/pass-outcome.d.ts +2 -0
  75. package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
  76. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts.map +1 -1
  77. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +2 -0
  78. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  79. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  80. package/dist/hooks/magic-context/read-session-db.d.ts +8 -2
  81. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  82. package/dist/hooks/magic-context/read-session-raw.d.ts +20 -0
  83. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  84. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +3 -3
  85. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts +42 -0
  87. package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts.map +1 -0
  88. package/dist/hooks/magic-context/system-date-refresh.d.ts +3 -2
  89. package/dist/hooks/magic-context/system-date-refresh.d.ts.map +1 -1
  90. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts +4 -0
  92. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts.map +1 -0
  93. package/dist/hooks/magic-context/tag-content-primitives.d.ts +1 -1
  94. package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/tag-messages.d.ts +17 -2
  96. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  97. package/dist/hooks/magic-context/text-complete.d.ts +1 -1
  98. package/dist/hooks/magic-context/text-complete.d.ts.map +1 -1
  99. package/dist/hooks/magic-context/tool-drop-target.d.ts +3 -2
  100. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  101. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -0
  102. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +6 -0
  104. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/transform-stage-logger.d.ts +3 -0
  106. package/dist/hooks/magic-context/transform-stage-logger.d.ts.map +1 -1
  107. package/dist/hooks/magic-context/transform.d.ts +4 -2
  108. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  109. package/dist/{index-27ddyx39.js → index-1np16gxq.js} +1 -1
  110. package/dist/{index-ykq24x1n.js → index-8rmt6s4f.js} +78 -32
  111. package/dist/{index-dwh99z66.js → index-pte3cfs9.js} +194 -5
  112. package/dist/{index-r7s7d350.js → index-s3ebcy63.js} +1 -1
  113. package/dist/{index-48e9znrc.js → index-t0zx3tgz.js} +481 -109
  114. package/dist/{index-kahkxcqw.js → index-xk1dz6q9.js} +870 -315
  115. package/dist/index.js +2 -2
  116. package/dist/{message-time-backfill-j96x1sab.js → message-time-backfill-g9py24yt.js} +1 -1
  117. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  118. package/dist/plugin/subagent-tool-policy.d.ts +4 -0
  119. package/dist/plugin/subagent-tool-policy.d.ts.map +1 -1
  120. package/dist/{read-session-chunk-t8bg6wkz.js → read-session-chunk-2s8x6xps.js} +3 -3
  121. package/dist/{recomp-orchestrator-k760qy1n.js → recomp-orchestrator-51xyaexp.js} +6 -6
  122. package/dist/{send-session-notification-njjf3b4s.js → send-session-notification-vdppp5x6.js} +3 -3
  123. package/dist/shared/model-suggestion-retry.d.ts +2 -0
  124. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  125. package/dist/shared/rpc-discovery-cleanup.d.ts +3 -0
  126. package/dist/shared/rpc-discovery-cleanup.d.ts.map +1 -0
  127. package/dist/shared/rpc-server.d.ts +2 -0
  128. package/dist/shared/rpc-server.d.ts.map +1 -1
  129. package/dist/shared/search-text.d.ts +8 -0
  130. package/dist/shared/search-text.d.ts.map +1 -0
  131. package/dist/shared/sqlite.d.ts +6 -1
  132. package/dist/shared/sqlite.d.ts.map +1 -1
  133. package/dist/shared/storage-file-mutex.d.ts.map +1 -1
  134. package/dist/shared/system-directive.d.ts +2 -0
  135. package/dist/shared/system-directive.d.ts.map +1 -1
  136. package/dist/shared/tag-transcript.d.ts +2 -0
  137. package/dist/shared/tag-transcript.d.ts.map +1 -1
  138. package/dist/shared/transcript.d.ts +3 -1
  139. package/dist/shared/transcript.d.ts.map +1 -1
  140. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  141. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  142. package/dist/tools/parameter-descriptions.d.ts +6 -6
  143. package/dist/tools/parameter-descriptions.d.ts.map +1 -1
  144. package/dist/v2/fold/native-replay.d.ts +11 -2
  145. package/dist/v2/fold/native-replay.d.ts.map +1 -1
  146. package/dist/v2/fold/policy.d.ts.map +1 -1
  147. package/dist/v2/fold/restore.d.ts.map +1 -1
  148. package/dist/v2/hooks/context.d.ts +4 -0
  149. package/dist/v2/hooks/context.d.ts.map +1 -1
  150. package/dist/v2/hooks/generate.d.ts +36 -1
  151. package/dist/v2/hooks/generate.d.ts.map +1 -1
  152. package/dist/v2/hooks/lkg-system.d.ts +35 -4
  153. package/dist/v2/hooks/lkg-system.d.ts.map +1 -1
  154. package/dist/v2/hooks/payload.d.ts +10 -1
  155. package/dist/v2/hooks/payload.d.ts.map +1 -1
  156. package/dist/v2/hooks/store.d.ts +2 -0
  157. package/dist/v2/hooks/store.d.ts.map +1 -1
  158. package/dist/v2/hooks/types.d.ts +12 -0
  159. package/dist/v2/hooks/types.d.ts.map +1 -1
  160. package/dist/v2/message-times.d.ts +17 -0
  161. package/dist/v2/message-times.d.ts.map +1 -0
  162. package/dist/v2/server.js +4692 -2394
  163. package/dist/v2/store-reader.d.ts +21 -0
  164. package/dist/v2/store-reader.d.ts.map +1 -1
  165. package/dist/web/main.js +307 -12
  166. package/dist/{wrapup-orchestrator-b2gswatj.js → wrapup-orchestrator-g0mww1h4.js} +6 -6
  167. package/package.json +1 -1
  168. package/src/config/latch-permanence-guard.test.ts +4 -5
  169. package/src/shared/model-suggestion-retry.test.ts +52 -0
  170. package/src/shared/model-suggestion-retry.ts +8 -3
  171. package/src/shared/prompt-surface-a1-golden.md +6 -7
  172. package/src/shared/rpc-discovery-cleanup.test.ts +125 -0
  173. package/src/shared/rpc-discovery-cleanup.ts +57 -0
  174. package/src/shared/rpc-server.ts +36 -13
  175. package/src/shared/search-text.test.ts +30 -0
  176. package/src/shared/search-text.ts +62 -0
  177. package/src/shared/sqlite-transaction-mode-guard.test.ts +2 -0
  178. package/src/shared/sqlite-turn-deadline.test.ts +286 -0
  179. package/src/shared/sqlite.ts +237 -9
  180. package/src/shared/storage-file-mutex.test.ts +51 -2
  181. package/src/shared/storage-file-mutex.ts +11 -1
  182. package/src/shared/system-directive.test.ts +37 -0
  183. package/src/shared/system-directive.ts +19 -1
  184. package/src/shared/tag-transcript.ts +63 -8
  185. package/src/shared/transcript.ts +1 -1
  186. package/src/shared/write-transaction-attribution.test.ts +1 -6
  187. package/dist/features/magic-context/message-index-sweep.d.ts +0 -11
  188. package/dist/features/magic-context/message-index-sweep.d.ts.map +0 -1
@@ -72,15 +72,9 @@ import {
72
72
  clearMemoryVerifications,
73
73
  queueMemoryMutation,
74
74
  scheduleAfterBootQuiet,
75
- BoundedSessionMap,
76
- registerOwnRpcServerInstance,
77
- rpcPortDir,
78
- rpcPortFilePath,
79
- parseRpcPortFile,
80
- inspectProcessesAsync,
81
- dirtyLkgRecoveryRevision,
82
- ownsLkgDirtyFence,
83
- invalidateCleanLkgRecoveryFence,
75
+ cleanSearchText,
76
+ keywordRelevance,
77
+ matchedSearchSnippet,
84
78
  getLastIndexedOrdinal,
85
79
  getIndexedMessageIdAtOrdinal,
86
80
  getIndexedMessageCorpusSize,
@@ -88,6 +82,11 @@ import {
88
82
  isMessageIndexReconciledThrough,
89
83
  clearIndexedMessages,
90
84
  indexMessagesAfterOrdinal,
85
+ registerOwnRpcServerInstance,
86
+ rpcPortDir,
87
+ rpcPortFilePath,
88
+ parseRpcPortFile,
89
+ inspectProcessesAsync,
91
90
  acquireCompartmentLease,
92
91
  releaseCompartmentLeaseBestEffort,
93
92
  isCompartmentLeaseHeld,
@@ -95,7 +94,8 @@ import {
95
94
  getMaxM0MutationId,
96
95
  ensureSessionMetaRow,
97
96
  clearCachedM0M1,
98
- getCompartments,
97
+ clearCachedM0,
98
+ getTableColumnNames,
99
99
  getLastCompartmentEndMessage,
100
100
  getLastCompartmentEndMessageId,
101
101
  getAuthorityManagedMarker,
@@ -155,6 +155,7 @@ import {
155
155
  clearEmergencyRecovery,
156
156
  clearDetectedContextLimit,
157
157
  getPersistedCompactionMarkerState,
158
+ clearCompactionMarkerPublicationIntent,
158
159
  setPersistedCompactionMarkerState,
159
160
  getDeferredClearedCompactionMarkerState,
160
161
  retireDeferredClearedCompactionMarkerState,
@@ -183,6 +184,9 @@ import {
183
184
  resolveEpochFloorForPass,
184
185
  providerResponseFailed,
185
186
  isSuccessfulProviderCompletion,
187
+ dirtyLkgRecoveryRevision,
188
+ ownsLkgDirtyFence,
189
+ invalidateCleanLkgRecoveryFence,
186
190
  rememberUnpublishedAutoSearchNoHint,
187
191
  getUnpublishedAutoSearchNoHint,
188
192
  forgetUnpublishedAutoSearchNoHint,
@@ -221,6 +225,7 @@ import {
221
225
  lkgDirtyRevision,
222
226
  readLkgRecoveryPrefix,
223
227
  noteLkgHealthyPrefix,
228
+ lkgInputIdentity,
224
229
  beginLkgPass,
225
230
  getInMemorySlot,
226
231
  getSlot,
@@ -272,6 +277,7 @@ import {
272
277
  HISTORIAN_RECOMP_AGENT,
273
278
  HISTORIAN_EDITOR_AGENT,
274
279
  runTokenLog,
280
+ shouldWaitForNewHistorianHistory,
275
281
  extractM0Block,
276
282
  TEMPORAL_MARKER_REPLAY_PATTERN,
277
283
  collectTemporalCandidates,
@@ -292,6 +298,7 @@ import {
292
298
  prepareCachedM0M1Replay,
293
299
  hasCompleteCachedM0M1,
294
300
  injectM0M1,
301
+ omitIncompleteFileTokenTotals,
295
302
  RECOVERY_NO_HEAD_LIMIT,
296
303
  deriveProtectedTailTokenTarget,
297
304
  selectPerRunCap,
@@ -301,7 +308,7 @@ import {
301
308
  recordHighPressureNoEligibleHead,
302
309
  getActiveCompartmentRun,
303
310
  startCompartmentAgent
304
- } from "./index-kahkxcqw.js";
311
+ } from "./index-xk1dz6q9.js";
305
312
  import {
306
313
  getHarness,
307
314
  getDataDir,
@@ -429,19 +436,24 @@ import {
429
436
  pickNearestPriorOwner,
430
437
  expandToolPart,
431
438
  markHostUnservedRow,
439
+ isHostRenderedSystemMessage,
440
+ markCoveredInstructionRow,
441
+ isCoveredInstructionRow,
442
+ takeCoveredInstructionRows,
443
+ cloneKeepingCoveredInstructionMarks,
432
444
  estimateTrueRawMessageTokens,
433
445
  stripSystemInjection,
434
446
  isTextPart,
435
447
  isToolPartWithOutput,
436
448
  isFilePart,
437
- buildFileSourceContent,
438
449
  toolPartHasUserAnswer,
439
450
  recordToolParameters,
440
451
  createDroppedInputGuard,
441
452
  assertExecutableToolInput,
442
453
  isEditTool,
454
+ BoundedSessionMap,
455
+ recordToolDefinitionSet,
443
456
  getCurrentToolSetHash,
444
- recordToolDefinition,
445
457
  getMeasuredToolDefinitionTokens,
446
458
  describeFinalWireTail,
447
459
  estimatePartImageTokens,
@@ -477,7 +489,7 @@ import {
477
489
  hasRawSessionMessageById2,
478
490
  readRawSessionMessageById2,
479
491
  readSessionChunk2
480
- } from "./index-48e9znrc.js";
492
+ } from "./index-t0zx3tgz.js";
481
493
  import {
482
494
  normalizeModelEntry2,
483
495
  resolveHistorianModel2
@@ -492,7 +504,7 @@ import {
492
504
  withAsyncPrivilegedWriter,
493
505
  indexCoordinationInput,
494
506
  withIndexChunk
495
- } from "./index-dwh99z66.js";
507
+ } from "./index-pte3cfs9.js";
496
508
  import {
497
509
  canonicalModelIdentity,
498
510
  piModelRefToCanonical,
@@ -509,7 +521,7 @@ import {
509
521
  latestRealUserTurnIdFromOpenCodeDb,
510
522
  getMessageTimesFromOpenCodeDb,
511
523
  findLastAssistantModelFromOpenCodeDb
512
- } from "./index-ykq24x1n.js";
524
+ } from "./index-8rmt6s4f.js";
513
525
  import {
514
526
  registerNotificationSink2,
515
527
  pushNotification2,
@@ -522,11 +534,14 @@ import {
522
534
  getErrorMessage,
523
535
  flushIgnoredMessages2,
524
536
  sendStatusNotification2
525
- } from "./index-r7s7d350.js";
537
+ } from "./index-s3ebcy63.js";
526
538
  import {
527
539
  logSlowWriteTransaction
528
540
  } from "./index-yjv8dpht.js";
529
541
 
542
+ // src/v2/hooks/context.ts
543
+ import { setTimeout as delay } from "node:timers/promises";
544
+
530
545
  // src/config/index.ts
531
546
  import { existsSync as existsSync4 } from "node:fs";
532
547
 
@@ -5041,6 +5056,8 @@ var RECONCILIATION_BATCH_SIZE = 100;
5041
5056
 
5042
5057
  class MagicContextMessageIndexHeapHolder {
5043
5058
  reconciledSessions = new Set;
5059
+ reconciledSnapshots = new Map;
5060
+ stalledSessions = new Set;
5044
5061
  reconciliationScheduledSessions = new Set;
5045
5062
  clearAndReindexScheduledSessions = new Map;
5046
5063
  sessionLocks = new Map;
@@ -5123,23 +5140,32 @@ function detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMess
5123
5140
  return null;
5124
5141
  return `indexed id '${indexedId}' at ordinal ${cursor} but projection has '${projectedId}'`;
5125
5142
  }
5143
+ function logReconciliationStall(sessionId, reason) {
5144
+ if (heapHolder.stalledSessions.has(sessionId))
5145
+ return;
5146
+ heapHolder.stalledSessions.add(sessionId);
5147
+ sessionLog(sessionId, `message FTS reconciliation stalled: ${reason}; will retry`);
5148
+ }
5126
5149
  async function reconcileSessionIndex(db, sessionId, readMessages) {
5127
5150
  if (!await sourceReady(readMessages, sessionId))
5128
5151
  return false;
5129
5152
  await runWithSessionLock(sessionId, async () => {
5130
- if (heapHolder.reconciledSessions.has(sessionId))
5153
+ if (!readMessages.getRevision && heapHolder.reconciledSessions.has(sessionId))
5131
5154
  return;
5132
5155
  let fallbackSnapshot = null;
5133
5156
  try {
5134
5157
  const fullReader = typeof readMessages === "function" ? readMessages : null;
5135
- const finalWatermark = readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = fullReader?.(sessionId) ?? []).length;
5158
+ const revision = readMessages.getRevision?.(sessionId);
5159
+ const previous = heapHolder.reconciledSnapshots.get(sessionId);
5160
+ 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
5161
  let cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
5137
- let after;
5138
- const misalignment = detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMessages, fallbackSnapshot);
5162
+ let after = cursor === previous?.count ? previous.after : undefined;
5163
+ const misalignment = revision !== undefined && previous && revision >= previous.revision ? null : detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMessages, fallbackSnapshot);
5139
5164
  if (misalignment !== null) {
5140
5165
  sessionLog(sessionId, `message FTS index misaligned (${misalignment}); clearing for full re-index`);
5141
5166
  withSqliteBackgroundWriter(() => clearIndexedMessages(db, sessionId));
5142
5167
  cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
5168
+ after = undefined;
5143
5169
  }
5144
5170
  while (cursor < finalWatermark) {
5145
5171
  const pageEnd = Math.min(finalWatermark, cursor + RECONCILIATION_BATCH_SIZE);
@@ -5159,6 +5185,22 @@ async function reconcileSessionIndex(db, sessionId, readMessages) {
5159
5185
  }
5160
5186
  if (isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
5161
5187
  heapHolder.reconciledSessions.add(sessionId);
5188
+ heapHolder.stalledSessions.delete(sessionId);
5189
+ if (revision !== undefined) {
5190
+ if (!after && finalWatermark > 0 && readMessages.readPage) {
5191
+ const last = readMessages.readPage(sessionId, finalWatermark - 1, 1, finalWatermark).at(-1);
5192
+ if (last?.ordinal === finalWatermark && typeof last.createdAt === "number")
5193
+ after = { timeCreated: last.createdAt, id: last.id };
5194
+ }
5195
+ heapHolder.reconciledSnapshots.set(sessionId, {
5196
+ revision,
5197
+ count: finalWatermark,
5198
+ after
5199
+ });
5200
+ }
5201
+ } else {
5202
+ heapHolder.reconciledSessions.delete(sessionId);
5203
+ logReconciliationStall(sessionId, `gap after ordinal ${cursor} (store count ${finalWatermark})`);
5162
5204
  }
5163
5205
  } finally {
5164
5206
  heapHolder.activeReconcilerBuffers.delete(sessionId);
@@ -5167,30 +5209,42 @@ async function reconcileSessionIndex(db, sessionId, readMessages) {
5167
5209
  return true;
5168
5210
  }
5169
5211
  function scheduleReconciliation(db, sessionId, readMessages) {
5170
- if (heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
5212
+ if (!readMessages.getRevision && heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
5171
5213
  return;
5172
5214
  }
5173
5215
  heapHolder.reconciliationScheduledSessions.add(sessionId);
5174
5216
  scheduleAfterBootQuiet(() => {
5175
5217
  defer(() => {
5218
+ let appendedDuringReconciliation = false;
5219
+ const previousSnapshot = heapHolder.reconciledSnapshots.get(sessionId);
5176
5220
  reconcileSessionIndex(db, sessionId, readMessages).then((ran) => {
5177
- if (ran)
5221
+ if (ran) {
5222
+ const snapshot = heapHolder.reconciledSnapshots.get(sessionId);
5223
+ appendedDuringReconciliation = snapshot !== undefined && snapshot !== previousSnapshot && readMessages.getRevision !== undefined && readMessages.getRevision(sessionId) !== snapshot.revision;
5178
5224
  return;
5225
+ }
5179
5226
  setTimeout(() => {
5180
5227
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5181
5228
  scheduleReconciliation(db, sessionId, readMessages);
5182
5229
  }, PREPARE_RETRY_MS).unref?.();
5183
5230
  }).catch((error) => {
5184
- logIndexingError(sessionId, "reconciliation", error);
5231
+ heapHolder.reconciledSessions.delete(sessionId);
5232
+ logReconciliationStall(sessionId, error instanceof Error ? error.message : String(error));
5185
5233
  if (isDatabaseLockedError(error))
5186
5234
  setTimeout(() => scheduleReconciliation(db, sessionId, readMessages), 1000).unref();
5187
5235
  }).finally(() => {
5188
5236
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5237
+ if (appendedDuringReconciliation)
5238
+ scheduleReconciliation(db, sessionId, readMessages);
5189
5239
  });
5190
5240
  });
5191
5241
  });
5192
5242
  }
5193
5243
  function scheduleReconciliationCatchup(db, sessionId, readMessages) {
5244
+ if (readMessages.getRevision) {
5245
+ scheduleReconciliation(db, sessionId, readMessages);
5246
+ return;
5247
+ }
5194
5248
  if (typeof readMessages.getCount !== "function") {
5195
5249
  scheduleReconciliation(db, sessionId, readMessages);
5196
5250
  return;
@@ -5208,6 +5262,7 @@ function scheduleReconciliationCatchup(db, sessionId, readMessages) {
5208
5262
  }
5209
5263
  function scheduleClearAndReindex(db, sessionId, readMessages) {
5210
5264
  heapHolder.reconciledSessions.delete(sessionId);
5265
+ heapHolder.reconciledSnapshots.delete(sessionId);
5211
5266
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5212
5267
  clearCompletedIncrementalKeys(sessionId);
5213
5268
  const existing = heapHolder.clearAndReindexScheduledSessions.get(sessionId);
@@ -5225,6 +5280,7 @@ function scheduleClearAndReindex(db, sessionId, readMessages) {
5225
5280
  return;
5226
5281
  heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
5227
5282
  heapHolder.reconciledSessions.delete(sessionId);
5283
+ heapHolder.reconciledSnapshots.delete(sessionId);
5228
5284
  clearCompletedIncrementalKeys(sessionId);
5229
5285
  clearIndexedMessages(db, sessionId);
5230
5286
  cleared = true;
@@ -6316,6 +6372,26 @@ class EmergencyFailClosedError extends Error {
6316
6372
  }
6317
6373
 
6318
6374
  // src/hooks/magic-context/history-boundary-repair.ts
6375
+ function readStoreBoundaries(db, sessionId) {
6376
+ const columns = getTableColumnNames(db, "compartments");
6377
+ const numbers = ["id", "sequence", "start_message", "end_message", "created_at"];
6378
+ const strings = ["session_id", "start_message_id", "end_message_id", "title", "content"];
6379
+ const predicates = [...numbers, ...strings].every((column) => columns.has(column)) ? [
6380
+ ...numbers.map((column) => `typeof(${column}) IN ('integer', 'real')`),
6381
+ ...strings.map((column) => `typeof(${column}) = 'text'`)
6382
+ ] : ["0"];
6383
+ for (const column of ["p1", "p2", "p3", "p4", "episode_type"]) {
6384
+ if (columns.has(column))
6385
+ predicates.push(`typeof(${column}) IN ('text', 'null')`);
6386
+ }
6387
+ for (const column of ["importance", "legacy"]) {
6388
+ if (columns.has(column))
6389
+ predicates.push(`typeof(${column}) IN ('integer', 'real', 'null')`);
6390
+ }
6391
+ return db.prepare(`SELECT sequence, ${columns.has("end_message_id") ? "end_message_id" : "NULL"} AS endMessageId
6392
+ FROM compartments WHERE session_id = ? AND ${predicates.join(" AND ")}
6393
+ ORDER BY sequence ASC`).all(sessionId);
6394
+ }
6319
6395
  function readBaseline(db, sessionId) {
6320
6396
  const row = db.prepare("SELECT cached_m0_bytes IS NOT NULL AS hasM0, cached_m0_last_baseline_end_message_id AS boundary FROM session_meta WHERE session_id = ?").get(sessionId);
6321
6397
  return {
@@ -6381,7 +6457,7 @@ function dropCompartmentsAfter(db, sessionId, anchor, holderId, activeBranch = f
6381
6457
  }
6382
6458
  function repairMissingHistoryBoundary(args) {
6383
6459
  const { db, sessionId, isInHostStore, scope = "store" } = args;
6384
- const compartments = scope === "active-branch" ? db.prepare("SELECT sequence, COALESCE(end_message_id, '') AS endMessageId FROM compartments WHERE session_id = ? ORDER BY sequence").all(sessionId) : getCompartments(db, sessionId);
6460
+ const compartments = scope === "active-branch" ? db.prepare("SELECT sequence, COALESCE(end_message_id, '') AS endMessageId FROM compartments WHERE session_id = ? ORDER BY sequence").all(sessionId) : readStoreBoundaries(db, sessionId);
6385
6461
  let latestIndex = compartments.length - 1;
6386
6462
  while (latestIndex >= 0 && !compartments[latestIndex]?.endMessageId)
6387
6463
  latestIndex -= 1;
@@ -6425,7 +6501,7 @@ function repairMissingHistoryBoundary(args) {
6425
6501
  let dropped;
6426
6502
  let anchorForDrop = anchor;
6427
6503
  try {
6428
- if (scope === "active-branch" && anchor) {
6504
+ if (anchor) {
6429
6505
  const row = db.prepare("SELECT end_message AS endMessage FROM compartments WHERE session_id = ? AND sequence = ?").get(sessionId, anchor.sequence);
6430
6506
  if (!row)
6431
6507
  return { kind: "unresolved", reason: "busy", missingEndMessageId: missing };
@@ -7200,7 +7276,7 @@ function searchMessagesInSnapshot(args, sessionFirst) {
7200
7276
  const filtered = rows.slice(0, limit);
7201
7277
  return filtered.map((row, rank) => ({
7202
7278
  source: "message",
7203
- content: previewText(row.content),
7279
+ content: matchedSearchSnippet(row.content, args.query) || previewText(row.content),
7204
7280
  score: linearDecayScore(rank, filtered.length),
7205
7281
  messageOrdinal: row.messageOrdinal,
7206
7282
  messageId: row.messageId,
@@ -7275,7 +7351,7 @@ function searchMessagesInSnapshot(args, sessionFirst) {
7275
7351
  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
7352
  return ranked.map((entry, rank) => ({
7277
7353
  source: "message",
7278
- content: previewText(entry.row.content),
7354
+ content: matchedSearchSnippet(entry.row.content, args.query) || previewText(entry.row.content),
7279
7355
  score: linearDecayScore(rank, ranked.length),
7280
7356
  messageOrdinal: entry.row.messageOrdinal,
7281
7357
  messageId: entry.row.messageId,
@@ -7592,7 +7668,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
7592
7668
  if (options.diagnostics) {
7593
7669
  options.diagnostics.suppressedLiveMessageMatches = outcome.suppressedLiveMessageMatches;
7594
7670
  }
7595
- messageResults = outcome.results;
7671
+ messageResults = outcome.results.filter((result) => result.messageId !== options.excludeMessageId);
7596
7672
  }
7597
7673
  const workspace = resolveSearchWorkspaceContext(db, projectPath);
7598
7674
  const [memoryOutcome, primerResults, noteResults] = await Promise.all([
@@ -7647,6 +7723,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
7647
7723
  }).immediate();
7648
7724
  }
7649
7725
  }
7726
+ if (options.autoHint) {
7727
+ return results.map((result) => ({
7728
+ ...result,
7729
+ relevanceScore: cleanSearchText(result.content).length === 0 ? 0 : keywordRelevance(trimmedQuery, result.content)
7730
+ }));
7731
+ }
7650
7732
  return results;
7651
7733
  }
7652
7734
  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 +8348,22 @@ function truncate(text, limit) {
8266
8348
  return normalized;
8267
8349
  return `${normalized.slice(0, Math.max(0, limit - 1)).trimEnd()}…`;
8268
8350
  }
8269
- function renderFragment(result, charCap, wordRules) {
8351
+ function renderFragment(result, charCap, wordRules, query) {
8270
8352
  switch (result.source) {
8271
8353
  case "memory": {
8272
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8354
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8273
8355
  return truncate(compressed, charCap);
8274
8356
  }
8275
8357
  case "message": {
8276
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8358
+ const compressed = cavemanCompress(query ? matchedSearchSnippet(result.content, query, charCap) : cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8277
8359
  return truncate(compressed, charCap);
8278
8360
  }
8279
8361
  case "primer": {
8280
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8362
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8281
8363
  return truncate(compressed, charCap);
8282
8364
  }
8283
8365
  case "note": {
8284
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8366
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8285
8367
  return truncate(compressed, charCap);
8286
8368
  }
8287
8369
  }
@@ -8292,7 +8374,7 @@ function buildAutoSearchHint(results, options = {}) {
8292
8374
  const picks = results.slice(0, maxFragments);
8293
8375
  const lines = [];
8294
8376
  for (const result of picks) {
8295
- const fragment = renderFragment(result, fragmentCharCap, options.wordRules ?? "english");
8377
+ const fragment = renderFragment(result, fragmentCharCap, options.wordRules ?? "english", options.query ?? "");
8296
8378
  if (fragment.length === 0)
8297
8379
  continue;
8298
8380
  lines.push(`- ${fragment}`);
@@ -8315,6 +8397,10 @@ ${trimmedBody}…
8315
8397
  }
8316
8398
  return wrapped;
8317
8399
  }
8400
+ function selectAutoSearchResults(results, threshold) {
8401
+ const relevance = (result) => result.relevanceScore ?? result.score;
8402
+ return results.filter((result) => relevance(result) >= threshold).sort((left, right) => relevance(right) - relevance(left));
8403
+ }
8318
8404
 
8319
8405
  // src/hooks/magic-context/transform-message-helpers.ts
8320
8406
  function isMeaningfulUserMessage(msg) {
@@ -8591,6 +8677,9 @@ async function runAutoSearchHint(args) {
8591
8677
  return null;
8592
8678
  const searchOptions = {
8593
8679
  limit: 10,
8680
+ autoHint: true,
8681
+ maxMessageOrdinal: Math.max(0, getLastCompartmentEndMessage(db, sessionId)),
8682
+ excludeMessageId: userMsgId,
8594
8683
  memoryEnabled: options.memoryEnabled,
8595
8684
  visibleMemoryIds: options.visibleMemoryIds ?? null,
8596
8685
  sources: ["memory", "message"]
@@ -8615,11 +8704,15 @@ async function runAutoSearchHint(args) {
8615
8704
  if (results.length === 0) {
8616
8705
  return writeNoHintAndReconcile("empty");
8617
8706
  }
8618
- if (results[0].score < options.scoreThreshold) {
8619
- sessionLog(sessionId, `auto-search: top score ${results[0].score.toFixed(3)} below threshold ${options.scoreThreshold}`);
8707
+ results = selectAutoSearchResults(results, options.scoreThreshold);
8708
+ if (results.length === 0) {
8709
+ sessionLog(sessionId, `auto-search: no fragment meets relevance threshold ${options.scoreThreshold}`);
8620
8710
  return writeNoHintAndReconcile("below-threshold");
8621
8711
  }
8622
- const hintText = buildAutoSearchHint(results, { wordRules: options.wordRules });
8712
+ const hintText = buildAutoSearchHint(results, {
8713
+ wordRules: options.wordRules,
8714
+ query: rawPrompt
8715
+ });
8623
8716
  if (!hintText) {
8624
8717
  return writeNoHintAndReconcile("empty");
8625
8718
  }
@@ -8683,6 +8776,30 @@ function getSessionErrorInfo(properties) {
8683
8776
  };
8684
8777
  }
8685
8778
 
8779
+ // src/hooks/magic-context/diagnostic-log-state.ts
8780
+ var states = new BoundedSessionMap(1000);
8781
+ var scope = (sessionId) => `${getMagicContextStorageDir()}\x00${getHarness()}\x00${sessionId}`;
8782
+ function diagnosticStateChanged(sessionId, category, state) {
8783
+ const key = scope(sessionId);
8784
+ const previous = states.get(key) ?? new Map;
8785
+ if (previous.get(category) === state)
8786
+ return false;
8787
+ previous.set(category, state);
8788
+ states.set(key, previous);
8789
+ return true;
8790
+ }
8791
+ function clearDiagnosticLogState(sessionId) {
8792
+ states.delete(scope(sessionId));
8793
+ }
8794
+
8795
+ // src/hooks/magic-context/nudge-evaluation-log.ts
8796
+ function logNudgeEvaluation(sessionId, phase, line) {
8797
+ const category = `${phase}:${line.split(":", 1)[0]}`;
8798
+ const state = line.split(" ").filter((field) => /^(ctx_reduce|band|dampening|verdict|reason|lease)=/.test(field)).join(" ");
8799
+ if (diagnosticStateChanged(sessionId, category, state))
8800
+ sessionLog(sessionId, line);
8801
+ }
8802
+
8686
8803
  // src/hooks/magic-context/stripped-command.ts
8687
8804
  function matchStrippedMagicContextCommand(parts) {
8688
8805
  if (parts.length !== 1)
@@ -8871,7 +8988,7 @@ function maybeInjectChannel1Nudge(args, sessionId, tool, output) {
8871
8988
  evaluable: state.evaluable,
8872
8989
  generationInvalidated: state.generationInvalidated
8873
8990
  });
8874
- sessionLog(sessionId, formatChannel1Evaluation(decision));
8991
+ logNudgeEvaluation(sessionId, "tool-completion", formatChannel1Evaluation(decision));
8875
8992
  setLastNudgeUndropped(args.db, sessionId, decision.nextLastNudge);
8876
8993
  const nextNudgeState = {
8877
8994
  ...nudgeState,
@@ -10358,6 +10475,35 @@ function systemPromptDates(prompt, sticky) {
10358
10475
  return { live: values.length ? JSON.stringify(values) : undefined, stable };
10359
10476
  }
10360
10477
 
10478
+ // src/hooks/magic-context/system-prompt-sticky-date.ts
10479
+ var STICKY_DATE_KEY = "systemPromptStickyDate";
10480
+ function readPersistedSystemPromptStickyDate(db, sessionId) {
10481
+ try {
10482
+ const saved = readReplayEnvelope(db, sessionId, "read")[STICKY_DATE_KEY];
10483
+ return typeof saved === "string" && saved.length > 0 ? saved : undefined;
10484
+ } catch (error) {
10485
+ sessionLog(sessionId, "system prompt sticky date record unreadable:", error);
10486
+ return;
10487
+ }
10488
+ }
10489
+ function persistSystemPromptStickyDate(db, sessionId, stickyDate) {
10490
+ try {
10491
+ const written = updateReplayDocument(db, sessionId, (doc) => {
10492
+ if (doc[STICKY_DATE_KEY] === stickyDate)
10493
+ return false;
10494
+ doc.version = 2;
10495
+ doc[STICKY_DATE_KEY] = stickyDate;
10496
+ return true;
10497
+ });
10498
+ if (!written)
10499
+ sessionLog(sessionId, "system prompt sticky date record not written");
10500
+ return written;
10501
+ } catch (error) {
10502
+ sessionLog(sessionId, "system prompt sticky date record write failed:", error);
10503
+ return false;
10504
+ }
10505
+ }
10506
+
10361
10507
  // src/hooks/magic-context/system-date-refresh.ts
10362
10508
  var channels = new WeakMap;
10363
10509
  var outputUpdates = new WeakMap;
@@ -10428,6 +10574,7 @@ function beginSystemDateRequest(history, sessionId, stage, turnId, identity) {
10428
10574
  systemDone: false,
10429
10575
  messagesSeen: false,
10430
10576
  permitted: undefined,
10577
+ signedThinkingKept: undefined,
10431
10578
  ambiguous: identity === undefined && (turnId === undefined || sameTurn)
10432
10579
  };
10433
10580
  const blocked = [...requests.values()].filter((candidate) => !candidate.explicit && candidate.ambiguous && !(candidate.systemSeen && candidate.messagesSeen) && candidate.turnId === turnId).length;
@@ -10450,6 +10597,10 @@ function systemDateRefreshPermission(history, request) {
10450
10597
  const current = state(history, request);
10451
10598
  return current?.ambiguous ? undefined : current?.permitted;
10452
10599
  }
10600
+ function systemDateSignedThinkingKept(history, request) {
10601
+ const current = state(history, request);
10602
+ return current?.ambiguous ? undefined : current?.signedThinkingKept;
10603
+ }
10453
10604
  function waitForSystemDateRefresh(history, request, apply) {
10454
10605
  const current = state(history, request);
10455
10606
  if (!current)
@@ -10464,7 +10615,7 @@ function retire(history, current) {
10464
10615
  if (unpairable) {
10465
10616
  const apply = current.waiting;
10466
10617
  current.waiting = undefined;
10467
- apply?.(false);
10618
+ apply?.(false, undefined);
10468
10619
  }
10469
10620
  const channel = channels.get(history);
10470
10621
  const requests = channel?.get(current.sessionId);
@@ -10472,14 +10623,15 @@ function retire(history, current) {
10472
10623
  if (requests?.size === 0)
10473
10624
  channel?.delete(current.sessionId);
10474
10625
  }
10475
- function finishSystemDateRefresh(history, request, permitted) {
10626
+ function finishSystemDateRefresh(history, request, permitted, signedThinkingKept) {
10476
10627
  const current = state(history, request);
10477
10628
  if (!current)
10478
10629
  return;
10479
10630
  current.permitted = current.ambiguous ? false : permitted;
10631
+ current.signedThinkingKept = current.ambiguous ? undefined : signedThinkingKept;
10480
10632
  const apply = current.waiting;
10481
10633
  current.waiting = undefined;
10482
- apply?.(current.permitted);
10634
+ apply?.(current.permitted, current.signedThinkingKept);
10483
10635
  retire(history, current);
10484
10636
  }
10485
10637
  function finishSystemDateHook(history, request) {
@@ -10515,6 +10667,15 @@ function createSystemPromptHashHandler(deps) {
10515
10667
  });
10516
10668
  const guidanceEpochs = createPromptSurfaceGuidanceEpochCache(promptSurfaceRuntime);
10517
10669
  const stickyDateBySession = new Map;
10670
+ const recordedStickyDateBySession = new Map;
10671
+ const recordedStickyDate = (sessionId) => {
10672
+ let recorded = recordedStickyDateBySession.get(sessionId);
10673
+ if (recorded === undefined) {
10674
+ recorded = readPersistedSystemPromptStickyDate(deps.db, sessionId) ?? null;
10675
+ recordedStickyDateBySession.set(sessionId, recorded);
10676
+ }
10677
+ return recorded ?? undefined;
10678
+ };
10518
10679
  const processSystemPrompt = async (input, output) => {
10519
10680
  const sessionId = input.sessionID;
10520
10681
  if (!sessionId)
@@ -10583,18 +10744,37 @@ function createSystemPromptHashHandler(deps) {
10583
10744
  const hasPersistedHash = previousHash !== "" && previousHash !== "0";
10584
10745
  if (!hasPersistedHash)
10585
10746
  stickyDateBySession.delete(sessionId);
10586
- const stickyDate = stickyDateBySession.get(sessionId);
10747
+ let stickyDate = stickyDateBySession.get(sessionId);
10748
+ if (stickyDate === undefined && hasPersistedHash) {
10749
+ const recorded = recordedStickyDate(sessionId);
10750
+ const live = systemPromptDates(liveSystemContent).live;
10751
+ if (recorded !== undefined && live !== undefined && recorded !== live && systemPromptFingerprint(systemPromptDates(liveSystemContent, recorded).stable, promptSurface.preset) === previousHash) {
10752
+ stickyDate = recorded;
10753
+ stickyDateBySession.set(sessionId, recorded);
10754
+ }
10755
+ }
10756
+ const setStickyDate = (value) => {
10757
+ stickyDateBySession.set(sessionId, value);
10758
+ if (value !== recordedStickyDate(sessionId)) {
10759
+ if (persistSystemPromptStickyDate(deps.db, sessionId, value))
10760
+ recordedStickyDateBySession.set(sessionId, value);
10761
+ }
10762
+ };
10587
10763
  const dates = systemPromptDates(liveSystemContent, stickyDate);
10588
10764
  const currentDate = dates.live;
10589
10765
  const stableCandidate = dates.stable;
10590
10766
  const stableCandidateHash = systemPromptFingerprint(stableCandidate, promptSurface.preset);
10591
10767
  const contentOrPresetChanged = hasPersistedHash && stableCandidateHash !== previousHash;
10592
10768
  const rewritePermission = systemDateRefreshPermission(deps.historyRefreshSessions, dateRequest);
10769
+ const signedThinkingKept = systemDateSignedThinkingKept(deps.historyRefreshSessions, dateRequest);
10770
+ const prefixBoundModel = isPrefixBoundThinkingModel(liveModel?.providerID, liveModel?.modelID);
10771
+ const thinkingAllowsDate = (kept) => prefixBoundModel ? kept === false : kept !== true;
10772
+ const systemDateMayMove = (rewrite, kept) => (rewrite || idleCacheExpired) && thinkingAllowsDate(kept);
10593
10773
  let deferredDateRefresh = false;
10594
- if (currentDate && stickyDate && currentDate !== stickyDate && isCacheBusting && !idleCacheExpired && !contentOrPresetChanged && !requestMessagesFinal) {
10774
+ if (currentDate && stickyDate && currentDate !== stickyDate && (isCacheBusting || idleCacheExpired && isPrefixBoundThinkingModel(liveModel?.providerID, liveModel?.modelID)) && rewritePermission === undefined && !contentOrPresetChanged && !requestMessagesFinal) {
10595
10775
  const liveElements = [...output.system];
10596
- deferredDateRefresh = waitForSystemDateRefresh(deps.historyRefreshSessions, dateRequest, (permitted) => {
10597
- if (!permitted) {
10776
+ deferredDateRefresh = waitForSystemDateRefresh(deps.historyRefreshSessions, dateRequest, (permitted, keptSignedThinking) => {
10777
+ if (!systemDateMayMove(permitted, keptSignedThinking)) {
10598
10778
  deps.systemPromptRefreshSessions.add(sessionId);
10599
10779
  return;
10600
10780
  }
@@ -10607,7 +10787,7 @@ function createSystemPromptHashHandler(deps) {
10607
10787
  cachedM0SystemHash: hash,
10608
10788
  systemPromptTokens: estimateTokens(content)
10609
10789
  });
10610
- stickyDateBySession.set(sessionId, currentDate);
10790
+ setStickyDate(currentDate);
10611
10791
  output.system.splice(0, output.system.length, ...liveElements);
10612
10792
  publishSystemDateOutput(output.system);
10613
10793
  deps.systemPromptRefreshSessions.delete(sessionId);
@@ -10618,12 +10798,12 @@ function createSystemPromptHashHandler(deps) {
10618
10798
  }
10619
10799
  });
10620
10800
  }
10621
- const dateMayAdvance = idleCacheExpired || contentOrPresetChanged || isCacheBusting && !deferredDateRefresh && (dateRequest ? rewritePermission === true : rewritePermission !== false);
10801
+ const dateMayAdvance = thinkingAllowsDate(signedThinkingKept) && (contentOrPresetChanged || !deferredDateRefresh && systemDateMayMove(isCacheBusting && (dateRequest ? rewritePermission === true : rewritePermission !== false), signedThinkingKept));
10622
10802
  if (currentDate && !stickyDate) {
10623
- stickyDateBySession.set(sessionId, currentDate);
10803
+ setStickyDate(currentDate);
10624
10804
  } else if (currentDate && stickyDate && currentDate !== stickyDate) {
10625
10805
  if (dateMayAdvance) {
10626
- stickyDateBySession.set(sessionId, currentDate);
10806
+ setStickyDate(currentDate);
10627
10807
  sessionLog(sessionId, `system prompt date updated: ${stickyDate} → ${currentDate} (cache-busting pass)`);
10628
10808
  } else {
10629
10809
  let offset = 0;
@@ -10678,7 +10858,7 @@ function createSystemPromptHashHandler(deps) {
10678
10858
  sessionLog(sessionId, "system prompt meta persist failed (fail-open):", error);
10679
10859
  }
10680
10860
  }
10681
- if (isCacheBusting && !deferredDateRefresh && (contentOrPresetChanged || !currentDate || currentDate === stickyDate || !dateRequest || rewritePermission === true)) {
10861
+ if (isCacheBusting && !deferredDateRefresh && (contentOrPresetChanged && thinkingAllowsDate(signedThinkingKept) || !currentDate || currentDate === stickyDate || !dateRequest && thinkingAllowsDate(signedThinkingKept) || rewritePermission === true && thinkingAllowsDate(signedThinkingKept))) {
10682
10862
  deps.systemPromptRefreshSessions.delete(sessionId);
10683
10863
  }
10684
10864
  };
@@ -10692,6 +10872,7 @@ function createSystemPromptHashHandler(deps) {
10692
10872
  return {
10693
10873
  handler,
10694
10874
  clearSession: (sessionId) => {
10875
+ recordedStickyDateBySession.delete(sessionId);
10695
10876
  clearSystemDateRefresh(deps.historyRefreshSessions, sessionId);
10696
10877
  guidanceEpochs.clear(sessionId);
10697
10878
  clearSystemPromptHashSession(sessionId, {
@@ -11203,6 +11384,8 @@ function reconcileCompactionMode(args) {
11203
11384
  return NO_TRANSITION;
11204
11385
  if (stored === "off_cleanup_pending") {
11205
11386
  const markerCleanup = (args.cleanupMarkers ?? cleanupOffMarkers)(sessionId);
11387
+ if (markerCleanup.verified)
11388
+ clearCompactionMarkerPublicationIntent(db, sessionId);
11206
11389
  return {
11207
11390
  ...NO_TRANSITION,
11208
11391
  recordToWrite: markerCleanup.verified ? "off" : null,
@@ -11217,7 +11400,9 @@ function reconcileCompactionMode(args) {
11217
11400
  if (markerCleanup.removedRows > 0)
11218
11401
  clearedSomething = true;
11219
11402
  if (getPersistedCompactionMarkerState(db, sessionId) !== null) {
11220
- setPersistedCompactionMarkerState(db, sessionId, null);
11403
+ setPersistedCompactionMarkerState(db, sessionId, null, {
11404
+ preservePending: !markerCleanup.verified
11405
+ });
11221
11406
  clearedSomething = true;
11222
11407
  }
11223
11408
  const pendingMarker = getPendingCompactionMarkerState(db, sessionId);
@@ -11760,6 +11945,13 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
11760
11945
  }
11761
11946
  return { shouldFire: false };
11762
11947
  }
11948
+ if (tailInfo.boundarySnapshot && shouldWaitForNewHistorianHistory(tailInfo.boundarySnapshot, {
11949
+ usagePercentage: usage.percentage,
11950
+ emergency: getOverflowState(db, sessionId).needsEmergencyRecovery
11951
+ })) {
11952
+ sessionLog(sessionId, "compartment trigger: waiting for new history after no forward progress");
11953
+ return { shouldFire: false };
11954
+ }
11763
11955
  const canClearReasoning = reasoningProjection?.canClearReasoning ?? modelAcceptsEmptyContent(reasoningProjection?.providerID);
11764
11956
  const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), keepReasoningTokens, sessionMeta.clearedReasoningThroughTag, canClearReasoning, reasoningProjection?.budgetCutoff, eligiblePendingDropTagIds);
11765
11957
  const relativePostDropTarget = executeThresholdPercentage * POST_DROP_TARGET_RATIO;
@@ -11867,6 +12059,8 @@ var PASS_DEGRADATION_EFFECTS = {
11867
12059
  "stale-reduce-strip-exception": "changes-request",
11868
12060
  "image-strip-exception": "changes-request",
11869
12061
  "m0-m1-injection-degradation": "changes-request",
12062
+ "host-instruction-retention-read-failure": "changes-request",
12063
+ "host-instruction-retention-persistence-failure": "changes-request",
11870
12064
  "m0-m1-fallback-failure": "changes-request",
11871
12065
  "compaction-marker-drain-failure": "changes-request",
11872
12066
  "auto-search-timeout": "served",
@@ -11942,6 +12136,27 @@ function resolveHistoryBudgetTokens(historyBudgetPercentage, contextUsage, execu
11942
12136
  }) / 100) * historyBudgetPercentage);
11943
12137
  }
11944
12138
 
12139
+ // src/hooks/magic-context/signed-thinking-fit-snapshot.ts
12140
+ function takeSignedThinkingFitSnapshot(args) {
12141
+ let snapshot = null;
12142
+ if (args.held && !args.compactionOff) {
12143
+ try {
12144
+ snapshot = cloneKeepingCoveredInstructionMarks(args.entryOrder);
12145
+ } catch (error) {
12146
+ sessionLog(args.sessionId, `signed thinking fit: could not copy the pass input (${error instanceof Error ? error.message : String(error)}); an over-window held request will be refused rather than retried`);
12147
+ }
12148
+ }
12149
+ snapshotObserver?.({
12150
+ sessionId: args.sessionId,
12151
+ held: args.held,
12152
+ activeAnthropicThinkingTurn: args.activeAnthropicThinkingTurn,
12153
+ compactionOff: args.compactionOff,
12154
+ snapshot
12155
+ });
12156
+ return snapshot;
12157
+ }
12158
+ var snapshotObserver;
12159
+
11945
12160
  // src/hooks/magic-context/temporal-served-projection.ts
11946
12161
  function readLkgTemporalDecisions(db, sessionId, runtime) {
11947
12162
  const slot = getInMemorySlot(sessionId) ?? loadPersistedLkgSlot(db, sessionId);
@@ -12165,7 +12380,7 @@ async function runCompartmentPhaseImpl(args) {
12165
12380
  justAwaitedPublication = activeRun.published;
12166
12381
  published = published || activeRun.published;
12167
12382
  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);
12383
+ pendingCompartmentInjection = prepareCompartmentInjection(args.db, args.resolvedSessionId, args.messages, historyReprepareShouldBust, args.projectPath, args.injectionBudgetTokens, args.experimentalTemporalAwareness, args.coveredHostInstructions);
12169
12384
  if (historyReprepareShouldBust) {
12170
12385
  rebuiltHistoryThisPass = true;
12171
12386
  }
@@ -12382,7 +12597,7 @@ function capturePendingDropEligibility(targets, protectedTagIds) {
12382
12597
  eligible.add(number);
12383
12598
  } else {
12384
12599
  const content = target.getContent?.();
12385
- if (typeof content === "string" && content.length > `[dropped §${number}§]`.length)
12600
+ if (typeof content === "string" && content.length > `[dropped §${number}§]`.length && target.canSetContent?.(`[dropped §${number}§]`) !== false)
12386
12601
  eligible.add(number);
12387
12602
  }
12388
12603
  }
@@ -12439,28 +12654,52 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
12439
12654
  function buildReplacementContent(tagId) {
12440
12655
  return `[dropped §${tagId}§]`;
12441
12656
  }
12657
+ var FROZEN_TEXT_ANNOTATION_SUFFIX = /(?:\n\n(?:<instruction name="deferred_notes">(?:(?!<\/instruction>)[\s\S])*<\/instruction>|<ctx-search-hint>(?:(?!<\/ctx-search-hint>)[\s\S])*<\/ctx-search-hint>))+$/;
12658
+ function renderDroppedText(tagId, renderedText) {
12659
+ const placeholder = buildReplacementContent(tagId);
12660
+ if (renderedText?.startsWith(placeholder))
12661
+ return renderedText;
12662
+ const annotations = renderedText?.match(FROZEN_TEXT_ANNOTATION_SUFFIX)?.[0] ?? "";
12663
+ return placeholder + annotations;
12664
+ }
12442
12665
  function applyNewToolDrop(target, options) {
12443
- if (options.persist && (target?.prepareDrop?.() ?? target?.canDrop?.()) === false) {
12666
+ const plan = planNewToolDrop(target, options, !!options.persist);
12667
+ if (!plan)
12444
12668
  return { result: "incomplete", mode: "full" };
12669
+ options.persist?.(plan.mode);
12670
+ return plan.apply();
12671
+ }
12672
+ function planNewToolDrop(target, options, prepare, plannedRemovals) {
12673
+ if (prepare && (target?.prepareDrop?.() ?? target?.canDrop?.()) === false) {
12674
+ return;
12445
12675
  }
12446
12676
  if (!target) {
12447
- options.persist?.("full");
12448
- return { result: "absent", mode: "full" };
12677
+ return { mode: "full", apply: () => ({ result: "absent", mode: "full" }) };
12449
12678
  }
12450
- if (options.inWindow && hasSmallToolInput(target) || options.keepSkeleton === true || target.cannotRemove?.() === true || target.wouldStrandConversationEnd?.() === true) {
12679
+ if (options.inWindow && hasSmallToolInput(target) || options.keepSkeleton === true || target.cannotRemove?.() === true || target.wouldStrandConversationEnd?.(plannedRemovals) === true) {
12451
12680
  const strip = target.hasAttachments?.() === true;
12452
- options.persist?.(strip ? "skeleton_stripped" : "skeleton_real");
12681
+ const mode = strip ? "skeleton_stripped" : "skeleton_real";
12453
12682
  return {
12454
- result: (strip ? target.skeletonStripped?.() : target.skeletonReal?.()) ?? "absent",
12455
- mode: strip ? "skeleton_stripped" : "skeleton_real"
12683
+ mode,
12684
+ apply: () => ({
12685
+ result: (strip ? target.skeletonStripped?.() : target.skeletonReal?.()) ?? "absent",
12686
+ mode
12687
+ })
12456
12688
  };
12457
12689
  }
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" };
12690
+ return {
12691
+ mode: "full",
12692
+ apply: () => {
12693
+ const result = target.drop?.() ?? "absent";
12694
+ if (result === "truncated" && target.hasAttachments?.() === true) {
12695
+ return {
12696
+ result: target.skeletonStripped?.() ?? "absent",
12697
+ mode: "skeleton_stripped"
12698
+ };
12699
+ }
12700
+ return { result, mode: result === "truncated" ? "skeleton_real" : "full" };
12701
+ }
12702
+ };
12464
12703
  }
12465
12704
  function hasSmallToolInput(target) {
12466
12705
  const bytes = target?.inputStringBytes?.() ?? null;
@@ -12504,6 +12743,7 @@ function prepareLegacyToolSkeletonConversions(db, sessionId, targets, options =
12504
12743
  AND drop_mode IN ('truncated', 'full')
12505
12744
  ORDER BY tag_number`).all(sessionId);
12506
12745
  const rows = readRows(db);
12746
+ options.prepareRemovals?.(rows);
12507
12747
  const identity = JSON.stringify(rows);
12508
12748
  const converted = new Map;
12509
12749
  for (const row of rows) {
@@ -12542,174 +12782,250 @@ function renderConvertedToolSkeletons(targets, converted) {
12542
12782
  }
12543
12783
  return didMutate;
12544
12784
  }
12785
+ var PENDING_OPERATION_CHUNK_SIZE = 64;
12786
+ var PENDING_OPERATION_REJECTED_LOG_CHUNK = 20;
12545
12787
  function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set, onTagReduced, onBatchComplete, onEligibilitySnapshot) {
12546
12788
  let didMutateMessage = false;
12547
12789
  let diagnostics;
12548
- const reject = (reason) => {
12790
+ const reject = (tagNumber, reason, state = {}) => {
12549
12791
  if (!diagnostics)
12550
12792
  return;
12551
12793
  diagnostics.reasons[reason] = (diagnostics.reasons[reason] ?? 0) + 1;
12794
+ const persisted = state.persisted === true;
12795
+ (diagnostics.rejected ??= []).push({
12796
+ tagNumber,
12797
+ reason,
12798
+ persisted,
12799
+ queueState: state.queueState ?? (persisted ? "removed" : "retained")
12800
+ });
12552
12801
  };
12553
12802
  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
- }
12803
+ let startedAt = 0;
12804
+ const mutations = [];
12805
+ let drainChunk;
12806
+ let hasMore = false;
12807
+ do {
12808
+ admitted = false;
12809
+ startedAt = 0;
12810
+ try {
12811
+ db.transaction(() => {
12812
+ admitted = true;
12813
+ startedAt = performance.now();
12814
+ if (drainChunk) {
12815
+ drainChunk();
12816
+ return;
12613
12817
  }
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);
12818
+ const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
12819
+ onEligibilitySnapshot?.(capturePendingDropEligibility(targets, protectedTagIds));
12820
+ const tags = preloadedTags ?? getTagsByNumbers(db, sessionId, [
12821
+ ...new Set([
12822
+ ...pendingOps.map((op) => op.tagId),
12823
+ ...syntheticPendingOps.map((op) => op.tagId)
12824
+ ])
12825
+ ]);
12826
+ const tagById = new Map(tags.map((tag) => [tag.tagNumber, tag]));
12827
+ const tagStatusById = new Map(tags.map((tag) => [tag.tagNumber, tag.status]));
12828
+ const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
12829
+ const opsToApply = [
12830
+ ...pendingOps.map((op) => ({ op, synthetic: false })),
12831
+ ...syntheticPendingOps.map((op) => ({ op, synthetic: true }))
12832
+ ];
12833
+ diagnostics = {
12834
+ source: pendingOps.length > 0 && syntheticPendingOps.length > 0 ? "mixed" : syntheticPendingOps.length > 0 ? "synthetic" : "pending",
12835
+ total: opsToApply.length,
12836
+ mutated: 0,
12837
+ persistedWithoutMutation: 0,
12838
+ reasons: {}
12839
+ };
12840
+ 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));
12841
+ const plannedRemovals = new Set;
12842
+ const removedTagIds = new Set;
12843
+ const record = (mutated) => {
12844
+ if (!diagnostics)
12845
+ return;
12846
+ if (mutated) {
12847
+ didMutateMessage = true;
12848
+ diagnostics.mutated += 1;
12849
+ } else
12850
+ diagnostics.persistedWithoutMutation += 1;
12851
+ };
12852
+ let cursor = 0;
12853
+ drainChunk = () => {
12854
+ const chunk = opsToApply.slice(cursor, cursor + PENDING_OPERATION_CHUNK_SIZE);
12855
+ cursor += chunk.length;
12856
+ hasMore = cursor < opsToApply.length;
12857
+ for (const { op: pendingOp, synthetic } of chunk) {
12858
+ const tagStatus = tagStatusById.get(pendingOp.tagId);
12859
+ if (tagStatus === "compacted" || tagStatus === "dropped") {
12860
+ reject(pendingOp.tagId, "already_reduced", {
12861
+ queueState: synthetic ? "none" : "removed"
12862
+ });
12621
12863
  if (!synthetic)
12622
12864
  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
12865
  continue;
12635
12866
  }
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}`);
12867
+ if (removedTagIds.has(pendingOp.tagId)) {
12868
+ reject(pendingOp.tagId, "drop_incomplete", {
12869
+ queueState: synthetic ? "none" : "retained"
12870
+ });
12640
12871
  continue;
12641
12872
  }
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}`);
12873
+ const target = targets.get(pendingOp.tagId);
12874
+ const veto = pendingDropVeto(pendingOp.tagId, target, protectedTagIds);
12875
+ if (veto) {
12876
+ reject(pendingOp.tagId, veto, {
12877
+ queueState: synthetic ? "none" : "retained"
12878
+ });
12653
12879
  continue;
12654
12880
  }
12655
- if (dropResult === "removed" || dropResult === "truncated") {
12656
- didMutateMessage = true;
12657
- operationMutated = true;
12658
- onTagReduced?.({
12659
- tagNumber: pendingOp.tagId,
12660
- mode: appliedMode === "full" ? "full" : "truncated"
12881
+ const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
12882
+ if (synthetic) {
12883
+ if (!isToolTag) {
12884
+ reject(pendingOp.tagId, "synthetic_non_tool", {
12885
+ queueState: "none"
12886
+ });
12887
+ continue;
12888
+ }
12889
+ if (target?.canDrop?.() !== true) {
12890
+ reject(pendingOp.tagId, "synthetic_target_not_droppable", {
12891
+ queueState: "none"
12892
+ });
12893
+ continue;
12894
+ }
12895
+ }
12896
+ const persistDrop = (mode) => {
12897
+ markTagDropped(db, sessionId, pendingOp.tagId, mode);
12898
+ if (!synthetic)
12899
+ removePendingOp(db, sessionId, pendingOp.tagId);
12900
+ };
12901
+ if (isToolTag) {
12902
+ if (editMarkerTagIds.has(pendingOp.tagId)) {
12903
+ const strip = target?.hasAttachments?.() === true;
12904
+ if (target?.canDrop?.() === false || target?.prepareDrop?.() === false || !target) {
12905
+ reject(pendingOp.tagId, "edit_marker_incomplete", {
12906
+ queueState: synthetic ? "none" : "retained"
12907
+ });
12908
+ continue;
12909
+ }
12910
+ persistDrop(strip ? "edit_marker_stripped" : "edit_marker");
12911
+ mutations.push(() => {
12912
+ const markResult = (strip ? target?.editMarkerStripped?.() : target?.editMarker?.()) ?? "absent";
12913
+ if (markResult === "incomplete" || markResult === "absent") {
12914
+ reject(pendingOp.tagId, `edit_marker_${markResult}`, {
12915
+ persisted: true,
12916
+ queueState: synthetic ? "none" : "removed"
12917
+ });
12918
+ return;
12919
+ }
12920
+ record(true);
12921
+ onTagReduced?.({
12922
+ tagNumber: pendingOp.tagId,
12923
+ mode: "edit_marker"
12924
+ });
12925
+ });
12926
+ } else {
12927
+ const plan = planNewToolDrop(target, { inWindow: skeletonWindow.has(pendingOp.tagId) }, true, plannedRemovals);
12928
+ if (!plan) {
12929
+ reject(pendingOp.tagId, "drop_incomplete", {
12930
+ queueState: synthetic ? "none" : "retained"
12931
+ });
12932
+ continue;
12933
+ }
12934
+ persistDrop(plan.mode);
12935
+ if (plan.mode === "full" && target?.drop) {
12936
+ target.notePlannedRemoval?.(plannedRemovals);
12937
+ removedTagIds.add(pendingOp.tagId);
12938
+ }
12939
+ mutations.push(() => {
12940
+ const { result: dropResult, mode: appliedMode } = plan.apply();
12941
+ if (dropResult === "incomplete" || synthetic && dropResult !== "removed" && dropResult !== "truncated") {
12942
+ reject(pendingOp.tagId, `drop_${dropResult}`, {
12943
+ persisted: true,
12944
+ queueState: synthetic ? "none" : "removed"
12945
+ });
12946
+ return;
12947
+ }
12948
+ if (dropResult === "removed" || dropResult === "truncated") {
12949
+ record(true);
12950
+ onTagReduced?.({
12951
+ tagNumber: pendingOp.tagId,
12952
+ mode: appliedMode === "full" ? "full" : "truncated"
12953
+ });
12954
+ } else {
12955
+ reject(pendingOp.tagId, `drop_${dropResult}`, {
12956
+ persisted: true,
12957
+ queueState: synthetic ? "none" : "removed"
12958
+ });
12959
+ record(false);
12960
+ }
12961
+ });
12962
+ }
12963
+ } else if (target) {
12964
+ const replacement = renderDroppedText(pendingOp.tagId, target.getContent?.());
12965
+ if (target.canSetContent?.(replacement) === false) {
12966
+ reject(pendingOp.tagId, "content_unchanged");
12967
+ continue;
12968
+ }
12969
+ persistDrop();
12970
+ mutations.push(() => {
12971
+ const priorContent = target.getContent?.();
12972
+ const changed = target.setContent(replacement);
12973
+ record(changed);
12974
+ if (changed) {
12975
+ const originalCharacters = typeof priorContent === "string" ? priorContent.length : tagById.get(pendingOp.tagId)?.byteSize ?? replacement.length;
12976
+ onTagReduced?.({
12977
+ tagNumber: pendingOp.tagId,
12978
+ mode: "partial",
12979
+ removedCharacters: Math.max(0, originalCharacters - replacement.length)
12980
+ });
12981
+ } else {
12982
+ reject(pendingOp.tagId, "content_unchanged", {
12983
+ persisted: true,
12984
+ queueState: "removed"
12985
+ });
12986
+ }
12661
12987
  });
12662
- } else {
12663
- reject(`drop_${dropResult}`);
12988
+ } else if (!synthetic) {
12989
+ persistDrop();
12990
+ reject(pendingOp.tagId, "target_absent", {
12991
+ persisted: true,
12992
+ queueState: "removed"
12993
+ });
12994
+ mutations.push(() => record(false));
12664
12995
  }
12665
- shouldPersistDrop = true;
12666
- }
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
12996
  }
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;
12997
+ };
12998
+ drainChunk();
12999
+ }).immediate();
13000
+ } catch (error) {
13001
+ if (!admitted && /database (?:table )?is locked|sqlite_(busy|locked)/i.test(String(error))) {
13002
+ sessionLog(sessionId, "pending operations write admission busy; retaining remaining operations for retry");
13003
+ hasMore = false;
13004
+ } else {
13005
+ throw error;
12698
13006
  }
13007
+ } finally {
13008
+ if (startedAt)
13009
+ logSlowWriteTransaction("apply_pending_operations", startedAt);
12699
13010
  }
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
- }
13011
+ for (const mutate of mutations.splice(0))
13012
+ mutate();
13013
+ } while (hasMore);
12707
13014
  if (diagnostics) {
12708
13015
  onBatchComplete?.(diagnostics);
12709
13016
  if (diagnostics.total > 0 && diagnostics.mutated === 0) {
12710
13017
  const reasons = Object.entries(diagnostics.reasons).sort(([left], [right]) => left.localeCompare(right)).map(([reason, count]) => `${reason}:${count}`).join(",");
12711
13018
  sessionLog(sessionId, `pending operations no-op: source=${diagnostics.source} total=${diagnostics.total} persisted=${diagnostics.persistedWithoutMutation} reasons=${reasons || "none"}`);
12712
13019
  }
13020
+ const rejected = diagnostics.rejected;
13021
+ if (rejected && rejected.length > 0) {
13022
+ const lineCount = Math.ceil(rejected.length / PENDING_OPERATION_REJECTED_LOG_CHUNK);
13023
+ for (let offset = 0;offset < rejected.length; offset += PENDING_OPERATION_REJECTED_LOG_CHUNK) {
13024
+ const entries = rejected.slice(offset, offset + PENDING_OPERATION_REJECTED_LOG_CHUNK).map((entry) => `${entry.tagNumber}:${entry.reason}:${entry.queueState}${entry.persisted ? ":persisted" : ""}`).join(",");
13025
+ const chunkLabel = lineCount > 1 ? ` chunk=${Math.floor(offset / PENDING_OPERATION_REJECTED_LOG_CHUNK) + 1}/${lineCount}` : "";
13026
+ sessionLog(sessionId, `pending operations rejected: source=${diagnostics.source} total=${diagnostics.total} mutated=${diagnostics.mutated} persisted=${diagnostics.persistedWithoutMutation}${chunkLabel} rejected=${entries}`);
13027
+ }
13028
+ }
12713
13029
  }
12714
13030
  return didMutateMessage;
12715
13031
  }
@@ -12750,7 +13066,7 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
12750
13066
  }
12751
13067
  }
12752
13068
  } else if (target) {
12753
- const changed = target.setContent(buildReplacementContent(tag.tagNumber));
13069
+ const changed = target.setContent(renderDroppedText(tag.tagNumber, target.getContent?.()));
12754
13070
  if (changed)
12755
13071
  didMutateMessage = true;
12756
13072
  }
@@ -12937,10 +13253,41 @@ function createExistingTagResolver(sessionId, tagger, db) {
12937
13253
  }
12938
13254
 
12939
13255
  // src/hooks/magic-context/transform-stage-logger.ts
12940
- function logTransformTiming(sessionId, stage, startMs, extra) {
12941
- const elapsed = (performance.now() - startMs).toFixed(1);
13256
+ import { AsyncLocalStorage } from "node:async_hooks";
13257
+ var SLOW_STAGE_MS = 100;
13258
+ var passes = new AsyncLocalStorage;
13259
+ async function withTransformTimingSummary(run) {
13260
+ const pass = {
13261
+ stages: [],
13262
+ slow: [],
13263
+ closed: false,
13264
+ sessionId: undefined
13265
+ };
13266
+ return passes.run(pass, async () => {
13267
+ try {
13268
+ return await run();
13269
+ } finally {
13270
+ pass.closed = true;
13271
+ if (pass.sessionId)
13272
+ sessionLog(pass.sessionId, `transform stages: ${pass.stages.join(" ")} slow>=${SLOW_STAGE_MS}ms=[${pass.slow.join(",")}]`);
13273
+ }
13274
+ });
13275
+ }
13276
+ function logTransformElapsed(sessionId, stage, elapsedMs, extra) {
13277
+ const elapsed = elapsedMs.toFixed(1);
12942
13278
  const suffix = extra ? ` ${extra}` : "";
12943
- sessionLog(sessionId, `transform stage: stage=${stage} elapsed=${elapsed}ms${suffix}`);
13279
+ const pass = passes.getStore();
13280
+ if (pass && !pass.closed) {
13281
+ pass.sessionId = sessionId;
13282
+ pass.stages.push(`${stage}=${elapsed}ms${extra ? `(${extra})` : ""}`);
13283
+ if (elapsedMs >= SLOW_STAGE_MS)
13284
+ pass.slow.push(stage);
13285
+ }
13286
+ if (elapsedMs >= SLOW_STAGE_MS)
13287
+ sessionLog(sessionId, `transform stage: stage=${stage} elapsed=${elapsed}ms${suffix}`);
13288
+ }
13289
+ function logTransformTiming(sessionId, stage, startMs, extra) {
13290
+ logTransformElapsed(sessionId, stage, performance.now() - startMs, extra);
12944
13291
  }
12945
13292
 
12946
13293
  // src/hooks/magic-context/tag-messages.ts
@@ -13318,13 +13665,19 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13318
13665
  }));
13319
13666
  accAssignTag += performance.now() - _tAssignText;
13320
13667
  const persistedSource = sourceContents.get(tagId);
13321
- if (persistedSource !== undefined) {
13322
- textPart.text = options.normalizeRestoredAssistantText && message.info.role === "assistant" ? options.normalizeRestoredAssistantText(persistedSource) : persistedSource;
13668
+ if (persistedSource !== undefined && !options.refreshSourceContents) {
13669
+ textPart.text = options.normalizeRestoredAssistantText && message.info.role === "assistant" ? options.normalizeRestoredAssistantText(persistedSource, message.info.providerID) : persistedSource;
13323
13670
  } else {
13324
13671
  const sourceContent = stripTagPrefix(textPart.text);
13325
- if (sourceContent.trim().length > 0) {
13672
+ if (sourceContent.trim().length > 0 || options.refreshSourceContents) {
13326
13673
  const _tSaveText = performance.now();
13327
- saveSourceContent(db, sessionId, tagId, sourceContent);
13674
+ if (options.refreshSourceContents) {
13675
+ db.transaction(() => {
13676
+ replaceSourceContent(db, sessionId, tagId, sourceContent);
13677
+ db.prepare("UPDATE tags SET byte_size = ?, token_count = ? WHERE session_id = ? AND tag_number = ?").run(byteSize(sourceContent), estimateTextTagTokenCount(sourceContent), sessionId, tagId);
13678
+ }).immediate();
13679
+ } else
13680
+ saveSourceContent(db, sessionId, tagId, sourceContent);
13328
13681
  accSaveSource += performance.now() - _tSaveText;
13329
13682
  }
13330
13683
  }
@@ -13343,6 +13696,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13343
13696
  dropReasoningParts: thinkingParts,
13344
13697
  mutationParts: [{ message, part: textPart }],
13345
13698
  textPrefix: skipPrefixInjection ? "" : prependTag(tagId, ""),
13699
+ canSetContent: (content) => textPart.text !== content,
13346
13700
  setContent: (content, options) => {
13347
13701
  if (textPart.text === content)
13348
13702
  return false;
@@ -13400,26 +13754,20 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13400
13754
  const filePart = part;
13401
13755
  const messageParts = message.parts;
13402
13756
  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
- }
13757
+ const existingTagId = resolver.resolve(messageId, "file", contentId, fileOrdinal) ?? getTagNumberByMessageId(db, sessionId, contentId) ?? undefined;
13758
+ fileOrdinal += 1;
13759
+ if (existingTagId === undefined)
13760
+ continue;
13761
+ const tagId = existingTagId;
13762
+ tagger.bindTag(sessionId, contentId, tagId);
13419
13763
  messageTagNumbers.set(message, Math.max(messageTagNumbers.get(message) ?? 0, tagId));
13420
13764
  targets.set(tagId, {
13421
13765
  message,
13422
13766
  mutationParts: [{ message, part: filePart }],
13767
+ canSetContent: (content) => {
13768
+ const current = messageParts[partIndex];
13769
+ return !(typeof current === "object" && current !== null && ("text" in current) && current.text === content);
13770
+ },
13423
13771
  setContent: (content) => {
13424
13772
  const prev = messageParts[partIndex];
13425
13773
  const prevText = typeof prev === "object" && prev !== null && "text" in prev ? prev.text : "";
@@ -13432,7 +13780,6 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13432
13780
  return true;
13433
13781
  }
13434
13782
  });
13435
- fileOrdinal += 1;
13436
13783
  }
13437
13784
  }
13438
13785
  if (message.info.role === "assistant" && !messageHasTextPart) {
@@ -13461,6 +13808,23 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13461
13808
  normalizationTargets
13462
13809
  };
13463
13810
  }
13811
+ // src/features/magic-context/storage-host-instruction-retention.ts
13812
+ var NAMESPACE3 = "hostInstructionRetention";
13813
+ function isHostInstructionRetentionOn(db, sessionId) {
13814
+ const lane = readReplayEnvelope(db, sessionId)[NAMESPACE3];
13815
+ return typeof lane === "object" && lane !== null && lane.on === true;
13816
+ }
13817
+ function markHostInstructionRetention(db, sessionId) {
13818
+ return updateReplayDocument(db, sessionId, (doc) => {
13819
+ const lane = doc[NAMESPACE3];
13820
+ if (typeof lane === "object" && lane !== null && lane.on === true)
13821
+ return false;
13822
+ doc.version = 2;
13823
+ doc[NAMESPACE3] = { on: true };
13824
+ return true;
13825
+ });
13826
+ }
13827
+
13464
13828
  // src/hooks/magic-context/channel2-cycle.ts
13465
13829
  function rearmChannel2AfterCoverageAdvancingHardFold(input) {
13466
13830
  if (input.compactionOff || !input.foldExecuted || input.previousCoverage === null || input.currentCoverage === null || input.currentCoverage <= input.previousCoverage) {
@@ -14374,6 +14738,28 @@ function freezeReasoningOnBustingPass(args) {
14374
14738
  sessionLog(args.sessionId, `proactive thinking strip: busting pass froze reasoning of ${messageIds.length} assistant(s) [${messageIds.join(",")}]`);
14375
14739
  return { strip: { messageIds }, persistenceFailed: false };
14376
14740
  }
14741
+ function servesThinkingBlock(messages) {
14742
+ for (const message of messages) {
14743
+ if (message.info.role !== "assistant")
14744
+ continue;
14745
+ for (const part of message.parts) {
14746
+ if (!isRecord(part) || part.ignored === true)
14747
+ continue;
14748
+ if (part.type === "redacted_thinking")
14749
+ return true;
14750
+ if (part.type !== "reasoning" && part.type !== "thinking")
14751
+ continue;
14752
+ const anthropic = isRecord(part.metadata) ? part.metadata.anthropic : undefined;
14753
+ if (!isRecord(anthropic))
14754
+ continue;
14755
+ if (anthropic.redactedData !== undefined)
14756
+ return true;
14757
+ if (typeof part.text === "string" && part.text !== "")
14758
+ return true;
14759
+ }
14760
+ }
14761
+ return false;
14762
+ }
14377
14763
  function dropMarkerSummaryTag(db, sessionId, summaryMessageId) {
14378
14764
  const tagNumber = getTagNumberByMessageId(db, sessionId, `${summaryMessageId}:p0`);
14379
14765
  if (tagNumber !== null)
@@ -14537,7 +14923,7 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
14537
14923
  clearedParts = stripClearedReasoning(targetedMessages.filter((message) => !restoredMessages.has(message)));
14538
14924
  }
14539
14925
  }
14540
- const bindingRecoveryParts = options?.skipMergedReasoningStrip ? 0 : stripReasoningFromAssistantIds(messages, resolvedProviderID, options?.frozenThinkingBindingMessageIds ?? new Set, restoredMessages);
14926
+ const bindingRecoveryParts = stripReasoningFromAssistantIds(messages, resolvedProviderID, options?.frozenThinkingBindingMessageIds ?? new Set, restoredMessages);
14541
14927
  const mergedReasoningParts = bindingRecoveryParts + (options?.skipMergedReasoningStrip ? 0 : stripReasoningFromMergedAssistants(messages, resolvedProviderID, {
14542
14928
  mutationExemptMessage: options?.reasoningMutationExemptMessage,
14543
14929
  frozenMessageIds: options?.mergedReasoningStrippedIds,
@@ -14614,7 +15000,7 @@ async function runPostTransformPhase(args) {
14614
15000
  let deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
14615
15001
  let materializationRequested = isExplicitFlush || deferredMaterialize;
14616
15002
  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) : []);
15003
+ const frozenThinking = new Set(getMergedReasoningStrippedIds(args.db, args.sessionId));
14618
15004
  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
15005
  const retainedThinking = args.activeThinkingTurn ? retainedActiveThinkingParts({
14620
15006
  messages: args.messages,
@@ -14640,6 +15026,7 @@ async function runPostTransformPhase(args) {
14640
15026
  let freezeM0M1 = args.freezeM0M1 === true || activeThinkingPrefixHold;
14641
15027
  let rewritingSignedPrefix = false;
14642
15028
  let thinkingReleasedForFit = false;
15029
+ let thinkingOmissionPersistenceFailed = false;
14643
15030
  const releaseThinkingForRewrite = (forFit = false) => {
14644
15031
  const stripped = freezeReasoningOnBustingPass({
14645
15032
  db: args.db,
@@ -14647,8 +15034,12 @@ async function runPostTransformPhase(args) {
14647
15034
  messages: args.messages,
14648
15035
  alreadyFrozen: bindingThinking
14649
15036
  });
14650
- if (stripped.persistenceFailed)
15037
+ if (stripped.persistenceFailed) {
15038
+ thinkingOmissionPersistenceFailed = true;
14651
15039
  throw new Error("Cannot persist signed thinking omission before prefix rewrite");
15040
+ }
15041
+ for (const id of stripped.strip?.messageIds ?? [])
15042
+ bindingThinking.add(id);
14652
15043
  retainedThinking.clear();
14653
15044
  protectedThinkingMessages.clear();
14654
15045
  activeThinkingTurn = false;
@@ -14658,6 +15049,9 @@ async function runPostTransformPhase(args) {
14658
15049
  rewritingSignedPrefix = true;
14659
15050
  thinkingReleasedForFit ||= forFit;
14660
15051
  };
15052
+ if (args.compactionModeTransition && args.thinkingBindingRecoveryEnabledForModel) {
15053
+ releaseThinkingForRewrite();
15054
+ }
14661
15055
  const foldDueDecision = m0M1EnabledForFold && args.m0M1 && !freezeM0M1 ? mustMaterialize({
14662
15056
  db: args.db,
14663
15057
  sessionId: args.sessionId,
@@ -14693,6 +15087,8 @@ async function runPostTransformPhase(args) {
14693
15087
  };
14694
15088
  if ((foldDueDecision.value || softRefreshOpportunity || firstRenderBust && activeThinkingPrefixHold) && m0M1EnabledForFold && args.m0M1) {
14695
15089
  let committedFoldBustsServedPrefix;
15090
+ let committedFoldChangesHead = false;
15091
+ let committedFoldThinkingIds = [];
14696
15092
  try {
14697
15093
  const previousM1 = args.sessionMeta.cachedM1Bytes?.toString("utf8");
14698
15094
  const foldResult = injectM0M1({
@@ -14719,6 +15115,24 @@ async function runPostTransformPhase(args) {
14719
15115
  m0Text: rendered.m0Bytes.toString(),
14720
15116
  m1Text: rendered.m1Bytes.toString()
14721
15117
  }) : foldBustsServedPrefix(foldDueDecision.reason, servedPrefixBeforeFold, rendered);
15118
+ committedFoldChangesHead = firstRenderBust ? !servedPrefixMatches({
15119
+ messages: servedBeforeFirstRender,
15120
+ m0Text: rendered.m0Bytes.toString(),
15121
+ m1Text: rendered.m1Bytes.toString()
15122
+ }) : foldChangesServedPrefix(servedPrefixBeforeFold, rendered);
15123
+ if (args.thinkingBindingRecoveryEnabledForModel && (compactionOff && !activeThinkingPrefixHold && committedFoldChangesHead || activeThinkingPrefixHold && firstRenderBust && bustsPrefix)) {
15124
+ const omission = freezeReasoningOnBustingPass({
15125
+ db,
15126
+ sessionId: args.sessionId,
15127
+ messages: args.messages,
15128
+ alreadyFrozen: bindingThinking
15129
+ });
15130
+ if (omission.persistenceFailed) {
15131
+ thinkingOmissionPersistenceFailed = true;
15132
+ throw new Error("Cannot persist signed thinking omission before prefix rewrite");
15133
+ }
15134
+ committedFoldThinkingIds = omission.strip?.messageIds ?? [];
15135
+ }
14722
15136
  if (bustsPrefix) {
14723
15137
  if (!conversions.isCurrent(db)) {
14724
15138
  throw new MaterializeContentionError({
@@ -14735,7 +15149,13 @@ async function runPostTransformPhase(args) {
14735
15149
  }
14736
15150
  });
14737
15151
  preparedPrefix = foldResult;
14738
- if (activeThinkingPrefixHold && firstRenderBust && committedFoldBustsServedPrefix) {
15152
+ if (foldResult.m0RematerializedThisPass) {
15153
+ for (const id of committedFoldThinkingIds)
15154
+ bindingThinking.add(id);
15155
+ }
15156
+ if (foldResult.m0RematerializedThisPass && activeThinkingPrefixHold && firstRenderBust && committedFoldBustsServedPrefix) {
15157
+ releaseThinkingForRewrite();
15158
+ } else if (compactionOff && foldResult.m0RematerializedThisPass && !activeThinkingPrefixHold && args.thinkingBindingRecoveryEnabledForModel && committedFoldChangesHead) {
14739
15159
  releaseThinkingForRewrite();
14740
15160
  }
14741
15161
  prefixPreflightFailed = foldResult.materializationContentionRetryExhausted === true;
@@ -14764,6 +15184,8 @@ async function runPostTransformPhase(args) {
14764
15184
  sessionLog(args.sessionId, "channel2 fold-cycle reset failed (ignored):", error);
14765
15185
  }
14766
15186
  } catch (error) {
15187
+ if (thinkingOmissionPersistenceFailed)
15188
+ throw error;
14767
15189
  preparedPrefix = cachedPrefixBeforePreflight;
14768
15190
  prefixPreflightFailed = true;
14769
15191
  failPass("m0-m1-fold-preexecution-degradation", error);
@@ -14881,17 +15303,28 @@ async function runPostTransformPhase(args) {
14881
15303
  throw new EmergencyFailClosedError("Magic Context could not read its saved reasoning-removal state for this session", { cause: error });
14882
15304
  }
14883
15305
  }
15306
+ const heuristicsLogChanged = diagnosticStateChanged(args.sessionId, "heuristics", JSON.stringify([
15307
+ args.currentTurnId,
15308
+ shouldRunHeuristics,
15309
+ shouldRunHeuristics ? null : args.schedulerDeferReason
15310
+ ]));
15311
+ const pendingLogChanged = diagnosticStateChanged(args.sessionId, "pending-ops", JSON.stringify([
15312
+ args.currentTurnId,
15313
+ shouldApplyPendingOps,
15314
+ shouldApplyPendingOps ? null : args.schedulerDeferReason,
15315
+ shouldApplyPendingOps ? null : (getPendingOpsCount(args.db, args.sessionId) ?? 0) > 0
15316
+ ]));
14884
15317
  if (shouldRunHeuristics) {
14885
15318
  const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
14886
15319
  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
15320
  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) {
15321
+ } else if (heuristicsLogChanged && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
14889
15322
  sessionLog(args.sessionId, `heuristics WILL NOT RUN — reason=${args.schedulerDeferReason}`);
14890
15323
  }
14891
15324
  if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
14892
15325
  sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
14893
15326
  }
14894
- if (!shouldApplyPendingOps && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
15327
+ if (!shouldApplyPendingOps && pendingLogChanged && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
14895
15328
  sessionLog(args.sessionId, `pending ops WILL NOT APPLY — reason=${args.schedulerDeferReason} pendingOps=${formatPendingOpsDepth()} context=${args.contextUsage.percentage.toFixed(1)}%`);
14896
15329
  }
14897
15330
  if (hasPendingUserOps && !shouldApplyPendingOps) {
@@ -15278,6 +15711,30 @@ async function runPostTransformPhase(args) {
15278
15711
  }
15279
15712
  }
15280
15713
  const m0M1Enabled = m0M1EnabledForFold;
15714
+ let retainCoveredInstructions = false;
15715
+ if (m0M1Enabled && args.m0M1 && !compactionOff && args.hostInstructionRows) {
15716
+ const covered = args.coveredHostInstructions ?? [];
15717
+ if (covered.length > 0 || canEditWholePrefix) {
15718
+ let retain = false;
15719
+ try {
15720
+ retain = isHostInstructionRetentionOn(args.db, args.sessionId);
15721
+ } catch (error) {
15722
+ failPass("host-instruction-retention-read-failure", error);
15723
+ }
15724
+ if (!retain && canEditWholePrefix) {
15725
+ let written = false;
15726
+ try {
15727
+ written = markHostInstructionRetention(args.db, args.sessionId);
15728
+ } catch (error) {
15729
+ failPass("host-instruction-retention-persistence-failure", error);
15730
+ }
15731
+ if (!written)
15732
+ failPass("host-instruction-retention-persistence-failure");
15733
+ retain = true;
15734
+ }
15735
+ retainCoveredInstructions = retain;
15736
+ }
15737
+ }
15281
15738
  if (m0M1Enabled && args.m0M1) {
15282
15739
  if (freezeM0M1 && !preparedPrefix) {
15283
15740
  preparedPrefix = prepareCachedM0M1Replay(args.db, args.sessionId);
@@ -15305,6 +15762,17 @@ async function runPostTransformPhase(args) {
15305
15762
  compactionOff
15306
15763
  });
15307
15764
  deliveredPrefix = result;
15765
+ if (retainCoveredInstructions) {
15766
+ const retained = new Set(args.messages);
15767
+ const covered = [...args.coveredHostInstructions ?? []];
15768
+ for (const message of messagesBeforeInjection) {
15769
+ if (!retained.has(message) && isHostRenderedSystemMessage(message)) {
15770
+ markCoveredInstructionRow(message.info);
15771
+ covered.push(message);
15772
+ }
15773
+ }
15774
+ args.messages.splice(result.prependedMessageCount, 0, ...covered);
15775
+ }
15308
15776
  if (result.prefixTrimStatus === "applied") {
15309
15777
  const retainedMessages = new Set(args.messages);
15310
15778
  const trimmedMessageIds = messagesBeforeInjection.filter((message) => !retainedMessages.has(message)).map((message) => message.info.id).filter((id) => typeof id === "string");
@@ -15575,7 +16043,7 @@ async function runPostTransformPhase(args) {
15575
16043
  }
15576
16044
  }
15577
16045
  const mergedReasoningStrippedIds = new Set(replaySnapshot?.mergedReasoningStrippedIds ?? []);
15578
- const thinkingBindingRecoveryMessageIds = new Set;
16046
+ const thinkingBindingRecoveryMessageIds = new Set(bindingThinking);
15579
16047
  let thinkingBindingRecovery = null;
15580
16048
  let proactiveThinkingStrip = null;
15581
16049
  if (!compactionOff) {
@@ -16080,7 +16548,9 @@ function createTransform(deps) {
16080
16548
  const loadedSessions = new Set;
16081
16549
  const prefixHoldLogTurnIds = new Map;
16082
16550
  const thinkingFitRetries = new Set;
16551
+ const compactionModeTransitionPending = new Set;
16083
16552
  const clearSessionLogState = (sessionId) => {
16553
+ clearDiagnosticLogState(sessionId);
16084
16554
  prefixHoldLogTurnIds.delete(sessionId);
16085
16555
  };
16086
16556
  const unmanagedOverWindowSessions = new Set;
@@ -16101,7 +16571,8 @@ function createTransform(deps) {
16101
16571
  const startTime = performance.now();
16102
16572
  const historianRun = deps.resolveHistorianRun?.();
16103
16573
  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;
16574
+ const entryOrderForThinkingFit = messages.slice();
16575
+ const coveredHostInstructions = takeCoveredInstructionRows(messages);
16105
16576
  const passOutcome = createPassOutcome();
16106
16577
  const tSessionId = performance.now();
16107
16578
  const sessionId = findSessionId(messages);
@@ -16115,8 +16586,21 @@ function createTransform(deps) {
16115
16586
  const temporalReplayIds = temporalCandidates ? messages.flatMap((message) => message.info.id ? [message.info.id] : []) : undefined;
16116
16587
  logTransformTiming(sessionId, "findSessionId", tSessionId, `messages=${messages.length}`);
16117
16588
  const tLkgEntry = performance.now();
16118
- const lkgInput = projectEntry(sessionId, messages);
16589
+ const lkgInput = projectEntry(sessionId, entryOrderForThinkingFit);
16119
16590
  const recovery = deps.compactionOff ? {} : readLkgRecoveryPrefix(sessionId, lkgInput, messages, deps.db);
16591
+ const recoveryTailSources = [];
16592
+ if (recovery.prefix) {
16593
+ const priorIdentities = new Set(recovery.prefix.inputs.map((input) => input.id));
16594
+ lkgInput.forEach((input, index) => {
16595
+ const identity = lkgInputIdentity(input.id, input.role, index);
16596
+ if (!identity || priorIdentities.has(identity))
16597
+ return;
16598
+ recoveryTailSources.push({
16599
+ identity,
16600
+ pristineSystem: input.id === null && input.role === "system" ? structuredClone(entryOrderForThinkingFit[index]) : undefined
16601
+ });
16602
+ });
16603
+ }
16120
16604
  logTransformTiming(sessionId, "lkg.entryProjection", tLkgEntry, entryReuse ? `reused=${entryReuse.reused} retained=${entryReuse.retained} retainedBytes=${entryReuse.retainedBytes}` : undefined);
16121
16605
  const resolvedSessionId = sessionId;
16122
16606
  const runNotificationParams = (sid) => {
@@ -16199,6 +16683,7 @@ function createTransform(deps) {
16199
16683
  const hasTransitionEffects = transition.recordToWrite !== null || transition.notice !== null || transition.invalidatedM0Baseline || transition.clearedCompartmentInProgress || transition.historianCatchUpSignaled;
16200
16684
  if (hasTransitionEffects) {
16201
16685
  if (transition.invalidatedM0Baseline) {
16686
+ compactionModeTransitionPending.add(sessionId);
16202
16687
  sessionMeta = {
16203
16688
  ...sessionMeta,
16204
16689
  cachedM0Bytes: null,
@@ -16417,6 +16902,13 @@ function createTransform(deps) {
16417
16902
  activeThinkingTurn ||= hasActiveAnthropicThinkingTurn(messages, resolvedProviderID, modelForBudget?.modelID);
16418
16903
  activeThinkingPrefixHold ||= activeThinkingTurn && isPrefixBoundThinkingModel(resolvedProviderID, modelForBudget?.modelID);
16419
16904
  freezeM0M1 ||= activeThinkingPrefixHold;
16905
+ const originalForThinkingFit = takeSignedThinkingFitSnapshot({
16906
+ sessionId,
16907
+ entryOrder: entryOrderForThinkingFit,
16908
+ held: activeThinkingPrefixHold,
16909
+ activeAnthropicThinkingTurn: activeThinkingTurn,
16910
+ compactionOff
16911
+ });
16420
16912
  if (freezeM0M1 && prefixHoldLogTurnIds.get(sessionId) !== currentTurnId) {
16421
16913
  prefixHoldLogTurnIds.set(sessionId, currentTurnId);
16422
16914
  const reason = activeThinkingPrefixHold ? "active thinking turn (prefix-bound model)" : "session directory unresolved";
@@ -16441,7 +16933,8 @@ function createTransform(deps) {
16441
16933
  systemPromptTokens: sessionMeta.systemPromptTokens,
16442
16934
  providerID: modelForBudget?.providerID,
16443
16935
  modelID: modelForBudget?.modelID,
16444
- agentName: runNotificationParams(sessionId)?.agent
16936
+ agentName: runNotificationParams(sessionId)?.agent,
16937
+ sessionId
16445
16938
  });
16446
16939
  const incomingTokens = incoming.messageTokens.conversation + incoming.messageTokens.toolCall;
16447
16940
  if (unmanagedOverWindowCarried || isClearlyOverWindow(incomingTokens, resolvedContextLimit)) {
@@ -16627,8 +17120,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16627
17120
  recordedSessionProjectIdentity.set(sessionId, sessionIdentityForBinding);
16628
17121
  }
16629
17122
  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`);
17123
+ const tagFloorMode = compactionOff || messages.length === 0 ? "inactive" : taggerFloor === 0 ? "fallback" : "scoped";
17124
+ if (diagnosticStateChanged(sessionId, "tag-floor", tagFloorMode) && tagFloorMode !== "inactive") {
17125
+ 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
17126
  }
16633
17127
  const ownerRatio = sessionDecisionCalibration(db, sessionId).proseRatio;
16634
17128
  prewarmTagOwners(db, sessionId, ownerRatio);
@@ -16677,7 +17171,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16677
17171
  const messagesBeforeInitialPrepare = isCacheBusting && deferredHistoryWasPendingAtPassStart ? [...messages] : null;
16678
17172
  if (fullFeatureMode && !compactionOff) {
16679
17173
  const tInj = performance.now();
16680
- pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness);
17174
+ pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness, coveredHostInstructions);
16681
17175
  if (messagesBeforeInitialPrepare) {
16682
17176
  const skippedVisibleMessages = pendingCompartmentInjection?.skippedVisibleMessages ?? 0;
16683
17177
  trimmedMessagesAtCompactionBoundary = messagesBeforeInitialPrepare.slice(0, skippedVisibleMessages);
@@ -16707,6 +17201,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16707
17201
  logTransformTiming(sessionId, "injectTemporalMarkers", tTemporal);
16708
17202
  }
16709
17203
  let taggingSucceeded = false;
17204
+ const refreshSourceContents = deps.storeGeneration === "v2" && fullFeatureMode && !compactionOff && !!(projectIdentity || sessionDirectory) && !unresolvedDirectoryHold && !recovery.prefix && sessionMeta.cachedM0Bytes == null && sessionMeta.cachedM1Bytes == null && deps.refreshSourceContents?.(sessionId) === true;
16710
17205
  let recoveryBatch = null;
16711
17206
  let recoveryNormalized = false;
16712
17207
  const normalizeRecoveryTail = recovery.prefix ? () => {
@@ -16742,7 +17237,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16742
17237
  scopedToolSweep,
16743
17238
  servedMessages: messages,
16744
17239
  protectedThinkingMessages: protectedThinkingMessagesForPass,
16745
- normalizeRestoredAssistantText: deps.normalizeRestoredAssistantText
17240
+ normalizeRestoredAssistantText: deps.normalizeRestoredAssistantText,
17241
+ refreshSourceContents
16746
17242
  });
16747
17243
  targets = result.targets;
16748
17244
  if (thinkingRecovery.restore)
@@ -16823,6 +17319,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16823
17319
  const rawGetNotifParams = runNotificationParams;
16824
17320
  const tCompartmentPhase = performance.now();
16825
17321
  const compartmentPhase = await runCompartmentPhase({
17322
+ coveredHostInstructions,
16826
17323
  hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
16827
17324
  compactionMarkerStrategy: deps.compactionMarkerStrategy,
16828
17325
  canRunCompartments,
@@ -16925,7 +17422,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16925
17422
  systemPromptTokens: sessionMeta.systemPromptTokens,
16926
17423
  providerID: modelForBudget?.providerID,
16927
17424
  modelID: modelForBudget?.modelID,
16928
- agentName: notificationParams.agent
17425
+ agentName: notificationParams.agent,
17426
+ sessionId
16929
17427
  });
16930
17428
  contextUsage = resolveUnknownUsageFromWireEstimate({
16931
17429
  usage: contextUsage,
@@ -16989,6 +17487,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16989
17487
  fullFeatureMode,
16990
17488
  compactionOff,
16991
17489
  canRunCompartments,
17490
+ hostInstructionRows: deps.storeGeneration === "v2",
16992
17491
  awaitedCompartmentRun,
16993
17492
  phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
16994
17493
  compartmentInProgress,
@@ -16997,6 +17496,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16997
17496
  activeThinkingPrefixHold,
16998
17497
  directoryPrefixHold: unresolvedDirectoryHold,
16999
17498
  forceSignedRebuildForFit: thinkingFitRetries.has(sessionId) || !!recovery.rebuildReason,
17499
+ compactionModeTransition: compactionModeTransitionPending.has(sessionId),
17000
17500
  readLastServedMessages: () => {
17001
17501
  const slot = getInMemorySlot(sessionId) ?? loadPersistedLkgSlot(db, sessionId);
17002
17502
  try {
@@ -17026,6 +17526,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17026
17526
  emergencyCeilingTokens,
17027
17527
  pendingCompartmentInjection,
17028
17528
  prefixTrimSourceOrder,
17529
+ coveredHostInstructions,
17029
17530
  hiddenMessagesAtCompactionSeam,
17030
17531
  trimmedMessagesAtCompactionBoundary,
17031
17532
  didMutateFromFlushedStatuses,
@@ -17053,9 +17554,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17053
17554
  }
17054
17555
  });
17055
17556
  if (recovery.prefix && !recoveryNormalized) {
17056
- const priorIds = new Set(recovery.prefix.inputs.map((input) => input.id));
17057
- const newIds = new Set(lkgInput.flatMap((input) => input.id && !priorIds.has(input.id) ? [input.id] : []));
17058
- const suffix = messages.filter((message) => message.info.id && newIds.has(message.info.id));
17557
+ const renderedById = new Map;
17558
+ for (const message of messages) {
17559
+ if (!message.info.id)
17560
+ continue;
17561
+ const group = renderedById.get(message.info.id) ?? [];
17562
+ group.push(message);
17563
+ renderedById.set(message.info.id, group);
17564
+ }
17565
+ const suffix = recoveryTailSources.flatMap(({ identity, pristineSystem }) => pristineSystem ? [pristineSystem] : renderedById.get(identity) ?? []);
17059
17566
  messages.splice(0, messages.length, ...JSON.parse(recovery.prefix.json), ...suffix);
17060
17567
  }
17061
17568
  const recoveryReleaseReason = recovery.rebuildReason ?? (recoveryNormalized ? "recovery_tail_normalized" : undefined);
@@ -17072,6 +17579,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17072
17579
  providerID: modelForBudget?.providerID,
17073
17580
  modelID: modelForBudget?.modelID,
17074
17581
  agentName: notificationParams.agent,
17582
+ sessionId,
17075
17583
  systemPromptHash: sessionMeta.systemPromptHash
17076
17584
  }, boundaryContextLimit);
17077
17585
  } catch {
@@ -17086,13 +17594,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17086
17594
  providerID: modelForBudget?.providerID,
17087
17595
  modelID: modelForBudget?.modelID,
17088
17596
  agentName: notificationParams.agent,
17597
+ sessionId,
17089
17598
  systemPromptHash: sessionMeta.systemPromptHash
17090
17599
  }, boundaryContextLimit) : undefined);
17091
17600
  if (finalWireEstimate) {
17092
17601
  sessionLog(sessionId, `transform: final-wire telemetry estimate=${finalWireEstimate.tokens} trusted=${finalWireEstimate.trusted} conversation=${finalWireEstimate.messageTokens.conversation} tools=${finalWireEstimate.messageTokens.toolCall} system=${finalWireEstimate.systemTokens} toolDefinitions=${finalWireEstimate.toolDefinitionTokens ?? "unknown"} tail=${finalWireTail}`);
17093
17602
  }
17094
17603
  if ((finalWireEstimate?.refusalGrade || finalWireEstimate?.refusalBasis === "byte-bound" && finalWireEstimate.refusalTokens !== undefined) && boundaryContextLimit > 0 && (finalWireEstimate.refusalTokens ?? finalWireEstimate.tokens) > boundaryContextLimit) {
17095
- if (!thinkingFitRetries.has(sessionId) && activeThinkingPrefixHold && originalForThinkingFit && hasActiveAnthropicThinkingTurn(messages, resolvedProviderID, modelForBudget?.modelID)) {
17604
+ const signedFitRetryWanted = !thinkingFitRetries.has(sessionId) && activeThinkingPrefixHold && hasActiveAnthropicThinkingTurn(messages, resolvedProviderID, modelForBudget?.modelID);
17605
+ if (signedFitRetryWanted && originalForThinkingFit) {
17096
17606
  thinkingFitRetries.add(sessionId);
17097
17607
  requestPendingMaterialization(deps.pendingMaterializationSessions, sessionId, "fit_retry");
17098
17608
  messages.splice(0, messages.length, ...originalForThinkingFit);
@@ -17103,7 +17613,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17103
17613
  }
17104
17614
  return;
17105
17615
  }
17106
- if (thinkingFitRetries.has(sessionId) || postTransformResult.thinkingReleasedForFit)
17616
+ if (signedFitRetryWanted) {
17617
+ sessionLog(sessionId, "signed thinking fit: the held request is over the window and no copy of the pass input exists to retry from; refusing it");
17618
+ }
17619
+ if (signedFitRetryWanted || thinkingFitRetries.has(sessionId) || postTransformResult.thinkingReleasedForFit)
17107
17620
  throw contextRefusalError("The request remains over the model window after stripping signed thinking and reclaiming context");
17108
17621
  }
17109
17622
  if (postTransformResult.prefixTrimStatus === "refused") {
@@ -17112,7 +17625,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17112
17625
  systemPromptTokens: sessionMeta.systemPromptTokens,
17113
17626
  providerID: modelForBudget?.providerID,
17114
17627
  modelID: modelForBudget?.modelID,
17115
- agentName: notificationParams.agent
17628
+ agentName: notificationParams.agent,
17629
+ sessionId
17116
17630
  });
17117
17631
  if (untrimmed.tokens > boundaryContextLimit) {
17118
17632
  sessionLog(sessionId, `history boundary unresolved: prefix trim refused and the untrimmed request estimate ${untrimmed.tokens} (trusted=${untrimmed.trusted}) exceeds the context limit ${boundaryContextLimit}; not sending it`);
@@ -17125,7 +17639,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17125
17639
  systemPromptTokens: sessionMeta.systemPromptTokens,
17126
17640
  providerID: modelForBudget?.providerID,
17127
17641
  modelID: modelForBudget?.modelID,
17128
- agentName: notificationParams.agent
17642
+ agentName: notificationParams.agent,
17643
+ sessionId
17129
17644
  });
17130
17645
  const servedTokens = served.toolDefinitionsMeasured ? served.rawTokens ?? served.tokens : Math.max(0, sessionMeta.systemPromptTokens) + served.messageTokens.conversation + served.messageTokens.toolCall;
17131
17646
  if (!Number.isFinite(servedTokens) || servedTokens > unmanagedOverWindowPass.limit) {
@@ -17203,7 +17718,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17203
17718
  systemPromptTokens: sessionMeta.systemPromptTokens,
17204
17719
  providerID: modelForBudget?.providerID,
17205
17720
  modelID: modelForBudget?.modelID,
17206
- agentName: notificationParams.agent
17721
+ agentName: notificationParams.agent,
17722
+ sessionId
17207
17723
  });
17208
17724
  } catch (error) {
17209
17725
  sessionLog(sessionId, "degraded pass size guard could not estimate:", error);
@@ -17220,7 +17736,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17220
17736
  if (!finalWireEstimate) {
17221
17737
  sessionLog(sessionId, `transform: final-wire telemetry estimate=unavailable trusted=false conversation=unknown tools=unknown system=unknown toolDefinitions=unknown tail=${finalWireTail}`);
17222
17738
  }
17223
- finishSystemDateRefresh(deps.historyRefreshSessions, dateRequest, postTransformResult.bustedThisPass && !activeThinkingPrefixHold || postTransformResult.thinkingReleasedForFit === true);
17739
+ const signedThinkingServed = isPrefixBoundThinkingModel(modelForBudget?.providerID, modelForBudget?.modelID) && servesThinkingBlock(messages);
17740
+ finishSystemDateRefresh(deps.historyRefreshSessions, dateRequest, postTransformResult.bustedThisPass && !activeThinkingPrefixHold && !signedThinkingServed || postTransformResult.thinkingReleasedForFit === true, signedThinkingServed);
17741
+ compactionModeTransitionPending.delete(sessionId);
17224
17742
  if (activeThinkingPrefixHold && !postTransformResult.thinkingReleasedForFit && sessionMeta.cachedM0Bytes != null && sessionMeta.cachedM1Bytes != null) {
17225
17743
  recordHeldHeadForRequest(sessionId, currentLkgRequestIdentity(sessionId), (ownsHistory) => deferDeliveredSystemRefresh(deps, sessionId, ownsHistory));
17226
17744
  }
@@ -17322,6 +17840,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17322
17840
  if (uncachedMessageIds.length > 0) {
17323
17841
  try {
17324
17842
  storedByMessage = getActiveTagTokenTotalsByMessage(db, sessionId, uncachedMessageIds);
17843
+ omitIncompleteFileTokenTotals(db, sessionId, messages.flatMap((message) => typeof message.info.id === "string" ? [{ id: message.info.id, parts: message.parts }] : []), storedByMessage);
17325
17844
  } catch {
17326
17845
  storedByMessage = new Map;
17327
17846
  }
@@ -17378,7 +17897,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17378
17897
  postReduceGraceBaselineU: channel1State.postReduceGraceBaselineU,
17379
17898
  postReduceGracePreLevel: channel1State.postReduceGracePreLevel
17380
17899
  });
17381
- sessionLog(sessionId, formatChannel1Evaluation(channel1Decision));
17900
+ logNudgeEvaluation(sessionId, "transform", formatChannel1Evaluation(channel1Decision));
17382
17901
  const channel2Evaluation = evaluateChannel2(channelBaseline);
17383
17902
  const leaseBefore = getChannel2NudgeState(db, sessionId);
17384
17903
  if (channelBaseline.evaluable && !channelBaseline.generationInvalidated && !channelBaseline.reducedSinceRefresh) {
@@ -17389,7 +17908,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17389
17908
  }
17390
17909
  }
17391
17910
  const leaseAfter = getChannel2NudgeState(db, sessionId);
17392
- sessionLog(sessionId, formatChannel2Evaluation(channel2Evaluation, {
17911
+ logNudgeEvaluation(sessionId, "transform", formatChannel2Evaluation(channel2Evaluation, {
17393
17912
  leaseBefore,
17394
17913
  leaseAfter,
17395
17914
  gateHoldReason: channelBaseline.reducedSinceRefresh ? "recent-reduce-refresh" : undefined
@@ -17412,6 +17931,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17412
17931
  providerID: modelForBudget?.providerID,
17413
17932
  modelID: modelForBudget?.modelID,
17414
17933
  agentName: notificationParams.agent,
17934
+ sessionId,
17415
17935
  systemPromptHash: sessionMeta.systemPromptHash
17416
17936
  });
17417
17937
  try {
@@ -17428,7 +17948,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17428
17948
  sessionLog(sessionId, "memory maintenance launch probe failed (ignored):", error);
17429
17949
  }
17430
17950
  };
17431
- return Object.assign(transform, {
17951
+ const timedTransform = (input, output) => withTransformTimingSummary(() => transform(input, output));
17952
+ return Object.assign(timedTransform, {
17432
17953
  clearSessionLogState(sessionId) {
17433
17954
  clearSessionLogState(sessionId);
17434
17955
  }
@@ -17882,8 +18403,26 @@ WHERE session_id = ?
17882
18403
  AND data IS NOT NULL
17883
18404
  AND (time_created > ? OR (time_created = ? AND id > ?))
17884
18405
  ORDER BY time_created, id`;
17885
- function readAssistantUsageRowsAfter(openCodeDb, sessionId, afterTimeCreated, afterId) {
17886
- const rows = openCodeDb.prepare(ASSISTANT_USAGE_ROWS_AFTER_SQL).all(sessionId, afterTimeCreated, afterTimeCreated, afterId);
18406
+ var V2_ASSISTANT_USAGE_ROWS_AFTER_SQL = `
18407
+ WITH newer AS (
18408
+ SELECT id, seq, data FROM session_message
18409
+ WHERE session_id = ? AND type = 'assistant' AND data IS NOT NULL AND seq > ?
18410
+ UNION ALL
18411
+ SELECT id, seq, data FROM session_message
18412
+ WHERE session_id = ? AND type = 'assistant' AND data IS NOT NULL AND seq = ? AND id > ?
18413
+ )
18414
+ SELECT
18415
+ json_extract(data, '$.agent') AS agent,
18416
+ seq AS time_created,
18417
+ id AS id,
18418
+ COALESCE(json_extract(data, '$.tokens.input'), 0)
18419
+ + COALESCE(json_extract(data, '$.tokens.cache.read'), 0)
18420
+ + COALESCE(json_extract(data, '$.tokens.cache.write'), 0) AS prompt,
18421
+ COALESCE(json_extract(data, '$.tokens.output'), 0) AS output
18422
+ FROM newer
18423
+ ORDER BY seq, id`;
18424
+ function readAssistantUsageRowsAfter(openCodeDb, sessionId, afterTimeCreated, afterId, generation = "v1") {
18425
+ const rows = openCodeDb.prepare(generation === "v2" ? V2_ASSISTANT_USAGE_ROWS_AFTER_SQL : ASSISTANT_USAGE_ROWS_AFTER_SQL).all(...generation === "v2" ? [sessionId, afterTimeCreated, sessionId, afterTimeCreated, afterId] : [sessionId, afterTimeCreated, afterTimeCreated, afterId]);
17887
18426
  return rows.map((r) => ({
17888
18427
  agent: r.agent ?? null,
17889
18428
  timeCreated: Number(r.time_created ?? 0),
@@ -17892,8 +18431,8 @@ function readAssistantUsageRowsAfter(openCodeDb, sessionId, afterTimeCreated, af
17892
18431
  output: Number(r.output ?? 0)
17893
18432
  }));
17894
18433
  }
17895
- function computeOpenCodeWorkMetricsIncremental(openCodeDb, sessionId, carry) {
17896
- const rows = readAssistantUsageRowsAfter(openCodeDb, sessionId, carry.lastTimeCreated, carry.lastId);
18434
+ function computeOpenCodeWorkMetricsIncremental(openCodeDb, sessionId, carry, generation = "v1") {
18435
+ const rows = readAssistantUsageRowsAfter(openCodeDb, sessionId, carry.lastTimeCreated, carry.lastId, generation);
17897
18436
  if (rows.length === 0) {
17898
18437
  return { carry, metrics: metricsFromCarry(carry) };
17899
18438
  }
@@ -18091,13 +18630,15 @@ function resolveTailHygieneStatus(tsBaseline, rustBaseline) {
18091
18630
  // src/plugin/rpc-handlers.ts
18092
18631
  var workMetricsCarryBySession = new Map;
18093
18632
  function resolveSidebarWorkMetrics(db, sessionId, persistedNewWork, persistedTotalInput) {
18094
- if (!openCodeDbExists()) {
18633
+ const generation = getHarness() === "opencode2" ? "v2" : "v1";
18634
+ if (!openCodeDbExists(generation)) {
18095
18635
  return { newWorkTokens: persistedNewWork, totalInputTokens: persistedTotalInput };
18096
18636
  }
18097
18637
  try {
18098
- const carry = workMetricsCarryBySession.get(sessionId) ?? emptyWorkMetricsCarry();
18099
- const { carry: nextCarry, metrics } = withReadOnlySessionDb((openCodeDb) => computeOpenCodeWorkMetricsIncremental(openCodeDb, sessionId, carry));
18100
- workMetricsCarryBySession.set(sessionId, nextCarry);
18638
+ const carryKey = `${generation}:${sessionId}`;
18639
+ const carry = workMetricsCarryBySession.get(carryKey) ?? emptyWorkMetricsCarry();
18640
+ const { carry: nextCarry, metrics } = withReadOnlySessionDb((openCodeDb) => computeOpenCodeWorkMetricsIncremental(openCodeDb, sessionId, carry, generation), generation);
18641
+ workMetricsCarryBySession.set(carryKey, nextCarry);
18101
18642
  try {
18102
18643
  setSessionWorkMetrics(db, sessionId, metrics.newWorkTokens, metrics.totalInputTokens);
18103
18644
  } catch {}
@@ -18216,7 +18757,7 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
18216
18757
  if (model) {
18217
18758
  activeProviderID = model.providerID;
18218
18759
  activeModelID = model.modelID;
18219
- measuredToolDefTokens = getMeasuredToolDefinitionTokens(model.providerID, model.modelID, agent) ?? 0;
18760
+ measuredToolDefTokens = getMeasuredToolDefinitionTokens(model.providerID, model.modelID, agent, sessionId) ?? 0;
18220
18761
  }
18221
18762
  }
18222
18763
  const contextLimit = activeProviderID && activeModelID ? resolveContextLimit(activeProviderID, activeModelID, {
@@ -18702,8 +19243,8 @@ function registerRpcHandlers(rpcServer, args) {
18702
19243
  const db = readDatabase();
18703
19244
  if (!db)
18704
19245
  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");
19246
+ const { runManagedRecomp } = await import("./recomp-orchestrator-51xyaexp.js");
19247
+ const { sendIgnoredMessage } = await import("./send-session-notification-vdppp5x6.js");
18707
19248
  log(`[rpc] recomp requested for session ${sessionId}`);
18708
19249
  if (!args.client && !args.hiddenCompletionExecutor) {
18709
19250
  return {
@@ -18752,7 +19293,7 @@ function registerRpcHandlers(rpcServer, args) {
18752
19293
  const db = readDatabase();
18753
19294
  if (!db)
18754
19295
  return { ok: false, error: "db unavailable" };
18755
- const { runManagedWrapup } = await import("./wrapup-orchestrator-b2gswatj.js");
19296
+ const { runManagedWrapup } = await import("./wrapup-orchestrator-g0mww1h4.js");
18756
19297
  const model = liveSessionState.liveModelBySession.get(sessionId);
18757
19298
  const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
18758
19299
  const ctx = {
@@ -18840,8 +19381,17 @@ function subagentToolRefusal(db, toolId, sessionId, isInternalChild = () => fals
18840
19381
  function hideSubagentTools(draft, db) {
18841
19382
  if (!getOrCreateSessionMeta(db, draft.sessionID).isSubagent)
18842
19383
  return;
19384
+ removePrimaryOnlyTools(draft.tools);
19385
+ }
19386
+ function removePrimaryOnlyTools(tools) {
18843
19387
  for (const id of PRIMARY_ONLY_TOOLS)
18844
- delete draft.tools[id];
19388
+ delete tools[id];
19389
+ }
19390
+ function storedSubagentMode(db, sessionId) {
19391
+ const row = db.prepare("SELECT is_subagent FROM session_meta WHERE session_id = ?").get(sessionId);
19392
+ if (!row || typeof row.is_subagent !== "number")
19393
+ return;
19394
+ return row.is_subagent === 1;
18845
19395
  }
18846
19396
 
18847
19397
  // src/shared/conflict-detector.ts
@@ -19099,7 +19649,58 @@ function readOmoDisabledHooks(directory) {
19099
19649
 
19100
19650
  // src/shared/rpc-server.ts
19101
19651
  import { randomBytes, timingSafeEqual } from "node:crypto";
19102
- import { readdirSync, readFileSync as readFileSync6, unlinkSync } from "node:fs";
19652
+ import { readdirSync, readFileSync as readFileSync6, rmdirSync, unlinkSync } from "node:fs";
19653
+
19654
+ // src/shared/rpc-discovery-cleanup.ts
19655
+ import { promises as fs } from "node:fs";
19656
+ import { join as join4 } from "node:path";
19657
+ async function reapDeadRpcDiscovery(storageDir) {
19658
+ const root = join4(storageDir, "rpc");
19659
+ let directories;
19660
+ try {
19661
+ directories = await fs.readdir(root, { withFileTypes: true });
19662
+ } catch {
19663
+ return;
19664
+ }
19665
+ const records = [];
19666
+ const projectDirs = [];
19667
+ for (const entry of directories) {
19668
+ if (!entry.isDirectory() || !/^[0-9a-f]{16}$/.test(entry.name))
19669
+ continue;
19670
+ const directory = join4(root, entry.name);
19671
+ projectDirs.push(directory);
19672
+ try {
19673
+ for (const name of await fs.readdir(directory)) {
19674
+ const match = /^port-(\d+)(?:-[0-9a-f]+)?\.json$/.exec(name);
19675
+ if (!match)
19676
+ continue;
19677
+ const path = join4(directory, name);
19678
+ try {
19679
+ const content = await fs.readFile(path, "utf8");
19680
+ const record = parseRpcPortFile(content, Number(match[1]));
19681
+ if (record && record.pid === Number(match[1]))
19682
+ records.push({ path, content, pid: record.pid });
19683
+ } catch {}
19684
+ }
19685
+ } catch {}
19686
+ }
19687
+ const processes = records.length ? await inspectProcessesAsync(true) : undefined;
19688
+ for (const record of records) {
19689
+ if (processes?.liveness(record.pid) !== "dead")
19690
+ continue;
19691
+ try {
19692
+ if (await fs.readFile(record.path, "utf8") === record.content)
19693
+ await fs.unlink(record.path);
19694
+ } catch {}
19695
+ }
19696
+ for (const directory of projectDirs) {
19697
+ try {
19698
+ await fs.rmdir(directory);
19699
+ } catch {}
19700
+ }
19701
+ }
19702
+
19703
+ // src/shared/rpc-server.ts
19103
19704
  var MAX_BODY_BYTES = 1048576;
19104
19705
  var WS_AUTH_TIMEOUT_MS = 5000;
19105
19706
  var WS_CLOSE_UNAUTHORIZED = 4401;
@@ -19122,17 +19723,20 @@ function websocketToken(req) {
19122
19723
  }
19123
19724
 
19124
19725
  class MagicContextRpcServer {
19726
+ storageDir;
19125
19727
  server = null;
19126
19728
  port = 0;
19127
19729
  handlers = new Map;
19128
19730
  portFilePath;
19129
19731
  portDir;
19130
19732
  startedAt = Date.now();
19733
+ stopped = false;
19131
19734
  instanceId = randomBytes(8).toString("hex");
19132
19735
  unregisterOwnInstance = null;
19133
19736
  sockets = new Set;
19134
19737
  token = randomBytes(32).toString("hex");
19135
19738
  constructor(storageDir, directory) {
19739
+ this.storageDir = storageDir;
19136
19740
  this.portFilePath = rpcPortFilePath(storageDir, directory, process.pid, this.instanceId);
19137
19741
  this.portDir = rpcPortDir(storageDir, directory);
19138
19742
  }
@@ -19150,6 +19754,10 @@ class MagicContextRpcServer {
19150
19754
  log("rpc server skipped: Bun runtime not available (no TUI consumer)");
19151
19755
  return 0;
19152
19756
  }
19757
+ this.stopped = false;
19758
+ await reapDeadRpcDiscovery(this.storageDir);
19759
+ if (this.stopped)
19760
+ return 0;
19153
19761
  this.startedAt = Date.now();
19154
19762
  const self = this;
19155
19763
  const server = Bun.serve({
@@ -19181,7 +19789,7 @@ class MagicContextRpcServer {
19181
19789
  try {
19182
19790
  this.warnIfOtherLiveInstance();
19183
19791
  this.unregisterOwnInstance ??= registerOwnRpcServerInstance(this.instanceId);
19184
- writeStorageFileAtomicSync(this.portFilePath, JSON.stringify({
19792
+ const publish = () => writeStorageFileAtomicSync(this.portFilePath, JSON.stringify({
19185
19793
  port: this.port,
19186
19794
  pid: process.pid,
19187
19795
  started_at: this.startedAt,
@@ -19189,6 +19797,13 @@ class MagicContextRpcServer {
19189
19797
  token: this.token,
19190
19798
  instance_id: this.instanceId
19191
19799
  }));
19800
+ try {
19801
+ publish();
19802
+ } catch (error) {
19803
+ if (error.code !== "ENOENT")
19804
+ throw error;
19805
+ publish();
19806
+ }
19192
19807
  log(`[rpc] server listening on 127.0.0.1:${this.port}`);
19193
19808
  } catch (err) {
19194
19809
  log(`[rpc] failed to write port file: ${err}`);
@@ -19196,6 +19811,7 @@ class MagicContextRpcServer {
19196
19811
  return this.port;
19197
19812
  }
19198
19813
  stop() {
19814
+ this.stopped = true;
19199
19815
  for (const ws of this.sockets) {
19200
19816
  try {
19201
19817
  if (ws.data.authTimer)
@@ -19212,6 +19828,9 @@ class MagicContextRpcServer {
19212
19828
  try {
19213
19829
  unlinkSync(this.portFilePath);
19214
19830
  } catch {}
19831
+ try {
19832
+ rmdirSync(this.portDir);
19833
+ } catch {}
19215
19834
  this.unregisterOwnInstance?.();
19216
19835
  this.unregisterOwnInstance = null;
19217
19836
  }
@@ -19369,17 +19988,17 @@ var FULL_PARAMETER_DESCRIPTIONS = {
19369
19988
  message: "Message ordinal from a <session-history> heading or a mmc_search hit, not a tag number. Returns that one message in full. Use alone."
19370
19989
  },
19371
19990
  mmc_note: {
19372
- action: "write | read | update | dismiss. Defaults to write when content is given, else read.",
19991
+ action: "write | read | update | dismiss.",
19373
19992
  content: "Note text for write/update: first line is the title (under 80 chars), then the detail.",
19374
19993
  filter: "Read filter: active (default), all, dismissed.",
19375
19994
  limit: "Rows per read (default 25).",
19376
19995
  offset: "Skip this many newest rows (default 0).",
19377
- note_ids: "Note ids: one for update, 1–50 for dismiss or read (read returns full bodies). Ignored by write."
19996
+ note_ids: "Note ids: one for update, 1–50 for dismiss, or 1–50 to read those notes in full. Write and a plain read take an empty list."
19378
19997
  },
19379
19998
  mmc_memory: {
19380
19999
  action: "write | update | archive | merge | get",
19381
20000
  content: "The memory text — one standalone fact (write, update, merge).",
19382
- category: "Kind of fact (required for write; on update/merge optional, omitted keeps the current category).",
20001
+ category: "Kind of fact (required for write; on update/merge, pass the memory's current category to keep it).",
19383
20002
  ids: "Memory ids from <project-memory>: one for update, one or more for archive, two or more for merge, 1–20 for get.",
19384
20003
  reason: "Why it is being archived (optional)."
19385
20004
  },
@@ -19403,17 +20022,17 @@ var LIGHT_PARAMETER_DESCRIPTIONS = {
19403
20022
  message: "Message ordinal from a <session-history> heading or a mmc_search hit, not a tag number. Returns that one message in full. Use alone."
19404
20023
  },
19405
20024
  mmc_note: {
19406
- action: "write | read | update | dismiss (default: write with content, else read).",
20025
+ action: "write | read | update | dismiss.",
19407
20026
  content: "Note text: first line title (<80 chars), then detail.",
19408
20027
  filter: "Read filter: active (default), all, dismissed.",
19409
20028
  limit: "Rows per read (default 25).",
19410
20029
  offset: "Skip newest rows (default 0).",
19411
- note_ids: "One id for update, 1–50 for dismiss or read (full bodies). Ignored by write."
20030
+ note_ids: "One id for update, 1–50 for dismiss, or 1–50 to read those notes in full. Write and a plain read take an empty list."
19412
20031
  },
19413
20032
  mmc_memory: {
19414
20033
  action: "write | update | archive | merge | get",
19415
20034
  content: "One standalone fact (write, update, merge).",
19416
- category: "Kind of fact (required for write; optional on update/merge).",
20035
+ category: "Kind of fact (required for write; on update/merge pass the current category to keep it).",
19417
20036
  ids: "Ids from <project-memory>: one for update, 1+ for archive, 2+ for merge, 1–20 for get.",
19418
20037
  reason: "Why it is archived (optional)."
19419
20038
  },
@@ -19945,18 +20564,56 @@ function containsHostInstance(value) {
19945
20564
  return false;
19946
20565
  }
19947
20566
  function clonePreservingInstances(value) {
19948
- if (isHostInstance(value))
20567
+ return cloneCounting(value, undefined);
20568
+ }
20569
+ function clonePreservingInstancesMeasured(value) {
20570
+ const meter = { bytes: 0 };
20571
+ const copy = cloneCounting(value, meter);
20572
+ return { copy, bytes: meter.bytes };
20573
+ }
20574
+ function cloneCounting(value, meter) {
20575
+ if (isHostInstance(value)) {
20576
+ if (meter)
20577
+ meter.bytes += instanceBytes(value, new WeakSet);
19949
20578
  return value;
19950
- if (Array.isArray(value))
19951
- return value.map(clonePreservingInstances);
20579
+ }
20580
+ if (Array.isArray(value)) {
20581
+ if (meter)
20582
+ meter.bytes += 16 + 8 * value.length;
20583
+ return value.map((entry) => cloneCounting(entry, meter));
20584
+ }
19952
20585
  if (value && typeof value === "object") {
19953
20586
  const copy = {};
19954
- for (const [key, entry] of Object.entries(value))
19955
- copy[key] = clonePreservingInstances(entry);
20587
+ if (meter)
20588
+ meter.bytes += 32;
20589
+ for (const [key, entry] of Object.entries(value)) {
20590
+ if (meter)
20591
+ meter.bytes += 16;
20592
+ copy[key] = cloneCounting(entry, meter);
20593
+ }
19956
20594
  return copy;
19957
20595
  }
20596
+ if (meter)
20597
+ meter.bytes += typeof value === "string" ? 2 * value.length : 8;
19958
20598
  return value;
19959
20599
  }
20600
+ function instanceBytes(value, seen) {
20601
+ if (typeof value === "string")
20602
+ return 2 * value.length;
20603
+ if (!value || typeof value !== "object")
20604
+ return 8;
20605
+ if (seen.has(value))
20606
+ return 0;
20607
+ seen.add(value);
20608
+ if (ArrayBuffer.isView(value))
20609
+ return value.byteLength;
20610
+ if (value instanceof ArrayBuffer)
20611
+ return value.byteLength;
20612
+ let bytes = 32;
20613
+ for (const entry of Object.values(value))
20614
+ bytes += 16 + instanceBytes(entry, seen);
20615
+ return bytes;
20616
+ }
19960
20617
  function contentKey(value) {
19961
20618
  const plain = (entry) => {
19962
20619
  if (ArrayBuffer.isView(entry)) {
@@ -20012,7 +20669,7 @@ function rebuildFileContent(value, output, attachments) {
20012
20669
  rebuilt.unshift({ type: "text", text: output });
20013
20670
  return { type: "content", value: rebuilt };
20014
20671
  }
20015
- function adaptPayload(draft, admittedIDs = new Set) {
20672
+ function adaptPayload(draft, admittedIDs = new Set, messageTimes = new Map, hiddenTimes = false) {
20016
20673
  const existingHeads = new Map(draft.messages.filter((m) => HEAD_IDS.some((id) => m.id === id)).map((m) => [m.id, m]));
20017
20674
  const source = draft.messages.filter((m) => !existingHeads.has(m.id));
20018
20675
  const results = new Map;
@@ -20122,6 +20779,7 @@ function adaptPayload(draft, admittedIDs = new Set) {
20122
20779
  id: message.id,
20123
20780
  sessionID: draft.sessionID,
20124
20781
  role: message.role,
20782
+ time: message.id ? messageTimes.get(message.id) : undefined,
20125
20783
  ...{
20126
20784
  providerID: draft.model.providerID,
20127
20785
  modelID: draft.model.id,
@@ -20130,7 +20788,19 @@ function adaptPayload(draft, admittedIDs = new Set) {
20130
20788
  },
20131
20789
  parts
20132
20790
  };
20791
+ if (hiddenTimes && mapped.info.time !== undefined) {
20792
+ const time = mapped.info.time;
20793
+ delete mapped.info.time;
20794
+ Object.defineProperty(mapped.info, "time", {
20795
+ value: time,
20796
+ enumerable: false,
20797
+ configurable: true,
20798
+ writable: true
20799
+ });
20800
+ }
20133
20801
  originals.set(mapped, message);
20802
+ if (isCoveredInstructionRow(message))
20803
+ markCoveredInstructionRow(mapped.info);
20134
20804
  if (typeof message.id !== "string")
20135
20805
  bridgesByCarrier.set(mapped, byCallID);
20136
20806
  messages.push(mapped);
@@ -20487,24 +21157,31 @@ ${data.output?.output ?? ""}`
20487
21157
  const sameModel = sameProvider && previousModel?.id === model.id;
20488
21158
  const reuse = sameModel && data.error === undefined;
20489
21159
  const metadata = (state) => state === undefined ? undefined : { [model.providerID]: state };
21160
+ const reasoningInterrupted = data.content?.some((part) => part.type === "reasoning" && part.time !== undefined && part.time.completed === undefined);
20490
21161
  const content = [];
20491
21162
  const results = [];
20492
21163
  for (const part of data.content ?? []) {
21164
+ let native = "native" in part ? part.native : part.type === "tool" ? part.providerState : part.state;
21165
+ if (part.type === "tool" && part.providerResultState !== null && typeof part.providerResultState === "object" && !Array.isArray(part.providerResultState))
21166
+ native = {
21167
+ ...native !== null && typeof native === "object" && !Array.isArray(native) ? native : {},
21168
+ ...part.providerResultState
21169
+ };
20493
21170
  if (part.type === "text") {
20494
21171
  if (part.text !== "")
20495
21172
  content.push({
20496
21173
  type: "text",
20497
21174
  text: part.text,
20498
- providerMetadata: reuse ? metadata(part.state) : undefined
21175
+ providerMetadata: reuse ? metadata(native) : undefined
20499
21176
  });
20500
21177
  continue;
20501
21178
  }
20502
21179
  if (part.type === "reasoning") {
20503
- if (part.text !== "" || reuse && part.state !== undefined)
21180
+ if (part.text !== "" || reuse && !reasoningInterrupted && native !== undefined)
20504
21181
  content.push({
20505
- type: reuse || data.error === undefined ? "reasoning" : "text",
21182
+ type: data.error === undefined && !reasoningInterrupted ? "reasoning" : "text",
20506
21183
  text: part.text,
20507
- providerMetadata: reuse ? metadata(part.state) : undefined
21184
+ providerMetadata: reuse && !reasoningInterrupted ? metadata(native) : undefined
20508
21185
  });
20509
21186
  continue;
20510
21187
  }
@@ -20523,7 +21200,7 @@ ${data.output?.output ?? ""}`
20523
21200
  name: part.name,
20524
21201
  input,
20525
21202
  providerExecuted: part.executed,
20526
- providerMetadata: toolReuse ? metadata(part.providerState) : undefined
21203
+ providerMetadata: toolReuse ? metadata(native) : undefined
20527
21204
  });
20528
21205
  if (!completed)
20529
21206
  continue;
@@ -20534,7 +21211,7 @@ ${data.output?.output ?? ""}`
20534
21211
  id: part.id,
20535
21212
  name: part.name,
20536
21213
  providerExecuted: part.executed,
20537
- providerMetadata: toolReuse ? metadata(part.providerResultState ?? part.providerState) : sameProvider ? metadata(part.providerResultState) : undefined,
21214
+ providerMetadata: (part.executed === true ? sameProvider : reuse) ? metadata(native) : undefined,
20538
21215
  result: state.status === "error" ? { error: state.error, content: toolContent } : single?.type === "text" ? { type: "text", value: single.text } : { type: "content", value: toolContent },
20539
21216
  ...state.status === "error" ? { resultType: "error" } : {}
20540
21217
  };
@@ -20562,13 +21239,50 @@ function copyNativeInput(messages) {
20562
21239
  return copies;
20563
21240
  }
20564
21241
  function isLocalCheckpoint(row) {
20565
- return row.type === "compaction" && row.data.status === "completed" && row.data.providerContext === undefined;
21242
+ return row.type === "compaction" && row.data.status === "completed" && row.data.providerContext === undefined && row.data.native?.messages === undefined;
21243
+ }
21244
+ function isAdmittedLocalCheckpoint(storage, sessionID, cut) {
21245
+ if (!isLocalCheckpoint(cut) || cut.session_id !== sessionID)
21246
+ return false;
21247
+ const admission = storage.admission(sessionID, cut.id);
21248
+ if (!admission?.payload || admission.digest !== foldDigest(admission.payload))
21249
+ return false;
21250
+ try {
21251
+ const snapshot = JSON.parse(admission.payload);
21252
+ return snapshot.source === storage.sourceID && snapshot.sessionID === sessionID && snapshot.admissionID === cut.id && snapshot.summary === cut.data.summary;
21253
+ } catch {
21254
+ return false;
21255
+ }
20566
21256
  }
20567
21257
  var conversational = (row) => RAW_MESSAGE_TYPES.includes(row.type) || row.type === "location-switched";
21258
+ var historyDigest = (reader, sessionID, through) => foldDigest(JSON.stringify(reader.range(sessionID, -1, through).filter(conversational)));
21259
+ var admissionKey = (sessionID) => `native-fold/v2/${encodeURIComponent(sessionID)}`;
21260
+ async function forgetNativeFoldProvenance(storage, sessionID, legacyOnly = false) {
21261
+ const remove = async (key) => {
21262
+ if (storage.remove)
21263
+ await storage.remove(key);
21264
+ else
21265
+ await storage.set(key, null);
21266
+ };
21267
+ if (!legacyOnly)
21268
+ await remove(admissionKey(sessionID));
21269
+ if (!storage.scan)
21270
+ return;
21271
+ let after;
21272
+ do {
21273
+ const page = await storage.scan({ prefix: "native-fold/v1/", after, limit: 100 });
21274
+ for (const { key } of page.entries) {
21275
+ if (key.slice("native-fold/v1/".length).split("/").slice(1).join("/") === sessionID)
21276
+ await remove(key);
21277
+ }
21278
+ after = page.next;
21279
+ } while (after);
21280
+ }
20568
21281
 
20569
21282
  class NativeFoldReplay {
20570
21283
  storage;
20571
21284
  openReader;
21285
+ admissions;
20572
21286
  changed = new Set;
20573
21287
  dirty = new Set;
20574
21288
  unavailable = new Set;
@@ -20576,9 +21290,11 @@ class NativeFoldReplay {
20576
21290
  metadataThrough = new Map;
20577
21291
  loaded = new Map;
20578
21292
  sources = new Map;
20579
- constructor(storage, openReader) {
21293
+ staleHeads = new Set;
21294
+ constructor(storage, openReader, admissions) {
20580
21295
  this.storage = storage;
20581
21296
  this.openReader = openReader;
21297
+ this.admissions = admissions;
20582
21298
  storage.onEvict((sessionID) => this.clear(sessionID));
20583
21299
  }
20584
21300
  account(sessionID) {
@@ -20617,6 +21333,51 @@ class NativeFoldReplay {
20617
21333
  async baseline(sessionID) {
20618
21334
  return this.tail(sessionID)?.baseline;
20619
21335
  }
21336
+ admissionKey(sessionID) {
21337
+ return admissionKey(sessionID);
21338
+ }
21339
+ async removeAdmission(key) {
21340
+ if (this.admissions?.remove)
21341
+ await this.admissions.remove(key);
21342
+ else
21343
+ await this.admissions?.set(key, null);
21344
+ }
21345
+ async removeLegacyAdmissions(sessionID) {
21346
+ if (this.admissions)
21347
+ await forgetNativeFoldProvenance(this.admissions, sessionID, true);
21348
+ }
21349
+ async admits(sessionID, cut, reader) {
21350
+ if (!isLocalCheckpoint(cut) || cut.session_id !== sessionID)
21351
+ return false;
21352
+ if (isAdmittedLocalCheckpoint(this.storage, sessionID, cut))
21353
+ return true;
21354
+ if (!this.admissions)
21355
+ return false;
21356
+ try {
21357
+ const source = reader.hostIdentity();
21358
+ const saved = await this.admissions.get(this.admissionKey(sessionID));
21359
+ if (!saved?.payload || saved.digest !== foldDigest(saved.payload))
21360
+ return false;
21361
+ const snapshot = JSON.parse(saved.payload);
21362
+ if (snapshot.sourceDigest !== foldDigest(source) || snapshot.sessionID !== sessionID || snapshot.admissionID !== cut.id || snapshot.summaryDigest !== foldDigest(cut.data.summary ?? ""))
21363
+ return false;
21364
+ if (snapshot.historyDigest !== historyDigest(reader, sessionID, cut.seq - 1)) {
21365
+ this.staleHeads.add(sessionID);
21366
+ this.invalidate(sessionID);
21367
+ await this.removeAdmission(this.admissionKey(sessionID));
21368
+ return false;
21369
+ }
21370
+ await this.storage.supply(sessionID, cut.id, JSON.stringify({
21371
+ source: this.storage.sourceID,
21372
+ sessionID,
21373
+ admissionID: cut.id,
21374
+ summary: cut.data.summary
21375
+ }));
21376
+ return true;
21377
+ } catch {
21378
+ return false;
21379
+ }
21380
+ }
20620
21381
  rendered(row, model) {
20621
21382
  return restoreRow(row, model, hostUsesMediaAssets() ? {
20622
21383
  asset: hostMediaAsset,
@@ -20694,6 +21455,7 @@ class NativeFoldReplay {
20694
21455
  this.loaded.set(draft.sessionID, through);
20695
21456
  this.unavailable.delete(draft.sessionID);
20696
21457
  this.changed.delete(draft.sessionID);
21458
+ this.staleHeads.delete(draft.sessionID);
20697
21459
  } finally {
20698
21460
  reader.close();
20699
21461
  }
@@ -20720,7 +21482,8 @@ class NativeFoldReplay {
20720
21482
  async supplyHeld(args) {
20721
21483
  const { draft, reader, summary } = args;
20722
21484
  const tail = this.tail(draft.sessionID);
20723
- const id = reader.latestRunningCompaction(draft.sessionID)?.id;
21485
+ const running = reader.latestRunningCompaction(draft.sessionID);
21486
+ const id = running?.id;
20724
21487
  if (!id || !tail || tail.model !== `${draft.model.providerID}/${draft.model.id}`)
20725
21488
  return false;
20726
21489
  const through = reader.latestSequence(draft.sessionID);
@@ -20744,6 +21507,21 @@ class NativeFoldReplay {
20744
21507
  summary
20745
21508
  };
20746
21509
  await this.storage.supply(draft.sessionID, id, JSON.stringify(snapshot));
21510
+ if (this.admissions) {
21511
+ const provenance = {
21512
+ sourceDigest: foldDigest(reader.hostIdentity()),
21513
+ sessionID: draft.sessionID,
21514
+ admissionID: id,
21515
+ summaryDigest: foldDigest(summary),
21516
+ historyDigest: historyDigest(reader, draft.sessionID, (running?.seq ?? through) - 1)
21517
+ };
21518
+ const payload = JSON.stringify(provenance);
21519
+ await this.admissions.set(this.admissionKey(draft.sessionID), {
21520
+ payload,
21521
+ digest: foldDigest(payload)
21522
+ });
21523
+ await this.removeLegacyAdmissions(draft.sessionID);
21524
+ }
20747
21525
  return true;
20748
21526
  }
20749
21527
  async restore(sessionID, cut, model, options = {}) {
@@ -20828,6 +21606,9 @@ class NativeFoldReplay {
20828
21606
  sourceChanged(sessionID) {
20829
21607
  return this.changed.has(sessionID);
20830
21608
  }
21609
+ needsHeadRebuild(sessionID) {
21610
+ return this.staleHeads.has(sessionID);
21611
+ }
20831
21612
  clear(sessionID) {
20832
21613
  this.sources.delete(sessionID);
20833
21614
  this.metadata.delete(sessionID);
@@ -20836,8 +21617,11 @@ class NativeFoldReplay {
20836
21617
  this.unavailable.delete(sessionID);
20837
21618
  this.dirty.delete(sessionID);
20838
21619
  this.changed.delete(sessionID);
21620
+ this.staleHeads.delete(sessionID);
20839
21621
  }
20840
21622
  async forget(sessionID) {
21623
+ if (this.admissions)
21624
+ await forgetNativeFoldProvenance(this.admissions, sessionID);
20841
21625
  await this.storage.forget(sessionID);
20842
21626
  }
20843
21627
  }
@@ -20852,11 +21636,7 @@ class HostFoldPolicy {
20852
21636
  this.deps = deps;
20853
21637
  }
20854
21638
  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;
21639
+ return cut.id === id && isAdmittedLocalCheckpoint(this.deps.storage, sessionID, cut);
20860
21640
  }
20861
21641
  async idle(sessionID) {
20862
21642
  const { storage, session, threshold } = this.deps;
@@ -21813,6 +22593,96 @@ async function createV2HiddenCompletionExecutor(host, options) {
21813
22593
  };
21814
22594
  }
21815
22595
 
22596
+ // src/v2/message-times.ts
22597
+ function isSettled(entry, readAt) {
22598
+ return (entry.version.type === "user" || entry.time.completed !== undefined) && typeof entry.version.updated === "number" && Number.isFinite(entry.version.updated) && entry.version.updated <= readAt - 1000;
22599
+ }
22600
+ function sameVersion(a, b) {
22601
+ return a.type === b.type && a.seq === b.seq && a.created === b.created && a.updated === b.updated;
22602
+ }
22603
+
22604
+ class V2MessageTimesCache {
22605
+ capacity;
22606
+ sessions = new Map;
22607
+ constructor(capacity = 64) {
22608
+ this.capacity = capacity;
22609
+ }
22610
+ delete(sessionID) {
22611
+ this.sessions.delete(sessionID);
22612
+ }
22613
+ deleteMessage(sessionID, messageID) {
22614
+ this.sessions.get(sessionID)?.entries.delete(messageID);
22615
+ }
22616
+ clear() {
22617
+ this.sessions.clear();
22618
+ }
22619
+ pass(sessionID) {
22620
+ const previous = this.sessions.get(sessionID);
22621
+ const current = { entries: new Map };
22622
+ this.sessions.delete(sessionID);
22623
+ this.sessions.set(sessionID, current);
22624
+ while (this.sessions.size > this.capacity) {
22625
+ const oldest = this.sessions.keys().next().value;
22626
+ if (oldest === undefined)
22627
+ break;
22628
+ this.sessions.delete(oldest);
22629
+ }
22630
+ const passTimes = new Map;
22631
+ return (reader, ids) => {
22632
+ const missing = [...new Set(ids)].filter((id) => !passTimes.has(id));
22633
+ if (missing.length > 0) {
22634
+ const readAt = Date.now();
22635
+ const identity = reader.hostIdentity();
22636
+ current.identity = identity;
22637
+ const reusable = previous?.identity === identity ? previous.entries : undefined;
22638
+ const known = [];
22639
+ const refresh = [];
22640
+ let first = Infinity;
22641
+ let last = -Infinity;
22642
+ for (const id of missing) {
22643
+ const entry = reusable?.get(id);
22644
+ if (entry && isSettled(entry, readAt)) {
22645
+ known.push(id);
22646
+ first = Math.min(first, entry.version.seq);
22647
+ last = Math.max(last, entry.version.seq);
22648
+ } else
22649
+ refresh.push(id);
22650
+ }
22651
+ const versions = reader.messageTimeVersions(sessionID, known, { first, last });
22652
+ for (const id of known) {
22653
+ const version = versions.get(id);
22654
+ const cached = reusable?.get(id);
22655
+ if (!version) {
22656
+ passTimes.set(id, null);
22657
+ } else if (cached && sameVersion(cached.version, version) && (version.type === "user" || cached.time.completed !== undefined)) {
22658
+ current.entries.set(id, cached);
22659
+ passTimes.set(id, cached.time);
22660
+ } else
22661
+ refresh.push(id);
22662
+ }
22663
+ const times = reader.messageTimes(sessionID, refresh, versions);
22664
+ for (const id of refresh) {
22665
+ const time = times.get(id);
22666
+ const version = versions.get(id);
22667
+ passTimes.set(id, time ?? null);
22668
+ if (time && version) {
22669
+ const entry = { version, time };
22670
+ if (isSettled(entry, readAt))
22671
+ current.entries.set(id, entry);
22672
+ }
22673
+ }
22674
+ }
22675
+ const result = new Map;
22676
+ for (const id of ids) {
22677
+ const time = passTimes.get(id);
22678
+ if (time)
22679
+ result.set(id, { ...time });
22680
+ }
22681
+ return result;
22682
+ };
22683
+ }
22684
+ }
22685
+
21816
22686
  // src/v2/hooks/channel2.ts
21817
22687
  import { randomBytes as randomBytes2 } from "node:crypto";
21818
22688
  var pendingCandidates = new WeakMap;
@@ -22038,26 +22908,70 @@ function generateReplayAnchor(messages) {
22038
22908
  return;
22039
22909
  return { id, tail: clonePreservingInstances(messages.slice(index + 1)) };
22040
22910
  }
22911
+ var DEFAULT_GENERATE_REPLAY_LIMITS = Object.freeze({
22912
+ maxSessions: 16,
22913
+ sessionMaxBytes: 128 * 1024 * 1024,
22914
+ totalMaxBytes: 256 * 1024 * 1024
22915
+ });
22041
22916
 
22042
22917
  class V2GenerateReplay {
22043
22918
  prefixes = new Map;
22919
+ totalBytes = 0;
22920
+ limits;
22921
+ constructor(limits = DEFAULT_GENERATE_REPLAY_LIMITS) {
22922
+ if (!Number.isSafeInteger(limits.maxSessions) || limits.maxSessions < 1 || !Number.isSafeInteger(limits.sessionMaxBytes) || limits.sessionMaxBytes < 1 || !Number.isSafeInteger(limits.totalMaxBytes) || limits.totalMaxBytes < 1)
22923
+ throw new Error("Generate replay limits must be positive integers");
22924
+ this.limits = { ...limits };
22925
+ }
22044
22926
  capture(draft, anchor) {
22927
+ this.forget(draft.sessionID);
22045
22928
  if (!anchor) {
22046
- this.prefixes.delete(draft.sessionID);
22047
22929
  sessionLog(draft.sessionID, "generate replay capture skipped: no-anchor");
22048
22930
  return;
22049
22931
  }
22932
+ const parts = {
22933
+ anchor: clonePreservingInstancesMeasured(anchor),
22934
+ system: clonePreservingInstancesMeasured(draft.system),
22935
+ messages: clonePreservingInstancesMeasured(draft.messages),
22936
+ tools: clonePreservingInstancesMeasured(draft.tools)
22937
+ };
22938
+ const bytes = 256 + parts.anchor.bytes + parts.system.bytes + parts.messages.bytes + parts.tools.bytes;
22939
+ if (bytes > this.limits.sessionMaxBytes || bytes > this.limits.totalMaxBytes) {
22940
+ sessionLog(draft.sessionID, `generate replay capture skipped: over-session-cap (${bytes} > ${Math.min(this.limits.sessionMaxBytes, this.limits.totalMaxBytes)} bytes)`);
22941
+ return;
22942
+ }
22943
+ while (this.prefixes.size > 0 && (this.prefixes.size >= this.limits.maxSessions || this.totalBytes + bytes > this.limits.totalMaxBytes)) {
22944
+ const oldest = this.prefixes.keys().next().value;
22945
+ if (oldest === undefined)
22946
+ break;
22947
+ this.forget(oldest);
22948
+ }
22050
22949
  this.prefixes.set(draft.sessionID, {
22051
- anchor: clonePreservingInstances(anchor),
22950
+ anchor: parts.anchor.copy,
22052
22951
  model: `${draft.model.providerID}/${draft.model.id}`,
22053
22952
  agent: draft.agent,
22054
- system: clonePreservingInstances(draft.system),
22055
- messages: clonePreservingInstances(draft.messages),
22056
- tools: clonePreservingInstances(draft.tools)
22953
+ system: parts.system.copy,
22954
+ messages: parts.messages.copy,
22955
+ tools: parts.tools.copy,
22956
+ bytes
22057
22957
  });
22958
+ this.totalBytes += bytes;
22058
22959
  }
22059
22960
  forget(sessionID) {
22961
+ const prefix = this.prefixes.get(sessionID);
22962
+ if (!prefix)
22963
+ return;
22060
22964
  this.prefixes.delete(sessionID);
22965
+ this.totalBytes -= prefix.bytes;
22966
+ }
22967
+ stats() {
22968
+ return {
22969
+ totalBytes: this.totalBytes,
22970
+ sessions: [...this.prefixes].map(([sessionId, prefix]) => ({
22971
+ sessionId,
22972
+ bytes: prefix.bytes
22973
+ }))
22974
+ };
22061
22975
  }
22062
22976
  apply(draft) {
22063
22977
  const prefix = this.prefixes.get(draft.sessionID);
@@ -22067,6 +22981,8 @@ class V2GenerateReplay {
22067
22981
  };
22068
22982
  if (!prefix)
22069
22983
  return skip("no-prefix");
22984
+ this.prefixes.delete(draft.sessionID);
22985
+ this.prefixes.set(draft.sessionID, prefix);
22070
22986
  if (prefix.model !== `${draft.model.providerID}/${draft.model.id}`)
22071
22987
  return skip("model-mismatch");
22072
22988
  if (prefix.agent !== draft.agent)
@@ -22110,21 +23026,25 @@ function identity(slot) {
22110
23026
 
22111
23027
  class V2LkgSystemReplay {
22112
23028
  systems = new BoundedSessionMap(1000);
22113
- capture(sessionId, slot, input, served) {
23029
+ capture(sessionId, slot, input, served, head) {
22114
23030
  this.systems.set(sessionId, {
22115
23031
  slot: identity(slot),
22116
- input: JSON.stringify(input),
22117
- served: structuredClone(served)
23032
+ input: hostInputKey(input),
23033
+ served: structuredClone(served),
23034
+ head: head ? structuredClone(head) : null
22118
23035
  });
22119
23036
  }
22120
23037
  restore(sessionId, slot, input, target) {
22121
23038
  const saved = this.systems.get(sessionId);
22122
- if (!slot || !saved || saved.slot !== identity(slot) || saved.input !== JSON.stringify(input))
22123
- return false;
23039
+ if (!slot || !saved || saved.slot !== identity(slot) || saved.input !== hostInputKey(input))
23040
+ return;
22124
23041
  target.splice(0, target.length, ...structuredClone(saved.served));
22125
- return true;
23042
+ return { head: saved.head ? structuredClone(saved.head) : null };
22126
23043
  }
22127
23044
  }
23045
+ function hostInputKey(input) {
23046
+ return JSON.stringify({ system: input.system, checkpoint: input.checkpoint });
23047
+ }
22128
23048
 
22129
23049
  // src/v2/hooks/model-limit-cache.ts
22130
23050
  var warmStarted = false;
@@ -22701,7 +23621,7 @@ function projectRawMessages(rows, ordinalFor) {
22701
23621
  const message = {
22702
23622
  id: row.id,
22703
23623
  ordinal: ordinalFor(row, index),
22704
- role: row.type === "assistant" ? "assistant" : "user",
23624
+ role: row.type === "assistant" ? "assistant" : row.type === "system" ? "system" : "user",
22705
23625
  createdAt: row.time_created ?? row.data.time?.created,
22706
23626
  parts: row.type === "assistant" ? (row.data.content ?? []).map((part) => {
22707
23627
  if (part.type !== "tool")
@@ -22785,6 +23705,22 @@ function* readV2RawMessagePagesForConversion(openReader, sessionID, pageRows = C
22785
23705
  function createV2RawMessageReader(openReader) {
22786
23706
  const servedBoundaryCache = new Map;
22787
23707
  return {
23708
+ getRevision: (sessionID) => {
23709
+ const reader = openReader();
23710
+ try {
23711
+ return reader.latestSequence(sessionID);
23712
+ } finally {
23713
+ reader.close();
23714
+ }
23715
+ },
23716
+ getCountAfterRevision: (sessionID, after, through) => {
23717
+ const reader = openReader();
23718
+ try {
23719
+ return reader.messageCountAfterSequence(sessionID, after, through);
23720
+ } finally {
23721
+ reader.close();
23722
+ }
23723
+ },
22788
23724
  readPage: (sessionID, afterOrdinal, limit, finalWatermark, after) => {
22789
23725
  const reader = openReader();
22790
23726
  try {
@@ -23616,10 +24552,10 @@ function updateMemoryContentInCurrentTransaction(db, memory, content, normalized
23616
24552
  clearMemoryVerifications(db, memory.id);
23617
24553
  }
23618
24554
  var ctxMemoryArgsShape = {
23619
- action: tool2.schema.enum([...CTX_MEMORY_ACTIONS]).optional().describe("write | update | archive | merge | get"),
23620
- content: tool2.schema.string().optional().describe("The memory text — one standalone fact (write, update, merge)."),
23621
- category: tool2.schema.enum([...V2_MEMORY_CATEGORIES]).optional().describe("Kind of fact (required for write; on update/merge optional, omitted keeps the current category)."),
23622
- ids: tool2.schema.array(tool2.schema.number()).optional().describe("Memory ids from <project-memory>: one for update, one or more for archive, two or more for merge, 1–20 for get."),
24555
+ action: tool2.schema.enum([...CTX_MEMORY_ACTIONS]).describe("write | update | archive | merge | get"),
24556
+ content: tool2.schema.string().describe("The memory text — one standalone fact (write, update, merge)."),
24557
+ category: tool2.schema.enum([...V2_MEMORY_CATEGORIES]).describe("Kind of fact (required for write; on update/merge, pass the memory's current category to keep it)."),
24558
+ ids: tool2.schema.array(tool2.schema.number()).describe("Memory ids from <project-memory>: one for update, one or more for archive, two or more for merge, 1–20 for get."),
23623
24559
  reason: tool2.schema.string().optional().describe("Why it is being archived (optional).")
23624
24560
  };
23625
24561
  var ctxMemoryArgsSchema = tool2.schema.object({ ...ctxMemoryArgsShape }).passthrough();
@@ -23977,7 +24913,7 @@ function renderGlance(notes, options) {
23977
24913
  const remaining = ordered.length - options.offset - page.length;
23978
24914
  const footer = remaining > 0 ? `
23979
24915
 
23980
- Showing ${page.length} of ${ordered.length} — ${remaining} older: mmc_note(action="read", offset=${options.offset + page.length})` : "";
24916
+ Showing ${page.length} of ${ordered.length} — ${remaining} older: mmc_note(action="read", content="", note_ids=[], offset=${options.offset + page.length})` : "";
23981
24917
  return `## Notes
23982
24918
 
23983
24919
  ${rows}${footer}`;
@@ -24015,7 +24951,7 @@ function captureAnchorOrdinal(db, sessionId) {
24015
24951
  }
24016
24952
  var DISMISS_FOOTER = `
24017
24953
 
24018
- To dismiss a stale note: mmc_note(action="dismiss", note_ids=[N])`;
24954
+ To dismiss a stale note: mmc_note(action="dismiss", note_ids=[N], content="")`;
24019
24955
  var DEFAULT_READ_LIMIT = 25;
24020
24956
  function readGlanceNotes(args) {
24021
24957
  if (args.filter === undefined) {
@@ -24045,12 +24981,12 @@ function noteAuthorityRefusal(action) {
24045
24981
  return renderCapabilityRefusal(isMutation ? "note_change" : "note_access");
24046
24982
  }
24047
24983
  var ctxNoteArgsShape = {
24048
- action: tool3.schema.enum(["write", "read", "dismiss", "update"]).optional().describe("write | read | update | dismiss. Defaults to write when content is given, else read."),
24049
- content: tool3.schema.string().optional().describe("Note text for write/update: first line is the title (under 80 chars), then the detail."),
24984
+ action: tool3.schema.enum(["write", "read", "dismiss", "update"]).describe("write | read | update | dismiss."),
24985
+ content: tool3.schema.string().describe("Note text for write/update: first line is the title (under 80 chars), then the detail."),
24050
24986
  filter: tool3.schema.enum(["all", "active", "dismissed"]).optional().describe("Read filter: active (default), all, dismissed."),
24051
24987
  limit: tool3.schema.number().optional().describe("Rows per read (default 25)."),
24052
24988
  offset: tool3.schema.number().optional().describe("Skip this many newest rows (default 0)."),
24053
- note_ids: tool3.schema.array(tool3.schema.number().int().min(1)).min(1).max(50).optional().describe("Note ids: one for update, 1–50 for dismiss or read (read returns full bodies). Ignored by write.")
24989
+ note_ids: tool3.schema.array(tool3.schema.number().int().min(1)).max(50).describe("Note ids: one for update, 1–50 for dismiss, or 1–50 to read those notes in full. Write and a plain read take an empty list.")
24054
24990
  };
24055
24991
  var ctxNoteArgsSchema = tool3.schema.object(ctxNoteArgsShape).passthrough();
24056
24992
  function formatDismissResults(results) {
@@ -24089,7 +25025,8 @@ function createCtxNoteTool(deps) {
24089
25025
  });
24090
25026
  const sessionId = toolContext.sessionID;
24091
25027
  const action = args.action ?? (args.content?.trim() ? "write" : "read");
24092
- const noteIds = action === "dismiss" || action === "update" || action === "read" && args.note_ids !== undefined ? parseNoteIds(action, args.note_ids) : undefined;
25028
+ const targetedReadIds = action === "read" && Array.isArray(args.note_ids) && args.note_ids.length === 0 ? undefined : args.note_ids;
25029
+ const noteIds = action === "dismiss" || action === "update" || action === "read" && targetedReadIds !== undefined ? parseNoteIds(action, targetedReadIds) : undefined;
24093
25030
  if (typeof noteIds === "string")
24094
25031
  return noteIds;
24095
25032
  const projectIdentity = deps.resolveProjectPath?.(toolContext.directory);
@@ -24252,7 +25189,7 @@ function createCtxReduceTool(deps) {
24252
25189
  args = unwrapImitatedReducedArgs(args, ["drop"], { drop: "string" });
24253
25190
  const sessionId = toolContext.sessionID;
24254
25191
  if (!args.drop) {
24255
- return "Error: 'drop' must be provided.";
25192
+ return `Error: 'drop' must be provided as a string of tag numbers, for example {"drop": "3-5,8"}.`;
24256
25193
  }
24257
25194
  let dropIds = [];
24258
25195
  try {
@@ -24634,6 +25571,26 @@ function persistV2UsageReading(args) {
24634
25571
  }
24635
25572
 
24636
25573
  // src/v2/hooks/context.ts
25574
+ function applyCheckpointHead(draft, head) {
25575
+ const { checkpoint, submitted } = head;
25576
+ const first = draft.messages.find((message) => message.id === HEAD_IDS[0]);
25577
+ const baseline = first?.content.find((part) => part.type === "text")?.text;
25578
+ if (typeof baseline !== "string")
25579
+ return false;
25580
+ for (const part of checkpoint.content)
25581
+ if (part.type === "text" && typeof part.text === "string") {
25582
+ part.text = part.text.replace(`<summary>
25583
+ ${submitted}
25584
+ </summary>`, `<summary>
25585
+ ${baseline}
25586
+ </summary>`);
25587
+ }
25588
+ const volatile = draft.messages.find((message) => message.id === HEAD_IDS[1]);
25589
+ if (volatile && first)
25590
+ volatile.content.push(...first.content.filter((part) => part.type !== "text"));
25591
+ draft.messages.splice(0, draft.messages.length, checkpoint, ...draft.messages.filter((message) => message !== first));
25592
+ return true;
25593
+ }
24637
25594
  var HIDDEN_SESSION_ERROR_GRACE_MS = 50;
24638
25595
  var STORE_POOL_DISPOSE_WAIT_MS = 1000;
24639
25596
 
@@ -24811,16 +25768,23 @@ function applyV2PromptSurfaceTools(draft, runtime, config) {
24811
25768
  function recordV2ToolDefinitions(draft) {
24812
25769
  if (!draft.tools)
24813
25770
  return;
25771
+ const tools = [];
24814
25772
  for (const [id, tool] of Object.entries(draft.tools)) {
24815
25773
  if (!tool)
24816
25774
  continue;
24817
25775
  recordToolParameters(id, tool.input);
24818
- recordToolDefinition(draft.model.providerID, draft.model.id, draft.agent, id, typeof tool.description === "string" ? tool.description : "", tool.input);
25776
+ tools.push({
25777
+ id,
25778
+ description: typeof tool.description === "string" ? tool.description : "",
25779
+ parameters: tool.input
25780
+ });
24819
25781
  }
25782
+ recordToolDefinitionSet(draft.model.providerID, draft.model.id, draft.agent, tools, draft.sessionID);
24820
25783
  }
24821
25784
  async function registerContext(context) {
24822
25785
  const directory = context.location.directory;
24823
25786
  const config = loadPluginConfigDetailed(directory).config;
25787
+ log(`[magic-context] OpenCode 2 keep_subagents=${config.keep_subagents === true}`);
24824
25788
  setHomeProjectPermission(config.allow_home_project);
24825
25789
  if (!config.enabled)
24826
25790
  return;
@@ -24857,11 +25821,12 @@ async function registerContext(context) {
24857
25821
  }
24858
25822
  const folds = new FoldOwner(context.storage);
24859
25823
  const nativeFoldMemory = !compactionOff && process.env.MMC_OC2_INVISIBLE_FOLD === "1" ? nativeFoldCache(() => storage.require()) : undefined;
24860
- const nativeFoldReplay = nativeFoldMemory ? new NativeFoldReplay(nativeFoldMemory, () => openStoreReader()) : undefined;
25824
+ const nativeFoldReplay = nativeFoldMemory ? new NativeFoldReplay(nativeFoldMemory, () => openStoreReader(), context.storage) : undefined;
24861
25825
  setOutputReserveConfig(config.output_reserve);
24862
25826
  const queriedModels = new Set;
24863
25827
  const rawLimits = new Map;
24864
25828
  const hiddenSessionErrors = new Map;
25829
+ const committedSourceRefreshes = new Map;
24865
25830
  const liveModels = new Map;
24866
25831
  const promptSurfaceRuntime = createPromptSurfaceRuntime({
24867
25832
  harness: "opencode2",
@@ -24941,6 +25906,7 @@ async function registerContext(context) {
24941
25906
  };
24942
25907
  let hiddenAgentsReady;
24943
25908
  const readerPool = new V2StoreReaderPool;
25909
+ const messageTimesCache = new V2MessageTimesCache;
24944
25910
  const openStoreReader = () => readerPool.open(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"));
24945
25911
  const createHiddenExecutor = async (database) => {
24946
25912
  await cleanupLegacyOnce(database);
@@ -25184,88 +26150,129 @@ async function registerContext(context) {
25184
26150
  }) : undefined;
25185
26151
  const usageController = new AbortController;
25186
26152
  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) {
26153
+ let retry = 0;
26154
+ while (!usageController.signal.aborted) {
26155
+ const subscribedAt = Date.now();
26156
+ try {
26157
+ for await (const value of context.event.subscribe({
26158
+ signal: usageController.signal
26159
+ })) {
26160
+ if (usageController.signal.aborted)
26161
+ break;
26162
+ const event = value;
26163
+ try {
26164
+ if (event.type === "provider.updated" || event.type === "model.updated") {
26165
+ queriedModels.clear();
26166
+ continue;
26167
+ }
26168
+ if (!event.data?.sessionID)
26169
+ continue;
26170
+ const sessionID = event.data.sessionID;
26171
+ if (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated") {
26172
+ nativeFoldReplay?.onEvent(event);
26173
+ restoredRows.forget(sessionID);
26174
+ messageTimesCache.delete(sessionID);
26175
+ }
26176
+ if (event.type === "session.step.started" || event.type === "session.step.ended" || event.type === "session.step.failed") {
26177
+ const messageID = event.data.assistantMessageID;
26178
+ if (typeof messageID === "string")
26179
+ messageTimesCache.deleteMessage(sessionID, messageID);
26180
+ }
26181
+ if (event.type === "session.revert.committed") {
26182
+ committedSourceRefreshes.set(sessionID, {});
26183
+ const database = db;
26184
+ if (database)
26185
+ withoutSqliteTransformPass(() => scheduleClearAndReindex(database, sessionID, pagedRead));
26186
+ }
26187
+ if (event.type === "session.error" || event.type === "session.execution.failed") {
26188
+ const error = hiddenTerminalError(event);
26189
+ if (error !== undefined)
26190
+ hiddenSessionErrors.set(sessionID, error);
26191
+ if (error !== undefined && db && !compactionOff) {
26192
+ const model = liveModels.get(sessionID);
26193
+ try {
26194
+ armLatestThinkingRecoveryFromError({
26195
+ db,
26196
+ sessionId: sessionID,
26197
+ error,
26198
+ providerID: model?.providerID,
26199
+ modelID: model?.modelID
26200
+ });
26201
+ } catch (armError) {
26202
+ log("[magic-context] v2 latest-thinking recovery arm failed", armError);
26203
+ }
26204
+ }
26205
+ continue;
26206
+ }
26207
+ if (event.type === "session.deleted") {
26208
+ committedSourceRefreshes.delete(sessionID);
26209
+ clearLkgMeasuredRequest(sessionID);
26210
+ deletedSessions.add(sessionID);
26211
+ transform?.clearSessionLogState(sessionID);
26212
+ if (db) {
26213
+ markSessionCleanupPending(db, sessionID);
26214
+ clearSession(db, sessionID, false, true);
26215
+ }
26216
+ rawProviders.get(sessionID)?.();
26217
+ rawProviders.delete(sessionID);
26218
+ usage.delete(sessionID);
26219
+ messageTimesCache.delete(sessionID);
26220
+ hiddenSessionErrors.delete(sessionID);
26221
+ storageNoticeBySession.delete(sessionID);
26222
+ liveModels.delete(sessionID);
26223
+ variants.delete(sessionID);
26224
+ agents.delete(sessionID);
26225
+ channel1.delete(sessionID);
26226
+ historyRefreshSessions.delete(sessionID);
26227
+ clearPendingMaterialization(pendingMaterializationSessions, sessionID);
26228
+ lastHeuristicsTurnId.delete(sessionID);
26229
+ restoredRows.forget(sessionID);
26230
+ if (nativeFoldReplay)
26231
+ await nativeFoldReplay.forget(sessionID);
26232
+ else
26233
+ await forgetNativeFoldProvenance(context.storage, sessionID);
26234
+ generateReplay.forget(sessionID);
26235
+ systemPromptRefreshSessions.delete(sessionID);
26236
+ systemPrompt?.clearSession(sessionID);
26237
+ clearMaintenanceSystemSnapshot(sessionID);
26238
+ tagger.cleanup(sessionID);
26239
+ sessionDirectories.delete(sessionID);
26240
+ forkSeedSettled.delete(sessionID);
26241
+ continue;
26242
+ }
26243
+ if (event.type !== "session.execution.succeeded")
26244
+ continue;
25208
26245
  const model = liveModels.get(sessionID);
25209
- try {
25210
- armLatestThinkingRecoveryFromError({
25211
- db,
25212
- sessionId: sessionID,
25213
- error,
25214
- providerID: model?.providerID,
25215
- modelID: model?.modelID
26246
+ if (model) {
26247
+ await recordUsage({
26248
+ sessionID,
26249
+ model: { providerID: model.providerID, id: model.modelID }
25216
26250
  });
25217
- } catch (armError) {
25218
- log("[magic-context] v2 latest-thinking recovery arm failed", armError);
26251
+ if (!compactionOff && typeof await nativeFoldReplay?.baseline(sessionID) === "string")
26252
+ hostFolds?.idle(sessionID);
25219
26253
  }
26254
+ } catch (error) {
26255
+ log(`[magic-context] v2 event handler failed (type=${event.type ?? "unknown"}, session=${event.data?.sessionID ?? "none"})`, error);
25220
26256
  }
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
26257
  }
26258
+ } catch (error) {
26259
+ if (!usageController.signal.aborted)
26260
+ log("[magic-context] v2 usage subscription failed", error);
26261
+ }
26262
+ if (usageController.signal.aborted)
26263
+ break;
26264
+ if (Date.now() - subscribedAt >= 30000)
26265
+ retry = 0;
26266
+ const ceiling = Math.min(30000, 250 * 2 ** retry);
26267
+ retry = Math.min(retry + 1, 7);
26268
+ try {
26269
+ await delay(ceiling * (0.5 + Math.random() * 0.5), undefined, {
26270
+ signal: usageController.signal
26271
+ });
26272
+ } catch (error) {
26273
+ if (!usageController.signal.aborted)
26274
+ throw error;
25265
26275
  }
25266
- } catch (error) {
25267
- if (!usageController.signal.aborted)
25268
- log("[magic-context] v2 usage subscription failed", error);
25269
26276
  }
25270
26277
  })();
25271
26278
  const materialize = (draft) => {
@@ -25281,7 +26288,7 @@ async function registerContext(context) {
25281
26288
  memoryInjectionBudgetTokens: config.memory.injection_budget_tokens,
25282
26289
  hardSignals: {
25283
26290
  systemHash: foldDigest(JSON.stringify(draft.system)),
25284
- toolSetHash: getCurrentToolSetHash(draft.model.providerID, draft.model.id, draft.agent),
26291
+ toolSetHash: getCurrentToolSetHash(draft.model.providerID, draft.model.id, draft.agent, draft.sessionID),
25285
26292
  modelKey: `${draft.model.providerID}/${draft.model.id}`,
25286
26293
  cacheExpired: false,
25287
26294
  lastResponseTime: state.lastResponseTime
@@ -25338,20 +26345,116 @@ async function registerContext(context) {
25338
26345
  reader.close();
25339
26346
  }
25340
26347
  });
26348
+ const restoreAfterCheckpoint = (args) => {
26349
+ const { db, reader, draft, cut, boundaryRepair } = args;
26350
+ 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);
26351
+ const servedBoundary = boundaryID ? servedBoundaryRow(reader, draft.sessionID, boundaryID) : null;
26352
+ const boundary = servedBoundary?.seq ?? reader.sequenceForId(draft.sessionID, boundaryID) ?? (reader.earliestSequence(draft.sessionID) ?? 0) - 1;
26353
+ const present = new Set(args.messages.map((message) => message.id));
26354
+ const restored = restoredRows.rows(reader, draft.sessionID, boundary, cut.seq).filter((row) => !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model, hostUsesMediaAssets() ? {
26355
+ asset: hostMediaAsset,
26356
+ 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)}`)
26357
+ } : undefined));
26358
+ const covered = reader.instructionRowsThrough(draft.sessionID, Math.min(boundary, cut.seq)).flatMap((row) => restoreRow(row, draft.model)).map((message) => markCoveredInstructionRow(message));
26359
+ return [
26360
+ ...covered,
26361
+ ...restored,
26362
+ ...args.messages.filter((message) => message !== args.incoming)
26363
+ ];
26364
+ };
26365
+ const temporalTimes = config.temporal_awareness === true;
26366
+ const anchorTimesOnly = !temporalTimes;
26367
+ const timeIds = (messages) => {
26368
+ if (temporalTimes)
26369
+ return messages.flatMap((message) => message.id ? [message.id] : []);
26370
+ const ids = [];
26371
+ for (const message of [...messages].reverse()) {
26372
+ if (message.id)
26373
+ ids.push(message.id);
26374
+ if (message.role === "assistant")
26375
+ break;
26376
+ }
26377
+ return ids;
26378
+ };
26379
+ const initializeTransform = (database) => transform ??= createTransform({
26380
+ cacheTtlConfig: config.cache_ttl,
26381
+ cacheTtlConfigured: config.cacheTtlConfigured,
26382
+ sampleCacheTtlConfig: () => liveConfigReader.poll().effective,
26383
+ db: database,
26384
+ tagger,
26385
+ ...createV2ThresholdDeps(config),
26386
+ contextUsageMap: usage,
26387
+ compactionOff,
26388
+ storeGeneration: "v2",
26389
+ normalizeRestoredAssistantText: (text, providerID) => {
26390
+ const normalized = stripCopiedTagNotation(text);
26391
+ return normalized === "" && !modelAcceptsEmptyContent(providerID) ? text : normalized;
26392
+ },
26393
+ refreshSourceContents: (sessionID) => committedSourceRefreshes.has(sessionID),
26394
+ hostCleanupCompactionMarkers: () => ({
26395
+ verified: true,
26396
+ removedLineages: 0,
26397
+ removedRows: 0,
26398
+ retainedLineages: 0
26399
+ }),
26400
+ protectedTokens: config.protected_tokens,
26401
+ protectedTokenTierOverrides: getProtectedTokensTierOverrides(config),
26402
+ protectedTools: config.protected_tools,
26403
+ liveModelBySession: liveModels,
26404
+ getToolSetHash: (sessionId) => {
26405
+ const model = liveModels.get(sessionId);
26406
+ if (!model)
26407
+ return "";
26408
+ return getCurrentToolSetHash(model.providerID, model.modelID, agents.get(sessionId), sessionId);
26409
+ },
26410
+ channel1StateBySession: channel1,
26411
+ historyRefreshSessions,
26412
+ pendingMaterializationSessions,
26413
+ lastHeuristicsTurnId,
26414
+ variantBySession: variants,
26415
+ keepReasoningTokens: config.keep_reasoning_tokens,
26416
+ directory,
26417
+ sessionDirectoryBySession: sessionDirectories,
26418
+ projectPath: directory,
26419
+ agentBySession: agents,
26420
+ maintenanceConfig: config.maintenance ? () => inheritMaintenanceModelConfig(config) : undefined,
26421
+ hiddenCompletionExecutor,
26422
+ historianRunnable: !compactionOff && hiddenCompletionExecutor !== undefined && config.historian?.disable !== true,
26423
+ historianModel: historianModels.primary,
26424
+ fallbackModels: historianModels.fallbacks,
26425
+ resolveHistorianRun: sampleHistorian,
26426
+ historianTimeoutMs: config.historian_timeout_ms,
26427
+ historianMaxOutputTokens: config.historian?.maxTokens,
26428
+ historianTwoPass: config.historian?.two_pass,
26429
+ historianExpandTools: config.historian?.expand_tools,
26430
+ compactionMarkerStrategy: v2CompactionMarkerStrategy,
26431
+ memoryConfig: {
26432
+ enabled: config.memory.enabled,
26433
+ injectionBudgetTokens: config.memory.injection_budget_tokens,
26434
+ autoPromote: config.memory.auto_promote
26435
+ },
26436
+ ...createHostSeams(context, readAllForConversion, pagedRead, liveModels)
26437
+ });
25341
26438
  const runManagedContext = async (draft) => {
25342
26439
  rememberHostMedia(draft.messages);
25343
26440
  if (hiddenChildHook.apply(draft))
25344
26441
  return;
25345
26442
  if (deletedSessions.has(draft.sessionID))
25346
26443
  return;
25347
- const systemAtEntry = structuredClone(draft.system);
26444
+ let systemAtEntry = structuredClone(draft.system);
25348
26445
  const slotAtEntry = getSlot(draft.sessionID);
26446
+ let checkpointAtEntry;
26447
+ let replayHead;
26448
+ const hostInput = () => checkpointAtEntry === undefined ? undefined : { system: systemAtEntry, checkpoint: checkpointAtEntry };
25349
26449
  const restoreLkgSystem = () => {
25350
26450
  retirePendingSystemPromptDelivery(draft.sessionID);
25351
- if (!lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), systemAtEntry, draft.system)) {
26451
+ const input = hostInput();
26452
+ const restored = input && lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), input, draft.system);
26453
+ if (!restored) {
25352
26454
  sessionLog(draft.sessionID, "lkg_system_state_mismatch");
25353
26455
  throw new Error("LKG system identity is unavailable or changed");
25354
26456
  }
26457
+ replayHead = restored.head;
25355
26458
  };
25356
26459
  const isMagicContextSynthetic = (id) => isAdmittedSynthetic(context, draft.sessionID, id);
25357
26460
  const newest = draft.messages.at(-1);
@@ -25360,6 +26463,11 @@ async function registerContext(context) {
25360
26463
  return;
25361
26464
  }
25362
26465
  await dropStorageNotices(draft.messages, isMagicContextSynthetic);
26466
+ let hostMessagesAtEntry = [...draft.messages];
26467
+ const cachedTimes = messageTimesCache.pass(draft.sessionID);
26468
+ const readTimes = (reader, messages) => {
26469
+ return cachedTimes(reader, timeIds(messages));
26470
+ };
25363
26471
  liveModels.set(draft.sessionID, {
25364
26472
  providerID: draft.model.providerID,
25365
26473
  modelID: draft.model.id
@@ -25371,8 +26479,9 @@ async function registerContext(context) {
25371
26479
  applyV2PromptSurfaceTools(draft, promptSurfaceRuntime, config.prompt_surface);
25372
26480
  const admissionDb = db ?? storage.current();
25373
26481
  const replayFits = (messages) => {
25374
- const system = structuredClone(draft.system);
25375
- if (!admissionDb || !draft.tools || !lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), draft.system, system))
26482
+ const system = [];
26483
+ const input = hostInput();
26484
+ if (!admissionDb || !draft.tools || !input || !lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), input, system))
25376
26485
  return false;
25377
26486
  const limit = lkgReplayLimit({
25378
26487
  db: admissionDb,
@@ -25407,15 +26516,75 @@ async function registerContext(context) {
25407
26516
  })
25408
26517
  }).fit === "under";
25409
26518
  };
26519
+ const buildReplayInput = async () => {
26520
+ let messages = [...hostMessagesAtEntry];
26521
+ const admitted = new Set;
26522
+ let times;
26523
+ try {
26524
+ const reader = openStoreReader();
26525
+ try {
26526
+ const cut = reader.latestCompaction(draft.sessionID);
26527
+ const localCut = cut && isLocalCheckpoint(cut) ? cut : undefined;
26528
+ const incoming = localCut && messages.find((message) => message.id === localCut.id);
26529
+ if (localCut && !incoming || cut && nativeFoldReplay)
26530
+ return;
26531
+ checkpointAtEntry = incoming || null;
26532
+ const modeDb = db ?? storage.current();
26533
+ const subagent = modeDb ? storedSubagentMode(modeDb, draft.sessionID) : undefined;
26534
+ if (subagent === undefined)
26535
+ return;
26536
+ if (subagent)
26537
+ removePrimaryOnlyTools(draft.tools);
26538
+ const candidates = syntheticCandidates(context, draft.sessionID, reader.syntheticMessageIDs(draft.sessionID));
26539
+ for (const message of messages)
26540
+ if (message.id && candidates.has(message.id) && await isAdmittedSynthetic(context, draft.sessionID, message.id))
26541
+ admitted.add(message.id);
26542
+ const replayDb = db ?? storage.current();
26543
+ if (localCut && incoming && replayDb)
26544
+ messages = restoreAfterCheckpoint({
26545
+ db: replayDb,
26546
+ reader,
26547
+ draft,
26548
+ messages,
26549
+ cut: localCut,
26550
+ incoming,
26551
+ boundaryRepair: undefined
26552
+ });
26553
+ else if (localCut)
26554
+ return;
26555
+ times = readTimes(reader, messages);
26556
+ } finally {
26557
+ reader.close();
26558
+ }
26559
+ } catch (error) {
26560
+ sessionLog(draft.sessionID, "lkg replay input unavailable", error);
26561
+ return;
26562
+ }
26563
+ const replayDraft = { ...draft, messages };
26564
+ return {
26565
+ draft: replayDraft,
26566
+ mapped: adaptPayload(replayDraft, admitted, times, anchorTimesOnly)
26567
+ };
26568
+ };
26569
+ const adoptReplay = (replayed) => {
26570
+ draft.messages.splice(0, draft.messages.length, ...replayed.messages);
26571
+ if (replayHead)
26572
+ applyCheckpointHead(draft, replayHead);
26573
+ };
25410
26574
  let postFold = false;
25411
26575
  try {
25412
26576
  if (!compactionOff && admissionDb)
25413
26577
  await withAsyncPrivilegedWriter(admissionDb, () => {
25414
26578
  return;
25415
26579
  }, {
25416
- beforeRetry: (_error) => {
26580
+ beforeRetry: async (_error) => {
26581
+ hostMessagesAtEntry = [...draft.messages];
26582
+ systemAtEntry = structuredClone(draft.system);
25417
26583
  let replayBlocked = false;
25418
- const mapped = adaptPayload(draft);
26584
+ const input = await buildReplayInput();
26585
+ if (!input)
26586
+ return;
26587
+ const { mapped } = input;
25419
26588
  try {
25420
26589
  const overflowDb = db;
25421
26590
  if (overflowDb !== undefined && overflowDb !== null && (isEmergencyRecoveryArmed(draft.sessionID) || getOverflowState(overflowDb, draft.sessionID).needsEmergencyRecovery)) {
@@ -25436,6 +26605,7 @@ async function registerContext(context) {
25436
26605
  restoreLkgSystem();
25437
26606
  mapped.messages.splice(0, mapped.messages.length, ...replay.messages);
25438
26607
  mapped.commit();
26608
+ adoptReplay(input.draft);
25439
26609
  sessionLog(draft.sessionID, "lkg_replay_served");
25440
26610
  throw new V2LkgAdmissionReplay;
25441
26611
  } else {
@@ -25452,6 +26622,8 @@ async function registerContext(context) {
25452
26622
  sessionLog(draft.sessionID, "lkg_replay_declined");
25453
26623
  }
25454
26624
  });
26625
+ hostMessagesAtEntry = [...draft.messages];
26626
+ systemAtEntry = structuredClone(draft.system);
25455
26627
  if (admissionDb)
25456
26628
  hideSubagentTools(draft, admissionDb);
25457
26629
  recordV2ToolDefinitions(draft);
@@ -25545,63 +26717,15 @@ async function registerContext(context) {
25545
26717
  }
25546
26718
  });
25547
26719
  }
25548
- transform ??= createTransform({
25549
- cacheTtlConfig: config.cache_ttl,
25550
- cacheTtlConfigured: config.cacheTtlConfigured,
25551
- sampleCacheTtlConfig: () => liveConfigReader.poll().effective,
25552
- db,
25553
- tagger,
25554
- ...createV2ThresholdDeps(config),
25555
- contextUsageMap: usage,
25556
- compactionOff,
25557
- storeGeneration: "v2",
25558
- normalizeRestoredAssistantText: stripCopiedTagNotation,
25559
- hostCleanupCompactionMarkers: () => ({
25560
- verified: true,
25561
- removedLineages: 0,
25562
- removedRows: 0,
25563
- retainedLineages: 0
25564
- }),
25565
- protectedTokens: config.protected_tokens,
25566
- protectedTokenTierOverrides: getProtectedTokensTierOverrides(config),
25567
- protectedTools: config.protected_tools,
25568
- liveModelBySession: liveModels,
25569
- getToolSetHash: (sessionId) => {
25570
- const model = liveModels.get(sessionId);
25571
- if (!model)
25572
- return "";
25573
- return getCurrentToolSetHash(model.providerID, model.modelID, agents.get(sessionId));
25574
- },
25575
- channel1StateBySession: channel1,
25576
- historyRefreshSessions,
25577
- pendingMaterializationSessions,
25578
- lastHeuristicsTurnId,
25579
- variantBySession: variants,
25580
- keepReasoningTokens: config.keep_reasoning_tokens,
25581
- directory,
25582
- sessionDirectoryBySession: sessionDirectories,
25583
- projectPath: directory,
25584
- agentBySession: agents,
25585
- maintenanceConfig: config.maintenance ? () => inheritMaintenanceModelConfig(config) : undefined,
25586
- hiddenCompletionExecutor,
25587
- historianRunnable: !compactionOff && hiddenCompletionExecutor !== undefined && config.historian?.disable !== true,
25588
- historianModel: historianModels.primary,
25589
- fallbackModels: historianModels.fallbacks,
25590
- resolveHistorianRun: sampleHistorian,
25591
- historianTimeoutMs: config.historian_timeout_ms,
25592
- historianMaxOutputTokens: config.historian?.maxTokens,
25593
- historianTwoPass: config.historian?.two_pass,
25594
- historianExpandTools: config.historian?.expand_tools,
25595
- compactionMarkerStrategy: v2CompactionMarkerStrategy,
25596
- memoryConfig: {
25597
- enabled: config.memory.enabled,
25598
- injectionBudgetTokens: config.memory.injection_budget_tokens,
25599
- autoPromote: config.memory.auto_promote
25600
- },
25601
- ...createHostSeams(context, readAllForConversion, pagedRead, liveModels)
25602
- });
26720
+ transform = initializeTransform(db);
26721
+ const refreshToken = committedSourceRefreshes.get(draft.sessionID);
26722
+ if (refreshToken) {
26723
+ clearCachedM0(db, draft.sessionID);
26724
+ restoredRows.forget(draft.sessionID);
26725
+ }
25603
26726
  const admitted = new Set;
25604
26727
  const reader = openStoreReader();
26728
+ let messageTimes;
25605
26729
  let checkpoint;
25606
26730
  let submitted;
25607
26731
  try {
@@ -25616,12 +26740,14 @@ async function registerContext(context) {
25616
26740
  historyRefreshSessions.add(draft.sessionID);
25617
26741
  requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "boundary_repair");
25618
26742
  }
25619
- const incoming = cut && draft.messages.find((message) => message.id === cut.id);
26743
+ const localCut = cut && isLocalCheckpoint(cut) ? cut : undefined;
26744
+ const incoming = localCut && draft.messages.find((message) => message.id === localCut.id);
25620
26745
  postFold = cut !== undefined;
25621
- if (cut && !incoming)
26746
+ checkpointAtEntry = incoming || null;
26747
+ if (localCut && !incoming)
25622
26748
  throw new Error("The host checkpoint disappeared from the context draft");
25623
26749
  let nativeRestored;
25624
- if (cut && nativeFoldReplay && isLocalCheckpoint(cut)) {
26750
+ if (cut && nativeFoldReplay && await nativeFoldReplay.admits(draft.sessionID, cut, reader)) {
25625
26751
  try {
25626
26752
  nativeRestored = await nativeFoldReplay.restore(draft.sessionID, cut, `${draft.model.providerID}/${draft.model.id}`, { bounded: true });
25627
26753
  } catch (error) {
@@ -25630,7 +26756,7 @@ async function registerContext(context) {
25630
26756
  nativeRestored = await nativeFoldReplay.restoreRead(draft.sessionID, cut, draft.model);
25631
26757
  }
25632
26758
  }
25633
- if (nativeRestored && nativeFoldReplay?.sourceChanged(draft.sessionID)) {
26759
+ if (cut && nativeFoldReplay?.sourceChanged(draft.sessionID)) {
25634
26760
  historyRefreshSessions.add(draft.sessionID);
25635
26761
  requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "host_history_change");
25636
26762
  }
@@ -25641,30 +26767,33 @@ async function registerContext(context) {
25641
26767
  return !id || !present.has(id);
25642
26768
  });
25643
26769
  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));
26770
+ } else if (localCut && cut && incoming) {
26771
+ if (!nativeFoldReplay) {
26772
+ const identity = await folds.observe({
26773
+ sessionID: draft.sessionID,
26774
+ cutSeq: cut.seq,
26775
+ summary: cut.data.summary ?? "",
26776
+ rendered: incoming,
26777
+ onHard: (reason) => {
26778
+ log(`[magic-context] HARD reason=${reason} session=${draft.sessionID}`);
26779
+ materialize(draft);
26780
+ requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "host_compaction");
26781
+ }
26782
+ });
26783
+ checkpoint = structuredClone(identity.rendered ?? incoming);
26784
+ submitted = identity.rendered ? identity.renderedSummary ?? identity.submitted : cut.data.summary ?? "";
26785
+ }
26786
+ draft.messages.splice(0, draft.messages.length, ...restoreAfterCheckpoint({
26787
+ db,
26788
+ reader,
26789
+ draft,
26790
+ messages: draft.messages,
26791
+ cut: localCut,
26792
+ incoming,
26793
+ boundaryRepair
26794
+ }));
25667
26795
  }
26796
+ messageTimes = readTimes(reader, draft.messages);
25668
26797
  } finally {
25669
26798
  reader.close();
25670
26799
  }
@@ -25676,31 +26805,18 @@ async function registerContext(context) {
25676
26805
  nativeFoldReplay.invalidate(draft.sessionID, true);
25677
26806
  }
25678
26807
  }
25679
- const mapped = adaptPayload(draft, admitted);
26808
+ const mapped = adaptPayload(draft, admitted, messageTimes, anchorTimesOnly);
25680
26809
  bindSystemDateRequestIdentity(mapped, draft);
25681
26810
  await transform({}, mapped);
25682
26811
  mapped.commit();
26812
+ if (refreshToken && committedSourceRefreshes.get(draft.sessionID) === refreshToken)
26813
+ committedSourceRefreshes.delete(draft.sessionID);
25683
26814
  if (db) {
25684
26815
  await deliverPendingChannel2(context, db, draft.sessionID, channel1.get(draft.sessionID));
25685
26816
  }
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
- }
26817
+ const head = replayHead !== undefined ? replayHead : checkpoint && submitted !== undefined ? { checkpoint, submitted } : null;
26818
+ const servedHead = head && structuredClone(head);
26819
+ const headApplied = head ? applyCheckpointHead(draft, head) : false;
25704
26820
  if (nativeMessages && !checkpoint) {
25705
26821
  try {
25706
26822
  await nativeFoldReplay?.capture(draft, nativeMessages);
@@ -25711,7 +26827,7 @@ ${baseline}
25711
26827
  }
25712
26828
  const capturedSlot = getSlot(draft.sessionID);
25713
26829
  if (capturedSlot && (!slotAtEntry || capturedSlot.capturedAt !== slotAtEntry.capturedAt || capturedSlot.captureSequence !== slotAtEntry.captureSequence || capturedSlot.jsonPrefix !== slotAtEntry.jsonPrefix)) {
25714
- lkgSystems.capture(draft.sessionID, capturedSlot, systemAtEntry, draft.system);
26830
+ lkgSystems.capture(draft.sessionID, capturedSlot, { system: systemAtEntry, checkpoint: checkpointAtEntry ?? null }, draft.system, headApplied ? servedHead : null);
25715
26831
  }
25716
26832
  } catch (error) {
25717
26833
  if (error instanceof V2ContextRefusal)
@@ -25737,7 +26853,10 @@ ${baseline}
25737
26853
  replayBlocked = true;
25738
26854
  sessionLog(draft.sessionID, "lkg_emergency_armed");
25739
26855
  } else {
25740
- const replayMapped = adaptPayload(draft);
26856
+ const input = await buildReplayInput();
26857
+ if (!input)
26858
+ throw new StorageBusyRefusalError(error, "v2-context");
26859
+ const replayMapped = input.mapped;
25741
26860
  const keys = resolveLkgModelKeys(replayMapped.messages);
25742
26861
  const replay = replayLkg({
25743
26862
  sessionId: draft.sessionID,
@@ -25751,6 +26870,8 @@ ${baseline}
25751
26870
  restoreLkgSystem();
25752
26871
  replayMapped.messages.splice(0, replayMapped.messages.length, ...replay.messages);
25753
26872
  replayMapped.commit();
26873
+ adoptReplay(input.draft);
26874
+ sessionLog(draft.sessionID, "lkg_replay_served");
25754
26875
  return;
25755
26876
  } else {
25756
26877
  sessionLog(draft.sessionID, replay.reason);
@@ -25895,13 +27016,15 @@ ${baseline}
25895
27016
  }, 0);
25896
27017
  return {
25897
27018
  async dispose() {
27019
+ messageTimesCache.clear();
27020
+ usageController.abort();
25898
27021
  await hiddenCompletionExecutor?.dispose();
27022
+ await usageDone;
25899
27023
  rpcStopped = true;
25900
27024
  rpcServer.stop();
25901
27025
  tools?.dispose();
25902
- usageController.abort();
25903
- await usageDone;
25904
27026
  deletedSessions.clear();
27027
+ committedSourceRefreshes.clear();
25905
27028
  for (const release of rawProviders.values())
25906
27029
  release();
25907
27030
  rawProviders.clear();