@retaw106/mmc-oc 2.5.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 (92) hide show
  1. package/dist/{context-xx09sh1g.js → context-cfbjrr0n.js} +418 -166
  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.d.ts +1 -24
  5. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  6. package/dist/features/magic-context/session-decision-calibration.d.ts.map +1 -1
  7. package/dist/features/magic-context/session-retention.fixture.d.ts +4 -0
  8. package/dist/features/magic-context/session-retention.fixture.d.ts.map +1 -0
  9. package/dist/features/magic-context/storage-meta-persisted.d.ts +21 -1
  10. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  11. package/dist/features/magic-context/storage-native-replay.d.ts +2 -0
  12. package/dist/features/magic-context/storage-native-replay.d.ts.map +1 -1
  13. package/dist/features/magic-context/storage-session-tables.d.ts +4 -11
  14. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  15. package/dist/features/magic-context/tool-definition-tokens.d.ts +113 -58
  16. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  17. package/dist/features/magic-context/work-metrics.d.ts +5 -3
  18. package/dist/features/magic-context/work-metrics.d.ts.map +1 -1
  19. package/dist/hooks/magic-context/apply-operations.d.ts +32 -0
  20. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  21. package/dist/hooks/magic-context/ask-answer-notice.d.ts +25 -0
  22. package/dist/hooks/magic-context/ask-answer-notice.d.ts.map +1 -0
  23. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +5 -5
  24. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/compaction-marker-publication.d.ts +14 -0
  26. package/dist/hooks/magic-context/compaction-marker-publication.d.ts.map +1 -0
  27. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -1
  28. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +11 -0
  29. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +11 -3
  32. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/historian-history-wait.d.ts +16 -0
  34. package/dist/hooks/magic-context/historian-history-wait.d.ts.map +1 -0
  35. package/dist/hooks/magic-context/history-boundary-repair.d.ts +1 -1
  36. package/dist/hooks/magic-context/history-boundary-repair.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts +3 -1
  40. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/lkg-slot.d.ts +2 -0
  44. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/read-session-db.d.ts +8 -2
  47. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/read-session-raw.d.ts +20 -0
  49. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  50. package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts +42 -0
  51. package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts.map +1 -0
  52. package/dist/hooks/magic-context/tag-messages.d.ts +2 -0
  53. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/todo-view.d.ts +2 -2
  55. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  56. package/dist/{index-mjf0p7yq.js → index-1np16gxq.js} +1 -1
  57. package/dist/{index-bpjjcdy9.js → index-8rmt6s4f.js} +77 -31
  58. package/dist/{index-k25thxq7.js → index-s3ebcy63.js} +1 -1
  59. package/dist/{index-1vxffj5j.js → index-t0zx3tgz.js} +408 -89
  60. package/dist/{index-0d40b4q8.js → index-xk1dz6q9.js} +9322 -9215
  61. package/dist/index.js +2 -2
  62. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  63. package/dist/{read-session-chunk-eb3fy45y.js → read-session-chunk-2s8x6xps.js} +2 -2
  64. package/dist/{recomp-orchestrator-mmpy5cb7.js → recomp-orchestrator-51xyaexp.js} +5 -5
  65. package/dist/{send-session-notification-zpqs213d.js → send-session-notification-vdppp5x6.js} +2 -2
  66. package/dist/shared/tag-transcript.d.ts +2 -0
  67. package/dist/shared/tag-transcript.d.ts.map +1 -1
  68. package/dist/shared/transcript.d.ts +3 -1
  69. package/dist/shared/transcript.d.ts.map +1 -1
  70. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  71. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  72. package/dist/tools/parameter-descriptions.d.ts +6 -6
  73. package/dist/tools/parameter-descriptions.d.ts.map +1 -1
  74. package/dist/v2/hooks/context.d.ts +5 -1
  75. package/dist/v2/hooks/context.d.ts.map +1 -1
  76. package/dist/v2/hooks/store.d.ts.map +1 -1
  77. package/dist/v2/message-times.d.ts +17 -0
  78. package/dist/v2/message-times.d.ts.map +1 -0
  79. package/dist/v2/server.js +12923 -12197
  80. package/dist/v2/store-reader.d.ts +14 -4
  81. package/dist/v2/store-reader.d.ts.map +1 -1
  82. package/dist/web/main.js +85 -11
  83. package/dist/{wrapup-orchestrator-jq589pgr.js → wrapup-orchestrator-g0mww1h4.js} +5 -5
  84. package/package.json +1 -1
  85. package/src/config/latch-permanence-guard.test.ts +0 -5
  86. package/src/shared/prompt-surface-a1-golden.md +6 -7
  87. package/src/shared/sqlite-transaction-mode-guard.test.ts +2 -0
  88. package/src/shared/tag-transcript.ts +47 -4
  89. package/src/shared/transcript.ts +1 -1
  90. package/src/shared/write-transaction-attribution.test.ts +1 -6
  91. package/dist/features/magic-context/message-index-sweep.d.ts +0 -11
  92. package/dist/features/magic-context/message-index-sweep.d.ts.map +0 -1
@@ -71,21 +71,10 @@ import {
71
71
  searchMemoriesFTSUnion,
72
72
  clearMemoryVerifications,
73
73
  queueMemoryMutation,
74
- BoundedSessionMap,
75
- registerOwnRpcServerInstance,
76
- rpcPortDir,
77
- rpcPortFilePath,
78
- parseRpcPortFile,
79
- inspectProcessesAsync,
80
- dirtyLkgRecoveryRevision,
81
- ownsLkgDirtyFence,
82
- invalidateCleanLkgRecoveryFence,
74
+ scheduleAfterBootQuiet,
83
75
  cleanSearchText,
84
76
  keywordRelevance,
85
77
  matchedSearchSnippet,
86
- gaDatabasePath,
87
- RAW_MESSAGE_TYPES,
88
- V2StoreReaderPool,
89
78
  getLastIndexedOrdinal,
90
79
  getIndexedMessageIdAtOrdinal,
91
80
  getIndexedMessageCorpusSize,
@@ -93,8 +82,11 @@ import {
93
82
  isMessageIndexReconciledThrough,
94
83
  clearIndexedMessages,
95
84
  indexMessagesAfterOrdinal,
96
- sweepOrphanedOpenCodeMessageIndexesCooperatively,
97
- scheduleAfterBootQuiet,
85
+ registerOwnRpcServerInstance,
86
+ rpcPortDir,
87
+ rpcPortFilePath,
88
+ parseRpcPortFile,
89
+ inspectProcessesAsync,
98
90
  acquireCompartmentLease,
99
91
  releaseCompartmentLeaseBestEffort,
100
92
  isCompartmentLeaseHeld,
@@ -103,7 +95,7 @@ import {
103
95
  ensureSessionMetaRow,
104
96
  clearCachedM0M1,
105
97
  clearCachedM0,
106
- getCompartments,
98
+ getTableColumnNames,
107
99
  getLastCompartmentEndMessage,
108
100
  getLastCompartmentEndMessageId,
109
101
  getAuthorityManagedMarker,
@@ -163,6 +155,7 @@ import {
163
155
  clearEmergencyRecovery,
164
156
  clearDetectedContextLimit,
165
157
  getPersistedCompactionMarkerState,
158
+ clearCompactionMarkerPublicationIntent,
166
159
  setPersistedCompactionMarkerState,
167
160
  getDeferredClearedCompactionMarkerState,
168
161
  retireDeferredClearedCompactionMarkerState,
@@ -191,10 +184,16 @@ import {
191
184
  resolveEpochFloorForPass,
192
185
  providerResponseFailed,
193
186
  isSuccessfulProviderCompletion,
187
+ dirtyLkgRecoveryRevision,
188
+ ownsLkgDirtyFence,
189
+ invalidateCleanLkgRecoveryFence,
194
190
  rememberUnpublishedAutoSearchNoHint,
195
191
  getUnpublishedAutoSearchNoHint,
196
192
  forgetUnpublishedAutoSearchNoHint,
197
193
  registerAutoSearchWork,
194
+ gaDatabasePath,
195
+ RAW_MESSAGE_TYPES,
196
+ V2StoreReaderPool,
198
197
  getOrCreateSessionMeta,
199
198
  updateSessionMeta,
200
199
  advanceToolReclaimWatermark,
@@ -226,6 +225,7 @@ import {
226
225
  lkgDirtyRevision,
227
226
  readLkgRecoveryPrefix,
228
227
  noteLkgHealthyPrefix,
228
+ lkgInputIdentity,
229
229
  beginLkgPass,
230
230
  getInMemorySlot,
231
231
  getSlot,
@@ -277,6 +277,7 @@ import {
277
277
  HISTORIAN_RECOMP_AGENT,
278
278
  HISTORIAN_EDITOR_AGENT,
279
279
  runTokenLog,
280
+ shouldWaitForNewHistorianHistory,
280
281
  extractM0Block,
281
282
  TEMPORAL_MARKER_REPLAY_PATTERN,
282
283
  collectTemporalCandidates,
@@ -307,7 +308,7 @@ import {
307
308
  recordHighPressureNoEligibleHead,
308
309
  getActiveCompartmentRun,
309
310
  startCompartmentAgent
310
- } from "./index-0d40b4q8.js";
311
+ } from "./index-xk1dz6q9.js";
311
312
  import {
312
313
  getHarness,
313
314
  getDataDir,
@@ -450,8 +451,9 @@ import {
450
451
  createDroppedInputGuard,
451
452
  assertExecutableToolInput,
452
453
  isEditTool,
454
+ BoundedSessionMap,
455
+ recordToolDefinitionSet,
453
456
  getCurrentToolSetHash,
454
- recordToolDefinition,
455
457
  getMeasuredToolDefinitionTokens,
456
458
  describeFinalWireTail,
457
459
  estimatePartImageTokens,
@@ -487,13 +489,12 @@ import {
487
489
  hasRawSessionMessageById2,
488
490
  readRawSessionMessageById2,
489
491
  readSessionChunk2
490
- } from "./index-1vxffj5j.js";
492
+ } from "./index-t0zx3tgz.js";
491
493
  import {
492
494
  normalizeModelEntry2,
493
495
  resolveHistorianModel2
494
496
  } from "./index-azbmnekv.js";
495
497
  import {
496
- Database,
497
498
  getSqliteMemoryStats,
498
499
  withSqliteBackgroundWriter,
499
500
  withSqliteTransformPass,
@@ -520,7 +521,7 @@ import {
520
521
  latestRealUserTurnIdFromOpenCodeDb,
521
522
  getMessageTimesFromOpenCodeDb,
522
523
  findLastAssistantModelFromOpenCodeDb
523
- } from "./index-bpjjcdy9.js";
524
+ } from "./index-8rmt6s4f.js";
524
525
  import {
525
526
  registerNotificationSink2,
526
527
  pushNotification2,
@@ -533,7 +534,7 @@ import {
533
534
  getErrorMessage,
534
535
  flushIgnoredMessages2,
535
536
  sendStatusNotification2
536
- } from "./index-k25thxq7.js";
537
+ } from "./index-s3ebcy63.js";
537
538
  import {
538
539
  logSlowWriteTransaction
539
540
  } from "./index-yjv8dpht.js";
@@ -6371,6 +6372,26 @@ class EmergencyFailClosedError extends Error {
6371
6372
  }
6372
6373
 
6373
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
+ }
6374
6395
  function readBaseline(db, sessionId) {
6375
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);
6376
6397
  return {
@@ -6436,7 +6457,7 @@ function dropCompartmentsAfter(db, sessionId, anchor, holderId, activeBranch = f
6436
6457
  }
6437
6458
  function repairMissingHistoryBoundary(args) {
6438
6459
  const { db, sessionId, isInHostStore, scope = "store" } = args;
6439
- 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);
6440
6461
  let latestIndex = compartments.length - 1;
6441
6462
  while (latestIndex >= 0 && !compartments[latestIndex]?.endMessageId)
6442
6463
  latestIndex -= 1;
@@ -6480,7 +6501,7 @@ function repairMissingHistoryBoundary(args) {
6480
6501
  let dropped;
6481
6502
  let anchorForDrop = anchor;
6482
6503
  try {
6483
- if (scope === "active-branch" && anchor) {
6504
+ if (anchor) {
6484
6505
  const row = db.prepare("SELECT end_message AS endMessage FROM compartments WHERE session_id = ? AND sequence = ?").get(sessionId, anchor.sequence);
6485
6506
  if (!row)
6486
6507
  return { kind: "unresolved", reason: "busy", missingEndMessageId: missing };
@@ -11363,6 +11384,8 @@ function reconcileCompactionMode(args) {
11363
11384
  return NO_TRANSITION;
11364
11385
  if (stored === "off_cleanup_pending") {
11365
11386
  const markerCleanup = (args.cleanupMarkers ?? cleanupOffMarkers)(sessionId);
11387
+ if (markerCleanup.verified)
11388
+ clearCompactionMarkerPublicationIntent(db, sessionId);
11366
11389
  return {
11367
11390
  ...NO_TRANSITION,
11368
11391
  recordToWrite: markerCleanup.verified ? "off" : null,
@@ -11377,7 +11400,9 @@ function reconcileCompactionMode(args) {
11377
11400
  if (markerCleanup.removedRows > 0)
11378
11401
  clearedSomething = true;
11379
11402
  if (getPersistedCompactionMarkerState(db, sessionId) !== null) {
11380
- setPersistedCompactionMarkerState(db, sessionId, null);
11403
+ setPersistedCompactionMarkerState(db, sessionId, null, {
11404
+ preservePending: !markerCleanup.verified
11405
+ });
11381
11406
  clearedSomething = true;
11382
11407
  }
11383
11408
  const pendingMarker = getPendingCompactionMarkerState(db, sessionId);
@@ -11920,6 +11945,13 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
11920
11945
  }
11921
11946
  return { shouldFire: false };
11922
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
+ }
11923
11955
  const canClearReasoning = reasoningProjection?.canClearReasoning ?? modelAcceptsEmptyContent(reasoningProjection?.providerID);
11924
11956
  const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), keepReasoningTokens, sessionMeta.clearedReasoningThroughTag, canClearReasoning, reasoningProjection?.budgetCutoff, eligiblePendingDropTagIds);
11925
11957
  const relativePostDropTarget = executeThresholdPercentage * POST_DROP_TARGET_RATIO;
@@ -12104,6 +12136,27 @@ function resolveHistoryBudgetTokens(historyBudgetPercentage, contextUsage, execu
12104
12136
  }) / 100) * historyBudgetPercentage);
12105
12137
  }
12106
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
+
12107
12160
  // src/hooks/magic-context/temporal-served-projection.ts
12108
12161
  function readLkgTemporalDecisions(db, sessionId, runtime) {
12109
12162
  const slot = getInMemorySlot(sessionId) ?? loadPersistedLkgSlot(db, sessionId);
@@ -12601,6 +12654,14 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
12601
12654
  function buildReplacementContent(tagId) {
12602
12655
  return `[dropped §${tagId}§]`;
12603
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
+ }
12604
12665
  function applyNewToolDrop(target, options) {
12605
12666
  const plan = planNewToolDrop(target, options, !!options.persist);
12606
12667
  if (!plan)
@@ -12682,6 +12743,7 @@ function prepareLegacyToolSkeletonConversions(db, sessionId, targets, options =
12682
12743
  AND drop_mode IN ('truncated', 'full')
12683
12744
  ORDER BY tag_number`).all(sessionId);
12684
12745
  const rows = readRows(db);
12746
+ options.prepareRemovals?.(rows);
12685
12747
  const identity = JSON.stringify(rows);
12686
12748
  const converted = new Map;
12687
12749
  for (const row of rows) {
@@ -12721,13 +12783,21 @@ function renderConvertedToolSkeletons(targets, converted) {
12721
12783
  return didMutate;
12722
12784
  }
12723
12785
  var PENDING_OPERATION_CHUNK_SIZE = 64;
12786
+ var PENDING_OPERATION_REJECTED_LOG_CHUNK = 20;
12724
12787
  function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set, onTagReduced, onBatchComplete, onEligibilitySnapshot) {
12725
12788
  let didMutateMessage = false;
12726
12789
  let diagnostics;
12727
- const reject = (reason) => {
12790
+ const reject = (tagNumber, reason, state = {}) => {
12728
12791
  if (!diagnostics)
12729
12792
  return;
12730
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
+ });
12731
12801
  };
12732
12802
  let admitted = false;
12733
12803
  let startedAt = 0;
@@ -12787,29 +12857,39 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12787
12857
  for (const { op: pendingOp, synthetic } of chunk) {
12788
12858
  const tagStatus = tagStatusById.get(pendingOp.tagId);
12789
12859
  if (tagStatus === "compacted" || tagStatus === "dropped") {
12790
- reject("already_reduced");
12860
+ reject(pendingOp.tagId, "already_reduced", {
12861
+ queueState: synthetic ? "none" : "removed"
12862
+ });
12791
12863
  if (!synthetic)
12792
12864
  removePendingOp(db, sessionId, pendingOp.tagId);
12793
12865
  continue;
12794
12866
  }
12795
12867
  if (removedTagIds.has(pendingOp.tagId)) {
12796
- reject("drop_incomplete");
12868
+ reject(pendingOp.tagId, "drop_incomplete", {
12869
+ queueState: synthetic ? "none" : "retained"
12870
+ });
12797
12871
  continue;
12798
12872
  }
12799
12873
  const target = targets.get(pendingOp.tagId);
12800
12874
  const veto = pendingDropVeto(pendingOp.tagId, target, protectedTagIds);
12801
12875
  if (veto) {
12802
- reject(veto);
12876
+ reject(pendingOp.tagId, veto, {
12877
+ queueState: synthetic ? "none" : "retained"
12878
+ });
12803
12879
  continue;
12804
12880
  }
12805
12881
  const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
12806
12882
  if (synthetic) {
12807
12883
  if (!isToolTag) {
12808
- reject("synthetic_non_tool");
12884
+ reject(pendingOp.tagId, "synthetic_non_tool", {
12885
+ queueState: "none"
12886
+ });
12809
12887
  continue;
12810
12888
  }
12811
12889
  if (target?.canDrop?.() !== true) {
12812
- reject("synthetic_target_not_droppable");
12890
+ reject(pendingOp.tagId, "synthetic_target_not_droppable", {
12891
+ queueState: "none"
12892
+ });
12813
12893
  continue;
12814
12894
  }
12815
12895
  }
@@ -12822,14 +12902,19 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12822
12902
  if (editMarkerTagIds.has(pendingOp.tagId)) {
12823
12903
  const strip = target?.hasAttachments?.() === true;
12824
12904
  if (target?.canDrop?.() === false || target?.prepareDrop?.() === false || !target) {
12825
- reject("edit_marker_incomplete");
12905
+ reject(pendingOp.tagId, "edit_marker_incomplete", {
12906
+ queueState: synthetic ? "none" : "retained"
12907
+ });
12826
12908
  continue;
12827
12909
  }
12828
12910
  persistDrop(strip ? "edit_marker_stripped" : "edit_marker");
12829
12911
  mutations.push(() => {
12830
12912
  const markResult = (strip ? target?.editMarkerStripped?.() : target?.editMarker?.()) ?? "absent";
12831
12913
  if (markResult === "incomplete" || markResult === "absent") {
12832
- reject(`edit_marker_${markResult}`);
12914
+ reject(pendingOp.tagId, `edit_marker_${markResult}`, {
12915
+ persisted: true,
12916
+ queueState: synthetic ? "none" : "removed"
12917
+ });
12833
12918
  return;
12834
12919
  }
12835
12920
  record(true);
@@ -12841,7 +12926,9 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12841
12926
  } else {
12842
12927
  const plan = planNewToolDrop(target, { inWindow: skeletonWindow.has(pendingOp.tagId) }, true, plannedRemovals);
12843
12928
  if (!plan) {
12844
- reject("drop_incomplete");
12929
+ reject(pendingOp.tagId, "drop_incomplete", {
12930
+ queueState: synthetic ? "none" : "retained"
12931
+ });
12845
12932
  continue;
12846
12933
  }
12847
12934
  persistDrop(plan.mode);
@@ -12852,7 +12939,10 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12852
12939
  mutations.push(() => {
12853
12940
  const { result: dropResult, mode: appliedMode } = plan.apply();
12854
12941
  if (dropResult === "incomplete" || synthetic && dropResult !== "removed" && dropResult !== "truncated") {
12855
- reject(`drop_${dropResult}`);
12942
+ reject(pendingOp.tagId, `drop_${dropResult}`, {
12943
+ persisted: true,
12944
+ queueState: synthetic ? "none" : "removed"
12945
+ });
12856
12946
  return;
12857
12947
  }
12858
12948
  if (dropResult === "removed" || dropResult === "truncated") {
@@ -12862,15 +12952,18 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12862
12952
  mode: appliedMode === "full" ? "full" : "truncated"
12863
12953
  });
12864
12954
  } else {
12865
- reject(`drop_${dropResult}`);
12955
+ reject(pendingOp.tagId, `drop_${dropResult}`, {
12956
+ persisted: true,
12957
+ queueState: synthetic ? "none" : "removed"
12958
+ });
12866
12959
  record(false);
12867
12960
  }
12868
12961
  });
12869
12962
  }
12870
12963
  } else if (target) {
12871
- const replacement = buildReplacementContent(pendingOp.tagId);
12964
+ const replacement = renderDroppedText(pendingOp.tagId, target.getContent?.());
12872
12965
  if (target.canSetContent?.(replacement) === false) {
12873
- reject("content_unchanged");
12966
+ reject(pendingOp.tagId, "content_unchanged");
12874
12967
  continue;
12875
12968
  }
12876
12969
  persistDrop();
@@ -12886,12 +12979,18 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12886
12979
  removedCharacters: Math.max(0, originalCharacters - replacement.length)
12887
12980
  });
12888
12981
  } else {
12889
- reject("content_unchanged");
12982
+ reject(pendingOp.tagId, "content_unchanged", {
12983
+ persisted: true,
12984
+ queueState: "removed"
12985
+ });
12890
12986
  }
12891
12987
  });
12892
12988
  } else if (!synthetic) {
12893
- reject("target_absent");
12894
12989
  persistDrop();
12990
+ reject(pendingOp.tagId, "target_absent", {
12991
+ persisted: true,
12992
+ queueState: "removed"
12993
+ });
12895
12994
  mutations.push(() => record(false));
12896
12995
  }
12897
12996
  }
@@ -12918,6 +13017,15 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12918
13017
  const reasons = Object.entries(diagnostics.reasons).sort(([left], [right]) => left.localeCompare(right)).map(([reason, count]) => `${reason}:${count}`).join(",");
12919
13018
  sessionLog(sessionId, `pending operations no-op: source=${diagnostics.source} total=${diagnostics.total} persisted=${diagnostics.persistedWithoutMutation} reasons=${reasons || "none"}`);
12920
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
+ }
12921
13029
  }
12922
13030
  return didMutateMessage;
12923
13031
  }
@@ -12958,7 +13066,7 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
12958
13066
  }
12959
13067
  }
12960
13068
  } else if (target) {
12961
- const changed = target.setContent(buildReplacementContent(tag.tagNumber));
13069
+ const changed = target.setContent(renderDroppedText(tag.tagNumber, target.getContent?.()));
12962
13070
  if (changed)
12963
13071
  didMutateMessage = true;
12964
13072
  }
@@ -16463,7 +16571,7 @@ function createTransform(deps) {
16463
16571
  const startTime = performance.now();
16464
16572
  const historianRun = deps.resolveHistorianRun?.();
16465
16573
  const messages = output.messages;
16466
- const originalForThinkingFit = messages.some((message) => message.parts.some((part) => isRecord(part) && ["reasoning", "thinking", "redacted_thinking"].includes(String(part.type)))) ? cloneKeepingCoveredInstructionMarks(messages) : null;
16574
+ const entryOrderForThinkingFit = messages.slice();
16467
16575
  const coveredHostInstructions = takeCoveredInstructionRows(messages);
16468
16576
  const passOutcome = createPassOutcome();
16469
16577
  const tSessionId = performance.now();
@@ -16478,8 +16586,21 @@ function createTransform(deps) {
16478
16586
  const temporalReplayIds = temporalCandidates ? messages.flatMap((message) => message.info.id ? [message.info.id] : []) : undefined;
16479
16587
  logTransformTiming(sessionId, "findSessionId", tSessionId, `messages=${messages.length}`);
16480
16588
  const tLkgEntry = performance.now();
16481
- const lkgInput = projectEntry(sessionId, messages);
16589
+ const lkgInput = projectEntry(sessionId, entryOrderForThinkingFit);
16482
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
+ }
16483
16604
  logTransformTiming(sessionId, "lkg.entryProjection", tLkgEntry, entryReuse ? `reused=${entryReuse.reused} retained=${entryReuse.retained} retainedBytes=${entryReuse.retainedBytes}` : undefined);
16484
16605
  const resolvedSessionId = sessionId;
16485
16606
  const runNotificationParams = (sid) => {
@@ -16781,6 +16902,13 @@ function createTransform(deps) {
16781
16902
  activeThinkingTurn ||= hasActiveAnthropicThinkingTurn(messages, resolvedProviderID, modelForBudget?.modelID);
16782
16903
  activeThinkingPrefixHold ||= activeThinkingTurn && isPrefixBoundThinkingModel(resolvedProviderID, modelForBudget?.modelID);
16783
16904
  freezeM0M1 ||= activeThinkingPrefixHold;
16905
+ const originalForThinkingFit = takeSignedThinkingFitSnapshot({
16906
+ sessionId,
16907
+ entryOrder: entryOrderForThinkingFit,
16908
+ held: activeThinkingPrefixHold,
16909
+ activeAnthropicThinkingTurn: activeThinkingTurn,
16910
+ compactionOff
16911
+ });
16784
16912
  if (freezeM0M1 && prefixHoldLogTurnIds.get(sessionId) !== currentTurnId) {
16785
16913
  prefixHoldLogTurnIds.set(sessionId, currentTurnId);
16786
16914
  const reason = activeThinkingPrefixHold ? "active thinking turn (prefix-bound model)" : "session directory unresolved";
@@ -16805,7 +16933,8 @@ function createTransform(deps) {
16805
16933
  systemPromptTokens: sessionMeta.systemPromptTokens,
16806
16934
  providerID: modelForBudget?.providerID,
16807
16935
  modelID: modelForBudget?.modelID,
16808
- agentName: runNotificationParams(sessionId)?.agent
16936
+ agentName: runNotificationParams(sessionId)?.agent,
16937
+ sessionId
16809
16938
  });
16810
16939
  const incomingTokens = incoming.messageTokens.conversation + incoming.messageTokens.toolCall;
16811
16940
  if (unmanagedOverWindowCarried || isClearlyOverWindow(incomingTokens, resolvedContextLimit)) {
@@ -17293,7 +17422,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17293
17422
  systemPromptTokens: sessionMeta.systemPromptTokens,
17294
17423
  providerID: modelForBudget?.providerID,
17295
17424
  modelID: modelForBudget?.modelID,
17296
- agentName: notificationParams.agent
17425
+ agentName: notificationParams.agent,
17426
+ sessionId
17297
17427
  });
17298
17428
  contextUsage = resolveUnknownUsageFromWireEstimate({
17299
17429
  usage: contextUsage,
@@ -17424,9 +17554,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17424
17554
  }
17425
17555
  });
17426
17556
  if (recovery.prefix && !recoveryNormalized) {
17427
- const priorIds = new Set(recovery.prefix.inputs.map((input) => input.id));
17428
- const newIds = new Set(lkgInput.flatMap((input) => input.id && !priorIds.has(input.id) ? [input.id] : []));
17429
- 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) ?? []);
17430
17566
  messages.splice(0, messages.length, ...JSON.parse(recovery.prefix.json), ...suffix);
17431
17567
  }
17432
17568
  const recoveryReleaseReason = recovery.rebuildReason ?? (recoveryNormalized ? "recovery_tail_normalized" : undefined);
@@ -17443,6 +17579,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17443
17579
  providerID: modelForBudget?.providerID,
17444
17580
  modelID: modelForBudget?.modelID,
17445
17581
  agentName: notificationParams.agent,
17582
+ sessionId,
17446
17583
  systemPromptHash: sessionMeta.systemPromptHash
17447
17584
  }, boundaryContextLimit);
17448
17585
  } catch {
@@ -17457,13 +17594,15 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17457
17594
  providerID: modelForBudget?.providerID,
17458
17595
  modelID: modelForBudget?.modelID,
17459
17596
  agentName: notificationParams.agent,
17597
+ sessionId,
17460
17598
  systemPromptHash: sessionMeta.systemPromptHash
17461
17599
  }, boundaryContextLimit) : undefined);
17462
17600
  if (finalWireEstimate) {
17463
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}`);
17464
17602
  }
17465
17603
  if ((finalWireEstimate?.refusalGrade || finalWireEstimate?.refusalBasis === "byte-bound" && finalWireEstimate.refusalTokens !== undefined) && boundaryContextLimit > 0 && (finalWireEstimate.refusalTokens ?? finalWireEstimate.tokens) > boundaryContextLimit) {
17466
- 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) {
17467
17606
  thinkingFitRetries.add(sessionId);
17468
17607
  requestPendingMaterialization(deps.pendingMaterializationSessions, sessionId, "fit_retry");
17469
17608
  messages.splice(0, messages.length, ...originalForThinkingFit);
@@ -17474,7 +17613,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17474
17613
  }
17475
17614
  return;
17476
17615
  }
17477
- 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)
17478
17620
  throw contextRefusalError("The request remains over the model window after stripping signed thinking and reclaiming context");
17479
17621
  }
17480
17622
  if (postTransformResult.prefixTrimStatus === "refused") {
@@ -17483,7 +17625,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17483
17625
  systemPromptTokens: sessionMeta.systemPromptTokens,
17484
17626
  providerID: modelForBudget?.providerID,
17485
17627
  modelID: modelForBudget?.modelID,
17486
- agentName: notificationParams.agent
17628
+ agentName: notificationParams.agent,
17629
+ sessionId
17487
17630
  });
17488
17631
  if (untrimmed.tokens > boundaryContextLimit) {
17489
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`);
@@ -17496,7 +17639,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17496
17639
  systemPromptTokens: sessionMeta.systemPromptTokens,
17497
17640
  providerID: modelForBudget?.providerID,
17498
17641
  modelID: modelForBudget?.modelID,
17499
- agentName: notificationParams.agent
17642
+ agentName: notificationParams.agent,
17643
+ sessionId
17500
17644
  });
17501
17645
  const servedTokens = served.toolDefinitionsMeasured ? served.rawTokens ?? served.tokens : Math.max(0, sessionMeta.systemPromptTokens) + served.messageTokens.conversation + served.messageTokens.toolCall;
17502
17646
  if (!Number.isFinite(servedTokens) || servedTokens > unmanagedOverWindowPass.limit) {
@@ -17574,7 +17718,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17574
17718
  systemPromptTokens: sessionMeta.systemPromptTokens,
17575
17719
  providerID: modelForBudget?.providerID,
17576
17720
  modelID: modelForBudget?.modelID,
17577
- agentName: notificationParams.agent
17721
+ agentName: notificationParams.agent,
17722
+ sessionId
17578
17723
  });
17579
17724
  } catch (error) {
17580
17725
  sessionLog(sessionId, "degraded pass size guard could not estimate:", error);
@@ -17786,6 +17931,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17786
17931
  providerID: modelForBudget?.providerID,
17787
17932
  modelID: modelForBudget?.modelID,
17788
17933
  agentName: notificationParams.agent,
17934
+ sessionId,
17789
17935
  systemPromptHash: sessionMeta.systemPromptHash
17790
17936
  });
17791
17937
  try {
@@ -18257,8 +18403,26 @@ WHERE session_id = ?
18257
18403
  AND data IS NOT NULL
18258
18404
  AND (time_created > ? OR (time_created = ? AND id > ?))
18259
18405
  ORDER BY time_created, id`;
18260
- function readAssistantUsageRowsAfter(openCodeDb, sessionId, afterTimeCreated, afterId) {
18261
- 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]);
18262
18426
  return rows.map((r) => ({
18263
18427
  agent: r.agent ?? null,
18264
18428
  timeCreated: Number(r.time_created ?? 0),
@@ -18267,8 +18431,8 @@ function readAssistantUsageRowsAfter(openCodeDb, sessionId, afterTimeCreated, af
18267
18431
  output: Number(r.output ?? 0)
18268
18432
  }));
18269
18433
  }
18270
- function computeOpenCodeWorkMetricsIncremental(openCodeDb, sessionId, carry) {
18271
- 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);
18272
18436
  if (rows.length === 0) {
18273
18437
  return { carry, metrics: metricsFromCarry(carry) };
18274
18438
  }
@@ -18466,13 +18630,15 @@ function resolveTailHygieneStatus(tsBaseline, rustBaseline) {
18466
18630
  // src/plugin/rpc-handlers.ts
18467
18631
  var workMetricsCarryBySession = new Map;
18468
18632
  function resolveSidebarWorkMetrics(db, sessionId, persistedNewWork, persistedTotalInput) {
18469
- if (!openCodeDbExists()) {
18633
+ const generation = getHarness() === "opencode2" ? "v2" : "v1";
18634
+ if (!openCodeDbExists(generation)) {
18470
18635
  return { newWorkTokens: persistedNewWork, totalInputTokens: persistedTotalInput };
18471
18636
  }
18472
18637
  try {
18473
- const carry = workMetricsCarryBySession.get(sessionId) ?? emptyWorkMetricsCarry();
18474
- const { carry: nextCarry, metrics } = withReadOnlySessionDb((openCodeDb) => computeOpenCodeWorkMetricsIncremental(openCodeDb, sessionId, carry));
18475
- 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);
18476
18642
  try {
18477
18643
  setSessionWorkMetrics(db, sessionId, metrics.newWorkTokens, metrics.totalInputTokens);
18478
18644
  } catch {}
@@ -18591,7 +18757,7 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
18591
18757
  if (model) {
18592
18758
  activeProviderID = model.providerID;
18593
18759
  activeModelID = model.modelID;
18594
- measuredToolDefTokens = getMeasuredToolDefinitionTokens(model.providerID, model.modelID, agent) ?? 0;
18760
+ measuredToolDefTokens = getMeasuredToolDefinitionTokens(model.providerID, model.modelID, agent, sessionId) ?? 0;
18595
18761
  }
18596
18762
  }
18597
18763
  const contextLimit = activeProviderID && activeModelID ? resolveContextLimit(activeProviderID, activeModelID, {
@@ -19077,8 +19243,8 @@ function registerRpcHandlers(rpcServer, args) {
19077
19243
  const db = readDatabase();
19078
19244
  if (!db)
19079
19245
  return { ok: false, error: "db unavailable" };
19080
- const { runManagedRecomp } = await import("./recomp-orchestrator-mmpy5cb7.js");
19081
- const { sendIgnoredMessage } = await import("./send-session-notification-zpqs213d.js");
19246
+ const { runManagedRecomp } = await import("./recomp-orchestrator-51xyaexp.js");
19247
+ const { sendIgnoredMessage } = await import("./send-session-notification-vdppp5x6.js");
19082
19248
  log(`[rpc] recomp requested for session ${sessionId}`);
19083
19249
  if (!args.client && !args.hiddenCompletionExecutor) {
19084
19250
  return {
@@ -19127,7 +19293,7 @@ function registerRpcHandlers(rpcServer, args) {
19127
19293
  const db = readDatabase();
19128
19294
  if (!db)
19129
19295
  return { ok: false, error: "db unavailable" };
19130
- const { runManagedWrapup } = await import("./wrapup-orchestrator-jq589pgr.js");
19296
+ const { runManagedWrapup } = await import("./wrapup-orchestrator-g0mww1h4.js");
19131
19297
  const model = liveSessionState.liveModelBySession.get(sessionId);
19132
19298
  const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
19133
19299
  const ctx = {
@@ -19822,17 +19988,17 @@ var FULL_PARAMETER_DESCRIPTIONS = {
19822
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."
19823
19989
  },
19824
19990
  mmc_note: {
19825
- action: "write | read | update | dismiss. Defaults to write when content is given, else read.",
19991
+ action: "write | read | update | dismiss.",
19826
19992
  content: "Note text for write/update: first line is the title (under 80 chars), then the detail.",
19827
19993
  filter: "Read filter: active (default), all, dismissed.",
19828
19994
  limit: "Rows per read (default 25).",
19829
19995
  offset: "Skip this many newest rows (default 0).",
19830
- 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."
19831
19997
  },
19832
19998
  mmc_memory: {
19833
19999
  action: "write | update | archive | merge | get",
19834
20000
  content: "The memory text — one standalone fact (write, update, merge).",
19835
- 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).",
19836
20002
  ids: "Memory ids from <project-memory>: one for update, one or more for archive, two or more for merge, 1–20 for get.",
19837
20003
  reason: "Why it is being archived (optional)."
19838
20004
  },
@@ -19856,17 +20022,17 @@ var LIGHT_PARAMETER_DESCRIPTIONS = {
19856
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."
19857
20023
  },
19858
20024
  mmc_note: {
19859
- action: "write | read | update | dismiss (default: write with content, else read).",
20025
+ action: "write | read | update | dismiss.",
19860
20026
  content: "Note text: first line title (<80 chars), then detail.",
19861
20027
  filter: "Read filter: active (default), all, dismissed.",
19862
20028
  limit: "Rows per read (default 25).",
19863
20029
  offset: "Skip newest rows (default 0).",
19864
- 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."
19865
20031
  },
19866
20032
  mmc_memory: {
19867
20033
  action: "write | update | archive | merge | get",
19868
20034
  content: "One standalone fact (write, update, merge).",
19869
- 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).",
19870
20036
  ids: "Ids from <project-memory>: one for update, 1+ for archive, 2+ for merge, 1–20 for get.",
19871
20037
  reason: "Why it is archived (optional)."
19872
20038
  },
@@ -22427,6 +22593,96 @@ async function createV2HiddenCompletionExecutor(host, options) {
22427
22593
  };
22428
22594
  }
22429
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
+
22430
22686
  // src/v2/hooks/channel2.ts
22431
22687
  import { randomBytes as randomBytes2 } from "node:crypto";
22432
22688
  var pendingCandidates = new WeakMap;
@@ -23365,7 +23621,7 @@ function projectRawMessages(rows, ordinalFor) {
23365
23621
  const message = {
23366
23622
  id: row.id,
23367
23623
  ordinal: ordinalFor(row, index),
23368
- role: row.type === "assistant" ? "assistant" : "user",
23624
+ role: row.type === "assistant" ? "assistant" : row.type === "system" ? "system" : "user",
23369
23625
  createdAt: row.time_created ?? row.data.time?.created,
23370
23626
  parts: row.type === "assistant" ? (row.data.content ?? []).map((part) => {
23371
23627
  if (part.type !== "tool")
@@ -24296,10 +24552,10 @@ function updateMemoryContentInCurrentTransaction(db, memory, content, normalized
24296
24552
  clearMemoryVerifications(db, memory.id);
24297
24553
  }
24298
24554
  var ctxMemoryArgsShape = {
24299
- action: tool2.schema.enum([...CTX_MEMORY_ACTIONS]).optional().describe("write | update | archive | merge | get"),
24300
- content: tool2.schema.string().optional().describe("The memory text — one standalone fact (write, update, merge)."),
24301
- category: tool2.schema.enum([...V2_MEMORY_CATEGORIES]).optional().describe("Kind of fact (required for write; on update/merge optional, omitted keeps the current category)."),
24302
- 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."),
24303
24559
  reason: tool2.schema.string().optional().describe("Why it is being archived (optional).")
24304
24560
  };
24305
24561
  var ctxMemoryArgsSchema = tool2.schema.object({ ...ctxMemoryArgsShape }).passthrough();
@@ -24657,7 +24913,7 @@ function renderGlance(notes, options) {
24657
24913
  const remaining = ordered.length - options.offset - page.length;
24658
24914
  const footer = remaining > 0 ? `
24659
24915
 
24660
- 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})` : "";
24661
24917
  return `## Notes
24662
24918
 
24663
24919
  ${rows}${footer}`;
@@ -24695,7 +24951,7 @@ function captureAnchorOrdinal(db, sessionId) {
24695
24951
  }
24696
24952
  var DISMISS_FOOTER = `
24697
24953
 
24698
- 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="")`;
24699
24955
  var DEFAULT_READ_LIMIT = 25;
24700
24956
  function readGlanceNotes(args) {
24701
24957
  if (args.filter === undefined) {
@@ -24725,12 +24981,12 @@ function noteAuthorityRefusal(action) {
24725
24981
  return renderCapabilityRefusal(isMutation ? "note_change" : "note_access");
24726
24982
  }
24727
24983
  var ctxNoteArgsShape = {
24728
- action: tool3.schema.enum(["write", "read", "dismiss", "update"]).optional().describe("write | read | update | dismiss. Defaults to write when content is given, else read."),
24729
- 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."),
24730
24986
  filter: tool3.schema.enum(["all", "active", "dismissed"]).optional().describe("Read filter: active (default), all, dismissed."),
24731
24987
  limit: tool3.schema.number().optional().describe("Rows per read (default 25)."),
24732
24988
  offset: tool3.schema.number().optional().describe("Skip this many newest rows (default 0)."),
24733
- 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.")
24734
24990
  };
24735
24991
  var ctxNoteArgsSchema = tool3.schema.object(ctxNoteArgsShape).passthrough();
24736
24992
  function formatDismissResults(results) {
@@ -24769,7 +25025,8 @@ function createCtxNoteTool(deps) {
24769
25025
  });
24770
25026
  const sessionId = toolContext.sessionID;
24771
25027
  const action = args.action ?? (args.content?.trim() ? "write" : "read");
24772
- 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;
24773
25030
  if (typeof noteIds === "string")
24774
25031
  return noteIds;
24775
25032
  const projectIdentity = deps.resolveProjectPath?.(toolContext.directory);
@@ -25511,16 +25768,23 @@ function applyV2PromptSurfaceTools(draft, runtime, config) {
25511
25768
  function recordV2ToolDefinitions(draft) {
25512
25769
  if (!draft.tools)
25513
25770
  return;
25771
+ const tools = [];
25514
25772
  for (const [id, tool] of Object.entries(draft.tools)) {
25515
25773
  if (!tool)
25516
25774
  continue;
25517
25775
  recordToolParameters(id, tool.input);
25518
- 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
+ });
25519
25781
  }
25782
+ recordToolDefinitionSet(draft.model.providerID, draft.model.id, draft.agent, tools, draft.sessionID);
25520
25783
  }
25521
25784
  async function registerContext(context) {
25522
25785
  const directory = context.location.directory;
25523
25786
  const config = loadPluginConfigDetailed(directory).config;
25787
+ log(`[magic-context] OpenCode 2 keep_subagents=${config.keep_subagents === true}`);
25524
25788
  setHomeProjectPermission(config.allow_home_project);
25525
25789
  if (!config.enabled)
25526
25790
  return;
@@ -25642,6 +25906,7 @@ async function registerContext(context) {
25642
25906
  };
25643
25907
  let hiddenAgentsReady;
25644
25908
  const readerPool = new V2StoreReaderPool;
25909
+ const messageTimesCache = new V2MessageTimesCache;
25645
25910
  const openStoreReader = () => readerPool.open(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"));
25646
25911
  const createHiddenExecutor = async (database) => {
25647
25912
  await cleanupLegacyOnce(database);
@@ -25762,17 +26027,11 @@ async function registerContext(context) {
25762
26027
  }
25763
26028
  });
25764
26029
  const pagedRead = createV2RawMessageReader(openStoreReader);
25765
- let orphanSweep;
25766
- let orphanSweepTimer;
25767
26030
  const prepareHistorySession = (sessionID) => {
25768
26031
  if (!rawProviders.has(sessionID))
25769
26032
  rawProviders.set(sessionID, setBoundedRawMessageProvider2(sessionID, createV2RawMessageProvider(pagedRead, sessionID)));
25770
26033
  };
25771
26034
  if (db && isDatabasePersisted(db)) {
25772
- const sweepDb = db;
25773
- orphanSweepTimer = scheduleAfterBootQuiet(() => {
25774
- orphanSweep = sweepOrphanedOpenCodeMessageIndexesCooperatively(sweepDb, () => new Database(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"), { readonly: true, fileMustExist: true })).catch((error) => log("[magic-context] v2 orphan sweep failed:", error));
25775
- });
25776
26035
  const backfillDb = db;
25777
26036
  scheduleAfterBootQuiet(() => {
25778
26037
  runV2SessionProjectBackfill(backfillDb, openStoreReader, config.allow_home_project).catch((error) => log("[session-project-backfill] OpenCode 2 backfill failed:", error));
@@ -25912,6 +26171,12 @@ async function registerContext(context) {
25912
26171
  if (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated") {
25913
26172
  nativeFoldReplay?.onEvent(event);
25914
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);
25915
26180
  }
25916
26181
  if (event.type === "session.revert.committed") {
25917
26182
  committedSourceRefreshes.set(sessionID, {});
@@ -25951,6 +26216,7 @@ async function registerContext(context) {
25951
26216
  rawProviders.get(sessionID)?.();
25952
26217
  rawProviders.delete(sessionID);
25953
26218
  usage.delete(sessionID);
26219
+ messageTimesCache.delete(sessionID);
25954
26220
  hiddenSessionErrors.delete(sessionID);
25955
26221
  storageNoticeBySession.delete(sessionID);
25956
26222
  liveModels.delete(sessionID);
@@ -26022,7 +26288,7 @@ async function registerContext(context) {
26022
26288
  memoryInjectionBudgetTokens: config.memory.injection_budget_tokens,
26023
26289
  hardSignals: {
26024
26290
  systemHash: foldDigest(JSON.stringify(draft.system)),
26025
- toolSetHash: getCurrentToolSetHash(draft.model.providerID, draft.model.id, draft.agent),
26291
+ toolSetHash: getCurrentToolSetHash(draft.model.providerID, draft.model.id, draft.agent, draft.sessionID),
26026
26292
  modelKey: `${draft.model.providerID}/${draft.model.id}`,
26027
26293
  cacheExpired: false,
26028
26294
  lastResponseTime: state.lastResponseTime
@@ -26110,6 +26376,65 @@ async function registerContext(context) {
26110
26376
  }
26111
26377
  return ids;
26112
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
+ });
26113
26438
  const runManagedContext = async (draft) => {
26114
26439
  rememberHostMedia(draft.messages);
26115
26440
  if (hiddenChildHook.apply(draft))
@@ -26139,22 +26464,9 @@ async function registerContext(context) {
26139
26464
  }
26140
26465
  await dropStorageNotices(draft.messages, isMagicContextSynthetic);
26141
26466
  let hostMessagesAtEntry = [...draft.messages];
26142
- const passTimes = new Map;
26467
+ const cachedTimes = messageTimesCache.pass(draft.sessionID);
26143
26468
  const readTimes = (reader, messages) => {
26144
- const ids = timeIds(messages);
26145
- const missing = ids.filter((id) => !passTimes.has(id));
26146
- if (missing.length) {
26147
- const read = reader.messageTimes(draft.sessionID, missing);
26148
- for (const id of missing)
26149
- passTimes.set(id, read.get(id) ?? null);
26150
- }
26151
- const times = new Map;
26152
- for (const id of ids) {
26153
- const time = passTimes.get(id);
26154
- if (time)
26155
- times.set(id, time);
26156
- }
26157
- return times;
26469
+ return cachedTimes(reader, timeIds(messages));
26158
26470
  };
26159
26471
  liveModels.set(draft.sessionID, {
26160
26472
  providerID: draft.model.providerID,
@@ -26405,65 +26717,7 @@ async function registerContext(context) {
26405
26717
  }
26406
26718
  });
26407
26719
  }
26408
- transform ??= createTransform({
26409
- cacheTtlConfig: config.cache_ttl,
26410
- cacheTtlConfigured: config.cacheTtlConfigured,
26411
- sampleCacheTtlConfig: () => liveConfigReader.poll().effective,
26412
- db,
26413
- tagger,
26414
- ...createV2ThresholdDeps(config),
26415
- contextUsageMap: usage,
26416
- compactionOff,
26417
- storeGeneration: "v2",
26418
- normalizeRestoredAssistantText: (text, providerID) => {
26419
- const normalized = stripCopiedTagNotation(text);
26420
- return normalized === "" && !modelAcceptsEmptyContent(providerID) ? text : normalized;
26421
- },
26422
- refreshSourceContents: (sessionID) => committedSourceRefreshes.has(sessionID),
26423
- hostCleanupCompactionMarkers: () => ({
26424
- verified: true,
26425
- removedLineages: 0,
26426
- removedRows: 0,
26427
- retainedLineages: 0
26428
- }),
26429
- protectedTokens: config.protected_tokens,
26430
- protectedTokenTierOverrides: getProtectedTokensTierOverrides(config),
26431
- protectedTools: config.protected_tools,
26432
- liveModelBySession: liveModels,
26433
- getToolSetHash: (sessionId) => {
26434
- const model = liveModels.get(sessionId);
26435
- if (!model)
26436
- return "";
26437
- return getCurrentToolSetHash(model.providerID, model.modelID, agents.get(sessionId));
26438
- },
26439
- channel1StateBySession: channel1,
26440
- historyRefreshSessions,
26441
- pendingMaterializationSessions,
26442
- lastHeuristicsTurnId,
26443
- variantBySession: variants,
26444
- keepReasoningTokens: config.keep_reasoning_tokens,
26445
- directory,
26446
- sessionDirectoryBySession: sessionDirectories,
26447
- projectPath: directory,
26448
- agentBySession: agents,
26449
- maintenanceConfig: config.maintenance ? () => inheritMaintenanceModelConfig(config) : undefined,
26450
- hiddenCompletionExecutor,
26451
- historianRunnable: !compactionOff && hiddenCompletionExecutor !== undefined && config.historian?.disable !== true,
26452
- historianModel: historianModels.primary,
26453
- fallbackModels: historianModels.fallbacks,
26454
- resolveHistorianRun: sampleHistorian,
26455
- historianTimeoutMs: config.historian_timeout_ms,
26456
- historianMaxOutputTokens: config.historian?.maxTokens,
26457
- historianTwoPass: config.historian?.two_pass,
26458
- historianExpandTools: config.historian?.expand_tools,
26459
- compactionMarkerStrategy: v2CompactionMarkerStrategy,
26460
- memoryConfig: {
26461
- enabled: config.memory.enabled,
26462
- injectionBudgetTokens: config.memory.injection_budget_tokens,
26463
- autoPromote: config.memory.auto_promote
26464
- },
26465
- ...createHostSeams(context, readAllForConversion, pagedRead, liveModels)
26466
- });
26720
+ transform = initializeTransform(db);
26467
26721
  const refreshToken = committedSourceRefreshes.get(draft.sessionID);
26468
26722
  if (refreshToken) {
26469
26723
  clearCachedM0(db, draft.sessionID);
@@ -26762,12 +27016,10 @@ async function registerContext(context) {
26762
27016
  }, 0);
26763
27017
  return {
26764
27018
  async dispose() {
27019
+ messageTimesCache.clear();
26765
27020
  usageController.abort();
26766
- if (orphanSweepTimer)
26767
- clearTimeout(orphanSweepTimer);
26768
27021
  await hiddenCompletionExecutor?.dispose();
26769
27022
  await usageDone;
26770
- await orphanSweep;
26771
27023
  rpcStopped = true;
26772
27024
  rpcServer.stop();
26773
27025
  tools?.dispose();