@retaw106/mmc-oc 2.0.0 → 2.1.1

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 (108) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/config/live-run-config.d.ts.map +1 -1
  3. package/dist/config-init.js +1 -1
  4. package/dist/{context-95zkksn3.js → context-cx3y8abt.js} +2602 -1594
  5. package/dist/features/magic-context/memory/types.d.ts +1 -0
  6. package/dist/features/magic-context/memory/types.d.ts.map +1 -1
  7. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  8. package/dist/features/magic-context/session-project-storage.d.ts +8 -2
  9. package/dist/features/magic-context/session-project-storage.d.ts.map +1 -1
  10. package/dist/features/magic-context/storage-meta-persisted.d.ts +12 -0
  11. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  12. package/dist/features/magic-context/storage-meta-session.d.ts +6 -0
  13. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  14. package/dist/features/magic-context/storage-tags.d.ts +2 -2
  15. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  16. package/dist/features/magic-context/transform-decision-log.d.ts +3 -1
  17. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  18. package/dist/hooks/magic-context/compartment-runner-types.d.ts +3 -5
  19. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  20. package/dist/hooks/magic-context/compartment-runner.d.ts +2 -1
  21. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  22. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  24. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  26. package/dist/hooks/magic-context/historian-drain-gate.d.ts +11 -0
  27. package/dist/hooks/magic-context/historian-drain-gate.d.ts.map +1 -0
  28. package/dist/hooks/magic-context/lkg-replay-fit.d.ts +118 -0
  29. package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -0
  30. package/dist/hooks/magic-context/lkg-replay.d.ts +2 -0
  31. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  32. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -28
  35. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  36. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  37. package/dist/{index-fg34g6a5.js → index-1j34a56j.js} +49 -8
  38. package/dist/{index-5pg0acf7.js → index-amycb7b1.js} +1 -1
  39. package/dist/{index-1mjhzqq7.js → index-dr0gepzw.js} +86 -23
  40. package/dist/{index-xt7y10x6.js → index-n0vnzz6h.js} +1 -1
  41. package/dist/{index-977gxfz0.js → index-ramz5kkm.js} +1 -1
  42. package/dist/{index-bdt9my9y.js → index-wtb9hzk6.js} +130 -50
  43. package/dist/index.js +1 -1
  44. package/dist/{message-time-backfill-zfernxbw.js → message-time-backfill-phrwp2fz.js} +1 -1
  45. package/dist/{read-session-chunk-hp464g13.js → read-session-chunk-82rkqa8j.js} +3 -3
  46. package/dist/{recomp-orchestrator-3qxeqwb9.js → recomp-orchestrator-vc5dkzy2.js} +6 -6
  47. package/dist/{send-session-notification-y29y9fsr.js → send-session-notification-rnc4nrsr.js} +3 -3
  48. package/dist/shared/harness.d.ts +1 -1
  49. package/dist/shared/harness.d.ts.map +1 -1
  50. package/dist/shared/historian-tool-expansions.d.ts +1 -1
  51. package/dist/shared/historian-tool-expansions.d.ts.map +1 -1
  52. package/dist/shared/historian-tool-template.d.ts +2 -2
  53. package/dist/shared/historian-tool-template.d.ts.map +1 -1
  54. package/dist/shared/model-resolution.d.ts +1 -1
  55. package/dist/shared/model-resolution.d.ts.map +1 -1
  56. package/dist/shared/sqlite.d.ts +14 -1
  57. package/dist/shared/sqlite.d.ts.map +1 -1
  58. package/dist/tools/ctx-expand/constants.d.ts +1 -1
  59. package/dist/tools/ctx-expand/constants.d.ts.map +1 -1
  60. package/dist/tools/ctx-expand/render.d.ts +3 -2
  61. package/dist/tools/ctx-expand/render.d.ts.map +1 -1
  62. package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
  63. package/dist/v2/fold/host-media.d.ts +4 -0
  64. package/dist/v2/fold/host-media.d.ts.map +1 -1
  65. package/dist/v2/fold/memory-cache.d.ts +70 -0
  66. package/dist/v2/fold/memory-cache.d.ts.map +1 -0
  67. package/dist/v2/fold/native-codec.d.ts +10 -0
  68. package/dist/v2/fold/native-codec.d.ts.map +1 -0
  69. package/dist/v2/fold/native-replay.d.ts +58 -0
  70. package/dist/v2/fold/native-replay.d.ts.map +1 -0
  71. package/dist/v2/fold/policy.d.ts +24 -0
  72. package/dist/v2/fold/policy.d.ts.map +1 -0
  73. package/dist/v2/hidden-child-record.d.ts +6 -0
  74. package/dist/v2/hidden-child-record.d.ts.map +1 -1
  75. package/dist/v2/hidden-completion.d.ts.map +1 -1
  76. package/dist/v2/hooks/context.d.ts.map +1 -1
  77. package/dist/v2/hooks/types.d.ts +6 -0
  78. package/dist/v2/hooks/types.d.ts.map +1 -1
  79. package/dist/v2/server.js +1819 -574
  80. package/dist/v2/store-reader.d.ts +16 -0
  81. package/dist/v2/store-reader.d.ts.map +1 -1
  82. package/dist/web/api.d.ts.map +1 -1
  83. package/dist/web/context-store.d.ts +2 -0
  84. package/dist/web/context-store.d.ts.map +1 -1
  85. package/dist/web/fixtures.d.ts +41 -0
  86. package/dist/web/fixtures.d.ts.map +1 -1
  87. package/dist/web/host-opencode.d.ts +9 -0
  88. package/dist/web/host-opencode.d.ts.map +1 -1
  89. package/dist/web/main.js +873 -64
  90. package/dist/web/memories.d.ts +18 -2
  91. package/dist/web/memories.d.ts.map +1 -1
  92. package/dist/web/ui/panel.css +3 -0
  93. package/dist/web/ui/panel.js +151 -80
  94. package/dist/web/views.d.ts +71 -9
  95. package/dist/web/views.d.ts.map +1 -1
  96. package/dist/{wrapup-orchestrator-wgb2nd19.js → wrapup-orchestrator-x9xamts2.js} +6 -6
  97. package/package.json +1 -1
  98. package/src/config/live-run-config.ts +28 -0
  99. package/src/shared/harness.ts +1 -1
  100. package/src/shared/historian-tool-defaults.json +6 -6
  101. package/src/shared/historian-tool-expansions.ts +65 -8
  102. package/src/shared/historian-tool-preview-defaults.json +13 -0
  103. package/src/shared/historian-tool-template.ts +48 -14
  104. package/src/shared/model-resolution.ts +1 -1
  105. package/src/shared/prompt-surface-a1-golden.md +2 -2
  106. package/src/shared/sqlite-acquisition-routing.test.ts +18 -0
  107. package/src/shared/sqlite.ts +100 -15
  108. package/src/shared/write-transaction-attribution.test.ts +2 -2
@@ -102,6 +102,7 @@ import {
102
102
  resolveCompactionModeRecord,
103
103
  getCompactionModeRecord,
104
104
  setCompactionModeRecord,
105
+ getProtectedTailDrainBudgetSkip,
105
106
  clearPersistedReasoningWatermark,
106
107
  getEmergencyInputSample,
107
108
  setEmergencyDropSample,
@@ -246,13 +247,15 @@ import {
246
247
  hasCompleteCachedM0M1,
247
248
  injectM0M1,
248
249
  RECOVERY_NO_HEAD_LIMIT,
250
+ deriveProtectedTailTokenTarget,
251
+ selectPerRunCap,
249
252
  resolveOpenCodeProtectedTailBoundary,
250
253
  getRawHistoryEligibility,
251
254
  hasRunnableCompartmentWindow,
252
255
  recordHighPressureNoEligibleHead,
253
256
  getActiveCompartmentRun,
254
257
  startCompartmentAgent
255
- } from "./index-bdt9my9y.js";
258
+ } from "./index-wtb9hzk6.js";
256
259
  import {
257
260
  getHarness,
258
261
  getDataDir,
@@ -386,6 +389,7 @@ import {
386
389
  getMeasuredToolDefinitionTokens,
387
390
  describeFinalWireTail,
388
391
  estimateMessageTokens,
392
+ wireContentBytes,
389
393
  createFinalWireUsageTracker,
390
394
  estimateFinalWireInputTokens,
391
395
  modelAcceptsEmptyContent,
@@ -412,7 +416,7 @@ import {
412
416
  primeInMemoryTailRawMessageCache2,
413
417
  readRawSessionMessageById2,
414
418
  readSessionChunk2
415
- } from "./index-1mjhzqq7.js";
419
+ } from "./index-dr0gepzw.js";
416
420
  import {
417
421
  getSqliteMemoryStats,
418
422
  withSqliteBackgroundWriter,
@@ -421,7 +425,7 @@ import {
421
425
  isTransientSqliteError,
422
426
  SqliteAcquisitionBusyError,
423
427
  withAsyncPrivilegedWriter
424
- } from "./index-fg34g6a5.js";
428
+ } from "./index-1j34a56j.js";
425
429
  import {
426
430
  canonicalModelIdentity,
427
431
  piModelRefToCanonical,
@@ -435,7 +439,7 @@ import {
435
439
  withReadOnlySessionDb,
436
440
  getMessageTimesFromOpenCodeDb,
437
441
  findLastAssistantModelFromOpenCodeDb
438
- } from "./index-977gxfz0.js";
442
+ } from "./index-ramz5kkm.js";
439
443
  import {
440
444
  registerNotificationSink2,
441
445
  pushNotification2,
@@ -448,7 +452,7 @@ import {
448
452
  getErrorMessage,
449
453
  flushIgnoredMessages2,
450
454
  sendStatusNotification2
451
- } from "./index-5pg0acf7.js";
455
+ } from "./index-amycb7b1.js";
452
456
  import {
453
457
  resolveHistorianModel2
454
458
  } from "./index-z2g20msd.js";
@@ -3034,6 +3038,10 @@ function sampleLiveConfig(boot, fresh) {
3034
3038
  let value = fresh;
3035
3039
  for (const part of parts)
3036
3040
  value = value?.[part];
3041
+ if (value === undefined) {
3042
+ removeLeaf(result, parts);
3043
+ continue;
3044
+ }
3037
3045
  let target = result;
3038
3046
  for (const part of parts.slice(0, -1)) {
3039
3047
  const child = target[part];
@@ -3047,6 +3055,26 @@ function sampleLiveConfig(boot, fresh) {
3047
3055
  }
3048
3056
  return result;
3049
3057
  }
3058
+ function removeLeaf(root, parts) {
3059
+ const parents = parts.slice(0, -1);
3060
+ let node = root;
3061
+ for (const part of parents) {
3062
+ const child = node[part];
3063
+ if (!child || typeof child !== "object" || Array.isArray(child))
3064
+ return;
3065
+ node = child;
3066
+ }
3067
+ const leaf = parts.at(-1);
3068
+ if (leaf === undefined || !Object.hasOwn(node, leaf))
3069
+ return;
3070
+ let target = root;
3071
+ for (const part of parents) {
3072
+ const copy = { ...target[part] };
3073
+ target[part] = copy;
3074
+ target = copy;
3075
+ }
3076
+ delete target[leaf];
3077
+ }
3050
3078
  function changedLiveKeys(previous, next) {
3051
3079
  const at = (config, path) => path.split(".").reduce((node, part) => node?.[part], config);
3052
3080
  return LIVE_RELOAD_CONFIG_PATHS.filter((path) => JSON.stringify(at(previous, path)) !== JSON.stringify(at(next, path)));
@@ -8599,6 +8627,9 @@ function createToolExecuteAfterHook(args) {
8599
8627
  };
8600
8628
  }
8601
8629
 
8630
+ // src/hooks/magic-context/lkg-measured-request.ts
8631
+ import { createHash as createHash3 } from "node:crypto";
8632
+
8602
8633
  // src/shared/provider-response-completion.ts
8603
8634
  function providerResponseFailed(input) {
8604
8635
  if (input.error !== undefined && input.error !== null && input.error !== "")
@@ -8620,9 +8651,49 @@ function lkgProviderInputTotal(tokens) {
8620
8651
  const counts = [tokens?.input ?? 0, tokens?.cache?.read ?? 0, tokens?.cache?.write ?? 0];
8621
8652
  return counts.every((count) => Number.isSafeInteger(count) && count >= 0) ? counts.reduce((sum, count) => sum + count, 0) : Number.NaN;
8622
8653
  }
8654
+ function identity(slot) {
8655
+ return createHash3("sha256").update(JSON.stringify([
8656
+ slot.capturedAt,
8657
+ slot.captureSequence,
8658
+ slot.rowVersion,
8659
+ slot.modelKey,
8660
+ slot.providerKey,
8661
+ slot.inputIdSeq,
8662
+ slot.inputContentDigests
8663
+ ])).update(slot.jsonPrefix).digest("hex");
8664
+ }
8665
+ function envelope(modelKey, systemPromptTokens, agentName) {
8666
+ const slash = modelKey.indexOf("/");
8667
+ return JSON.stringify([
8668
+ modelKey,
8669
+ systemPromptTokens,
8670
+ agentName,
8671
+ getMeasuredToolDefinitionTokens(modelKey.slice(0, slash), modelKey.slice(slash + 1), agentName)
8672
+ ]);
8673
+ }
8623
8674
  function beginV2LkgRequest(sessionId, modelKey, previousResponseId) {
8624
8675
  requests.set(sessionId, { kind: "v2", previousResponseId, startedAt: Date.now(), modelKey });
8625
8676
  }
8677
+ function claimLkgRequestIdentity(sessionId) {
8678
+ const request = requests.get(sessionId);
8679
+ if (!request || claimedRequests.has(request))
8680
+ return;
8681
+ claimedRequests.add(request);
8682
+ return request;
8683
+ }
8684
+ function noteCapturedLkgRequest(args) {
8685
+ const request = args.request;
8686
+ if (!request || request.modelKey !== args.slot.modelKey) {
8687
+ captures.delete(args.sessionId);
8688
+ return;
8689
+ }
8690
+ captures.set(args.sessionId, {
8691
+ request,
8692
+ slot: identity(args.slot),
8693
+ prefixCount: JSON.parse(args.slot.jsonPrefix).length,
8694
+ envelope: envelope(request.modelKey, args.systemPromptTokens, args.agentName)
8695
+ });
8696
+ }
8626
8697
  function noteLkgProviderResponse(args) {
8627
8698
  if (!args.responseId || !args.modelKey)
8628
8699
  return;
@@ -8650,7 +8721,7 @@ function noteLkgProviderResponse(args) {
8650
8721
  }
8651
8722
 
8652
8723
  // src/hooks/magic-context/lkg-persist.ts
8653
- import { createHash as createHash3 } from "node:crypto";
8724
+ import { createHash as createHash4 } from "node:crypto";
8654
8725
  function parseStringArray(value) {
8655
8726
  if (typeof value !== "string")
8656
8727
  return null;
@@ -8764,7 +8835,7 @@ function rememberFingerprint(db, sessionId, fingerprint) {
8764
8835
  saved.set(sessionId, fingerprint);
8765
8836
  }
8766
8837
  function slotFingerprint(slot) {
8767
- return createHash3("sha256").update(JSON.stringify([
8838
+ return createHash4("sha256").update(JSON.stringify([
8768
8839
  slot.jsonPrefix,
8769
8840
  slot.inputIdSeq,
8770
8841
  slot.inputContentDigests,
@@ -9210,7 +9281,7 @@ function captureLkgSlot(args) {
9210
9281
  if (!built)
9211
9282
  return false;
9212
9283
  const modelKeys = canonicalLkgModelKeys(args.modelKey, args.providerKey);
9213
- return captureSlot(args.sessionId, {
9284
+ const slot = {
9214
9285
  jsonPrefix: built.jsonPrefix,
9215
9286
  inputIdSeq: built.inputIdSeq,
9216
9287
  inputContentDigests: built.inputContentDigests,
@@ -9218,7 +9289,17 @@ function captureLkgSlot(args) {
9218
9289
  modelKey: modelKeys.modelKey,
9219
9290
  providerKey: modelKeys.providerKey,
9220
9291
  capturedAt: args.capturedAt ?? Date.now()
9221
- });
9292
+ };
9293
+ const captured = captureSlot(args.sessionId, slot);
9294
+ if (captured)
9295
+ noteCapturedLkgRequest({
9296
+ sessionId: args.sessionId,
9297
+ slot,
9298
+ request: built.anchorIndex === args.input.length - 1 ? claimLkgRequestIdentity(args.sessionId) : undefined,
9299
+ systemPromptTokens: args.systemPromptTokens ?? 0,
9300
+ agentName: args.agentName
9301
+ });
9302
+ return captured;
9222
9303
  }
9223
9304
  function entryIdsAreValid(slot, entryIds) {
9224
9305
  if (slot.inputIdSeq.length === 0 || entryIds.length < slot.inputIdSeq.length)
@@ -9444,6 +9525,45 @@ function replayLkg(args) {
9444
9525
  return { ok: true, messages: replayed };
9445
9526
  }
9446
9527
 
9528
+ // src/hooks/magic-context/lkg-replay-fit.ts
9529
+ var RAW_FALLBACK_BYTES_PER_CONTEXT_TOKEN = 4;
9530
+ function lkgReplayLimit(args) {
9531
+ const { db, sessionId, model } = args;
9532
+ const trusted = model ? resolveTrustedContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : undefined;
9533
+ if (trusted !== undefined && trusted > 0)
9534
+ return trusted;
9535
+ const detected = getOverflowState(db, sessionId, args.modelKey).detectedContextLimit;
9536
+ return detected > 0 ? detected : undefined;
9537
+ }
9538
+ function measureLkgReplay(args) {
9539
+ const baseline = args.measuredInputTokens ?? 0;
9540
+ const tailLimit = Math.max(0, args.limit - baseline);
9541
+ const proxy = wireContentBytes(args.messages, tailLimit * RAW_FALLBACK_BYTES_PER_CONTEXT_TOKEN, RAW_FALLBACK_BYTES_PER_CONTEXT_TOKEN);
9542
+ const skipped = { proxy, estimatorRan: false, trusted: false };
9543
+ if (proxy === null)
9544
+ return { fit: "unproven", tokens: null, ...skipped };
9545
+ const proxyTokens = baseline + Math.ceil(proxy.bytes / RAW_FALLBACK_BYTES_PER_CONTEXT_TOKEN);
9546
+ if (proxy.aborted || proxyTokens > args.limit) {
9547
+ return { fit: "over", tokens: null, proxyTokens, ...skipped };
9548
+ }
9549
+ let estimate;
9550
+ try {
9551
+ estimate = args.estimate();
9552
+ } catch {
9553
+ return { fit: "unproven", tokens: null, ...skipped };
9554
+ }
9555
+ const seen = { proxy, estimatorRan: true, trusted: estimate.trusted };
9556
+ const tokens = baseline + estimate.tokens;
9557
+ if (!estimate.trusted || !Number.isFinite(tokens) || tokens <= 0 || estimate.tokens < 0) {
9558
+ return {
9559
+ fit: "unproven",
9560
+ tokens: Number.isFinite(estimate.tokens) ? estimate.tokens : null,
9561
+ ...seen
9562
+ };
9563
+ }
9564
+ return tokens > args.limit ? { fit: "over", tokens, proxyTokens, ...seen } : { fit: "under", tokens, ...seen };
9565
+ }
9566
+
9447
9567
  // src/hooks/magic-context/storage-busy-refusal.ts
9448
9568
  var STORAGE_BUSY_MESSAGE = "Magic Context's database is busy (another process held it too long); send your message again.";
9449
9569
  function describeStorageBusyCause(cause) {
@@ -9471,7 +9591,7 @@ class StorageBusyRefusalError extends Error {
9471
9591
  }
9472
9592
 
9473
9593
  // src/hooks/magic-context/system-prompt-hash.ts
9474
- import { createHash as createHash4 } from "node:crypto";
9594
+ import { createHash as createHash5 } from "node:crypto";
9475
9595
 
9476
9596
  // src/agents/magic-context-prompt.ts
9477
9597
  var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
@@ -9712,7 +9832,7 @@ function createSystemPromptHashHandler(deps) {
9712
9832
  }
9713
9833
  const stickyDate = stickyDateBySession.get(sessionId);
9714
9834
  const stableCandidate = currentDate && stickyDate && currentDate !== stickyDate ? liveSystemContent.replace(DATE_PATTERN_ALL, stickyDate) : liveSystemContent;
9715
- const stableCandidateHash = createHash4("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
9835
+ const stableCandidateHash = createHash5("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
9716
9836
  const contentOrPresetChanged = hasPersistedHash && stableCandidateHash !== previousHash;
9717
9837
  const dateMayAdvance = isCacheBusting || idleCacheExpired || contentOrPresetChanged;
9718
9838
  if (currentDate && !stickyDate) {
@@ -9732,7 +9852,7 @@ function createSystemPromptHashHandler(deps) {
9732
9852
  `);
9733
9853
  if (!availability.frozen || !modelKey)
9734
9854
  return;
9735
- const currentHash = createHash4("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
9855
+ const currentHash = createHash5("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
9736
9856
  if (!sessionMetaEarly) {
9737
9857
  return;
9738
9858
  }
@@ -9947,10 +10067,14 @@ function recordSessionProjectIdentity(db, sessionId, projectPath) {
9947
10067
  return;
9948
10068
  const harness = getHarness();
9949
10069
  const now = Date.now();
10070
+ let previousProjectPath;
9950
10071
  db.transaction(() => {
10072
+ const existing = db.prepare("SELECT project_path FROM session_projects WHERE session_id = ? AND harness = ?").get(sessionId, harness);
10073
+ previousProjectPath = existing?.project_path;
9951
10074
  getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
9952
10075
  getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath, SESSION_CHUNK_REPAIR_BATCH_SIZE);
9953
10076
  }).immediate();
10077
+ return previousProjectPath === projectPath ? undefined : { previousProjectPath, projectPath };
9954
10078
  }
9955
10079
  function hasRecordedSessionProjectIdentity(db, sessionId) {
9956
10080
  const row = db.prepare("SELECT 1 AS found FROM session_projects WHERE session_id = ? AND harness = ?").get(sessionId, getHarness());
@@ -10384,6 +10508,29 @@ function commitCompactionModeRecord(db, sessionId, record) {
10384
10508
  setCompactionModeRecord(db, sessionId, record);
10385
10509
  }
10386
10510
 
10511
+ // src/hooks/magic-context/historian-drain-gate.ts
10512
+ var loggedWindows = new WeakMap;
10513
+ function isHistorianDrainBudgetSpent(args) {
10514
+ const target = deriveProtectedTailTokenTarget(args);
10515
+ const state = getProtectedTailDrainBudgetSkip({
10516
+ ...args,
10517
+ usable: target.usable,
10518
+ perRunCap: selectPerRunCap({ ...args, N: target.N })
10519
+ });
10520
+ if (!state)
10521
+ return false;
10522
+ let windows = loggedWindows.get(args.db);
10523
+ if (!windows) {
10524
+ windows = new Map;
10525
+ loggedWindows.set(args.db, windows);
10526
+ }
10527
+ if (windows.get(args.sessionId) !== state.resetsAt) {
10528
+ windows.set(args.sessionId, state.resetsAt);
10529
+ sessionLog(args.sessionId, `historian skip: internal drain budget spent (${state.spentTokens}/${state.limitTokens} tokens); next eligible at ${new Date(state.nextEligibleAt).toISOString()}`);
10530
+ }
10531
+ return true;
10532
+ }
10533
+
10387
10534
  // src/features/magic-context/storage-reasoning-removal.ts
10388
10535
  var NAMESPACE2 = "reasoningRemoval";
10389
10536
  var BACKUP_NAMESPACE = "reasoningRemovalBackup";
@@ -11375,7 +11522,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
11375
11522
  taggerFloor,
11376
11523
  storedTotalsExcludeToolTags
11377
11524
  });
11378
- const hasProtectedEligibleHead = boundary.offset < boundary.protectedTailStart;
11525
+ const hasProtectedEligibleHead = boundary.offset < Math.min(boundary.protectedTailStart, boundary.eligibleEndOrdinal);
11379
11526
  if (!hasProtectedEligibleHead) {
11380
11527
  return {
11381
11528
  ...TAIL_INFO_DEFAULTS,
@@ -11387,7 +11534,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
11387
11534
  const seed = sessionDecisionCalibration(db, sessionId);
11388
11535
  const sourceRatio = Math.max(seed.proseRatio, seed.toolsRatio);
11389
11536
  const scanBudget = Math.floor(Math.max(MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE, triggerBudget * TAIL_SIZE_TRIGGER_MULTIPLIER) / sourceRatio);
11390
- const chunk = readSessionChunk2(sessionId, scanBudget, rawEligibility.offset, boundary.protectedTailStart);
11537
+ const chunk = readSessionChunk2(sessionId, scanBudget, rawEligibility.offset, boundary.eligibleEndOrdinal);
11391
11538
  const isMeaningful = chunk.hasMore || boundary.trueRawEligibleTokens >= MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE || Math.ceil(chunk.tokenEstimate * sourceRatio) >= MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE || chunk.messageCount >= MIN_PROACTIVE_TAIL_MESSAGE_COUNT;
11392
11539
  return {
11393
11540
  nextStartOrdinal: rawEligibility.offset,
@@ -11414,6 +11561,14 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
11414
11561
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
11415
11562
  return { shouldFire: false };
11416
11563
  }
11564
+ if (isHistorianDrainBudgetSpent({
11565
+ db,
11566
+ sessionId,
11567
+ usagePercentage: usage.percentage,
11568
+ contextLimit: resolveBoundaryContextLimit(usage, contextLimit),
11569
+ executeThresholdPercentage
11570
+ }))
11571
+ return { shouldFire: false };
11417
11572
  const lazyInMemoryTail = typeof inMemoryTail === "function" ? inMemoryTail : undefined;
11418
11573
  let resolvedInMemoryTail = typeof inMemoryTail === "function" ? undefined : inMemoryTail;
11419
11574
  if (resolvedInMemoryTail) {
@@ -11927,8 +12082,24 @@ function historianJoinFailClosedMessage(input) {
11927
12082
  return `historian did not complete within ${seconds} s: ${reason}`;
11928
12083
  }
11929
12084
  function runCompartmentPhase(args) {
12085
+ if (args.historianRunnable !== false && !args.compactionOff && args.canRunCompartments && !getActiveCompartmentRun(args.sessionId) && (args.sessionMeta.compartmentInProgress || args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE) && isHistorianDrainBudgetSpent({
12086
+ db: args.db,
12087
+ sessionId: args.sessionId,
12088
+ contextLimit: args.boundaryContextLimit,
12089
+ executeThresholdPercentage: args.boundaryExecuteThresholdPercentage,
12090
+ usagePercentage: args.boundaryUsage.percentage
12091
+ })) {
12092
+ if (args.sessionMeta.compartmentInProgress) {
12093
+ updateSessionMeta(args.db, args.sessionId, { compartmentInProgress: false });
12094
+ }
12095
+ return runCompartmentPhaseImpl({
12096
+ ...args,
12097
+ canRunCompartments: false,
12098
+ sessionMeta: { compartmentInProgress: false }
12099
+ });
12100
+ }
11930
12101
  const historianRunnable = args.historianRunnable !== false;
11931
- const willReadRawHistory = historianRunnable && !args.compactionOff && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && (args.sessionMeta.compartmentInProgress || args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE);
12102
+ const willReadRawHistory = historianRunnable && !args.compactionOff && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE;
11932
12103
  if (!willReadRawHistory) {
11933
12104
  return runCompartmentPhaseImpl(args);
11934
12105
  }
@@ -12054,7 +12225,7 @@ async function runCompartmentPhaseImpl(args) {
12054
12225
  compartmentInProgress = false;
12055
12226
  }
12056
12227
  if (historianRunnable && args.canRunCompartments && args.sessionMeta.compartmentInProgress && !getActiveCompartmentRun(args.sessionId)) {
12057
- if (!hasEligibleHistoryForCompartment()) {
12228
+ if (args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE && !hasEligibleHistoryForCompartment()) {
12058
12229
  sessionLog(args.sessionId, `transform: skipping compartment start, no eligible history before protected tail (beyond ${lastObservedCompartmentEnd})`);
12059
12230
  updateSessionMeta(args.db, args.sessionId, { compartmentInProgress: false });
12060
12231
  compartmentInProgress = false;
@@ -12071,7 +12242,7 @@ async function runCompartmentPhaseImpl(args) {
12071
12242
  db: args.db,
12072
12243
  sessionId: args.sessionId,
12073
12244
  historianChunkTokens: args.historianChunkTokens,
12074
- boundarySnapshot: getBoundarySnapshotForCompartment() ?? undefined,
12245
+ boundarySnapshot: args.preResolvedBoundarySnapshot,
12075
12246
  currentContextLimit: args.boundaryContextLimit,
12076
12247
  historyBudgetTokens: args.historyBudgetTokens,
12077
12248
  historianTimeoutMs: args.historianTimeoutMs,
@@ -12089,6 +12260,12 @@ async function runCompartmentPhaseImpl(args) {
12089
12260
  autoPromote: args.autoPromote,
12090
12261
  onCompartmentStatePublished: args.onCompartmentStatePublished,
12091
12262
  preserveInjectionCacheUntilConsumed: true
12263
+ }, undefined, () => {
12264
+ const snapshot = getBoundarySnapshotForCompartment();
12265
+ if (snapshot && hasRunnableCompartmentWindow(snapshot))
12266
+ return snapshot;
12267
+ sessionLog(args.sessionId, `transform: skipping compartment start, no eligible history before protected tail (beyond ${lastObservedCompartmentEnd})`);
12268
+ return null;
12092
12269
  });
12093
12270
  compartmentInProgress = true;
12094
12271
  }
@@ -13442,6 +13619,8 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
13442
13619
  continue;
13443
13620
  const strippedSource = stripTagPrefix(stripped);
13444
13621
  if (strippedSource.trim().length === 0) {
13622
+ if (target.thinkingDropProtected)
13623
+ continue;
13445
13624
  const dropResult = target.drop?.() ?? "absent";
13446
13625
  const replacement = `[dropped §${tag.tagNumber}§]`;
13447
13626
  const didReplace = dropResult === "absent" ? target.setContent(replacement) : false;
@@ -15833,19 +16012,33 @@ function createTransform(deps) {
15833
16012
  if (false) {}
15834
16013
  return false;
15835
16014
  };
15836
- const startRecoveryRun = () => {
15837
- const scale = emergencyUsagePercentageEarly >= 95 ? 0.25 : 0.5;
15838
- let boundarySnapshot = getRunnableBoundaryForCompartment();
15839
- if (!boundarySnapshot || !hasRunnableCompartmentWindow(boundarySnapshot)) {
15840
- boundarySnapshot = getRunnableBoundaryForCompartment(scale);
15841
- }
15842
- if (false) {}
15843
- if (!canRunCompartments || !deps.client && !deps.hiddenCompletionExecutor || !boundarySnapshot || !hasRunnableCompartmentWindow(boundarySnapshot)) {
16015
+ const startRecoveryRun = (onReady) => {
16016
+ if (isHistorianDrainBudgetSpent({
16017
+ db,
16018
+ sessionId,
16019
+ contextLimit: boundaryContextLimit,
16020
+ executeThresholdPercentage: boundaryExecuteThreshold,
16021
+ usagePercentage: boundaryUsageForProtectedTail.percentage
16022
+ }))
15844
16023
  return false;
15845
- }
15846
- if (getActiveCompartmentRun(sessionId)) {
16024
+ if (!canRunCompartments || !deps.client && !deps.hiddenCompletionExecutor || getActiveCompartmentRun(sessionId))
16025
+ return false;
16026
+ const prepareRecoveryBoundary = () => {
16027
+ const scale = emergencyUsagePercentageEarly >= 95 ? 0.25 : 0.5;
16028
+ let boundarySnapshot = getRunnableBoundaryForCompartment();
16029
+ if (!boundarySnapshot || !hasRunnableCompartmentWindow(boundarySnapshot)) {
16030
+ boundarySnapshot = getRunnableBoundaryForCompartment(scale);
16031
+ }
16032
+ if (false) {}
16033
+ if (!boundarySnapshot || !hasRunnableCompartmentWindow(boundarySnapshot))
16034
+ return null;
16035
+ onReady?.();
16036
+ return boundarySnapshot;
16037
+ };
16038
+ const urgent = emergencyUsagePercentageEarly >= 95;
16039
+ const boundarySnapshot = urgent ? prepareRecoveryBoundary() : undefined;
16040
+ if (urgent && !boundarySnapshot)
15847
16041
  return false;
15848
- }
15849
16042
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
15850
16043
  startCompartmentAgent({
15851
16044
  client: deps.client,
@@ -15854,7 +16047,7 @@ function createTransform(deps) {
15854
16047
  db,
15855
16048
  sessionId,
15856
16049
  historianChunkTokens: historianRun?.chunkTokens ?? deps.getHistorianChunkTokens?.() ?? 20000,
15857
- boundarySnapshot,
16050
+ boundarySnapshot: boundarySnapshot ?? undefined,
15858
16051
  currentContextLimit: boundaryContextLimit,
15859
16052
  historyBudgetTokens,
15860
16053
  historianTimeoutMs: historianRun?.timeoutMs ?? deps.historianTimeoutMs,
@@ -15874,7 +16067,7 @@ function createTransform(deps) {
15874
16067
  deferredHistoryRefreshSessions.add(sid);
15875
16068
  deferredMaterializationSessions.add(sid);
15876
16069
  }
15877
- });
16070
+ }, undefined, urgent ? undefined : prepareRecoveryBoundary);
15878
16071
  return true;
15879
16072
  };
15880
16073
  if (fullFeatureMode && !compactionOff && historianFailureState.failureCount > 0 && emergencyUsagePercentageEarly >= 95 && !recoveryNoHeadEscapeActive) {
@@ -15888,13 +16081,15 @@ function createTransform(deps) {
15888
16081
  sessionLog(sessionId, "transform: emergency recovery remains armed — no complete eligible head before protected tail");
15889
16082
  }
15890
16083
  sessionLog(sessionId, `EMERGENCY: historian recovery requested at ${emergencyPercentage}%, failures: ${historianFailureState.failureCount}`);
15891
- } else if (fullFeatureMode && !compactionOff && isFirstTransformPassForSession && historianFailureState.failureCount > 0 && getEligibleHistoryForCompartment() && startRecoveryRun()) {
15892
- sessionLog(sessionId, `transform: historian recovery triggered on session load after ${historianFailureState.failureCount} failure(s)`);
15893
- if (deps.client) {
15894
- withoutSqliteTransformPass(() => sendStatusNotification2(deps.client, sessionId, `## Historian recovery
16084
+ } else if (fullFeatureMode && !compactionOff && isFirstTransformPassForSession && historianFailureState.failureCount > 0) {
16085
+ startRecoveryRun(() => {
16086
+ sessionLog(sessionId, `transform: historian recovery triggered on session load after ${historianFailureState.failureCount} failure(s)`);
16087
+ if (deps.client) {
16088
+ withoutSqliteTransformPass(() => sendStatusNotification2(deps.client, sessionId, `## Historian recovery
15895
16089
 
15896
16090
  Historian previously failed ${historianFailureState.failureCount} time(s), so Magic Context is retrying history comparting immediately after restart.`, notificationParams));
15897
- }
16091
+ }
16092
+ });
15898
16093
  }
15899
16094
  logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
15900
16095
  const memoryProjectDirectory = compartmentDirectory || process.cwd();
@@ -16441,7 +16636,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16441
16636
  input: lkgInput,
16442
16637
  output: messages,
16443
16638
  modelKey,
16444
- providerKey
16639
+ providerKey,
16640
+ systemPromptTokens: sessionMeta.systemPromptTokens,
16641
+ agentName: notificationParams?.agent
16445
16642
  });
16446
16643
  if (captured) {
16447
16644
  const capturedSlot = getInMemorySlot(sessionId);
@@ -17855,8 +18052,8 @@ function registerRpcHandlers(rpcServer, args) {
17855
18052
  const db = readDatabase();
17856
18053
  if (!db)
17857
18054
  return { ok: false, error: "db unavailable" };
17858
- const { runManagedRecomp } = await import("./recomp-orchestrator-3qxeqwb9.js");
17859
- const { sendIgnoredMessage } = await import("./send-session-notification-y29y9fsr.js");
18055
+ const { runManagedRecomp } = await import("./recomp-orchestrator-vc5dkzy2.js");
18056
+ const { sendIgnoredMessage } = await import("./send-session-notification-rnc4nrsr.js");
17860
18057
  log(`[rpc] recomp requested for session ${sessionId}`);
17861
18058
  if (!args.client && !args.hiddenCompletionExecutor) {
17862
18059
  return {
@@ -17905,7 +18102,7 @@ function registerRpcHandlers(rpcServer, args) {
17905
18102
  const db = readDatabase();
17906
18103
  if (!db)
17907
18104
  return { ok: false, error: "db unavailable" };
17908
- const { runManagedWrapup } = await import("./wrapup-orchestrator-wgb2nd19.js");
18105
+ const { runManagedWrapup } = await import("./wrapup-orchestrator-x9xamts2.js");
17909
18106
  const model = liveSessionState.liveModelBySession.get(sessionId);
17910
18107
  const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
17911
18108
  const ctx = {
@@ -18646,7 +18843,8 @@ function hostUsesMediaAssets() {
18646
18843
  schemaUsesAssets.set(messageClass, uses);
18647
18844
  return uses;
18648
18845
  }
18649
- function decodeThroughHostSchema(source) {
18846
+ function decodeThroughHostSchema(encoded) {
18847
+ const source = encoded.source;
18650
18848
  const messageClass = rememberedMessageClass;
18651
18849
  if (!messageClass)
18652
18850
  return "no host message class seen";
@@ -18666,7 +18864,7 @@ function decodeThroughHostSchema(source) {
18666
18864
  const run = decode?.run;
18667
18865
  if (typeof run !== "function")
18668
18866
  return "host media schema has no decode transformation";
18669
- const result = run.call(decode, { _tag: "Some", value: { source } }, {});
18867
+ const result = run.call(decode, { _tag: "Some", value: encoded }, {});
18670
18868
  const option = result?._tag === "Success" ? result.value : undefined;
18671
18869
  const asset = option?._tag === "Some" ? option.value : undefined;
18672
18870
  if (!isClassInstance(asset) || asset.source !== source)
@@ -18674,18 +18872,30 @@ function decodeThroughHostSchema(source) {
18674
18872
  return asset;
18675
18873
  }
18676
18874
  function hostMediaAsset(data, mediaType) {
18677
- const source = { type: "base64", data, mediaType };
18875
+ return hostMediaFromEncoded({ source: { type: "base64", data, mediaType } });
18876
+ }
18877
+ function hostMediaFromEncoded(value) {
18878
+ if (!isRecord3(value.source))
18879
+ return "missing Media.Asset source";
18880
+ const encoded = structuredClone(value);
18881
+ if (encoded.source.type === "bytes") {
18882
+ if (typeof encoded.source.data !== "string")
18883
+ return "bytes media has no JSON codec payload";
18884
+ encoded.source.data = new Uint8Array(Buffer.from(encoded.source.data, "base64"));
18885
+ }
18886
+ if (!["bytes", "base64", "url", "ref"].includes(String(encoded.source.type)))
18887
+ return "unknown Media.Asset source";
18678
18888
  let first = "no Media.Asset seen in this process";
18679
18889
  if (rememberedAssetClass) {
18680
18890
  try {
18681
- return new rememberedAssetClass({ source });
18891
+ return new rememberedAssetClass(encoded);
18682
18892
  } catch (error) {
18683
18893
  first = `remembered asset class threw: ${String(error)}`;
18684
18894
  }
18685
18895
  }
18686
18896
  let second;
18687
18897
  try {
18688
- const decoded = decodeThroughHostSchema(source);
18898
+ const decoded = decodeThroughHostSchema(encoded);
18689
18899
  if (typeof decoded !== "string")
18690
18900
  return decoded;
18691
18901
  second = decoded;
@@ -18703,9 +18913,12 @@ var v2CompactionMarkerStrategy = {
18703
18913
  reconcile: () => false
18704
18914
  };
18705
18915
 
18916
+ // src/v2/fold/memory-cache.ts
18917
+ import { randomUUID as randomUUID2 } from "node:crypto";
18918
+
18706
18919
  // src/v2/fold/owner.ts
18707
- import { createHash as createHash5 } from "node:crypto";
18708
- var foldDigest = (value) => createHash5("sha256").update(value).digest("hex");
18920
+ import { createHash as createHash6 } from "node:crypto";
18921
+ var foldDigest = (value) => createHash6("sha256").update(value).digest("hex");
18709
18922
 
18710
18923
  class FoldOwner {
18711
18924
  storage;
@@ -18785,1609 +18998,2235 @@ class FoldOwner {
18785
18998
  }
18786
18999
  }
18787
19000
 
18788
- // src/v2/fold/restore.ts
18789
- import { fileURLToPath as fileURLToPath2 } from "node:url";
19001
+ // src/v2/fold/memory-cache.ts
19002
+ var DEFAULT_NATIVE_FOLD_BUDGET = Object.freeze({
19003
+ maxSessionBytes: 16 * 1024 * 1024,
19004
+ maxSessions: 16
19005
+ });
19006
+ var stringBytes = (value) => (value?.length ?? 0) * 2;
19007
+
19008
+ class NativeFoldCache {
19009
+ resolveDB;
19010
+ sourceID = randomUUID2();
19011
+ tails = new Map;
19012
+ nativeRows = new Map;
19013
+ admissions = new Map;
19014
+ retention = new Map;
19015
+ evictionListeners = new Set;
19016
+ budget;
19017
+ constructor(resolveDB, budget = DEFAULT_NATIVE_FOLD_BUDGET) {
19018
+ this.resolveDB = resolveDB;
19019
+ if (!Number.isSafeInteger(budget.maxSessionBytes) || budget.maxSessionBytes < 1 || !Number.isSafeInteger(budget.maxSessions) || budget.maxSessions < 1)
19020
+ throw new Error("Native fold cache budgets must be positive integers");
19021
+ this.budget = { ...budget };
19022
+ }
19023
+ onEvict(listener) {
19024
+ this.evictionListeners.add(listener);
19025
+ }
19026
+ touch(sessionID) {
19027
+ const state = this.retention.get(sessionID) ?? { active: 0, bytes: 0, replayBytes: 0 };
19028
+ this.retention.delete(sessionID);
19029
+ this.retention.set(sessionID, state);
19030
+ return state;
19031
+ }
19032
+ hold(sessionID) {
19033
+ const state = this.touch(sessionID);
19034
+ state.active++;
19035
+ return () => {
19036
+ state.active--;
19037
+ this.enforceBudget();
19038
+ };
19039
+ }
19040
+ accountReplay(sessionID, bytes) {
19041
+ this.touch(sessionID).replayBytes = bytes;
19042
+ this.recount(sessionID);
19043
+ }
19044
+ usage() {
19045
+ return {
19046
+ sessions: this.retention.size,
19047
+ bytes: [...this.retention.values()].reduce((total, state) => total + state.bytes, 0)
19048
+ };
19049
+ }
19050
+ recount(sessionID) {
19051
+ const state = this.touch(sessionID);
19052
+ let bytes = 256 + stringBytes(sessionID) + state.replayBytes;
19053
+ const tail = this.tails.get(sessionID);
19054
+ if (tail)
19055
+ bytes += 128 + stringBytes(tail.data) + stringBytes(tail.digest);
19056
+ for (const row of this.nativeRows.get(sessionID)?.values() ?? [])
19057
+ bytes += 256 + stringBytes(row.id) + stringBytes(row.type) + stringBytes(row.data) + stringBytes(row.digest);
19058
+ for (const row of this.admissions.get(sessionID)?.values() ?? [])
19059
+ bytes += 256 + stringBytes(row.admission_id) + stringBytes(row.status) + stringBytes(row.owner_token) + stringBytes(row.data) + stringBytes(row.payload) + stringBytes(row.digest);
19060
+ state.bytes = bytes;
19061
+ this.enforceBudget();
19062
+ }
19063
+ enforceBudget() {
19064
+ for (const [id, state] of this.retention)
19065
+ if (!state.active && state.bytes > this.budget.maxSessionBytes)
19066
+ this.evict(id);
19067
+ for (const [id, state] of this.retention) {
19068
+ if (this.retention.size <= this.budget.maxSessions)
19069
+ break;
19070
+ if (!state.active)
19071
+ this.evict(id);
19072
+ }
19073
+ }
19074
+ evict(sessionID) {
19075
+ this.tails.delete(sessionID);
19076
+ this.nativeRows.delete(sessionID);
19077
+ this.admissions.delete(sessionID);
19078
+ this.retention.delete(sessionID);
19079
+ for (const listener of this.evictionListeners)
19080
+ listener(sessionID);
19081
+ }
19082
+ get db() {
19083
+ return this.resolveDB();
19084
+ }
19085
+ tail(sessionID) {
19086
+ const record = this.tails.get(sessionID);
19087
+ if (record)
19088
+ this.touch(sessionID);
19089
+ return record && { ...record };
19090
+ }
19091
+ async saveTail(sessionID, data, rows) {
19092
+ this.tails.set(sessionID, {
19093
+ revision: (this.tails.get(sessionID)?.revision ?? -1) + 1,
19094
+ data,
19095
+ digest: foldDigest(data)
19096
+ });
19097
+ const kept = this.nativeRows.get(sessionID) ?? new Map;
19098
+ for (const row of rows)
19099
+ kept.set(row.id, Object.freeze({ ...row, revision: (kept.get(row.id)?.revision ?? -1) + 1 }));
19100
+ this.nativeRows.set(sessionID, kept);
19101
+ this.recount(sessionID);
19102
+ }
19103
+ replaceRows(sessionID, through, rows, after = -1) {
19104
+ const kept = this.nativeRows.get(sessionID) ?? new Map;
19105
+ for (const [id, row] of kept)
19106
+ if (row.seq > after && row.seq <= through)
19107
+ kept.delete(id);
19108
+ for (const row of rows)
19109
+ kept.set(row.id, Object.freeze({ ...row, revision: 0 }));
19110
+ this.nativeRows.set(sessionID, kept);
19111
+ this.recount(sessionID);
19112
+ }
19113
+ truncate(sessionID, through) {
19114
+ const kept = this.nativeRows.get(sessionID);
19115
+ if (kept) {
19116
+ for (const [id, row] of kept)
19117
+ if (row.seq > through)
19118
+ kept.delete(id);
19119
+ }
19120
+ if (kept)
19121
+ this.recount(sessionID);
19122
+ }
19123
+ sequenceForID(sessionID, id) {
19124
+ return this.nativeRows.get(sessionID)?.get(id)?.seq;
19125
+ }
19126
+ containsRows(sessionID, ids) {
19127
+ const kept = this.nativeRows.get(sessionID);
19128
+ return ids.every((id) => kept?.has(id));
19129
+ }
19130
+ rows(sessionID, after, through) {
19131
+ if (this.retention.has(sessionID))
19132
+ this.touch(sessionID);
19133
+ return [...this.nativeRows.get(sessionID)?.values() ?? []].filter((row) => row.seq > after && row.seq <= through).sort((a, b) => a.seq - b.seq).map((row) => ({ ...row }));
19134
+ }
19135
+ admission(sessionID, id) {
19136
+ const record = this.admissions.get(sessionID)?.get(id);
19137
+ if (record)
19138
+ this.touch(sessionID);
19139
+ return record && { ...record };
19140
+ }
19141
+ put(sessionID, id, record) {
19142
+ const kept = this.admissions.get(sessionID) ?? new Map;
19143
+ kept.set(id, Object.freeze({ ...record }));
19144
+ this.admissions.set(sessionID, kept);
19145
+ this.recount(sessionID);
19146
+ }
19147
+ async supply(sessionID, id, payload) {
19148
+ const old = this.admission(sessionID, id);
19149
+ this.put(sessionID, id, {
19150
+ admission_id: id,
19151
+ revision: (old?.revision ?? -1) + 1,
19152
+ status: old?.status ?? "supplied",
19153
+ owner_token: old?.owner_token ?? null,
19154
+ data: old?.data ?? "{}",
19155
+ payload,
19156
+ digest: foldDigest(payload),
19157
+ logged_at: old?.logged_at ?? null
19158
+ });
19159
+ }
19160
+ latestAttempt(sessionID) {
19161
+ const record = [...this.admissions.get(sessionID)?.values() ?? []].reverse().find((row) => JSON.parse(row.data).after !== undefined);
19162
+ return record && { ...record };
19163
+ }
19164
+ async claim(sessionID, id, data, owner, _now) {
19165
+ const old = this.admission(sessionID, id);
19166
+ if (old?.owner_token || old?.logged_at !== null && old?.logged_at !== undefined)
19167
+ return false;
19168
+ this.put(sessionID, id, {
19169
+ admission_id: id,
19170
+ revision: 0,
19171
+ status: "pending",
19172
+ owner_token: owner,
19173
+ data,
19174
+ payload: old?.payload ?? null,
19175
+ digest: old?.digest ?? null,
19176
+ logged_at: null
19177
+ });
19178
+ return true;
19179
+ }
19180
+ async finish(sessionID, id, owner, status, now) {
19181
+ const old = this.admission(sessionID, id);
19182
+ if (!old || old.owner_token !== owner || old.status !== "pending")
19183
+ return false;
19184
+ this.put(sessionID, id, { ...old, status, owner_token: null, logged_at: now });
19185
+ return true;
19186
+ }
19187
+ async forget(sessionID) {
19188
+ this.evict(sessionID);
19189
+ }
19190
+ }
19191
+ function nativeFoldCache(db, budget) {
19192
+ return new NativeFoldCache(typeof db === "function" ? db : () => db, budget);
19193
+ }
18790
19194
 
18791
- // src/v2/hooks/storage-notice.ts
18792
- var STORAGE_NOTICE_PREFIX = "[Magic Context storage notice] ";
18793
- function formatStorageRefusalNotice(reason) {
18794
- return `${STORAGE_NOTICE_PREFIX}This turn was not sent to the model. ${formatFailClosedBlockingSummary(reason)}`;
19195
+ // src/v2/tool-result.ts
19196
+ function isToolError(part) {
19197
+ const result = part.result;
19198
+ return part.resultType === "error" || result?.type === "error" || result !== null && typeof result === "object" && "error" in result;
18795
19199
  }
18796
- function formatStorageRecoveryNotice(hiddenWorkRecovered) {
18797
- return hiddenWorkRecovered ? `${STORAGE_NOTICE_PREFIX}Magic Context storage is available again and turns are sent to the model. The historian and dreamer are running again. Restart OpenCode to enable Magic Context's tools.` : `${STORAGE_NOTICE_PREFIX}Magic Context storage is available again and turns are sent to the model. Restart OpenCode to enable Magic Context's tools, historian and dreamer.`;
19200
+ function toolErrorText(result) {
19201
+ const value = result.value === undefined ? result : result.value;
19202
+ return typeof value === "string" ? value : JSON.stringify(value);
18798
19203
  }
18799
- function isStorageNoticeText(text) {
18800
- return typeof text === "string" && text.startsWith(STORAGE_NOTICE_PREFIX);
19204
+ function toolStateContent(state) {
19205
+ if (typeof state.output === "string")
19206
+ return state.output;
19207
+ if (state.status === "error")
19208
+ return toolErrorText({ error: state.error, content: state.content ?? [] });
19209
+ if (typeof state.content === "string")
19210
+ return state.content;
19211
+ if (!Array.isArray(state.content))
19212
+ return "";
19213
+ return state.content.map((part) => {
19214
+ if (typeof part === "string")
19215
+ return part;
19216
+ if (!part || typeof part !== "object")
19217
+ return "";
19218
+ const value = part;
19219
+ if (typeof value.text === "string")
19220
+ return value.text;
19221
+ if (typeof value.value === "string")
19222
+ return value.value;
19223
+ return "";
19224
+ }).filter(Boolean).join(`
19225
+ `);
18801
19226
  }
18802
- function hasStorageNoticeShape(message) {
18803
- if (message.role !== "user" || typeof message.id !== "string")
18804
- return false;
18805
- if (message.content.length !== 1)
19227
+
19228
+ // src/v2/hooks/payload.ts
19229
+ var HEAD_IDS = ["__magic_context_v2_m0__", "__magic_context_v2_m1__"];
19230
+ var HOST_CONTENT_TYPES = new Set([
19231
+ "text",
19232
+ "media",
19233
+ "tool-call",
19234
+ "tool-result",
19235
+ "reasoning",
19236
+ "compaction",
19237
+ "effort"
19238
+ ]);
19239
+ function rejectContentPart(message, part, reason) {
19240
+ const type = typeof part.type === "string" ? part.type : "<missing>";
19241
+ const text = `v2 context omitted a content part the host would reject: type=${type} message=${String(message.info.id ?? "<head>")} reason=${reason}`;
19242
+ if (typeof message.info.sessionID === "string")
19243
+ sessionLog(message.info.sessionID, text);
19244
+ else
19245
+ log(text);
19246
+ }
19247
+ function isHostInstance(value) {
19248
+ if (!value || typeof value !== "object" || Array.isArray(value))
18806
19249
  return false;
18807
- const part = message.content[0];
18808
- return part?.type === "text" && isStorageNoticeText(part.text);
19250
+ const prototype = Object.getPrototypeOf(value);
19251
+ return prototype !== Object.prototype && prototype !== null;
18809
19252
  }
18810
- async function dropStorageNotices(messages, isAdmittedSynthetic) {
18811
- const drop = new Set;
18812
- for (const message of messages) {
18813
- if (!hasStorageNoticeShape(message))
18814
- continue;
18815
- if (await isAdmittedSynthetic(message.id))
18816
- drop.add(message);
18817
- }
18818
- if (drop.size === 0)
18819
- return 0;
18820
- const kept = messages.filter((message) => !drop.has(message));
18821
- messages.splice(0, messages.length, ...kept);
18822
- return drop.size;
19253
+ function containsHostInstance(value) {
19254
+ if (isHostInstance(value))
19255
+ return true;
19256
+ if (Array.isArray(value))
19257
+ return value.some(containsHostInstance);
19258
+ if (value && typeof value === "object")
19259
+ return Object.values(value).some(containsHostInstance);
19260
+ return false;
18823
19261
  }
18824
-
18825
- // src/v2/fold/restore.ts
18826
- function unavailableAttachmentNote(name, mediaType) {
18827
- return `[Attachment ${name ? `"${name}" ` : ""}(${mediaType}) is not available in this restored history]`;
19262
+ function clonePreservingInstances(value) {
19263
+ if (isHostInstance(value))
19264
+ return value;
19265
+ if (Array.isArray(value))
19266
+ return value.map(clonePreservingInstances);
19267
+ if (value && typeof value === "object") {
19268
+ const copy = {};
19269
+ for (const [key, entry] of Object.entries(value))
19270
+ copy[key] = clonePreservingInstances(entry);
19271
+ return copy;
19272
+ }
19273
+ return value;
18828
19274
  }
18829
- var imageMimes = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
18830
- function attachmentParts(files, rowID, media) {
18831
- const seen = new Map;
18832
- return files.flatMap((file) => {
18833
- if (imageMimes.has(file.mime) && file.source.type === "inline" && file.mention?.text) {
18834
- const key = JSON.stringify([
18835
- file.mime,
18836
- file.name ?? null,
18837
- file.description ?? null,
18838
- file.mention.text
18839
- ]);
18840
- const payloads = seen.get(key) ?? new Set;
18841
- if (payloads.has(file.data))
18842
- return [];
18843
- payloads.add(file.data);
18844
- seen.set(key, payloads);
19275
+ function contentKey(value) {
19276
+ const plain = (entry) => {
19277
+ if (ArrayBuffer.isView(entry)) {
19278
+ return {
19279
+ bytes: Buffer.from(entry.buffer, entry.byteOffset, entry.byteLength).toString("base64")
19280
+ };
18845
19281
  }
18846
- const uri = file.source.type === "uri" ? file.source.uri : undefined;
18847
- const location = uri?.startsWith("file:") ? fileURLToPath2(uri) : undefined;
18848
- if (file.mime === "text/plain" || file.mime === "application/x-directory") {
18849
- const directory = file.mime === "application/x-directory";
18850
- return [
18851
- {
18852
- type: "text",
18853
- text: `
18854
-
18855
- ${[
18856
- directory ? `Attached directory: ${location ?? file.name ?? uri ?? "directory"}` : `Attached file: ${file.name ?? uri ?? "inline attachment"}`,
18857
- file.description === undefined ? undefined : `Description: ${file.description}`,
18858
- directory && !file.data.length ? undefined : "",
18859
- directory && !file.data.length ? undefined : Buffer.from(file.data, "base64").toString("utf8")
18860
- ].filter((line) => line !== undefined).join(`
18861
- `)}`,
18862
- metadata: {
18863
- attachment: {
18864
- source: file.source,
18865
- name: file.name,
18866
- description: file.description
18867
- }
18868
- }
18869
- }
18870
- ];
18871
- }
18872
- if (!imageMimes.has(file.mime) && file.mime !== "application/pdf")
18873
- return [];
18874
- const metadata = file.description === undefined ? undefined : { description: file.description };
18875
- const located = location ? [{ type: "text", text: `Attached file: ${location}` }] : [];
18876
- if (!media)
18877
- return [
18878
- ...located,
18879
- {
18880
- type: "media",
18881
- mediaType: file.mime,
18882
- data: file.data,
18883
- filename: file.name,
18884
- metadata
18885
- }
18886
- ];
18887
- const asset = media.asset(file.data, file.mime);
18888
- if (typeof asset === "string") {
18889
- media.unavailable({ rowID, name: file.name, mediaType: file.mime, reason: asset });
18890
- return [
18891
- ...located,
18892
- { type: "text", text: unavailableAttachmentNote(file.name, file.mime) }
18893
- ];
19282
+ if (Array.isArray(entry))
19283
+ return entry.map(plain);
19284
+ if (entry && typeof entry === "object") {
19285
+ return Object.fromEntries(Object.entries(entry).map(([key, nested]) => [key, plain(nested)]));
18894
19286
  }
18895
- return [...located, { type: "media", media: asset, filename: file.name, metadata }];
18896
- });
19287
+ return entry;
19288
+ };
19289
+ return JSON.stringify(plain(value));
18897
19290
  }
18898
- function restoreRow(row, model, media) {
18899
- const data = row.data;
18900
- const make = (role, content, metadata = data.metadata) => ({
18901
- id: row.id,
18902
- role,
18903
- content,
18904
- ...metadata === undefined ? {} : { metadata }
18905
- });
18906
- if (row.type === "user") {
18907
- const skills = data.skills ?? [];
18908
- const content = [
18909
- ...skills.flatMap((skill) => skill.text === undefined ? [] : [{ type: "text", text: skill.text }]),
18910
- ...data.text ? [{ type: "text", text: data.text }] : [],
18911
- ...attachmentParts(data.files ?? [], row.id, media)
18912
- ];
18913
- return content.length ? [
18914
- make("user", content, {
18915
- ...data.metadata ?? {},
18916
- ...data.agents?.length ? { agents: data.agents } : {}
18917
- })
18918
- ] : [];
18919
- }
18920
- if (row.type === "system")
18921
- return [{ role: "system", content: [{ type: "text", text: data.text ?? "" }] }];
18922
- if (row.type === "synthetic" && isStorageNoticeText(data.text))
18923
- return [];
18924
- if (["synthetic", "skill"].includes(row.type))
18925
- return [make("user", [{ type: "text", text: data.text ?? "" }])];
18926
- if (row.type === "location-switched")
18927
- return [
18928
- make("user", [
18929
- {
18930
- type: "text",
18931
- text: `The working directory has been changed to ${data.location.directory}.`
18932
- }
18933
- ])
18934
- ];
18935
- if (row.type === "shell")
18936
- return data.metadata?.background === true ? [] : [
18937
- make("user", [
18938
- {
18939
- type: "text",
18940
- text: `The following shell command was executed by the user:
18941
-
18942
- Command:
18943
- ${data.command}
18944
-
18945
- Output:
18946
- ${data.output?.output ?? ""}`
18947
- }
18948
- ])
18949
- ];
18950
- if (row.type !== "assistant")
18951
- return [];
18952
- const previousModel = data.model;
18953
- const sameProvider = previousModel?.providerID === model.providerID;
18954
- const sameModel = sameProvider && previousModel?.id === model.id;
18955
- const reuse = sameModel && data.error === undefined;
18956
- const metadata = (state) => state === undefined ? undefined : { [model.providerID]: state };
18957
- const content = [];
18958
- const results = [];
18959
- for (const part of data.content ?? []) {
18960
- if (part.type === "text") {
18961
- if (part.text !== "")
18962
- content.push({
18963
- type: "text",
18964
- text: part.text,
18965
- providerMetadata: reuse ? metadata(part.state) : undefined
18966
- });
18967
- continue;
18968
- }
18969
- if (part.type === "reasoning") {
18970
- if (part.text !== "" || reuse && part.state !== undefined)
18971
- content.push({
18972
- type: reuse || data.error === undefined ? "reasoning" : "text",
18973
- text: part.text,
18974
- providerMetadata: reuse ? metadata(part.state) : undefined
18975
- });
19291
+ function fileContentValue(result) {
19292
+ const value = result?.value;
19293
+ if (result?.type !== "content" || !Array.isArray(value))
19294
+ return;
19295
+ return value.some((item) => item?.type === "file") ? value : undefined;
19296
+ }
19297
+ function contentValueText(value) {
19298
+ return value.filter((item) => item?.type === "text" && typeof item.text === "string").map((item) => item.text).join(`
19299
+ `);
19300
+ }
19301
+ function contentValueAttachments(value) {
19302
+ return value.filter((item) => item?.type === "file").map((item) => ({
19303
+ type: "file",
19304
+ mime: item.mime,
19305
+ url: item.uri,
19306
+ ...typeof item.name === "string" ? { filename: item.name } : {}
19307
+ }));
19308
+ }
19309
+ function rebuildFileContent(value, output) {
19310
+ if (isDroppedToolOutput(output))
19311
+ return { type: "text", value: output };
19312
+ const rebuilt = [];
19313
+ let placed = false;
19314
+ for (const item of value) {
19315
+ if (item?.type !== "text") {
19316
+ rebuilt.push(item);
18976
19317
  continue;
18977
19318
  }
18978
- const state = part.state;
18979
- const completed = state.status === "completed" || state.status === "error";
18980
- const toolReuse = reuse || sameModel && part.executed === true && completed;
18981
- let input = state.input;
18982
- if (state.status === "streaming" && typeof input === "string") {
18983
- try {
18984
- input = JSON.parse(input);
18985
- } catch {}
18986
- }
18987
- content.push({
18988
- type: "tool-call",
18989
- id: part.id,
18990
- name: part.name,
18991
- input,
18992
- providerExecuted: part.executed,
18993
- providerMetadata: toolReuse ? metadata(part.providerState) : undefined
18994
- });
18995
- if (!completed)
19319
+ if (placed)
18996
19320
  continue;
18997
- const toolContent = state.content ?? [];
18998
- const single = toolContent.length === 1 ? toolContent[0] : undefined;
18999
- const result = {
19000
- type: "tool-result",
19001
- id: part.id,
19002
- name: part.name,
19003
- providerExecuted: part.executed,
19004
- providerMetadata: toolReuse ? metadata(part.providerResultState ?? part.providerState) : sameProvider ? metadata(part.providerResultState) : undefined,
19005
- result: state.status === "error" ? { error: state.error, content: toolContent } : single?.type === "text" ? { type: "text", value: single.text } : { type: "content", value: toolContent },
19006
- ...state.status === "error" ? { resultType: "error" } : {}
19007
- };
19008
- if (part.executed === true)
19009
- content.push(result);
19010
- else
19011
- results.push({ role: "tool", content: [result] });
19321
+ placed = true;
19322
+ rebuilt.push({ ...item, text: output });
19012
19323
  }
19013
- return [...content.length ? [make("assistant", content)] : [], ...results];
19014
- }
19015
-
19016
- // src/v2/fork-inheritance.ts
19017
- var RAW_TYPES = new Set(RAW_MESSAGE_TYPES);
19018
- function forkBoundarySeq(origin, sequenceForId) {
19019
- const seq = sequenceForId(origin.parentSessionID, origin.boundary.messageID);
19020
- if (seq === undefined)
19021
- return;
19022
- return origin.boundary.type === "before" ? seq - 1 : seq;
19324
+ if (!placed && output)
19325
+ rebuilt.unshift({ type: "text", text: output });
19326
+ return { type: "content", value: rebuilt };
19023
19327
  }
19024
- function buildForkIdMap(parentRows, forkRows, throughSeq) {
19025
- const parentBySeq = new Map;
19026
- for (const row of parentRows)
19027
- if (row.seq <= throughSeq)
19028
- parentBySeq.set(row.seq, row);
19029
- const parentToFork = new Map;
19030
- const forkOrdinals = new Map;
19031
- let ordinal = 0;
19032
- for (const row of forkRows) {
19033
- if (row.seq > throughSeq)
19034
- break;
19035
- if (RAW_TYPES.has(row.type)) {
19036
- ordinal += 1;
19037
- forkOrdinals.set(row.id, ordinal);
19038
- }
19039
- const parent = parentBySeq.get(row.seq);
19040
- if (parent && parent.type === row.type && parent.time_created === row.time_created && row.id !== parent.id && row.id.endsWith(`_${row.seq}`)) {
19041
- parentToFork.set(parent.id, row.id);
19328
+ function adaptPayload(draft, admittedIDs = new Set) {
19329
+ const existingHeads = new Map(draft.messages.filter((m) => HEAD_IDS.some((id) => m.id === id)).map((m) => [m.id, m]));
19330
+ const source = draft.messages.filter((m) => !existingHeads.has(m.id));
19331
+ const results = new Map;
19332
+ const hostParts = new Map;
19333
+ const hostPartTypes = new Set;
19334
+ for (const message of source) {
19335
+ for (const part of message.content) {
19336
+ if (part.type !== "tool-call" && part.type !== "tool-result" && part.type !== "tool" && containsHostInstance(part)) {
19337
+ const key = contentKey(part);
19338
+ if (!hostParts.has(key))
19339
+ hostParts.set(key, part);
19340
+ hostPartTypes.add(part.type);
19341
+ }
19342
+ if (part.type === "tool-result" && typeof part.id === "string") {
19343
+ const queue = results.get(part.id) ?? [];
19344
+ queue.push({ part, message });
19345
+ results.set(part.id, queue);
19346
+ }
19042
19347
  }
19043
19348
  }
19044
- const parentOrdinals = new Map;
19045
- let parentOrdinal = 0;
19046
- for (const row of parentRows) {
19047
- if (row.seq > throughSeq)
19048
- break;
19049
- if (!RAW_TYPES.has(row.type))
19050
- continue;
19051
- parentOrdinal += 1;
19052
- parentOrdinals.set(parentOrdinal, row.id);
19053
- }
19054
- return { parentToFork, forkOrdinals, parentOrdinals, throughSeq };
19055
- }
19056
- var CONTENT_ID_SUFFIX = /(:(?:p|file)\d+)$/;
19057
- var BLOCK_ID_SUFFIX = /(#\d+)$/;
19058
- function splitMessageScopedId(id) {
19059
- const match = id.match(CONTENT_ID_SUFFIX) ?? id.match(BLOCK_ID_SUFFIX);
19060
- if (!match?.[1])
19061
- return { messageId: id, suffix: "" };
19062
- return { messageId: id.slice(0, -match[1].length), suffix: match[1] };
19063
- }
19064
- function forkCloneFilter(idMap, copiedToolCallIds) {
19065
- const mapMessageScoped = (id) => {
19066
- const direct = idMap.parentToFork.get(id);
19067
- if (direct)
19068
- return direct;
19069
- const { messageId, suffix } = splitMessageScopedId(id);
19070
- if (!suffix)
19071
- return;
19072
- const mapped = idMap.parentToFork.get(messageId);
19073
- return mapped ? `${mapped}${suffix}` : undefined;
19074
- };
19075
- return {
19076
- resolveBoundaryOrdinal: (messageId) => {
19077
- const forkId = idMap.parentToFork.get(messageId);
19078
- return forkId ? idMap.forkOrdinals.get(forkId) : undefined;
19079
- },
19080
- includeMessageId: (messageId) => mapMessageScoped(messageId) !== undefined || copiedToolCallIds.has(messageId),
19081
- mapMessageId: (messageId) => mapMessageScoped(messageId) ?? messageId,
19082
- includeTag: (tag) => {
19083
- if (tag.type === "tool") {
19084
- return tag.toolOwnerMessageId !== null && idMap.parentToFork.has(tag.toolOwnerMessageId);
19085
- }
19086
- return mapMessageScoped(tag.messageId) !== undefined;
19087
- },
19088
- mapOrdinal: (sourceOrdinal) => {
19089
- const parentId = idMap.parentOrdinals.get(sourceOrdinal);
19090
- const forkId = parentId ? idMap.parentToFork.get(parentId) : undefined;
19091
- return forkId ? idMap.forkOrdinals.get(forkId) : undefined;
19092
- },
19093
- copySessionNotesAndFacts: true,
19094
- selectPendingPiMarker: () => null
19095
- };
19096
- }
19097
- function countSessionRows(db, table, sessionId) {
19098
- const row = db.prepare(`SELECT COUNT(*) AS count FROM ${table} WHERE session_id = ?`).get(sessionId);
19099
- return typeof row?.count === "number" ? row.count : 0;
19100
- }
19101
- function sessionHasMagicContextState(db, sessionId) {
19102
- return countSessionRows(db, "compartments", sessionId) > 0 || countSessionRows(db, "tags", sessionId) > 0;
19103
- }
19104
- function seedV2ForkFromParent(args) {
19105
- const { db, store, sessionId } = args;
19106
- if (sessionHasMagicContextState(db, sessionId))
19107
- return { kind: "has-state" };
19108
- const origin = store.forkOrigin(sessionId);
19109
- if (!origin)
19110
- return { kind: "not-a-fork" };
19111
- const parentSessionID = origin.parentSessionID;
19112
- if (parentSessionID === sessionId)
19113
- return { kind: "not-a-fork" };
19114
- if (!sessionHasMagicContextState(db, parentSessionID))
19115
- return { kind: "parent-missing", parentSessionID, reason: "no Magic Context state" };
19116
- if (!store.sessionExists(parentSessionID))
19117
- return { kind: "parent-missing", parentSessionID, reason: "no host session row" };
19118
- const throughSeq = forkBoundarySeq(origin, (session, id) => store.sequenceForId(session, id));
19119
- if (throughSeq === undefined)
19120
- return { kind: "parent-missing", parentSessionID, reason: "boundary row not in the store" };
19121
- const idMap = buildForkIdMap(store.rowStampsThrough(parentSessionID, throughSeq), store.rowStampsThrough(sessionId, throughSeq), throughSeq);
19122
- if (idMap.parentToFork.size === 0)
19123
- return { kind: "parent-missing", parentSessionID, reason: "no copied rows pair up" };
19124
- const toolTags = db.prepare("SELECT message_id, tool_owner_message_id FROM tags WHERE session_id = ? AND type = 'tool'").all(parentSessionID);
19125
- const copiedToolCallIds = new Set(toolTags.filter((row) => row.tool_owner_message_id !== null && idMap.parentToFork.has(row.tool_owner_message_id)).map((row) => row.message_id));
19126
- const result = copySessionStateForClone(db, parentSessionID, sessionId, forkCloneFilter(idMap, copiedToolCallIds));
19127
- if (result.kind === "destination-not-empty")
19128
- return { kind: "destination-not-empty", parentSessionID };
19129
- return { kind: "seeded", parentSessionID, pairedRows: idMap.parentToFork.size, result };
19130
- }
19131
-
19132
- // src/v2/hidden-child-record.ts
19133
- function keptUnderRetention(keepSubagents, child) {
19134
- return keepSubagents && (child.ever_settled === true || child.role === "historian");
19135
- }
19136
- function roleTitle(role) {
19137
- if (role === "maintainer-a")
19138
- return "Magic Context maintainer A";
19139
- if (role === "maintainer-b")
19140
- return "Magic Context maintainer B";
19141
- return "Magic Context historian";
19142
- }
19143
- function roleAgent(role) {
19144
- if (role === "maintainer-a")
19145
- return MEMORY_MAINTAINER_A_AGENT;
19146
- if (role === "maintainer-b")
19147
- return MEMORY_MAINTAINER_B_AGENT;
19148
- return HIDDEN_HISTORIAN_AGENT;
19149
- }
19150
- function childCreateInput(identity, role, model) {
19151
- const agent = roleAgent(role);
19152
- return {
19153
- title: roleTitle(role),
19154
- agent,
19155
- model: {
19156
- providerID: model.providerID,
19157
- id: model.modelID,
19158
- ...model.variant ? { variant: model.variant } : {}
19159
- },
19160
- location: { directory: identity.directory },
19161
- metadata: { magic_context: "hidden-run", role },
19162
- permissions: hiddenChildPermissions(agent)
19163
- };
19164
- }
19165
- function assistantOutcome(row) {
19166
- const outcome = row?.data.outcome;
19167
- return outcome === "succeeded" || outcome === "failed" || outcome === "interrupted" ? outcome : undefined;
19168
- }
19169
- function withReader(openReader, read) {
19170
- const reader = openReader();
19171
- try {
19172
- return read(reader);
19173
- } finally {
19174
- reader.close?.();
19175
- }
19176
- }
19177
- function errorText(value) {
19178
- if (value instanceof Error)
19179
- return value.message;
19180
- if (typeof value === "string")
19181
- return value;
19182
- try {
19183
- return JSON.stringify(value);
19184
- } catch {
19185
- return String(value);
19186
- }
19187
- }
19188
-
19189
- // src/v2/hidden-child-native.ts
19190
- function nativeSessionRemove(session) {
19191
- const remove = session.remove;
19192
- if (typeof remove !== "function")
19193
- return;
19194
- return (input) => Promise.resolve(remove.call(session, { sessionID: input.sessionID }));
19195
- }
19196
- function isSessionNotFound(error) {
19197
- if (!error || typeof error !== "object")
19198
- return false;
19199
- const fields = error;
19200
- if (fields.status === 404)
19201
- return true;
19202
- const label = [fields.name, fields._tag, fields.message].filter((value) => typeof value === "string").join(" ");
19203
- return /not\s*found/i.test(label);
19204
- }
19205
- var parentDroppedNoted = false;
19206
- function createNativeHiddenChildren(host, removeSession, options) {
19207
- const removing = new Map;
19208
- const remove = (child) => {
19209
- const inFlight = removing.get(child.id);
19210
- if (inFlight)
19211
- return inFlight;
19212
- const done = (async () => {
19213
- try {
19214
- let timer;
19215
- try {
19216
- await Promise.race([
19217
- removeSession({ sessionID: child.id }),
19218
- new Promise((_, reject) => {
19219
- timer = setTimeout(() => reject(new Error("session.remove timed out")), options.removalTimeoutMs ?? 5000);
19220
- })
19221
- ]);
19222
- } finally {
19223
- if (timer)
19224
- clearTimeout(timer);
19225
- }
19226
- } catch (error) {
19227
- if (isSessionNotFound(error))
19228
- return;
19229
- options.log(`[magic-context] hidden child ${child.id} could not be removed; it goes when its parent session is deleted: ${errorText(error)}`);
19349
+ const paired = new Set;
19350
+ const bridges = new Map;
19351
+ const originals = new Map;
19352
+ const bridgesByMessageID = new Map;
19353
+ const bridgesByCarrier = new Map;
19354
+ const originalsByID = new Map;
19355
+ const bridgesFor = (message) => typeof message.info.id === "string" ? bridgesByMessageID.get(message.info.id) : bridgesByCarrier.get(message);
19356
+ const nativeTool = (call, result) => {
19357
+ const hostResult = result?.part.result;
19358
+ const failed = result !== undefined && isToolError(result.part);
19359
+ const value = hostResult?.value;
19360
+ const files = fileContentValue(hostResult);
19361
+ const output = failed && hostResult ? toolErrorText(hostResult) : files ? contentValueText(files) : typeof value === "string" ? value : value === undefined ? "" : JSON.stringify(value);
19362
+ const part = {
19363
+ type: "tool",
19364
+ callID: call?.id ?? result?.part.id,
19365
+ tool: call?.name ?? result?.part.name,
19366
+ state: {
19367
+ input: structuredClone(call?.input ?? {}),
19368
+ status: failed ? "error" : result ? "completed" : "running",
19369
+ ...result ? { output } : {},
19370
+ ...result && (call?.name ?? result.part.name) === "question" ? { metadata: { userAnswer: true } } : {},
19371
+ ...files ? { attachments: contentValueAttachments(files) } : {}
19230
19372
  }
19231
- })().finally(() => {
19232
- removing.delete(child.id);
19373
+ };
19374
+ bridges.set(part, {
19375
+ call,
19376
+ result: result?.part,
19377
+ resultMessage: result?.message,
19378
+ output,
19379
+ files
19233
19380
  });
19234
- removing.set(child.id, done);
19235
- return done;
19236
- };
19237
- const confirmPlacement = async (sessionID, parentID) => {
19238
- let stored;
19239
- try {
19240
- stored = await host.get({ sessionID });
19241
- } catch (error) {
19242
- options.log(`[magic-context] could not read back hidden child ${sessionID} to confirm its parent: ${errorText(error)}`);
19243
- return;
19244
- }
19245
- const directory = stored.location?.directory;
19246
- if (options.directory !== undefined && directory !== undefined && directory !== options.directory) {
19247
- throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", `hidden child ${sessionID} is bound to ${directory}, not to this instance's ${options.directory}`, true);
19248
- }
19249
- if (stored.parentID === parentID || parentDroppedNoted)
19250
- return;
19251
- parentDroppedNoted = true;
19252
- options.log(`[magic-context] this OpenCode 2 host does not keep the parent of hidden-run sessions (asked for ${parentID}, read back ${stored.parentID ?? "none"}); they are created as separate sessions and still removed when each run ends`);
19381
+ if (result)
19382
+ paired.add(result.part);
19383
+ return part;
19253
19384
  };
19254
- const create = async (identity, role, model) => {
19255
- const parentID = identity.parentSessionId;
19256
- const input = childCreateInput(identity, role, model);
19257
- const { location, ...parented } = input;
19258
- const created = await host.create(parentID ? { ...parented, parentID } : { ...parented, location });
19259
- if (!created.id)
19260
- throw new Error("OpenCode 2 did not return a child session id");
19261
- options.hook.registerChild(created.id, input.agent);
19262
- const child = {
19263
- id: created.id,
19264
- role,
19265
- generation: options.generation,
19266
- title: roleTitle(role),
19267
- model,
19268
- created_at: Date.now(),
19269
- directory: identity.directory
19385
+ const convertedTool = (source) => {
19386
+ const sourceState = source.state && typeof source.state === "object" ? source.state : {};
19387
+ const output = toolStateContent(sourceState);
19388
+ const { content: _content, ...projectedState } = structuredClone(sourceState);
19389
+ const part = {
19390
+ type: "tool",
19391
+ callID: source.callID ?? source.id,
19392
+ tool: source.tool ?? source.name,
19393
+ state: { ...projectedState, output }
19270
19394
  };
19271
- if (parentID) {
19272
- try {
19273
- await confirmPlacement(created.id, parentID);
19274
- } catch (error) {
19275
- await remove(child);
19276
- throw error;
19395
+ bridges.set(part, { native: source, output });
19396
+ return part;
19397
+ };
19398
+ const callParts = new Map;
19399
+ for (const message of source) {
19400
+ for (const part of message.content) {
19401
+ if (part.type === "tool-call") {
19402
+ callParts.set(part, nativeTool(part, results.get(String(part.id))?.shift()));
19403
+ } else if (part.type === "tool") {
19404
+ callParts.set(part, convertedTool(part));
19277
19405
  }
19278
19406
  }
19279
- return child;
19280
- };
19281
- const kept = (child) => keptUnderRetention(options.keepSubagents, child);
19282
- return {
19283
- open: create,
19284
- create,
19285
- retire(child) {
19286
- if (!kept(child))
19287
- remove(child);
19288
- },
19289
- async finish(child, retired) {
19290
- if (retired) {
19291
- await removing.get(child.id);
19292
- return;
19293
- }
19294
- if (!kept(child))
19295
- await remove(child);
19296
- },
19297
- updateModel: (child, model) => ({ ...child, model }),
19298
- markEverSettled: (child) => ({ ...child, ever_settled: true })
19299
- };
19300
- }
19301
-
19302
- // src/v2/hidden-child-cleanup.ts
19303
- var PREFIX = "opencode2_hidden_children:";
19304
- var COMPLETE = "opencode2_hidden_children_cleanup_complete";
19305
- async function cleanupLegacyHiddenChildren(db, remove, note, options = {}) {
19306
- if (db.prepare("SELECT 1 FROM schema_migrations_meta WHERE key = ?").get(COMPLETE))
19307
- return;
19308
- const rows = db.prepare("SELECT key, value FROM schema_migrations_meta WHERE key GLOB ? ORDER BY key LIMIT 25").all(`${PREFIX}*`);
19309
- let remaining = options.limit ?? 25;
19310
- const now = options.now ?? (() => performance.now());
19311
- const deadline = now() + (options.budgetMs ?? 2000);
19312
- for (const row of rows) {
19313
- let record;
19314
- try {
19315
- record = JSON.parse(row.value);
19316
- if (!record || typeof record !== "object" || record.active !== undefined && (!record.active || typeof record.active !== "object" || Array.isArray(record.active)) || record.retired_children !== undefined && !Array.isArray(record.retired_children))
19317
- throw new Error("invalid record");
19318
- } catch {
19319
- note(`[magic-context] legacy hidden-child cleanup cannot read ${row.key}`);
19407
+ }
19408
+ const messages = [];
19409
+ for (const message of source) {
19410
+ const parts = [];
19411
+ for (const content of message.content) {
19412
+ if (paired.has(content))
19413
+ continue;
19414
+ const part = callParts.get(content) ?? (content.type === "tool-result" ? nativeTool(undefined, { part: content, message }) : clonePreservingInstances(content));
19415
+ if (message.id && admittedIDs.has(message.id))
19416
+ part.synthetic = true;
19417
+ parts.push(part);
19418
+ }
19419
+ if (!parts.length && message.content.length)
19320
19420
  continue;
19421
+ const byCallID = new Map;
19422
+ for (const part of parts) {
19423
+ const bridge = bridges.get(part);
19424
+ if (bridge && typeof part.callID === "string")
19425
+ byCallID.set(part.callID, bridge);
19321
19426
  }
19322
- const children = [
19323
- ...Object.values(record.active ?? {}),
19324
- ...record.retired_children ?? []
19325
- ];
19326
- for (const child of children) {
19327
- if (remaining-- <= 0 || now() >= deadline)
19328
- return;
19329
- if (typeof child?.id !== "string") {
19330
- note(`[magic-context] legacy hidden-child cleanup has an invalid child in ${row.key}`);
19331
- continue;
19332
- }
19333
- let timer;
19334
- try {
19335
- try {
19336
- await Promise.race([
19337
- remove({ sessionID: child.id }),
19338
- new Promise((_, reject) => {
19339
- timer = setTimeout(() => reject(new Error("session.remove timed out")), Math.min(options.timeoutMs ?? 1000, Math.max(1, deadline - now())));
19340
- })
19341
- ]);
19342
- } catch (error) {
19343
- if (!isSessionNotFound(error))
19344
- throw error;
19427
+ if (typeof message.id === "string") {
19428
+ bridgesByMessageID.set(message.id, byCallID);
19429
+ originalsByID.set(message.id, message);
19430
+ }
19431
+ const mapped = {
19432
+ info: {
19433
+ id: message.id,
19434
+ sessionID: draft.sessionID,
19435
+ role: message.role,
19436
+ ...{
19437
+ providerID: draft.model.providerID,
19438
+ modelID: draft.model.id,
19439
+ agent: draft.agent
19345
19440
  }
19346
- record.active = Object.fromEntries(Object.entries(record.active ?? {}).filter(([, entry]) => entry.id !== child.id));
19347
- record.retired_children = (record.retired_children ?? []).filter((entry) => entry.id !== child.id);
19348
- db.prepare("UPDATE schema_migrations_meta SET value = ? WHERE key = ?").run(JSON.stringify(record), row.key);
19349
- } catch (error) {
19350
- note(`[magic-context] legacy hidden child ${child.id} cleanup deferred: ${String(error)}`);
19351
- } finally {
19352
- if (timer)
19353
- clearTimeout(timer);
19441
+ },
19442
+ parts
19443
+ };
19444
+ originals.set(mapped, message);
19445
+ if (typeof message.id !== "string")
19446
+ bridgesByCarrier.set(mapped, byCallID);
19447
+ messages.push(mapped);
19448
+ }
19449
+ return {
19450
+ messages,
19451
+ commit() {
19452
+ let head = 0;
19453
+ const rendered = [];
19454
+ for (const message of messages) {
19455
+ const original = originals.get(message) ?? (typeof message.info.id === "string" ? originalsByID.get(message.info.id) : undefined);
19456
+ const id = message.info.syntheticHead ? HEAD_IDS[head++] : original?.id;
19457
+ const content = [];
19458
+ const following = [];
19459
+ for (const candidate of message.parts) {
19460
+ const part = candidate;
19461
+ const bridge = bridges.get(part) ?? (part.type === "tool" && typeof part.callID === "string" ? bridgesFor(message)?.get(part.callID) : undefined);
19462
+ if (!bridge) {
19463
+ if (part.type === "tool") {
19464
+ const state = part.state;
19465
+ if (typeof part.callID !== "string" || typeof part.tool !== "string" || !state || typeof state !== "object") {
19466
+ rejectContentPart(message, part, "tool has no call ID, name, or state");
19467
+ continue;
19468
+ }
19469
+ content.push({
19470
+ type: "tool-call",
19471
+ id: part.callID,
19472
+ name: part.tool,
19473
+ input: state.input
19474
+ });
19475
+ if (state.status === "completed" || state.status === "error") {
19476
+ following.push({
19477
+ role: "tool",
19478
+ content: [
19479
+ {
19480
+ type: "tool-result",
19481
+ id: part.callID,
19482
+ name: part.tool,
19483
+ result: {
19484
+ type: state.status === "error" ? "error" : "text",
19485
+ value: toolStateContent(state)
19486
+ }
19487
+ }
19488
+ ]
19489
+ });
19490
+ }
19491
+ continue;
19492
+ }
19493
+ if (part.type === "file") {
19494
+ const mime = part.mime;
19495
+ const url = part.url;
19496
+ const prefix = `data:${mime};base64,`;
19497
+ if (typeof mime !== "string" || !/^image\/(png|jpeg|gif|webp)$/.test(mime) || typeof url !== "string" || !url.startsWith(prefix)) {
19498
+ rejectContentPart(message, part, "file is not an inline supported image");
19499
+ continue;
19500
+ }
19501
+ const asset = hostMediaAsset(url.slice(prefix.length), mime);
19502
+ if (typeof asset === "string") {
19503
+ rejectContentPart(message, part, `host media unavailable: ${asset}`);
19504
+ continue;
19505
+ }
19506
+ content.push({ type: "media", media: asset });
19507
+ continue;
19508
+ }
19509
+ if (!HOST_CONTENT_TYPES.has(String(part.type))) {
19510
+ rejectContentPart(message, part, "unknown host content type");
19511
+ continue;
19512
+ }
19513
+ const { synthetic: _synthetic, ...clean } = part;
19514
+ const original = hostPartTypes.has(clean.type) && !containsHostInstance(clean) ? hostParts.get(contentKey(clean)) : undefined;
19515
+ content.push(original ?? clean);
19516
+ continue;
19517
+ }
19518
+ const state = part.state;
19519
+ if (bridge.native) {
19520
+ const native = bridge.native;
19521
+ const callID = String(native.id ?? native.callID ?? part.callID);
19522
+ const name = String(native.name ?? native.tool ?? part.tool);
19523
+ content.push({ type: "tool-call", id: callID, name, input: state.input });
19524
+ if (state.status === "completed" || state.status === "error") {
19525
+ following.push({
19526
+ role: "tool",
19527
+ content: [
19528
+ {
19529
+ type: "tool-result",
19530
+ id: callID,
19531
+ name,
19532
+ result: {
19533
+ type: state.status === "error" ? "error" : "text",
19534
+ value: state.output
19535
+ }
19536
+ }
19537
+ ]
19538
+ });
19539
+ }
19540
+ continue;
19541
+ }
19542
+ if (bridge.call)
19543
+ content.push({ ...bridge.call, input: state.input });
19544
+ if (bridge.result && bridge.resultMessage) {
19545
+ const result = {
19546
+ ...bridge.result,
19547
+ result: state.output === bridge.output ? bridge.result.result : bridge.files && typeof state.output === "string" ? rebuildFileContent(bridge.files, state.output) : {
19548
+ type: state.status === "error" ? "error" : "text",
19549
+ value: state.output
19550
+ }
19551
+ };
19552
+ if (bridge.resultMessage === original)
19553
+ content.push(result);
19554
+ else
19555
+ following.push({ ...bridge.resultMessage, content: [result] });
19556
+ }
19557
+ }
19558
+ if (content.length || !original?.content.length) {
19559
+ const value = {
19560
+ ...original,
19561
+ id,
19562
+ role: message.info.role ?? "user",
19563
+ content
19564
+ };
19565
+ const existing = id ? existingHeads.get(id) : undefined;
19566
+ rendered.push(existing ? Object.assign(existing, { content }) : value);
19567
+ }
19568
+ rendered.push(...following);
19354
19569
  }
19570
+ draft.messages.splice(0, draft.messages.length, ...rendered);
19355
19571
  }
19356
- if (Object.keys(record.active ?? {}).length === 0 && (record.retired_children ?? []).length === 0)
19357
- db.prepare("DELETE FROM schema_migrations_meta WHERE key = ?").run(row.key);
19358
- }
19359
- if (!db.prepare("SELECT 1 FROM schema_migrations_meta WHERE key GLOB ? LIMIT 1").get(`${PREFIX}*`))
19360
- db.prepare("INSERT OR IGNORE INTO schema_migrations_meta (key, value) VALUES (?, 'true')").run(COMPLETE);
19572
+ };
19361
19573
  }
19362
19574
 
19363
- // src/v2/hidden-completion.ts
19364
- var POLL_INTERVAL_MS = 200;
19365
- function modelKey(model) {
19366
- return `${model.providerID}/${model.modelID}`;
19575
+ // src/v2/fold/native-codec.ts
19576
+ class NativeReplayUnavailable extends Error {
19367
19577
  }
19368
- function sameModel(left, right) {
19369
- return modelKey(left) === modelKey(right) && left.variant === right.variant;
19578
+ function encodeNative(messages) {
19579
+ for (const message of messages)
19580
+ for (const part of message.content) {
19581
+ if (part.type !== "media" || !part.media)
19582
+ continue;
19583
+ const asset = part.media;
19584
+ if (typeof asset.toJSON !== "function" || asset.headers !== undefined)
19585
+ throw new NativeReplayUnavailable("Native media has no lossless replay codec");
19586
+ const encoded = asset.toJSON();
19587
+ const revived = hostMediaFromEncoded(encoded);
19588
+ if (typeof revived === "string" || JSON.stringify(revived) !== JSON.stringify(asset))
19589
+ throw new NativeReplayUnavailable("Native media cannot be decoded losslessly before admission");
19590
+ }
19591
+ const encoded = JSON.parse(JSON.stringify(messages));
19592
+ const freeze = (value) => {
19593
+ if (!value || typeof value !== "object")
19594
+ return;
19595
+ for (const item of Object.values(value))
19596
+ freeze(item);
19597
+ Object.freeze(value);
19598
+ };
19599
+ freeze(encoded);
19600
+ return encoded;
19370
19601
  }
19371
- function configuredHead(identity) {
19372
- const candidates = [identity.model, ...identity.configuredModels ?? []];
19373
- for (const candidate of candidates) {
19374
- const entry = toModelEntry(candidate);
19375
- const parsed = entry ? parseProviderModel(entry.model) : null;
19376
- if (parsed)
19377
- return { ...parsed, ...entry?.qualifier ? { variant: entry.qualifier } : {} };
19378
- }
19379
- return;
19380
- }
19381
- var HIDDEN_MAINTAINER_ROLES = {
19382
- "maintainer-a": "magic-context-maintainer-a",
19383
- "maintainer-b": "magic-context-maintainer-b"
19384
- };
19385
- function roleFor(identity) {
19386
- for (const [role, agent] of Object.entries(HIDDEN_MAINTAINER_ROLES)) {
19387
- if (identity.agent === agent)
19388
- return role;
19389
- }
19390
- return "historian";
19391
- }
19392
- function promptText(request) {
19393
- const parts = request.body.parts;
19394
- return Array.isArray(parts) ? parts.flatMap((part) => part && typeof part === "object" && typeof part.text === "string" ? [part.text] : []).join(`
19395
- `) : "";
19602
+ function reviveNative(messages) {
19603
+ const result = structuredClone([...messages]);
19604
+ for (const message of result)
19605
+ for (const part of message.content) {
19606
+ if (part.type !== "media" || !part.media)
19607
+ continue;
19608
+ const asset = hostMediaFromEncoded(part.media);
19609
+ if (typeof asset === "string")
19610
+ throw new NativeReplayUnavailable(asset);
19611
+ part.media = asset;
19612
+ }
19613
+ return result;
19396
19614
  }
19397
- function meter(system, prompt, text) {
19398
- return {
19399
- input: estimateTokens(system) + estimateTokens(prompt),
19400
- output: estimateTokens(text),
19401
- cacheRead: 0,
19402
- cacheWrite: 0
19403
- };
19615
+
19616
+ // src/v2/fold/restore.ts
19617
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
19618
+
19619
+ // src/v2/hooks/storage-notice.ts
19620
+ var STORAGE_NOTICE_PREFIX = "[Magic Context storage notice] ";
19621
+ function formatStorageRefusalNotice(reason) {
19622
+ return `${STORAGE_NOTICE_PREFIX}This turn was not sent to the model. ${formatFailClosedBlockingSummary(reason)}`;
19404
19623
  }
19405
- function assistantReasoning(row) {
19406
- const reasoning = (row.data.content ?? []).flatMap((part) => part.type === "reasoning" && typeof part.text === "string" ? [part.text] : []).join(`
19407
- `);
19408
- return reasoning.length > 0 ? reasoning : null;
19624
+ function formatStorageRecoveryNotice(hiddenWorkRecovered) {
19625
+ return hiddenWorkRecovered ? `${STORAGE_NOTICE_PREFIX}Magic Context storage is available again and turns are sent to the model. The historian and dreamer are running again. Restart OpenCode to enable Magic Context's tools.` : `${STORAGE_NOTICE_PREFIX}Magic Context storage is available again and turns are sent to the model. Restart OpenCode to enable Magic Context's tools, historian and dreamer.`;
19409
19626
  }
19410
- function assistantText(row) {
19411
- const text = (row.data.content ?? []).flatMap((part) => part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("");
19412
- return text.length > 0 ? text : null;
19627
+ function isStorageNoticeText(text) {
19628
+ return typeof text === "string" && text.startsWith(STORAGE_NOTICE_PREFIX);
19413
19629
  }
19414
-
19415
- class HiddenProviderError extends Error {
19416
- settled;
19417
- constructor(detail, options = {}) {
19418
- super(`Hidden completion provider error: ${detail}`);
19419
- this.name = "HiddenProviderError";
19420
- this.settled = options.settled ?? true;
19421
- }
19630
+ function hasStorageNoticeShape(message) {
19631
+ if (message.role !== "user" || typeof message.id !== "string")
19632
+ return false;
19633
+ if (message.content.length !== 1)
19634
+ return false;
19635
+ const part = message.content[0];
19636
+ return part?.type === "text" && isStorageNoticeText(part.text);
19422
19637
  }
19423
- function requestModel(request, current) {
19424
- const requested = request.body.model;
19425
- if (requested && typeof requested.providerID === "string" && typeof requested.modelID === "string") {
19426
- return {
19427
- providerID: requested.providerID,
19428
- modelID: requested.modelID,
19429
- ...typeof request.body.variant === "string" ? { variant: request.body.variant } : {}
19430
- };
19638
+ async function dropStorageNotices(messages, isAdmittedSynthetic) {
19639
+ const drop = new Set;
19640
+ for (const message of messages) {
19641
+ if (!hasStorageNoticeShape(message))
19642
+ continue;
19643
+ if (await isAdmittedSynthetic(message.id))
19644
+ drop.add(message);
19431
19645
  }
19432
- return current;
19433
- }
19434
- async function sleepUntilPoll(signal, deadline) {
19435
- if (signal?.aborted)
19436
- throw new Error("Hidden completion prompt aborted");
19437
- const delay = Math.min(POLL_INTERVAL_MS, Math.max(0, deadline - Date.now()));
19438
- if (delay <= 0)
19439
- return;
19440
- await new Promise((resolve, reject) => {
19441
- const timer = setTimeout(resolve, delay);
19442
- const abort = () => {
19443
- clearTimeout(timer);
19444
- reject(new Error("Hidden completion prompt aborted"));
19445
- };
19446
- signal?.addEventListener("abort", abort, { once: true });
19447
- if (signal?.aborted)
19448
- abort();
19449
- else
19450
- setTimeout(() => {
19451
- signal?.removeEventListener("abort", abort);
19452
- }, delay);
19453
- });
19646
+ if (drop.size === 0)
19647
+ return 0;
19648
+ const kept = messages.filter((message) => !drop.has(message));
19649
+ messages.splice(0, messages.length, ...kept);
19650
+ return drop.size;
19454
19651
  }
19455
- function isProviderFailure(error) {
19456
- if (!error || typeof error !== "object")
19457
- return false;
19458
- const type = error.type;
19459
- return typeof type === "string" && (type.startsWith("provider.") || type.toLowerCase().includes("provider"));
19652
+
19653
+ // src/v2/fold/restore.ts
19654
+ function unavailableAttachmentNote(name, mediaType) {
19655
+ return `[Attachment ${name ? `"${name}" ` : ""}(${mediaType}) is not available in this restored history]`;
19460
19656
  }
19461
- async function awaitAssistantRow(openReader, readSessionError, localFailure, childID, afterSeq, deadline, signal) {
19462
- for (;; ) {
19463
- const { assistant, idle } = withReader(openReader, (reader) => ({
19464
- assistant: reader.latestAssistant(childID),
19465
- idle: reader.latestIdle(childID)
19466
- }));
19467
- const newAssistant = assistant && assistant.seq > afterSeq ? assistant : undefined;
19468
- const newIdle = idle && idle.seq > afterSeq ? idle : undefined;
19469
- const refused = localFailure();
19470
- if (refused)
19471
- throw refused;
19472
- if (newIdle && (!newAssistant || newIdle.seq > newAssistant.seq)) {
19473
- const outcome = newIdle.data.outcome;
19474
- if (outcome === "failed" || outcome === "interrupted") {
19475
- const sessionError = await readSessionError();
19476
- const details = [
19477
- `outcome=${outcome}`,
19478
- `terminal_row=${errorText(newIdle)}`,
19479
- `session_error=${sessionError === undefined ? "unavailable" : errorText(sessionError)}`
19480
- ];
19481
- throw sessionError === undefined || !isProviderFailure(sessionError) ? new Error(`Hidden completion failed: ${details.join("; ")}`) : new HiddenProviderError(details.join("; "));
19482
- }
19483
- if (outcome === "succeeded" && newAssistant)
19484
- return newAssistant;
19657
+ var imageMimes = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
19658
+ function attachmentParts(files, rowID, media) {
19659
+ const seen = new Map;
19660
+ return files.flatMap((file) => {
19661
+ if (imageMimes.has(file.mime) && file.source.type === "inline" && file.mention?.text) {
19662
+ const key = JSON.stringify([
19663
+ file.mime,
19664
+ file.name ?? null,
19665
+ file.description ?? null,
19666
+ file.mention.text
19667
+ ]);
19668
+ const payloads = seen.get(key) ?? new Set;
19669
+ if (payloads.has(file.data))
19670
+ return [];
19671
+ payloads.add(file.data);
19672
+ seen.set(key, payloads);
19485
19673
  }
19486
- if (newAssistant) {
19487
- const outcome = assistantOutcome(newAssistant);
19488
- if (outcome === "failed" || outcome === "interrupted") {
19489
- const sessionError = await readSessionError();
19490
- const details = [
19491
- `outcome=${outcome}`,
19492
- `terminal_row=${errorText(newAssistant)}`,
19493
- `session_error=${sessionError === undefined ? "unavailable" : errorText(sessionError)}`
19494
- ];
19495
- throw sessionError === undefined || !isProviderFailure(sessionError) ? new Error(`Hidden completion failed: ${details.join("; ")}`) : new HiddenProviderError(details.join("; "));
19496
- }
19497
- if (newAssistant.data.error !== undefined) {
19498
- throw new HiddenProviderError(errorText(newAssistant.data.error), {
19499
- settled: typeof newAssistant.data.finish === "string"
19500
- });
19501
- }
19502
- if (typeof newAssistant.data.finish === "string" || outcome === "succeeded") {
19503
- return newAssistant;
19504
- }
19674
+ const uri = file.source.type === "uri" ? file.source.uri : undefined;
19675
+ const location = uri?.startsWith("file:") ? fileURLToPath2(uri) : undefined;
19676
+ if (file.mime === "text/plain" || file.mime === "application/x-directory") {
19677
+ const directory = file.mime === "application/x-directory";
19678
+ return [
19679
+ {
19680
+ type: "text",
19681
+ text: `
19682
+
19683
+ ${[
19684
+ directory ? `Attached directory: ${location ?? file.name ?? uri ?? "directory"}` : `Attached file: ${file.name ?? uri ?? "inline attachment"}`,
19685
+ file.description === undefined ? undefined : `Description: ${file.description}`,
19686
+ directory && !file.data.length ? undefined : "",
19687
+ directory && !file.data.length ? undefined : Buffer.from(file.data, "base64").toString("utf8")
19688
+ ].filter((line) => line !== undefined).join(`
19689
+ `)}`,
19690
+ metadata: {
19691
+ attachment: {
19692
+ source: file.source,
19693
+ name: file.name,
19694
+ description: file.description
19695
+ }
19696
+ }
19697
+ }
19698
+ ];
19505
19699
  }
19506
- if (Date.now() >= deadline) {
19507
- throw new Error("Hidden completion timed out waiting for a persisted assistant row");
19700
+ if (!imageMimes.has(file.mime) && file.mime !== "application/pdf")
19701
+ return [];
19702
+ const metadata = file.description === undefined ? undefined : { description: file.description };
19703
+ const located = location ? [{ type: "text", text: `Attached file: ${location}` }] : [];
19704
+ if (!media)
19705
+ return [
19706
+ ...located,
19707
+ {
19708
+ type: "media",
19709
+ mediaType: file.mime,
19710
+ data: file.data,
19711
+ filename: file.name,
19712
+ metadata
19713
+ }
19714
+ ];
19715
+ const asset = media.asset(file.data, file.mime);
19716
+ if (typeof asset === "string") {
19717
+ media.unavailable({ rowID, name: file.name, mediaType: file.mime, reason: asset });
19718
+ return [
19719
+ ...located,
19720
+ { type: "text", text: unavailableAttachmentNote(file.name, file.mime) }
19721
+ ];
19508
19722
  }
19509
- await sleepUntilPoll(signal, deadline);
19510
- }
19511
- }
19512
- var V2_HIDDEN_EXECUTOR_CAPABILITIES = {
19513
- tools: true,
19514
- harness: "opencode2"
19515
- };
19516
- function createLateHiddenExecutor(current) {
19517
- const wired = () => {
19518
- const executor = current();
19519
- if (executor)
19520
- return executor;
19521
- throw new Error("Magic Context hidden work is unavailable until the context database opens.");
19522
- };
19523
- return {
19524
- get capabilities() {
19525
- return current()?.capabilities ?? V2_HIDDEN_EXECUTOR_CAPABILITIES;
19526
- },
19527
- open: (run) => wired().open(run),
19528
- attempt: (handle, request) => wired().attempt(handle, request),
19529
- collect: (handle, limit) => wired().collect(handle, limit),
19530
- close: (handle, settlement) => wired().close(handle, settlement)
19531
- };
19723
+ return [...located, { type: "media", media: asset, filename: file.name, metadata }];
19724
+ });
19532
19725
  }
19533
- async function createV2HiddenCompletionExecutor(host, options) {
19534
- const runs = new WeakMap;
19535
- const generation = options.generation ?? "opencode2";
19536
- const roleTails = new Map;
19537
- const note = options.log ?? log;
19538
- const removeSession = host.removeSession;
19539
- if (!removeSession)
19540
- throw new Error("Magic Context requires OpenCode 2.0.22 session.remove");
19541
- const lifecycle = createNativeHiddenChildren(host, (input) => removeSession.call(host, input), {
19542
- hook: options.hook,
19543
- generation,
19544
- keepSubagents: options.keepSubagents === true,
19545
- log: note,
19546
- removalTimeoutMs: options.removalTimeoutMs,
19547
- directory: options.directory
19726
+ function restoreRow(row, model, media) {
19727
+ const data = row.data;
19728
+ const make = (role, content, metadata = data.metadata) => ({
19729
+ id: row.id,
19730
+ role,
19731
+ content,
19732
+ ...metadata === undefined ? {} : { metadata }
19548
19733
  });
19549
- const acquireRole = async (role) => {
19550
- const previous = roleTails.get(role) ?? Promise.resolve();
19551
- let release;
19552
- const gate = new Promise((resolve) => {
19553
- release = resolve;
19734
+ if (row.type === "user") {
19735
+ const skills = data.skills ?? [];
19736
+ const content = [
19737
+ ...skills.flatMap((skill) => skill.text === undefined ? [] : [{ type: "text", text: skill.text }]),
19738
+ ...data.text ? [{ type: "text", text: data.text }] : [],
19739
+ ...attachmentParts(data.files ?? [], row.id, media)
19740
+ ];
19741
+ return content.length ? [
19742
+ make("user", content, {
19743
+ ...data.metadata ?? {},
19744
+ ...data.agents?.length ? { agents: data.agents } : {}
19745
+ })
19746
+ ] : [];
19747
+ }
19748
+ if (row.type === "system")
19749
+ return [{ role: "system", content: [{ type: "text", text: data.text ?? "" }] }];
19750
+ if (row.type === "synthetic" && isStorageNoticeText(data.text))
19751
+ return [];
19752
+ if (["synthetic", "skill"].includes(row.type))
19753
+ return [make("user", [{ type: "text", text: data.text ?? "" }])];
19754
+ if (row.type === "location-switched")
19755
+ return [
19756
+ make("user", [
19757
+ {
19758
+ type: "text",
19759
+ text: `The working directory has been changed to ${data.location.directory}.`
19760
+ }
19761
+ ])
19762
+ ];
19763
+ if (row.type === "shell")
19764
+ return data.metadata?.background === true ? [] : [
19765
+ make("user", [
19766
+ {
19767
+ type: "text",
19768
+ text: `The following shell command was executed by the user:
19769
+
19770
+ Command:
19771
+ ${data.command}
19772
+
19773
+ Output:
19774
+ ${data.output?.output ?? ""}`
19775
+ }
19776
+ ])
19777
+ ];
19778
+ if (row.type !== "assistant")
19779
+ return [];
19780
+ const previousModel = data.model;
19781
+ const sameProvider = previousModel?.providerID === model.providerID;
19782
+ const sameModel = sameProvider && previousModel?.id === model.id;
19783
+ const reuse = sameModel && data.error === undefined;
19784
+ const metadata = (state) => state === undefined ? undefined : { [model.providerID]: state };
19785
+ const content = [];
19786
+ const results = [];
19787
+ for (const part of data.content ?? []) {
19788
+ if (part.type === "text") {
19789
+ if (part.text !== "")
19790
+ content.push({
19791
+ type: "text",
19792
+ text: part.text,
19793
+ providerMetadata: reuse ? metadata(part.state) : undefined
19794
+ });
19795
+ continue;
19796
+ }
19797
+ if (part.type === "reasoning") {
19798
+ if (part.text !== "" || reuse && part.state !== undefined)
19799
+ content.push({
19800
+ type: reuse || data.error === undefined ? "reasoning" : "text",
19801
+ text: part.text,
19802
+ providerMetadata: reuse ? metadata(part.state) : undefined
19803
+ });
19804
+ continue;
19805
+ }
19806
+ const state = part.state;
19807
+ const completed = state.status === "completed" || state.status === "error";
19808
+ const toolReuse = reuse || sameModel && part.executed === true && completed;
19809
+ let input = state.input;
19810
+ if (state.status === "streaming" && typeof input === "string") {
19811
+ try {
19812
+ input = JSON.parse(input);
19813
+ } catch {}
19814
+ }
19815
+ content.push({
19816
+ type: "tool-call",
19817
+ id: part.id,
19818
+ name: part.name,
19819
+ input,
19820
+ providerExecuted: part.executed,
19821
+ providerMetadata: toolReuse ? metadata(part.providerState) : undefined
19554
19822
  });
19555
- const tail = previous.then(() => gate);
19556
- roleTails.set(role, tail);
19557
- await previous;
19558
- return () => {
19559
- release();
19560
- if (roleTails.get(role) === tail)
19561
- roleTails.delete(role);
19823
+ if (!completed)
19824
+ continue;
19825
+ const toolContent = state.content ?? [];
19826
+ const single = toolContent.length === 1 ? toolContent[0] : undefined;
19827
+ const result = {
19828
+ type: "tool-result",
19829
+ id: part.id,
19830
+ name: part.name,
19831
+ providerExecuted: part.executed,
19832
+ providerMetadata: toolReuse ? metadata(part.providerResultState ?? part.providerState) : sameProvider ? metadata(part.providerResultState) : undefined,
19833
+ result: state.status === "error" ? { error: state.error, content: toolContent } : single?.type === "text" ? { type: "text", value: single.text } : { type: "content", value: toolContent },
19834
+ ...state.status === "error" ? { resultType: "error" } : {}
19562
19835
  };
19563
- };
19564
- const warnedVariants = new Set;
19565
- const validateVariant = async (model) => {
19566
- if (!model.variant || !options.modelCatalog)
19567
- return model;
19836
+ if (part.executed === true)
19837
+ content.push(result);
19838
+ else
19839
+ results.push({ role: "tool", content: [result] });
19840
+ }
19841
+ return [...content.length ? [make("assistant", content)] : [], ...results];
19842
+ }
19843
+
19844
+ // src/v2/fold/native-replay.ts
19845
+ var coordinates = new WeakMap;
19846
+ function nativeRowID(message) {
19847
+ return coordinates.get(message) ?? message.id;
19848
+ }
19849
+ function copyNativeInput(messages) {
19850
+ const copies = reviveNative(encodeNative(messages));
19851
+ copies.forEach((copy, i) => {
19852
+ const original = messages[i];
19853
+ const id = original && nativeRowID(original);
19854
+ if (id !== undefined)
19855
+ coordinates.set(copy, id);
19856
+ });
19857
+ return copies;
19858
+ }
19859
+ function isLocalCheckpoint(row) {
19860
+ return row.type === "compaction" && row.data.status === "completed" && row.data.providerContext === undefined;
19861
+ }
19862
+ var conversational = (row) => RAW_MESSAGE_TYPES.includes(row.type) || row.type === "location-switched";
19863
+
19864
+ class NativeFoldReplay {
19865
+ storage;
19866
+ openReader;
19867
+ changed = new Set;
19868
+ dirty = new Set;
19869
+ unavailable = new Set;
19870
+ metadata = new Map;
19871
+ metadataThrough = new Map;
19872
+ loaded = new Map;
19873
+ sources = new Map;
19874
+ constructor(storage, openReader) {
19875
+ this.storage = storage;
19876
+ this.openReader = openReader;
19877
+ storage.onEvict((sessionID) => this.clear(sessionID));
19878
+ }
19879
+ account(sessionID) {
19880
+ const source = this.sources.get(sessionID);
19881
+ let bytes = 256 + (source?.length ?? 0) * 2;
19882
+ for (const row of this.metadata.get(sessionID) ?? [])
19883
+ bytes += 128 + (row.id.length + row.type.length) * 2;
19884
+ this.storage.accountReplay(sessionID, bytes);
19885
+ }
19886
+ async observeSource(sessionID, reader) {
19887
+ const source = reader.hostIdentity();
19888
+ const prior = this.sources.get(sessionID);
19889
+ if (prior && prior !== source)
19890
+ await this.forget(sessionID);
19891
+ this.sources.set(sessionID, source);
19892
+ this.account(sessionID);
19893
+ }
19894
+ onEvent(event) {
19895
+ const sessionID = event.data?.sessionID;
19896
+ if (sessionID && (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated"))
19897
+ this.invalidate(sessionID);
19898
+ }
19899
+ invalidate(sessionID, suppressNomination = false) {
19900
+ if (suppressNomination)
19901
+ this.unavailable.add(sessionID);
19902
+ this.dirty.add(sessionID);
19903
+ this.changed.add(sessionID);
19904
+ this.metadata.delete(sessionID);
19905
+ this.metadataThrough.delete(sessionID);
19906
+ this.account(sessionID);
19907
+ }
19908
+ tail(sessionID) {
19909
+ const record = this.storage.tail(sessionID);
19910
+ return record ? JSON.parse(record.data) : undefined;
19911
+ }
19912
+ async baseline(sessionID) {
19913
+ return this.tail(sessionID)?.baseline;
19914
+ }
19915
+ rendered(row, model) {
19916
+ return restoreRow(row, model, hostUsesMediaAssets() ? {
19917
+ asset: hostMediaAsset,
19918
+ unavailable: () => {}
19919
+ } : undefined);
19920
+ }
19921
+ record(row, messages) {
19922
+ const data = JSON.stringify(encodeNative(messages));
19923
+ return { id: row.id, type: row.type, seq: row.seq, data, digest: foldDigest(data) };
19924
+ }
19925
+ records(sessionID, native, reader) {
19926
+ let metadata = this.metadata.get(sessionID);
19927
+ const through = reader.latestSequence(sessionID);
19928
+ const known = new Set(metadata?.map((row) => row.id));
19929
+ if (!metadata || (this.metadataThrough.get(sessionID) ?? -1) < through || native.some((message) => message.id && !known.has(message.id))) {
19930
+ metadata = reader.rowStampsThrough(sessionID, through).filter(conversational);
19931
+ this.metadata.set(sessionID, metadata);
19932
+ this.metadataThrough.set(sessionID, through);
19933
+ }
19934
+ const byID = new Map(metadata.map((row) => [row.id, row]));
19935
+ const grouped = new Map;
19936
+ const anchorIndex = native.findIndex((message) => {
19937
+ const id = nativeRowID(message);
19938
+ return id !== undefined && byID.has(id);
19939
+ });
19940
+ const leading = native.slice(0, anchorIndex < 0 ? native.length : anchorIndex).filter((message) => !nativeRowID(message) && message.role === "system");
19941
+ const anchorMessage = native[anchorIndex];
19942
+ const anchorID = anchorMessage && nativeRowID(anchorMessage);
19943
+ const anchor = anchorID ? byID.get(anchorID) : undefined;
19944
+ const leadingRows = anchor ? metadata.filter((row) => row.type === "system" && row.seq < anchor.seq).slice(-leading.length) : [];
19945
+ const leadingIDs = new Map(leading.map((message, i) => [message, leadingRows[i]?.id]));
19946
+ let cursor = -1;
19947
+ let owner;
19948
+ for (const message of native) {
19949
+ let id = nativeRowID(message);
19950
+ if (!id && message.role === "system") {
19951
+ if (leadingIDs.has(message)) {
19952
+ id = leadingIDs.get(message);
19953
+ if (!id)
19954
+ continue;
19955
+ } else
19956
+ id = metadata.find((row) => row.type === "system" && row.seq > cursor)?.id;
19957
+ }
19958
+ if (!id && message.role === "tool")
19959
+ id = owner;
19960
+ const row = id ? byID.get(id) : undefined;
19961
+ if (!row)
19962
+ throw new NativeReplayUnavailable("Native carrier has no source row coordinate");
19963
+ cursor = row.seq;
19964
+ coordinates.set(message, row.id);
19965
+ if (message.role !== "tool")
19966
+ owner = row.id;
19967
+ const messages = grouped.get(row) ?? [];
19968
+ messages.push(message);
19969
+ grouped.set(row, messages);
19970
+ }
19971
+ return [...grouped].map(([row, messages]) => this.record(row, messages));
19972
+ }
19973
+ async capture(draft, native) {
19974
+ const release = this.storage.hold(draft.sessionID);
19568
19975
  try {
19569
- const listed = await options.modelCatalog();
19570
- const rows = Array.isArray(listed) ? listed : listed && typeof listed === "object" && Array.isArray(listed.data) ? listed.data : [];
19571
- const entry = rows.find((row) => row && typeof row === "object" && row.providerID === model.providerID && row.id === model.modelID);
19572
- if (!entry)
19573
- return model;
19574
- if (entry.variants && typeof entry.variants === "object" && Object.hasOwn(entry.variants, model.variant))
19575
- return model;
19576
- const key = `${model.providerID}/${model.modelID}:${model.variant}`;
19577
- if (!warnedVariants.has(key)) {
19578
- warnedVariants.add(key);
19579
- note(`[magic-context] ${recordHiddenVariantWarning(model.providerID, model.modelID, model.variant)}`);
19976
+ rememberHostMedia(native);
19977
+ const reader = this.openReader(draft.sessionID);
19978
+ try {
19979
+ const rows = this.records(draft.sessionID, native, reader);
19980
+ const baseline = draft.messages.find((message) => message.id === HEAD_IDS[0])?.content.find((part) => part.type === "text")?.text;
19981
+ const through = Math.max(-1, ...rows.map((row) => row.seq));
19982
+ const tail = {
19983
+ model: `${draft.model.providerID}/${draft.model.id}`,
19984
+ sourceSeq: through,
19985
+ baseline: typeof baseline === "string" ? baseline : this.tail(draft.sessionID)?.baseline
19986
+ };
19987
+ await this.storage.saveTail(draft.sessionID, JSON.stringify(tail), rows);
19988
+ this.storage.truncate(draft.sessionID, through);
19989
+ this.loaded.set(draft.sessionID, through);
19990
+ this.unavailable.delete(draft.sessionID);
19991
+ this.changed.delete(draft.sessionID);
19992
+ } finally {
19993
+ reader.close();
19580
19994
  }
19581
- return { providerID: model.providerID, modelID: model.modelID };
19582
19995
  } catch {
19583
- return model;
19584
- }
19585
- };
19586
- const resolveHead = async (identity) => {
19587
- const configured = configuredHead(identity);
19588
- if (configured)
19589
- return validateVariant(configured);
19590
- if (!identity.parentSessionId) {
19591
- throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion requires a configured model or an existing parent session model", true);
19996
+ this.unavailable.add(draft.sessionID);
19997
+ this.invalidate(draft.sessionID);
19998
+ } finally {
19999
+ this.account(draft.sessionID);
20000
+ release();
19592
20001
  }
19593
- const parent = await host.get({ sessionID: identity.parentSessionId });
19594
- if (!parent.model) {
19595
- throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion could not resolve the parent session model", true);
20002
+ }
20003
+ async canReplay(sessionID, _reader) {
20004
+ return !this.unavailable.has(sessionID) && typeof await this.baseline(sessionID) === "string";
20005
+ }
20006
+ async supply(args) {
20007
+ const release = this.storage.hold(args.draft.sessionID);
20008
+ try {
20009
+ return await this.supplyHeld(args);
20010
+ } finally {
20011
+ this.account(args.draft.sessionID);
20012
+ release();
19596
20013
  }
19597
- return {
19598
- providerID: parent.model.providerID,
19599
- modelID: parent.model.id,
19600
- ...parent.model.variant ? { variant: parent.model.variant } : {}
20014
+ }
20015
+ async supplyHeld(args) {
20016
+ const { draft, reader, summary } = args;
20017
+ const tail = this.tail(draft.sessionID);
20018
+ const id = reader.latestRunningCompaction(draft.sessionID)?.id;
20019
+ if (!id || !tail || tail.model !== `${draft.model.providerID}/${draft.model.id}`)
20020
+ return false;
20021
+ const through = reader.latestSequence(draft.sessionID);
20022
+ const after = this.dirty.has(draft.sessionID) ? -1 : tail.sourceSeq;
20023
+ const fresh = reader.range(draft.sessionID, after, through).filter(conversational);
20024
+ const records = fresh.map((row) => this.record(row, this.rendered(row, draft.model)));
20025
+ if (this.dirty.has(draft.sessionID))
20026
+ this.storage.replaceRows(draft.sessionID, through, records);
20027
+ await this.storage.saveTail(draft.sessionID, JSON.stringify({
20028
+ ...tail,
20029
+ sourceSeq: Math.max(tail.sourceSeq, ...fresh.map((row) => row.seq))
20030
+ }), records);
20031
+ this.dirty.delete(draft.sessionID);
20032
+ this.metadata.delete(draft.sessionID);
20033
+ this.metadataThrough.delete(draft.sessionID);
20034
+ this.loaded.set(draft.sessionID, through);
20035
+ const snapshot = {
20036
+ source: this.storage.sourceID,
20037
+ sessionID: draft.sessionID,
20038
+ admissionID: id,
20039
+ summary
19601
20040
  };
19602
- };
19603
- const switchChildModel = async (run, requested) => {
19604
- if (sameModel(run.child.model, requested))
20041
+ await this.storage.supply(draft.sessionID, id, JSON.stringify(snapshot));
20042
+ return true;
20043
+ }
20044
+ async restore(sessionID, cut, model, options = {}) {
20045
+ const release = this.storage.hold(sessionID);
20046
+ try {
20047
+ return await this.restoreHeld(sessionID, cut, model, options);
20048
+ } finally {
20049
+ this.account(sessionID);
20050
+ release();
20051
+ }
20052
+ }
20053
+ async restoreHeld(sessionID, cut, model, options) {
20054
+ if (!isLocalCheckpoint(cut))
19605
20055
  return;
19606
- await host.switchModel({
19607
- sessionID: run.child.id,
19608
- model: {
19609
- providerID: requested.providerID,
19610
- id: requested.modelID,
19611
- ...requested.variant ? { variant: requested.variant } : {}
20056
+ const resolvedModel = {
20057
+ providerID: model.slice(0, model.indexOf("/")),
20058
+ id: model.slice(model.indexOf("/") + 1)
20059
+ };
20060
+ const tail = this.tail(sessionID);
20061
+ if (tail && tail.model !== model)
20062
+ this.invalidate(sessionID);
20063
+ let after = options.after ?? -1;
20064
+ if (options.bounded && options.after === undefined && !this.changed.has(sessionID)) {
20065
+ const state = getOrCreateSessionMeta(this.storage.db, sessionID);
20066
+ const max = this.storage.db.prepare("SELECT COALESCE(MAX(id),0) AS id FROM m0_mutation_log WHERE session_id=?").get(sessionID);
20067
+ const boundary = this.storage.db.prepare("SELECT cached_m0_last_baseline_end_message_id AS id FROM session_meta WHERE session_id=?").get(sessionID)?.id;
20068
+ if (max.id <= (state.cachedM0MaxMutationId ?? 0) && boundary)
20069
+ after = this.storage.sequenceForID(sessionID, boundary) ?? -1;
20070
+ }
20071
+ const through = cut.seq - 1;
20072
+ let reader;
20073
+ try {
20074
+ let metadata = this.metadata.get(sessionID);
20075
+ if (!metadata || (this.metadataThrough.get(sessionID) ?? -1) < through) {
20076
+ reader = this.openReader(sessionID);
20077
+ metadata = reader.rowStampsThrough(sessionID, through).filter(conversational);
20078
+ this.metadata.set(sessionID, metadata);
20079
+ this.metadataThrough.set(sessionID, through);
20080
+ }
20081
+ const required = metadata.filter((row) => row.seq > after && row.seq <= through);
20082
+ if (this.dirty.has(sessionID) || !tail || (this.loaded.get(sessionID) ?? -1) < through && !this.storage.admission(sessionID, cut.id) || !this.storage.containsRows(sessionID, required.map((row) => row.id))) {
20083
+ reader ??= this.openReader(sessionID);
20084
+ const fresh = reader.range(sessionID, after, through).filter(conversational);
20085
+ const records = fresh.map((row) => this.record(row, this.rendered(row, resolvedModel)));
20086
+ const restored = new Set(records.map((row) => row.id));
20087
+ if (required.some((row) => !restored.has(row.id)))
20088
+ throw new NativeReplayUnavailable("Host restore omitted a required source row");
20089
+ this.storage.replaceRows(sessionID, through, records, after);
20090
+ await this.storage.saveTail(sessionID, JSON.stringify({
20091
+ model,
20092
+ sourceSeq: through,
20093
+ baseline: tail?.baseline ?? cut.data.summary
20094
+ }), []);
20095
+ this.loaded.set(sessionID, through);
20096
+ this.dirty.delete(sessionID);
19612
20097
  }
19613
- });
19614
- run.child = lifecycle.updateModel(run.child, requested);
19615
- };
19616
- const retire = (run, reason) => {
19617
- if (run.retired)
19618
- return;
19619
- lifecycle.retire(run.child, reason);
19620
- run.retired = true;
19621
- };
19622
- const interruptAndRetire = async (run, reason) => {
20098
+ } finally {
20099
+ reader?.close();
20100
+ }
20101
+ const messages = [];
20102
+ for (const row of this.storage.rows(sessionID, after, cut.seq - 1)) {
20103
+ const revived = reviveNative(JSON.parse(row.data));
20104
+ for (const message of revived)
20105
+ coordinates.set(message, row.id);
20106
+ messages.push(...revived);
20107
+ }
20108
+ return messages;
20109
+ }
20110
+ async restoreRead(sessionID, cut, model) {
20111
+ const reader = this.openReader(sessionID);
19623
20112
  try {
19624
- await host.interrupt({ sessionID: run.child.id });
20113
+ return reader.range(sessionID, -1, cut.seq - 1).filter(conversational).flatMap((row) => {
20114
+ const messages = this.rendered(row, model);
20115
+ for (const message of messages)
20116
+ coordinates.set(message, row.id);
20117
+ return messages;
20118
+ });
19625
20119
  } finally {
19626
- retire(run, reason);
20120
+ reader.close();
19627
20121
  }
19628
- };
19629
- return {
19630
- capabilities: V2_HIDDEN_EXECUTOR_CAPABILITIES,
19631
- async open(identity) {
19632
- const role = roleFor(identity);
19633
- const releaseRole = await acquireRole(role);
19634
- let openedChild;
20122
+ }
20123
+ sourceChanged(sessionID) {
20124
+ return this.changed.has(sessionID);
20125
+ }
20126
+ clear(sessionID) {
20127
+ this.sources.delete(sessionID);
20128
+ this.metadata.delete(sessionID);
20129
+ this.metadataThrough.delete(sessionID);
20130
+ this.loaded.delete(sessionID);
20131
+ this.unavailable.delete(sessionID);
20132
+ this.dirty.delete(sessionID);
20133
+ this.changed.delete(sessionID);
20134
+ }
20135
+ async forget(sessionID) {
20136
+ await this.storage.forget(sessionID);
20137
+ }
20138
+ }
20139
+
20140
+ // src/v2/fold/policy.ts
20141
+ import { randomUUID as randomUUID3 } from "node:crypto";
20142
+ class HostFoldPolicy {
20143
+ deps;
20144
+ active = new Set;
20145
+ owner = randomUUID3();
20146
+ constructor(deps) {
20147
+ this.deps = deps;
20148
+ }
20149
+ owned(sessionID, cut, id) {
20150
+ const row = this.deps.storage.admission(sessionID, id);
20151
+ if (!isLocalCheckpoint(cut) || cut.id !== id || !row?.payload || row.digest !== foldDigest(row.payload))
20152
+ return false;
20153
+ const snapshot = JSON.parse(row.payload);
20154
+ return snapshot.summary === cut.data.summary && snapshot.source === this.deps.storage.sourceID && snapshot.sessionID === sessionID && snapshot.admissionID === id;
20155
+ }
20156
+ async idle(sessionID) {
20157
+ const { storage, session, threshold } = this.deps;
20158
+ if (!Number.isSafeInteger(threshold) || threshold <= 0 || typeof session.compact !== "function" || this.active.has(sessionID))
20159
+ return;
20160
+ this.active.add(sessionID);
20161
+ const now = this.deps.now ?? Date.now;
20162
+ let attempt;
20163
+ let claimed = false;
20164
+ try {
20165
+ const reader = this.deps.openReader();
19635
20166
  try {
19636
- await options.ensureAgent?.();
19637
- const head = await resolveHead(identity);
19638
- const active = await lifecycle.open(identity, role, head);
19639
- openedChild = active;
19640
- const handle = { id: active.id, childSessionId: active.id };
19641
- const run = {
19642
- identity,
19643
- role,
19644
- child: active,
19645
- releaseRole,
19646
- failed: false,
19647
- unsettledFailure: false,
19648
- retired: false
19649
- };
19650
- runs.set(handle, run);
19651
- await switchChildModel(run, head);
19652
- return handle;
19653
- } catch (error) {
19654
- if (openedChild)
19655
- lifecycle.retire(openedChild, "hidden-run-open-failed");
19656
- releaseRole();
19657
- throw error;
19658
- }
19659
- },
19660
- async attempt(handle, request) {
19661
- const run = runs.get(handle);
19662
- if (!run)
19663
- throw new Error("Unknown hidden completion run");
19664
- if (request.signal?.aborted) {
19665
- await interruptAndRetire(run, "aborted-before-prompt");
19666
- throw new Error("Hidden completion prompt aborted");
19667
- }
19668
- const requested = await validateVariant(requestModel(request, run.child.model));
19669
- if (run.retired) {
19670
- run.child = await lifecycle.create(run.identity, run.role, requested);
19671
- run.failed = false;
19672
- run.unsettledFailure = false;
19673
- run.retired = false;
19674
- handle.id = run.child.id;
19675
- handle.childSessionId = run.child.id;
19676
- }
19677
- await switchChildModel(run, requested);
19678
- const baseline = withReader(options.openReader, (reader) => reader.latestSequence(run.child.id));
19679
- const marker = `mc:hidden:${crypto.randomUUID()}:${crypto.randomUUID()}`;
19680
- run.completion = undefined;
19681
- const stepCap = options.resolveStepCap?.(run.identity);
19682
- const attempt = {
19683
- childSessionId: run.child.id,
19684
- identity: run.identity,
19685
- agent: run.identity.agent,
19686
- request,
19687
- shaped: false,
19688
- ...stepCap === undefined ? {} : { stepCap }
19689
- };
19690
- options.hook.registerAttempt(marker, attempt);
19691
- const deadline = Date.now() + run.identity.timeoutMs;
19692
- let abortReject;
19693
- const aborted = new Promise((_resolve, reject) => {
19694
- abortReject = reject;
19695
- });
19696
- const onAbort = () => {
19697
- interruptAndRetire(run, "prompt-aborted").finally(() => abortReject(new Error("Hidden completion prompt aborted")));
19698
- };
19699
- const deadlineTimer = setTimeout(() => {
19700
- interruptAndRetire(run, "prompt-timeout").finally(() => abortReject(new Error("Hidden completion prompt timed out")));
19701
- }, Math.max(0, deadline - Date.now()));
19702
- request.signal?.addEventListener("abort", onAbort, { once: true });
19703
- try {
19704
- await Promise.race([
19705
- host.prompt({ sessionID: run.child.id, text: marker }),
19706
- aborted
19707
- ]);
19708
- await Promise.race([host.wait({ sessionID: run.child.id }), aborted]);
19709
- const row = await Promise.race([
19710
- awaitAssistantRow(options.openReader, async () => {
19711
- try {
19712
- const eventError = await host.terminalError?.({
19713
- sessionID: run.child.id
19714
- });
19715
- if (eventError !== undefined)
19716
- return eventError;
19717
- return (await host.get({ sessionID: run.child.id })).error;
19718
- } catch {
19719
- return;
19720
- }
19721
- }, () => attempt.refusal ?? attempt.stepLimit, run.child.id, baseline, deadline, request.signal),
19722
- aborted
19723
- ]);
19724
- if (!attempt.shaped) {
19725
- throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Host did not dispatch the hidden child context hook", true);
19726
- }
19727
- const text = assistantText(row);
19728
- const system = typeof request.body.system === "string" ? request.body.system : run.identity.system;
19729
- const tokens = row.data.tokens;
19730
- const tokenNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
19731
- const reportedInput = tokenNumber(tokens?.input);
19732
- const reportedOutput = tokenNumber(tokens?.output);
19733
- if (request.signal?.aborted || run.retired || Date.now() >= deadline) {
19734
- await interruptAndRetire(run, "prompt-aborted-or-timeout");
19735
- throw new Error(request.signal?.aborted ? "Hidden completion prompt aborted" : "Hidden completion prompt timed out");
20167
+ const cut = reader.latestCompaction(sessionID);
20168
+ const previous = storage.latestAttempt(sessionID);
20169
+ const old = previous ? JSON.parse(previous.data) : undefined;
20170
+ if (cut && previous?.status === "pending" && old && this.owned(sessionID, cut, old.id)) {
20171
+ if (await storage.claim(sessionID, old.id, previous.data, this.owner, now()) && await storage.finish(sessionID, old.id, this.owner, "completed", now()))
20172
+ this.deps.log(sessionID, `v2 host fold: rows_before=${old.before} rows_after=${reader.storedRowsAfter(sessionID, cut.seq)} duration_ms=${now() - old.started} reason=row_threshold id=${cut.id} status=completed`);
20173
+ return;
19736
20174
  }
19737
- run.completion = {
19738
- text,
19739
- tokenLog: runTokenLog(tokens, run.identity.maxOutputTokens, row.data.finish),
19740
- reasoning: text ? null : assistantReasoning(row),
19741
- usage: reportedInput !== undefined || reportedOutput !== undefined ? {
19742
- input: reportedInput ?? 0,
19743
- output: reportedOutput ?? 0,
19744
- cacheRead: tokenNumber(tokens?.cache?.read) ?? 0,
19745
- cacheWrite: tokenNumber(tokens?.cache?.write) ?? 0
19746
- } : meter(system, promptText(request), text ?? ""),
19747
- lengthCapped: ["length", "max_tokens"].includes(row.data.finish ?? ""),
19748
- providerId: row.data.model?.providerID ?? requested.providerID,
19749
- modelId: row.data.model?.id ?? requested.modelID,
19750
- ...attempt.steps === undefined ? {} : { steps: attempt.steps }
20175
+ const after = cut?.seq ?? -1;
20176
+ const before = reader.storedRowsAfter(sessionID, after);
20177
+ if (before < threshold || !await this.deps.canReplay(sessionID, reader))
20178
+ return;
20179
+ const retry = old?.after === after ? old.attempt + (previous?.status === "failed" || previous?.status === "coalesced" ? 1 : 0) : 0;
20180
+ const id = old?.after === after && previous?.status === "pending" ? old.id : `msg_mc_fold_${foldDigest(`${storage.sourceID}/${sessionID}/${after}/${retry}`).slice(0, 24)}`;
20181
+ attempt = {
20182
+ after,
20183
+ before,
20184
+ watermark: reader.latestSequence(sessionID),
20185
+ attempt: retry,
20186
+ id,
20187
+ started: now()
19751
20188
  };
19752
- if (!run.child.ever_settled)
19753
- run.child = lifecycle.markEverSettled(run.child);
19754
- } catch (caught) {
19755
- const error = attempt.stepLimit ?? attempt.refusal ?? caught;
19756
- run.failed = true;
19757
- if (!(error instanceof HiddenProviderError)) {
19758
- run.unsettledFailure = true;
19759
- }
19760
- if (request.signal?.aborted && !run.retired) {
19761
- await interruptAndRetire(run, "prompt-aborted");
19762
- } else if (error instanceof Error && error.message.includes("timed out") && !run.retired) {
19763
- await interruptAndRetire(run, "prompt-timeout");
19764
- } else if ((error instanceof HiddenAgentStepLimit || error instanceof HiddenProviderError && error.settled) && !run.retired) {
19765
- await interruptAndRetire(run, error instanceof HiddenAgentStepLimit ? "hidden-run-step-limit" : "hidden-run-provider-error");
19766
- }
19767
- throw error;
20189
+ claimed = await storage.claim(sessionID, id, JSON.stringify(attempt), this.owner, now());
20190
+ if (!claimed)
20191
+ return;
19768
20192
  } finally {
19769
- clearTimeout(deadlineTimer);
19770
- request.signal?.removeEventListener("abort", onAbort);
19771
- options.hook.releaseAttempt(marker);
20193
+ reader.close();
19772
20194
  }
19773
- },
19774
- async collect(handle) {
19775
- const completion = runs.get(handle)?.completion;
19776
- if (!completion)
19777
- throw new Error("Hidden completion has no settled output");
19778
- return completion;
19779
- },
19780
- async close(handle, settlement) {
19781
- if (!handle)
19782
- return;
19783
- const run = runs.get(handle);
19784
- if (!run)
19785
- return;
20195
+ const admitted = await session.compact({
20196
+ sessionID,
20197
+ id: attempt.id,
20198
+ delivery: "queue"
20199
+ });
20200
+ await session.wait({ sessionID });
20201
+ const settled = this.deps.openReader();
19786
20202
  try {
19787
- const reusable = !run.retired && run.failed && !run.unsettledFailure;
19788
- if (!run.completion && (run.failed || !settlement.promptSettled) && !reusable) {
19789
- retire(run, "hidden-run-failed");
20203
+ const cut = settled.latestCompaction(sessionID);
20204
+ if (admitted?.id !== attempt.id || !cut || cut.seq <= attempt.after || !this.owned(sessionID, cut, attempt.id)) {
20205
+ if (await storage.finish(sessionID, attempt.id, this.owner, "coalesced", now()))
20206
+ this.deps.log(sessionID, `v2 host fold: rows_before=${attempt.before} rows_after=unknown duration_ms=${now() - attempt.started} reason=row_threshold id=${attempt.id} actual_id=${cut?.id ?? admitted?.id ?? "unknown"} status=coalesced`);
20207
+ return;
19790
20208
  }
20209
+ const after = settled.storedRowsAfter(sessionID, cut.seq);
20210
+ if (await storage.finish(sessionID, attempt.id, this.owner, "completed", now()))
20211
+ this.deps.log(sessionID, `v2 host fold: rows_before=${attempt.before} rows_after=${after} duration_ms=${now() - attempt.started} reason=row_threshold id=${cut.id} status=completed`);
19791
20212
  } finally {
19792
- runs.delete(handle);
19793
- run.releaseRole();
20213
+ settled.close();
19794
20214
  }
19795
- await lifecycle.finish(run.child, run.retired);
20215
+ } catch (error) {
20216
+ if (claimed && attempt) {
20217
+ let finished = false;
20218
+ try {
20219
+ finished = await storage.finish(sessionID, attempt.id, this.owner, "failed", now());
20220
+ } catch {
20221
+ finished = true;
20222
+ }
20223
+ if (finished)
20224
+ this.deps.log(sessionID, `v2 host fold: rows_before=${attempt.before} rows_after=unknown duration_ms=${now() - attempt.started} reason=row_threshold id=${attempt.id} status=failed error=${JSON.stringify(String(error))}`);
20225
+ } else
20226
+ this.deps.log(sessionID, `v2 host fold: rows_before=unknown rows_after=unknown duration_ms=0 reason=row_threshold status=failed error=${JSON.stringify(String(error))} cache_error=${JSON.stringify(String(error))}`);
20227
+ } finally {
20228
+ this.active.delete(sessionID);
19796
20229
  }
19797
- };
19798
- }
19799
-
19800
- // src/v2/hooks/channel2.ts
19801
- import { randomBytes as randomBytes2 } from "node:crypto";
19802
- var pendingCandidates = new WeakMap;
19803
- function syntheticCandidates(context, sessionID, stored) {
19804
- const pending = pendingCandidates.get(context.storage);
19805
- for (const [key, id] of pending ?? []) {
19806
- if (!key.startsWith(`${sessionID}/`))
19807
- continue;
19808
- if (stored.has(id))
19809
- pending?.delete(key);
19810
- else
19811
- stored.add(id);
19812
20230
  }
19813
- return stored;
19814
20231
  }
19815
- function clearSyntheticCandidates(context) {
19816
- pendingCandidates.delete(context.storage);
20232
+
20233
+ // src/v2/fork-inheritance.ts
20234
+ var RAW_TYPES = new Set(RAW_MESSAGE_TYPES);
20235
+ function forkBoundarySeq(origin, sequenceForId) {
20236
+ const seq = sequenceForId(origin.parentSessionID, origin.boundary.messageID);
20237
+ if (seq === undefined)
20238
+ return;
20239
+ return origin.boundary.type === "before" ? seq - 1 : seq;
19817
20240
  }
19818
- async function deliverSynthetic(context, sessionID, text) {
19819
- const id = `msg_${randomBytes2(12).toString("hex")}`;
19820
- await context.storage.set(`synthetic/${sessionID}/${id}`, { id });
19821
- let candidates = pendingCandidates.get(context.storage);
19822
- if (!candidates) {
19823
- candidates = new Map;
19824
- pendingCandidates.set(context.storage, candidates);
20241
+ function buildForkIdMap(parentRows, forkRows, throughSeq) {
20242
+ const parentBySeq = new Map;
20243
+ for (const row of parentRows)
20244
+ if (row.seq <= throughSeq)
20245
+ parentBySeq.set(row.seq, row);
20246
+ const parentToFork = new Map;
20247
+ const forkOrdinals = new Map;
20248
+ let ordinal = 0;
20249
+ for (const row of forkRows) {
20250
+ if (row.seq > throughSeq)
20251
+ break;
20252
+ if (RAW_TYPES.has(row.type)) {
20253
+ ordinal += 1;
20254
+ forkOrdinals.set(row.id, ordinal);
20255
+ }
20256
+ const parent = parentBySeq.get(row.seq);
20257
+ if (parent && parent.type === row.type && parent.time_created === row.time_created && row.id !== parent.id && row.id.endsWith(`_${row.seq}`)) {
20258
+ parentToFork.set(parent.id, row.id);
20259
+ }
19825
20260
  }
19826
- candidates.set(`${sessionID}/${id}`, id);
19827
- await context.session.synthetic({ sessionID, id, text, delivery: "steer" });
19828
- return id;
19829
- }
19830
- async function isAdmittedSynthetic(context, sessionID, id) {
19831
- const record = await context.storage.get(`synthetic/${sessionID}/${id}`);
19832
- return record !== null && typeof record === "object" && "id" in record && record.id === id;
19833
- }
19834
- async function deliverPendingChannel2(context, db, sessionID, baseline) {
19835
- if (getChannel2NudgeState(db, sessionID) !== "pending")
19836
- return;
19837
- const evaluation = evaluateChannel2(baseline);
19838
- if (!evaluation.evaluable || !evaluation.shouldTrigger)
19839
- return;
19840
- const token = randomBytes2(16).toString("hex");
19841
- if (!claimChannel2NudgeState(db, sessionID, token))
19842
- return;
19843
- try {
19844
- await deliverSynthetic(context, sessionID, buildChannel2Reminder(evaluation.reclaimableTokens, reclaimableToolOutputCount(baseline?.baselineParts ?? [])));
19845
- } catch (error) {
19846
- casChannel2NudgeClaim(db, sessionID, "pending", token);
19847
- throw error;
20261
+ const parentOrdinals = new Map;
20262
+ let parentOrdinal = 0;
20263
+ for (const row of parentRows) {
20264
+ if (row.seq > throughSeq)
20265
+ break;
20266
+ if (!RAW_TYPES.has(row.type))
20267
+ continue;
20268
+ parentOrdinal += 1;
20269
+ parentOrdinals.set(parentOrdinal, row.id);
19848
20270
  }
19849
- casChannel2NudgeClaim(db, sessionID, "delivered", token);
20271
+ return { parentToFork, forkOrdinals, parentOrdinals, throughSeq };
19850
20272
  }
19851
-
19852
- // src/v2/hooks/commands.ts
19853
- async function registerV2Commands(args) {
19854
- const domain = args.command;
19855
- if (!domain || typeof domain.transform !== "function") {
19856
- log("[magic-context] v2 host exposes no command domain; /mmc-* commands are TUI-only");
19857
- return false;
19858
- }
19859
- const descriptions = getMagicContextBuiltinCommands(args.compactionEnabled);
19860
- const commands = buildV2Commands(args.rpc, args.directory);
19861
- try {
19862
- await domain.transform((editor) => {
19863
- for (const command of commands) {
19864
- editor.add({
19865
- name: command.name,
19866
- description: descriptions[command.name].description,
19867
- execute: command.execute
19868
- });
20273
+ var CONTENT_ID_SUFFIX = /(:(?:p|file)\d+)$/;
20274
+ var BLOCK_ID_SUFFIX = /(#\d+)$/;
20275
+ function splitMessageScopedId(id) {
20276
+ const match = id.match(CONTENT_ID_SUFFIX) ?? id.match(BLOCK_ID_SUFFIX);
20277
+ if (!match?.[1])
20278
+ return { messageId: id, suffix: "" };
20279
+ return { messageId: id.slice(0, -match[1].length), suffix: match[1] };
20280
+ }
20281
+ function forkCloneFilter(idMap, copiedToolCallIds) {
20282
+ const mapMessageScoped = (id) => {
20283
+ const direct = idMap.parentToFork.get(id);
20284
+ if (direct)
20285
+ return direct;
20286
+ const { messageId, suffix } = splitMessageScopedId(id);
20287
+ if (!suffix)
20288
+ return;
20289
+ const mapped = idMap.parentToFork.get(messageId);
20290
+ return mapped ? `${mapped}${suffix}` : undefined;
20291
+ };
20292
+ return {
20293
+ resolveBoundaryOrdinal: (messageId) => {
20294
+ const forkId = idMap.parentToFork.get(messageId);
20295
+ return forkId ? idMap.forkOrdinals.get(forkId) : undefined;
20296
+ },
20297
+ includeMessageId: (messageId) => mapMessageScoped(messageId) !== undefined || copiedToolCallIds.has(messageId),
20298
+ mapMessageId: (messageId) => mapMessageScoped(messageId) ?? messageId,
20299
+ includeTag: (tag) => {
20300
+ if (tag.type === "tool") {
20301
+ return tag.toolOwnerMessageId !== null && idMap.parentToFork.has(tag.toolOwnerMessageId);
19869
20302
  }
19870
- });
19871
- } catch (error) {
19872
- log("[magic-context] v2 command registration failed", error);
19873
- return false;
19874
- }
19875
- log(`[magic-context] registered server-side commands: ${commands.map((command) => command.name).join(" ")}`);
19876
- return true;
20303
+ return mapMessageScoped(tag.messageId) !== undefined;
20304
+ },
20305
+ mapOrdinal: (sourceOrdinal) => {
20306
+ const parentId = idMap.parentOrdinals.get(sourceOrdinal);
20307
+ const forkId = parentId ? idMap.parentToFork.get(parentId) : undefined;
20308
+ return forkId ? idMap.forkOrdinals.get(forkId) : undefined;
20309
+ },
20310
+ copySessionNotesAndFacts: true,
20311
+ selectPendingPiMarker: () => null
20312
+ };
19877
20313
  }
19878
- function commandArgument(input, name) {
19879
- const raw = typeof input.prompt?.text === "string" ? input.prompt.text.trim() : "";
19880
- const prefix = `/${name}`;
19881
- if (raw === prefix)
19882
- return "";
19883
- if (raw.startsWith(`${prefix} `))
19884
- return raw.slice(prefix.length).trim();
19885
- return raw;
20314
+ function countSessionRows(db, table, sessionId) {
20315
+ const row = db.prepare(`SELECT COUNT(*) AS count FROM ${table} WHERE session_id = ?`).get(sessionId);
20316
+ return typeof row?.count === "number" ? row.count : 0;
19886
20317
  }
19887
- function reportResult(sessionID, title, message) {
19888
- pushNotification2("action", { action: "show-result-dialog", title, message }, sessionID);
20318
+ function sessionHasMagicContextState(db, sessionId) {
20319
+ return countSessionRows(db, "compartments", sessionId) > 0 || countSessionRows(db, "tags", sessionId) > 0;
19889
20320
  }
19890
- function reportUsage(sessionID, message) {
19891
- pushNotification2("toast", { message, variant: "warning" }, sessionID);
20321
+ function seedV2ForkFromParent(args) {
20322
+ const { db, store, sessionId } = args;
20323
+ if (sessionHasMagicContextState(db, sessionId))
20324
+ return { kind: "has-state" };
20325
+ const origin = store.forkOrigin(sessionId);
20326
+ if (!origin)
20327
+ return { kind: "not-a-fork" };
20328
+ const parentSessionID = origin.parentSessionID;
20329
+ if (parentSessionID === sessionId)
20330
+ return { kind: "not-a-fork" };
20331
+ if (!sessionHasMagicContextState(db, parentSessionID))
20332
+ return { kind: "parent-missing", parentSessionID, reason: "no Magic Context state" };
20333
+ if (!store.sessionExists(parentSessionID))
20334
+ return { kind: "parent-missing", parentSessionID, reason: "no host session row" };
20335
+ const throughSeq = forkBoundarySeq(origin, (session, id) => store.sequenceForId(session, id));
20336
+ if (throughSeq === undefined)
20337
+ return { kind: "parent-missing", parentSessionID, reason: "boundary row not in the store" };
20338
+ const idMap = buildForkIdMap(store.rowStampsThrough(parentSessionID, throughSeq), store.rowStampsThrough(sessionId, throughSeq), throughSeq);
20339
+ if (idMap.parentToFork.size === 0)
20340
+ return { kind: "parent-missing", parentSessionID, reason: "no copied rows pair up" };
20341
+ const toolTags = db.prepare("SELECT message_id, tool_owner_message_id FROM tags WHERE session_id = ? AND type = 'tool'").all(parentSessionID);
20342
+ const copiedToolCallIds = new Set(toolTags.filter((row) => row.tool_owner_message_id !== null && idMap.parentToFork.has(row.tool_owner_message_id)).map((row) => row.message_id));
20343
+ const result = copySessionStateForClone(db, parentSessionID, sessionId, forkCloneFilter(idMap, copiedToolCallIds));
20344
+ if (result.kind === "destination-not-empty")
20345
+ return { kind: "destination-not-empty", parentSessionID };
20346
+ return { kind: "seeded", parentSessionID, pairedRows: idMap.parentToFork.size, result };
19892
20347
  }
19893
- function reportRpcReply(sessionID, title, reply, pending) {
19894
- if (reply.ok !== true) {
19895
- const error = typeof reply.error === "string" ? reply.error : `${title} request failed`;
19896
- pushNotification2("toast", { message: error, variant: "error" }, sessionID);
19897
- return;
19898
- }
19899
- if (reply.started === true) {
19900
- pushNotification2("toast", { message: pending, variant: "info" }, sessionID);
19901
- return;
19902
- }
19903
- reportResult(sessionID, title, typeof reply.message === "string" ? reply.message : "");
20348
+
20349
+ // src/v2/hidden-child-record.ts
20350
+ function keptUnderRetention(keepSubagents, child) {
20351
+ return keepSubagents && (child.ever_settled === true || child.role === "historian");
19904
20352
  }
19905
- function buildV2Commands(rpc, directory) {
19906
- return [
19907
- {
19908
- name: "mmc-status",
19909
- execute: async (input) => {
19910
- const detail = await rpc.dispatch("status-detail", {
19911
- sessionId: input.sessionID,
19912
- directory
19913
- });
19914
- if (typeof detail.error === "string") {
19915
- throw new Error(`Magic Context status is unavailable: ${detail.error}`);
19916
- }
19917
- pushNotification2("action", { action: "show-status-dialog" }, input.sessionID);
19918
- }
19919
- },
19920
- {
19921
- name: "mmc-recomp",
19922
- execute: async (input) => {
19923
- if (isTuiConnected2(input.sessionID)) {
19924
- pushNotification2("action", { action: "show-recomp-dialog" }, input.sessionID);
19925
- return;
19926
- }
19927
- const reply = await rpc.dispatch("recomp", { sessionId: input.sessionID });
19928
- if (reply.ok !== true) {
19929
- throw new Error("Magic Context could not start the history rebuild.");
19930
- }
19931
- }
19932
- },
19933
- {
19934
- name: "mmc-flush",
19935
- execute: async (input) => {
19936
- const reply = await rpc.dispatch("flush", { sessionId: input.sessionID });
19937
- reportRpcReply(input.sessionID, "Flush", reply, "Flush started");
19938
- }
19939
- },
19940
- {
19941
- name: "mmc-wrapup",
19942
- execute: async (input) => {
19943
- const argument = commandArgument(input, "mmc-wrapup");
19944
- if (argument !== "" && !/^\d+$/.test(argument)) {
19945
- const usage = "Usage: /mmc-wrapup [messages_to_keep] where messages_to_keep is a positive integer";
19946
- reportUsage(input.sessionID, usage);
19947
- throw new Error(usage);
19948
- }
19949
- const messagesToKeep = argument === "" ? 20 : Number.parseInt(argument, 10);
19950
- if (messagesToKeep <= 0) {
19951
- const usage = "messages_to_keep must be a positive integer";
19952
- reportUsage(input.sessionID, usage);
19953
- throw new Error(usage);
19954
- }
19955
- const reply = await rpc.dispatch("wrapup", {
19956
- sessionId: input.sessionID,
19957
- messagesToKeep
19958
- });
19959
- reportRpcReply(input.sessionID, "Wrapup", reply, "Wrapup started; the summary appears when it finishes");
19960
- }
20353
+ var HIDDEN_CHILD_ROLE_TITLES = {
20354
+ "maintainer-a": "Magic Context maintainer A",
20355
+ "maintainer-b": "Magic Context maintainer B",
20356
+ historian: "Magic Context historian"
20357
+ };
20358
+ function roleTitle(role) {
20359
+ return HIDDEN_CHILD_ROLE_TITLES[role];
20360
+ }
20361
+ function roleAgent(role) {
20362
+ if (role === "maintainer-a")
20363
+ return MEMORY_MAINTAINER_A_AGENT;
20364
+ if (role === "maintainer-b")
20365
+ return MEMORY_MAINTAINER_B_AGENT;
20366
+ return HIDDEN_HISTORIAN_AGENT;
20367
+ }
20368
+ function childCreateInput(identity, role, model) {
20369
+ const agent = roleAgent(role);
20370
+ return {
20371
+ title: roleTitle(role),
20372
+ agent,
20373
+ model: {
20374
+ providerID: model.providerID,
20375
+ id: model.modelID,
20376
+ ...model.variant ? { variant: model.variant } : {}
19961
20377
  },
19962
- {
19963
- name: "mmc-memory-maintain",
19964
- execute: async (input) => {
19965
- const argument = commandArgument(input, "mmc-memory-maintain");
19966
- const subcommand = argument === "" ? "status" : argument.trim().toLowerCase();
19967
- if (subcommand !== "run" && subcommand !== "status" && subcommand !== "resume") {
19968
- const usage = "Usage: /mmc-memory-maintain [run|status|resume] — status is the default";
19969
- reportUsage(input.sessionID, usage);
19970
- throw new Error(usage);
19971
- }
19972
- const reply = await rpc.dispatch("maintenance", {
19973
- sessionId: input.sessionID,
19974
- subcommand
19975
- });
19976
- reportRpcReply(input.sessionID, "Memory maintenance", reply, "Maintenance run started; see /mmc-memory-maintain status for the outcome");
19977
- }
19978
- }
19979
- ];
20378
+ location: { directory: identity.directory },
20379
+ metadata: { magic_context: "hidden-run", role },
20380
+ permissions: hiddenChildPermissions(agent)
20381
+ };
19980
20382
  }
19981
-
19982
- // src/v2/hooks/deleted-session-tombstones.ts
19983
- class DeletedSessionTombstones {
19984
- limit;
19985
- #ids = new Set;
19986
- constructor(limit = 1000) {
19987
- this.limit = limit;
19988
- if (!Number.isSafeInteger(limit) || limit < 1) {
19989
- throw new Error("Deleted-session tombstone limit must be a positive integer");
19990
- }
19991
- }
19992
- add(sessionID) {
19993
- this.#ids.delete(sessionID);
19994
- this.#ids.add(sessionID);
19995
- while (this.#ids.size > this.limit) {
19996
- const oldest = this.#ids.values().next().value;
19997
- if (oldest === undefined)
19998
- break;
19999
- this.#ids.delete(oldest);
20000
- }
20001
- }
20002
- has(sessionID) {
20003
- return this.#ids.has(sessionID);
20004
- }
20005
- clear() {
20006
- this.#ids.clear();
20383
+ function assistantOutcome(row) {
20384
+ const outcome = row?.data.outcome;
20385
+ return outcome === "succeeded" || outcome === "failed" || outcome === "interrupted" ? outcome : undefined;
20386
+ }
20387
+ function withReader(openReader, read) {
20388
+ const reader = openReader();
20389
+ try {
20390
+ return read(reader);
20391
+ } finally {
20392
+ reader.close?.();
20007
20393
  }
20008
- get size() {
20009
- return this.#ids.size;
20394
+ }
20395
+ function errorText(value) {
20396
+ if (value instanceof Error)
20397
+ return value.message;
20398
+ if (typeof value === "string")
20399
+ return value;
20400
+ try {
20401
+ return JSON.stringify(value);
20402
+ } catch {
20403
+ return String(value);
20010
20404
  }
20011
20405
  }
20012
20406
 
20013
- // src/v2/tool-result.ts
20014
- function isToolError(part) {
20015
- const result = part.result;
20016
- return part.resultType === "error" || result?.type === "error" || result !== null && typeof result === "object" && "error" in result;
20017
- }
20018
- function toolErrorText(result) {
20019
- const value = result.value === undefined ? result : result.value;
20020
- return typeof value === "string" ? value : JSON.stringify(value);
20021
- }
20022
- function toolStateContent(state) {
20023
- if (typeof state.output === "string")
20024
- return state.output;
20025
- if (state.status === "error")
20026
- return toolErrorText({ error: state.error, content: state.content ?? [] });
20027
- if (typeof state.content === "string")
20028
- return state.content;
20029
- if (!Array.isArray(state.content))
20030
- return "";
20031
- return state.content.map((part) => {
20032
- if (typeof part === "string")
20033
- return part;
20034
- if (!part || typeof part !== "object")
20035
- return "";
20036
- const value = part;
20037
- if (typeof value.text === "string")
20038
- return value.text;
20039
- if (typeof value.value === "string")
20040
- return value.value;
20041
- return "";
20042
- }).filter(Boolean).join(`
20043
- `);
20044
- }
20045
-
20046
- // src/v2/hooks/payload.ts
20047
- var HEAD_IDS = ["__magic_context_v2_m0__", "__magic_context_v2_m1__"];
20048
- var HOST_CONTENT_TYPES = new Set([
20049
- "text",
20050
- "media",
20051
- "tool-call",
20052
- "tool-result",
20053
- "reasoning",
20054
- "compaction",
20055
- "effort"
20056
- ]);
20057
- function rejectContentPart(message, part, reason) {
20058
- const type = typeof part.type === "string" ? part.type : "<missing>";
20059
- const text = `v2 context omitted a content part the host would reject: type=${type} message=${String(message.info.id ?? "<head>")} reason=${reason}`;
20060
- if (typeof message.info.sessionID === "string")
20061
- sessionLog(message.info.sessionID, text);
20062
- else
20063
- log(text);
20407
+ // src/v2/hidden-child-native.ts
20408
+ function nativeSessionRemove(session) {
20409
+ const remove = session.remove;
20410
+ if (typeof remove !== "function")
20411
+ return;
20412
+ return (input) => Promise.resolve(remove.call(session, { sessionID: input.sessionID }));
20064
20413
  }
20065
- function isHostInstance(value) {
20066
- if (!value || typeof value !== "object" || Array.isArray(value))
20414
+ function isSessionNotFound(error) {
20415
+ if (!error || typeof error !== "object")
20067
20416
  return false;
20068
- const prototype = Object.getPrototypeOf(value);
20069
- return prototype !== Object.prototype && prototype !== null;
20070
- }
20071
- function containsHostInstance(value) {
20072
- if (isHostInstance(value))
20417
+ const fields = error;
20418
+ if (fields.status === 404)
20073
20419
  return true;
20074
- if (Array.isArray(value))
20075
- return value.some(containsHostInstance);
20076
- if (value && typeof value === "object")
20077
- return Object.values(value).some(containsHostInstance);
20078
- return false;
20079
- }
20080
- function clonePreservingInstances(value) {
20081
- if (isHostInstance(value))
20082
- return value;
20083
- if (Array.isArray(value))
20084
- return value.map(clonePreservingInstances);
20085
- if (value && typeof value === "object") {
20086
- const copy = {};
20087
- for (const [key, entry] of Object.entries(value))
20088
- copy[key] = clonePreservingInstances(entry);
20089
- return copy;
20090
- }
20091
- return value;
20420
+ const label = [fields.name, fields._tag, fields.message].filter((value) => typeof value === "string").join(" ");
20421
+ return /not\s*found/i.test(label);
20092
20422
  }
20093
- function contentKey(value) {
20094
- const plain = (entry) => {
20095
- if (ArrayBuffer.isView(entry)) {
20096
- return {
20097
- bytes: Buffer.from(entry.buffer, entry.byteOffset, entry.byteLength).toString("base64")
20098
- };
20423
+ var parentDroppedNoted = false;
20424
+ function createNativeHiddenChildren(host, removeSession, options) {
20425
+ const removing = new Map;
20426
+ const remove = (child) => {
20427
+ const inFlight = removing.get(child.id);
20428
+ if (inFlight)
20429
+ return inFlight;
20430
+ const done = (async () => {
20431
+ try {
20432
+ let timer;
20433
+ try {
20434
+ await Promise.race([
20435
+ removeSession({ sessionID: child.id }),
20436
+ new Promise((_, reject) => {
20437
+ timer = setTimeout(() => reject(new Error("session.remove timed out")), options.removalTimeoutMs ?? 5000);
20438
+ })
20439
+ ]);
20440
+ } finally {
20441
+ if (timer)
20442
+ clearTimeout(timer);
20443
+ }
20444
+ } catch (error) {
20445
+ if (isSessionNotFound(error))
20446
+ return;
20447
+ options.log(`[magic-context] hidden child ${child.id} could not be removed; it goes when its parent session is deleted: ${errorText(error)}`);
20448
+ }
20449
+ })().finally(() => {
20450
+ removing.delete(child.id);
20451
+ });
20452
+ removing.set(child.id, done);
20453
+ return done;
20454
+ };
20455
+ const confirmPlacement = async (sessionID, parentID) => {
20456
+ let stored;
20457
+ try {
20458
+ stored = await host.get({ sessionID });
20459
+ } catch (error) {
20460
+ options.log(`[magic-context] could not read back hidden child ${sessionID} to confirm its parent: ${errorText(error)}`);
20461
+ return;
20099
20462
  }
20100
- if (Array.isArray(entry))
20101
- return entry.map(plain);
20102
- if (entry && typeof entry === "object") {
20103
- return Object.fromEntries(Object.entries(entry).map(([key, nested]) => [key, plain(nested)]));
20463
+ const directory = stored.location?.directory;
20464
+ if (options.directory !== undefined && directory !== undefined && directory !== options.directory) {
20465
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", `hidden child ${sessionID} is bound to ${directory}, not to this instance's ${options.directory}`, true);
20104
20466
  }
20105
- return entry;
20467
+ if (stored.parentID === parentID || parentDroppedNoted)
20468
+ return;
20469
+ parentDroppedNoted = true;
20470
+ options.log(`[magic-context] this OpenCode 2 host does not keep the parent of hidden-run sessions (asked for ${parentID}, read back ${stored.parentID ?? "none"}); they are created as separate sessions and still removed when each run ends`);
20471
+ };
20472
+ const create = async (identity, role, model) => {
20473
+ const parentID = identity.parentSessionId;
20474
+ const input = childCreateInput(identity, role, model);
20475
+ const { location, ...parented } = input;
20476
+ const created = await host.create(parentID ? { ...parented, parentID } : { ...parented, location });
20477
+ if (!created.id)
20478
+ throw new Error("OpenCode 2 did not return a child session id");
20479
+ options.hook.registerChild(created.id, input.agent);
20480
+ const child = {
20481
+ id: created.id,
20482
+ role,
20483
+ generation: options.generation,
20484
+ title: roleTitle(role),
20485
+ model,
20486
+ created_at: Date.now(),
20487
+ directory: identity.directory
20488
+ };
20489
+ if (parentID) {
20490
+ try {
20491
+ await confirmPlacement(created.id, parentID);
20492
+ } catch (error) {
20493
+ await remove(child);
20494
+ throw error;
20495
+ }
20496
+ }
20497
+ return child;
20498
+ };
20499
+ const kept = (child) => keptUnderRetention(options.keepSubagents, child);
20500
+ return {
20501
+ open: create,
20502
+ create,
20503
+ retire(child) {
20504
+ if (!kept(child))
20505
+ remove(child);
20506
+ },
20507
+ async finish(child, retired) {
20508
+ if (retired) {
20509
+ await removing.get(child.id);
20510
+ return;
20511
+ }
20512
+ if (!kept(child))
20513
+ await remove(child);
20514
+ },
20515
+ updateModel: (child, model) => ({ ...child, model }),
20516
+ markEverSettled: (child) => ({ ...child, ever_settled: true })
20106
20517
  };
20107
- return JSON.stringify(plain(value));
20108
20518
  }
20109
- function fileContentValue(result) {
20110
- const value = result?.value;
20111
- if (result?.type !== "content" || !Array.isArray(value))
20519
+
20520
+ // src/v2/hidden-child-cleanup.ts
20521
+ var PREFIX = "opencode2_hidden_children:";
20522
+ var COMPLETE = "opencode2_hidden_children_cleanup_complete";
20523
+ async function cleanupLegacyHiddenChildren(db, remove, note, options = {}) {
20524
+ if (db.prepare("SELECT 1 FROM schema_migrations_meta WHERE key = ?").get(COMPLETE))
20112
20525
  return;
20113
- return value.some((item) => item?.type === "file") ? value : undefined;
20114
- }
20115
- function contentValueText(value) {
20116
- return value.filter((item) => item?.type === "text" && typeof item.text === "string").map((item) => item.text).join(`
20117
- `);
20118
- }
20119
- function contentValueAttachments(value) {
20120
- return value.filter((item) => item?.type === "file").map((item) => ({
20121
- type: "file",
20122
- mime: item.mime,
20123
- url: item.uri,
20124
- ...typeof item.name === "string" ? { filename: item.name } : {}
20125
- }));
20126
- }
20127
- function rebuildFileContent(value, output) {
20128
- if (isDroppedToolOutput(output))
20129
- return { type: "text", value: output };
20130
- const rebuilt = [];
20131
- let placed = false;
20132
- for (const item of value) {
20133
- if (item?.type !== "text") {
20134
- rebuilt.push(item);
20526
+ const rows = db.prepare("SELECT key, value FROM schema_migrations_meta WHERE key GLOB ? ORDER BY key LIMIT 25").all(`${PREFIX}*`);
20527
+ let remaining = options.limit ?? 25;
20528
+ const now = options.now ?? (() => performance.now());
20529
+ const deadline = now() + (options.budgetMs ?? 2000);
20530
+ for (const row of rows) {
20531
+ let record;
20532
+ try {
20533
+ record = JSON.parse(row.value);
20534
+ if (!record || typeof record !== "object" || record.active !== undefined && (!record.active || typeof record.active !== "object" || Array.isArray(record.active)) || record.retired_children !== undefined && !Array.isArray(record.retired_children))
20535
+ throw new Error("invalid record");
20536
+ } catch {
20537
+ note(`[magic-context] legacy hidden-child cleanup cannot read ${row.key}`);
20135
20538
  continue;
20136
20539
  }
20137
- if (placed)
20138
- continue;
20139
- placed = true;
20140
- rebuilt.push({ ...item, text: output });
20141
- }
20142
- if (!placed && output)
20143
- rebuilt.unshift({ type: "text", text: output });
20144
- return { type: "content", value: rebuilt };
20145
- }
20146
- function adaptPayload(draft, admittedIDs = new Set) {
20147
- const existingHeads = new Map(draft.messages.filter((m) => HEAD_IDS.some((id) => m.id === id)).map((m) => [m.id, m]));
20148
- const source = draft.messages.filter((m) => !existingHeads.has(m.id));
20149
- const results = new Map;
20150
- const hostParts = new Map;
20151
- const hostPartTypes = new Set;
20152
- for (const message of source) {
20153
- for (const part of message.content) {
20154
- if (part.type !== "tool-call" && part.type !== "tool-result" && part.type !== "tool" && containsHostInstance(part)) {
20155
- const key = contentKey(part);
20156
- if (!hostParts.has(key))
20157
- hostParts.set(key, part);
20158
- hostPartTypes.add(part.type);
20159
- }
20160
- if (part.type === "tool-result" && typeof part.id === "string") {
20161
- const queue = results.get(part.id) ?? [];
20162
- queue.push({ part, message });
20163
- results.set(part.id, queue);
20540
+ const children = [
20541
+ ...Object.values(record.active ?? {}),
20542
+ ...record.retired_children ?? []
20543
+ ];
20544
+ for (const child of children) {
20545
+ if (remaining-- <= 0 || now() >= deadline)
20546
+ return;
20547
+ if (typeof child?.id !== "string") {
20548
+ note(`[magic-context] legacy hidden-child cleanup has an invalid child in ${row.key}`);
20549
+ continue;
20550
+ }
20551
+ let timer;
20552
+ try {
20553
+ try {
20554
+ await Promise.race([
20555
+ remove({ sessionID: child.id }),
20556
+ new Promise((_, reject) => {
20557
+ timer = setTimeout(() => reject(new Error("session.remove timed out")), Math.min(options.timeoutMs ?? 1000, Math.max(1, deadline - now())));
20558
+ })
20559
+ ]);
20560
+ } catch (error) {
20561
+ if (!isSessionNotFound(error))
20562
+ throw error;
20563
+ }
20564
+ record.active = Object.fromEntries(Object.entries(record.active ?? {}).filter(([, entry]) => entry.id !== child.id));
20565
+ record.retired_children = (record.retired_children ?? []).filter((entry) => entry.id !== child.id);
20566
+ db.prepare("UPDATE schema_migrations_meta SET value = ? WHERE key = ?").run(JSON.stringify(record), row.key);
20567
+ } catch (error) {
20568
+ note(`[magic-context] legacy hidden child ${child.id} cleanup deferred: ${String(error)}`);
20569
+ } finally {
20570
+ if (timer)
20571
+ clearTimeout(timer);
20164
20572
  }
20165
20573
  }
20574
+ if (Object.keys(record.active ?? {}).length === 0 && (record.retired_children ?? []).length === 0)
20575
+ db.prepare("DELETE FROM schema_migrations_meta WHERE key = ?").run(row.key);
20166
20576
  }
20167
- const paired = new Set;
20168
- const bridges = new Map;
20169
- const originals = new Map;
20170
- const bridgesByMessageID = new Map;
20171
- const bridgesByCarrier = new Map;
20172
- const originalsByID = new Map;
20173
- const bridgesFor = (message) => typeof message.info.id === "string" ? bridgesByMessageID.get(message.info.id) : bridgesByCarrier.get(message);
20174
- const nativeTool = (call, result) => {
20175
- const hostResult = result?.part.result;
20176
- const failed = result !== undefined && isToolError(result.part);
20177
- const value = hostResult?.value;
20178
- const files = fileContentValue(hostResult);
20179
- const output = failed && hostResult ? toolErrorText(hostResult) : files ? contentValueText(files) : typeof value === "string" ? value : value === undefined ? "" : JSON.stringify(value);
20180
- const part = {
20181
- type: "tool",
20182
- callID: call?.id ?? result?.part.id,
20183
- tool: call?.name ?? result?.part.name,
20184
- state: {
20185
- input: structuredClone(call?.input ?? {}),
20186
- status: failed ? "error" : result ? "completed" : "running",
20187
- ...result ? { output } : {},
20188
- ...result && (call?.name ?? result.part.name) === "question" ? { metadata: { userAnswer: true } } : {},
20189
- ...files ? { attachments: contentValueAttachments(files) } : {}
20190
- }
20191
- };
20192
- bridges.set(part, {
20193
- call,
20194
- result: result?.part,
20195
- resultMessage: result?.message,
20196
- output,
20197
- files
20198
- });
20199
- if (result)
20200
- paired.add(result.part);
20201
- return part;
20577
+ if (!db.prepare("SELECT 1 FROM schema_migrations_meta WHERE key GLOB ? LIMIT 1").get(`${PREFIX}*`))
20578
+ db.prepare("INSERT OR IGNORE INTO schema_migrations_meta (key, value) VALUES (?, 'true')").run(COMPLETE);
20579
+ }
20580
+
20581
+ // src/v2/hidden-completion.ts
20582
+ var POLL_INTERVAL_MS = 200;
20583
+ function modelKey(model) {
20584
+ return `${model.providerID}/${model.modelID}`;
20585
+ }
20586
+ function sameModel(left, right) {
20587
+ return modelKey(left) === modelKey(right) && left.variant === right.variant;
20588
+ }
20589
+ function configuredHead(identity) {
20590
+ const candidates = [identity.model, ...identity.configuredModels ?? []];
20591
+ for (const candidate of candidates) {
20592
+ const entry = toModelEntry(candidate);
20593
+ const parsed = entry ? parseProviderModel(entry.model) : null;
20594
+ if (parsed)
20595
+ return { ...parsed, ...entry?.qualifier ? { variant: entry.qualifier } : {} };
20596
+ }
20597
+ return;
20598
+ }
20599
+ var HIDDEN_MAINTAINER_ROLES = {
20600
+ "maintainer-a": "magic-context-maintainer-a",
20601
+ "maintainer-b": "magic-context-maintainer-b"
20602
+ };
20603
+ function roleFor(identity) {
20604
+ for (const [role, agent] of Object.entries(HIDDEN_MAINTAINER_ROLES)) {
20605
+ if (identity.agent === agent)
20606
+ return role;
20607
+ }
20608
+ return "historian";
20609
+ }
20610
+ function promptText(request) {
20611
+ const parts = request.body.parts;
20612
+ return Array.isArray(parts) ? parts.flatMap((part) => part && typeof part === "object" && typeof part.text === "string" ? [part.text] : []).join(`
20613
+ `) : "";
20614
+ }
20615
+ function meter(system, prompt, text) {
20616
+ return {
20617
+ input: estimateTokens(system) + estimateTokens(prompt),
20618
+ output: estimateTokens(text),
20619
+ cacheRead: 0,
20620
+ cacheWrite: 0
20202
20621
  };
20203
- const convertedTool = (source) => {
20204
- const sourceState = source.state && typeof source.state === "object" ? source.state : {};
20205
- const output = toolStateContent(sourceState);
20206
- const { content: _content, ...projectedState } = structuredClone(sourceState);
20207
- const part = {
20208
- type: "tool",
20209
- callID: source.callID ?? source.id,
20210
- tool: source.tool ?? source.name,
20211
- state: { ...projectedState, output }
20622
+ }
20623
+ function assistantReasoning(row) {
20624
+ const reasoning = (row.data.content ?? []).flatMap((part) => part.type === "reasoning" && typeof part.text === "string" ? [part.text] : []).join(`
20625
+ `);
20626
+ return reasoning.length > 0 ? reasoning : null;
20627
+ }
20628
+ function assistantText(row) {
20629
+ const text = (row.data.content ?? []).flatMap((part) => part.type === "text" && typeof part.text === "string" ? [part.text] : []).join("");
20630
+ return text.length > 0 ? text : null;
20631
+ }
20632
+
20633
+ class HiddenProviderError extends Error {
20634
+ settled;
20635
+ constructor(detail, options = {}) {
20636
+ super(`Hidden completion provider error: ${detail}`);
20637
+ this.name = "HiddenProviderError";
20638
+ this.settled = options.settled ?? true;
20639
+ }
20640
+ }
20641
+ function requestModel(request, current) {
20642
+ const requested = request.body.model;
20643
+ if (requested && typeof requested.providerID === "string" && typeof requested.modelID === "string") {
20644
+ return {
20645
+ providerID: requested.providerID,
20646
+ modelID: requested.modelID,
20647
+ ...typeof request.body.variant === "string" ? { variant: request.body.variant } : {}
20212
20648
  };
20213
- bridges.set(part, { native: source, output });
20214
- return part;
20215
- };
20216
- const callParts = new Map;
20217
- for (const message of source) {
20218
- for (const part of message.content) {
20219
- if (part.type === "tool-call") {
20220
- callParts.set(part, nativeTool(part, results.get(String(part.id))?.shift()));
20221
- } else if (part.type === "tool") {
20222
- callParts.set(part, convertedTool(part));
20223
- }
20224
- }
20225
20649
  }
20226
- const messages = [];
20227
- for (const message of source) {
20228
- const parts = [];
20229
- for (const content of message.content) {
20230
- if (paired.has(content))
20231
- continue;
20232
- const part = callParts.get(content) ?? (content.type === "tool-result" ? nativeTool(undefined, { part: content, message }) : clonePreservingInstances(content));
20233
- if (message.id && admittedIDs.has(message.id))
20234
- part.synthetic = true;
20235
- parts.push(part);
20650
+ return current;
20651
+ }
20652
+ async function sleepUntilPoll(signal, deadline) {
20653
+ if (signal?.aborted)
20654
+ throw new Error("Hidden completion prompt aborted");
20655
+ const delay = Math.min(POLL_INTERVAL_MS, Math.max(0, deadline - Date.now()));
20656
+ if (delay <= 0)
20657
+ return;
20658
+ await new Promise((resolve, reject) => {
20659
+ const timer = setTimeout(resolve, delay);
20660
+ const abort = () => {
20661
+ clearTimeout(timer);
20662
+ reject(new Error("Hidden completion prompt aborted"));
20663
+ };
20664
+ signal?.addEventListener("abort", abort, { once: true });
20665
+ if (signal?.aborted)
20666
+ abort();
20667
+ else
20668
+ setTimeout(() => {
20669
+ signal?.removeEventListener("abort", abort);
20670
+ }, delay);
20671
+ });
20672
+ }
20673
+ function isProviderFailure(error) {
20674
+ if (!error || typeof error !== "object")
20675
+ return false;
20676
+ const type = error.type;
20677
+ return typeof type === "string" && (type.startsWith("provider.") || type.toLowerCase().includes("provider"));
20678
+ }
20679
+ async function awaitAssistantRow(openReader, readSessionError, localFailure, childID, afterSeq, deadline, signal) {
20680
+ for (;; ) {
20681
+ const { assistant, idle } = withReader(openReader, (reader) => ({
20682
+ assistant: reader.latestAssistant(childID),
20683
+ idle: reader.latestIdle(childID)
20684
+ }));
20685
+ const newAssistant = assistant && assistant.seq > afterSeq ? assistant : undefined;
20686
+ const newIdle = idle && idle.seq > afterSeq ? idle : undefined;
20687
+ const refused = localFailure();
20688
+ if (refused)
20689
+ throw refused;
20690
+ if (newIdle && (!newAssistant || newIdle.seq > newAssistant.seq)) {
20691
+ const outcome = newIdle.data.outcome;
20692
+ if (outcome === "failed" || outcome === "interrupted") {
20693
+ const sessionError = await readSessionError();
20694
+ const details = [
20695
+ `outcome=${outcome}`,
20696
+ `terminal_row=${errorText(newIdle)}`,
20697
+ `session_error=${sessionError === undefined ? "unavailable" : errorText(sessionError)}`
20698
+ ];
20699
+ throw sessionError === undefined || !isProviderFailure(sessionError) ? new Error(`Hidden completion failed: ${details.join("; ")}`) : new HiddenProviderError(details.join("; "));
20700
+ }
20701
+ if (outcome === "succeeded" && newAssistant)
20702
+ return newAssistant;
20236
20703
  }
20237
- if (!parts.length && message.content.length)
20238
- continue;
20239
- const byCallID = new Map;
20240
- for (const part of parts) {
20241
- const bridge = bridges.get(part);
20242
- if (bridge && typeof part.callID === "string")
20243
- byCallID.set(part.callID, bridge);
20704
+ if (newAssistant) {
20705
+ const outcome = assistantOutcome(newAssistant);
20706
+ if (outcome === "failed" || outcome === "interrupted") {
20707
+ const sessionError = await readSessionError();
20708
+ const details = [
20709
+ `outcome=${outcome}`,
20710
+ `terminal_row=${errorText(newAssistant)}`,
20711
+ `session_error=${sessionError === undefined ? "unavailable" : errorText(sessionError)}`
20712
+ ];
20713
+ throw sessionError === undefined || !isProviderFailure(sessionError) ? new Error(`Hidden completion failed: ${details.join("; ")}`) : new HiddenProviderError(details.join("; "));
20714
+ }
20715
+ if (newAssistant.data.error !== undefined) {
20716
+ throw new HiddenProviderError(errorText(newAssistant.data.error), {
20717
+ settled: typeof newAssistant.data.finish === "string"
20718
+ });
20719
+ }
20720
+ if (typeof newAssistant.data.finish === "string" || outcome === "succeeded") {
20721
+ return newAssistant;
20722
+ }
20244
20723
  }
20245
- if (typeof message.id === "string") {
20246
- bridgesByMessageID.set(message.id, byCallID);
20247
- originalsByID.set(message.id, message);
20724
+ if (Date.now() >= deadline) {
20725
+ throw new Error("Hidden completion timed out waiting for a persisted assistant row");
20248
20726
  }
20249
- const mapped = {
20250
- info: {
20251
- id: message.id,
20252
- sessionID: draft.sessionID,
20253
- role: message.role,
20254
- ...{
20255
- providerID: draft.model.providerID,
20256
- modelID: draft.model.id,
20257
- agent: draft.agent
20258
- }
20259
- },
20260
- parts
20261
- };
20262
- originals.set(mapped, message);
20263
- if (typeof message.id !== "string")
20264
- bridgesByCarrier.set(mapped, byCallID);
20265
- messages.push(mapped);
20727
+ await sleepUntilPoll(signal, deadline);
20266
20728
  }
20729
+ }
20730
+ var V2_HIDDEN_EXECUTOR_CAPABILITIES = {
20731
+ tools: true,
20732
+ harness: "opencode2"
20733
+ };
20734
+ function createLateHiddenExecutor(current) {
20735
+ const wired = () => {
20736
+ const executor = current();
20737
+ if (executor)
20738
+ return executor;
20739
+ throw new Error("Magic Context hidden work is unavailable until the context database opens.");
20740
+ };
20267
20741
  return {
20268
- messages,
20269
- commit() {
20270
- let head = 0;
20271
- const rendered = [];
20272
- for (const message of messages) {
20273
- const original = originals.get(message) ?? (typeof message.info.id === "string" ? originalsByID.get(message.info.id) : undefined);
20274
- const id = message.info.syntheticHead ? HEAD_IDS[head++] : original?.id;
20275
- const content = [];
20276
- const following = [];
20277
- for (const candidate of message.parts) {
20278
- const part = candidate;
20279
- const bridge = bridges.get(part) ?? (part.type === "tool" && typeof part.callID === "string" ? bridgesFor(message)?.get(part.callID) : undefined);
20280
- if (!bridge) {
20281
- if (part.type === "tool") {
20282
- const state = part.state;
20283
- if (typeof part.callID !== "string" || typeof part.tool !== "string" || !state || typeof state !== "object") {
20284
- rejectContentPart(message, part, "tool has no call ID, name, or state");
20285
- continue;
20286
- }
20287
- content.push({
20288
- type: "tool-call",
20289
- id: part.callID,
20290
- name: part.tool,
20291
- input: state.input
20292
- });
20293
- if (state.status === "completed" || state.status === "error") {
20294
- following.push({
20295
- role: "tool",
20296
- content: [
20297
- {
20298
- type: "tool-result",
20299
- id: part.callID,
20300
- name: part.tool,
20301
- result: {
20302
- type: state.status === "error" ? "error" : "text",
20303
- value: toolStateContent(state)
20304
- }
20305
- }
20306
- ]
20307
- });
20308
- }
20309
- continue;
20310
- }
20311
- if (part.type === "file") {
20312
- const mime = part.mime;
20313
- const url = part.url;
20314
- const prefix = `data:${mime};base64,`;
20315
- if (typeof mime !== "string" || !/^image\/(png|jpeg|gif|webp)$/.test(mime) || typeof url !== "string" || !url.startsWith(prefix)) {
20316
- rejectContentPart(message, part, "file is not an inline supported image");
20317
- continue;
20318
- }
20319
- const asset = hostMediaAsset(url.slice(prefix.length), mime);
20320
- if (typeof asset === "string") {
20321
- rejectContentPart(message, part, `host media unavailable: ${asset}`);
20322
- continue;
20323
- }
20324
- content.push({ type: "media", media: asset });
20325
- continue;
20326
- }
20327
- if (!HOST_CONTENT_TYPES.has(String(part.type))) {
20328
- rejectContentPart(message, part, "unknown host content type");
20329
- continue;
20330
- }
20331
- const { synthetic: _synthetic, ...clean } = part;
20332
- const original = hostPartTypes.has(clean.type) && !containsHostInstance(clean) ? hostParts.get(contentKey(clean)) : undefined;
20333
- content.push(original ?? clean);
20334
- continue;
20335
- }
20336
- const state = part.state;
20337
- if (bridge.native) {
20338
- const native = bridge.native;
20339
- const callID = String(native.id ?? native.callID ?? part.callID);
20340
- const name = String(native.name ?? native.tool ?? part.tool);
20341
- content.push({ type: "tool-call", id: callID, name, input: state.input });
20342
- if (state.status === "completed" || state.status === "error") {
20343
- following.push({
20344
- role: "tool",
20345
- content: [
20346
- {
20347
- type: "tool-result",
20348
- id: callID,
20349
- name,
20350
- result: {
20351
- type: state.status === "error" ? "error" : "text",
20352
- value: state.output
20353
- }
20354
- }
20355
- ]
20742
+ get capabilities() {
20743
+ return current()?.capabilities ?? V2_HIDDEN_EXECUTOR_CAPABILITIES;
20744
+ },
20745
+ open: (run) => wired().open(run),
20746
+ attempt: (handle, request) => wired().attempt(handle, request),
20747
+ collect: (handle, limit) => wired().collect(handle, limit),
20748
+ close: (handle, settlement) => wired().close(handle, settlement)
20749
+ };
20750
+ }
20751
+ async function createV2HiddenCompletionExecutor(host, options) {
20752
+ const runs = new WeakMap;
20753
+ const generation = options.generation ?? "opencode2";
20754
+ const roleTails = new Map;
20755
+ const note = options.log ?? log;
20756
+ const removeSession = host.removeSession;
20757
+ if (!removeSession)
20758
+ throw new Error("Magic Context requires OpenCode 2.0.22 session.remove");
20759
+ const lifecycle = createNativeHiddenChildren(host, (input) => removeSession.call(host, input), {
20760
+ hook: options.hook,
20761
+ generation,
20762
+ keepSubagents: options.keepSubagents === true,
20763
+ log: note,
20764
+ removalTimeoutMs: options.removalTimeoutMs,
20765
+ directory: options.directory
20766
+ });
20767
+ const acquireRole = async (role) => {
20768
+ const previous = roleTails.get(role) ?? Promise.resolve();
20769
+ let release;
20770
+ const gate = new Promise((resolve) => {
20771
+ release = resolve;
20772
+ });
20773
+ const tail = previous.then(() => gate);
20774
+ roleTails.set(role, tail);
20775
+ await previous;
20776
+ return () => {
20777
+ release();
20778
+ if (roleTails.get(role) === tail)
20779
+ roleTails.delete(role);
20780
+ };
20781
+ };
20782
+ const warnedVariants = new Set;
20783
+ const validateVariant = async (model) => {
20784
+ if (!model.variant || !options.modelCatalog)
20785
+ return model;
20786
+ try {
20787
+ const listed = await options.modelCatalog();
20788
+ const rows = Array.isArray(listed) ? listed : listed && typeof listed === "object" && Array.isArray(listed.data) ? listed.data : [];
20789
+ const entry = rows.find((row) => row && typeof row === "object" && row.providerID === model.providerID && row.id === model.modelID);
20790
+ if (!entry)
20791
+ return model;
20792
+ if (entry.variants && typeof entry.variants === "object" && Object.hasOwn(entry.variants, model.variant))
20793
+ return model;
20794
+ const key = `${model.providerID}/${model.modelID}:${model.variant}`;
20795
+ if (!warnedVariants.has(key)) {
20796
+ warnedVariants.add(key);
20797
+ note(`[magic-context] ${recordHiddenVariantWarning(model.providerID, model.modelID, model.variant)}`);
20798
+ }
20799
+ return { providerID: model.providerID, modelID: model.modelID };
20800
+ } catch {
20801
+ return model;
20802
+ }
20803
+ };
20804
+ const resolveHead = async (identity) => {
20805
+ const configured = configuredHead(identity);
20806
+ if (configured)
20807
+ return validateVariant(configured);
20808
+ if (!identity.parentSessionId) {
20809
+ throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion requires a configured model or an existing parent session model", true);
20810
+ }
20811
+ const parent = await host.get({ sessionID: identity.parentSessionId });
20812
+ if (!parent.model) {
20813
+ throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion could not resolve the parent session model", true);
20814
+ }
20815
+ return {
20816
+ providerID: parent.model.providerID,
20817
+ modelID: parent.model.id,
20818
+ ...parent.model.variant ? { variant: parent.model.variant } : {}
20819
+ };
20820
+ };
20821
+ const switchChildModel = async (run, requested) => {
20822
+ if (sameModel(run.child.model, requested))
20823
+ return;
20824
+ await host.switchModel({
20825
+ sessionID: run.child.id,
20826
+ model: {
20827
+ providerID: requested.providerID,
20828
+ id: requested.modelID,
20829
+ ...requested.variant ? { variant: requested.variant } : {}
20830
+ }
20831
+ });
20832
+ run.child = lifecycle.updateModel(run.child, requested);
20833
+ };
20834
+ const retire = (run, reason) => {
20835
+ if (run.retired)
20836
+ return;
20837
+ lifecycle.retire(run.child, reason);
20838
+ run.retired = true;
20839
+ };
20840
+ const interruptAndRetire = async (run, reason) => {
20841
+ try {
20842
+ await host.interrupt({ sessionID: run.child.id });
20843
+ } finally {
20844
+ retire(run, reason);
20845
+ }
20846
+ };
20847
+ return {
20848
+ capabilities: V2_HIDDEN_EXECUTOR_CAPABILITIES,
20849
+ async open(identity) {
20850
+ const role = roleFor(identity);
20851
+ const releaseRole = await acquireRole(role);
20852
+ let openedChild;
20853
+ try {
20854
+ await options.ensureAgent?.();
20855
+ const head = await resolveHead(identity);
20856
+ const active = await lifecycle.open(identity, role, head);
20857
+ openedChild = active;
20858
+ const handle = { id: active.id, childSessionId: active.id };
20859
+ const run = {
20860
+ identity,
20861
+ role,
20862
+ child: active,
20863
+ releaseRole,
20864
+ failed: false,
20865
+ unsettledFailure: false,
20866
+ retired: false
20867
+ };
20868
+ runs.set(handle, run);
20869
+ await switchChildModel(run, head);
20870
+ return handle;
20871
+ } catch (error) {
20872
+ if (openedChild)
20873
+ lifecycle.retire(openedChild, "hidden-run-open-failed");
20874
+ releaseRole();
20875
+ throw error;
20876
+ }
20877
+ },
20878
+ async attempt(handle, request) {
20879
+ const run = runs.get(handle);
20880
+ if (!run)
20881
+ throw new Error("Unknown hidden completion run");
20882
+ if (request.signal?.aborted) {
20883
+ await interruptAndRetire(run, "aborted-before-prompt");
20884
+ throw new Error("Hidden completion prompt aborted");
20885
+ }
20886
+ const requested = await validateVariant(requestModel(request, run.child.model));
20887
+ if (run.retired) {
20888
+ run.child = await lifecycle.create(run.identity, run.role, requested);
20889
+ run.failed = false;
20890
+ run.unsettledFailure = false;
20891
+ run.retired = false;
20892
+ handle.id = run.child.id;
20893
+ handle.childSessionId = run.child.id;
20894
+ }
20895
+ await switchChildModel(run, requested);
20896
+ const baseline = withReader(options.openReader, (reader) => reader.latestSequence(run.child.id));
20897
+ const marker = `mc:hidden:${crypto.randomUUID()}:${crypto.randomUUID()}`;
20898
+ run.completion = undefined;
20899
+ const stepCap = options.resolveStepCap?.(run.identity);
20900
+ const attempt = {
20901
+ childSessionId: run.child.id,
20902
+ identity: run.identity,
20903
+ agent: run.identity.agent,
20904
+ request,
20905
+ shaped: false,
20906
+ ...stepCap === undefined ? {} : { stepCap }
20907
+ };
20908
+ options.hook.registerAttempt(marker, attempt);
20909
+ const deadline = Date.now() + run.identity.timeoutMs;
20910
+ let abortReject;
20911
+ const aborted = new Promise((_resolve, reject) => {
20912
+ abortReject = reject;
20913
+ });
20914
+ const onAbort = () => {
20915
+ interruptAndRetire(run, "prompt-aborted").finally(() => abortReject(new Error("Hidden completion prompt aborted")));
20916
+ };
20917
+ const deadlineTimer = setTimeout(() => {
20918
+ interruptAndRetire(run, "prompt-timeout").finally(() => abortReject(new Error("Hidden completion prompt timed out")));
20919
+ }, Math.max(0, deadline - Date.now()));
20920
+ request.signal?.addEventListener("abort", onAbort, { once: true });
20921
+ try {
20922
+ await Promise.race([
20923
+ host.prompt({ sessionID: run.child.id, text: marker }),
20924
+ aborted
20925
+ ]);
20926
+ await Promise.race([host.wait({ sessionID: run.child.id }), aborted]);
20927
+ const row = await Promise.race([
20928
+ awaitAssistantRow(options.openReader, async () => {
20929
+ try {
20930
+ const eventError = await host.terminalError?.({
20931
+ sessionID: run.child.id
20356
20932
  });
20933
+ if (eventError !== undefined)
20934
+ return eventError;
20935
+ return (await host.get({ sessionID: run.child.id })).error;
20936
+ } catch {
20937
+ return;
20357
20938
  }
20358
- continue;
20359
- }
20360
- if (bridge.call)
20361
- content.push({ ...bridge.call, input: state.input });
20362
- if (bridge.result && bridge.resultMessage) {
20363
- const result = {
20364
- ...bridge.result,
20365
- result: state.output === bridge.output ? bridge.result.result : bridge.files && typeof state.output === "string" ? rebuildFileContent(bridge.files, state.output) : {
20366
- type: state.status === "error" ? "error" : "text",
20367
- value: state.output
20368
- }
20369
- };
20370
- if (bridge.resultMessage === original)
20371
- content.push(result);
20372
- else
20373
- following.push({ ...bridge.resultMessage, content: [result] });
20374
- }
20939
+ }, () => attempt.refusal ?? attempt.stepLimit, run.child.id, baseline, deadline, request.signal),
20940
+ aborted
20941
+ ]);
20942
+ if (!attempt.shaped) {
20943
+ const task = run.identity.title.replace(/^magic-context-dream-/, "");
20944
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", `Host did not dispatch the hidden child context hook (task=${task}, agent=${run.identity.agent}, child=${run.child.id}, directory=${run.identity.directory}, stage=context/HiddenChildHook.apply). Check that the child's location loads the owning Magic Context instance; changing models cannot repair missing context shaping.`, true);
20945
+ }
20946
+ const text = assistantText(row);
20947
+ const system = typeof request.body.system === "string" ? request.body.system : run.identity.system;
20948
+ const tokens = row.data.tokens;
20949
+ const tokenNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
20950
+ const reportedInput = tokenNumber(tokens?.input);
20951
+ const reportedOutput = tokenNumber(tokens?.output);
20952
+ if (request.signal?.aborted || run.retired || Date.now() >= deadline) {
20953
+ await interruptAndRetire(run, "prompt-aborted-or-timeout");
20954
+ throw new Error(request.signal?.aborted ? "Hidden completion prompt aborted" : "Hidden completion prompt timed out");
20955
+ }
20956
+ run.completion = {
20957
+ text,
20958
+ tokenLog: runTokenLog(tokens, run.identity.maxOutputTokens, row.data.finish),
20959
+ reasoning: text ? null : assistantReasoning(row),
20960
+ usage: reportedInput !== undefined || reportedOutput !== undefined ? {
20961
+ input: reportedInput ?? 0,
20962
+ output: reportedOutput ?? 0,
20963
+ cacheRead: tokenNumber(tokens?.cache?.read) ?? 0,
20964
+ cacheWrite: tokenNumber(tokens?.cache?.write) ?? 0
20965
+ } : meter(system, promptText(request), text ?? ""),
20966
+ lengthCapped: ["length", "max_tokens"].includes(row.data.finish ?? ""),
20967
+ providerId: row.data.model?.providerID ?? requested.providerID,
20968
+ modelId: row.data.model?.id ?? requested.modelID,
20969
+ ...attempt.steps === undefined ? {} : { steps: attempt.steps }
20970
+ };
20971
+ if (!run.child.ever_settled)
20972
+ run.child = lifecycle.markEverSettled(run.child);
20973
+ } catch (caught) {
20974
+ const error = attempt.stepLimit ?? attempt.refusal ?? caught;
20975
+ run.failed = true;
20976
+ if (!(error instanceof HiddenProviderError)) {
20977
+ run.unsettledFailure = true;
20978
+ }
20979
+ if (request.signal?.aborted && !run.retired) {
20980
+ await interruptAndRetire(run, "prompt-aborted");
20981
+ } else if (error instanceof Error && error.message.includes("timed out") && !run.retired) {
20982
+ await interruptAndRetire(run, "prompt-timeout");
20983
+ } else if ((error instanceof HiddenAgentStepLimit || error instanceof HiddenProviderError && error.settled) && !run.retired) {
20984
+ await interruptAndRetire(run, error instanceof HiddenAgentStepLimit ? "hidden-run-step-limit" : "hidden-run-provider-error");
20985
+ }
20986
+ throw error;
20987
+ } finally {
20988
+ clearTimeout(deadlineTimer);
20989
+ request.signal?.removeEventListener("abort", onAbort);
20990
+ options.hook.releaseAttempt(marker);
20991
+ }
20992
+ },
20993
+ async collect(handle) {
20994
+ const completion = runs.get(handle)?.completion;
20995
+ if (!completion)
20996
+ throw new Error("Hidden completion has no settled output");
20997
+ return completion;
20998
+ },
20999
+ async close(handle, settlement) {
21000
+ if (!handle)
21001
+ return;
21002
+ const run = runs.get(handle);
21003
+ if (!run)
21004
+ return;
21005
+ try {
21006
+ const reusable = !run.retired && run.failed && !run.unsettledFailure;
21007
+ if (!run.completion && (run.failed || !settlement.promptSettled) && !reusable) {
21008
+ retire(run, "hidden-run-failed");
21009
+ }
21010
+ } finally {
21011
+ runs.delete(handle);
21012
+ run.releaseRole();
21013
+ }
21014
+ await lifecycle.finish(run.child, run.retired);
21015
+ }
21016
+ };
21017
+ }
21018
+
21019
+ // src/v2/hooks/channel2.ts
21020
+ import { randomBytes as randomBytes2 } from "node:crypto";
21021
+ var pendingCandidates = new WeakMap;
21022
+ function syntheticCandidates(context, sessionID, stored) {
21023
+ const pending = pendingCandidates.get(context.storage);
21024
+ for (const [key, id] of pending ?? []) {
21025
+ if (!key.startsWith(`${sessionID}/`))
21026
+ continue;
21027
+ if (stored.has(id))
21028
+ pending?.delete(key);
21029
+ else
21030
+ stored.add(id);
21031
+ }
21032
+ return stored;
21033
+ }
21034
+ function clearSyntheticCandidates(context) {
21035
+ pendingCandidates.delete(context.storage);
21036
+ }
21037
+ async function deliverSynthetic(context, sessionID, text) {
21038
+ const id = `msg_${randomBytes2(12).toString("hex")}`;
21039
+ await context.storage.set(`synthetic/${sessionID}/${id}`, { id });
21040
+ let candidates = pendingCandidates.get(context.storage);
21041
+ if (!candidates) {
21042
+ candidates = new Map;
21043
+ pendingCandidates.set(context.storage, candidates);
21044
+ }
21045
+ candidates.set(`${sessionID}/${id}`, id);
21046
+ await context.session.synthetic({ sessionID, id, text, delivery: "steer" });
21047
+ return id;
21048
+ }
21049
+ async function isAdmittedSynthetic(context, sessionID, id) {
21050
+ const record = await context.storage.get(`synthetic/${sessionID}/${id}`);
21051
+ return record !== null && typeof record === "object" && "id" in record && record.id === id;
21052
+ }
21053
+ async function deliverPendingChannel2(context, db, sessionID, baseline) {
21054
+ if (getChannel2NudgeState(db, sessionID) !== "pending")
21055
+ return;
21056
+ const evaluation = evaluateChannel2(baseline);
21057
+ if (!evaluation.evaluable || !evaluation.shouldTrigger)
21058
+ return;
21059
+ const token = randomBytes2(16).toString("hex");
21060
+ if (!claimChannel2NudgeState(db, sessionID, token))
21061
+ return;
21062
+ try {
21063
+ await deliverSynthetic(context, sessionID, buildChannel2Reminder(evaluation.reclaimableTokens, reclaimableToolOutputCount(baseline?.baselineParts ?? [])));
21064
+ } catch (error) {
21065
+ casChannel2NudgeClaim(db, sessionID, "pending", token);
21066
+ throw error;
21067
+ }
21068
+ casChannel2NudgeClaim(db, sessionID, "delivered", token);
21069
+ }
21070
+
21071
+ // src/v2/hooks/commands.ts
21072
+ async function registerV2Commands(args) {
21073
+ const domain = args.command;
21074
+ if (!domain || typeof domain.transform !== "function") {
21075
+ log("[magic-context] v2 host exposes no command domain; /mmc-* commands are TUI-only");
21076
+ return false;
21077
+ }
21078
+ const descriptions = getMagicContextBuiltinCommands(args.compactionEnabled);
21079
+ const commands = buildV2Commands(args.rpc, args.directory);
21080
+ try {
21081
+ await domain.transform((editor) => {
21082
+ for (const command of commands) {
21083
+ editor.add({
21084
+ name: command.name,
21085
+ description: descriptions[command.name].description,
21086
+ execute: command.execute
21087
+ });
21088
+ }
21089
+ });
21090
+ } catch (error) {
21091
+ log("[magic-context] v2 command registration failed", error);
21092
+ return false;
21093
+ }
21094
+ log(`[magic-context] registered server-side commands: ${commands.map((command) => command.name).join(" ")}`);
21095
+ return true;
21096
+ }
21097
+ function commandArgument(input, name) {
21098
+ const raw = typeof input.prompt?.text === "string" ? input.prompt.text.trim() : "";
21099
+ const prefix = `/${name}`;
21100
+ if (raw === prefix)
21101
+ return "";
21102
+ if (raw.startsWith(`${prefix} `))
21103
+ return raw.slice(prefix.length).trim();
21104
+ return raw;
21105
+ }
21106
+ function reportResult(sessionID, title, message) {
21107
+ pushNotification2("action", { action: "show-result-dialog", title, message }, sessionID);
21108
+ }
21109
+ function reportUsage(sessionID, message) {
21110
+ pushNotification2("toast", { message, variant: "warning" }, sessionID);
21111
+ }
21112
+ function reportRpcReply(sessionID, title, reply, pending) {
21113
+ if (reply.ok !== true) {
21114
+ const error = typeof reply.error === "string" ? reply.error : `${title} request failed`;
21115
+ pushNotification2("toast", { message: error, variant: "error" }, sessionID);
21116
+ return;
21117
+ }
21118
+ if (reply.started === true) {
21119
+ pushNotification2("toast", { message: pending, variant: "info" }, sessionID);
21120
+ return;
21121
+ }
21122
+ reportResult(sessionID, title, typeof reply.message === "string" ? reply.message : "");
21123
+ }
21124
+ function buildV2Commands(rpc, directory) {
21125
+ return [
21126
+ {
21127
+ name: "mmc-status",
21128
+ execute: async (input) => {
21129
+ const detail = await rpc.dispatch("status-detail", {
21130
+ sessionId: input.sessionID,
21131
+ directory
21132
+ });
21133
+ if (typeof detail.error === "string") {
21134
+ throw new Error(`Magic Context status is unavailable: ${detail.error}`);
20375
21135
  }
20376
- if (content.length || !original?.content.length) {
20377
- const value = {
20378
- ...original,
20379
- id,
20380
- role: message.info.role ?? "user",
20381
- content
20382
- };
20383
- const existing = id ? existingHeads.get(id) : undefined;
20384
- rendered.push(existing ? Object.assign(existing, { content }) : value);
21136
+ pushNotification2("action", { action: "show-status-dialog" }, input.sessionID);
21137
+ }
21138
+ },
21139
+ {
21140
+ name: "mmc-recomp",
21141
+ execute: async (input) => {
21142
+ if (isTuiConnected2(input.sessionID)) {
21143
+ pushNotification2("action", { action: "show-recomp-dialog" }, input.sessionID);
21144
+ return;
21145
+ }
21146
+ const reply = await rpc.dispatch("recomp", { sessionId: input.sessionID });
21147
+ if (reply.ok !== true) {
21148
+ throw new Error("Magic Context could not start the history rebuild.");
20385
21149
  }
20386
- rendered.push(...following);
20387
21150
  }
20388
- draft.messages.splice(0, draft.messages.length, ...rendered);
21151
+ },
21152
+ {
21153
+ name: "mmc-flush",
21154
+ execute: async (input) => {
21155
+ const reply = await rpc.dispatch("flush", { sessionId: input.sessionID });
21156
+ reportRpcReply(input.sessionID, "Flush", reply, "Flush started");
21157
+ }
21158
+ },
21159
+ {
21160
+ name: "mmc-wrapup",
21161
+ execute: async (input) => {
21162
+ const argument = commandArgument(input, "mmc-wrapup");
21163
+ if (argument !== "" && !/^\d+$/.test(argument)) {
21164
+ const usage = "Usage: /mmc-wrapup [messages_to_keep] where messages_to_keep is a positive integer";
21165
+ reportUsage(input.sessionID, usage);
21166
+ throw new Error(usage);
21167
+ }
21168
+ const messagesToKeep = argument === "" ? 20 : Number.parseInt(argument, 10);
21169
+ if (messagesToKeep <= 0) {
21170
+ const usage = "messages_to_keep must be a positive integer";
21171
+ reportUsage(input.sessionID, usage);
21172
+ throw new Error(usage);
21173
+ }
21174
+ const reply = await rpc.dispatch("wrapup", {
21175
+ sessionId: input.sessionID,
21176
+ messagesToKeep
21177
+ });
21178
+ reportRpcReply(input.sessionID, "Wrapup", reply, "Wrapup started; the summary appears when it finishes");
21179
+ }
21180
+ },
21181
+ {
21182
+ name: "mmc-memory-maintain",
21183
+ execute: async (input) => {
21184
+ const argument = commandArgument(input, "mmc-memory-maintain");
21185
+ const subcommand = argument === "" ? "status" : argument.trim().toLowerCase();
21186
+ if (subcommand !== "run" && subcommand !== "status" && subcommand !== "resume") {
21187
+ const usage = "Usage: /mmc-memory-maintain [run|status|resume] — status is the default";
21188
+ reportUsage(input.sessionID, usage);
21189
+ throw new Error(usage);
21190
+ }
21191
+ const reply = await rpc.dispatch("maintenance", {
21192
+ sessionId: input.sessionID,
21193
+ subcommand
21194
+ });
21195
+ reportRpcReply(input.sessionID, "Memory maintenance", reply, "Maintenance run started; see /mmc-memory-maintain status for the outcome");
21196
+ }
20389
21197
  }
20390
- };
21198
+ ];
21199
+ }
21200
+
21201
+ // src/v2/hooks/deleted-session-tombstones.ts
21202
+ class DeletedSessionTombstones {
21203
+ limit;
21204
+ #ids = new Set;
21205
+ constructor(limit = 1000) {
21206
+ this.limit = limit;
21207
+ if (!Number.isSafeInteger(limit) || limit < 1) {
21208
+ throw new Error("Deleted-session tombstone limit must be a positive integer");
21209
+ }
21210
+ }
21211
+ add(sessionID) {
21212
+ this.#ids.delete(sessionID);
21213
+ this.#ids.add(sessionID);
21214
+ while (this.#ids.size > this.limit) {
21215
+ const oldest = this.#ids.values().next().value;
21216
+ if (oldest === undefined)
21217
+ break;
21218
+ this.#ids.delete(oldest);
21219
+ }
21220
+ }
21221
+ has(sessionID) {
21222
+ return this.#ids.has(sessionID);
21223
+ }
21224
+ clear() {
21225
+ this.#ids.clear();
21226
+ }
21227
+ get size() {
21228
+ return this.#ids.size;
21229
+ }
20391
21230
  }
20392
21231
 
20393
21232
  // src/v2/hooks/generate.ts
@@ -20433,9 +21272,9 @@ function hiddenTerminalError(event) {
20433
21272
  }
20434
21273
 
20435
21274
  // src/v2/hooks/lkg-system.ts
20436
- import { createHash as createHash6 } from "node:crypto";
20437
- function identity(slot) {
20438
- return createHash6("sha256").update(JSON.stringify({
21275
+ import { createHash as createHash7 } from "node:crypto";
21276
+ function identity2(slot) {
21277
+ return createHash7("sha256").update(JSON.stringify({
20439
21278
  capturedAt: slot.capturedAt,
20440
21279
  captureSequence: slot.captureSequence,
20441
21280
  rowVersion: slot.rowVersion,
@@ -20450,14 +21289,14 @@ class V2LkgSystemReplay {
20450
21289
  systems = new BoundedSessionMap(1000);
20451
21290
  capture(sessionId, slot, input, served) {
20452
21291
  this.systems.set(sessionId, {
20453
- slot: identity(slot),
21292
+ slot: identity2(slot),
20454
21293
  input: JSON.stringify(input),
20455
21294
  served: structuredClone(served)
20456
21295
  });
20457
21296
  }
20458
21297
  restore(sessionId, slot, input, target) {
20459
21298
  const saved = this.systems.get(sessionId);
20460
- if (!slot || !saved || saved.slot !== identity(slot) || saved.input !== JSON.stringify(input))
21299
+ if (!slot || !saved || saved.slot !== identity2(slot) || saved.input !== JSON.stringify(input))
20461
21300
  return false;
20462
21301
  target.splice(0, target.length, ...structuredClone(saved.served));
20463
21302
  return true;
@@ -20642,7 +21481,7 @@ function hasRequiredSessionAPI(session) {
20642
21481
  }
20643
21482
 
20644
21483
  // src/features/magic-context/session-project-backfill.ts
20645
- import { randomUUID as randomUUID2 } from "node:crypto";
21484
+ import { randomUUID as randomUUID4 } from "node:crypto";
20646
21485
  import { existsSync as existsSync7 } from "node:fs";
20647
21486
  var LEASE_TTL_MS = 10 * 60 * 1000;
20648
21487
  var SESSION_PAGE_SIZE = 100;
@@ -20784,7 +21623,7 @@ async function runSessionProjectBackfill(db, source, options = {}) {
20784
21623
  const now = options.now ?? Date.now;
20785
21624
  const resolveIdentity = options.resolveIdentity ?? ((directory) => resolveProjectIdentityForSession(directory, options.allowHomeProject));
20786
21625
  const yieldFn = options.yieldFn ?? defaultYieldFn;
20787
- const holderId = options.holderId ?? randomUUID2();
21626
+ const holderId = options.holderId ?? randomUUID4();
20788
21627
  const readPage = createPageReader(source);
20789
21628
  const result = {
20790
21629
  status: "completed",
@@ -21304,7 +22143,7 @@ Returns the raw transcript as [N] U:/A: lines, capped at ~15K tokens; an oversiz
21304
22143
 
21305
22144
  Finer recovery:
21306
22145
  - verbose=true lists each message separately with its ordinal and a per-part preview (tool calls with output sizes) so you can pick one.
21307
- - message=N returns that one message in full — every text part and every tool call's complete input and output — from stored history. This is the way back to a tool output you released with mmc_reduce; if the message was deleted from history it says so.`;
22146
+ - message=N returns that one message in full — every text part and every tool call's complete input and output — from stored history. This is the way back to a tool output you released with mmc_reduce; if the message is no longer in stored history it says so.`;
21308
22147
  var CTX_EXPAND_TOKEN_BUDGET = 15000;
21309
22148
 
21310
22149
  // src/features/magic-context/tag-input.ts
@@ -21377,7 +22216,7 @@ function resolveCtxExpandMode(args, domain) {
21377
22216
  }
21378
22217
 
21379
22218
  // src/tools/ctx-expand/render.ts
21380
- import { createHash as createHash7 } from "node:crypto";
22219
+ import { createHash as createHash8 } from "node:crypto";
21381
22220
  function isRecord4(value) {
21382
22221
  return value !== null && typeof value === "object" && !Array.isArray(value);
21383
22222
  }
@@ -21466,7 +22305,7 @@ function reasoningOf(part) {
21466
22305
  function renderPartPreview(part, expandTools) {
21467
22306
  if (!isRecord4(part))
21468
22307
  return null;
21469
- const expansion = expandToolPart(part, expandTools);
22308
+ const expansion = expandToolPart(part, expandTools, true);
21470
22309
  if (expansion !== null)
21471
22310
  return ` • tool ${part.tool}: ${expansion}`;
21472
22311
  const text = textOf(part);
@@ -21530,7 +22369,7 @@ function renderMessageByOrdinal(sessionId, ordinal) {
21530
22369
  });
21531
22370
  const msg = found[0];
21532
22371
  if (!msg) {
21533
- return `No message at ordinal ${ordinal} in this session's stored history — it was deleted ` + `(session prune/revert) or the ordinal is wrong, so it can't be recovered. ` + `Re-run the tool if you still need the data.`;
22372
+ return `No message at ordinal ${ordinal} is currently in this session's stored history — ` + `it may have been removed by a session prune/revert, or the ordinal may be wrong. ` + `Re-run the tool if you still need the data.`;
21534
22373
  }
21535
22374
  const rendered = msg.parts.map(renderPartFull).filter((l) => l !== null);
21536
22375
  const lines = [`[${msg.ordinal}] ${roleLabel(msg.role)} — full recovery:`, ""];
@@ -21601,9 +22440,12 @@ function renderItemByTag(db, sessionId, number, textIndexDomain = "part") {
21601
22440
  const index = scoped ? Number(scoped[2]) : 0;
21602
22441
  const piText = message.parts.filter((part) => isRecord4(part) && part.type === "text");
21603
22442
  const part = message.parts[index];
21604
- const matching = derived ? piText.filter((part) => isRecord4(part) && typeof part.text === "string" && createHash7("sha256").update(part.text).digest("hex") === derived[3]) : [];
22443
+ const matching = derived ? piText.filter((part) => isRecord4(part) && typeof part.text === "string" && createHash8("sha256").update(part.text).digest("hex") === derived[3]) : [];
21605
22444
  const selected = derived ? matching[Number(derived[4])] : textIndexDomain === "text" ? piText[index] : part;
21606
- return selected ? renderPartFull(selected) ?? "" : `Tag ${number}'s original text part is no longer in stored history.`;
22445
+ if (!selected)
22446
+ return `Tag ${number}'s original text part is no longer in stored history.`;
22447
+ const renderedPart = renderPartFull(selected);
22448
+ return renderedPart !== null ? renderedPart : `Tag ${number}'s stored text part has no renderable content (empty or structural-only); the requested content was not recovered.`;
21607
22449
  }
21608
22450
 
21609
22451
  // src/tools/ctx-expand/tools.ts
@@ -21629,52 +22471,57 @@ function createCtxExpandTool(deps) {
21629
22471
  message: "number"
21630
22472
  });
21631
22473
  const sessionId = toolContext.sessionID;
21632
- const mode = resolveCtxExpandMode(args, "positive");
21633
- if (mode.kind === "error") {
21634
- return mode.message;
21635
- }
21636
- if (mode.kind === "tag") {
21637
- return renderItemByTag(deps.db, sessionId, mode.tag);
21638
- }
21639
- if (mode.kind === "message") {
21640
- return renderMessageByOrdinal(sessionId, mode.message);
21641
- }
21642
- const { start, end, verbose } = mode;
21643
- const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
21644
- if (lastCompartmentEnd >= 0 && start > lastCompartmentEnd) {
21645
- return `Range ${start}-${end} is entirely within the live tail (after the last compacted message ${lastCompartmentEnd}); those messages are already visible in context.`;
21646
- }
21647
- const effectiveEnd = lastCompartmentEnd >= 0 ? Math.min(end, lastCompartmentEnd) : end;
21648
- if (verbose) {
21649
- const v = renderVerboseRange(sessionId, start, effectiveEnd, CTX_EXPAND_TOKEN_BUDGET, deps.expandTools);
21650
- if (!v.text) {
21651
- return `No messages found in range ${start}-${effectiveEnd}. The range may be outside this session's history.`;
22474
+ try {
22475
+ const mode = resolveCtxExpandMode(args, "positive");
22476
+ if (mode.kind === "error") {
22477
+ return mode.message;
21652
22478
  }
21653
- const out = [
21654
- `Messages ${start}-${v.lastOrdinal} (verbose). Recover any one in full with mmc_expand(message=<ordinal>):`,
21655
- "",
21656
- v.text
21657
- ];
21658
- if (v.truncated) {
21659
- out.push("", `Truncated at message ${v.lastOrdinal} (budget: ~${CTX_EXPAND_TOKEN_BUDGET} tokens). Call again with start=${v.lastOrdinal + 1} end=${effectiveEnd} verbose=true for more.`);
22479
+ if (mode.kind === "tag") {
22480
+ return renderItemByTag(deps.db, sessionId, mode.tag);
21660
22481
  }
21661
- return out.join(`
22482
+ if (mode.kind === "message") {
22483
+ return renderMessageByOrdinal(sessionId, mode.message);
22484
+ }
22485
+ const { start, end, verbose } = mode;
22486
+ const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
22487
+ if (lastCompartmentEnd >= 0 && start > lastCompartmentEnd) {
22488
+ return `Range ${start}-${end} is entirely within the live tail (after the last compacted message ${lastCompartmentEnd}); those messages are already visible in context.`;
22489
+ }
22490
+ const effectiveEnd = lastCompartmentEnd >= 0 ? Math.min(end, lastCompartmentEnd) : end;
22491
+ if (verbose) {
22492
+ const v = renderVerboseRange(sessionId, start, effectiveEnd, CTX_EXPAND_TOKEN_BUDGET, deps.expandTools);
22493
+ if (!v.text) {
22494
+ return `No messages found in range ${start}-${effectiveEnd}. The range may be outside this session's history.`;
22495
+ }
22496
+ const out = [
22497
+ `Messages ${start}-${v.lastOrdinal} (verbose). Recover any one in full with mmc_expand(message=<ordinal>):`,
22498
+ "",
22499
+ v.text
22500
+ ];
22501
+ if (v.truncated) {
22502
+ out.push("", `Truncated at message ${v.lastOrdinal} (budget: ~${CTX_EXPAND_TOKEN_BUDGET} tokens). Call again with start=${v.lastOrdinal + 1} end=${effectiveEnd} verbose=true for more.`);
22503
+ }
22504
+ return out.join(`
21662
22505
  `);
21663
- }
21664
- const chunk = readSessionChunk2(sessionId, CTX_EXPAND_TOKEN_BUDGET, start, effectiveEnd + 1, { expand: false });
21665
- if (!chunk.text || chunk.messageCount === 0) {
21666
- return `No messages found in range ${start}-${end}. The range may be outside this session's history.`;
21667
- }
21668
- const lines = [];
21669
- lines.push(`Messages ${chunk.startIndex}-${chunk.endIndex} (${chunk.messageCount} messages, ~${chunk.tokenEstimate} tokens):`);
21670
- lines.push("");
21671
- lines.push(chunk.text);
21672
- if (chunk.endIndex < effectiveEnd) {
22506
+ }
22507
+ const chunk = readSessionChunk2(sessionId, CTX_EXPAND_TOKEN_BUDGET, start, effectiveEnd + 1, { expand: false });
22508
+ if (!chunk.text || chunk.messageCount === 0) {
22509
+ return `No messages found in range ${start}-${end}. The range may be outside this session's history.`;
22510
+ }
22511
+ const lines = [];
22512
+ lines.push(`Messages ${chunk.startIndex}-${chunk.endIndex} (${chunk.messageCount} messages, ~${chunk.tokenEstimate} tokens):`);
21673
22513
  lines.push("");
21674
- lines.push(`Truncated at message ${chunk.endIndex} (budget: ~${CTX_EXPAND_TOKEN_BUDGET} tokens). Call again with start=${chunk.endIndex + 1} end=${effectiveEnd} for more.`);
21675
- }
21676
- return lines.join(`
22514
+ lines.push(chunk.text);
22515
+ if (chunk.endIndex < effectiveEnd) {
22516
+ lines.push("");
22517
+ lines.push(`Truncated at message ${chunk.endIndex} (budget: ~${CTX_EXPAND_TOKEN_BUDGET} tokens). Call again with start=${chunk.endIndex + 1} end=${effectiveEnd} for more.`);
22518
+ }
22519
+ return lines.join(`
21677
22520
  `);
22521
+ } catch (error) {
22522
+ const message = error instanceof Error ? error.message : String(error);
22523
+ return `Error: mmc_expand failed to read this session's stored history: ${message}`;
22524
+ }
21678
22525
  }
21679
22526
  });
21680
22527
  }
@@ -22912,6 +23759,9 @@ function persistV2UsageReading(args) {
22912
23759
 
22913
23760
  // src/v2/hooks/context.ts
22914
23761
  var HIDDEN_SESSION_ERROR_GRACE_MS = 50;
23762
+
23763
+ class V2LkgAdmissionReplay extends Error {
23764
+ }
22915
23765
  function isBlockingV2TransformError(error) {
22916
23766
  return error instanceof EmergencyFailClosedError || error instanceof UnresolvedHistoryBoundaryError || error instanceof UnmanagedOverWindowError || error instanceof DegradedPassRefusalError || isFailClosedBlockingError(error);
22917
23767
  }
@@ -23120,6 +23970,8 @@ async function registerContext(context) {
23120
23970
  return;
23121
23971
  }
23122
23972
  const folds = new FoldOwner(context.storage);
23973
+ const nativeFoldMemory = !compactionOff && process.env.MMC_OC2_INVISIBLE_FOLD === "1" ? nativeFoldCache(() => storage.require()) : undefined;
23974
+ const nativeFoldReplay = nativeFoldMemory ? new NativeFoldReplay(nativeFoldMemory, () => openStoreReader()) : undefined;
23123
23975
  setOutputReserveConfig(config.output_reserve);
23124
23976
  const queriedModels = new Set;
23125
23977
  const rawLimits = new Map;
@@ -23151,7 +24003,7 @@ async function registerContext(context) {
23151
24003
  let storageRecoveryAnnounced = false;
23152
24004
  const storageNoticeBySession = new Map;
23153
24005
  const storeStorageNotice = (sessionID, text, what) => {
23154
- withoutSqliteTransformPass(() => context.session.wait({ sessionID }).then(() => deliverSynthetic(context, sessionID, text)).catch((error) => sessionLog(sessionID, `v2 storage ${what} notice could not be delivered:`, error)));
24006
+ withoutSqliteTransformPass(() => Promise.resolve().then(() => context.session.wait({ sessionID })).then(() => deliverSynthetic(context, sessionID, text)).catch((error) => sessionLog(sessionID, `v2 storage ${what} notice could not be delivered:`, error)));
23155
24007
  };
23156
24008
  const noticeStorageRefusal = (sessionID, reason) => {
23157
24009
  const message = formatStorageRefusalNotice(reason);
@@ -23418,6 +24270,14 @@ async function registerContext(context) {
23418
24270
  }
23419
24271
  return unsafe;
23420
24272
  };
24273
+ const hostFolds = nativeFoldReplay && nativeFoldMemory ? new HostFoldPolicy({
24274
+ session: context.session,
24275
+ storage: nativeFoldMemory,
24276
+ openReader: openStoreReader,
24277
+ canReplay: (sessionID, reader) => nativeFoldReplay.canReplay(sessionID, reader),
24278
+ threshold: Number(process.env.MMC_OC2_HOST_FOLD_ROWS ?? 1000),
24279
+ log: sessionLog
24280
+ }) : undefined;
23421
24281
  const usageController = new AbortController;
23422
24282
  const usageDone = (async () => {
23423
24283
  try {
@@ -23428,6 +24288,10 @@ async function registerContext(context) {
23428
24288
  if (!event.data?.sessionID)
23429
24289
  continue;
23430
24290
  const sessionID = event.data.sessionID;
24291
+ if (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated") {
24292
+ nativeFoldReplay?.onEvent(event);
24293
+ restoredRows.forget(sessionID);
24294
+ }
23431
24295
  if (event.type === "session.error" || event.type === "session.execution.failed") {
23432
24296
  const error = hiddenTerminalError(event);
23433
24297
  if (error !== undefined)
@@ -23453,6 +24317,7 @@ async function registerContext(context) {
23453
24317
  pendingMaterializationSessions.delete(sessionID);
23454
24318
  lastHeuristicsTurnId.delete(sessionID);
23455
24319
  restoredRows.forget(sessionID);
24320
+ await nativeFoldReplay?.forget(sessionID);
23456
24321
  generateReplay.forget(sessionID);
23457
24322
  systemPromptRefreshSessions.delete(sessionID);
23458
24323
  systemPrompt?.clearSession(sessionID);
@@ -23465,11 +24330,14 @@ async function registerContext(context) {
23465
24330
  if (event.type !== "session.execution.succeeded")
23466
24331
  continue;
23467
24332
  const model = liveModels.get(sessionID);
23468
- if (model)
24333
+ if (model) {
23469
24334
  await recordUsage({
23470
24335
  sessionID,
23471
24336
  model: { providerID: model.providerID, id: model.modelID }
23472
24337
  });
24338
+ if (!compactionOff && typeof await nativeFoldReplay?.baseline(sessionID) === "string")
24339
+ hostFolds?.idle(sessionID);
24340
+ }
23473
24341
  }
23474
24342
  } catch (error) {
23475
24343
  if (!usageController.signal.aborted)
@@ -23504,10 +24372,32 @@ async function registerContext(context) {
23504
24372
  }
23505
24373
  if (compactionOff)
23506
24374
  return;
24375
+ if (nativeFoldReplay)
24376
+ rememberHostMedia(draft.messages);
23507
24377
  const reader = openStoreReader();
23508
24378
  try {
23509
24379
  const watermark = reader.latestSequenceForIds(draft.sessionID, draft.messages.flatMap((message) => message.id ? [message.id] : []));
23510
24380
  const running = reader.latestRunningCompaction(draft.sessionID);
24381
+ if (nativeFoldReplay) {
24382
+ try {
24383
+ if (await nativeFoldReplay.canReplay(draft.sessionID, reader)) {
24384
+ const state = getOrCreateSessionMeta(storage.require(), draft.sessionID);
24385
+ const summary = await nativeFoldReplay.baseline(draft.sessionID) ?? state.cachedM0Bytes?.toString("utf8") ?? "<session-history></session-history>";
24386
+ if (await nativeFoldReplay.supply({
24387
+ draft,
24388
+ reader,
24389
+ previousCut: reader.latestCompaction(draft.sessionID),
24390
+ summary
24391
+ })) {
24392
+ draft.result = { summary };
24393
+ return;
24394
+ }
24395
+ }
24396
+ } catch (error) {
24397
+ nativeFoldReplay.invalidate(draft.sessionID, true);
24398
+ sessionLog(draft.sessionID, `v2 host fold: legacy compaction reason=${JSON.stringify(String(error))}`);
24399
+ }
24400
+ }
23511
24401
  const fold = await folds.supply({
23512
24402
  sessionID: draft.sessionID,
23513
24403
  watermark,
@@ -23554,12 +24444,88 @@ async function registerContext(context) {
23554
24444
  withoutSqliteTransformPass(() => warmModelLimitCacheFromCatalog(context));
23555
24445
  agents.set(draft.sessionID, draft.agent);
23556
24446
  applyV2PromptSurfaceTools(draft, promptSurfaceRuntime, config.prompt_surface);
24447
+ const admissionDb = db ?? storage.current();
24448
+ const replayFits = (messages) => {
24449
+ const system = structuredClone(draft.system);
24450
+ if (!admissionDb || !draft.tools || !lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), draft.system, system))
24451
+ return false;
24452
+ const limit = lkgReplayLimit({
24453
+ db: admissionDb,
24454
+ sessionId: draft.sessionID,
24455
+ model: {
24456
+ providerID: draft.model.providerID,
24457
+ modelID: draft.model.id
24458
+ },
24459
+ modelKey: `${draft.model.providerID}/${draft.model.id}`
24460
+ });
24461
+ if (limit === undefined)
24462
+ return false;
24463
+ let toolDefinitionTokens = 0;
24464
+ for (const tool of Object.values(draft.tools)) {
24465
+ if (!tool || typeof tool.description !== "string" || !tool.input)
24466
+ return false;
24467
+ const schema = JSON.stringify(tool.input);
24468
+ if (!schema)
24469
+ return false;
24470
+ toolDefinitionTokens += estimateTokens(tool.description) + estimateTokens(schema);
24471
+ }
24472
+ return measureLkgReplay({
24473
+ messages,
24474
+ limit,
24475
+ estimate: () => estimateFinalWireInputTokens({
24476
+ messages,
24477
+ toolDefinitionTokens,
24478
+ systemPromptTokens: estimateTokens(JSON.stringify(system)),
24479
+ providerID: draft.model.providerID,
24480
+ modelID: draft.model.id,
24481
+ agentName: draft.agent
24482
+ })
24483
+ }).fit === "under";
24484
+ };
23557
24485
  let postFold = false;
23558
24486
  try {
23559
- const admissionDb = db ?? storage.current();
23560
24487
  if (!compactionOff && admissionDb)
23561
24488
  await withAsyncPrivilegedWriter(admissionDb, () => {
23562
24489
  return;
24490
+ }, {
24491
+ beforeRetry: (_error) => {
24492
+ let replayBlocked = false;
24493
+ const mapped = adaptPayload(draft);
24494
+ try {
24495
+ const overflowDb = db;
24496
+ if (overflowDb !== undefined && overflowDb !== null && (isEmergencyRecoveryArmed(draft.sessionID) || getOverflowState(overflowDb, draft.sessionID).needsEmergencyRecovery)) {
24497
+ replayBlocked = true;
24498
+ sessionLog(draft.sessionID, "lkg_emergency_armed");
24499
+ } else {
24500
+ const keys = resolveLkgModelKeys(mapped.messages);
24501
+ const replay = replayLkg({
24502
+ sessionId: draft.sessionID,
24503
+ messages: mapped.messages,
24504
+ modelKey: keys.modelKey,
24505
+ providerKey: keys.providerKey
24506
+ });
24507
+ if (replay.ok && !replayFits(replay.messages)) {
24508
+ replayBlocked = true;
24509
+ sessionLog(draft.sessionID, "lkg_replay_does_not_fit");
24510
+ } else if (replay.ok) {
24511
+ restoreLkgSystem();
24512
+ mapped.messages.splice(0, mapped.messages.length, ...replay.messages);
24513
+ mapped.commit();
24514
+ sessionLog(draft.sessionID, "lkg_replay_served");
24515
+ throw new V2LkgAdmissionReplay;
24516
+ } else {
24517
+ sessionLog(draft.sessionID, replay.reason);
24518
+ }
24519
+ }
24520
+ } catch (replayError) {
24521
+ if (replayError instanceof V2LkgAdmissionReplay)
24522
+ throw replayError;
24523
+ replayBlocked = true;
24524
+ sessionLog(draft.sessionID, "lkg_replay_unavailable", replayError);
24525
+ }
24526
+ if (replayBlocked)
24527
+ sessionLog(draft.sessionID, "lkg_replay_declined");
24528
+ }
23563
24529
  });
23564
24530
  if (admissionDb)
23565
24531
  hideSubagentTools(draft, admissionDb);
@@ -23714,7 +24680,28 @@ async function registerContext(context) {
23714
24680
  postFold = cut !== undefined;
23715
24681
  if (cut && !incoming)
23716
24682
  throw new Error("The host checkpoint disappeared from the context draft");
23717
- if (cut && incoming) {
24683
+ let nativeRestored;
24684
+ if (cut && nativeFoldReplay && isLocalCheckpoint(cut)) {
24685
+ try {
24686
+ nativeRestored = await nativeFoldReplay.restore(draft.sessionID, cut, `${draft.model.providerID}/${draft.model.id}`, { bounded: true });
24687
+ } catch (error) {
24688
+ nativeFoldReplay.invalidate(draft.sessionID, true);
24689
+ sessionLog(draft.sessionID, "v2 host fold: cache unavailable; restoring host rows", error);
24690
+ nativeRestored = await nativeFoldReplay.restoreRead(draft.sessionID, cut, draft.model);
24691
+ }
24692
+ }
24693
+ if (nativeRestored && nativeFoldReplay?.sourceChanged(draft.sessionID)) {
24694
+ historyRefreshSessions.add(draft.sessionID);
24695
+ pendingMaterializationSessions.add(draft.sessionID);
24696
+ }
24697
+ if (cut && incoming && nativeRestored) {
24698
+ const present = new Set(draft.messages.flatMap((message) => message.id ? [message.id] : []));
24699
+ const hidden = nativeRestored.filter((message) => {
24700
+ const id = nativeRowID(message);
24701
+ return !id || !present.has(id);
24702
+ });
24703
+ draft.messages.splice(0, draft.messages.length, ...hidden, ...draft.messages.filter((message) => message !== incoming));
24704
+ } else if (cut && incoming) {
23718
24705
  const identity = await folds.observe({
23719
24706
  sessionID: draft.sessionID,
23720
24707
  cutSeq: cut.seq,
@@ -23741,6 +24728,14 @@ async function registerContext(context) {
23741
24728
  } finally {
23742
24729
  reader.close();
23743
24730
  }
24731
+ let nativeMessages;
24732
+ if (nativeFoldReplay) {
24733
+ try {
24734
+ nativeMessages = copyNativeInput(draft.messages);
24735
+ } catch {
24736
+ nativeFoldReplay.invalidate(draft.sessionID, true);
24737
+ }
24738
+ }
23744
24739
  const mapped = adaptPayload(draft, admitted);
23745
24740
  beginV2LkgRequest(draft.sessionID, `${draft.model.providerID}/${draft.model.id}`, latestLkgResponseIds.get(draft.sessionID));
23746
24741
  await transform({}, mapped);
@@ -23766,6 +24761,14 @@ ${baseline}
23766
24761
  draft.messages.splice(0, draft.messages.length, checkpoint, ...draft.messages.filter((message) => message !== head));
23767
24762
  }
23768
24763
  }
24764
+ if (nativeMessages && !checkpoint) {
24765
+ try {
24766
+ await nativeFoldReplay?.capture(draft, nativeMessages);
24767
+ } catch (error) {
24768
+ nativeFoldReplay?.invalidate(draft.sessionID, true);
24769
+ sessionLog(draft.sessionID, "v2 host fold: optional capture unavailable", error);
24770
+ }
24771
+ }
23769
24772
  const capturedSlot = getSlot(draft.sessionID);
23770
24773
  if (capturedSlot && (!slotAtEntry || capturedSlot.capturedAt !== slotAtEntry.capturedAt || capturedSlot.captureSequence !== slotAtEntry.captureSequence || capturedSlot.jsonPrefix !== slotAtEntry.jsonPrefix)) {
23771
24774
  lkgSystems.capture(draft.sessionID, capturedSlot, systemAtEntry, draft.system);
@@ -23773,6 +24776,8 @@ ${baseline}
23773
24776
  } catch (error) {
23774
24777
  if (error instanceof V2ContextRefusal)
23775
24778
  throw error;
24779
+ if (error instanceof V2LkgAdmissionReplay)
24780
+ return;
23776
24781
  if (!compactionOff && (isTransientSqliteError(error) || error instanceof StorageBusyRefusalError)) {
23777
24782
  if (isTransientSqliteError(error)) {
23778
24783
  try {
@@ -23800,13 +24805,16 @@ ${baseline}
23800
24805
  modelKey: keys.modelKey,
23801
24806
  providerKey: keys.providerKey
23802
24807
  });
23803
- if (replay.ok) {
24808
+ if (replay.ok && !replayFits(replay.messages)) {
24809
+ sessionLog(draft.sessionID, "lkg_replay_does_not_fit");
24810
+ } else if (replay.ok) {
23804
24811
  restoreLkgSystem();
23805
24812
  replayMapped.messages.splice(0, replayMapped.messages.length, ...replay.messages);
23806
24813
  replayMapped.commit();
23807
24814
  return;
24815
+ } else {
24816
+ sessionLog(draft.sessionID, replay.reason);
23808
24817
  }
23809
- sessionLog(draft.sessionID, replay.reason);
23810
24818
  }
23811
24819
  } catch (replayError) {
23812
24820
  replayBlocked = true;