@cortexkit/pi-magic-context 0.49.0 → 0.49.2

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 (31) hide show
  1. package/dist/auto-search-worker.js +3 -3
  2. package/dist/{embedding-backfill-b71dvfs8.js → embedding-backfill-scywarbn.js} +7 -7
  3. package/dist/embedding-worker-process.js +29 -0
  4. package/dist/embedding-worker.js +5 -5
  5. package/dist/index-0j0zqb4t.js +712 -0
  6. package/dist/{index-hwqb3s7f.js → index-0rasmwm8.js} +5 -5
  7. package/dist/{index-bejpsj10.js → index-27jh224p.js} +1 -1
  8. package/dist/{index-ehybv5nr.js → index-28vnkyy7.js} +1129 -2990
  9. package/dist/{index-r024r8da.js → index-4gfq5t09.js} +16 -1
  10. package/dist/{index-vf38qhee.js → index-81nthk8j.js} +44 -1
  11. package/dist/{index-yzcjxnt2.js → index-b2anqqad.js} +422 -6
  12. package/dist/{index-1evzceyw.js → index-cyrnv16r.js} +314 -1072
  13. package/dist/index-fqb1bddn.js +4947 -0
  14. package/dist/{index-041ex0cj.js → index-g7hndmqm.js} +20 -34
  15. package/dist/index-gc2749rx.js +1168 -0
  16. package/dist/{index-t7xfqtg6.js → index-p5zesr4e.js} +22 -718
  17. package/dist/{index-yarjn32j.js → index-r874cgmv.js} +38 -36
  18. package/dist/{index-3mgf68pn.js → index-rd53pk0h.js} +1 -1
  19. package/dist/{index-904reqtg.js → index-rdtgp48t.js} +6 -4
  20. package/dist/index.js +1637 -1126
  21. package/dist/{message-index-bounded-qz5dz2se.js → message-index-bounded-110sb4fm.js} +6 -5
  22. package/dist/migration-worker.js +6 -5
  23. package/dist/{project-embedding-registry-ky7wrkr1.js → project-embedding-registry-64t0mw8y.js} +6 -6
  24. package/dist/raw-ordinal-warmup-worker.js +1 -1
  25. package/dist/{read-session-chunk-24sd89tf.js → read-session-chunk-rvmc25n5.js} +3 -2
  26. package/dist/{search-jbh28nwy.js → search-7z3w8pmz.js} +15 -14
  27. package/dist/subagent-entry.js +17 -16
  28. package/package.json +3 -3
  29. package/dist/index-3rea6zd9.js +0 -2396
  30. package/dist/index-bgmv2kaf.js +0 -290
  31. /package/dist/{index-5prbx026.js → index-2pp04pmg.js} +0 -0
package/dist/index.js CHANGED
@@ -27,9 +27,6 @@ import {
27
27
  detectConfigFile,
28
28
  MIN_PLAUSIBLE_CONTEXT_LIMIT,
29
29
  catalogOutputReserve,
30
- reloadWindowOverlay,
31
- getWindowOverlay,
32
- resolveWindowOverlayFacts,
33
30
  deriveWindowGeometry,
34
31
  hasTrustedAbsoluteWall,
35
32
  applyProvenInputFloor,
@@ -45,101 +42,6 @@ import {
45
42
  cortexKitProjectConfigBasePath,
46
43
  migrateMagicContextConfigLocations,
47
44
  getProtectedTokensTierOverrides,
48
- MAX_EXECUTE_THRESHOLD,
49
- escalationBands,
50
- decodeMergedReasoningParts,
51
- HYGIENE_PROVIDER_UNITS_VERSION,
52
- sessionDecisionCalibration,
53
- transitionSessionHygieneUnits,
54
- computeProtectionWindow,
55
- readEpochFloorSnapshot,
56
- getProtectionWindowForSession,
57
- ensureSessionMetaRow,
58
- persistCachedM0,
59
- clearCachedM0M1,
60
- isRustMarkerAdmissionFenced,
61
- ReplayDocumentError,
62
- readReplayEnvelope,
63
- updateReplayDocument,
64
- isProviderOverflowFailClosedProven,
65
- describeProtectedTailDrainBudgetSkip,
66
- loadProtectedTailMeta,
67
- markProtectedTailPolicyV3Seeded,
68
- recordProtectedTailPublicationFloor,
69
- recordProtectedTailNoEligibleHead,
70
- getWrapupInProgressState,
71
- isWrapupInProgress,
72
- acquireWrapupInProgress,
73
- updateWrapupInProgress,
74
- releaseWrapupInProgress,
75
- resolveCompactionModeRecord,
76
- getCompactionModeRecord,
77
- setCompactionModeRecord,
78
- getProtectedTailDrainBudgetSkip,
79
- reserveProtectedTailDrainTokens,
80
- clearEmergencyDrainLatch,
81
- recordHistorianDrainFailure,
82
- clearHistorianDrainFailure,
83
- rollbackProtectedTailDrainReservation,
84
- clearPersistedReasoningWatermark,
85
- getEmergencyInputSample,
86
- setEmergencyDropSample,
87
- clearEmergencyDropSample,
88
- getLastNudgeUndropped,
89
- setLastNudgeUndropped,
90
- getChannel1NudgeState,
91
- setChannel1NudgeState,
92
- markChannel1PostReduceGracePending,
93
- captureChannel1PostReduceGraceBaseline,
94
- getChannel2NudgeState,
95
- getChannel2NudgeClaim,
96
- setChannel2NudgeState,
97
- casChannel2NudgeState,
98
- claimChannel2NudgeState,
99
- casChannel2NudgeClaim,
100
- getPersistedNoteNudge,
101
- setPersistedNoteNudgeTrigger,
102
- setPersistedNoteNudgeTriggerMessageId,
103
- getNoteNudgeAnchors,
104
- getAutoSearchHintDecisions,
105
- deliverNoteNudgeAtomic,
106
- appendAutoSearchHintDecision,
107
- pruneNoteNudgeAnchors,
108
- queueAutoSearchHintDecisionRetirement,
109
- flushAutoSearchHintDecisionRetirement,
110
- getPersistedTodoSyntheticAnchor,
111
- setPersistedTodoSyntheticAnchor,
112
- clearPersistedTodoSyntheticAnchor,
113
- getNoteLastReadAt,
114
- getHistorianFailureState,
115
- incrementHistorianFailure,
116
- clearHistorianFailureState,
117
- getOverflowState,
118
- recordOverflowDetected,
119
- clearEmergencyRecovery,
120
- clearDetectedContextLimit,
121
- getStrippedPlaceholderIds,
122
- applyStrippedPlaceholderDelta,
123
- THINKING_BINDING_RECOVERY_FROZEN_PREFIX,
124
- THINKING_BINDING_STRIP_ORDER_END_MARKER,
125
- thinkingBindingRecoveryFrozenId,
126
- getThinkingBindingRecoveryTarget,
127
- armThinkingBindingRecovery,
128
- clearThinkingBindingRecoveryIf,
129
- getMergedReasoningStrippedIds,
130
- addMergedReasoningStrippedIds,
131
- getProcessedImageStrippedIds,
132
- addProcessedImageStrippedIds,
133
- getPendingCompactionMarkerState,
134
- getCompactionMarkerHealth,
135
- clearPendingCompactionMarkerStateIf,
136
- getPendingPiCompactionMarkerState,
137
- setPendingPiCompactionMarkerState,
138
- clearPendingPiCompactionMarkerStateIf,
139
- getSessionsWithPendingPiMarker,
140
- setSessionWorkMetrics,
141
- getSessionWorkMetrics,
142
- resolveEpochFloorForPass,
143
45
  rememberUnpublishedAutoSearchNoHint,
144
46
  getUnpublishedAutoSearchNoHint,
145
47
  forgetUnpublishedAutoSearchNoHint,
@@ -182,9 +84,23 @@ import {
182
84
  getUncoveredCompartmentEndThrough,
183
85
  isPartialCompartmentEnd,
184
86
  readProjectDocsCanonical,
185
- BoundedSessionMap,
186
87
  providerResponseFailed,
187
88
  isSuccessfulProviderCompletion,
89
+ requestPendingMaterialization,
90
+ pendingMaterializationOrigin,
91
+ clearPendingMaterialization,
92
+ recordSystemRefreshOwnership,
93
+ recordSystemPromptForRequest,
94
+ recordHeldHeadForRequest,
95
+ bindSystemPromptResponse,
96
+ acknowledgeSystemPromptDelivery,
97
+ deferDeliveredSystemRefresh,
98
+ clearSystemPromptDelivery,
99
+ saveLkgSlotToDb,
100
+ loadPersistedLkgSlot,
101
+ drainStaleLkgSlots,
102
+ createDbLkgPersistence,
103
+ replayLkg,
188
104
  registerLkgPersistence,
189
105
  LKG_SNAPSHOT_ARRAY,
190
106
  LKG_SNAPSHOT_OBJECT,
@@ -208,7 +124,6 @@ import {
208
124
  getInMemorySlot,
209
125
  getSlot,
210
126
  dropSlot,
211
- noteEntry,
212
127
  TOOL_SWEEP_SCOPED_MARKER,
213
128
  encodePiContentDecision,
214
129
  decodePiContentDecision,
@@ -331,8 +246,14 @@ import {
331
246
  registerTodoStateLifecycle,
332
247
  syncCtxMemoryToolEnabled,
333
248
  registerMagicContextTools
334
- } from "./index-ehybv5nr.js";
249
+ } from "./index-28vnkyy7.js";
335
250
  import {
251
+ canonicalModelIdentity,
252
+ piModelRefToCanonical,
253
+ resolveModelRefForPi,
254
+ modelRefLookupOrder,
255
+ ompModelRefToCanonical,
256
+ resolveModelRefForOmp,
336
257
  isValidLanguageCode,
337
258
  withContentLanguageDirective,
338
259
  parseCron,
@@ -342,15 +263,7 @@ import {
342
263
  DEFAULT_HISTORIAN_TIMEOUT_MS,
343
264
  DREAM_TASK_PROMOTION_DEFAULTS,
344
265
  LIVE_RELOAD_CONFIG_PATHS
345
- } from "./index-1evzceyw.js";
346
- import {
347
- canonicalModelIdentity,
348
- piModelRefToCanonical,
349
- resolveModelRefForPi,
350
- modelRefLookupOrder,
351
- ompModelRefToCanonical,
352
- resolveModelRefForOmp
353
- } from "./index-bgmv2kaf.js";
266
+ } from "./index-cyrnv16r.js";
354
267
  import {
355
268
  FAIL_CLOSED_DOCTOR_COMMAND,
356
269
  formatFailClosedBlockingMessage,
@@ -358,7 +271,6 @@ import {
358
271
  isFailClosedBlockingError,
359
272
  shouldBypassFailClosedBlock,
360
273
  createFailClosedController,
361
- piHarnessKindFromExecutable,
362
274
  getErrorMessage,
363
275
  describeError,
364
276
  startBootDeadline,
@@ -374,9 +286,8 @@ import {
374
286
  openCurrentDatabase,
375
287
  openDatabaseAsync,
376
288
  closeDatabase
377
- } from "./index-t7xfqtg6.js";
289
+ } from "./index-p5zesr4e.js";
378
290
  import {
379
- sameProjectDirectory,
380
291
  setHomeProjectPermission,
381
292
  ProjectIdentityError,
382
293
  resolveProjectIdentityStrict,
@@ -386,12 +297,106 @@ import {
386
297
  resolveProjectIdentityForSession,
387
298
  beginBootQuietPeriod,
388
299
  scheduleAfterBootQuiet
389
- } from "./index-041ex0cj.js";
300
+ } from "./index-g7hndmqm.js";
390
301
  import {
391
302
  detectThinkingBindingMismatch,
392
303
  detectLatestTurnThinkingMismatch,
393
304
  isPrefixBoundThinkingModel,
394
305
  detectOverflow,
306
+ MAX_EXECUTE_THRESHOLD,
307
+ escalationBands,
308
+ decodeMergedReasoningParts,
309
+ HYGIENE_PROVIDER_UNITS_VERSION,
310
+ sessionDecisionCalibration,
311
+ transitionSessionHygieneUnits,
312
+ computeProtectionWindow,
313
+ readEpochFloorSnapshot,
314
+ getProtectionWindowForSession,
315
+ ensureSessionMetaRow,
316
+ persistCachedM0,
317
+ clearCachedM0M1,
318
+ ReplayDocumentError,
319
+ readReplayEnvelope,
320
+ updateReplayDocument,
321
+ isProviderOverflowFailClosedProven,
322
+ describeProtectedTailDrainBudgetSkip,
323
+ loadProtectedTailMeta,
324
+ markProtectedTailPolicyV3Seeded,
325
+ recordProtectedTailPublicationFloor,
326
+ recordProtectedTailNoEligibleHead,
327
+ getWrapupInProgressState,
328
+ isWrapupInProgress,
329
+ acquireWrapupInProgress,
330
+ updateWrapupInProgress,
331
+ releaseWrapupInProgress,
332
+ resolveCompactionModeRecord,
333
+ getCompactionModeRecord,
334
+ setCompactionModeRecord,
335
+ getProtectedTailDrainBudgetSkip,
336
+ reserveProtectedTailDrainTokens,
337
+ clearEmergencyDrainLatch,
338
+ recordHistorianDrainFailure,
339
+ clearHistorianDrainFailure,
340
+ rollbackProtectedTailDrainReservation,
341
+ clearPersistedReasoningWatermark,
342
+ getEmergencyInputSample,
343
+ setEmergencyDropSample,
344
+ clearEmergencyDropSample,
345
+ getLastNudgeUndropped,
346
+ setLastNudgeUndropped,
347
+ getChannel1NudgeState,
348
+ setChannel1NudgeState,
349
+ markChannel1PostReduceGracePending,
350
+ captureChannel1PostReduceGraceBaseline,
351
+ getChannel2NudgeState,
352
+ getChannel2NudgeClaim,
353
+ setChannel2NudgeState,
354
+ casChannel2NudgeState,
355
+ claimChannel2NudgeState,
356
+ casChannel2NudgeClaim,
357
+ getPersistedNoteNudge,
358
+ setPersistedNoteNudgeTrigger,
359
+ setPersistedNoteNudgeTriggerMessageId,
360
+ getNoteNudgeAnchors,
361
+ getAutoSearchHintDecisions,
362
+ deliverNoteNudgeAtomic,
363
+ appendAutoSearchHintDecision,
364
+ pruneNoteNudgeAnchors,
365
+ queueAutoSearchHintDecisionRetirement,
366
+ flushAutoSearchHintDecisionRetirement,
367
+ getPersistedTodoSyntheticAnchor,
368
+ setPersistedTodoSyntheticAnchor,
369
+ clearPersistedTodoSyntheticAnchor,
370
+ getNoteLastReadAt,
371
+ getHistorianFailureState,
372
+ incrementHistorianFailure,
373
+ clearHistorianFailureState,
374
+ getOverflowState,
375
+ recordOverflowDetected,
376
+ clearEmergencyRecovery,
377
+ clearDetectedContextLimit,
378
+ getStrippedPlaceholderIds,
379
+ applyStrippedPlaceholderDelta,
380
+ THINKING_BINDING_RECOVERY_FROZEN_PREFIX,
381
+ THINKING_BINDING_STRIP_ORDER_END_MARKER,
382
+ thinkingBindingRecoveryFrozenId,
383
+ getThinkingBindingRecoveryTarget,
384
+ armThinkingBindingRecovery,
385
+ clearThinkingBindingRecoveryIf,
386
+ getMergedReasoningStrippedIds,
387
+ addMergedReasoningStrippedIds,
388
+ getProcessedImageStrippedIds,
389
+ addProcessedImageStrippedIds,
390
+ getPendingCompactionMarkerState,
391
+ getCompactionMarkerHealth,
392
+ clearPendingCompactionMarkerStateIf,
393
+ getPendingPiCompactionMarkerState,
394
+ setPendingPiCompactionMarkerState,
395
+ clearPendingPiCompactionMarkerStateIf,
396
+ getSessionsWithPendingPiMarker,
397
+ setSessionWorkMetrics,
398
+ getSessionWorkMetrics,
399
+ resolveEpochFloorForPass,
395
400
  retreatPastHostUnservedRows,
396
401
  completedToolArcCrossesBoundary,
397
402
  estimateTrueRawMessageTokens,
@@ -416,6 +421,16 @@ import {
416
421
  modelAcceptsEmptyContent,
417
422
  isAnthropicFamilyRoute,
418
423
  variantChangeBustsProviderCache,
424
+ isInActiveAnthropicTurn,
425
+ activeAnthropicTurnStart,
426
+ hasAnthropicReasoning,
427
+ findLatestAssistantReasoningMutationExemptMessage,
428
+ DEFAULT_KEEP_REASONING_TOKENS,
429
+ resolveKeepReasoningTokens,
430
+ reasoningStepCost,
431
+ reasoningBudgetCutoff,
432
+ reasoningTextAndOpaque,
433
+ opaqueThinkingCost,
419
434
  SKELETON_REAL_INPUT_MAX_BYTES,
420
435
  toolInputStringBytes,
421
436
  setRawMessageProvider2,
@@ -435,7 +450,7 @@ import {
435
450
  getRawSessionTagKeysThrough2,
436
451
  getLegacyProtectedTailStartOrdinal2,
437
452
  readSessionChunk2
438
- } from "./index-3rea6zd9.js";
453
+ } from "./index-fqb1bddn.js";
439
454
  import {
440
455
  UNKNOWN_FIT_RATIO,
441
456
  hasMeasuredDecisionCalibration,
@@ -567,20 +582,17 @@ import {
567
582
  RAW_SUMMARY_TEXT_MAX_CHARS2
568
583
  } from "./index-vakawmbc.js";
569
584
  import {
570
- formatSynapseLaneDescriptor
571
- } from "./index-21v1kfs7.js";
572
- import"./index-r024r8da.js";
573
- import {
574
- buildCanonicalChunkTextFromFts,
575
- buildCompartmentSummaryFallbackText,
576
- canonicalizeInMemoryChunkTextForEmbedding,
577
- chunkCanonicalText,
578
- chunkEmbeddingWindowsAreCurrent,
579
- replaceCompartmentChunkEmbeddings,
580
- deleteChunkEmbedBackoffForSession,
581
- chunkWindowSourceKey
582
- } from "./index-bejpsj10.js";
585
+ piHarnessKindFromExecutable
586
+ } from "./index-0j0zqb4t.js";
583
587
  import {
588
+ BoundedSessionMap,
589
+ LkgRecoveryFenceError,
590
+ clearLkgFenceProcessState,
591
+ lkgFenceRequiresRebuild,
592
+ lkgRecoveryFenceUnclean,
593
+ ownsLkgDirtyFence,
594
+ invalidateCleanLkgRecoveryFence,
595
+ markLkgRecoveryDirty,
584
596
  readSessionActivity,
585
597
  observeSessionActivity,
586
598
  backfillSessionActivity,
@@ -594,10 +606,25 @@ import {
594
606
  indexSingleMessage,
595
607
  indexMessagesAfterOrdinal,
596
608
  sweepOrphanedOpenCodeMessageIndexes
597
- } from "./index-yzcjxnt2.js";
609
+ } from "./index-b2anqqad.js";
610
+ import {
611
+ formatSynapseLaneDescriptor
612
+ } from "./index-21v1kfs7.js";
613
+ import {
614
+ sameProjectDirectory
615
+ } from "./index-4gfq5t09.js";
616
+ import {
617
+ buildCanonicalChunkTextFromFts,
618
+ buildCompartmentSummaryFallbackText,
619
+ canonicalizeInMemoryChunkTextForEmbedding,
620
+ chunkCanonicalText,
621
+ chunkEmbeddingWindowsAreCurrent,
622
+ replaceCompartmentChunkEmbeddings,
623
+ deleteChunkEmbedBackoffForSession,
624
+ chunkWindowSourceKey
625
+ } from "./index-27jh224p.js";
598
626
  import {
599
627
  recordSessionProjectIdentity,
600
- drainBackgroundBatches,
601
628
  GIT_SWEEP_LEASE_RENEWAL_MS,
602
629
  acquireGitSweepLease,
603
630
  renewGitSweepLease,
@@ -620,21 +647,19 @@ import {
620
647
  embedSessionCompartmentChunks2,
621
648
  getEmbeddingCoverageStatus2,
622
649
  getAutoEmbeddingSessionCoverage2
623
- } from "./index-yarjn32j.js";
650
+ } from "./index-r874cgmv.js";
624
651
  import {
625
652
  V2_MEMORY_CATEGORIES
626
653
  } from "./index-135e8hvg.js";
627
654
  import {
628
655
  unescapeXml,
629
656
  parseCompartmentOutput,
630
- layoutLkgPrefix,
631
- assembleLkgPrefix,
632
657
  resolveWorkspaceShareCategories,
633
658
  resolveWorkspaceIdentitySet,
634
659
  expandWorkspaceIdentitySetWithAliases,
635
660
  sourceNameForMemory,
636
661
  computeWorkspaceEpochFingerprint
637
- } from "./index-3mgf68pn.js";
662
+ } from "./index-rd53pk0h.js";
638
663
  import {
639
664
  configureContextDatabasePragmas2
640
665
  } from "./index-fapenpch.js";
@@ -684,7 +709,7 @@ import {
684
709
  normalizeVerificationFiles,
685
710
  indexCommitsForProject,
686
711
  embedUnembeddedCommits
687
- } from "./index-hwqb3s7f.js";
712
+ } from "./index-0rasmwm8.js";
688
713
  import {
689
714
  setEmbeddingSessionBusy2,
690
715
  isEmbeddingHostBusy2
@@ -715,9 +740,10 @@ import {
715
740
  import {
716
741
  pushNotification2
717
742
  } from "./index-q1yc6bs0.js";
743
+ import"./index-gc2749rx.js";
718
744
  import {
719
745
  cosineSimilarity
720
- } from "./index-904reqtg.js";
746
+ } from "./index-rdtgp48t.js";
721
747
  import {
722
748
  buildHiddenAgentRegistrations,
723
749
  logTemperatureDecision,
@@ -732,6 +758,9 @@ import {
732
758
  import {
733
759
  computeNormalizedHash
734
760
  } from "./index-9x1f96r8.js";
761
+ import {
762
+ normalizeProtectedToolName
763
+ } from "./index-674f6qs2.js";
735
764
  import {
736
765
  logSlowWriteTransaction,
737
766
  WriteTransactionSteps
@@ -741,10 +770,7 @@ import {
741
770
  ensureStorageDirectorySync,
742
771
  writeStorageFileSync,
743
772
  writeStorageFileAtomicSync
744
- } from "./index-vf38qhee.js";
745
- import {
746
- normalizeProtectedToolName
747
- } from "./index-674f6qs2.js";
773
+ } from "./index-81nthk8j.js";
748
774
 
749
775
  // src/index.ts
750
776
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
@@ -2573,6 +2599,24 @@ function shouldKeepSubagents() {
2573
2599
  return keepSubagents;
2574
2600
  }
2575
2601
 
2602
+ // ../plugin/src/standalone-plugin-marker.ts
2603
+ var markerSymbol = Symbol.for("cortexkit.standalone-plugins");
2604
+ function registerStandalonePluginMarker(version) {
2605
+ try {
2606
+ const globals = globalThis;
2607
+ let registry = globals[markerSymbol];
2608
+ if (registry === undefined) {
2609
+ registry = new Map;
2610
+ globals[markerSymbol] = registry;
2611
+ }
2612
+ registry.set("magic-context", { version });
2613
+ } catch (error) {
2614
+ try {
2615
+ log2("could not register the standalone plugin marker", error);
2616
+ } catch {}
2617
+ }
2618
+ }
2619
+
2576
2620
  // ../plugin/src/shared/host-stall-profiler.ts
2577
2621
  import * as path7 from "node:path";
2578
2622
 
@@ -3366,6 +3410,112 @@ function startHostStallProfilerSwitch() {
3366
3410
  log2("[magic-context] host stall profiler: could not start the enable-file switch", error);
3367
3411
  }
3368
3412
  }
3413
+ // package.json
3414
+ var package_default = {
3415
+ name: "@cortexkit/pi-magic-context",
3416
+ version: "0.49.2",
3417
+ type: "module",
3418
+ description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
3419
+ main: "dist/index.js",
3420
+ license: "MIT",
3421
+ author: "ualtinok",
3422
+ keywords: [
3423
+ "pi",
3424
+ "pi-coding-agent",
3425
+ "omp",
3426
+ "oh-my-pi",
3427
+ "extension",
3428
+ "context",
3429
+ "memory",
3430
+ "magic-context",
3431
+ "ai",
3432
+ "llm"
3433
+ ],
3434
+ repository: {
3435
+ type: "git",
3436
+ url: "https://github.com/cortexkit/magic-context",
3437
+ directory: "packages/pi-plugin"
3438
+ },
3439
+ files: [
3440
+ "dist",
3441
+ "README.md"
3442
+ ],
3443
+ "//": "The build intentionally bundles typebox (no --external typebox) and keeps it a regular dependency. OMP's extension loader rewrites every bare `typebox` import to its own omptype-based shim, whose schemas are callable objects rather than JSON Schema; they fail structuredClone during tool registration, so an external typebox import stops Magic Context loading on OMP. src/typebox-bundling.test.ts guards this.",
3444
+ scripts: {
3445
+ build: "bun ../../scripts/check-bun.mjs && tsc -p ../retina-local-fs/tsconfig.build.json && bun ../../scripts/clean-dist-chunks.mjs dist index.js subagent-entry.js historian-calibration-extension.js embedding-worker-process.js raw-ordinal-warmup-worker.js transformers-web.js transformers-node-wasm.js && bun build ../plugin/src/features/magic-context/memory/transformers-web-entry.ts --outfile dist/transformers-web.js --target browser --format esm --external onnxruntime-web && bun ../plugin/scripts/build-transformers-node-wasm.ts dist && bun build src/index.ts src/subagent-entry.ts src/historian-calibration-extension.ts ../plugin/src/features/magic-context/memory/embedding-worker.ts ../plugin/src/features/magic-context/memory/embedding-worker-process.ts ../plugin/src/features/magic-context/migration-worker.ts ../plugin/src/hooks/magic-context/auto-search-worker.ts ../plugin/src/hooks/magic-context/raw-ordinal-warmup-worker.ts --outdir dist --entry-naming '[name].[ext]' --target node --format esm --splitting --external @earendil-works/pi-coding-agent --external @oh-my-pi/pi-coding-agent --external @earendil-works/pi-tui --external onnxruntime-node --external onnxruntime-web --external sharp --external bun:ffi --external node:sqlite",
3446
+ "build:e2e-argv": `bun ../../scripts/clean-dist-chunks.mjs ../../tests/docker/.generated subagent-runner-e2e.mjs && bun build src/subagent-runner.ts --outdir ../../tests/docker/.generated --entry-naming 'subagent-runner-e2e.mjs' --splitting --target node --format esm --external node:sqlite && node --input-type=module -e 'const { __test } = await import("../../tests/docker/.generated/subagent-runner-e2e.mjs"); if (typeof __test.buildArgs !== "function" || typeof __test.resolvePiInvocation !== "function") throw new Error("argv renderer exports missing"); console.log("Node argv renderer: 2 exports loaded")'`,
3447
+ typecheck: "tsc -p ../retina-local-fs/tsconfig.build.json && tsc --noEmit",
3448
+ test: "bun ../../scripts/check-bun.mjs && bun install --frozen-lockfile && BUN_JSC_useOMGJIT=0 bun test --parallel=4 --timeout 30000",
3449
+ "test:serial": "bun ../../scripts/check-bun.mjs && bun install --frozen-lockfile && BUN_JSC_useOMGJIT=0 bun test --parallel=1 --timeout 30000",
3450
+ lint: "bun ../../scripts/check-bun.mjs && biome check src",
3451
+ "lint:fix": "biome check --write src",
3452
+ format: "biome format --write src",
3453
+ "format:check": "biome format src",
3454
+ clean: "bun ../../scripts/clean-dist-chunks.mjs dist index.js subagent-entry.js historian-calibration-extension.js embedding-worker.js embedding-worker-process.js migration-worker.js raw-ordinal-warmup-worker.js transformers-web.js transformers-node-wasm.js",
3455
+ prepublishOnly: "bun run build"
3456
+ },
3457
+ "//test": "Test runs cap file-isolated workers at four (one for test:serial) and disable JSC's optimizing WebAssembly tier so per-file isolation does not pay its compilation cost on every file. These are not production settings and do not change host process engine options.",
3458
+ dependencies: {
3459
+ "@cortexkit/subc-client": "0.11.1",
3460
+ "@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
3461
+ "ai-tokenizer": "^1.0.6",
3462
+ "comment-json": "^5.0.0",
3463
+ "onnxruntime-web": "1.26.0-dev.20260416-b7804b056c",
3464
+ "quickjs-emscripten": "^0.32.0",
3465
+ zod: "^4.1.8"
3466
+ },
3467
+ optionalDependencies: {
3468
+ "onnxruntime-node": "1.30.0",
3469
+ sharp: "^0.35.0"
3470
+ },
3471
+ devDependencies: {
3472
+ "@biomejs/biome": "^2.5.1",
3473
+ "@earendil-works/pi-ai": "0.83.0",
3474
+ "@earendil-works/pi-coding-agent": "0.83.0",
3475
+ "@earendil-works/pi-tui": "0.83.0",
3476
+ "@huggingface/transformers": "^4.3.0",
3477
+ "@types/better-sqlite3": "^7.6.13",
3478
+ "@types/bun": "^1.3.10",
3479
+ "@types/node": "^22.20.0",
3480
+ "pi-agent-core-087": "npm:@earendil-works/pi-agent-core@0.87.1",
3481
+ "pi-ai-086": "npm:@earendil-works/pi-ai@0.86.0",
3482
+ "pi-coding-agent-086": "npm:@earendil-works/pi-coding-agent@0.86.0",
3483
+ "pi-coding-agent-087": "npm:@earendil-works/pi-coding-agent@0.87.1",
3484
+ typebox: "^1.3.1",
3485
+ typescript: "^5.8.0"
3486
+ },
3487
+ peerDependencies: {
3488
+ "@earendil-works/pi-coding-agent": "*",
3489
+ "@earendil-works/pi-tui": "*",
3490
+ typebox: "*"
3491
+ },
3492
+ peerDependenciesMeta: {
3493
+ "@earendil-works/pi-coding-agent": {
3494
+ optional: true
3495
+ },
3496
+ "@earendil-works/pi-tui": {
3497
+ optional: true
3498
+ },
3499
+ typebox: {
3500
+ optional: true
3501
+ }
3502
+ },
3503
+ exports: {
3504
+ ".": {
3505
+ import: "./dist/index.js"
3506
+ }
3507
+ },
3508
+ pi: {
3509
+ extensions: [
3510
+ "./dist/index.js"
3511
+ ]
3512
+ },
3513
+ omp: {
3514
+ extensions: [
3515
+ "./dist/index.js"
3516
+ ]
3517
+ }
3518
+ };
3369
3519
 
3370
3520
  // src/clone-inheritance.ts
3371
3521
  import { readFile } from "node:fs/promises";
@@ -10259,7 +10409,7 @@ function getAsyncModule() {
10259
10409
  await beforeModuleLoad();
10260
10410
  const [{ default: singlefileAsyncifyVariant }, { newQuickJSAsyncWASMModuleFromVariant }] = await importPluginModule(() => Promise.all([
10261
10411
  import("./index-e7vx3byk.js").then((m)=>__toESM(m.default,1)),
10262
- import("./index-5prbx026.js")
10412
+ import("./index-2pp04pmg.js")
10263
10413
  ]));
10264
10414
  const module = await newQuickJSAsyncWASMModuleFromVariant(singlefileAsyncifyVariant);
10265
10415
  return module;
@@ -16131,284 +16281,6 @@ function clearDreamerTickFailure(db) {
16131
16281
  db.prepare("DELETE FROM schema_migrations_meta WHERE key = ?").run(DREAMER_TICK_FAILURE_KEY);
16132
16282
  }
16133
16283
 
16134
- // ../plugin/src/hooks/magic-context/lkg-persist.ts
16135
- import { createHash as createHash11 } from "node:crypto";
16136
- function parseStringArray(value) {
16137
- if (typeof value !== "string")
16138
- return null;
16139
- let parsed;
16140
- try {
16141
- parsed = JSON.parse(value);
16142
- } catch {
16143
- return null;
16144
- }
16145
- if (!Array.isArray(parsed))
16146
- return null;
16147
- const result = [];
16148
- for (const entry of parsed) {
16149
- if (typeof entry !== "string" || entry.length === 0)
16150
- return null;
16151
- result.push(entry);
16152
- }
16153
- return result;
16154
- }
16155
- function parseNullableString(value) {
16156
- if (value === null || value === undefined)
16157
- return null;
16158
- return typeof value === "string" ? value : undefined;
16159
- }
16160
- function parseNullableInteger(value) {
16161
- if (value === null || value === undefined)
16162
- return;
16163
- return typeof value === "number" && Number.isSafeInteger(value) ? value : undefined;
16164
- }
16165
- function parsePersistedLkgSlot(row) {
16166
- if (!row || typeof row !== "object")
16167
- return;
16168
- const record = row;
16169
- const jsonPrefix = record.json_prefix;
16170
- const lastInputMessageId = record.last_input_message_id;
16171
- const capturedAt = record.captured_at;
16172
- let inputIdsRaw = record.input_id_seq;
16173
- let piOutputEntryIds;
16174
- if (typeof inputIdsRaw === "string") {
16175
- try {
16176
- const metadata = JSON.parse(inputIdsRaw);
16177
- if (metadata && !Array.isArray(metadata) && metadata.version === 1 && Array.isArray(metadata.piOutputEntryIds)) {
16178
- if (!metadata.piOutputEntryIds.every((id) => id === null || typeof id === "string" && id.length > 0))
16179
- return;
16180
- piOutputEntryIds = metadata.piOutputEntryIds;
16181
- inputIdsRaw = JSON.stringify(metadata.inputIds);
16182
- }
16183
- } catch {
16184
- return;
16185
- }
16186
- }
16187
- const inputIdSeq = parseStringArray(inputIdsRaw);
16188
- const inputContentDigests = parseStringArray(record.input_content_digests);
16189
- const modelKey = parseNullableString(record.model_key);
16190
- const providerKey = parseNullableString(record.provider_key);
16191
- if (typeof jsonPrefix !== "string" || typeof lastInputMessageId !== "string" || lastInputMessageId.length === 0 || typeof capturedAt !== "number" || !Number.isFinite(capturedAt) || inputIdSeq === null || inputContentDigests === null || inputContentDigests.length !== inputIdSeq.length || modelKey === undefined || providerKey === undefined) {
16192
- return;
16193
- }
16194
- if (piOutputEntryIds) {
16195
- try {
16196
- const output = JSON.parse(jsonPrefix);
16197
- const inputs = new Set(inputIdSeq);
16198
- if (!Array.isArray(output) || output.length !== piOutputEntryIds.length || piOutputEntryIds.some((id) => id !== null && !inputs.has(id)))
16199
- return;
16200
- } catch {
16201
- return;
16202
- }
16203
- }
16204
- let inputContentSignatures;
16205
- if (record.input_content_signatures !== null && record.input_content_signatures !== undefined) {
16206
- const parsed = parseStringArray(record.input_content_signatures);
16207
- if (parsed === null || parsed.length !== inputIdSeq.length)
16208
- return;
16209
- inputContentSignatures = parsed;
16210
- }
16211
- const slot = {
16212
- jsonPrefix,
16213
- inputIdSeq,
16214
- inputContentDigests,
16215
- lastInputMessageId,
16216
- modelKey,
16217
- providerKey,
16218
- capturedAt
16219
- };
16220
- if (inputContentSignatures)
16221
- slot.inputContentSignatures = inputContentSignatures;
16222
- if (piOutputEntryIds)
16223
- slot.piOutputEntryIds = piOutputEntryIds;
16224
- const rowVersion = parseNullableInteger(record.row_version);
16225
- if (rowVersion !== undefined)
16226
- slot.rowVersion = rowVersion;
16227
- const captureSequence = parseNullableInteger(record.capture_sequence);
16228
- if (captureSequence !== undefined)
16229
- slot.captureSequence = captureSequence;
16230
- return slot;
16231
- }
16232
- var persistedFingerprints = new WeakMap;
16233
- var PERSISTED_FINGERPRINT_MAX_SESSIONS = 1000;
16234
- function rememberFingerprint(db, sessionId, fingerprint) {
16235
- let saved = persistedFingerprints.get(db);
16236
- if (!saved) {
16237
- saved = new Map;
16238
- persistedFingerprints.set(db, saved);
16239
- }
16240
- saved.delete(sessionId);
16241
- if (saved.size >= PERSISTED_FINGERPRINT_MAX_SESSIONS) {
16242
- const oldest = saved.keys().next().value;
16243
- if (oldest !== undefined)
16244
- saved.delete(oldest);
16245
- }
16246
- saved.set(sessionId, fingerprint);
16247
- }
16248
- function slotFingerprint(slot) {
16249
- return createHash11("sha256").update(JSON.stringify([
16250
- slot.jsonPrefix,
16251
- slot.inputIdSeq,
16252
- slot.inputContentDigests,
16253
- slot.inputContentSignatures,
16254
- slot.piOutputEntryIds,
16255
- slot.lastInputMessageId,
16256
- slot.modelKey,
16257
- slot.providerKey,
16258
- slot.rowVersion,
16259
- slot.captureSequence
16260
- ])).digest("hex");
16261
- }
16262
- function saveLkgSlotToDb(db, sessionId, slot, publishMetadata) {
16263
- const fingerprint = slotFingerprint(slot);
16264
- if (!publishMetadata && persistedFingerprints.get(db)?.get(sessionId) === fingerprint)
16265
- return true;
16266
- const layout = layoutLkgPrefix(slot.jsonPrefix);
16267
- try {
16268
- db.transaction(() => {
16269
- const storedHashes = new Map;
16270
- for (const row of db.prepare("SELECT chunk, hash FROM lkg_slot_chunks WHERE session_id = ?").all(sessionId)) {
16271
- storedHashes.set(row.chunk, row.hash);
16272
- }
16273
- const upsertChunk = db.prepare(`INSERT INTO lkg_slot_chunks (session_id, chunk, hash, body) VALUES (?, ?, ?, ?)
16274
- ON CONFLICT(session_id, chunk) DO UPDATE SET hash = excluded.hash, body = excluded.body`);
16275
- for (let index = 0;index < layout.chunks.length; index += 1) {
16276
- if (storedHashes.get(index) === layout.chunkHashes[index])
16277
- continue;
16278
- upsertChunk.run(sessionId, index, layout.chunkHashes[index], layout.chunks[index]);
16279
- }
16280
- db.prepare("DELETE FROM lkg_slot_chunks WHERE session_id = ? AND chunk >= ?").run(sessionId, layout.chunks.length);
16281
- db.prepare(`INSERT INTO lkg_slots (
16282
- session_id, json_prefix_chars, json_prefix_chunks, json_prefix_hash,
16283
- input_id_seq, input_content_digests, input_content_signatures,
16284
- last_input_message_id, model_key, provider_key,
16285
- captured_at, row_version, capture_sequence
16286
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
16287
- ON CONFLICT(session_id) DO UPDATE SET
16288
- json_prefix_chars = excluded.json_prefix_chars,
16289
- json_prefix_chunks = excluded.json_prefix_chunks,
16290
- json_prefix_hash = excluded.json_prefix_hash,
16291
- input_id_seq = excluded.input_id_seq,
16292
- input_content_digests = excluded.input_content_digests,
16293
- input_content_signatures = excluded.input_content_signatures,
16294
- last_input_message_id = excluded.last_input_message_id,
16295
- model_key = excluded.model_key,
16296
- provider_key = excluded.provider_key,
16297
- captured_at = excluded.captured_at,
16298
- row_version = excluded.row_version,
16299
- capture_sequence = excluded.capture_sequence`).run(sessionId, layout.chars, layout.chunks.length, layout.hash, JSON.stringify(slot.piOutputEntryIds ? {
16300
- version: 1,
16301
- inputIds: slot.inputIdSeq,
16302
- piOutputEntryIds: slot.piOutputEntryIds
16303
- } : slot.inputIdSeq), JSON.stringify(slot.inputContentDigests), slot.inputContentSignatures ? JSON.stringify(slot.inputContentSignatures) : null, slot.lastInputMessageId, slot.modelKey, slot.providerKey, slot.capturedAt, slot.rowVersion ?? null, slot.captureSequence ?? null);
16304
- publishMetadata?.();
16305
- }).immediate();
16306
- rememberFingerprint(db, sessionId, fingerprint);
16307
- return true;
16308
- } catch (error) {
16309
- if (!publishMetadata)
16310
- sessionLog2(sessionId, "LKG snapshot persistence failed (in-memory slot retained):", error);
16311
- return false;
16312
- }
16313
- }
16314
- function clearPersistedLkgSlot(db, sessionId) {
16315
- try {
16316
- clearPersistedLkgSlotStrict(db, sessionId);
16317
- } catch (error) {
16318
- sessionLog2(sessionId, "LKG snapshot durable clear failed:", error);
16319
- }
16320
- }
16321
- function clearPersistedLkgSlotStrict(db, sessionId) {
16322
- db.transaction(() => {
16323
- db.prepare("DELETE FROM lkg_slot_chunks WHERE session_id = ?").run(sessionId);
16324
- db.prepare("DELETE FROM lkg_slots WHERE session_id = ?").run(sessionId);
16325
- }).immediate();
16326
- persistedFingerprints.get(db)?.delete(sessionId);
16327
- }
16328
- function loadPersistedLkgSlot(db, sessionId) {
16329
- if (isRustMarkerAdmissionFenced(db, sessionId))
16330
- return;
16331
- let row;
16332
- let chunkRows;
16333
- try {
16334
- ({ row, chunkRows } = db.transaction(() => {
16335
- const slotRow = db.prepare("SELECT * FROM lkg_slots WHERE session_id = ?").get(sessionId);
16336
- if (!slotRow)
16337
- return { row: undefined, chunkRows: [] };
16338
- const slices = db.prepare("SELECT chunk, hash, body FROM lkg_slot_chunks WHERE session_id = ? ORDER BY chunk").all(sessionId);
16339
- return { row: slotRow, chunkRows: slices };
16340
- }).deferred());
16341
- } catch (error) {
16342
- sessionLog2(sessionId, "LKG snapshot durable load failed:", error);
16343
- return;
16344
- }
16345
- if (!row)
16346
- return;
16347
- const prefix = assembleLkgPrefix({
16348
- chars: row.json_prefix_chars,
16349
- chunks: row.json_prefix_chunks,
16350
- hash: row.json_prefix_hash
16351
- }, chunkRows);
16352
- const slot = prefix ? parsePersistedLkgSlot({ ...row, json_prefix: prefix.jsonPrefix }) : undefined;
16353
- if (!prefix || !slot) {
16354
- if (!prefix)
16355
- sessionLog2(sessionId, "LKG snapshot slices failed verification; slot cleared");
16356
- clearPersistedLkgSlot(db, sessionId);
16357
- return;
16358
- }
16359
- return slot;
16360
- }
16361
- function pruneStaleLkgSlotsBatch(db, now) {
16362
- const previousTimeout = db.prepare("PRAGMA busy_timeout").get();
16363
- const cutoff = now - 7 * 24 * 60 * 60 * 1000;
16364
- const stale = `captured_at < ? AND NOT EXISTS (
16365
- SELECT 1 FROM session_projects sp
16366
- WHERE sp.session_id = lkg_slots.session_id AND sp.updated_at >= ?
16367
- )`;
16368
- const slot = db.prepare(`SELECT session_id FROM lkg_slots WHERE ${stale} LIMIT 1`).get(cutoff, cutoff);
16369
- const chunks = db.prepare(`SELECT rowid FROM lkg_slot_chunks c WHERE
16370
- session_id = ? OR NOT EXISTS (SELECT 1 FROM lkg_slots s WHERE s.session_id = c.session_id)
16371
- LIMIT 25`).all(slot?.session_id ?? "");
16372
- if (!slot && chunks.length === 0)
16373
- return { slots: 0, chunks: 0 };
16374
- try {
16375
- db.exec("PRAGMA busy_timeout = 0");
16376
- let transactionStartedAt = 0;
16377
- const changes = db.transaction(() => {
16378
- transactionStartedAt = performance.now();
16379
- const removed = slot ? db.prepare(`DELETE FROM lkg_slots WHERE session_id = ? AND ${stale}`).run(slot.session_id, cutoff, cutoff).changes : 0;
16380
- const removeChunk = db.prepare(`DELETE FROM lkg_slot_chunks WHERE rowid = ? AND NOT EXISTS (
16381
- SELECT 1 FROM lkg_slots s WHERE s.session_id = lkg_slot_chunks.session_id
16382
- )`);
16383
- let removedChunks = 0;
16384
- for (const { rowid } of chunks)
16385
- removedChunks += removeChunk.run(rowid).changes;
16386
- return { slots: removed, chunks: removedChunks };
16387
- }).immediate();
16388
- logSlowWriteTransaction("lkg_stale_gc", transactionStartedAt);
16389
- if (changes.slots && slot)
16390
- persistedFingerprints.get(db)?.delete(slot.session_id);
16391
- return changes;
16392
- } finally {
16393
- db.exec(`PRAGMA busy_timeout = ${Number(previousTimeout.timeout) || 0}`);
16394
- }
16395
- }
16396
- async function drainStaleLkgSlots(db, now = Date.now(), budgetMs = 2000) {
16397
- let removed = 0;
16398
- await drainBackgroundBatches(() => {
16399
- const batch = pruneStaleLkgSlotsBatch(db, now);
16400
- removed += batch.slots;
16401
- return batch.slots + batch.chunks > 0;
16402
- }, { budgetMs });
16403
- return removed;
16404
- }
16405
- function createDbLkgPersistence(db) {
16406
- return {
16407
- load: (sessionId) => loadPersistedLkgSlot(db, sessionId),
16408
- clear: (sessionId) => clearPersistedLkgSlot(db, sessionId)
16409
- };
16410
- }
16411
-
16412
16284
  // ../plugin/src/plugin/dream-timer.ts
16413
16285
  var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
16414
16286
  var GIT_COMMIT_BACKLOG_DRAIN_MAX_MS = 5 * 60 * 1000;
@@ -17300,13 +17172,33 @@ function resolveModelRefForTarget(ref, targetHarness) {
17300
17172
  return targetHarness === "omp" ? resolveModelRefForOmp(ref) : resolveModelRefForPi(ref);
17301
17173
  }
17302
17174
  var configuredSubagentExtensions;
17175
+ var PI_NON_LOCAL_EXTENSION_PREFIXES = [
17176
+ "npm:",
17177
+ "git:",
17178
+ "github:",
17179
+ "http:",
17180
+ "https:",
17181
+ "ssh:",
17182
+ "builtin:"
17183
+ ];
17303
17184
  function configurePiSubagentExtensions(extensions) {
17304
17185
  configuredSubagentExtensions = extensions?.slice();
17305
17186
  }
17306
17187
  function resolveSubagentExtensionEntry(entry, targetHarness) {
17307
17188
  const trimmed = entry.trim();
17308
17189
  const isNpmSource = trimmed.startsWith("npm:");
17309
- return !isNpmSource && !isAbsolute(trimmed) ? resolvePath(getHostAgentSettingsDir(targetHarness), trimmed) : trimmed;
17190
+ const isPiSource = PI_NON_LOCAL_EXTENSION_PREFIXES.some((prefix) => trimmed.startsWith(prefix));
17191
+ if (isNpmSource || targetHarness === "pi" && isPiSource)
17192
+ return trimmed;
17193
+ let normalized = trimmed;
17194
+ if (normalized === "~") {
17195
+ normalized = homedir();
17196
+ } else if (normalized.startsWith("~/") || process.platform === "win32" && normalized.startsWith("~\\")) {
17197
+ normalized = join10(homedir(), normalized.slice(2));
17198
+ } else if (/^file:\/\//.test(normalized)) {
17199
+ normalized = fileURLToPath(normalized);
17200
+ }
17201
+ return isAbsolute(normalized) ? normalized : resolvePath(getHostAgentSettingsDir(targetHarness), normalized);
17310
17202
  }
17311
17203
  var PI_READ_ONLY_BUILTINS = ["read", "grep", "find", "ls"];
17312
17204
  var PI_AFT_READ_TOOLS = ["aft_outline", "aft_zoom", "aft_search"];
@@ -21013,6 +20905,15 @@ var canonicalReasons = new Set([
21013
20905
  "project_memory_epoch",
21014
20906
  "ttl_idle",
21015
20907
  "explicit_flush",
20908
+ "user_flush",
20909
+ "fit_retry",
20910
+ "pending_materialization",
20911
+ "variant_change",
20912
+ "recomp",
20913
+ "boundary_repair",
20914
+ "host_history_change",
20915
+ "thinking_hold",
20916
+ "mutation_drift",
21016
20917
  "max_mutation_id",
21017
20918
  "first_render",
21018
20919
  "pressure_refold",
@@ -22549,168 +22450,6 @@ function isHistorianDrainBudgetSpent(args) {
22549
22450
  return true;
22550
22451
  }
22551
22452
 
22552
- // ../plugin/src/hooks/magic-context/active-anthropic-turn.ts
22553
- function isInActiveAnthropicTurn(messages, index, anthropic) {
22554
- const start = activeAnthropicTurnStart(messages, anthropic);
22555
- return start !== undefined && index >= start;
22556
- }
22557
- function activeAnthropicTurnStart(messages, anthropic) {
22558
- if (!anthropic)
22559
- return;
22560
- for (let user = messages.length - 1;user >= 0; user--) {
22561
- const message = messages[user];
22562
- if (!isRecord(message))
22563
- continue;
22564
- const info = isRecord(message.info) ? message.info : message;
22565
- if (info.role !== "user" || info.synthetic === true || message.synthetic === true)
22566
- continue;
22567
- const id = typeof info.id === "string" ? info.id : "";
22568
- if (id.startsWith("synth-user-"))
22569
- continue;
22570
- const parts = Array.isArray(message.parts) ? message.parts : Array.isArray(message.content) ? message.content : [];
22571
- if (parts.length > 0 && parts.every((part) => isRecord(part) && (part.synthetic === true || part.ignored === true || ["tool_result", "toolResult", "tool-result"].includes(String(part.type)))))
22572
- continue;
22573
- return user + 1;
22574
- }
22575
- return;
22576
- }
22577
- function hasAnthropicReasoning(messages) {
22578
- return messages.some((message) => {
22579
- if (!isRecord(message))
22580
- return false;
22581
- const info = isRecord(message.info) ? message.info : message;
22582
- if (isAnthropicFamilyRoute(typeof info.providerID === "string" ? info.providerID : typeof info.provider === "string" ? info.provider : undefined, typeof info.modelID === "string" ? info.modelID : typeof info.model === "string" ? info.model : undefined))
22583
- return true;
22584
- const parts = Array.isArray(message.parts) ? message.parts : [];
22585
- return parts.some((part) => isRecord(part) && isRecord(part.metadata) && isRecord(part.metadata.anthropic));
22586
- });
22587
- }
22588
-
22589
- // ../plugin/src/hooks/magic-context/strip-content.ts
22590
- var METADATA_PART_TYPES = new Set([
22591
- "step-start",
22592
- "step-finish",
22593
- "snapshot",
22594
- "patch",
22595
- "agent",
22596
- "retry",
22597
- "subtask",
22598
- "compaction"
22599
- ]);
22600
- var CLEARED_REASONING_TYPES = new Set(["thinking", "reasoning"]);
22601
- var REASONING_IGNORED_PART_TYPES = new Set([
22602
- "step-start",
22603
- "step-finish",
22604
- "snapshot",
22605
- "patch",
22606
- "agent",
22607
- "retry",
22608
- "subtask",
22609
- "compaction"
22610
- ]);
22611
- var REASONING_PART_TYPES = new Set(["reasoning", "thinking", "redacted_thinking"]);
22612
- function hasReasoningReplayContent(message) {
22613
- return message.parts.some((part) => {
22614
- if (!isRecord(part) || part.ignored === true)
22615
- return false;
22616
- const type = typeof part.type === "string" ? part.type : "";
22617
- if (REASONING_IGNORED_PART_TYPES.has(type))
22618
- return false;
22619
- return type !== "text" || typeof part.text !== "string" || part.text.trim().length > 0;
22620
- });
22621
- }
22622
- function findLatestAssistantReasoningMutationExemptMessage(messages) {
22623
- for (let index = messages.length - 1;index >= 0; index -= 1) {
22624
- const message = messages[index];
22625
- if (message.info.role === "assistant" && hasReasoningReplayContent(message))
22626
- return message;
22627
- }
22628
- return;
22629
- }
22630
-
22631
- // ../plugin/src/hooks/magic-context/reasoning-budget.ts
22632
- var DEFAULT_KEEP_REASONING_TOKENS = 1e4;
22633
- var UNKNOWN_REASONING_STEP_TOKENS = 1000;
22634
- function resolveKeepReasoningTokens(config, modelKey) {
22635
- const values = config && typeof config === "object" ? Object.assign(Object.create(null), config) : undefined;
22636
- return typeof config === "number" ? config : resolveModelConfigValue(values, modelKey)?.value ?? values?.default ?? DEFAULT_KEEP_REASONING_TOKENS;
22637
- }
22638
- function reasoningStepCost(reported, textEstimate, opaque) {
22639
- if (reported !== undefined && Number.isFinite(reported) && reported > 0)
22640
- return reported;
22641
- if (textEstimate > 0)
22642
- return Math.ceil(textEstimate);
22643
- return opaque ? UNKNOWN_REASONING_STEP_TOKENS : 0;
22644
- }
22645
- function reasoningBudgetCutoff(steps, budget) {
22646
- const cost = (step) => step.alreadyRemoved ? 0 : typeof step.cost === "function" ? step.cost() : step.cost;
22647
- let kept = 0;
22648
- let upperBound = Number.POSITIVE_INFINITY;
22649
- for (const step of steps) {
22650
- if (!step.exempt)
22651
- continue;
22652
- kept += cost(step);
22653
- if (step.tag > 0)
22654
- upperBound = Math.min(upperBound, step.tag - 1);
22655
- }
22656
- for (let index = steps.length - 1;index >= 0; index--) {
22657
- const step = steps[index];
22658
- if (step.exempt || step.alreadyRemoved)
22659
- continue;
22660
- const tokens = cost(step);
22661
- if (kept + tokens <= budget) {
22662
- kept += tokens;
22663
- if (step.tag > 0)
22664
- upperBound = Math.min(upperBound, step.tag - 1);
22665
- continue;
22666
- }
22667
- let tag = step.tag;
22668
- for (let older = index - 1;tag <= 0 && older >= 0; older--)
22669
- tag = steps[older].tag;
22670
- return Math.max(0, Math.min(tag, upperBound));
22671
- }
22672
- return 0;
22673
- }
22674
- function reasoningTextAndOpaque(parts) {
22675
- let text = "";
22676
- let inlineText = "";
22677
- let opaque = false;
22678
- let hasReasoning = false;
22679
- const detailText = new Set;
22680
- for (const part of parts) {
22681
- if (!isRecord(part))
22682
- continue;
22683
- if (part.ignored === true)
22684
- continue;
22685
- if (isRecord(part.metadata)) {
22686
- const router = part.metadata.openrouter;
22687
- if (isRecord(router) && Array.isArray(router.reasoning_details) && router.reasoning_details.length > 0) {
22688
- hasReasoning = true;
22689
- opaque = true;
22690
- for (const detail of router.reasoning_details) {
22691
- if (!isRecord(detail))
22692
- continue;
22693
- if (detail.type === "reasoning.text" && typeof detail.text === "string")
22694
- detailText.add(detail.text);
22695
- if (detail.type === "reasoning.summary" && typeof detail.summary === "string")
22696
- detailText.add(detail.summary);
22697
- }
22698
- }
22699
- }
22700
- if (["reasoning", "thinking", "redacted_thinking"].includes(String(part.type))) {
22701
- hasReasoning = true;
22702
- const visible = part.type === "redacted_thinking" || part.redacted === true ? "" : typeof part.thinking === "string" ? part.thinking : typeof part.text === "string" ? part.text : "";
22703
- if (visible !== "[cleared]")
22704
- text += visible;
22705
- opaque ||= part.type === "redacted_thinking" || part.redacted === true || visible === "" && (part.metadata !== undefined || part.signature !== undefined || part.thinkingSignature !== undefined);
22706
- } else if (part.type === "text" && typeof part.text === "string") {
22707
- for (const match of part.text.matchAll(/<(?:thinking|think)>([\s\S]*?)<\/(?:thinking|think)>/gi))
22708
- inlineText += match[1];
22709
- }
22710
- }
22711
- return { text: text || [...detailText].join(""), inlineText, opaque, hasReasoning };
22712
- }
22713
-
22714
22453
  // ../plugin/src/hooks/magic-context/compartment-trigger.ts
22715
22454
  var PROACTIVE_TRIGGER_OFFSET_PERCENTAGE = 2;
22716
22455
  var POST_DROP_TARGET_RATIO = 0.75;
@@ -23655,9 +23394,9 @@ function advanceToolReclaimWatermarkToCurrentMax(db, sessionId) {
23655
23394
  }
23656
23395
 
23657
23396
  // ../plugin/src/shared/tag-transcript.ts
23658
- import { createHash as createHash12 } from "node:crypto";
23397
+ import { createHash as createHash11 } from "node:crypto";
23659
23398
  function textIdentityDigest(value) {
23660
- return createHash12("sha256").update(value).digest("hex");
23399
+ return createHash11("sha256").update(value).digest("hex");
23661
23400
  }
23662
23401
  function buildContentDerivedTextIds(messageId, parts) {
23663
23402
  const sources = parts.filter((part) => part.kind === "text").map((part) => stripTagPrefix(part.getText() ?? ""));
@@ -31632,6 +31371,17 @@ class PiContextBudget {
31632
31371
  abandoned = false;
31633
31372
  completed = false;
31634
31373
  failureReason;
31374
+ signal;
31375
+ cancelled = false;
31376
+ isCancelled(error) {
31377
+ return this.cancelled || this.signal?.aborted === true || !this.signal && typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
31378
+ }
31379
+ cancel() {
31380
+ this.cancelled = true;
31381
+ this.abandoned = true;
31382
+ this.completed = false;
31383
+ this.failureReason = undefined;
31384
+ }
31635
31385
  assertOwner = () => {};
31636
31386
  constructor(startedAt = performance.now(), now = () => performance.now()) {
31637
31387
  this.startedAt = startedAt;
@@ -31649,6 +31399,7 @@ class PiContextBudget {
31649
31399
  }
31650
31400
  assertOutcome = () => {
31651
31401
  this.assertOwner();
31402
+ this.signal?.throwIfAborted();
31652
31403
  if (this.abandoned || this.elapsed() >= PI_CONTEXT_BUDGET.outcomeMs)
31653
31404
  throw new PiContextDeadlineError(this.diagnostic());
31654
31405
  };
@@ -31658,6 +31409,7 @@ class PiContextBudget {
31658
31409
  throw new PiContextDeadlineError(this.diagnostic());
31659
31410
  };
31660
31411
  assertDecisionPublication = () => {
31412
+ this.signal?.throwIfAborted();
31661
31413
  if (!this.completed)
31662
31414
  this.assertOwner();
31663
31415
  if (this.abandoned || !this.completed && this.elapsed() >= PI_CONTEXT_BUDGET.outcomeMs)
@@ -31667,17 +31419,33 @@ class PiContextBudget {
31667
31419
  return `stage=${this.stage} elapsed=${Math.round(this.elapsed())}ms recovery=${this.recovery}`;
31668
31420
  }
31669
31421
  waitUntil = async (pending, assert, remaining) => {
31670
- assert();
31422
+ try {
31423
+ assert();
31424
+ } catch (error) {
31425
+ pending.catch(() => {});
31426
+ throw error;
31427
+ }
31671
31428
  let timer;
31429
+ let onAbort;
31672
31430
  try {
31673
31431
  return await Promise.race([
31674
31432
  pending,
31433
+ ...this.signal ? [
31434
+ new Promise((_, reject) => {
31435
+ onAbort = () => reject(this.signal?.reason);
31436
+ this.signal?.addEventListener("abort", onAbort, {
31437
+ once: true
31438
+ });
31439
+ })
31440
+ ] : [],
31675
31441
  new Promise((_, reject) => {
31676
31442
  timer = setTimeout(() => reject(new PiContextDeadlineError(this.diagnostic())), remaining());
31677
31443
  })
31678
31444
  ]);
31679
31445
  } finally {
31680
31446
  clearTimeout(timer);
31447
+ if (onAbort)
31448
+ this.signal?.removeEventListener("abort", onAbort);
31681
31449
  assert();
31682
31450
  }
31683
31451
  };
@@ -31706,7 +31474,6 @@ function resolvePiWindowGeometry(args) {
31706
31474
  output: args.model?.maxTokens
31707
31475
  }, {
31708
31476
  providerLimit: observedWindow === undefined ? undefined : { context: observedWindow },
31709
- overlay: resolveWindowOverlayFacts(providerID, modelID, getWindowOverlay()),
31710
31477
  contextCap: isSaneLimit2(args.detectedContextLimit) ? args.detectedContextLimit : undefined,
31711
31478
  outputReserveOverride,
31712
31479
  harness: "pi"
@@ -31850,6 +31617,775 @@ function isOmpUnmanagedCaptureRequest(payload) {
31850
31617
  return last?.role === "user" && firstText(last.content, request.textType)?.startsWith(CAPTURE_PREFIX) === true;
31851
31618
  }
31852
31619
 
31620
+ // src/pi-dispatch-google.ts
31621
+ function piGoogleConversation(payload) {
31622
+ if (!payload || typeof payload !== "object")
31623
+ return;
31624
+ const body = payload;
31625
+ if (body.messages !== undefined || body.input !== undefined)
31626
+ return;
31627
+ if (Array.isArray(body.contents))
31628
+ return body;
31629
+ const request = body.request;
31630
+ if (!request || typeof request !== "object")
31631
+ return;
31632
+ const conversation = request;
31633
+ return Array.isArray(conversation.contents) ? conversation : undefined;
31634
+ }
31635
+
31636
+ // src/pi-dispatch-identity.ts
31637
+ var MAX_NODES = 1e5;
31638
+ var MAX_STRING_UNITS = 32 * 1024 * 1024;
31639
+ var MAX_DEPTH = 128;
31640
+ function piConversationFields(payload) {
31641
+ try {
31642
+ if (!payload || typeof payload !== "object")
31643
+ return;
31644
+ const body = payload;
31645
+ let conversation;
31646
+ let anthropic = false;
31647
+ if (Array.isArray(body.messages) && body.input === undefined) {
31648
+ conversation = { messages: body.messages, system: body.system };
31649
+ anthropic = typeof body.system === "string" || Array.isArray(body.system);
31650
+ } else if ((Array.isArray(body.input) || typeof body.input === "string") && body.messages === undefined) {
31651
+ conversation = {
31652
+ input: body.input,
31653
+ instructions: body.instructions,
31654
+ previous_response_id: body.previous_response_id,
31655
+ conversation: body.conversation,
31656
+ prompt: body.prompt
31657
+ };
31658
+ } else {
31659
+ const google = piGoogleConversation(payload);
31660
+ if (!google)
31661
+ return;
31662
+ conversation = {
31663
+ contents: google.contents,
31664
+ systemInstruction: google.systemInstruction,
31665
+ configSystemInstruction: google.config?.systemInstruction
31666
+ };
31667
+ }
31668
+ const fields = [];
31669
+ const seen = new WeakSet;
31670
+ let nodes = 0;
31671
+ let strings = 0;
31672
+ const visit = (value, position, depth) => {
31673
+ if (++nodes > MAX_NODES || depth > MAX_DEPTH)
31674
+ throw new Error("conversation structure limit");
31675
+ if (typeof value === "string") {
31676
+ strings += value.length;
31677
+ if (strings > MAX_STRING_UNITS)
31678
+ throw new Error("conversation string limit");
31679
+ fields.push(LKG_SNAPSHOT_STRING, value);
31680
+ } else if (value === null)
31681
+ fields.push(LKG_SNAPSHOT_NULL);
31682
+ else if (typeof value === "number")
31683
+ fields.push(LKG_SNAPSHOT_NUMBER, value);
31684
+ else if (typeof value === "boolean")
31685
+ fields.push(LKG_SNAPSHOT_BOOLEAN, value);
31686
+ else if (!value || typeof value !== "object")
31687
+ fields.push(LKG_SNAPSHOT_UNDEFINED);
31688
+ else {
31689
+ if (seen.has(value))
31690
+ throw new Error("cyclic conversation");
31691
+ seen.add(value);
31692
+ if (Array.isArray(value)) {
31693
+ if (anthropic && (position === "content" || position === "system") && value.length === 1) {
31694
+ const block = value[0];
31695
+ if (block && typeof block === "object" && block.type === "text" && typeof block.text === "string" && Object.keys(block).every((key) => key === "type" || key === "text" || key === "cache_control")) {
31696
+ visit(block.text, "other", depth + 1);
31697
+ seen.delete(value);
31698
+ return;
31699
+ }
31700
+ }
31701
+ fields.push(LKG_SNAPSHOT_ARRAY, value.length);
31702
+ for (const item of value)
31703
+ visit(item, position === "messages" ? "message" : anthropic && (position === "content" || position === "system") ? "block" : "other", depth + 1);
31704
+ } else {
31705
+ const entries = Object.entries(value).filter(([key, child]) => child !== undefined && typeof child !== "function" && typeof child !== "symbol" && !(anthropic && position === "block" && key === "cache_control"));
31706
+ for (const [key] of entries)
31707
+ strings += key.length;
31708
+ if (strings > MAX_STRING_UNITS)
31709
+ throw new Error("conversation key limit");
31710
+ entries.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
31711
+ fields.push(LKG_SNAPSHOT_OBJECT, entries.length);
31712
+ for (const [key, child] of entries) {
31713
+ fields.push(LKG_SNAPSHOT_KEY, key);
31714
+ visit(child, position === "root" && key === "messages" ? "messages" : position === "root" && key === "system" ? "system" : position === "message" && key === "content" ? "content" : "other", depth + 1);
31715
+ }
31716
+ }
31717
+ seen.delete(value);
31718
+ }
31719
+ };
31720
+ visit(conversation, "root", 0);
31721
+ return fields;
31722
+ } catch {
31723
+ return;
31724
+ }
31725
+ }
31726
+ function piManagedSignature(messages) {
31727
+ for (const message of messages.slice(0, 8)) {
31728
+ if (!message || typeof message !== "object")
31729
+ continue;
31730
+ const content = message.content;
31731
+ const text = typeof content === "string" ? content : Array.isArray(content) ? content.find((part) => part?.type === "text" && typeof part.text === "string")?.text : undefined;
31732
+ if (!text)
31733
+ continue;
31734
+ const marker = /^(<session-history>|<session-history-since>|<memory>|§\d+§)/.exec(text)?.[0];
31735
+ return marker ?? text.slice(0, 128);
31736
+ }
31737
+ return;
31738
+ }
31739
+ function piHasManagedSignature(payload, signature) {
31740
+ if (!signature || !payload || typeof payload !== "object")
31741
+ return false;
31742
+ const body = payload;
31743
+ const google = piGoogleConversation(payload);
31744
+ const nativeText = !!google || body.inferenceConfig !== undefined;
31745
+ if (typeof body.input === "string" && body.messages === undefined)
31746
+ return body.input.slice(0, 4096).includes(signature);
31747
+ const messages = Array.isArray(body.messages) ? body.messages : Array.isArray(body.input) ? body.input : google?.contents;
31748
+ if (!messages)
31749
+ return false;
31750
+ for (const message of messages.slice(0, 8)) {
31751
+ if (!message || typeof message !== "object")
31752
+ continue;
31753
+ const content = google ? message.parts : message.content;
31754
+ if (typeof content === "string" && content.slice(0, 4096).includes(signature))
31755
+ return true;
31756
+ if (!Array.isArray(content))
31757
+ continue;
31758
+ for (const block of content.slice(0, 32)) {
31759
+ if (block && (["text", "input_text", "output_text"].includes(block.type) || nativeText && block.type === undefined) && typeof block.text === "string" && block.text.slice(0, 4096).includes(signature))
31760
+ return true;
31761
+ }
31762
+ }
31763
+ return false;
31764
+ }
31765
+
31766
+ // src/pi-dispatch-chat-history.ts
31767
+ var MAX_EXACT_UNITS = 32 * 1024 * 1024;
31768
+ var IMAGE_CAPTION = "Attached image(s) from tool result:";
31769
+ function object(value) {
31770
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
31771
+ }
31772
+ function omitsAssistant(message, model, compat) {
31773
+ if (!Array.isArray(message.content))
31774
+ return false;
31775
+ let thinking = false;
31776
+ let hasTextBlock = false;
31777
+ for (const value of message.content) {
31778
+ const block = object(value);
31779
+ if (!block)
31780
+ return false;
31781
+ if (block.type === "text") {
31782
+ hasTextBlock = true;
31783
+ if (typeof block.text !== "string" || block.text.trim())
31784
+ return false;
31785
+ } else if (block.type === "thinking") {
31786
+ if (typeof block.thinking !== "string")
31787
+ return false;
31788
+ thinking ||= block.thinking.trim().length > 0;
31789
+ } else
31790
+ return false;
31791
+ }
31792
+ if (!hasTextBlock && ["length", "error", "aborted"].includes(String(message.stopReason)))
31793
+ return true;
31794
+ if (compat.requiresReasoningContentForAllAssistantTurns === true)
31795
+ return false;
31796
+ if (!thinking)
31797
+ return true;
31798
+ return message.api === model.api && message.provider === model.provider && message.model === model.id && compat.requiresThinkingAsText !== true && compat.requiresReasoningContentForToolCalls !== true && compat.replayReasoningContent !== true && compat.mistralReasoningContentParts !== true && compat.thinkingFormat !== "zai";
31799
+ }
31800
+ function piChatHistoryPlan(messages, model) {
31801
+ if (model?.api !== "openai-completions")
31802
+ return;
31803
+ const compat = object(model.compat) ?? {};
31804
+ const calls = new Set;
31805
+ for (const value of messages) {
31806
+ const message = object(value);
31807
+ if (message?.role !== "assistant" || !Array.isArray(message.content))
31808
+ continue;
31809
+ for (const value of message.content) {
31810
+ const block = object(value);
31811
+ if (block?.type === "toolCall" && typeof block.id === "string")
31812
+ calls.add(block.id);
31813
+ }
31814
+ }
31815
+ const transformed = [];
31816
+ let pending = new Set;
31817
+ let exactUnits = 0;
31818
+ for (let index = 0;index < messages.length; index++) {
31819
+ const message = object(messages[index]);
31820
+ if (!message)
31821
+ return;
31822
+ if ((message.role === "bashExecution" || message.role === "pythonExecution") && message.excludeFromContext === true)
31823
+ continue;
31824
+ if (message.role === "assistant" || message.role === "user" || message.role === "developer")
31825
+ pending = new Set;
31826
+ if (message.role === "assistant") {
31827
+ if (omitsAssistant(message, model, compat))
31828
+ continue;
31829
+ if (Array.isArray(message.content))
31830
+ for (const value of message.content) {
31831
+ const block = object(value);
31832
+ if (block?.type === "toolCall" && typeof block.id === "string")
31833
+ pending.add(block.id);
31834
+ }
31835
+ }
31836
+ if (message.role === "toolResult" && typeof message.toolCallId === "string") {
31837
+ pending.delete(message.toolCallId);
31838
+ if (!calls.has(message.toolCallId)) {
31839
+ if (pending.size || typeof message.toolName !== "string" || !Array.isArray(message.content))
31840
+ return;
31841
+ const parts = [];
31842
+ for (const value of message.content) {
31843
+ const part = object(value);
31844
+ if (part?.type === "text" && typeof part.text === "string" && part.text.trim())
31845
+ parts.push(part.text);
31846
+ }
31847
+ if (!parts.length)
31848
+ return;
31849
+ const error = message.isError ? ' is-error="true"' : "";
31850
+ const template = `<stale-tool-result tool="${message.toolName}" id="${message.toolCallId}"${error}>
31851
+ ${parts.join(`
31852
+ `)}
31853
+ </stale-tool-result>`;
31854
+ if (exactUnits + template.length > MAX_EXACT_UNITS)
31855
+ return;
31856
+ const text = new TextDecoder().decode(new TextEncoder().encode(template));
31857
+ exactUnits += text.length;
31858
+ if (exactUnits > MAX_EXACT_UNITS)
31859
+ return;
31860
+ transformed.push({ kind: "note", text });
31861
+ continue;
31862
+ }
31863
+ }
31864
+ transformed.push({ kind: "source", index });
31865
+ }
31866
+ const steps = [];
31867
+ let images = [];
31868
+ const flushImages = () => {
31869
+ if (images.length) {
31870
+ steps.push({ kind: "images", urls: images });
31871
+ images = [];
31872
+ }
31873
+ };
31874
+ const vision = model.input?.includes("image") === true && compat.stripImageInput !== true;
31875
+ for (const step of transformed) {
31876
+ const message = step.kind === "source" ? object(messages[step.index]) : undefined;
31877
+ if (message?.role !== "toolResult")
31878
+ flushImages();
31879
+ steps.push(step);
31880
+ if (message?.role !== "toolResult" || !vision || !Array.isArray(message.content))
31881
+ continue;
31882
+ for (const value of message.content) {
31883
+ const block = object(value);
31884
+ if (block?.type !== "image")
31885
+ continue;
31886
+ if (compat.requiresAssistantAfterToolResult === true)
31887
+ return;
31888
+ let url;
31889
+ if (typeof block.url === "string")
31890
+ url = block.url;
31891
+ else if (typeof block.data === "string" && typeof block.mimeType === "string")
31892
+ url = `data:${block.mimeType};base64,${block.data}`;
31893
+ else
31894
+ return;
31895
+ exactUnits += url.length;
31896
+ if (exactUnits > MAX_EXACT_UNITS)
31897
+ return;
31898
+ images.push(url);
31899
+ }
31900
+ }
31901
+ flushImages();
31902
+ return steps;
31903
+ }
31904
+ function piMatchesChatImages(content, urls) {
31905
+ if (!Array.isArray(content) || content.length !== urls.length + 1)
31906
+ return false;
31907
+ const caption = object(content[0]);
31908
+ if (caption?.type !== "text" || caption.text !== IMAGE_CAPTION || Object.keys(caption).length !== 2)
31909
+ return false;
31910
+ for (let i = 0;i < urls.length; i++) {
31911
+ const block = object(content[i + 1]);
31912
+ const image = object(block?.image_url);
31913
+ if (block?.type !== "image_url" || Object.keys(block).length !== 2 || !image || Object.keys(image).length !== 1 || image.url !== urls[i])
31914
+ return false;
31915
+ }
31916
+ return true;
31917
+ }
31918
+
31919
+ // src/pi-dispatch-responses-history.ts
31920
+ var MAX_TEXT_UNITS = 32 * 1024 * 1024;
31921
+ function object2(value) {
31922
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
31923
+ }
31924
+ function wellFormed(text) {
31925
+ return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "�");
31926
+ }
31927
+ function textIdentity(text, phase) {
31928
+ return JSON.stringify([
31929
+ text,
31930
+ phase === "commentary" || phase === "final_answer" ? phase : null
31931
+ ]);
31932
+ }
31933
+ function signaturePhase(block) {
31934
+ try {
31935
+ if (typeof block.textSignature === "string") {
31936
+ const signature = object2(JSON.parse(block.textSignature));
31937
+ if (signature?.v === 1 && typeof signature.id === "string")
31938
+ return signature.phase;
31939
+ }
31940
+ } catch {}
31941
+ return;
31942
+ }
31943
+ function piResponsesAssistantTexts(value, model) {
31944
+ const message = object2(value);
31945
+ if (!message || !Array.isArray(message.content))
31946
+ return;
31947
+ const texts = [];
31948
+ const blocks = [];
31949
+ let units = 0;
31950
+ for (const value of message.content) {
31951
+ const block = object2(value);
31952
+ if (block?.type === "toolCall")
31953
+ continue;
31954
+ if (block?.type !== "text" || typeof block.text !== "string")
31955
+ return;
31956
+ units += block.text.length;
31957
+ if (units > MAX_TEXT_UNITS)
31958
+ return;
31959
+ const sameModel = message.api === model?.api && message.model === model?.id && message.provider === model?.provider;
31960
+ texts.push(textIdentity(wellFormed(block.text), sameModel ? signaturePhase(block) : undefined));
31961
+ blocks.push(block);
31962
+ }
31963
+ const payload = object2(message.providerPayload);
31964
+ if (message.api !== model?.api || typeof model?.id !== "string" || typeof model?.provider !== "string" || message.model !== model?.id || (payload?.provider ?? message.provider) !== model?.provider || payload?.type !== "openaiResponsesHistory" || payload.dt !== true || !Array.isArray(payload.items) || message.content.length !== blocks.length)
31965
+ return texts;
31966
+ const replay = [];
31967
+ for (const value of payload.items) {
31968
+ const item = object2(value);
31969
+ if (item?.type !== "message" || item.role !== "assistant" || !Array.isArray(item.content))
31970
+ return texts;
31971
+ for (const value of item.content) {
31972
+ const part = object2(value);
31973
+ const block = blocks[replay.length];
31974
+ if (!block || part?.type !== "output_text" || typeof part.text !== "string")
31975
+ return texts;
31976
+ let signature;
31977
+ try {
31978
+ if (typeof block.textSignature === "string")
31979
+ signature = object2(JSON.parse(block.textSignature));
31980
+ } catch {
31981
+ return texts;
31982
+ }
31983
+ if (signature?.v !== 1 || typeof signature.id !== "string" || item.id !== signature.id || item.phase !== signature.phase || part.text !== block.text.replace(/^§\d+§ /u, ""))
31984
+ return texts;
31985
+ replay.push(textIdentity(wellFormed(part.text), item.phase));
31986
+ }
31987
+ }
31988
+ return replay.length === texts.length ? replay : texts;
31989
+ }
31990
+ function piResponsesWireTexts(value, phase) {
31991
+ if (phase !== undefined && phase !== null && phase !== "commentary" && phase !== "final_answer")
31992
+ return;
31993
+ if (typeof value === "string")
31994
+ return [textIdentity(value, phase)];
31995
+ if (!Array.isArray(value))
31996
+ return;
31997
+ const texts = [];
31998
+ let units = 0;
31999
+ for (const partValue of value) {
32000
+ const part = object2(partValue);
32001
+ if (part?.type !== "output_text" || typeof part.text !== "string")
32002
+ return;
32003
+ units += part.text.length;
32004
+ if (units > MAX_TEXT_UNITS)
32005
+ return;
32006
+ texts.push(textIdentity(part.text, phase));
32007
+ }
32008
+ return texts;
32009
+ }
32010
+
32011
+ // src/pi-dispatch-structure.ts
32012
+ var MAX_MESSAGES = 1e5;
32013
+ function object3(value) {
32014
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
32015
+ }
32016
+ function messageStructure(value) {
32017
+ const message = object3(value);
32018
+ if (!message)
32019
+ return;
32020
+ const role = [
32021
+ "custom",
32022
+ "hookMessage",
32023
+ "developer",
32024
+ "branchSummary",
32025
+ "compactionSummary",
32026
+ "bashExecution",
32027
+ "pythonExecution"
32028
+ ].includes(String(message.role)) ? "user" : message.role;
32029
+ if (role !== "user" && role !== "assistant" && role !== "toolResult")
32030
+ return;
32031
+ const row = { role, calls: [], results: [] };
32032
+ if (typeof message.timestamp === "number")
32033
+ row.timestamp = message.timestamp;
32034
+ if (role === "toolResult") {
32035
+ if (typeof message.toolCallId !== "string")
32036
+ return;
32037
+ row.results.push(message.toolCallId);
32038
+ }
32039
+ if (role === "assistant" && Array.isArray(message.content)) {
32040
+ for (const value of message.content) {
32041
+ const block = object3(value);
32042
+ if (block?.type !== "toolCall" && block?.type !== "tool_use")
32043
+ continue;
32044
+ if (typeof block.id !== "string")
32045
+ return;
32046
+ row.calls.push(block.id);
32047
+ row.callNames ??= [];
32048
+ row.callNames.push(typeof block.name === "string" ? block.name : "");
32049
+ }
32050
+ }
32051
+ return row;
32052
+ }
32053
+ function piPreparedStructure(messages, model) {
32054
+ if (!messages.length || messages.length > MAX_MESSAGES)
32055
+ return;
32056
+ const rows = [];
32057
+ const toolNames = new Map;
32058
+ const byIndex = new Map;
32059
+ for (let index = 0;index < messages.length; index++) {
32060
+ const message = messages[index];
32061
+ const source = object3(message);
32062
+ if (rows.length === 0 && (source?.role === "system" || source?.role === "developer"))
32063
+ continue;
32064
+ if ((source?.role === "bashExecution" || source?.role === "pythonExecution") && source.excludeFromContext === true)
32065
+ continue;
32066
+ const row = messageStructure(message);
32067
+ if (!row)
32068
+ return;
32069
+ row.calls.forEach((id, index) => {
32070
+ toolNames.set(id, row.callNames?.[index] ?? "");
32071
+ });
32072
+ if (row.results.length)
32073
+ row.resultNames = row.results.map((id) => toolNames.get(id) ?? "");
32074
+ rows.push(row);
32075
+ byIndex.set(index, row);
32076
+ }
32077
+ const responsesApi = [
32078
+ "openai-responses",
32079
+ "azure-openai-responses",
32080
+ "openai-codex-responses"
32081
+ ].includes(model?.api ?? "");
32082
+ let responsesMessages = responsesApi ? [] : undefined;
32083
+ if (responsesMessages) {
32084
+ for (const [index, row] of byIndex) {
32085
+ if (row.role !== "assistant") {
32086
+ responsesMessages.push(row);
32087
+ continue;
32088
+ }
32089
+ const texts = piResponsesAssistantTexts(messages[index], model);
32090
+ if (!texts) {
32091
+ responsesMessages = undefined;
32092
+ break;
32093
+ }
32094
+ if (!texts.length && !row.calls.length)
32095
+ continue;
32096
+ const previous = responsesMessages.at(-1);
32097
+ if (previous?.role === "assistant") {
32098
+ previous.calls.push(...row.calls);
32099
+ previous.responseTexts?.push(...texts);
32100
+ } else
32101
+ responsesMessages.push({
32102
+ ...row,
32103
+ calls: [...row.calls],
32104
+ responseTexts: [...texts]
32105
+ });
32106
+ }
32107
+ }
32108
+ const plan = piChatHistoryPlan(messages, model);
32109
+ const chatMessages = plan?.flatMap((step) => {
32110
+ if (step.kind === "source") {
32111
+ const row = byIndex.get(step.index);
32112
+ return row ? [row] : [];
32113
+ }
32114
+ return [
32115
+ {
32116
+ role: "user",
32117
+ calls: [],
32118
+ results: [],
32119
+ ...step.kind === "note" ? { exactText: step.text } : { exactImages: step.urls }
32120
+ }
32121
+ ];
32122
+ });
32123
+ return {
32124
+ messages: rows,
32125
+ ...chatMessages ? { chatMessages } : {},
32126
+ ...responsesMessages ? { responsesMessages } : {},
32127
+ ...model?.api ? { api: model.api } : {}
32128
+ };
32129
+ }
32130
+ function payloadStructure(payload, ollama = false, responsesItems = false) {
32131
+ const body = object3(payload);
32132
+ if (!body)
32133
+ return;
32134
+ const google = piGoogleConversation(payload);
32135
+ if (google)
32136
+ return googleStructure(google.contents);
32137
+ const bedrock = body.inferenceConfig !== undefined;
32138
+ if (body.messages === undefined && typeof body.input === "string")
32139
+ return [{ role: "user", calls: [], results: [] }];
32140
+ const responses = body.messages === undefined && Array.isArray(body.input);
32141
+ const messages = responses ? body.input : body.messages;
32142
+ if (!Array.isArray(messages) || messages.length > MAX_MESSAGES)
32143
+ return;
32144
+ const rows = [];
32145
+ for (const value of messages) {
32146
+ const message = object3(value);
32147
+ if (!message)
32148
+ return;
32149
+ if (rows.length === 0 && (message.role === "system" || message.role === "developer"))
32150
+ continue;
32151
+ if (responses && message.type === "reasoning")
32152
+ continue;
32153
+ if (responses && ["function_call", "custom_tool_call", "computer_call"].includes(String(message.type))) {
32154
+ if (typeof message.call_id !== "string")
32155
+ return;
32156
+ let assistant = rows.at(-1);
32157
+ if (assistant?.role !== "assistant") {
32158
+ assistant = {
32159
+ role: "assistant",
32160
+ calls: [],
32161
+ results: [],
32162
+ ...responsesItems ? { responseTexts: [] } : {}
32163
+ };
32164
+ rows.push(assistant);
32165
+ }
32166
+ assistant.calls.push(message.call_id);
32167
+ continue;
32168
+ }
32169
+ if (responses && [
32170
+ "function_call_output",
32171
+ "custom_tool_call_output",
32172
+ "computer_call_output"
32173
+ ].includes(String(message.type))) {
32174
+ if (typeof message.call_id !== "string")
32175
+ return;
32176
+ rows.push({ role: "toolResult", calls: [], results: [message.call_id] });
32177
+ continue;
32178
+ }
32179
+ if (message.role === "tool") {
32180
+ if (message.tool_call_id === undefined && ollama && typeof message.tool_name === "string") {
32181
+ rows.push({
32182
+ role: "toolResult",
32183
+ calls: [],
32184
+ results: [""],
32185
+ resultNames: [message.tool_name],
32186
+ idlessResults: [true]
32187
+ });
32188
+ continue;
32189
+ }
32190
+ if (typeof message.tool_call_id !== "string")
32191
+ return;
32192
+ rows.push({
32193
+ role: "toolResult",
32194
+ calls: [],
32195
+ results: [message.tool_call_id]
32196
+ });
32197
+ continue;
32198
+ }
32199
+ if (message.role === "user" && Array.isArray(message.content)) {
32200
+ const results = message.content.filter((block) => object3(block)?.type === "tool_result" || bedrock && object3(block)?.toolResult);
32201
+ if (results.length) {
32202
+ for (const block of results) {
32203
+ const id = bedrock ? block.toolResult?.toolUseId : block.tool_use_id;
32204
+ if (typeof id !== "string")
32205
+ return;
32206
+ rows.push({
32207
+ role: "toolResult",
32208
+ calls: [],
32209
+ results: [id]
32210
+ });
32211
+ }
32212
+ continue;
32213
+ }
32214
+ }
32215
+ const row = messageStructure(message);
32216
+ if (!row)
32217
+ return;
32218
+ row.wireContent = message.content;
32219
+ if (responses && responsesItems && row.role === "assistant") {
32220
+ const texts = piResponsesWireTexts(message.content, message.phase);
32221
+ if (!texts)
32222
+ return;
32223
+ row.responseTexts = [...texts];
32224
+ }
32225
+ row.wireRole = message.role;
32226
+ if (bedrock && row.role === "assistant" && Array.isArray(message.content)) {
32227
+ for (const block of message.content) {
32228
+ if (!block?.toolUse)
32229
+ continue;
32230
+ if (typeof block.toolUse.toolUseId !== "string")
32231
+ return;
32232
+ row.calls.push(block.toolUse.toolUseId);
32233
+ }
32234
+ }
32235
+ if (Array.isArray(message.tool_calls)) {
32236
+ for (const call of message.tool_calls) {
32237
+ const source = object3(call);
32238
+ if (!source)
32239
+ return;
32240
+ if (source.id === undefined && ollama) {
32241
+ const fn = object3(source.function);
32242
+ if (typeof fn?.name !== "string")
32243
+ return;
32244
+ row.calls.push("");
32245
+ row.callNames ??= [];
32246
+ row.callNames.push(fn.name);
32247
+ row.idlessCalls ??= [];
32248
+ row.idlessCalls.push(true);
32249
+ } else {
32250
+ if (typeof source.id !== "string")
32251
+ return;
32252
+ row.calls.push(source.id);
32253
+ if (ollama) {
32254
+ row.callNames ??= [];
32255
+ row.callNames.push("");
32256
+ row.idlessCalls ??= [];
32257
+ row.idlessCalls.push(false);
32258
+ }
32259
+ }
32260
+ }
32261
+ }
32262
+ if (responses && row.role === "assistant" && rows.at(-1)?.role === "assistant") {
32263
+ const previous = rows[rows.length - 1];
32264
+ previous.calls.push(...row.calls);
32265
+ if (responsesItems)
32266
+ previous.responseTexts?.push(...row.responseTexts ?? []);
32267
+ } else
32268
+ rows.push(row);
32269
+ }
32270
+ return rows;
32271
+ }
32272
+ function googleStructure(contents) {
32273
+ if (contents.length > MAX_MESSAGES)
32274
+ return;
32275
+ const rows = [];
32276
+ for (const value of contents) {
32277
+ const message = object3(value);
32278
+ if (!message || !Array.isArray(message.parts))
32279
+ return;
32280
+ if (message.role !== "user" && message.role !== "model")
32281
+ return;
32282
+ const row = {
32283
+ role: message.role === "model" ? "assistant" : "user",
32284
+ calls: [],
32285
+ results: []
32286
+ };
32287
+ const results = [];
32288
+ for (const value of message.parts) {
32289
+ const part = object3(value);
32290
+ if (!part)
32291
+ return;
32292
+ if (part.functionCall) {
32293
+ const call = object3(part.functionCall);
32294
+ if (row.role !== "assistant" || typeof call?.name !== "string" || call.id !== undefined && typeof call.id !== "string")
32295
+ return;
32296
+ row.calls.push(call.id ?? "");
32297
+ row.callNames ??= [];
32298
+ row.callNames.push(call.name);
32299
+ }
32300
+ if (part.functionResponse) {
32301
+ const result = object3(part.functionResponse);
32302
+ if (row.role !== "user" || typeof result?.name !== "string" || result.id !== undefined && typeof result.id !== "string")
32303
+ return;
32304
+ results.push({
32305
+ role: "toolResult",
32306
+ calls: [],
32307
+ results: [result.id ?? ""],
32308
+ resultNames: [result.name]
32309
+ });
32310
+ }
32311
+ }
32312
+ if (results.length)
32313
+ rows.push(...results);
32314
+ else
32315
+ rows.push(row);
32316
+ }
32317
+ return rows;
32318
+ }
32319
+ function wireId(id, anthropic, responses) {
32320
+ if (anthropic)
32321
+ return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
32322
+ if (responses) {
32323
+ const callId = id.split(/[\n|]/, 1)[0];
32324
+ return /^[a-zA-Z0-9_-]{1,64}$/.test(callId) ? callId : undefined;
32325
+ }
32326
+ return id;
32327
+ }
32328
+ function safeRole(row, readable) {
32329
+ if (!readable)
32330
+ return "unreadable";
32331
+ if (!row)
32332
+ return "missing";
32333
+ return ["user", "assistant", "toolResult"].includes(row.role) ? row.role : "unknown";
32334
+ }
32335
+ function safeCount(value) {
32336
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : "unreadable";
32337
+ }
32338
+ function structureDetail(index, expected, actual, comparison) {
32339
+ const expectedRow = expected?.[index];
32340
+ const actualRow = actual?.[index];
32341
+ return `row=${index} expectedRows=${safeCount(expected?.length)} actualRows=${safeCount(actual?.length)} expectedRole=${safeRole(expectedRow, !!expected)} actualRole=${safeRole(actualRow, !!actual)} expectedCalls=${safeCount(expected ? expectedRow?.calls.length ?? 0 : undefined)} actualCalls=${safeCount(actual ? actualRow?.calls.length ?? 0 : undefined)} expectedResults=${safeCount(expected ? expectedRow?.results.length ?? 0 : undefined)} actualResults=${safeCount(actual ? actualRow?.results.length ?? 0 : undefined)} comparison=${comparison}`;
32342
+ }
32343
+ function piPreparedStructureMismatch(payload, prepared) {
32344
+ try {
32345
+ const body = object3(payload);
32346
+ const ollama = prepared?.api === "ollama-chat" && !!body && Array.isArray(body.messages) && body.input === undefined && body.system === undefined && body.inferenceConfig === undefined;
32347
+ const responses = body?.messages === undefined && Array.isArray(body?.input);
32348
+ const rows = payloadStructure(payload, ollama, responses && !!prepared?.responsesMessages);
32349
+ const chat = !!body && Array.isArray(body.messages) && body.system === undefined && body.input === undefined && body.inferenceConfig === undefined;
32350
+ const expectedRows = responses && prepared?.responsesMessages ? prepared.responsesMessages : chat && prepared?.chatMessages ? prepared.chatMessages : prepared?.messages;
32351
+ if (!rows || !expectedRows)
32352
+ return structureDetail(0, expectedRows, rows, "count");
32353
+ if (!body)
32354
+ return structureDetail(0, expectedRows, rows, "count");
32355
+ const google = !!piGoogleConversation(payload);
32356
+ const anthropic = google || body.inferenceConfig !== undefined || typeof body.system === "string" || Array.isArray(body.system);
32357
+ for (let i = 0;i < Math.min(rows.length, expectedRows.length); i++) {
32358
+ const expected = expectedRows[i];
32359
+ const actual = rows[i];
32360
+ if (actual.role !== expected.role)
32361
+ return structureDetail(i, expectedRows, rows, "role");
32362
+ if (expected.responseTexts !== undefined && (expected.responseTexts.length !== actual.responseTexts?.length || expected.responseTexts.some((text, index) => text !== actual.responseTexts?.[index])))
32363
+ return structureDetail(i, expectedRows, rows, "content");
32364
+ if (expected.exactText !== undefined || expected.exactImages !== undefined) {
32365
+ if (actual.wireRole !== "user")
32366
+ return structureDetail(i, expectedRows, rows, "role");
32367
+ if (expected.exactText !== undefined && actual.wireContent !== expected.exactText || expected.exactImages !== undefined && !piMatchesChatImages(actual.wireContent, expected.exactImages))
32368
+ return structureDetail(i, expectedRows, rows, "content");
32369
+ }
32370
+ if (actual.calls.length !== expected.calls.length || actual.results.length !== expected.results.length)
32371
+ return structureDetail(i, expectedRows, rows, "count");
32372
+ if (actual.timestamp !== undefined && actual.timestamp !== expected.timestamp)
32373
+ return structureDetail(i, expectedRows, rows, "timestamp");
32374
+ for (let j = 0;j < actual.calls.length; j++)
32375
+ if (google && actual.calls[j] === "" || ollama && actual.idlessCalls?.[j] === true ? !expected.callNames?.[j] || actual.callNames?.[j] !== expected.callNames[j] : actual.calls[j] !== wireId(expected.calls[j], anthropic, responses))
32376
+ return structureDetail(i, expectedRows, rows, google && actual.calls[j] === "" || ollama && actual.idlessCalls?.[j] === true ? "name" : "call id");
32377
+ for (let j = 0;j < actual.results.length; j++)
32378
+ if (google && actual.results[j] === "" || ollama && actual.idlessResults?.[j] === true ? !expected.resultNames?.[j] || actual.resultNames?.[j] !== expected.resultNames[j] : actual.results[j] !== wireId(expected.results[j], anthropic, responses))
32379
+ return structureDetail(i, expectedRows, rows, google && actual.results[j] === "" || ollama && actual.idlessResults?.[j] === true ? "name" : "result id");
32380
+ }
32381
+ if (rows.length !== expectedRows.length)
32382
+ return structureDetail(Math.min(rows.length, expectedRows.length), expectedRows, rows, "count");
32383
+ return;
32384
+ } catch {
32385
+ return structureDetail(0, undefined, undefined, "count");
32386
+ }
32387
+ }
32388
+
31853
32389
  // src/pi-context-refusal.ts
31854
32390
  var ENTRY_TYPE = "magic-context-turn-refused";
31855
32391
  var RETRY_MESSAGE = "Magic Context could not safely prepare this turn; send your message again.";
@@ -31867,6 +32403,26 @@ function clearPiContextReceipt(sessionId) {
31867
32403
  for (const receipts of receiptMaps)
31868
32404
  receipts.delete(sessionId);
31869
32405
  }
32406
+ function createPiContextOwnershipGuards(operations, key, active, budget, owner) {
32407
+ const sideTurn = budget.sideTurn;
32408
+ const signal = budget.signal;
32409
+ const isOwned = () => sideTurn ? operations.get(key) === owner : operations.get(key) === active && active.pass === budget;
32410
+ const isCurrent = () => isOwned() && (sideTurn || !active.ended);
32411
+ const assertOwner = () => {
32412
+ if (!isCurrent())
32413
+ throw new PiContextSupersededError("Pi context pass superseded: no longer valid for this operation", active.ended ? "agent_end" : operations.get(key) !== (sideTurn ? owner : active) ? "operation replacement or cache eviction" : "newer context pass");
32414
+ signal?.throwIfAborted();
32415
+ };
32416
+ return { isOwned, isCurrent, assertOwner };
32417
+ }
32418
+ function releasePiOperationPayloads(operation) {
32419
+ operation.inputKeys = undefined;
32420
+ operation.inputMessages = undefined;
32421
+ operation.inputBranch = undefined;
32422
+ operation.dispatchFields = undefined;
32423
+ operation.managedSignature = undefined;
32424
+ operation.preparedStructure = undefined;
32425
+ }
31870
32426
  function operationKey(ctx) {
31871
32427
  return ctx.sessionManager?.getSessionId?.() ?? ctx.sessionManager ?? "no-session";
31872
32428
  }
@@ -31894,6 +32450,69 @@ function endBelongsToEarlierRun(operation, event) {
31894
32450
  return false;
31895
32451
  return operation.inputKeys.some((key) => !ended.has(key));
31896
32452
  }
32453
+ function messageSnapshots(messages) {
32454
+ const snapshots = [];
32455
+ for (const message of messages) {
32456
+ const id = messageKey(message);
32457
+ const fields = lkgContentFields(message);
32458
+ if (!id || !fields)
32459
+ return;
32460
+ snapshots.push({ id, fields });
32461
+ }
32462
+ return snapshots.length ? snapshots : undefined;
32463
+ }
32464
+ function inputBranch(ctx, inputs) {
32465
+ try {
32466
+ const branch = ctx.sessionManager.getBranch();
32467
+ const entries = branch.filter((entry) => entry.type === "message" || entry.type === "custom_message");
32468
+ const anchorId = entries.at(-1)?.id;
32469
+ const native = messageSnapshots(entries.map((entry) => {
32470
+ if (entry.type === "message")
32471
+ return entry.message;
32472
+ const attribution = entry.attribution;
32473
+ const timestamp = new Date(entry.timestamp).getTime();
32474
+ if (!Number.isFinite(timestamp) || !entry.customType || typeof entry.content !== "string" && !Array.isArray(entry.content) || attribution !== undefined && attribution !== "agent" && attribution !== "user")
32475
+ return;
32476
+ return {
32477
+ role: "custom",
32478
+ customType: entry.customType,
32479
+ content: entry.content,
32480
+ display: entry.display,
32481
+ details: entry.details,
32482
+ attribution,
32483
+ timestamp
32484
+ };
32485
+ }));
32486
+ inputs ??= native;
32487
+ if (!anchorId || !native || !inputs || native.length > inputs.length || exactReusablePrefix(native, inputs) !== native.length)
32488
+ return;
32489
+ return {
32490
+ anchorId,
32491
+ anchorIndex: native.length - 1,
32492
+ entryIds: entries.map((entry) => entry.id),
32493
+ messages: inputs
32494
+ };
32495
+ } catch {
32496
+ return;
32497
+ }
32498
+ }
32499
+ function dispatchedEndBelongsToEarlierRun(operation, event, ctx) {
32500
+ if (!operation.dispatched || !operation.started || !operation.ready || !operation.pass?.completed || operation.refused || operation.pass.abandoned || !operation.inputBranch)
32501
+ return false;
32502
+ try {
32503
+ if (ctx.isIdle() !== false)
32504
+ return false;
32505
+ const current = inputBranch(ctx);
32506
+ const prepared = operation.inputBranch;
32507
+ if (!current || current.entryIds[prepared.anchorIndex] !== prepared.anchorId || current.messages.length !== prepared.messages.length || exactReusablePrefix(current.messages, prepared.messages) !== prepared.messages.length)
32508
+ return false;
32509
+ const messages = event?.messages;
32510
+ const ended = Array.isArray(messages) ? messageSnapshots(messages) : undefined;
32511
+ return !!(ended && ended.length <= prepared.anchorIndex && ended.length < prepared.messages.length && exactReusablePrefix(prepared.messages, ended) === ended.length);
32512
+ } catch {
32513
+ return false;
32514
+ }
32515
+ }
31897
32516
  function inputMessageKeys(event) {
31898
32517
  try {
31899
32518
  const messages = event.messages;
@@ -31915,6 +32534,7 @@ function registerPiGuardedContext(pi, handler, options = {}) {
31915
32534
  const sideSessions = new Map;
31916
32535
  receiptMaps.add(operations);
31917
32536
  const newOperation = () => ({
32537
+ retainedAfterEnd: false,
31918
32538
  dispatched: false,
31919
32539
  started: false,
31920
32540
  ready: false,
@@ -31943,6 +32563,7 @@ function registerPiGuardedContext(pi, handler, options = {}) {
31943
32563
  budget.recovery = budget.recovery === "not attempted" ? "no managed result; refused" : budget.recovery;
31944
32564
  const identityConflict = findPiTagIdentityConflict2(reason);
31945
32565
  const message = identityConflict ? `${identityConflict.message}. ${budget.diagnostic()}` : `${RETRY_MESSAGE} ${budget.diagnostic()} (${reason instanceof Error ? reason.message : String(reason)})`;
32566
+ log2("[magic-context][pi] CONTEXT REFUSED", message);
31946
32567
  try {
31947
32568
  ctx.ui?.notify(message, "error");
31948
32569
  } catch (error) {
@@ -31980,7 +32601,9 @@ function registerPiGuardedContext(pi, handler, options = {}) {
31980
32601
  log2(`[magic-context][pi] OMP context counts session=${String(key)} side_contexts=${counts.sides} context_passes=${counts.contexts} dispatch_fence=${counts.sides ? "latched off" : "on"}`);
31981
32602
  const operation = operations.get(key);
31982
32603
  if (operation) {
31983
- if (endBelongsToEarlierRun(operation, event)) {
32604
+ if (endBelongsToEarlierRun(operation, event) || lifecycleSeen.starts > lifecycleSeen.ends && dispatchedEndBelongsToEarlierRun(operation, event, ctx)) {
32605
+ if (operation.dispatched)
32606
+ operation.retainedAfterEnd = true;
31984
32607
  if (lifecycleSeen.starts <= lifecycleSeen.ends)
31985
32608
  operation.started = false;
31986
32609
  log2(`[magic-context][pi] agent_end attributed to an earlier run; keeping the latest context pass session=${String(key)} ${operation.pass?.diagnostic() ?? ""}`);
@@ -31988,9 +32611,18 @@ function registerPiGuardedContext(pi, handler, options = {}) {
31988
32611
  }
31989
32612
  operation.ended = true;
31990
32613
  operation.ready = false;
32614
+ releasePiOperationPayloads(operation);
31991
32615
  }
31992
32616
  });
31993
32617
  pi.on("before_provider_request", (event, ctx) => {
32618
+ const cancelledOperation = operations.get(operationKey(ctx));
32619
+ const signal = ctx.signal;
32620
+ if (signal ? signal.aborted : cancelledOperation?.pass?.isCancelled()) {
32621
+ cancelledOperation?.pass?.cancel();
32622
+ if (cancelledOperation)
32623
+ cancelledOperation.ready = false;
32624
+ return;
32625
+ }
31994
32626
  if (options.compactionOff?.(ctx))
31995
32627
  return;
31996
32628
  const payload = event.payload;
@@ -32018,6 +32650,10 @@ function registerPiGuardedContext(pi, handler, options = {}) {
32018
32650
  const isCurrent = () => operations.get(key) === active;
32019
32651
  const capture = isOmpUnmanagedCaptureRequest(payload);
32020
32652
  const budget = (capture ? undefined : active.pass) ?? new PiContextBudget;
32653
+ if (active.refused && active.pass === budget) {
32654
+ ctx.abort();
32655
+ return;
32656
+ }
32021
32657
  let refusalOrigin;
32022
32658
  try {
32023
32659
  if (capture)
@@ -32032,8 +32668,33 @@ function registerPiGuardedContext(pi, handler, options = {}) {
32032
32668
  }
32033
32669
  if (!budget.completed || !active.ready || active.refused || budget.abandoned)
32034
32670
  throw new Error("context pass ran without a managed context receipt");
32671
+ if (!piHasManagedSignature(payload, active.managedSignature))
32672
+ throw new Error("provider request does not match this pass's managed dispatch (missing current receipt signature)");
32673
+ const fields = piConversationFields(payload);
32674
+ if (!fields)
32675
+ throw new Error("provider conversation identity could not be established");
32676
+ const structureMismatch = piPreparedStructureMismatch(payload, active.preparedStructure);
32677
+ if (structureMismatch)
32678
+ throw new Error(`provider request does not match this pass's managed dispatch (prepared turn structure); ${structureMismatch}`);
32679
+ if (active.dispatched) {
32680
+ if (!active.dispatchFields || exactReusablePrefix([{ id: "conversation", fields }], [{ id: "conversation", fields: active.dispatchFields }]) !== 1)
32681
+ throw new Error("provider request does not match this pass's managed dispatch");
32682
+ }
32683
+ if (!active.dispatched && active.inputMessages && (!active.inputBranch || active.inputBranch.anchorIndex < active.inputMessages.length - 1)) {
32684
+ const previous = active.inputBranch;
32685
+ const persisted = inputBranch(ctx, active.inputMessages);
32686
+ if (!previous || persisted && persisted.anchorIndex > previous.anchorIndex && persisted.entryIds[previous.anchorIndex] === previous.anchorId)
32687
+ active.inputBranch = persisted;
32688
+ }
32689
+ if (!active.dispatched)
32690
+ active.dispatchFields = fields;
32035
32691
  active.dispatched = true;
32036
32692
  } catch (error) {
32693
+ if (signal ? signal.aborted : budget.isCancelled(error)) {
32694
+ budget.cancel();
32695
+ active.ready = false;
32696
+ return;
32697
+ }
32037
32698
  active.refused = true;
32038
32699
  budget.stage = refusalOrigin ? `provider dispatch (origin=${refusalOrigin}; context stage=${budget.stage})` : "provider dispatch";
32039
32700
  refuse(ctx, budget, error, isCurrent);
@@ -32045,6 +32706,7 @@ function registerPiGuardedContext(pi, handler, options = {}) {
32045
32706
  if (fenceEnabled && isOmpDumpContext())
32046
32707
  return { messages: event.messages };
32047
32708
  const budget = new PiContextBudget;
32709
+ budget.signal = event.signal ?? ctx.signal;
32048
32710
  budget.sideTurn = fenceEnabled && isOmpSideContext(event);
32049
32711
  const key = operationKey(ctx);
32050
32712
  if (fenceEnabled) {
@@ -32057,7 +32719,7 @@ function registerPiGuardedContext(pi, handler, options = {}) {
32057
32719
  if (budget.sideTurn && ++counts.sides === 1)
32058
32720
  log2(`[magic-context][pi] OMP dispatch fence disabled for session ${String(key)}: verified ephemeral context; session-wide abort cannot distinguish provider operations (side_contexts=${counts.sides} context_passes=${counts.contexts})`);
32059
32721
  }
32060
- const owner = operations.get(key);
32722
+ const owner = budget.sideTurn ? operations.get(key) : undefined;
32061
32723
  let operation = operations.get(key);
32062
32724
  if (budget.sideTurn || !operation || operation.ended || !fenceEnabled) {
32063
32725
  operation = newOperation();
@@ -32066,26 +32728,38 @@ function registerPiGuardedContext(pi, handler, options = {}) {
32066
32728
  }
32067
32729
  const active = operation;
32068
32730
  active.pass = budget;
32069
- active.inputKeys = undefined;
32731
+ releasePiOperationPayloads(active);
32732
+ active.retainedAfterEnd = false;
32070
32733
  active.dispatched = false;
32071
32734
  active.ready = false;
32072
32735
  active.refused = false;
32073
- const isOwned = () => budget.sideTurn ? operations.get(key) === owner : operations.get(key) === active && active.pass === budget;
32074
- const isCurrent = () => isOwned() && (budget.sideTurn || !active.ended);
32075
- budget.assertOwner = () => {
32076
- if (!isCurrent())
32077
- throw new PiContextSupersededError("Pi context pass superseded: no longer valid for this operation", active.ended ? "agent_end" : operations.get(key) !== (budget.sideTurn ? owner : active) ? "operation replacement or cache eviction" : "newer context pass");
32078
- };
32736
+ const { isOwned, isCurrent, assertOwner } = createPiContextOwnershipGuards(operations, key, active, budget, owner);
32737
+ budget.assertOwner = assertOwner;
32079
32738
  try {
32080
- if (fenceEnabled && !budget.sideTurn)
32739
+ budget.assertOutcome();
32740
+ let inputs;
32741
+ if (fenceEnabled && !budget.sideTurn) {
32081
32742
  active.inputKeys = inputMessageKeys(event);
32743
+ inputs = messageSnapshots(event.messages);
32744
+ active.inputMessages = inputs;
32745
+ }
32082
32746
  const result = await budget.waitMandatory(Promise.resolve(withSqliteTransformPass2(() => handler(event, ctx, budget))));
32083
32747
  if (result?.messages) {
32748
+ active.managedSignature = piManagedSignature(result.messages);
32749
+ active.preparedStructure = piPreparedStructure(result.messages, fenceEnabled ? ctx.model : undefined);
32084
32750
  budget.completed = true;
32085
32751
  active.ready = true;
32752
+ if (inputs)
32753
+ active.inputBranch = inputBranch(ctx, inputs);
32086
32754
  }
32087
32755
  return result;
32088
32756
  } catch (error) {
32757
+ if (budget.isCancelled(error)) {
32758
+ budget.cancel();
32759
+ if (isOwned())
32760
+ active.ready = false;
32761
+ return;
32762
+ }
32089
32763
  if (error instanceof PiContextSupersededError || !isCurrent()) {
32090
32764
  if (fenceEnabled && !budget.sideTurn && !sideSessions.get(key)?.sides && !options.compactionOff?.(ctx)) {
32091
32765
  const nonce = crypto.randomUUID();
@@ -32123,6 +32797,9 @@ function registerPiGuardedContext(pi, handler, options = {}) {
32123
32797
  active.refused = true;
32124
32798
  refuse(ctx, budget, error, isOwned);
32125
32799
  return { messages: event.messages };
32800
+ } finally {
32801
+ if (!fenceEnabled || budget.sideTurn)
32802
+ releasePiOperationPayloads(active);
32126
32803
  }
32127
32804
  });
32128
32805
  }
@@ -32241,342 +32918,6 @@ function createPiFallbackIndex() {
32241
32918
  };
32242
32919
  }
32243
32920
 
32244
- // ../plugin/src/hooks/magic-context/openai-compat-adjacency.ts
32245
- function assertOpenAiCompatAdjacency(messages) {
32246
- const violations = [];
32247
- for (let i = 0;i < messages.length; i++) {
32248
- const msg = messages[i];
32249
- if (msg.role !== "assistant" || !msg.tool_calls || msg.tool_calls.length === 0) {
32250
- continue;
32251
- }
32252
- const expectedIds = msg.tool_calls.map((tc) => tc.id);
32253
- const expectedSet = new Set(expectedIds);
32254
- const collected = new Map;
32255
- let j = i + 1;
32256
- while (j < messages.length && messages[j].role === "tool") {
32257
- const toolMsg = messages[j];
32258
- const id = toolMsg.tool_call_id;
32259
- if (!id) {
32260
- violations.push({
32261
- index: i,
32262
- kind: "unmatched_tool_call_id",
32263
- detail: `tool message at index ${j} missing tool_call_id`
32264
- });
32265
- } else if (!expectedSet.has(id)) {
32266
- violations.push({
32267
- index: i,
32268
- kind: "unmatched_tool_call_id",
32269
- toolCallId: id,
32270
- assistantToolCallIds: expectedIds,
32271
- detail: `tool message at index ${j} references unexpected id ${id}`
32272
- });
32273
- } else {
32274
- collected.set(id, j);
32275
- }
32276
- j++;
32277
- }
32278
- const followingRoles = messages.slice(i + 1, Math.min(messages.length, i + 4)).map((m) => m.role);
32279
- const missing = expectedIds.filter((id) => !collected.has(id));
32280
- if (missing.length > 0) {
32281
- violations.push({
32282
- index: i,
32283
- kind: "missing_tool_messages",
32284
- assistantToolCallIds: expectedIds,
32285
- followingRoles,
32286
- detail: missing.length === expectedIds.length ? `assistant at index ${i} has tool_calls but next messages are not contiguous tool role (following: ${followingRoles.join(", ") || "none"})` : `assistant at index ${i} missing tool results for: ${missing.join(", ")}`
32287
- });
32288
- if (j < messages.length && messages[j].role !== "tool") {
32289
- const last = violations[violations.length - 1];
32290
- last.detail += `; blocked by ${messages.slice(i + 1, j + 1).map((m, off) => `${m.role}[${i + 1 + off}]`).join(", ")}`;
32291
- }
32292
- }
32293
- }
32294
- for (let i = 0;i < messages.length; i++) {
32295
- if (messages[i].role !== "tool")
32296
- continue;
32297
- const id = messages[i].tool_call_id ?? "";
32298
- if (!id)
32299
- continue;
32300
- let found = false;
32301
- for (let k = i - 1;k >= 0; k--) {
32302
- const prev = messages[k];
32303
- if (prev.role === "assistant" && prev.tool_calls?.some((tc) => tc.id === id)) {
32304
- const between = messages.slice(k + 1, i);
32305
- if (between.every((m) => m.role === "tool")) {
32306
- found = true;
32307
- }
32308
- break;
32309
- }
32310
- if (prev.role === "assistant" || prev.role === "user")
32311
- break;
32312
- }
32313
- if (!found) {
32314
- violations.push({
32315
- index: i,
32316
- kind: "orphan_tool_message",
32317
- toolCallId: id,
32318
- detail: `tool message at index ${i} is not immediately after its assistant tool_calls`
32319
- });
32320
- }
32321
- }
32322
- return { ok: violations.length === 0, violations };
32323
- }
32324
-
32325
- // ../plugin/src/hooks/magic-context/lkg-replay.ts
32326
- function canonicalLkgModelKeys(modelKey, providerKey) {
32327
- const canonicalModelKey = modelKey ? piModelRefToCanonical(modelKey) : null;
32328
- const slash = canonicalModelKey?.indexOf("/") ?? -1;
32329
- return {
32330
- modelKey: canonicalModelKey,
32331
- providerKey: slash > 0 && canonicalModelKey ? canonicalModelKey.slice(0, slash) : providerKey
32332
- };
32333
- }
32334
- function recordValue(info, key) {
32335
- return info && typeof info === "object" ? info[key] : undefined;
32336
- }
32337
- function messageInfo(message) {
32338
- if (message.info && typeof message.info === "object")
32339
- return message.info;
32340
- return message;
32341
- }
32342
- function messageParts(message) {
32343
- return Array.isArray(message.parts) ? message.parts : [];
32344
- }
32345
- function messageRole(message) {
32346
- const infoRole = recordValue(messageInfo(message), "role");
32347
- if (typeof infoRole === "string")
32348
- return infoRole;
32349
- const role = recordValue(message, "role");
32350
- return typeof role === "string" ? role : undefined;
32351
- }
32352
- function messageId2(message) {
32353
- const id = recordValue(messageInfo(message), "id") ?? recordValue(message, "id");
32354
- return typeof id === "string" && id.length > 0 ? id : null;
32355
- }
32356
- function entryIdsAreValid(slot, entryIds) {
32357
- if (slot.inputIdSeq.length === 0 || entryIds.length < slot.inputIdSeq.length)
32358
- return false;
32359
- if (slot.inputIdSeq[slot.inputIdSeq.length - 1] !== slot.lastInputMessageId)
32360
- return false;
32361
- const seen = new Set;
32362
- for (const id of entryIds) {
32363
- if (!id || seen.has(id))
32364
- return false;
32365
- seen.add(id);
32366
- }
32367
- if (entryIds.indexOf(slot.lastInputMessageId) !== slot.inputIdSeq.length - 1)
32368
- return false;
32369
- for (let index = 0;index < slot.inputIdSeq.length; index += 1) {
32370
- if (entryIds[index] !== slot.inputIdSeq[index])
32371
- return false;
32372
- }
32373
- return true;
32374
- }
32375
- function entryContentIsValid(slot, entry) {
32376
- return entry.entryContentDigests.length >= slot.inputContentDigests.length && slot.inputContentDigests.every((digest, index) => isLegacyLkgDigest(digest) ? entry.entryLegacyContentDigests?.[index] === digest : entry.entryContentDigests[index] === digest);
32377
- }
32378
- function partCallIds(message) {
32379
- const ids = [];
32380
- for (const rawPart of messageParts(message)) {
32381
- if (!rawPart || typeof rawPart !== "object")
32382
- continue;
32383
- const part = rawPart;
32384
- if (part.type !== "tool" && part.type !== "tool_use")
32385
- continue;
32386
- const callId = part.callID ?? part.callId ?? part.id;
32387
- if (typeof callId === "string" && callId.length > 0)
32388
- ids.push(callId);
32389
- }
32390
- return ids;
32391
- }
32392
- function partResultIds(message) {
32393
- const ids = [];
32394
- for (const rawPart of messageParts(message)) {
32395
- if (!rawPart || typeof rawPart !== "object")
32396
- continue;
32397
- const part = rawPart;
32398
- if (part.type !== "tool_result" && part.type !== "tool-result")
32399
- continue;
32400
- const callId = part.tool_call_id ?? part.tool_use_id ?? part.callID ?? part.callId;
32401
- if (typeof callId === "string" && callId.length > 0)
32402
- ids.push(callId);
32403
- }
32404
- return ids;
32405
- }
32406
- function partIsReasoning(part) {
32407
- return Boolean(part && typeof part === "object" && part.type === "reasoning");
32408
- }
32409
- function partIsAnthropicThinking(part) {
32410
- if (!part || typeof part !== "object")
32411
- return false;
32412
- const type = part.type;
32413
- return type === "thinking" || type === "reasoning" || type === "redacted_thinking";
32414
- }
32415
- function partEndsAnthropicAssistantRun(part) {
32416
- if (!part || typeof part !== "object")
32417
- return false;
32418
- const value = part;
32419
- if (value.type !== "tool" || value.providerExecuted === true || !value.state || typeof value.state !== "object") {
32420
- return false;
32421
- }
32422
- const status = value.state.status;
32423
- return status === "completed" || status === "error";
32424
- }
32425
- function partIsOpenCodeStepMetadata(part) {
32426
- if (!part || typeof part !== "object")
32427
- return false;
32428
- const type = part.type;
32429
- return type === "step-start" || type === "step-finish";
32430
- }
32431
- function validateAnthropicReasoningRuns(messages) {
32432
- let index = 0;
32433
- while (index < messages.length) {
32434
- if (messageRole(messages[index]) !== "assistant") {
32435
- index += 1;
32436
- continue;
32437
- }
32438
- let firstMessageInRun = null;
32439
- let sawOtherContent = false;
32440
- while (index < messages.length && messageRole(messages[index]) === "assistant") {
32441
- for (const part of messageParts(messages[index])) {
32442
- if (partEndsAnthropicAssistantRun(part)) {
32443
- firstMessageInRun = null;
32444
- sawOtherContent = false;
32445
- } else if (!partIsOpenCodeStepMetadata(part)) {
32446
- if (firstMessageInRun === null)
32447
- firstMessageInRun = index;
32448
- if (partIsAnthropicThinking(part)) {
32449
- if (sawOtherContent || index !== firstMessageInRun)
32450
- return false;
32451
- } else {
32452
- sawOtherContent = true;
32453
- }
32454
- }
32455
- }
32456
- index += 1;
32457
- }
32458
- }
32459
- return true;
32460
- }
32461
- function validateLkgSeamBoundary(prefix, tail) {
32462
- const last = prefix[prefix.length - 1];
32463
- const first = tail[0];
32464
- if (!last || !first)
32465
- return true;
32466
- const lastCalls = partCallIds(last);
32467
- if (lastCalls.length === 0)
32468
- return true;
32469
- const firstCalls = new Set([...partCallIds(first), ...partResultIds(first)]);
32470
- if (messageRole(first) === "tool" || lastCalls.some((callId) => firstCalls.has(callId)))
32471
- return false;
32472
- return !messageParts(last).some((part) => {
32473
- if (!part || typeof part !== "object")
32474
- return false;
32475
- const value = part;
32476
- if (value.type !== "tool")
32477
- return false;
32478
- const state = value.state;
32479
- return !state || typeof state !== "object" || state.status !== "completed";
32480
- });
32481
- }
32482
- function validateLkgSeam(prefix, tail, providerKey) {
32483
- const all = [...prefix, ...tail];
32484
- const ids = new Set;
32485
- const calls = new Set;
32486
- const results = new Set;
32487
- for (const message of all) {
32488
- const id = messageId2(message);
32489
- if (id !== null) {
32490
- if (ids.has(id))
32491
- return false;
32492
- ids.add(id);
32493
- }
32494
- for (const callId of partCallIds(message)) {
32495
- if (calls.has(callId))
32496
- return false;
32497
- calls.add(callId);
32498
- }
32499
- for (const callId of partResultIds(message)) {
32500
- if (results.has(callId))
32501
- return false;
32502
- results.add(callId);
32503
- }
32504
- if (messageRole(message) !== "assistant" && messageParts(message).some(partIsReasoning))
32505
- return false;
32506
- if (providerKey !== "anthropic" && messageParts(message).some((part) => {
32507
- if (!part || typeof part !== "object")
32508
- return false;
32509
- const value = part;
32510
- return (value.type === "text" || value.type === "reasoning") && value.text === "";
32511
- }))
32512
- return false;
32513
- }
32514
- if (!validateLkgSeamBoundary(prefix, tail))
32515
- return false;
32516
- const wireCandidates = all.map((message) => message);
32517
- if (wireCandidates.every((message) => typeof message.role === "string")) {
32518
- const adjacency = assertOpenAiCompatAdjacency(wireCandidates);
32519
- if (!adjacency.ok)
32520
- return false;
32521
- const wireCallIds = new Set;
32522
- for (const wireMessage of wireCandidates) {
32523
- for (const call of wireMessage.tool_calls ?? []) {
32524
- if (wireCallIds.has(call.id))
32525
- return false;
32526
- wireCallIds.add(call.id);
32527
- }
32528
- }
32529
- }
32530
- return true;
32531
- }
32532
- function replayLkg(args) {
32533
- const slot = getSlot(args.sessionId);
32534
- if (!slot)
32535
- return { ok: false, reason: "lkg_invalidated_reshape" };
32536
- const requestedModelKeys = canonicalLkgModelKeys(args.modelKey, args.providerKey);
32537
- const capturedModelKeys = canonicalLkgModelKeys(slot.modelKey, slot.providerKey);
32538
- if (capturedModelKeys.modelKey !== requestedModelKeys.modelKey || capturedModelKeys.providerKey !== requestedModelKeys.providerKey) {
32539
- dropSlot(args.sessionId, "lkg_model_mismatch");
32540
- return { ok: false, reason: "lkg_model_mismatch" };
32541
- }
32542
- const entry = args.entry ?? noteEntry(args.sessionId, args.messages);
32543
- if (!entry || entry.anchorIndex !== slot.inputIdSeq.length - 1 || !entryIdsAreValid(slot, entry.entryInputIds)) {
32544
- dropSlot(args.sessionId, "lkg_invalidated_reshape");
32545
- return { ok: false, reason: "lkg_invalidated_reshape" };
32546
- }
32547
- if (!entryContentIsValid(slot, entry)) {
32548
- dropSlot(args.sessionId, "lkg_content_mismatch");
32549
- return { ok: false, reason: "lkg_content_mismatch" };
32550
- }
32551
- let prefix;
32552
- try {
32553
- const parsed = JSON.parse(slot.jsonPrefix);
32554
- if (!Array.isArray(parsed))
32555
- throw new Error("prefix is not an array");
32556
- prefix = parsed;
32557
- } catch {
32558
- dropSlot(args.sessionId, "lkg_seam_invalid");
32559
- return { ok: false, reason: "lkg_seam_invalid" };
32560
- }
32561
- const replayed = [...prefix, ...entry.pristineTail];
32562
- args.prepareReplay?.(replayed);
32563
- if (!args.skipSeamValidation) {
32564
- if (!validateLkgSeamBoundary(prefix, entry.pristineTail)) {
32565
- dropSlot(args.sessionId, "lkg_unsafe_seam");
32566
- return { ok: false, reason: "lkg_unsafe_seam" };
32567
- }
32568
- if (!validateLkgSeam(prefix, entry.pristineTail, requestedModelKeys.providerKey)) {
32569
- dropSlot(args.sessionId, "lkg_seam_invalid");
32570
- return { ok: false, reason: "lkg_seam_invalid" };
32571
- }
32572
- }
32573
- if (requestedModelKeys.providerKey === "anthropic" && !validateAnthropicReasoningRuns(replayed)) {
32574
- dropSlot(args.sessionId, "lkg_anthropic_reasoning_run_invalid");
32575
- return { ok: false, reason: "lkg_anthropic_reasoning_run_invalid" };
32576
- }
32577
- return { ok: true, messages: replayed };
32578
- }
32579
-
32580
32921
  // src/pi-lkg.ts
32581
32922
  var piLkgSessionStates = new Map;
32582
32923
  function completedProviderUsage(message) {
@@ -32633,6 +32974,7 @@ function clearPiLkgSessionState(sessionId) {
32633
32974
  if (state)
32634
32975
  state.captureSequence += 1;
32635
32976
  piLkgSessionStates.delete(sessionId);
32977
+ clearLkgFenceProcessState(sessionId);
32636
32978
  }
32637
32979
 
32638
32980
  class PiLkgUncapturable extends Error {
@@ -32853,6 +33195,50 @@ function createPiLkgCoordinator(db, scheduleCapture = (capture) => setImmediate(
32853
33195
  }
32854
33196
  return state;
32855
33197
  };
33198
+ const recoveryFor = (snapshot) => {
33199
+ const state = stateFor(snapshot.sessionId);
33200
+ const prefix = state.recoveryPrefix;
33201
+ if (!prefix) {
33202
+ const slot = getSlot(snapshot.sessionId);
33203
+ return lkgRecoveryFenceUnclean(snapshot.sessionId) || slot && lkgFenceRequiresRebuild(snapshot.sessionId, state.acceptedInputs ? slot : loadPersistedLkgSlot(db, snapshot.sessionId) ?? slot, !!state.acceptedInputs) ? { rebuildReason: "lkg_restart_rebuild" } : {};
33204
+ }
33205
+ const durableSlot = loadPersistedLkgSlot(db, snapshot.sessionId) ?? getSlot(snapshot.sessionId);
33206
+ if (snapshot.preparationFailure || !durableSlot || !ownsLkgDirtyFence(snapshot.sessionId, prefix.fenceRevision) || prefix.modelKey !== snapshot.modelKey || prefix.providerKey !== snapshot.providerKey || JSON.stringify(prefix.systemEntries) !== JSON.stringify(snapshot.systemEntries) || exactReusablePrefix(snapshot.inputs, prefix.inputs) !== prefix.inputs.length)
33207
+ return { rebuildReason: "lkg_recovery_input_rebuild" };
33208
+ return { prefix };
33209
+ };
33210
+ const noteRecovery = (snapshot, messages) => {
33211
+ const state = stateFor(snapshot.sessionId);
33212
+ const anchor = snapshot.replayAnchorInputIndex;
33213
+ const slot = getSlot(snapshot.sessionId);
33214
+ if (snapshot.preparationFailure || anchor === null || !slot?.piOutputEntryIds)
33215
+ throw new PiLkgUncapturable("lkg_output_mapping_unavailable", "Cannot retain recovered output ownership");
33216
+ const surviving = new Set(snapshot.inputs.map((input) => input.id));
33217
+ const outputEntryIds = [
33218
+ ...slot.piOutputEntryIds.filter((id) => id === null || surviving.has(id)),
33219
+ ...snapshot.inputs.slice(anchor + 1).map((input) => input.id)
33220
+ ];
33221
+ if (outputEntryIds.length !== messages.length)
33222
+ throw new PiLkgUncapturable("lkg_output_mapping_unavailable", "Recovered output ownership does not match the served array");
33223
+ state.recoveryPrefix = {
33224
+ fenceRevision: markLkgRecoveryDirty({
33225
+ sessionId: snapshot.sessionId,
33226
+ slot,
33227
+ processLocalProof: !!state.acceptedInputs,
33228
+ ownDirtyRevision: state.recoveryPrefix?.fenceRevision
33229
+ }),
33230
+ modelKey: snapshot.modelKey,
33231
+ providerKey: snapshot.providerKey,
33232
+ systemEntries: snapshot.systemEntries,
33233
+ inputs: snapshot.inputs,
33234
+ json: JSON.stringify(messages),
33235
+ outputEntryIds,
33236
+ untaggedInputIds: new Set([
33237
+ ...state.recoveryPrefix?.untaggedInputIds ?? [],
33238
+ ...snapshot.inputs.slice(anchor + 1).map((input) => input.id)
33239
+ ])
33240
+ };
33241
+ };
32856
33242
  const beginPass = (args) => {
32857
33243
  const snapped = snapshotInputs(args.messages, args.entryIds, omitsRootBookkeeping(args));
32858
33244
  const slot = getSlot(args.sessionId);
@@ -32949,7 +33335,8 @@ function createPiLkgCoordinator(db, scheduleCapture = (capture) => setImmediate(
32949
33335
  modelKey: piModelRefToCanonical(request.modelKey).toLowerCase(),
32950
33336
  inputTokens: request.usage.inputTokens,
32951
33337
  envelopeSignature: request.envelopeSignature,
32952
- appendedMessages
33338
+ appendedMessages,
33339
+ previousMessages: JSON.parse(request.jsonPrefix)
32953
33340
  };
32954
33341
  };
32955
33342
  const replay = (snapshot, parentOf) => {
@@ -33169,7 +33556,10 @@ function createPiLkgCoordinator(db, scheduleCapture = (capture) => setImmediate(
33169
33556
  if (args.publishServedNumbers) {
33170
33557
  if (lkgSlotRejection(plan.sessionId, slot))
33171
33558
  throw new PiLkgUncapturable("lkg_slot_rejected", "LKG slot rejected the Pi snapshot");
33172
- if (!saveLkgSlotToDb(db, plan.sessionId, slot, args.publishServedNumbers)) {
33559
+ if (!saveLkgSlotToDb(db, plan.sessionId, slot, args.publishServedNumbers, {
33560
+ rebuild: args.releaseRecovery,
33561
+ retainDirtyRevision: !args.releaseRecovery ? state.recoveryPrefix?.fenceRevision : undefined
33562
+ })) {
33173
33563
  throw new Error("Pi LKG/served publication failed");
33174
33564
  }
33175
33565
  args.assertCurrentPass?.();
@@ -33179,7 +33569,18 @@ function createPiLkgCoordinator(db, scheduleCapture = (capture) => setImmediate(
33179
33569
  }
33180
33570
  state.acceptedInputs = plan.inputs;
33181
33571
  state.acceptedSlot = slot;
33182
- const persisted = args.publishServedNumbers ? true : saveLkgSlotToDb(db, plan.sessionId, slot);
33572
+ if (state.recoveryPrefix) {
33573
+ state.recoveryPrefix = args.releaseRecovery ? undefined : {
33574
+ ...state.recoveryPrefix,
33575
+ inputs: plan.inputs,
33576
+ json: plan.jsonPrefix,
33577
+ outputEntryIds: ownership ?? state.recoveryPrefix.outputEntryIds
33578
+ };
33579
+ }
33580
+ const persisted = args.publishServedNumbers ? true : saveLkgSlotToDb(db, plan.sessionId, slot, undefined, {
33581
+ rebuild: args.releaseRecovery,
33582
+ retainDirtyRevision: state.recoveryPrefix?.fenceRevision
33583
+ });
33183
33584
  state.syncCaptureRequired = !persisted;
33184
33585
  if (args.publishServedNumbers)
33185
33586
  noteCapturedRequest();
@@ -33226,6 +33627,8 @@ function createPiLkgCoordinator(db, scheduleCapture = (capture) => setImmediate(
33226
33627
  return state.outputSnapshot ?? undefined;
33227
33628
  };
33228
33629
  return {
33630
+ noteRecovery,
33631
+ recoveryFor,
33229
33632
  beginPass(args) {
33230
33633
  return {
33231
33634
  ...beginPass(args),
@@ -33290,7 +33693,7 @@ function resolvePiLkgOutputEntryIds(messages, syntheticLeadingCount, entryId) {
33290
33693
  }
33291
33694
 
33292
33695
  // src/pi-lkg-fit-envelope.ts
33293
- import { createHash as createHash13 } from "node:crypto";
33696
+ import { createHash as createHash12 } from "node:crypto";
33294
33697
  function readPiLkgFitEnvelope(ctx, pi, modelKey, frozen, wireSchema) {
33295
33698
  try {
33296
33699
  if (!modelKey || typeof pi.getAllTools !== "function")
@@ -33352,7 +33755,7 @@ function readPiLkgFitEnvelope(ctx, pi, modelKey, frozen, wireSchema) {
33352
33755
  refusalToolDefinitionTokens,
33353
33756
  toolDefinitionsMeasured: refusalToolDefinitionTokens !== undefined,
33354
33757
  envelopeBytes: Buffer.byteLength(envelopeJson),
33355
- envelopeSignature: activeNames ? createHash13("sha256").update(envelopeJson).update(JSON.stringify(activeNames)).digest("hex") : undefined,
33758
+ envelopeSignature: activeNames ? createHash12("sha256").update(envelopeJson).update(JSON.stringify(activeNames)).digest("hex") : undefined,
33356
33759
  calibration
33357
33760
  };
33358
33761
  } catch {
@@ -33361,13 +33764,13 @@ function readPiLkgFitEnvelope(ctx, pi, modelKey, frozen, wireSchema) {
33361
33764
  }
33362
33765
 
33363
33766
  // src/pi-message-identity.ts
33364
- import { createHash as createHash16 } from "node:crypto";
33767
+ import { createHash as createHash15 } from "node:crypto";
33365
33768
 
33366
33769
  // src/pi-tool-identity.ts
33367
- import { createHash as createHash15 } from "node:crypto";
33770
+ import { createHash as createHash14 } from "node:crypto";
33368
33771
 
33369
33772
  // src/served-array-ledger.ts
33370
- import { createHash as createHash14 } from "node:crypto";
33773
+ import { createHash as createHash13 } from "node:crypto";
33371
33774
  import { readFileSync as readFileSync11, statSync as statSync6 } from "node:fs";
33372
33775
  import * as path12 from "node:path";
33373
33776
 
@@ -33527,7 +33930,7 @@ function getPiLastServedArray(sessionId) {
33527
33930
  return previous ? `[${previous.serializedMessages.join(",")}]` : undefined;
33528
33931
  }
33529
33932
  function sha256(value) {
33530
- return createHash14("sha256").update(value).digest("hex");
33933
+ return createHash13("sha256").update(value).digest("hex");
33531
33934
  }
33532
33935
  function safeSessionFileStem(sessionId) {
33533
33936
  const readable = sessionId.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 96);
@@ -33644,20 +34047,21 @@ function capturePiServedArray(sessionId, messages, options = {}) {
33644
34047
  const digest = sha256(serializedArray);
33645
34048
  const storageDir = options.storageDir ?? getMagicContextStorageDir();
33646
34049
  identityPersistenceFailed = true;
33647
- const previousNumbers = getPiServedTagNumbers(sessionId, storageDir);
34050
+ const previousNumbers = options.recoveryWithoutTagState ? new Set : getPiServedTagNumbers(sessionId, storageDir);
34051
+ const managedNumbers = options.recoveryWithoutTagState ? [] : options.servedTagNumbers ?? [];
33648
34052
  identityPersistenceFailed = false;
33649
34053
  const served = new Set(previousNumbers);
33650
- if (options.db) {
34054
+ if (options.db && !options.recoveryWithoutTagState) {
33651
34055
  identityPersistenceFailed = true;
33652
34056
  for (const number of readPiCommittedServedNumbers(options.db, sessionId))
33653
34057
  served.add(number);
33654
- for (const number of options.servedTagNumbers ?? []) {
34058
+ for (const number of managedNumbers) {
33655
34059
  if (!served.has(number))
33656
34060
  throw new PiServedIdentityError(new Error("Pi identities have no committed LKG"));
33657
34061
  }
33658
34062
  identityPersistenceFailed = false;
33659
34063
  }
33660
- for (const number of options.servedTagNumbers ?? []) {
34064
+ for (const number of managedNumbers) {
33661
34065
  if (Number.isSafeInteger(number) && number > 0)
33662
34066
  served.add(number);
33663
34067
  }
@@ -33797,7 +34201,7 @@ function readPiServedCachedArray(sessionId) {
33797
34201
  const memory = getPiLastServedArray(sessionId);
33798
34202
  const slot = memory === undefined ? getSlot(sessionId) : undefined;
33799
34203
  const jsonPrefix = memory ?? slot?.jsonPrefix;
33800
- if (jsonPrefix === undefined || createHash15("sha256").update(jsonPrefix).digest("hex") !== getPiLastServedDigest(sessionId))
34204
+ if (jsonPrefix === undefined || createHash14("sha256").update(jsonPrefix).digest("hex") !== getPiLastServedDigest(sessionId))
33801
34205
  return;
33802
34206
  let parsed;
33803
34207
  try {
@@ -33821,7 +34225,7 @@ function piMessageEntryFingerprint(message) {
33821
34225
  const m = message;
33822
34226
  if (typeof m.role !== "string")
33823
34227
  return null;
33824
- const contentHash = createHash16("sha256").update(stableStringify(m.content)).digest("hex");
34228
+ const contentHash = createHash15("sha256").update(stableStringify(m.content)).digest("hex");
33825
34229
  return JSON.stringify([
33826
34230
  typeof m.responseId === "string" ? m.responseId : null,
33827
34231
  typeof m.timestamp === "number" || typeof m.timestamp === "string" ? m.timestamp : null,
@@ -34226,6 +34630,7 @@ function tokenizePiMessages(messages, options) {
34226
34630
  }
34227
34631
  if (!Array.isArray(content))
34228
34632
  continue;
34633
+ let opaqueCounted = false;
34229
34634
  for (const part of content) {
34230
34635
  if (!part || typeof part !== "object")
34231
34636
  continue;
@@ -34234,14 +34639,15 @@ function tokenizePiMessages(messages, options) {
34234
34639
  case "text":
34235
34640
  if (typeof p.text === "string")
34236
34641
  conversation += estimateTokens(p.text);
34237
- if (typeof p.textSignature === "string")
34238
- conversation += estimateTokens(p.textSignature);
34239
34642
  break;
34240
34643
  case "thinking":
34241
- if (typeof p.thinking === "string")
34644
+ case "redacted_thinking":
34645
+ if (!p.redacted && typeof p.thinking === "string")
34242
34646
  conversation += estimateTokens(p.thinking);
34243
- if (typeof p.thinkingSignature === "string")
34244
- conversation += estimateTokens(p.thinkingSignature);
34647
+ if (!opaqueCounted && (p.redacted || p.type === "redacted_thinking" || !p.thinking && p.thinkingSignature)) {
34648
+ opaqueCounted = true;
34649
+ conversation += opaqueThinkingCost(msg.usage?.reasoning, msg.usage?.output).tokens;
34650
+ }
34245
34651
  break;
34246
34652
  case "image":
34247
34653
  conversation += 1200;
@@ -34305,7 +34711,11 @@ function tokenizePiMessages(messages, options) {
34305
34711
  function buildTokenCacheFingerprint(value) {
34306
34712
  const message = value;
34307
34713
  const role = typeof message.role === "string" ? message.role : null;
34308
- const fingerprint = [role];
34714
+ const fingerprint = [
34715
+ role,
34716
+ String(message.usage?.reasoning ?? ""),
34717
+ String(message.usage?.output ?? "")
34718
+ ];
34309
34719
  if (role !== "user" && role !== "assistant" && role !== "toolResult") {
34310
34720
  return fingerprint;
34311
34721
  }
@@ -34335,7 +34745,8 @@ function buildTokenCacheFingerprint(value) {
34335
34745
  fingerprint.push("text", typeof part.text === "string" ? part.text : null, typeof part.textSignature === "string" ? part.textSignature : null);
34336
34746
  break;
34337
34747
  case "thinking":
34338
- fingerprint.push("thinking", typeof part.thinking === "string" ? part.thinking : null, typeof part.thinkingSignature === "string" ? part.thinkingSignature : null);
34748
+ case "redacted_thinking":
34749
+ fingerprint.push(part.type, String(part.redacted ?? false), typeof part.thinking === "string" ? part.thinking : null, typeof part.thinkingSignature === "string" ? part.thinkingSignature : null);
34339
34750
  break;
34340
34751
  case "image":
34341
34752
  fingerprint.push("image");
@@ -34349,6 +34760,39 @@ function buildTokenCacheFingerprint(value) {
34349
34760
  }
34350
34761
  return fingerprint;
34351
34762
  }
34763
+ function piOpaqueThinkingFallbackSteps(messages) {
34764
+ return messages.filter((raw) => {
34765
+ if (!raw || typeof raw !== "object")
34766
+ return false;
34767
+ const message = raw;
34768
+ return opaqueThinkingCost(message.usage?.reasoning, message.usage?.output).fallback && Array.isArray(message.content) && message.content.some((p) => p && (p.type === "redacted_thinking" || p.type === "thinking" && (p.redacted || !p.thinking && p.thinkingSignature)));
34769
+ }).length;
34770
+ }
34771
+ function piFitMessageBytes(raw) {
34772
+ const message = raw;
34773
+ const opaque = Array.isArray(message.content) && message.content.some((p) => p && (p.type === "redacted_thinking" || p.type === "thinking" && (p.redacted || !p.thinking && p.thinkingSignature)));
34774
+ if (!opaque && (!Array.isArray(message.content) || !message.content.some((part) => part && (part.type === "thinking" && part.thinkingSignature !== undefined || part.type === "text" && part.textSignature !== undefined))))
34775
+ return Buffer.byteLength(JSON.stringify(raw));
34776
+ const content = Array.isArray(message.content) ? message.content.map((part) => {
34777
+ if (!part || typeof part !== "object")
34778
+ return part;
34779
+ if (part.type === "redacted_thinking" || part.type === "thinking" && part.redacted)
34780
+ return { type: part.type, redacted: true };
34781
+ if (part.type === "thinking") {
34782
+ const plain = { ...part };
34783
+ delete plain.thinkingSignature;
34784
+ return plain;
34785
+ }
34786
+ if (part.type === "text") {
34787
+ const plain = { ...part };
34788
+ delete plain.textSignature;
34789
+ return plain;
34790
+ }
34791
+ return part;
34792
+ }) : undefined;
34793
+ const bytes = Buffer.byteLength(JSON.stringify(content ? { ...message, content } : raw));
34794
+ return bytes + (opaque ? 4 * opaqueThinkingCost(message.usage?.reasoning, message.usage?.output).tokens : 0);
34795
+ }
34352
34796
  function tokenCacheFingerprintsEqual(left, right) {
34353
34797
  if (left.length !== right.length)
34354
34798
  return false;
@@ -34441,7 +34885,7 @@ function estimatePiOutgoingInputTokens(messages, observed, measuredPrefix, conte
34441
34885
  if (!message || typeof message !== "object")
34442
34886
  return false;
34443
34887
  const m = message;
34444
- return ["user", "assistant", "toolResult"].includes(m.role ?? "") && (typeof m.content === "string" || Array.isArray(m.content) && m.content.every((p) => p && typeof p === "object" && ["text", "thinking", "toolCall"].includes(String(p.type))));
34888
+ return ["user", "assistant", "toolResult"].includes(m.role ?? "") && (typeof m.content === "string" || Array.isArray(m.content) && m.content.every((p) => p && typeof p === "object" && ["text", "thinking", "redacted_thinking", "toolCall"].includes(String(p.type))));
34445
34889
  });
34446
34890
  if (!complete)
34447
34891
  return { tokens: 0, trusted: false };
@@ -34458,9 +34902,7 @@ function estimatePiOutgoingInputTokens(messages, observed, measuredPrefix, conte
34458
34902
  for (const part of message.content) {
34459
34903
  for (const value of [
34460
34904
  part.text,
34461
- part.thinking,
34462
- part.thinkingSignature,
34463
- part.textSignature,
34905
+ part.redacted ? undefined : part.thinking,
34464
34906
  part.name
34465
34907
  ])
34466
34908
  if (typeof value === "string")
@@ -34485,7 +34927,7 @@ function estimatePiOutgoingInputTokens(messages, observed, measuredPrefix, conte
34485
34927
  tools: observed.toolDefinitionTokens
34486
34928
  }, observed.calibration ?? calibrationForModelKey(observed.modelKey), true);
34487
34929
  const fit = observed.calibration ?? calibrationForModelKey(observed.modelKey);
34488
- const upper = envelope + Math.max(UNKNOWN_FIT_RATIO, fit.toolsRatio, fit.proseRatio) * Buffer.byteLength(JSON.stringify(priced));
34930
+ const upper = envelope + Math.max(UNKNOWN_FIT_RATIO, fit.toolsRatio, fit.proseRatio) * priced.reduce((sum, message) => sum + piFitMessageBytes(message), 0);
34489
34931
  if (upper <= contextLimit)
34490
34932
  return {
34491
34933
  tokens: upper,
@@ -34500,9 +34942,7 @@ function estimatePiOutgoingInputTokens(messages, observed, measuredPrefix, conte
34500
34942
  return tokenCountUsesByteBound(content);
34501
34943
  return content.some((part) => [
34502
34944
  part.text,
34503
- part.thinking,
34504
- part.thinkingSignature,
34505
- part.textSignature,
34945
+ part.redacted ? undefined : part.thinking,
34506
34946
  part.name,
34507
34947
  part.arguments === undefined ? undefined : JSON.stringify(part.arguments)
34508
34948
  ].some((value) => typeof value === "string" && tokenCountUsesByteBound(value)));
@@ -34511,7 +34951,7 @@ function estimatePiOutgoingInputTokens(messages, observed, measuredPrefix, conte
34511
34951
  return {
34512
34952
  tokens: providerMass({
34513
34953
  system: observed.systemTokens,
34514
- tools: observed.toolDefinitionTokens + Buffer.byteLength(JSON.stringify(messages))
34954
+ tools: observed.toolDefinitionTokens + messages.reduce((sum, message) => sum + piFitMessageBytes(message), 0)
34515
34955
  }, observed.calibration ?? calibrationForModelKey(observed.modelKey), true),
34516
34956
  trusted: true,
34517
34957
  refusalGrade: false,
@@ -34531,9 +34971,7 @@ function estimatePiOutgoingInputTokens(messages, observed, measuredPrefix, conte
34531
34971
  return !tokenCountUsesByteBound(content);
34532
34972
  return content.every((part) => [
34533
34973
  part.text,
34534
- part.thinking,
34535
- part.thinkingSignature,
34536
- part.textSignature,
34974
+ part.redacted ? undefined : part.thinking,
34537
34975
  part.name,
34538
34976
  part.arguments === undefined ? undefined : JSON.stringify(part.arguments)
34539
34977
  ].every((value) => typeof value !== "string" || !tokenCountUsesByteBound(value)));
@@ -34566,12 +35004,7 @@ function assertPiRawFallbackFits(messages, contextLimit, log, cause, observed, m
34566
35004
  let serializationFailed = false;
34567
35005
  try {
34568
35006
  for (const message of pricedMessages) {
34569
- const serialized = JSON.stringify(message);
34570
- if (typeof serialized !== "string") {
34571
- serializationFailed = true;
34572
- break;
34573
- }
34574
- bytes += Buffer.byteLength(serialized) + 1;
35007
+ bytes += piFitMessageBytes(message) + 1;
34575
35008
  if (baseInputTokens + Math.ceil(bytes / 4) > contextLimit)
34576
35009
  break;
34577
35010
  }
@@ -34587,7 +35020,7 @@ function assertPiRawFallbackFits(messages, contextLimit, log, cause, observed, m
34587
35020
  if (!message || typeof message !== "object")
34588
35021
  return false;
34589
35022
  const m = message;
34590
- return ["user", "assistant", "toolResult"].includes(m.role ?? "") && (typeof m.content === "string" || Array.isArray(m.content) && m.content.every((p) => p !== null && typeof p === "object" && ["text", "thinking", "toolCall"].includes(String(p.type))));
35023
+ return ["user", "assistant", "toolResult"].includes(m.role ?? "") && (typeof m.content === "string" || Array.isArray(m.content) && m.content.every((p) => p !== null && typeof p === "object" && ["text", "thinking", "redacted_thinking", "toolCall"].includes(String(p.type))));
34591
35024
  });
34592
35025
  const raw = tokenizePiMessages([...pricedMessages]);
34593
35026
  if (!hasTokenizerForFit()) {
@@ -35016,8 +35449,13 @@ function applyPiProactiveThinkingStrip(args) {
35016
35449
  if (protectedMessages.has(args.messages[index]))
35017
35450
  continue;
35018
35451
  const entryId = args.entryIds[index];
35019
- if (!entryId || !hasThinkingPart(args.messages[index]))
35452
+ if (!hasThinkingPart(args.messages[index]))
35453
+ continue;
35454
+ if (!entryId) {
35455
+ if (args.requirePersistence)
35456
+ throw new Error("Cannot persist thinking omission without a stable entry id");
35020
35457
  continue;
35458
+ }
35021
35459
  entryIds.push(entryId);
35022
35460
  indices.push(index);
35023
35461
  }
@@ -35033,6 +35471,8 @@ function applyPiProactiveThinkingStrip(args) {
35033
35471
  persisted = false;
35034
35472
  }
35035
35473
  if (!persisted) {
35474
+ if (args.requirePersistence)
35475
+ throw new Error("Cannot persist thinking omissions before recovery prefix rebuild");
35036
35476
  reportBindingRecovery(args.sessionId, args.report, "proactive thinking strip: persistence failed; serving the thinking unchanged");
35037
35477
  return null;
35038
35478
  }
@@ -35763,7 +36203,97 @@ function stripPiProcessedImages(args) {
35763
36203
  }
35764
36204
 
35765
36205
  // src/system-prompt.ts
35766
- import { createHash as createHash17 } from "node:crypto";
36206
+ import { createHash as createHash16 } from "node:crypto";
36207
+
36208
+ // ../plugin/src/hooks/magic-context/system-prompt-dates.ts
36209
+ function replaceHostDates(prompt, replace) {
36210
+ const fields = /<(plugin-env|environment|env)>[\s\S]*?<\/\1>|Today's date: [^\r\n<]+/g;
36211
+ return prompt.replace(fields, (block) => block.replace(/(^[\t ]*(?:Date|Today's date):[\t ]*)([^\r\n<]+)/gm, (_line, label, date) => `${label}${replace(date)}`));
36212
+ }
36213
+ function systemPromptDates(prompt, sticky) {
36214
+ const values = [];
36215
+ replaceHostDates(prompt, (date) => {
36216
+ values.push(date);
36217
+ return date;
36218
+ });
36219
+ const prior = sticky ? JSON.parse(sticky) : [];
36220
+ let index = 0;
36221
+ const stable = replaceHostDates(prompt, (date) => prior[index++] ?? date);
36222
+ return { live: values.length ? JSON.stringify(values) : undefined, stable };
36223
+ }
36224
+
36225
+ // src/system-prompt-delivery-pi.ts
36226
+ var requests = new BoundedSessionMap(1000);
36227
+ function beginPiSystemPromptRequest(db, sessionId, modelKey, branch) {
36228
+ acknowledgePiPendingSystemPromptResponses(sessionId);
36229
+ const request = {
36230
+ kind: "v2",
36231
+ startedAt: Date.now(),
36232
+ previousResponseId: undefined,
36233
+ modelKey: piModelRefToCanonical(modelKey)
36234
+ };
36235
+ requests.set(sessionId, { request, branch, replies: [] });
36236
+ recordSystemPromptForRequest(sessionId, request, getOrCreateSessionMeta(db, sessionId).systemPromptHash, db);
36237
+ }
36238
+ function recordPiHeldSystemHead(sessionId, deferRefresh) {
36239
+ recordHeldHeadForRequest(sessionId, requests.get(sessionId)?.request, deferRefresh);
36240
+ }
36241
+ function acknowledgePiSystemPromptResponse(sessionId, message) {
36242
+ const saved = requests.get(sessionId);
36243
+ if (!saved?.branch || !message || typeof message !== "object" || message.role !== "assistant")
36244
+ return;
36245
+ if (!saved.replies.includes(message)) {
36246
+ if (saved.replies.length === 32)
36247
+ saved.replies.shift();
36248
+ saved.replies.push(message);
36249
+ }
36250
+ acknowledgePiPendingSystemPromptResponses(sessionId);
36251
+ }
36252
+ function acknowledgePiPendingSystemPromptResponses(sessionId) {
36253
+ const saved = requests.get(sessionId);
36254
+ if (!saved?.branch)
36255
+ return;
36256
+ let entries;
36257
+ try {
36258
+ entries = saved.branch.readBranch();
36259
+ } catch {
36260
+ return;
36261
+ }
36262
+ if (!entries)
36263
+ return;
36264
+ for (const value of entries) {
36265
+ if (!value || typeof value !== "object")
36266
+ continue;
36267
+ const entry = value;
36268
+ if (entry.type !== "message" || !entry.id || entry.parentId !== saved.branch.parentId || !entry.message || !saved.replies.includes(entry.message))
36269
+ continue;
36270
+ const reply = entry.message;
36271
+ if (!reply.provider || !reply.model || typeof reply.timestamp !== "number")
36272
+ continue;
36273
+ const completion = { finish: reply.stopReason, error: reply.errorMessage };
36274
+ if (!isSuccessfulProviderCompletion(completion) && !providerResponseFailed(completion))
36275
+ continue;
36276
+ const response = {
36277
+ sessionId,
36278
+ request: saved.request,
36279
+ responseId: entry.id,
36280
+ createdAt: reply.timestamp,
36281
+ modelKey: piModelRefToCanonical(`${reply.provider}/${reply.model}`),
36282
+ ...completion,
36283
+ v2: true
36284
+ };
36285
+ bindSystemPromptResponse(sessionId, saved.request, response);
36286
+ acknowledgeSystemPromptDelivery(response);
36287
+ requests.delete(sessionId);
36288
+ return;
36289
+ }
36290
+ }
36291
+ function clearPiSystemPromptDelivery(sessionId) {
36292
+ requests.delete(sessionId);
36293
+ clearSystemPromptDelivery(sessionId);
36294
+ }
36295
+
36296
+ // src/system-prompt.ts
35767
36297
  var MAGIC_CONTEXT_MARKER = "## Magic Context";
35768
36298
  var stickyDateBySession = new Map;
35769
36299
  function buildMagicContextBlock(opts) {
@@ -35778,7 +36308,6 @@ function composeMagicContextSystemPrompt(basePrompt, block) {
35778
36308
 
35779
36309
  ${block}` : basePrompt;
35780
36310
  }
35781
- var DATE_PATTERN = /Today's date: .+/;
35782
36311
  function processSystemPromptForCache(args) {
35783
36312
  const { db, sessionId, systemPrompt, isCacheBusting } = args;
35784
36313
  let sessionMeta;
@@ -35790,11 +36319,13 @@ function processSystemPromptForCache(args) {
35790
36319
  const previousHash = sessionMeta?.systemPromptHash ?? "";
35791
36320
  const isFirstHash = previousHash === "" || previousHash === "0";
35792
36321
  let frozenPrompt = systemPrompt;
35793
- const dateMatch = systemPrompt.match(DATE_PATTERN);
35794
- const liveDate = dateMatch ? dateMatch[0] : null;
36322
+ if (isFirstHash)
36323
+ stickyDateBySession.delete(sessionId);
35795
36324
  const stickyDate = stickyDateBySession.get(sessionId);
35796
- const stableCandidate = liveDate && stickyDate && liveDate !== stickyDate ? systemPrompt.replace(DATE_PATTERN, stickyDate) : systemPrompt;
35797
- const stableCandidateHash = createHash17("md5").update(promptSurfaceHashMaterial(stableCandidate, args.promptSurfacePreset)).digest("hex");
36325
+ const dates = systemPromptDates(systemPrompt, stickyDate);
36326
+ const liveDate = dates.live;
36327
+ const stableCandidate = dates.stable;
36328
+ const stableCandidateHash = createHash16("md5").update(promptSurfaceHashMaterial(stableCandidate, args.promptSurfacePreset)).digest("hex");
35798
36329
  const contentOrPresetChanged = !isFirstHash && stableCandidateHash !== previousHash;
35799
36330
  const idleCacheExpired = sessionMeta !== undefined && computeHardCacheExpired(sessionMeta.cacheTtl, sessionMeta.lastResponseTime, Date.now());
35800
36331
  const dateMayAdvance = isCacheBusting || idleCacheExpired || contentOrPresetChanged;
@@ -35805,11 +36336,11 @@ function processSystemPromptForCache(args) {
35805
36336
  stickyDateBySession.set(sessionId, liveDate);
35806
36337
  sessionLog2(sessionId, `system prompt date updated: ${stickyDate} → ${liveDate} (cache-busting pass)`);
35807
36338
  } else {
35808
- frozenPrompt = systemPrompt.replace(DATE_PATTERN, stickyDate);
36339
+ frozenPrompt = stableCandidate;
35809
36340
  sessionLog2(sessionId, `system prompt date frozen: real=${liveDate}, using=${stickyDate} (cache-stable pass)`);
35810
36341
  }
35811
36342
  }
35812
- const currentHash = createHash17("md5").update(promptSurfaceHashMaterial(frozenPrompt, args.promptSurfacePreset)).digest("hex");
36343
+ const currentHash = createHash16("md5").update(promptSurfaceHashMaterial(frozenPrompt, args.promptSurfacePreset)).digest("hex");
35813
36344
  const hashChanged = !isFirstHash && currentHash !== previousHash;
35814
36345
  if (hashChanged) {
35815
36346
  sessionLog2(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${frozenPrompt.length})`);
@@ -35834,6 +36365,7 @@ function processSystemPromptForCache(args) {
35834
36365
  };
35835
36366
  }
35836
36367
  function clearPiSystemPromptSession(sessionId) {
36368
+ clearPiSystemPromptDelivery(sessionId);
35837
36369
  stickyDateBySession.delete(sessionId);
35838
36370
  }
35839
36371
 
@@ -36453,6 +36985,21 @@ var systemPromptRefreshSessions = new Set;
36453
36985
  var pendingMaterializationSessions = new Set;
36454
36986
  var deferredHistoryRefreshSessions = new Set;
36455
36987
  var deferredMaterializationSessions = new Set;
36988
+ function signalPiSystemHashChange(sessionId, hash) {
36989
+ recordSystemRefreshOwnership(sessionId, hash, !historyRefreshSessions.has(sessionId), historyRefreshSessions, pendingMaterializationSessions);
36990
+ signalPiHistoryRefresh(sessionId);
36991
+ signalPiSystemPromptRefresh(sessionId);
36992
+ if (!pendingMaterializationSessions.has(sessionId))
36993
+ signalPiPendingMaterialization(sessionId, "system_hash");
36994
+ }
36995
+ function deferPiDeliveredSystemRefresh(sessionId, ownsHistory) {
36996
+ deferDeliveredSystemRefresh({
36997
+ historyRefreshSessions,
36998
+ pendingMaterializationSessions,
36999
+ deferredHistoryRefreshSessions,
37000
+ deferredMaterializationSessions
37001
+ }, sessionId, ownsHistory);
37002
+ }
36456
37003
  var sessionsByProject = new Map;
36457
37004
  var lastSeenProjectIdentityBySession = new Map;
36458
37005
  var persistedProjectIdentityBySession = new Map;
@@ -36464,14 +37011,24 @@ var lastHeuristicsTurnIdBySession = new Map;
36464
37011
  var routinePressureAppliedBySession = new Map;
36465
37012
  var firstContextPassSeenBySession = new Set;
36466
37013
  var contextPassGeneration = new Map;
37014
+ function createPiContextGenerationGuard(assertOperation, passSessionId, generation, sideTurn, signal) {
37015
+ return () => {
37016
+ assertOperation();
37017
+ if (!sideTurn && passSessionId && contextPassGeneration.get(passSessionId) !== generation)
37018
+ throw new PiContextSupersededError("Pi context pass superseded by a newer context generation", "context generation");
37019
+ signal?.throwIfAborted();
37020
+ };
37021
+ }
36467
37022
 
36468
37023
  class PiLkgAdmissionReplay extends Error {
36469
37024
  messages;
36470
37025
  recovery;
36471
- constructor(messages, recovery = "fitting LKG before writer retries") {
37026
+ trigger;
37027
+ constructor(messages, recovery = "fitting LKG before writer retries", trigger = "writer_busy") {
36472
37028
  super("Saved request served before writer wait");
36473
37029
  this.messages = messages;
36474
37030
  this.recovery = recovery;
37031
+ this.trigger = trigger;
36475
37032
  }
36476
37033
  }
36477
37034
  var liveModelBySession = new Map;
@@ -36646,8 +37203,8 @@ function signalPiHistoryRefresh(sessionId) {
36646
37203
  function signalPiSystemPromptRefresh(sessionId) {
36647
37204
  systemPromptRefreshSessions.add(sessionId);
36648
37205
  }
36649
- function signalPiPendingMaterialization(sessionId) {
36650
- pendingMaterializationSessions.add(sessionId);
37206
+ function signalPiPendingMaterialization(sessionId, origin = "user_flush") {
37207
+ requestPendingMaterialization(pendingMaterializationSessions, sessionId, origin);
36651
37208
  }
36652
37209
  function clearPiM0Cache(db, sessionId, reason) {
36653
37210
  clearM0M1PiCache(db, sessionId, reason);
@@ -36774,7 +37331,7 @@ function hasPendingMaterialization(sessionId) {
36774
37331
  }
36775
37332
  function consumePendingMaterialization(sessionId) {
36776
37333
  const wasSet = pendingMaterializationSessions.has(sessionId);
36777
- pendingMaterializationSessions.delete(sessionId);
37334
+ clearPendingMaterialization(pendingMaterializationSessions, sessionId);
36778
37335
  return wasSet;
36779
37336
  }
36780
37337
  function resolveSessionId2(ctx) {
@@ -38047,7 +38604,7 @@ function registerPiContextHandler(pi, baseOptions) {
38047
38604
  sessionLog2(sessionId, `variant changed (${event.previousLevel} -> ${event.level}), triggering flush`);
38048
38605
  historyRefreshSessions.add(sessionId);
38049
38606
  systemPromptRefreshSessions.add(sessionId);
38050
- pendingMaterializationSessions.add(sessionId);
38607
+ requestPendingMaterialization(pendingMaterializationSessions, sessionId, "variant_change");
38051
38608
  lastHeuristicsTurnIdBySession.delete(sessionId);
38052
38609
  return;
38053
38610
  }
@@ -38061,14 +38618,8 @@ function registerPiContextHandler(pi, baseOptions) {
38061
38618
  const generation = Symbol();
38062
38619
  if (passSessionId && !budget.sideTurn)
38063
38620
  contextPassGeneration.set(passSessionId, generation);
38064
- const signal = event.signal ?? ctx.signal;
38065
- const assertOperation = budget.assertOwner;
38066
- budget.assertOwner = () => {
38067
- assertOperation();
38068
- if (!budget.sideTurn && passSessionId && contextPassGeneration.get(passSessionId) !== generation)
38069
- throw new PiContextSupersededError("Pi context pass superseded by a newer context generation", "context generation");
38070
- signal?.throwIfAborted();
38071
- };
38621
+ const signal = budget.signal;
38622
+ budget.assertOwner = createPiContextGenerationGuard(budget.assertOwner, passSessionId, generation, budget.sideTurn, signal);
38072
38623
  let assertCurrentPass = budget.assert;
38073
38624
  const guardAwait = budget.wait;
38074
38625
  const passGuard = { assert: assertCurrentPass, wait: guardAwait };
@@ -38114,6 +38665,11 @@ function registerPiContextHandler(pi, baseOptions) {
38114
38665
  rawMessageCount = event.messages.length;
38115
38666
  const fullWireMessageCount = rawMessageCount;
38116
38667
  const options = baseOptions.resolveForProject?.(projectDirectory) ?? baseOptions;
38668
+ const deliveryModelKey = resolvePiContextModelKey(ctx);
38669
+ if (!budget.sideTurn && deliveryModelKey) {
38670
+ const parentId = ctx.sessionManager.getLeafId?.();
38671
+ beginPiSystemPromptRequest(options.db, sessionId, deliveryModelKey, parentId === null || typeof parentId === "string" ? { parentId, readBranch: () => ctx.sessionManager.getBranch() } : undefined);
38672
+ }
38117
38673
  const schedulerConfig = options.scheduler ?? DEFAULT_SCHEDULER_CONFIG;
38118
38674
  const scheduler = schedulerFor(options);
38119
38675
  lkgCompactionOff = options.compactionOff === true;
@@ -38167,6 +38723,7 @@ function registerPiContextHandler(pi, baseOptions) {
38167
38723
  transport: ctx.model?.transport
38168
38724
  });
38169
38725
  lkgPassSnapshot = snapshot;
38726
+ const recovery = budget.sideTurn || lkgCompactionOff ? {} : lkgCoordinator.recoveryFor(snapshot);
38170
38727
  const lkgInputFields = new WeakMap(snapshot.inputs.flatMap((input) => {
38171
38728
  const message = event.messages[input.messageIndex];
38172
38729
  return message && typeof message === "object" ? [[message, input.fields]] : [];
@@ -38195,7 +38752,7 @@ function registerPiContextHandler(pi, baseOptions) {
38195
38752
  rawContextWindow: piUsage?.contextWindow,
38196
38753
  detectedContextLimit: state.detectedContextLimit
38197
38754
  })?.usableHard;
38198
- if (lkgCompactionOff || lkgEmergencyRecoveryArmed || isProviderOverflowFailClosedProven(sessionId))
38755
+ if (lkgCompactionOff || recovery.rebuildReason || lkgEmergencyRecoveryArmed || isProviderOverflowFailClosedProven(sessionId))
38199
38756
  return;
38200
38757
  const replay = lkgCoordinator.replay(snapshot, (id) => ctx.sessionManager.getEntry?.(id)?.parentId);
38201
38758
  if (!replay.ok)
@@ -38490,7 +39047,7 @@ function registerPiContextHandler(pi, baseOptions) {
38490
39047
  }
38491
39048
  if (stableIdSchemeCutover && !options.compactionOff) {
38492
39049
  schedulerDecision = "execute";
38493
- signalPiPendingMaterialization(sessionId);
39050
+ signalPiPendingMaterialization(sessionId, "tag_identity_repair");
38494
39051
  sessionLog2(sessionId, `stable-id scheme cutover: stored=${storedStableIdScheme} < current=${PI_STABLE_ID_SCHEME} — forcing execute+materialize this pass`);
38495
39052
  }
38496
39053
  const tBoundaryChecks = performance.now();
@@ -38560,6 +39117,8 @@ function registerPiContextHandler(pi, baseOptions) {
38560
39117
  assertCurrentPass();
38561
39118
  const inputForThinkingFit = isPrefixBoundThinkingModel(ctx.model?.provider, ctx.model?.id) ? structuredClone(event.messages) : null;
38562
39119
  const pipelineArgs = {
39120
+ recoveryPrefix: recovery.prefix,
39121
+ recoveryRebuildReason: recovery.rebuildReason,
38563
39122
  assertCurrentPass,
38564
39123
  db: options.db,
38565
39124
  tagger,
@@ -38641,12 +39200,12 @@ function registerPiContextHandler(pi, baseOptions) {
38641
39200
  return;
38642
39201
  }
38643
39202
  logPiLkgRecovery(sessionId, "Pi held identity rebuild: replaying the served prefix and retaining the pending repair");
38644
- throw new PiLkgAdmissionReplay(replay.messages, "held tag-identity rebuild: replaying the served prefix");
39203
+ throw new PiLkgAdmissionReplay(replay.messages, "held tag-identity rebuild: replaying the served prefix", "held_identity_repair");
38645
39204
  }
38646
39205
  };
38647
39206
  let result = await budget.waitMandatory(runPipeline(pipelineArgs));
38648
39207
  logTransformTiming(sessionId, "runPipeline", tRunPipeline);
38649
- if (result.identityRebuilt)
39208
+ if (result.identityRebuilt || result.lkgFrozenReleaseReason)
38650
39209
  schedulerDecision = "execute";
38651
39210
  const postPipelineStart = performance.now();
38652
39211
  const tTransformDecision = performance.now();
@@ -38669,7 +39228,8 @@ function registerPiContextHandler(pi, baseOptions) {
38669
39228
  droppedTokens: result.droppedTokens,
38670
39229
  droppedCount: result.droppedCount,
38671
39230
  inputTokens: usageInputTokens,
38672
- bustedThisPass: true
39231
+ bustedThisPass: true,
39232
+ lkgFrozenReleaseReason: result.lkgFrozenReleaseReason
38673
39233
  }, piDecisionSnapshotNewestAssistant, budget.assertDecisionPublication);
38674
39234
  } : undefined;
38675
39235
  logTransformTiming(sessionId, "transformDecisionAndReuseState", tTransformDecision);
@@ -38838,15 +39398,38 @@ function registerPiContextHandler(pi, baseOptions) {
38838
39398
  entryIds: outputEntryIds,
38839
39399
  provider: lkgProviderKey ?? undefined,
38840
39400
  model: ctx.model?.id,
38841
- cacheBustingPass: result.signedPrefixRewritten || result.prefixBustPermitted && !result.strictThinkingKept && (isCacheBusting || result.prefixRebuildAlreadyPriced || result.executedWorkThisPass && (result.prefixEditBesidesReasoningTrim || hostEditBeforeNewestThinking)),
39401
+ cacheBustingPass: !!recovery.rebuildReason || result.signedPrefixRewritten || result.prefixBustPermitted && !result.strictThinkingKept && (isCacheBusting || result.prefixRebuildAlreadyPriced || result.executedWorkThisPass && (result.prefixEditBesidesReasoningTrim || hostEditBeforeNewestThinking)),
38842
39402
  stripActiveTurn: result.signedPrefixRewritten,
39403
+ requirePersistence: !!recovery.rebuildReason,
38843
39404
  report: (line) => sessionLog2(sessionId, line)
38844
39405
  });
38845
39406
  } catch (err) {
39407
+ if (recovery.rebuildReason)
39408
+ throw err;
38846
39409
  sessionLog2(sessionId, `proactive thinking strip failed: ${err instanceof Error ? err.message : String(err)}`);
38847
39410
  }
38848
39411
  }
38849
39412
  logTransformTiming(sessionId, "thinkingBinding", tThinkingBinding);
39413
+ if (recovery.prefix && !result.recoveryNormalized) {
39414
+ const priorIds = new Set(recovery.prefix.inputs.map((input) => input.id));
39415
+ const newIds = new Set(snapshot.inputs.filter((input) => !priorIds.has(input.id)).map((input) => input.id));
39416
+ const suffix = outputMessages.filter((message) => {
39417
+ const id = result.postCommitEntryIdByRef.get(message) ?? result.lkgEntryIdByRef.get(message);
39418
+ return id !== undefined && newIds.has(id);
39419
+ });
39420
+ const prefix = JSON.parse(recovery.prefix.json);
39421
+ const recoveredEntryIds = new Map(result.postCommitEntryIdByRef);
39422
+ prefix.forEach((message, index) => {
39423
+ const id = recovery.prefix?.outputEntryIds[index];
39424
+ if (id)
39425
+ recoveredEntryIds.set(message, id);
39426
+ });
39427
+ result.postCommitEntryIdByRef = recoveredEntryIds;
39428
+ outputMessages = [...prefix, ...suffix];
39429
+ result.syntheticLeadingCount = recovery.prefix.outputEntryIds.findIndex((id) => id !== null);
39430
+ if (result.syntheticLeadingCount < 0)
39431
+ result.syntheticLeadingCount = prefix.length;
39432
+ }
38850
39433
  const tChannelAccounting = performance.now();
38851
39434
  try {
38852
39435
  const sessionMetaForCh1 = sessionMeta;
@@ -38968,7 +39551,8 @@ function registerPiContextHandler(pi, baseOptions) {
38968
39551
  runPiDebugAssertion(assertTailHygieneLastWriter);
38969
39552
  if (!options.compactionOff && (result.executedWorkThisPass || isCacheBusting || schedulerDecision === "execute")) {
38970
39553
  const envelope = readPiLkgFitEnvelope(ctx, pi, resolvePiContextModelKey(ctx), sessionDecisionCalibration(options.db, sessionId), toolWireSchema);
38971
- let estimate = estimatePiOutgoingInputTokens(outputMessages, envelope, lkgPassSnapshot ? lkgCoordinator.measureOutgoingPrefix(lkgPassSnapshot, outputMessages, (id) => ctx.sessionManager.getEntry?.(id)?.parentId) : undefined, rawFallbackLimit);
39554
+ const measuredPrefix = lkgPassSnapshot ? lkgCoordinator.measureOutgoingPrefix(lkgPassSnapshot, outputMessages, (id) => ctx.sessionManager.getEntry?.(id)?.parentId) : undefined;
39555
+ let estimate = estimatePiOutgoingInputTokens(outputMessages, envelope, measuredPrefix, rawFallbackLimit);
38972
39556
  if (inputForThinkingFit && result.strictThinkingKept && rawFallbackLimit && estimate.refusalGrade && (estimate.refusalTokens ?? estimate.tokens) > rawFallbackLimit) {
38973
39557
  result = await budget.waitMandatory(runPipeline({
38974
39558
  ...pipelineArgs,
@@ -38994,6 +39578,16 @@ function registerPiContextHandler(pi, baseOptions) {
38994
39578
  });
38995
39579
  estimate = estimatePiOutgoingInputTokens(outputMessages, envelope, undefined, rawFallbackLimit);
38996
39580
  }
39581
+ const opaqueFallbackSteps = piOpaqueThinkingFallbackSteps(outputMessages);
39582
+ if (opaqueFallbackSteps > 0)
39583
+ sessionLog2(sessionId, `opaque thinking fallback: steps=${opaqueFallbackSteps} tokensPerStep=1000 (native usage unavailable; telemetry only)`);
39584
+ if (measuredPrefix?.previousMessages?.some((raw) => {
39585
+ const message = raw;
39586
+ return Array.isArray(message.content) && message.content.some((part) => part.thinkingSignature);
39587
+ })) {
39588
+ const previous = estimatePiOutgoingInputTokens(measuredPrefix.previousMessages, envelope);
39589
+ sessionLog2(sessionId, `thinking estimate drift: estimate=${previous.tokens} provider=${measuredPrefix.inputTokens} ratio=${(previous.tokens / measuredPrefix.inputTokens).toFixed(4)} (previous served request; telemetry only)`);
39590
+ }
38997
39591
  if (result.signedPrefixRewritten && rawFallbackLimit && estimate.refusalGrade && (estimate.refusalTokens ?? estimate.tokens) > rawFallbackLimit)
38998
39592
  throw contextRefusalError("The request remains over the model window after stripping signed thinking and reclaiming context");
38999
39593
  const refusal = outgoingContextRefusal(estimate, rawFallbackLimit, protectedToolTokenCount(getActiveTagsBySession2(options.db, sessionId), options.protectedTools, envelope ? calibrationForModelKey(envelope.modelKey) : undefined));
@@ -39026,10 +39620,18 @@ function registerPiContextHandler(pi, baseOptions) {
39026
39620
  snapshot: lkgPassSnapshot,
39027
39621
  outputMessages,
39028
39622
  outputEntryIds: resolvePiLkgOutputEntryIds(outputMessages, result.syntheticLeadingCount, (message) => result.postCommitEntryIdByRef.get(message) ?? result.lkgEntryIdByRef.get(message)),
39029
- cacheBusting: result.bustedThisPass
39623
+ cacheBusting: result.bustedThisPass,
39624
+ releaseRecovery: result.recoveryNormalized || !!recovery.rebuildReason
39030
39625
  });
39031
39626
  numbersCommitted = true;
39032
39627
  } catch (error) {
39628
+ if (error instanceof LkgRecoveryFenceError)
39629
+ throw new PiServedIdentityError(error);
39630
+ try {
39631
+ invalidateCleanLkgRecoveryFence(sessionId, () => loadPersistedLkgSlot(options.db, sessionId));
39632
+ } catch (fenceError) {
39633
+ throw new PiServedIdentityError(fenceError);
39634
+ }
39033
39635
  budget.assertOutcome();
39034
39636
  clearPiLkgSessionState(sessionId);
39035
39637
  if (error instanceof PiLkgUncapturable) {
@@ -39076,8 +39678,12 @@ function registerPiContextHandler(pi, baseOptions) {
39076
39678
  }
39077
39679
  budget.assertOutcome();
39078
39680
  publishTransformDecision?.();
39681
+ if (!budget.sideTurn && result.strictThinkingKept && !result.signedPrefixRewritten && !result.materialized)
39682
+ recordPiHeldSystemHead(sessionId, (ownsHistory) => deferPiDeliveredSystemRefresh(sessionId, ownsHistory));
39079
39683
  return { messages: outputMessages };
39080
39684
  } catch (err) {
39685
+ if (budget.isCancelled(err))
39686
+ throw err;
39081
39687
  budget.assertOutcome();
39082
39688
  budget.stage = "recovery";
39083
39689
  if (err instanceof PiServedIdentityError) {
@@ -39087,9 +39693,11 @@ function registerPiContextHandler(pi, baseOptions) {
39087
39693
  }
39088
39694
  if (err instanceof PiLkgAdmissionReplay && sessionIdForError) {
39089
39695
  budget.assertOutcome();
39696
+ if (lkgPassSnapshot && err.trigger === "writer_busy")
39697
+ lkgCoordinator.noteRecovery(lkgPassSnapshot, err.messages);
39090
39698
  if (!budget.sideTurn)
39091
39699
  captureServedEvidence(sessionIdForError, err.messages, {
39092
- db: baseOptions.db,
39700
+ recoveryWithoutTagState: true,
39093
39701
  assertCurrentPass: budget.assertOutcome
39094
39702
  });
39095
39703
  budget.assertOutcome();
@@ -39116,7 +39724,10 @@ function registerPiContextHandler(pi, baseOptions) {
39116
39724
  const failureLabel = transientStorageFailure ? "TRANSIENT STORAGE FAILURE" : "DEGRADED PASS";
39117
39725
  if (replayOrRefuse && sessionIdForError && lkgPassSnapshot && !lkgCompactionOff && !lkgEmergencyRecoveryArmed) {
39118
39726
  try {
39119
- const replay = lkgCoordinator.replay(lkgPassSnapshot, (id) => ctx.sessionManager.getEntry?.(id)?.parentId);
39727
+ const replay = lkgCoordinator.recoveryFor(lkgPassSnapshot).rebuildReason ? {
39728
+ ok: false,
39729
+ reason: lkgPassSnapshot.replayFailure ?? "lkg_recovery_unproven"
39730
+ } : lkgCoordinator.replay(lkgPassSnapshot, (id) => ctx.sessionManager.getEntry?.(id)?.parentId);
39120
39731
  if (replay.ok) {
39121
39732
  assertPiRawFallbackFits(replay.messages, rawFallbackLimit, (line) => {
39122
39733
  if (sessionIdForError)
@@ -39125,9 +39736,10 @@ function registerPiContextHandler(pi, baseOptions) {
39125
39736
  const reason = piStorageErrorReason(err);
39126
39737
  logPiLkgRecovery(sessionIdForError, `${failureLabel} ${reason}: LKG replay served ${replay.messages.length} messages instead of raw ${rawMessageCount}`);
39127
39738
  budget.assertOutcome();
39739
+ lkgCoordinator.noteRecovery(lkgPassSnapshot, replay.messages);
39128
39740
  if (!budget.sideTurn)
39129
39741
  captureServedEvidence(sessionIdForError, replay.messages, {
39130
- db: baseOptions.db,
39742
+ recoveryWithoutTagState: true,
39131
39743
  assertCurrentPass: budget.assertOutcome
39132
39744
  });
39133
39745
  budget.assertOutcome();
@@ -39781,7 +40393,7 @@ async function runPipeline(args) {
39781
40393
  parts: (message) => Array.isArray(message?.content) ? message.content : []
39782
40394
  });
39783
40395
  if (thinkingRecovery.ended)
39784
- signalPiPendingMaterialization(args.sessionId);
40396
+ signalPiPendingMaterialization(args.sessionId, "thinking_hold");
39785
40397
  let restoreOriginals;
39786
40398
  let activeThinkingTurn = hasActiveAnthropicThinkingTurn(args.messages, args.resolvedProviderID, args.resolvedModelID);
39787
40399
  let protectedSignedPrefix = activeThinkingTurn && args.reasoningClearing?.prefixBound === true;
@@ -39798,7 +40410,8 @@ async function runPipeline(args) {
39798
40410
  model: args.resolvedModelID,
39799
40411
  cacheBustingPass: true,
39800
40412
  stripActiveTurn: true,
39801
- persistOnly: true
40413
+ persistOnly: true,
40414
+ requirePersistence: !!args.recoveryRebuildReason
39802
40415
  });
39803
40416
  if (activeThinkingTurn && !result)
39804
40417
  throw new Error("Cannot persist signed thinking omission before prefix rewrite");
@@ -39806,7 +40419,7 @@ async function runPipeline(args) {
39806
40419
  activeThinkingTurn = false;
39807
40420
  protectedSignedPrefix = false;
39808
40421
  };
39809
- if (args.forceSignedRebuildForFit && protectedSignedPrefix)
40422
+ if (args.recoveryRebuildReason || args.forceSignedRebuildForFit && protectedSignedPrefix)
39810
40423
  stripForPrefixRewrite();
39811
40424
  const realStableId = (msg, index) => resolvePiRealStableId(msg, index, args.entryIds, args.entryIdByRef ?? undefined);
39812
40425
  const passFallbackIds = settlePiFallbackOccurrences(args.db, args.sessionId, piContentFallbackIds(args.messages, realStableId));
@@ -40164,6 +40777,8 @@ async function runPipeline(args) {
40164
40777
  ...message,
40165
40778
  parts: message.parts
40166
40779
  }));
40780
+ const recoveryNormalized = !!args.recoveryPrefix && (foldBustsServedPrefixThisPass || firstRenderBust || identityRebuild);
40781
+ const taggingView = args.recoveryPrefix && !recoveryNormalized ? mutationView.filter((message) => !args.recoveryPrefix?.untaggedInputIds.has(message.info.id ?? "")) : mutationView;
40167
40782
  let tagTextTokenCache = piTagTextTokenCacheBySession.get(args.sessionId);
40168
40783
  if (!tagTextTokenCache) {
40169
40784
  tagTextTokenCache = new Map;
@@ -40176,7 +40791,7 @@ async function runPipeline(args) {
40176
40791
  }
40177
40792
  const { targets } = runPersistedReplayStage("tagging-persistence-failure", () => args.tagger.cleanup(args.sessionId), () => {
40178
40793
  args.assertCurrentPass?.();
40179
- return tagTranscript(args.sessionId, { ...transcript, messages: mutationView }, args.tagger, args.db, {
40794
+ return tagTranscript(args.sessionId, { ...transcript, messages: taggingView }, args.tagger, args.db, {
40180
40795
  skipPrefixInjection: !ctxReduceCallable,
40181
40796
  entryFingerprintByMessageId,
40182
40797
  reuseMessageIds: textIdentityPlan.reusableMessageIds,
@@ -40310,7 +40925,7 @@ async function runPipeline(args) {
40310
40925
  shouldRunReasoningCleanup: args.reasoningClearing !== undefined && shouldRunHeuristics
40311
40926
  });
40312
40927
  if (shouldApplyPendingOps) {
40313
- const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : foldBustsServedPrefixThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : `${reclaimRideLabel(rideSignals)} (scheduler=${args.schedulerDecision})`;
40928
+ const applyReason = hasPendingMaterializeSignal ? `pending_materialization origin=${pendingMaterializationOrigin(pendingMaterializationSessions, args.sessionId)}` : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : foldBustsServedPrefixThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : `${reclaimRideLabel(rideSignals)} (scheduler=${args.schedulerDecision})`;
40314
40929
  const pendingOpsDepth = getPendingOpsCount(args.db, args.sessionId);
40315
40930
  const pendingDecisionLog = `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOpsDepth === null ? "not loaded (deferred pass)" : pendingOpsDepth} context=${args.contextUsage.percentage.toFixed(1)}%`;
40316
40931
  sessionLog2(args.sessionId, pendingDecisionLog);
@@ -40655,7 +41270,7 @@ async function runPipeline(args) {
40655
41270
  db: args.db,
40656
41271
  sessionId: args.sessionId,
40657
41272
  activeTags,
40658
- targets: newTargets,
41273
+ targets,
40659
41274
  legacyReminderTagNumbers: textIdentityPlan.legacyReminderTagNumbers,
40660
41275
  cacheBusting: isCacheBustingPass
40661
41276
  });
@@ -40912,7 +41527,7 @@ async function runPipeline(args) {
40912
41527
  }
40913
41528
  }
40914
41529
  const materializeReason = identityRebuild ? PI_TAG_IDENTITY_REPAIR_REASON : injectionResult?.m0Reason ?? null;
40915
- const bustedThisPass = identityRebuild || firstRenderBust || pendingOpsDidMutate || heuristicOrReasoningDidMutate || autoReclaimDidMutateThisPass || materialized || historyWasConsumedThisPass;
41530
+ const bustedThisPass = !!args.recoveryRebuildReason || recoveryNormalized || identityRebuild || firstRenderBust || pendingOpsDidMutate || heuristicOrReasoningDidMutate || autoReclaimDidMutateThisPass || materialized || historyWasConsumedThisPass;
40916
41531
  const calibrationBustReason = identityRebuild ? PI_TAG_IDENTITY_REPAIR_REASON : materialized || firstRenderBust ? "fold" : args.forceMaterialization ? "force" : pendingOpsDidMutate ? "flush" : historyWasConsumedThisPass ? "refresh" : args.schedulerDecision === "execute" ? "execute" : "unknown";
40917
41532
  const activeCalibration = sessionDecisionCalibration(args.db, args.sessionId, {
40918
41533
  bustPermitted: bustedThisPass,
@@ -40952,6 +41567,8 @@ async function runPipeline(args) {
40952
41567
  }
40953
41568
  return {
40954
41569
  messages: outputMessages,
41570
+ recoveryNormalized,
41571
+ lkgFrozenReleaseReason: args.recoveryRebuildReason ?? (recoveryNormalized ? "recovery_tail_normalized" : undefined),
40955
41572
  prefixBustPermitted: isCacheBustingPass,
40956
41573
  prefixMutationAllowed,
40957
41574
  strictThinkingKept: protectedSignedPrefix,
@@ -40972,7 +41589,7 @@ async function runPipeline(args) {
40972
41589
  emergency,
40973
41590
  bustedThisPass,
40974
41591
  agentDropsAppliedThisPass: pendingOpsDidMutate,
40975
- prefixEditBesidesReasoningTrim: prefixEditBesidesReasoningTrim || firstRenderBust || args.isCacheBusting || hasPendingMaterializeSignal || deferredMaterializationConsumedThisPass || foldBustsServedPrefixThisPass || publishedM1RefreshedThisPass || materialized || historyWasConsumedThisPass || pendingOpsDidMutate || autoReclaimDidMutateThisPass || emergency,
41592
+ prefixEditBesidesReasoningTrim: !!args.recoveryRebuildReason || prefixEditBesidesReasoningTrim || firstRenderBust || args.isCacheBusting || hasPendingMaterializeSignal || deferredMaterializationConsumedThisPass || foldBustsServedPrefixThisPass || publishedM1RefreshedThisPass || materialized || historyWasConsumedThisPass || pendingOpsDidMutate || autoReclaimDidMutateThisPass || emergency,
40976
41593
  targetCount: targets.size,
40977
41594
  reasoningWatermark: args.sessionMeta.clearedReasoningThroughTag ?? 0,
40978
41595
  activeTags,
@@ -41199,7 +41816,7 @@ function appendReminderToPiUserMessage(message, reminder) {
41199
41816
  function clearPiCompactionOffInMemoryState(sessionId) {
41200
41817
  historyRefreshSessions.delete(sessionId);
41201
41818
  deferredHistoryRefreshSessions.delete(sessionId);
41202
- pendingMaterializationSessions.delete(sessionId);
41819
+ clearPendingMaterialization(pendingMaterializationSessions, sessionId);
41203
41820
  deferredMaterializationSessions.delete(sessionId);
41204
41821
  clearPiChannel1State(sessionId);
41205
41822
  }
@@ -41212,7 +41829,7 @@ function clearContextHandlerSession(sessionId) {
41212
41829
  clearAutoSearchForPiSession(sessionId);
41213
41830
  lastEmergencyNotificationAtMs.delete(sessionId);
41214
41831
  historyRefreshSessions.delete(sessionId);
41215
- pendingMaterializationSessions.delete(sessionId);
41832
+ clearPendingMaterialization(pendingMaterializationSessions, sessionId);
41216
41833
  systemPromptRefreshSessions.delete(sessionId);
41217
41834
  deferredHistoryRefreshSessions.delete(sessionId);
41218
41835
  deferredMaterializationSessions.delete(sessionId);
@@ -43880,112 +44497,6 @@ function buildStatusViewFor(check, options) {
43880
44497
  }, check.versions, options);
43881
44498
  }
43882
44499
  }
43883
- // package.json
43884
- var package_default = {
43885
- name: "@cortexkit/pi-magic-context",
43886
- version: "0.49.0",
43887
- type: "module",
43888
- description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
43889
- main: "dist/index.js",
43890
- license: "MIT",
43891
- author: "ualtinok",
43892
- keywords: [
43893
- "pi",
43894
- "pi-coding-agent",
43895
- "omp",
43896
- "oh-my-pi",
43897
- "extension",
43898
- "context",
43899
- "memory",
43900
- "magic-context",
43901
- "ai",
43902
- "llm"
43903
- ],
43904
- repository: {
43905
- type: "git",
43906
- url: "https://github.com/cortexkit/magic-context",
43907
- directory: "packages/pi-plugin"
43908
- },
43909
- files: [
43910
- "dist",
43911
- "README.md"
43912
- ],
43913
- "//": "The build intentionally bundles typebox (no --external typebox) and keeps it a regular dependency. OMP's extension loader rewrites every bare `typebox` import to its own omptype-based shim, whose schemas are callable objects rather than JSON Schema; they fail structuredClone during tool registration, so an external typebox import stops Magic Context loading on OMP. src/typebox-bundling.test.ts guards this.",
43914
- scripts: {
43915
- build: "bun ../../scripts/check-bun.mjs && tsc -p ../retina-local-fs/tsconfig.build.json && bun ../../scripts/clean-dist-chunks.mjs dist index.js subagent-entry.js historian-calibration-extension.js raw-ordinal-warmup-worker.js transformers-web.js transformers-node-wasm.js && bun build ../plugin/src/features/magic-context/memory/transformers-web-entry.ts --outfile dist/transformers-web.js --target browser --format esm --external onnxruntime-web && bun ../plugin/scripts/build-transformers-node-wasm.ts dist && bun build src/index.ts src/subagent-entry.ts src/historian-calibration-extension.ts ../plugin/src/features/magic-context/memory/embedding-worker.ts ../plugin/src/features/magic-context/migration-worker.ts ../plugin/src/hooks/magic-context/auto-search-worker.ts ../plugin/src/hooks/magic-context/raw-ordinal-warmup-worker.ts --outdir dist --entry-naming '[name].[ext]' --target node --format esm --splitting --external @earendil-works/pi-coding-agent --external @oh-my-pi/pi-coding-agent --external @earendil-works/pi-tui --external onnxruntime-node --external onnxruntime-web --external sharp --external node:sqlite",
43916
- "build:e2e-argv": `bun ../../scripts/clean-dist-chunks.mjs ../../tests/docker/.generated subagent-runner-e2e.mjs && bun build src/subagent-runner.ts --outdir ../../tests/docker/.generated --entry-naming 'subagent-runner-e2e.mjs' --splitting --target node --format esm --external node:sqlite && node --input-type=module -e 'const { __test } = await import("../../tests/docker/.generated/subagent-runner-e2e.mjs"); if (typeof __test.buildArgs !== "function" || typeof __test.resolvePiInvocation !== "function") throw new Error("argv renderer exports missing"); console.log("Node argv renderer: 2 exports loaded")'`,
43917
- typecheck: "tsc -p ../retina-local-fs/tsconfig.build.json && tsc --noEmit",
43918
- test: "bun ../../scripts/check-bun.mjs && bun install --frozen-lockfile && BUN_JSC_useOMGJIT=0 bun test --parallel=4 --timeout 30000",
43919
- "test:serial": "bun ../../scripts/check-bun.mjs && bun install --frozen-lockfile && BUN_JSC_useOMGJIT=0 bun test --parallel=1 --timeout 30000",
43920
- lint: "bun ../../scripts/check-bun.mjs && biome check src",
43921
- "lint:fix": "biome check --write src",
43922
- format: "biome format --write src",
43923
- "format:check": "biome format src",
43924
- clean: "bun ../../scripts/clean-dist-chunks.mjs dist index.js subagent-entry.js historian-calibration-extension.js embedding-worker.js migration-worker.js raw-ordinal-warmup-worker.js transformers-web.js transformers-node-wasm.js",
43925
- prepublishOnly: "bun run build"
43926
- },
43927
- "//test": "Test runs cap file-isolated workers at four (one for test:serial) and disable JSC's optimizing WebAssembly tier so per-file isolation does not pay its compilation cost on every file. These are not production settings and do not change host process engine options.",
43928
- dependencies: {
43929
- "@cortexkit/subc-client": "0.11.1",
43930
- "@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
43931
- "ai-tokenizer": "^1.0.6",
43932
- "comment-json": "^5.0.0",
43933
- "onnxruntime-web": "1.26.0-dev.20260416-b7804b056c",
43934
- "quickjs-emscripten": "^0.32.0",
43935
- zod: "^4.1.8"
43936
- },
43937
- optionalDependencies: {
43938
- "onnxruntime-node": "1.30.0",
43939
- sharp: "^0.35.0"
43940
- },
43941
- devDependencies: {
43942
- "@biomejs/biome": "^2.5.1",
43943
- "@earendil-works/pi-ai": "0.83.0",
43944
- "@earendil-works/pi-coding-agent": "0.83.0",
43945
- "@earendil-works/pi-tui": "0.83.0",
43946
- "@huggingface/transformers": "^4.3.0",
43947
- "@types/better-sqlite3": "^7.6.13",
43948
- "@types/bun": "^1.3.10",
43949
- "@types/node": "^22.20.0",
43950
- "pi-agent-core-087": "npm:@earendil-works/pi-agent-core@0.87.1",
43951
- "pi-ai-086": "npm:@earendil-works/pi-ai@0.86.0",
43952
- "pi-coding-agent-086": "npm:@earendil-works/pi-coding-agent@0.86.0",
43953
- "pi-coding-agent-087": "npm:@earendil-works/pi-coding-agent@0.87.1",
43954
- typebox: "^1.3.1",
43955
- typescript: "^5.8.0"
43956
- },
43957
- peerDependencies: {
43958
- "@earendil-works/pi-coding-agent": "*",
43959
- "@earendil-works/pi-tui": "*",
43960
- typebox: "*"
43961
- },
43962
- peerDependenciesMeta: {
43963
- "@earendil-works/pi-coding-agent": {
43964
- optional: true
43965
- },
43966
- "@earendil-works/pi-tui": {
43967
- optional: true
43968
- },
43969
- typebox: {
43970
- optional: true
43971
- }
43972
- },
43973
- exports: {
43974
- ".": {
43975
- import: "./dist/index.js"
43976
- }
43977
- },
43978
- pi: {
43979
- extensions: [
43980
- "./dist/index.js"
43981
- ]
43982
- },
43983
- omp: {
43984
- extensions: [
43985
- "./dist/index.js"
43986
- ]
43987
- }
43988
- };
43989
44500
 
43990
44501
  // src/dialogs/status-dialog.ts
43991
44502
  var REFRESH_INTERVAL_MS = 1000;
@@ -45498,6 +46009,7 @@ function withTimeout(p, ms) {
45498
46009
  }
45499
46010
 
45500
46011
  // src/index.ts
46012
+ registerStandalonePluginMarker(package_default.version);
45501
46013
  var PI_HARNESS_DETECTION = await resolvePiHarnessDetection();
45502
46014
  var PI_HARNESS_KIND = PI_HARNESS_DETECTION.kind;
45503
46015
  var PREFIX2 = `[magic-context][${PI_HARNESS_KIND}]`;
@@ -45743,6 +46255,7 @@ function resolvePiPressureContextLimit(args) {
45743
46255
  }) ?? 0;
45744
46256
  }
45745
46257
  async function persistPiPressureFromMessageEnd(args) {
46258
+ acknowledgePiSystemPromptResponse(args.sessionId, args.message);
45746
46259
  if (piMessageAnchorsLiveUsage(args.message)) {
45747
46260
  recordPiLiveUsageClassification(args.sessionId, false);
45748
46261
  } else if (typeof args.piTokensIsRawBranchEstimate === "boolean") {
@@ -45970,7 +46483,6 @@ async function src_default(pi) {
45970
46483
  info("plugin DISABLED via config (enabled: false) — skipping registration");
45971
46484
  return;
45972
46485
  }
45973
- reloadWindowOverlay(bootConfig.config.models?.window_overlay_path);
45974
46486
  setStoragePrivatePermissionEnforcement(bootConfig.config.storage.enforce_private_permissions);
45975
46487
  setSqlitePragmaConfig({
45976
46488
  cacheSizeMb: bootConfig.config.sqlite.cache_size_mb,
@@ -46754,9 +47266,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
46754
47266
  promptSurfacePreset: promptSurface.preset
46755
47267
  });
46756
47268
  if (result.hashChanged) {
46757
- signalPiHistoryRefresh(sessionId);
46758
- signalPiSystemPromptRefresh(sessionId);
46759
- signalPiPendingMaterialization(sessionId);
47269
+ signalPiSystemHashChange(sessionId, result.currentHash);
46760
47270
  }
46761
47271
  if (isCacheBusting) {
46762
47272
  clearSystemPromptRefresh(sessionId);
@@ -46772,6 +47282,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
46772
47282
  });
46773
47283
  info("registered before_agent_start system prompt injector");
46774
47284
  pi.on("agent_end", (event, ctx) => {
47285
+ acknowledgePiPendingSystemPromptResponses(ctx.sessionManager.getSessionId());
46775
47286
  setEmbeddingSessionBusy2(ctx.sessionManager.getSessionId(), false);
46776
47287
  log2("agent_end: returning synchronously (background work continues)");
46777
47288
  try {