@cortexkit/pi-magic-context 0.49.30 → 0.49.32

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 (30) hide show
  1. package/dist/auto-search-worker.js +4 -4
  2. package/dist/chunk-embedding-write-worker.js +4 -4
  3. package/dist/{compartment-chunk-embedding-pkk5beqp.js → compartment-chunk-embedding-8c85ebce.js} +1 -1
  4. package/dist/{embedding-backfill-v83xh6e8.js → embedding-backfill-rwfmyvze.js} +3 -3
  5. package/dist/{index-kmk3xpf9.js → index-0gymvr5j.js} +47 -7
  6. package/dist/{index-n2ayqhbx.js → index-87xkw8xm.js} +7 -5
  7. package/dist/{index-4nny4r40.js → index-9xd7qveg.js} +1 -1
  8. package/dist/{index-g026ztby.js → index-c474g0gj.js} +4 -18
  9. package/dist/{index-gxjppvsh.js → index-d0n9yjnc.js} +35 -13
  10. package/dist/{index-5qh6z3sn.js → index-d5q1q700.js} +1 -1
  11. package/dist/{index-2pnhk4gc.js → index-drmr22ac.js} +115 -39
  12. package/dist/{index-0cq3g9y5.js → index-e59j3yq5.js} +414 -11
  13. package/dist/{index-0x1c054v.js → index-eqw9t2ty.js} +1 -1
  14. package/dist/index-nrzkqte4.js +18 -0
  15. package/dist/{index-0s14xaca.js → index-pb3ea2tq.js} +1 -1
  16. package/dist/{index-y5x5wt5t.js → index-r9y6tbbm.js} +6 -4
  17. package/dist/{index-74bc8ts8.js → index-wpazxe9x.js} +64 -3
  18. package/dist/{index-0jykn0dw.js → index-xn5yh0pn.js} +65 -2
  19. package/dist/index.js +722 -447
  20. package/dist/{message-index-bounded-vkqx693v.js → message-index-bounded-n30vk21s.js} +4 -4
  21. package/dist/migration-worker.js +6 -5
  22. package/dist/{project-embedding-registry-wwbhm9rf.js → project-embedding-registry-acqb6be4.js} +2 -2
  23. package/dist/raw-ordinal-warmup-worker.js +3 -3
  24. package/dist/{read-session-chunk-73kd0ans.js → read-session-chunk-ka6dhc77.js} +3 -3
  25. package/dist/{search-archive-ck531w6h.js → search-archive-msy2bczx.js} +4 -4
  26. package/dist/{search-tgv2rdac.js → search-qbxrnnjb.js} +9 -9
  27. package/dist/{storage-tags-9qaasrky.js → storage-tags-6409qq18.js} +2 -2
  28. package/dist/subagent-entry.js +12 -12
  29. package/dist/tag-snapshot-worker-pi.js +11 -8
  30. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -139,6 +139,7 @@ import {
139
139
  decodePiContentDecision,
140
140
  getPiContentDecisions,
141
141
  freezePiContentDecision,
142
+ withNativeReplayWriteBarrier,
142
143
  getNativeReplayState,
143
144
  saveNativeToolInputs,
144
145
  addNativeReasoningIds,
@@ -262,7 +263,7 @@ import {
262
263
  registerTodoStateLifecycle,
263
264
  syncCtxMemoryToolEnabled,
264
265
  registerMagicContextTools
265
- } from "./index-gxjppvsh.js";
266
+ } from "./index-d0n9yjnc.js";
266
267
  import"./index-4knyh1kt.js";
267
268
  import {
268
269
  canonicalModelIdentity,
@@ -304,7 +305,7 @@ import {
304
305
  openCurrentDatabase,
305
306
  openDatabaseAsync,
306
307
  closeDatabase
307
- } from "./index-y5x5wt5t.js";
308
+ } from "./index-r9y6tbbm.js";
308
309
  import {
309
310
  sameProjectDirectory,
310
311
  pruneMissingProjectIdentities,
@@ -329,6 +330,7 @@ import {
329
330
  HYGIENE_PROVIDER_UNITS_VERSION,
330
331
  sessionDecisionCalibration,
331
332
  transitionSessionHygieneUnits,
333
+ rowWindowMass,
332
334
  computeProtectionWindow,
333
335
  readEpochFloorSnapshot,
334
336
  getProtectionWindowForSession,
@@ -481,7 +483,7 @@ import {
481
483
  getRawSessionTagKeysThrough2,
482
484
  getLegacyProtectedTailStartOrdinal2,
483
485
  readSessionChunk2
484
- } from "./index-n2ayqhbx.js";
486
+ } from "./index-87xkw8xm.js";
485
487
  import {
486
488
  UNKNOWN_FIT_RATIO,
487
489
  hasMeasuredDecisionCalibration,
@@ -568,7 +570,7 @@ import {
568
570
  getToolTagNumberByOwner2,
569
571
  getNullOwnerToolTag2,
570
572
  adoptNullOwnerToolTag2
571
- } from "./index-0x1c054v.js";
573
+ } from "./index-eqw9t2ty.js";
572
574
  import {
573
575
  textMentionsRecentCommit,
574
576
  hasMeaningfulUserText2,
@@ -592,18 +594,15 @@ import {
592
594
  guardSqliteTransformPass2,
593
595
  assertTransformWrite2,
594
596
  isTransientSqliteError2,
595
- withAsyncPrivilegedWriter2,
596
- indexCoordinationInput2
597
+ withAsyncPrivilegedWriter2
597
598
  } from "./index-2qtx0q6h.js";
598
599
  import {
599
600
  stableStringify,
600
- closeQuietly,
601
- isKnownAutocommit,
602
601
  getTableColumnNames,
603
602
  observeTemporalDecisions,
604
603
  freezeTemporalDecisions,
605
604
  tagIdentityRevisionKey
606
- } from "./index-g026ztby.js";
605
+ } from "./index-c474g0gj.js";
607
606
  import {
608
607
  BoundedSessionMap,
609
608
  resolveOpenCodeDbPath,
@@ -618,7 +617,6 @@ import {
618
617
  createWorkerShutdown
619
618
  } from "./index-54wmg4rj.js";
620
619
  import {
621
- runSessionWarmupWorker,
622
620
  RAW_SUMMARY_TEXT_MAX_CHARS2
623
621
  } from "./index-6981g1xv.js";
624
622
  import {
@@ -634,7 +632,7 @@ import {
634
632
  replaceCompartmentChunkEmbeddings2,
635
633
  deleteChunkEmbedBackoffForSession2,
636
634
  chunkWindowSourceKey2
637
- } from "./index-kmk3xpf9.js";
635
+ } from "./index-0gymvr5j.js";
638
636
  import {
639
637
  recordSessionProjectIdentity,
640
638
  GIT_SWEEP_LEASE_RENEWAL_MS,
@@ -669,20 +667,13 @@ import {
669
667
  embedSessionCompartmentChunks2,
670
668
  getEmbeddingCoverageStatus2,
671
669
  getAutoEmbeddingSessionCoverage2
672
- } from "./index-0jykn0dw.js";
670
+ } from "./index-xn5yh0pn.js";
673
671
  import {
674
672
  clearCompressionDepth,
675
673
  clearCompressionDepthRange,
676
674
  cleanSearchText,
677
- matchedSearchSnippet,
678
- getMessageIndexSourceIdentity,
679
- isMessageIndexSourceCurrent,
680
- getLastIndexedOrdinal,
681
- getMessageIndexReconciliationStartOrdinal,
682
- isMessageIndexReconciledThrough,
683
- indexSingleMessage,
684
- indexMessagesAfterOrdinal
685
- } from "./index-74bc8ts8.js";
675
+ matchedSearchSnippet
676
+ } from "./index-wpazxe9x.js";
686
677
  import {
687
678
  rememberV1HiddenRun
688
679
  } from "./index-6x556c2q.js";
@@ -697,7 +688,7 @@ import {
697
688
  expandWorkspaceIdentitySetWithAliases,
698
689
  sourceNameForMemory,
699
690
  computeWorkspaceEpochFingerprint
700
- } from "./index-0s14xaca.js";
691
+ } from "./index-pb3ea2tq.js";
701
692
  import {
702
693
  configureContextDatabasePragmas2
703
694
  } from "./index-fapenpch.js";
@@ -746,8 +737,14 @@ import {
746
737
  verificationFileExists,
747
738
  normalizeVerificationFiles,
748
739
  indexCommitsForProject,
749
- embedUnembeddedCommits
750
- } from "./index-0cq3g9y5.js";
740
+ embedUnembeddedCommits,
741
+ getMessageIndexEpoch,
742
+ isMessageIndexSearchable,
743
+ scheduleReconciliation,
744
+ scheduleIncrementalIndex,
745
+ scheduleClearAndReindex,
746
+ clearSessionTracking
747
+ } from "./index-e59j3yq5.js";
751
748
  import {
752
749
  setEmbeddingSessionBusy2,
753
750
  isEmbeddingHostBusy2
@@ -783,7 +780,7 @@ import {
783
780
  } from "./index-wqpjhx1p.js";
784
781
  import {
785
782
  cosineSimilarity
786
- } from "./index-4nny4r40.js";
783
+ } from "./index-9xd7qveg.js";
787
784
  import"./index-6wdwv3a6.js";
788
785
  import {
789
786
  DREAMER_PRIMER_INVESTIGATOR_ALLOWED_TOOLS,
@@ -803,7 +800,7 @@ import {
803
800
  PiContextSupersededError,
804
801
  PiContextBudget,
805
802
  PiTagHydrationError,
806
- getPiTagSnapshotView,
803
+ getPiPassTagSnapshotView,
807
804
  getPiActiveTagSnapshotView,
808
805
  readPiFallbackTagRows,
809
806
  prewarmPiTagSnapshot,
@@ -811,10 +808,10 @@ import {
811
808
  drainPiTagSnapshotSession,
812
809
  assertPiTagSnapshotReady,
813
810
  ensurePiTagSnapshotReady
814
- } from "./index-2pnhk4gc.js";
811
+ } from "./index-drmr22ac.js";
815
812
  import"./index-jn44h81p.js";
816
813
  import"./index-1cvyaw9a.js";
817
- import"./index-5qh6z3sn.js";
814
+ import"./index-d5q1q700.js";
818
815
  import {
819
816
  __toESM
820
817
  } from "./index-22jkk6wg.js";
@@ -824,6 +821,10 @@ import {
824
821
  import {
825
822
  normalizeProtectedToolName
826
823
  } from "./index-674f6qs2.js";
824
+ import {
825
+ closeQuietly,
826
+ isKnownAutocommit
827
+ } from "./index-nrzkqte4.js";
827
828
  import {
828
829
  logSlowWriteTransaction,
829
830
  WriteTransactionSteps
@@ -3559,7 +3560,7 @@ function startHostStallProfilerSwitch() {
3559
3560
  // package.json
3560
3561
  var package_default = {
3561
3562
  name: "@cortexkit/pi-magic-context",
3562
- version: "0.49.30",
3563
+ version: "0.49.32",
3563
3564
  type: "module",
3564
3565
  description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
3565
3566
  main: "dist/index.js",
@@ -3625,12 +3626,14 @@ var package_default = {
3625
3626
  "@types/node": "^22.20.0",
3626
3627
  "omp-coding-agent-1812": "npm:@oh-my-pi/pi-coding-agent@18.12.3",
3627
3628
  "omp-coding-agent-18126": "npm:@oh-my-pi/pi-coding-agent@18.12.6",
3629
+ "omp-coding-agent-18132": "npm:@oh-my-pi/pi-coding-agent@18.13.2",
3628
3630
  "omp-pi-ai-171": "npm:@oh-my-pi/pi-ai@17.1.7",
3629
3631
  "omp-pi-ai-1889": "npm:@oh-my-pi/pi-ai@18.8.9",
3630
3632
  "omp-pi-ai-1811": "npm:@oh-my-pi/pi-ai@18.11.3",
3631
3633
  "omp-pi-ai-1812": "npm:@oh-my-pi/pi-ai@18.12.3",
3632
3634
  "omp-pi-ai-18126": "npm:@oh-my-pi/pi-ai@18.12.6",
3633
3635
  "omp-pi-ai-1813": "npm:@oh-my-pi/pi-ai@18.13.0",
3636
+ "omp-pi-ai-18132": "npm:@oh-my-pi/pi-ai@18.13.2",
3634
3637
  "pi-agent-core-087": "npm:@earendil-works/pi-agent-core@0.87.1",
3635
3638
  "pi-ai-086": "npm:@earendil-works/pi-ai@0.86.0",
3636
3639
  "pi-ai-087": "npm:@earendil-works/pi-ai@0.87.1",
@@ -4366,16 +4369,47 @@ function getDreamTaskBacklog(db, projectPath, task, options = {}) {
4366
4369
  }
4367
4370
  }
4368
4371
  var backlogCaches = new WeakMap;
4372
+ var displayBacklogCaches = new WeakMap;
4373
+ var DISPLAY_BACKLOG_MAX_AGE_MS = 60000;
4369
4374
  function getDreamTaskBacklogs(db, projectPath, tasks = CANONICAL_DREAM_TASKS, options = {}) {
4370
4375
  if (tasks.length === 0)
4371
4376
  return {};
4372
4377
  if (!isKnownAutocommit(db)) {
4373
4378
  backlogCaches.delete(db);
4379
+ displayBacklogCaches.delete(db);
4374
4380
  const result = {};
4375
4381
  for (const task of tasks)
4376
4382
  result[task] = getDreamTaskBacklog(db, projectPath, task, options);
4377
4383
  return result;
4378
4384
  }
4385
+ if (options.display) {
4386
+ let entries = displayBacklogCaches.get(db);
4387
+ if (!entries) {
4388
+ entries = new Map;
4389
+ displayBacklogCaches.set(db, entries);
4390
+ }
4391
+ const optionKey = (value) => value === undefined ? "omitted" : value === null ? "null" : `number:${value}`;
4392
+ const key = JSON.stringify([
4393
+ projectPath,
4394
+ tasks,
4395
+ optionKey(options.lastRunAt),
4396
+ optionKey(options.retrospectiveWatermarkMs)
4397
+ ]);
4398
+ const now = Date.now();
4399
+ const cached = entries.get(key);
4400
+ if (cached && now < cached.expiresAt && now >= cached.expiresAt - DISPLAY_BACKLOG_MAX_AGE_MS)
4401
+ return structuredClone(cached.value);
4402
+ const value = {};
4403
+ for (const task of tasks)
4404
+ value[task] = getDreamTaskBacklog(db, projectPath, task, options);
4405
+ if (entries.size >= 256)
4406
+ entries.delete(entries.keys().next().value);
4407
+ entries.set(key, {
4408
+ expiresAt: now + DISPLAY_BACKLOG_MAX_AGE_MS,
4409
+ value: structuredClone(value)
4410
+ });
4411
+ return value;
4412
+ }
4379
4413
  let cache = backlogCaches.get(db);
4380
4414
  if (!cache) {
4381
4415
  cache = {
@@ -14762,7 +14796,6 @@ function parseMapMemoriesManifest(text) {
14762
14796
  }
14763
14797
  function validateMapMemoriesManifest(text, expectedIds) {
14764
14798
  const parsed = parseMapMemoriesManifest(text);
14765
- assertParsedManifestNonEmpty(parsed.length, expectedIds.size, text, "mappings", "memory");
14766
14799
  assertNoDuplicateManifestIds(parsed.filter((entry) => expectedIds.has(entry.id)).map((entry) => entry.id), "mappings");
14767
14800
  return parsed;
14768
14801
  }
@@ -16949,8 +16982,7 @@ function parsePartialVerifyManifest(text, expectedIds) {
16949
16982
  var VERIFY_BATCH_SIZE = 5;
16950
16983
  var VERIFY_TOKENS_PER_MEMORY = 1e5;
16951
16984
  var VERIFY_RUN_TOKEN_BUDGET = 2500000;
16952
- var VERIFY_RUN_SLICE_MS = 240000;
16953
- var VERIFY_IN_FLIGHT_GRACE_MS = 120000;
16985
+ var VERIFY_BATCH_DEFAULT_MS = 240000;
16954
16986
  function verifyBatchTokenBudget(size, configured) {
16955
16987
  return Math.min(configured ?? Number.MAX_SAFE_INTEGER, size * VERIFY_TOKENS_PER_MEMORY);
16956
16988
  }
@@ -16980,8 +17012,8 @@ function validateVerifyCompletion(messages, text, expectedIds, responseText = te
16980
17012
  }
16981
17013
  var IDENTICAL_PROVIDER_FAILURE_BATCH_LIMIT = 2;
16982
17014
  var VERIFY_BATCH_FLOOR_MS = 30000;
16983
- function computeVerifyBatchSliceMs(remainingMs, _batchesRemaining) {
16984
- return Math.min(remainingMs, VERIFY_RUN_SLICE_MS);
17015
+ function computeVerifyBatchSliceMs(remainingMs, batchesRemaining) {
17016
+ return Math.min(remainingMs, Math.max(VERIFY_BATCH_DEFAULT_MS, remainingMs / Math.max(1, batchesRemaining)));
16985
17017
  }
16986
17018
  function closeBroadCycle(args, cycleStartAt) {
16987
17019
  if (!args.forceBroad || cycleStartAt === undefined)
@@ -17005,7 +17037,6 @@ async function runVerify(args) {
17005
17037
  }
17006
17038
  async function runVerifyWithCooldown(args) {
17007
17039
  const runStartedAt = Date.now();
17008
- const sliceDeadline = runStartedAt + VERIFY_RUN_SLICE_MS;
17009
17040
  const result = {
17010
17041
  verified: 0,
17011
17042
  updated: 0,
@@ -17053,12 +17084,10 @@ async function runVerifyWithCooldown(args) {
17053
17084
  try {
17054
17085
  for (let i = 0;i < batches.length; i += 1) {
17055
17086
  const now = Date.now();
17056
- const startCutoff = Math.min(args.deadline, sliceDeadline);
17057
- const hardStop = Math.min(args.deadline, sliceDeadline + VERIFY_IN_FLIGHT_GRACE_MS);
17058
- const remainingMs = Math.max(0, hardStop - now);
17059
- if (now >= startCutoff) {
17087
+ const remainingMs = Math.max(0, args.deadline - now);
17088
+ if (now >= args.deadline) {
17060
17089
  result.stopReason = "deadline";
17061
- log2(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: stopping before batch ${i + 1}/${batches.length} — the run deadline passed ${now - startCutoff}ms ago`);
17090
+ log2(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: stopping before batch ${i + 1}/${batches.length} — the run deadline passed ${now - args.deadline}ms ago`);
17062
17091
  break;
17063
17092
  }
17064
17093
  if (remainingMs < VERIFY_BATCH_FLOOR_MS) {
@@ -17997,7 +18026,7 @@ function createDreamTaskExecutor(deps) {
17997
18026
  return { status: "failed", transient: true, error };
17998
18027
  }
17999
18028
  const processed = result.mapped + result.independent;
18000
- if (processed > 0) {
18029
+ if (processed > 0 || result.failure === undefined) {
18001
18030
  const progress = `map-memories: committed ${processed} mapping(s) (mapped ${result.mapped}, independent ${result.independent}); ${result.remaining} remain`;
18002
18031
  recordRun("completed", null, { progress });
18003
18032
  return { status: "completed" };
@@ -22427,7 +22456,7 @@ function normalizePiUserEntry(entry, sessionId, ordinal, followsAssistantReply)
22427
22456
  return null;
22428
22457
  if (message.role !== "user" || typeof message.timestamp !== "number")
22429
22458
  return null;
22430
- const text = extractPiTextContent(message.content).trim();
22459
+ const text = cleanUserText2(extractPiTextContent(message.content));
22431
22460
  if (!text)
22432
22461
  return null;
22433
22462
  return {
@@ -22461,7 +22490,7 @@ function extractPiTextContent(content) {
22461
22490
  if (part === null || typeof part !== "object")
22462
22491
  return [];
22463
22492
  const record = part;
22464
- return record.type === "text" && typeof record.text === "string" ? [record.text] : [];
22493
+ return record.synthetic !== true && record.type === "text" && typeof record.text === "string" ? [record.text] : [];
22465
22494
  }).join(`
22466
22495
  `);
22467
22496
  }
@@ -23677,290 +23706,6 @@ function commitPiCompactionModeRecord(db, sessionId, record) {
23677
23706
  // src/context-handler.ts
23678
23707
  import * as crypto3 from "node:crypto";
23679
23708
 
23680
- // ../plugin/src/features/magic-context/message-index-async.ts
23681
- var indexCancellations = new Map;
23682
- var sessionEpochs = new Map;
23683
- var workerMeasurements = new WeakMap;
23684
- function isDatabaseLockedError(error) {
23685
- if (!error || typeof error !== "object")
23686
- return false;
23687
- const e = error;
23688
- if (typeof e.code === "string") {
23689
- if (e.code === "SQLITE_BUSY" || e.code === "SQLITE_LOCKED")
23690
- return true;
23691
- }
23692
- if (typeof e.message === "string") {
23693
- if (/database is locked/i.test(e.message))
23694
- return true;
23695
- if (/sqlite_(busy|locked)/i.test(e.message))
23696
- return true;
23697
- }
23698
- return false;
23699
- }
23700
- var INCREMENTAL_DEBOUNCE_MS = 100;
23701
- var RECONCILIATION_BATCH_SIZE = 100;
23702
-
23703
- class MagicContextMessageIndexHeapHolder {
23704
- reconciledSessions = new Set;
23705
- reconciledSnapshots = new Map;
23706
- stalledSessions = new Set;
23707
- reconciliationScheduledSessions = new Set;
23708
- clearAndReindexScheduledSessions = new Map;
23709
- sessionLocks = new Map;
23710
- incrementalTimers = new Map;
23711
- pendingIncrementalKeys = new Set;
23712
- completedIncrementalKeys = new Set;
23713
- activeReconcilerBuffers = new Map;
23714
- }
23715
- var heapHolder = new MagicContextMessageIndexHeapHolder;
23716
- var PREPARE_RETRY_MS = 60000;
23717
- async function sourceReady(source, sessionId) {
23718
- const prepare = source?.prepare;
23719
- return typeof prepare === "function" ? prepare(sessionId) : true;
23720
- }
23721
- function defer(fn) {
23722
- const immediate = globalThis.setImmediate;
23723
- if (typeof immediate === "function") {
23724
- inRootAsyncContext2(() => immediate(fn));
23725
- return;
23726
- }
23727
- inRootAsyncContext2(() => setTimeout(fn, 0));
23728
- }
23729
- function yieldToEventLoop() {
23730
- return new Promise((resolve) => defer(resolve));
23731
- }
23732
- function runWithSessionLock(sessionId, operation) {
23733
- const previous = heapHolder.sessionLocks.get(sessionId) ?? Promise.resolve();
23734
- const run = previous.catch(() => {
23735
- return;
23736
- }).then(async () => {
23737
- await operation();
23738
- });
23739
- heapHolder.sessionLocks.set(sessionId, run);
23740
- run.finally(() => {
23741
- if (heapHolder.sessionLocks.get(sessionId) === run) {
23742
- heapHolder.sessionLocks.delete(sessionId);
23743
- }
23744
- }).catch(() => {
23745
- return;
23746
- });
23747
- return run;
23748
- }
23749
- function logIndexingError(sessionId, action, error) {
23750
- if (isDatabaseLockedError(error)) {
23751
- sessionLog2(sessionId, `message FTS async ${action} skipped (database busy; will retry on next reconciliation)`);
23752
- return;
23753
- }
23754
- sessionLog2(sessionId, `message FTS async ${action} failed: ${error instanceof Error ? error.message : String(error)}`);
23755
- log2(`[message-index-async] ${action} failed for ${sessionId}:`, error);
23756
- }
23757
- function logReconciliationStall(sessionId, reason) {
23758
- if (heapHolder.stalledSessions.has(sessionId))
23759
- return;
23760
- heapHolder.stalledSessions.add(sessionId);
23761
- sessionLog2(sessionId, `message FTS reconciliation stalled: ${reason}; will retry`);
23762
- }
23763
- async function reconcileSessionIndex(db, sessionId, readMessages) {
23764
- if (!await sourceReady(readMessages, sessionId)) {
23765
- logReconciliationStall(sessionId, "raw message reader is not ready");
23766
- return false;
23767
- }
23768
- await runWithSessionLock(sessionId, async () => {
23769
- if (!readMessages.getRevision && heapHolder.reconciledSessions.has(sessionId))
23770
- return;
23771
- let fallbackSnapshot = null;
23772
- try {
23773
- const fullReader = typeof readMessages === "function" ? readMessages : null;
23774
- const revision = readMessages.getRevision?.(sessionId);
23775
- const previous = heapHolder.reconciledSnapshots.get(sessionId);
23776
- const finalWatermark = previous && revision === previous.revision ? previous.count : revision !== undefined && readMessages.getCountAfterRevision ? previous && revision > previous.revision ? previous.count + readMessages.getCountAfterRevision(sessionId, previous.revision, revision) : readMessages.getCountAfterRevision(sessionId, -1, revision) : readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = fullReader?.(sessionId) ?? []).length;
23777
- let cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
23778
- let after = cursor === previous?.count ? previous.after : undefined;
23779
- while (cursor < finalWatermark) {
23780
- const pageEnd = Math.min(finalWatermark, cursor + RECONCILIATION_BATCH_SIZE);
23781
- const messages = readMessages.readPage ? readMessages.readPage(sessionId, cursor, RECONCILIATION_BATCH_SIZE, finalWatermark, after) : (fallbackSnapshot ?? []).filter((message) => message.ordinal > cursor && message.ordinal <= pageEnd);
23782
- const retainedMessages = fallbackSnapshot ?? messages;
23783
- heapHolder.activeReconcilerBuffers.set(sessionId, retainedMessages);
23784
- withSqliteBackgroundWriter2(() => indexMessagesAfterOrdinal(db, sessionId, messages, cursor, pageEnd));
23785
- const nextCursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
23786
- if (nextCursor <= cursor)
23787
- break;
23788
- cursor = nextCursor;
23789
- const last = messages.at(-1);
23790
- after = last?.ordinal === cursor && typeof last.createdAt === "number" ? { timeCreated: last.createdAt, id: last.id } : undefined;
23791
- if (cursor < finalWatermark) {
23792
- await yieldToEventLoop();
23793
- }
23794
- }
23795
- if (isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
23796
- heapHolder.reconciledSessions.add(sessionId);
23797
- if (revision !== undefined) {
23798
- if (!after && finalWatermark > 0 && readMessages.readPage) {
23799
- const last = readMessages.readPage(sessionId, finalWatermark - 1, 1, finalWatermark).at(-1);
23800
- if (last?.ordinal === finalWatermark && typeof last.createdAt === "number")
23801
- after = { timeCreated: last.createdAt, id: last.id };
23802
- }
23803
- heapHolder.reconciledSnapshots.set(sessionId, {
23804
- revision,
23805
- count: finalWatermark,
23806
- after
23807
- });
23808
- }
23809
- } else {
23810
- logReconciliationStall(sessionId, `gap after ordinal ${cursor} (store count ${finalWatermark})`);
23811
- }
23812
- } finally {
23813
- heapHolder.activeReconcilerBuffers.delete(sessionId);
23814
- }
23815
- });
23816
- return true;
23817
- }
23818
- function scheduleReconciliation(db, sessionId, readMessages) {
23819
- if (!readMessages.getRevision && heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
23820
- return;
23821
- }
23822
- heapHolder.reconciliationScheduledSessions.add(sessionId);
23823
- scheduleAfterBootQuiet(() => {
23824
- defer(() => {
23825
- let appendedDuringReconciliation = false;
23826
- const previousSnapshot = heapHolder.reconciledSnapshots.get(sessionId);
23827
- reconcileSessionIndex(db, sessionId, readMessages).then((ran) => {
23828
- if (ran) {
23829
- const snapshot = heapHolder.reconciledSnapshots.get(sessionId);
23830
- appendedDuringReconciliation = snapshot !== undefined && snapshot !== previousSnapshot && readMessages.getRevision !== undefined && readMessages.getRevision(sessionId) !== snapshot.revision;
23831
- return;
23832
- }
23833
- inRootAsyncContext2(() => setTimeout(() => {
23834
- heapHolder.reconciliationScheduledSessions.delete(sessionId);
23835
- scheduleReconciliation(db, sessionId, readMessages);
23836
- }, PREPARE_RETRY_MS)).unref?.();
23837
- }).catch((error) => {
23838
- logReconciliationStall(sessionId, error instanceof Error ? error.message : String(error));
23839
- if (isDatabaseLockedError(error))
23840
- inRootAsyncContext2(() => setTimeout(() => scheduleReconciliation(db, sessionId, readMessages), 1000)).unref();
23841
- }).finally(() => {
23842
- heapHolder.reconciliationScheduledSessions.delete(sessionId);
23843
- if (appendedDuringReconciliation)
23844
- scheduleReconciliation(db, sessionId, readMessages);
23845
- });
23846
- });
23847
- });
23848
- }
23849
- function scheduleIncrementalIndex(db, sessionId, messageId, messageSource) {
23850
- const schedulingKey = `${sessionId}\x00${messageId}`;
23851
- const epoch = sessionEpochs.get(sessionId) ?? 0;
23852
- if (heapHolder.pendingIncrementalKeys.has(schedulingKey))
23853
- return;
23854
- const activeTimer = heapHolder.incrementalTimers.get(schedulingKey);
23855
- if (activeTimer)
23856
- clearTimeout(activeTimer);
23857
- const timer = inRootAsyncContext2(() => setTimeout(() => {
23858
- heapHolder.incrementalTimers.delete(schedulingKey);
23859
- heapHolder.pendingIncrementalKeys.add(schedulingKey);
23860
- const indexMessage = async () => {
23861
- if ((sessionEpochs.get(sessionId) ?? 0) !== epoch || !heapHolder.pendingIncrementalKeys.has(schedulingKey))
23862
- return;
23863
- const message = typeof messageSource === "function" ? messageSource(sessionId, messageId) : messageSource;
23864
- if (!message)
23865
- return;
23866
- const revisionKey = `${schedulingKey}\x00${getMessageIndexSourceIdentity(message)}`;
23867
- if (heapHolder.completedIncrementalKeys.has(revisionKey))
23868
- return;
23869
- const currentWatermark = getLastIndexedOrdinal(db, sessionId);
23870
- if (message.ordinal <= currentWatermark && isMessageIndexSourceCurrent(db, sessionId, message)) {
23871
- heapHolder.completedIncrementalKeys.add(revisionKey);
23872
- return;
23873
- }
23874
- const wasReconciled = heapHolder.reconciledSessions.delete(sessionId);
23875
- await indexSingleMessageOffThread(db, sessionId, message);
23876
- if ((sessionEpochs.get(sessionId) ?? 0) !== epoch || !heapHolder.pendingIncrementalKeys.has(schedulingKey))
23877
- return;
23878
- const finalWatermark = getLastIndexedOrdinal(db, sessionId);
23879
- if (wasReconciled && isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
23880
- heapHolder.reconciledSessions.add(sessionId);
23881
- }
23882
- heapHolder.completedIncrementalKeys.add(revisionKey);
23883
- };
23884
- sourceReady(messageSource, sessionId).then((ready) => {
23885
- if ((sessionEpochs.get(sessionId) ?? 0) !== epoch)
23886
- return;
23887
- if (ready)
23888
- return runWithSessionLock(sessionId, indexMessage);
23889
- setTimeout(() => scheduleIncrementalIndex(db, sessionId, messageId, messageSource), PREPARE_RETRY_MS).unref?.();
23890
- }).catch((error) => {
23891
- if ((sessionEpochs.get(sessionId) ?? 0) !== epoch)
23892
- return;
23893
- heapHolder.reconciledSessions.delete(sessionId);
23894
- logIndexingError(sessionId, `incremental index for ${messageId}`, error);
23895
- if (isDatabaseLockedError(error))
23896
- setTimeout(() => scheduleIncrementalIndex(db, sessionId, messageId, messageSource), 1000).unref();
23897
- }).finally(() => {
23898
- if ((sessionEpochs.get(sessionId) ?? 0) === epoch)
23899
- heapHolder.pendingIncrementalKeys.delete(schedulingKey);
23900
- });
23901
- }, INCREMENTAL_DEBOUNCE_MS));
23902
- heapHolder.incrementalTimers.set(schedulingKey, timer);
23903
- }
23904
- async function indexSingleMessageOffThread(db, sessionId, message) {
23905
- const path = getSqliteDatabasePath2(db);
23906
- if (!path)
23907
- return withSqliteBackgroundWriter2(() => indexSingleMessage(db, sessionId, message));
23908
- const cancellation = new Int32Array(new SharedArrayBuffer(4));
23909
- const active = indexCancellations.get(sessionId) ?? new Set;
23910
- active.add(cancellation);
23911
- indexCancellations.set(sessionId, active);
23912
- const result = await runSessionWarmupWorker({
23913
- path,
23914
- sessionId,
23915
- indexMessage: message,
23916
- harness: getHarness2(),
23917
- indexCancellation: cancellation.buffer,
23918
- ...indexCoordinationInput2()
23919
- }, {}).finally(() => {
23920
- active.delete(cancellation);
23921
- if (active.size === 0)
23922
- indexCancellations.delete(sessionId);
23923
- });
23924
- if (!("inserted" in result))
23925
- throw new Error("failure" in result ? result.detail : "unexpected indexing worker reply");
23926
- if (result.measurements) {
23927
- const sessions = workerMeasurements.get(db) ?? new Map;
23928
- sessions.set(sessionId, result.measurements);
23929
- workerMeasurements.set(db, sessions);
23930
- if (result.measurements.skipped)
23931
- log2(`[magic-context] incremental FTS skipped oversized source ${message.id} (${result.measurements.sourceBytes} bytes); identity and progress persisted`);
23932
- }
23933
- return result.inserted;
23934
- }
23935
- function clearSessionTracking(sessionId) {
23936
- sessionEpochs.set(sessionId, (sessionEpochs.get(sessionId) ?? 0) + 1);
23937
- for (const cancellation of indexCancellations.get(sessionId) ?? [])
23938
- Atomics.store(cancellation, 0, 1);
23939
- heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
23940
- heapHolder.reconciledSessions.delete(sessionId);
23941
- heapHolder.reconciledSnapshots.delete(sessionId);
23942
- heapHolder.stalledSessions.delete(sessionId);
23943
- heapHolder.reconciliationScheduledSessions.delete(sessionId);
23944
- heapHolder.sessionLocks.delete(sessionId);
23945
- heapHolder.activeReconcilerBuffers.delete(sessionId);
23946
- const prefix = `${sessionId}\x00`;
23947
- for (const [key, timer] of heapHolder.incrementalTimers) {
23948
- if (key.startsWith(prefix)) {
23949
- clearTimeout(timer);
23950
- heapHolder.incrementalTimers.delete(key);
23951
- }
23952
- }
23953
- for (const key of heapHolder.pendingIncrementalKeys) {
23954
- if (key.startsWith(prefix)) {
23955
- heapHolder.pendingIncrementalKeys.delete(key);
23956
- }
23957
- }
23958
- for (const key of heapHolder.completedIncrementalKeys) {
23959
- if (key.startsWith(prefix))
23960
- heapHolder.completedIncrementalKeys.delete(key);
23961
- }
23962
- }
23963
-
23964
23709
  // ../plugin/src/hooks/magic-context/event-resolvers.ts
23965
23710
  var DEFAULT_CONTEXT_LIMIT = 200000;
23966
23711
  var clampWarnSeen = new Set;
@@ -24957,6 +24702,7 @@ function prepareLegacyToolSkeletonConversions(db, sessionId, targets, options =
24957
24702
  });
24958
24703
  };
24959
24704
  const rows = readRows(db);
24705
+ options.prepareRemovals?.(rows);
24960
24706
  const converted = new Map;
24961
24707
  for (const row of rows) {
24962
24708
  const target = targets.get(row.tagNumber);
@@ -25188,6 +24934,15 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
25188
24934
  }
25189
24935
  return didMutateMessage;
25190
24936
  }
24937
+ function prepareFlushedToolRemovals(targets, tags) {
24938
+ for (const tag of tags) {
24939
+ if (tag.status !== "dropped" || tag.type !== "tool")
24940
+ continue;
24941
+ if (tag.dropMode != null && tag.dropMode !== "full")
24942
+ continue;
24943
+ targets.get(tag.tagNumber)?.prepareReplayDrop?.();
24944
+ }
24945
+ }
25191
24946
  function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
25192
24947
  let didMutateMessage = false;
25193
24948
  const tags = preloadedTags ?? getDroppedTagsByNumbers2(db, sessionId, [...targets.keys()]);
@@ -27884,7 +27639,7 @@ function tagTranscript(sessionId, transcript, tagger, db, options = {}) {
27884
27639
  skipPrefixInjection,
27885
27640
  preserveTagOnlyAssistantText: options.preserveTagOnlyAssistantText,
27886
27641
  entryFingerprint: options.entryFingerprintByMessageId?.get(messageId) ?? null,
27887
- reuseIdentity: reuseIdentity || contentDerivedTextIds !== undefined,
27642
+ reuseIdentity: reuseIdentity || options.reuseTextMessageIds?.has(messageId) === true || contentDerivedTextIds !== undefined,
27888
27643
  timing,
27889
27644
  textIdentitySourceCache: options.textIdentitySourceCache,
27890
27645
  textTokenCache: options.textTokenCache
@@ -27953,7 +27708,11 @@ function tagTranscript(sessionId, transcript, tagger, db, options = {}) {
27953
27708
  if (timing)
27954
27709
  timing.identity += performance.now() - identityStart;
27955
27710
  } else {
27956
- const accounting = readAggregateToolAccounting(part, timing, options.toolTokenCache, tokenCacheKey);
27711
+ const accounting = readAggregateToolAccounting(part, timing, options.toolTokenCache, tokenCacheKey, {
27712
+ byteSize: existing.maxByteSize,
27713
+ tokenCount: existing.maxTokenCount,
27714
+ inputTokenCount: existing.inputTokenCount
27715
+ });
27957
27716
  text = accounting.text;
27958
27717
  if (part.kind === "tool_result") {
27959
27718
  applyGrownToolResultAccounting({
@@ -28035,7 +27794,7 @@ function tagTranscript(sessionId, transcript, tagger, db, options = {}) {
28035
27794
  if (timing)
28036
27795
  timing.identity += performance.now() - identityStart;
28037
27796
  } else {
28038
- const accounting = readAggregateToolAccounting(part, timing, options.toolTokenCache, tokenCacheKey);
27797
+ const accounting = readAggregateToolAccounting(part, timing, options.toolTokenCache, tokenCacheKey, tagger.getToolTagAccounting(sessionId, callId, messageId));
28039
27798
  text = accounting.text;
28040
27799
  const outputByteSize = part.kind === "tool_result" ? accounting.byteSize : 0;
28041
27800
  const outputTokenCount = part.kind === "tool_result" ? accounting.tokenCount : 0;
@@ -28131,12 +27890,14 @@ function applyGrownToolResultAccounting(args) {
28131
27890
  updateTagTokenCount2(args.db, args.sessionId, args.aggregate.tagId, tokenCount);
28132
27891
  syncToolAggregateAccounting(args.tagger, args.sessionId, args.aggregate);
28133
27892
  }
28134
- function readAggregateToolAccounting(part, timing, tokenCache, tokenCacheKey) {
27893
+ function readAggregateToolAccounting(part, timing, tokenCache, tokenCacheKey, persisted) {
28135
27894
  const text = part.getText() ?? "";
28136
27895
  const byteSize = getToolPartByteSize(part, text);
28137
- const metadata = part.getToolMetadata();
27896
+ const metadata = part.getToolMetadata({
27897
+ skipInputTokenCount: persisted?.inputTokenCount != null
27898
+ });
28138
27899
  let tokenCount = 0;
28139
- if (part.kind === "tool_result") {
27900
+ if (part.kind === "tool_result" && (!persisted || persisted.tokenCount === null || byteSize > persisted.byteSize)) {
28140
27901
  const tokenStart = timing ? performance.now() : 0;
28141
27902
  tokenCount = getCachedToolPartTokenCount(part, text, tokenCache, tokenCacheKey);
28142
27903
  if (timing)
@@ -28523,6 +28284,12 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
28523
28284
  return any ? "truncated" : "absent";
28524
28285
  },
28525
28286
  prepareDrop: () => !occurrences.some((occ) => occ.part.canRemove?.() === "defer"),
28287
+ prepareReplayDrop: () => {
28288
+ if (complete() && !requiresToolArcSkeleton) {
28289
+ for (const occ of occurrences)
28290
+ occ.part.canRemove?.();
28291
+ }
28292
+ },
28526
28293
  canDrop: () => complete() && !occurrences.some((occ) => occ.part.hasUserAnswer?.()),
28527
28294
  requiresToolArcSkeleton,
28528
28295
  readInput() {
@@ -28866,6 +28633,8 @@ class AutoSearchBusyError extends Error {
28866
28633
  }
28867
28634
  }
28868
28635
  async function searchAutoHint(db, sessionId, projectPath, query, options, entry = new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "./auto-search-worker.ts" : "./auto-search-worker.js", import.meta.url)) {
28636
+ const messageIndexEpoch = getMessageIndexEpoch(sessionId);
28637
+ const messageIndexWasSearchable = isMessageIndexSearchable(sessionId);
28869
28638
  const {
28870
28639
  rerankConfig: _rerankConfig,
28871
28640
  rerankClient: _rerankClient,
@@ -28874,7 +28643,8 @@ async function searchAutoHint(db, sessionId, projectPath, query, options, entry
28874
28643
  captureRerankLanes: _captureRerankLanes,
28875
28644
  ...hintOptions
28876
28645
  } = options;
28877
- return executeAutoSearchWorker(db, sessionId, projectPath, query, { ...hintOptions, explicitSearch: false, rerank: false }, entry, "search");
28646
+ const results = await executeAutoSearchWorker(db, sessionId, projectPath, query, { ...hintOptions, explicitSearch: false, rerank: false }, entry, "search");
28647
+ return messageIndexWasSearchable && isMessageIndexSearchable(sessionId) && getMessageIndexEpoch(sessionId) === messageIndexEpoch ? results : results.filter((result) => result.source !== "message");
28878
28648
  }
28879
28649
  var pendingBackfills = new WeakMap;
28880
28650
  var searchWorkers = new WeakMap;
@@ -31359,7 +31129,8 @@ function tagAttribution(input) {
31359
31129
  if (!cached) {
31360
31130
  removed.length = 0;
31361
31131
  added.length = 0;
31362
- added.push(...input.tags);
31132
+ for (const tag of input.tags)
31133
+ added.push(tag);
31363
31134
  cached = {
31364
31135
  tags: input.tags,
31365
31136
  messageTags: new Map,
@@ -31448,7 +31219,10 @@ function attributeTags(input, arcs, messageIds) {
31448
31219
  exactToolTags,
31449
31220
  orphanTagsByCall,
31450
31221
  boundsByOwner
31451
- } = tagAttribution(input);
31222
+ } = tagAttribution({
31223
+ ...input,
31224
+ tags: attributionProjection(input, arcs, messageIds)
31225
+ });
31452
31226
  const messageIndexById = new Map;
31453
31227
  for (let index = 0;index < messageIds.length; index += 1) {
31454
31228
  const id = input.stableId?.(input.messages[index], index);
@@ -31511,6 +31285,61 @@ function attributeTags(input, arcs, messageIds) {
31511
31285
  }
31512
31286
  return { messageTags, tagsByNumber };
31513
31287
  }
31288
+ var attributionProjections = new WeakMap;
31289
+ function attributionProjection(input, arcs, messageIds) {
31290
+ const owners = new Set(messageIds);
31291
+ const calls = new Set;
31292
+ const numbers = new Set;
31293
+ for (const arc of arcs) {
31294
+ owners.add(arc.ownerId);
31295
+ calls.add(arc.callId);
31296
+ }
31297
+ const notePrefix = (text) => {
31298
+ for (const candidate of [text, stripChannel1ReminderSpans(text)]) {
31299
+ const match = candidate.trimStart().match(TAG_PREFIX);
31300
+ if (match)
31301
+ numbers.add(Number(match[1]));
31302
+ }
31303
+ };
31304
+ for (let index = 0;index < input.messages.length; index++) {
31305
+ const id = input.stableId?.(input.messages[index], index);
31306
+ if (id)
31307
+ owners.add(id);
31308
+ const message = input.messages[index];
31309
+ if (!isRecord5(message))
31310
+ continue;
31311
+ if (typeof message.content === "string")
31312
+ notePrefix(message.content);
31313
+ else if (Array.isArray(message.content)) {
31314
+ for (const part of message.content)
31315
+ if (isRecord5(part) && typeof part.text === "string")
31316
+ notePrefix(part.text);
31317
+ }
31318
+ }
31319
+ const cacheable = input.tagCacheKey !== undefined;
31320
+ const cached = cacheable ? attributionProjections.get(input.tags) : undefined;
31321
+ const content = cacheable ? input.messages.map(safeStableStringify) : undefined;
31322
+ if (cached && cached.messageIds.length === messageIds.length && messageIds.every((id, index) => id === cached.messageIds[index]) && content?.length === cached.content.length && content.every((value, index) => value === cached.content[index]) && owners.size === cached.owners.size && [...owners].every((owner) => cached.owners.has(owner)) && calls.size === cached.calls.size && [...calls].every((call) => cached.calls.has(call)) && numbers.size === cached.numbers.size && [...numbers].every((number) => cached.numbers.has(number)))
31323
+ return cached.projection;
31324
+ const projection = input.tags.filter((tag) => {
31325
+ if (numbers.has(tag.tagNumber))
31326
+ return true;
31327
+ const owner = messageIdForTag(tag);
31328
+ if (owner !== null && owners.has(owner))
31329
+ return true;
31330
+ return tag.type === "tool" && tag.toolOwnerMessageId === null && calls.has(tag.messageId);
31331
+ });
31332
+ if (cacheable && content)
31333
+ attributionProjections.set(input.tags, {
31334
+ messageIds,
31335
+ content,
31336
+ owners,
31337
+ calls,
31338
+ numbers,
31339
+ projection
31340
+ });
31341
+ return projection;
31342
+ }
31514
31343
  var partJsonMemo = new TailHygieneJsonMemo;
31515
31344
  var excludedViews = new WeakMap;
31516
31345
  function excludedDraftForApi(key, value, providerApi) {
@@ -35221,6 +35050,76 @@ function canRemoveNativeToolCall(message, toolCallId) {
35221
35050
  var NATIVE_TOOL_REMOVAL_MARKER = '{"__magic_context_remove_tool_arc__":true}';
35222
35051
 
35223
35052
  // src/native-replay-state-pi.ts
35053
+ var removalBatches = new WeakMap;
35054
+
35055
+ class PiToolRemovalBatchError extends Error {
35056
+ constructor(cause) {
35057
+ super("Native tool removal batch could not be persisted", { cause });
35058
+ }
35059
+ }
35060
+ function withPiToolRemovalBatch(args, edit) {
35061
+ let sessions = removalBatches.get(args.db);
35062
+ const enclosing = sessions?.get(args.sessionId);
35063
+ if (enclosing)
35064
+ return edit(enclosing.flush);
35065
+ if (!sessions) {
35066
+ sessions = new Map;
35067
+ removalBatches.set(args.db, sessions);
35068
+ }
35069
+ let publishing = false;
35070
+ const batch = {
35071
+ saved: args.saved,
35072
+ planned: new Map(args.saved),
35073
+ requested: new Map,
35074
+ pending: new Map,
35075
+ flushed: false,
35076
+ flush() {
35077
+ if (batch.flushed)
35078
+ return;
35079
+ batch.persistPending();
35080
+ batch.flushed = true;
35081
+ },
35082
+ persistPending() {
35083
+ if (publishing || batch.pending.size === 0)
35084
+ return;
35085
+ const connection = args.db;
35086
+ if (connection.inTransaction !== true && connection.isTransaction !== true)
35087
+ throw new Error("Native removal publication requires a caller-owned transaction");
35088
+ try {
35089
+ publishing = true;
35090
+ saveNativeToolInputs(args.db, args.sessionId, batch.pending);
35091
+ batch.pending.clear();
35092
+ } catch (cause) {
35093
+ throw new PiToolRemovalBatchError(cause);
35094
+ } finally {
35095
+ publishing = false;
35096
+ }
35097
+ }
35098
+ };
35099
+ sessions.set(args.sessionId, batch);
35100
+ try {
35101
+ const result = withNativeReplayWriteBarrier(args.db, args.sessionId, batch.persistPending, () => edit(batch.flush));
35102
+ if (batch.requested.size > 0 && !batch.flushed)
35103
+ throw new Error("Native removal markers were not flushed in the caller's transaction");
35104
+ const saved = args.saved;
35105
+ if (saved && batch.requested.size > 0) {
35106
+ const prior = new Map([...batch.requested.keys()].map((id) => [id, saved.get(id)]));
35107
+ args.rollbackObservations?.push(() => {
35108
+ for (const [id, value] of prior) {
35109
+ if (value === undefined)
35110
+ saved.delete(id);
35111
+ else
35112
+ saved.set(id, value);
35113
+ }
35114
+ });
35115
+ for (const [id, marker] of batch.requested)
35116
+ saved.set(id, marker);
35117
+ }
35118
+ return result;
35119
+ } finally {
35120
+ sessions.delete(args.sessionId);
35121
+ }
35122
+ }
35224
35123
  function applyNativeToolInputReplayPi(args, saved) {
35225
35124
  if (saved.size === 0 && (!args.canApply || args.changes.size === 0))
35226
35125
  return 0;
@@ -35332,6 +35231,12 @@ function applyNativeReasoningReplayPi(args, saved) {
35332
35231
  function preparePiToolRemovalMeasurements(args) {
35333
35232
  if (!args.saved || !args.canApply)
35334
35233
  return;
35234
+ const batch = removalBatches.get(args.db)?.get(args.sessionId);
35235
+ if (batch?.saved === args.saved) {
35236
+ for (const callId of args.callIds)
35237
+ authorizePiToolRemoval({ ...args, callId });
35238
+ return;
35239
+ }
35335
35240
  const requested = new Map;
35336
35241
  for (const callId of args.callIds) {
35337
35242
  if (args.saved.get(callId) !== NATIVE_TOOL_REMOVAL_MARKER)
@@ -35347,9 +35252,54 @@ function preparePiToolRemovalMeasurements(args) {
35347
35252
  args.saved.set(callId, marker);
35348
35253
  } catch {}
35349
35254
  }
35255
+ function preparePiToolRemovalChecks(args) {
35256
+ if (!args.db?.inTransaction || args.rows.length === 0)
35257
+ return;
35258
+ const occurrences = new Map;
35259
+ for (const raw of args.messages) {
35260
+ if (!raw || typeof raw !== "object")
35261
+ continue;
35262
+ const message = raw;
35263
+ if (message.role !== "assistant" || !Array.isArray(message.content))
35264
+ continue;
35265
+ for (const rawPart of message.content) {
35266
+ if (!rawPart || typeof rawPart !== "object")
35267
+ continue;
35268
+ const part = rawPart;
35269
+ if (part.type === "toolCall" && typeof part.id === "string")
35270
+ occurrences.set(part.id, (occurrences.get(part.id) ?? 0) + 1);
35271
+ }
35272
+ }
35273
+ const requested = [];
35274
+ for (const row of args.rows) {
35275
+ if (row.callId === null || occurrences.get(row.callId) !== 1)
35276
+ continue;
35277
+ const target = args.targets.get(row.tagNumber);
35278
+ if (target?.requiresToolArcSkeleton || target?.canDrop?.() !== true)
35279
+ continue;
35280
+ if (!target.mutationParts?.some(({ part }) => part !== null && typeof part === "object" && ("kind" in part) && part.kind === "tool_use" && ("id" in part) && part.id === row.callId))
35281
+ continue;
35282
+ requested.push(row.callId);
35283
+ }
35284
+ if (requested.length)
35285
+ args.prepare(requested);
35286
+ }
35350
35287
  function authorizePiToolRemoval(args) {
35351
35288
  if (!args.saved)
35352
35289
  return false;
35290
+ const batch = removalBatches.get(args.db)?.get(args.sessionId);
35291
+ if (batch?.saved === args.saved) {
35292
+ if (batch.planned.get(args.callId) === NATIVE_TOOL_REMOVAL_MARKER)
35293
+ return true;
35294
+ if (!args.canApply)
35295
+ return false;
35296
+ if (batch.flushed)
35297
+ throw new Error("Tool removal requested after lane publication");
35298
+ batch.planned.set(args.callId, NATIVE_TOOL_REMOVAL_MARKER);
35299
+ batch.requested.set(args.callId, NATIVE_TOOL_REMOVAL_MARKER);
35300
+ batch.pending.set(args.callId, NATIVE_TOOL_REMOVAL_MARKER);
35301
+ return true;
35302
+ }
35353
35303
  if (args.saved.get(args.callId) === NATIVE_TOOL_REMOVAL_MARKER)
35354
35304
  return true;
35355
35305
  if (!args.canApply)
@@ -35406,6 +35356,57 @@ function isSentinelPart(part) {
35406
35356
  return p.type === "text" && typeof p.text === "string" && (p.text === "" || p.text === WHOLE_MESSAGE_PLACEHOLDER_TEXT);
35407
35357
  }
35408
35358
 
35359
+ // src/pass-tag-projection-pi.ts
35360
+ function projectPiReplayDrops(transcript, metadata) {
35361
+ const owners = new Set;
35362
+ const addresses = new Set;
35363
+ const calls = new Set;
35364
+ const prefixes = new Set;
35365
+ for (const message of transcript.messages) {
35366
+ owners.add(message.info.id ?? "");
35367
+ let ordinal = 0;
35368
+ for (const part of message.parts) {
35369
+ if (part.kind === "text") {
35370
+ addresses.add(`${message.info.id}:p${ordinal++}`);
35371
+ const prefix = /^§(\d+)§\s/.exec(part.getText() ?? "");
35372
+ if (prefix)
35373
+ prefixes.add(Number(prefix[1]));
35374
+ } else if ((part.kind === "tool_use" || part.kind === "tool_result") && part.id)
35375
+ calls.add(part.id);
35376
+ }
35377
+ }
35378
+ const numbers = new Set;
35379
+ for (const tag of metadata) {
35380
+ if (tag.status !== "dropped")
35381
+ continue;
35382
+ if (prefixes.has(tag.tagNumber) || (tag.type === "tool" ? calls.has(tag.messageId) && (tag.toolOwnerMessageId === null || tag.toolOwnerMessageId === "" || owners.has(tag.toolOwnerMessageId)) : addresses.has(tag.messageId)))
35383
+ numbers.add(tag.tagNumber);
35384
+ }
35385
+ return metadata.filter((tag) => tag.status === "dropped" && numbers.has(tag.tagNumber));
35386
+ }
35387
+ function protectedPiPassTagNumbers(rows, floor, toolsRatio = 1) {
35388
+ if (!(toolsRatio >= 0) || rows.some((row) => !Number.isFinite(row.tagNumber)))
35389
+ return computeProtectionWindow(rows, floor, toolsRatio).protectedTagNumbers;
35390
+ const numbers = [];
35391
+ let group;
35392
+ let groups = 0;
35393
+ let mass = 0;
35394
+ for (let index = rows.length - 1;index >= 0; index--) {
35395
+ const row = rows[index];
35396
+ if (row?.type !== "tool")
35397
+ continue;
35398
+ if (row.tagNumber !== group) {
35399
+ if (groups >= 3 && Math.ceil(mass * toolsRatio) >= floor)
35400
+ break;
35401
+ group = row.tagNumber;
35402
+ groups++;
35403
+ numbers.push(row.tagNumber);
35404
+ }
35405
+ mass += rowWindowMass(row);
35406
+ }
35407
+ return new Set(numbers.reverse());
35408
+ }
35409
+
35409
35410
  // src/pi-append-compaction.ts
35410
35411
  var loggedIncompatibleHost = false;
35411
35412
  var failedWrites2 = new WeakMap;
@@ -36562,23 +36563,113 @@ function piMatchesChatImages(content, urls) {
36562
36563
  return true;
36563
36564
  }
36564
36565
 
36565
- // src/pi-dispatch-image-budget.ts
36566
+ // src/pi-dispatch-date-reminder.ts
36566
36567
  function object8(value) {
36567
36568
  return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
36568
36569
  }
36570
+ function piDateReminderText(value, cwd) {
36571
+ if (typeof value !== "string")
36572
+ return false;
36573
+ const match = /^<system-reminder>\nToday: (\d{4}-\d{2}-\d{2}); current working directory: '([^\r\n<>§]+)'\. Do not repeat this information in your reply\.\n<\/system-reminder>$/u.exec(value);
36574
+ if (!match)
36575
+ return false;
36576
+ const [, date, path] = match;
36577
+ if ([...path].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127))
36578
+ return false;
36579
+ const parsed = new Date(`${date}T00:00:00Z`);
36580
+ if (!Number.isFinite(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== date)
36581
+ return false;
36582
+ if (!/^(?:\/|[A-Za-z]:\/)/u.test(path) || path.includes("\\"))
36583
+ return false;
36584
+ return cwd === undefined || path === cwd.replace(/\\/gu, "/");
36585
+ }
36586
+ function piDateReminderWireText(content, cwd) {
36587
+ if (typeof content === "string")
36588
+ return piDateReminderText(content, cwd) ? content : undefined;
36589
+ if (!Array.isArray(content) || content.length !== 1)
36590
+ return;
36591
+ const block = object8(content[0]);
36592
+ const cache = object8(block?.cache_control);
36593
+ if (block?.type !== "text" || !cache || cache.type !== "ephemeral" || Object.keys(block).some((key) => !["type", "text", "cache_control"].includes(key)) || Object.keys(cache).some((key) => !["type", "ttl", "scope"].includes(key)) || cache.ttl !== undefined && cache.ttl !== "5m" && cache.ttl !== "1h" || cache.scope !== undefined && cache.scope !== "global")
36594
+ return;
36595
+ return piDateReminderText(block.text, cwd) ? block.text : undefined;
36596
+ }
36597
+ var PI_DATE_REMINDER_APIS = new Set([
36598
+ "anthropic-messages",
36599
+ "openai-completions",
36600
+ "openai-responses",
36601
+ "azure-openai-responses",
36602
+ "openai-codex-responses",
36603
+ "bedrock-converse-stream",
36604
+ "google-generative-ai",
36605
+ "google-vertex",
36606
+ "google-gemini-cli",
36607
+ "ollama-chat"
36608
+ ]);
36609
+ function singleText(value, type) {
36610
+ if (!Array.isArray(value) || value.length !== 1)
36611
+ return;
36612
+ const part = object8(value[0]);
36613
+ return part && (type === undefined ? Object.keys(part).length === 1 : part.type === type && Object.keys(part).length === 2) ? part.text : undefined;
36614
+ }
36615
+ function piWithoutDateReminders(payload, api, cwd, developerRole, includesPreparedFirstUser) {
36616
+ const body = object8(payload);
36617
+ if (!body)
36618
+ return;
36619
+ const google = api.startsWith("google-");
36620
+ const envelope = google ? object8(body.request) ?? body : body;
36621
+ const field = google ? "contents" : api.endsWith("responses") ? "input" : "messages";
36622
+ const messages = envelope[field];
36623
+ if (!Array.isArray(messages))
36624
+ return;
36625
+ let firstUser = false;
36626
+ let removed = false;
36627
+ const kept = [];
36628
+ for (const value of messages) {
36629
+ const row = object8(value);
36630
+ if (!row)
36631
+ return;
36632
+ const text = google ? singleText(row.parts) : api === "bedrock-converse-stream" ? singleText(row.content) : api.endsWith("responses") ? singleText(row.content, "input_text") ?? (api === "openai-codex-responses" ? row.content : undefined) : row.content;
36633
+ if (piDateReminderText(text, cwd)) {
36634
+ const keys = google ? ["role", "parts"] : api.endsWith("responses") ? ["role", "content", "type"] : ["role", "content"];
36635
+ const role = api === "ollama-chat" ? "system" : api === "openai-completions" && developerRole ? "developer" : "user";
36636
+ if (!firstUser || row.role !== role || Object.keys(row).some((key) => !keys.includes(key)) || row.type !== undefined && row.type !== "message")
36637
+ return;
36638
+ if (!removed) {
36639
+ const prefix = { ...envelope, [field]: kept };
36640
+ if (!includesPreparedFirstUser(google && body.request !== undefined ? { ...body, request: prefix } : prefix))
36641
+ return;
36642
+ }
36643
+ removed = true;
36644
+ continue;
36645
+ }
36646
+ if (row.role === "user" && (typeof row.content === "string" || Array.isArray(row.content) && row.content.some((part) => object8(part)?.type === "input_text" || object8(part)?.type === "text" || typeof object8(part)?.text === "string") || Array.isArray(row.parts) && row.parts.some((part) => typeof object8(part)?.text === "string")))
36647
+ firstUser = true;
36648
+ kept.push(value);
36649
+ }
36650
+ if (!removed)
36651
+ return;
36652
+ const filtered = { ...envelope, [field]: kept };
36653
+ return google && body.request !== undefined ? { ...body, request: filtered } : filtered;
36654
+ }
36655
+
36656
+ // src/pi-dispatch-image-budget.ts
36657
+ function object9(value) {
36658
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
36659
+ }
36569
36660
  function piImageBudgetPlan(model) {
36570
- if (!model?.input?.includes("image") || object8(model.compat)?.stripImageInput === true)
36661
+ if (!model?.input?.includes("image") || object9(model.compat)?.stripImageInput === true)
36571
36662
  return;
36572
36663
  return {
36573
36664
  count: 0,
36574
36665
  api: model.api,
36575
36666
  rows: new Map,
36576
- hoistToolImages: model.api?.startsWith("google-") === true && object8(model.compat)?.multimodalFunctionResponse !== true || model.api === "bedrock-converse-stream" && model.requiresToolResultImageHoisting === true,
36667
+ hoistToolImages: model.api?.startsWith("google-") === true && object9(model.compat)?.multimodalFunctionResponse !== true || model.api === "bedrock-converse-stream" && model.requiresToolResultImageHoisting === true,
36577
36668
  hoistErrorImages: model.api === "anthropic-messages" || model.api === "bedrock-converse-stream"
36578
36669
  };
36579
36670
  }
36580
36671
  function inputImage(block, api) {
36581
- const file = object8(block.providerFile);
36672
+ const file = object9(block.providerFile);
36582
36673
  if (api === "ollama-chat")
36583
36674
  return { kind: "bytes", value: String(block.data ?? "") };
36584
36675
  if ((api?.endsWith("responses") && file?.provider === "openai" || api === "anthropic-messages" && file?.provider === "anthropic") && typeof file?.id === "string")
@@ -36598,7 +36689,7 @@ function piRecordImages(plan, row, source) {
36598
36689
  return;
36599
36690
  const images = [];
36600
36691
  for (const value of source.content) {
36601
- const block = object8(value);
36692
+ const block = object9(value);
36602
36693
  if (block?.type === "image")
36603
36694
  images.push(inputImage(block, plan.api));
36604
36695
  }
@@ -36624,20 +36715,20 @@ function piWireImages(content, ollamaImages) {
36624
36715
  return [];
36625
36716
  const images = [];
36626
36717
  for (const value of content) {
36627
- const block = object8(value);
36718
+ const block = object9(value);
36628
36719
  if (!block)
36629
36720
  continue;
36630
- const source = object8(block.source);
36631
- const inline = object8(block.inlineData);
36632
- const file = object8(block.fileData);
36633
- const bedrock = object8(block.image);
36721
+ const source = object9(block.source);
36722
+ const inline = object9(block.inlineData);
36723
+ const file = object9(block.fileData);
36724
+ const bedrock = object9(block.image);
36634
36725
  if (block.type === "image_url" || block.type === "input_image") {
36635
36726
  if (typeof block.file_id === "string")
36636
36727
  images.push({ kind: "file", value: block.file_id });
36637
36728
  else
36638
36729
  images.push({
36639
36730
  kind: "url",
36640
- value: String(typeof block.image_url === "string" ? block.image_url : object8(block.image_url)?.url)
36731
+ value: String(typeof block.image_url === "string" ? block.image_url : object9(block.image_url)?.url)
36641
36732
  });
36642
36733
  } else if (block.type === "image") {
36643
36734
  if (source?.type === "file")
@@ -36661,7 +36752,7 @@ function piWireImages(content, ollamaImages) {
36661
36752
  else if (bedrock)
36662
36753
  images.push({
36663
36754
  kind: "data",
36664
- value: String(object8(bedrock.source)?.bytes),
36755
+ value: String(object9(bedrock.source)?.bytes),
36665
36756
  mime: `image/${bedrock.format}`
36666
36757
  });
36667
36758
  }
@@ -36683,11 +36774,11 @@ function piMatchesImages(actual, expected) {
36683
36774
  return true;
36684
36775
  }
36685
36776
  function piWireImageCount(payload) {
36686
- const body = object8(payload);
36777
+ const body = object9(payload);
36687
36778
  const visit = (value) => {
36688
36779
  if (Array.isArray(value))
36689
36780
  return value.reduce((n, item) => n + visit(item), 0);
36690
- const block = object8(value);
36781
+ const block = object9(value);
36691
36782
  if (!block)
36692
36783
  return 0;
36693
36784
  if (["image", "image_url", "input_image"].includes(String(block.type)) || block.inlineData || block.fileData || block.image)
@@ -36701,12 +36792,12 @@ function piWireImageCount(payload) {
36701
36792
  block.response
36702
36793
  ].reduce((n, item) => n + visit(item), Array.isArray(block.images) ? block.images.length : 0);
36703
36794
  };
36704
- return visit(body?.messages ?? body?.input ?? body?.contents ?? object8(body?.request)?.contents);
36795
+ return visit(body?.messages ?? body?.input ?? body?.contents ?? object9(body?.request)?.contents);
36705
36796
  }
36706
36797
 
36707
36798
  // src/pi-dispatch-responses-history.ts
36708
36799
  var MAX_TEXT_UNITS = 32 * 1024 * 1024;
36709
- function object9(value) {
36800
+ function object10(value) {
36710
36801
  return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
36711
36802
  }
36712
36803
  function wellFormed2(text) {
@@ -36721,7 +36812,7 @@ function textIdentity2(text, phase) {
36721
36812
  function signaturePhase(block) {
36722
36813
  try {
36723
36814
  if (typeof block.textSignature === "string") {
36724
- const signature = object9(JSON.parse(block.textSignature));
36815
+ const signature = object10(JSON.parse(block.textSignature));
36725
36816
  if (signature?.v === 1 && typeof signature.id === "string")
36726
36817
  return signature.phase;
36727
36818
  }
@@ -36743,19 +36834,19 @@ ${wellFormed2(text)}
36743
36834
  function coldReplayable(items) {
36744
36835
  let reasoning = false;
36745
36836
  for (const value of items) {
36746
- const item = object9(value);
36837
+ const item = object10(value);
36747
36838
  if (typeof item?.encrypted_content === "string")
36748
36839
  return false;
36749
36840
  if (item?.type !== "reasoning")
36750
36841
  continue;
36751
- if (!Array.isArray(item.content) || !item.content.some((part) => object9(part)?.type === "reasoning_text"))
36842
+ if (!Array.isArray(item.content) || !item.content.some((part) => object10(part)?.type === "reasoning_text"))
36752
36843
  return false;
36753
36844
  reasoning = true;
36754
36845
  }
36755
36846
  return reasoning;
36756
36847
  }
36757
36848
  function piResponsesAssistantTexts(value, model, host, alternatives) {
36758
- const message = object9(value);
36849
+ const message = object10(value);
36759
36850
  if (!message || !Array.isArray(message.content))
36760
36851
  return;
36761
36852
  if (piOmitsTruncatedAssistant(message))
@@ -36765,7 +36856,7 @@ function piResponsesAssistantTexts(value, model, host, alternatives) {
36765
36856
  const sameModel = model !== undefined && typeof model.api === "string" && typeof model.id === "string" && typeof model.provider === "string" && message.api === model.api && message.model === model.id && message.provider === model.provider;
36766
36857
  let units = 0;
36767
36858
  for (const value of message.content) {
36768
- const block = object9(value);
36859
+ const block = object10(value);
36769
36860
  if (block?.type === "toolCall")
36770
36861
  continue;
36771
36862
  if (block?.type === "thinking") {
@@ -36775,7 +36866,7 @@ function piResponsesAssistantTexts(value, model, host, alternatives) {
36775
36866
  return;
36776
36867
  if (!block.thinking.trim())
36777
36868
  continue;
36778
- const compat = object9(model.compat);
36869
+ const compat = object10(model.compat);
36779
36870
  if (block.summary === false && (compat?.requiresReasoningContentForToolCalls === true || compat?.requiresReasoningContentForAllAssistantTurns === true))
36780
36871
  return;
36781
36872
  const text = demotedThinking(block.thinking, model);
@@ -36795,7 +36886,7 @@ function piResponsesAssistantTexts(value, model, host, alternatives) {
36795
36886
  texts.push(textIdentity2(wellFormed2(block.text), sameModel ? signaturePhase(block) : undefined));
36796
36887
  blocks.push(block);
36797
36888
  }
36798
- const payload = object9(message.providerPayload);
36889
+ const payload = object10(message.providerPayload);
36799
36890
  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))
36800
36891
  return texts;
36801
36892
  const replay = [];
@@ -36809,7 +36900,7 @@ function piResponsesAssistantTexts(value, model, host, alternatives) {
36809
36900
  let unsigned = false;
36810
36901
  let rewrittenText = false;
36811
36902
  for (const value of payload.items) {
36812
- const item = object9(value);
36903
+ const item = object10(value);
36813
36904
  if (item?.type === "reasoning")
36814
36905
  continue;
36815
36906
  if (item?.type === "function_call" || item?.type === "custom_tool_call") {
@@ -36820,14 +36911,14 @@ function piResponsesAssistantTexts(value, model, host, alternatives) {
36820
36911
  return texts;
36821
36912
  const itemTexts = [];
36822
36913
  for (const value of item.content) {
36823
- const part = object9(value);
36914
+ const part = object10(value);
36824
36915
  const block = blocks[bound];
36825
36916
  if (!block || part?.type !== "output_text" || typeof part.text !== "string")
36826
36917
  return texts;
36827
36918
  let signature;
36828
36919
  try {
36829
36920
  if (typeof block.textSignature === "string")
36830
- signature = object9(JSON.parse(block.textSignature));
36921
+ signature = object10(JSON.parse(block.textSignature));
36831
36922
  } catch {
36832
36923
  return texts;
36833
36924
  }
@@ -36837,7 +36928,7 @@ function piResponsesAssistantTexts(value, model, host, alternatives) {
36837
36928
  if (!allowUnsigned || "textSignature" in block || stripped !== block.text.replace(/^§\d+§ /u, ""))
36838
36929
  return texts;
36839
36930
  unsigned = true;
36840
- rewrittenText ||= part.text !== stripped && part.text !== block.text;
36931
+ rewrittenText ||= part.text !== stripped;
36841
36932
  }
36842
36933
  bound++;
36843
36934
  itemTexts.push(part.text);
@@ -36866,7 +36957,7 @@ function piResponsesWireTexts(value, phase) {
36866
36957
  const texts = [];
36867
36958
  let units = 0;
36868
36959
  for (const partValue of value) {
36869
- const part = object9(partValue);
36960
+ const part = object10(partValue);
36870
36961
  if (part?.type !== "output_text" || typeof part.text !== "string")
36871
36962
  return;
36872
36963
  units += part.text.length;
@@ -36878,6 +36969,7 @@ function piResponsesWireTexts(value, phase) {
36878
36969
  }
36879
36970
 
36880
36971
  // src/pi-dispatch-structure.ts
36972
+ var dateReminderPlans = new WeakMap;
36881
36973
  var MAX_MESSAGES = 1e5;
36882
36974
  var ORPHAN_NOTE = Symbol("prepared orphan tool result");
36883
36975
  var ANTHROPIC_CONTINUE_PAD_TEXT = "Continue.";
@@ -36904,11 +36996,11 @@ var TRANSFORM_MESSAGES_APIS = new Set([
36904
36996
  "devin-agent",
36905
36997
  "apple-foundation-models"
36906
36998
  ]);
36907
- function object10(value) {
36999
+ function object11(value) {
36908
37000
  return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
36909
37001
  }
36910
37002
  function messageStructure(value) {
36911
- const message = object10(value);
37003
+ const message = object11(value);
36912
37004
  if (!message)
36913
37005
  return;
36914
37006
  const role = [
@@ -36937,7 +37029,7 @@ function messageStructure(value) {
36937
37029
  }
36938
37030
  if (role === "assistant" && Array.isArray(message.content)) {
36939
37031
  for (const value of message.content) {
36940
- const block = object10(value);
37032
+ const block = object11(value);
36941
37033
  if (block?.type !== "toolCall" && block?.type !== "tool_use")
36942
37034
  continue;
36943
37035
  if (typeof block.id !== "string")
@@ -36953,7 +37045,7 @@ function windowCalls(message) {
36953
37045
  if (!Array.isArray(message.content))
36954
37046
  return [];
36955
37047
  return message.content.flatMap((value) => {
36956
- const block = object10(value);
37048
+ const block = object11(value);
36957
37049
  return block?.type === "toolCall" && typeof block.id === "string" ? [
36958
37050
  {
36959
37051
  id: block.id,
@@ -36963,7 +37055,7 @@ function windowCalls(message) {
36963
37055
  });
36964
37056
  }
36965
37057
  function duplicateSuffix(model) {
36966
- const compat = object10(model?.compat);
37058
+ const compat = object11(model?.compat);
36967
37059
  if (model?.api === "openai-completions") {
36968
37060
  if (compat?.requiresMistralToolIds === true)
36969
37061
  return { prefix: "dup", max: 9 };
@@ -36980,7 +37072,7 @@ function appendDuplicateSuffix(id, suffix, max) {
36980
37072
  }
36981
37073
  function projectMissingToolResults(messages, model, host = "omp") {
36982
37074
  const input = messages.filter((value) => {
36983
- const message = object10(value);
37075
+ const message = object11(value);
36984
37076
  return !((message?.role === "bashExecution" || message?.role === "pythonExecution") && message.excludeFromContext === true);
36985
37077
  });
36986
37078
  if (host === "pi")
@@ -36995,7 +37087,7 @@ function projectMissingToolResults(messages, model, host = "omp") {
36995
37087
  const realResults = new Map;
36996
37088
  const validToolUseIds = new Set;
36997
37089
  const deduplicated = input.map((value, index) => {
36998
- const message = object10(value);
37090
+ const message = object11(value);
36999
37091
  if (message?.role === "toolResult" && typeof message.toolCallId === "string") {
37000
37092
  let key = pairingId(message.toolCallId);
37001
37093
  let output = value;
@@ -37022,7 +37114,7 @@ function projectMissingToolResults(messages, model, host = "omp") {
37022
37114
  const touched = new Set;
37023
37115
  let changed = false;
37024
37116
  const content = message.content.map((part) => {
37025
- const block = object10(part);
37117
+ const block = object11(part);
37026
37118
  if (block?.type !== "toolCall" || typeof block.id !== "string")
37027
37119
  return part;
37028
37120
  const key = pairingId(block.id);
@@ -37101,7 +37193,7 @@ function projectMissingToolResults(messages, model, host = "omp") {
37101
37193
  };
37102
37194
  for (let index = 0;index < deduplicated.length; index++) {
37103
37195
  const value = deduplicated[index];
37104
- const message = object10(value);
37196
+ const message = object11(value);
37105
37197
  if (message?.role === "assistant") {
37106
37198
  flush(message.timestamp);
37107
37199
  if (piOmitsTruncatedAssistant(message))
@@ -37142,7 +37234,7 @@ function projectMissingToolResults(messages, model, host = "omp") {
37142
37234
  if (pending.some((call) => !answered.has(pairingId(call.id))) || aborted.size > 0)
37143
37235
  continue;
37144
37236
  const parts = message.content.flatMap((value) => {
37145
- const part = object10(value);
37237
+ const part = object11(value);
37146
37238
  return part?.type === "text" && typeof part.text === "string" && part.text.trim() ? [part.text] : [];
37147
37239
  });
37148
37240
  if (!parts.length)
@@ -37170,11 +37262,11 @@ function projectUnmodeledToolResults(messages) {
37170
37262
  return pipe > 0 ? id.slice(0, pipe) : id;
37171
37263
  };
37172
37264
  for (const value of messages) {
37173
- const message = object10(value);
37265
+ const message = object11(value);
37174
37266
  if (message?.role !== "assistant" || !Array.isArray(message.content))
37175
37267
  continue;
37176
37268
  for (const value of message.content) {
37177
- const block = object10(value);
37269
+ const block = object11(value);
37178
37270
  if (block?.type !== "toolCall" || typeof block.id !== "string")
37179
37271
  continue;
37180
37272
  if ([
@@ -37190,7 +37282,7 @@ function projectUnmodeledToolResults(messages) {
37190
37282
  const pairingId = (id) => !opaqueIds.has(id) && responsesComponents.has(component(id)) ? component(id) : id;
37191
37283
  const lastResult = new Map;
37192
37284
  messages.forEach((value, index) => {
37193
- const message = object10(value);
37285
+ const message = object11(value);
37194
37286
  if (message?.role === "toolResult" && typeof message.toolCallId === "string")
37195
37287
  lastResult.set(pairingId(message.toolCallId), index);
37196
37288
  });
@@ -37221,7 +37313,7 @@ function projectUnmodeledToolResults(messages) {
37221
37313
  };
37222
37314
  for (let index = 0;index < messages.length; index++) {
37223
37315
  const value = messages[index];
37224
- const message = object10(value);
37316
+ const message = object11(value);
37225
37317
  if ((message?.role === "bashExecution" || message?.role === "pythonExecution") && message.excludeFromContext === true)
37226
37318
  continue;
37227
37319
  if (message?.role !== "toolResult")
@@ -37263,7 +37355,7 @@ function projectPiToolResults(messages) {
37263
37355
  held.length = 0;
37264
37356
  };
37265
37357
  for (const value of messages) {
37266
- const message = object10(value);
37358
+ const message = object11(value);
37267
37359
  const role = message?.role;
37268
37360
  if (role === "assistant") {
37269
37361
  close(message?.timestamp);
@@ -37291,23 +37383,26 @@ function projectPiToolResults(messages) {
37291
37383
  close();
37292
37384
  return projected;
37293
37385
  }
37294
- function preparePiDispatch(messages, model, omp) {
37386
+ function preparePiDispatch(messages, model, omp, cwd) {
37295
37387
  let output = messages;
37296
37388
  const structure = buildPiPreparedStructure(messages, model, omp ? (index, source) => {
37297
- if (object10(source.providerPayload)?.type !== "openaiResponsesHistory")
37389
+ if (object11(source.providerPayload)?.type !== "openaiResponsesHistory")
37298
37390
  return;
37299
37391
  if (output === messages)
37300
37392
  output = messages.slice();
37301
37393
  const { providerPayload: _payload, ...copy } = source;
37302
37394
  output[index] = copy;
37303
37395
  } : undefined, omp ? "omp" : "pi");
37396
+ const reminders = structure && dateReminderPlans.get(structure);
37397
+ if (reminders)
37398
+ reminders.cwd = cwd;
37304
37399
  return { messages: output, structure };
37305
37400
  }
37306
37401
  function buildPiPreparedStructure(messages, model, prepareUser, host = "omp") {
37307
37402
  if (!messages.length || messages.length > MAX_MESSAGES)
37308
37403
  return;
37309
37404
  for (let index = 0;index < messages.length; index++) {
37310
- const source = object10(messages[index]);
37405
+ const source = object11(messages[index]);
37311
37406
  if (source?.role === "user" || source?.role === "compactionSummary")
37312
37407
  prepareUser?.(index, source);
37313
37408
  }
@@ -37319,11 +37414,12 @@ function buildPiPreparedStructure(messages, model, prepareUser, host = "omp") {
37319
37414
  const toolIds = new Map;
37320
37415
  const responsesToolIds = new Map;
37321
37416
  const byIndex = new Map;
37417
+ let firstUserRow;
37322
37418
  const imageBudget = piImageBudgetPlan(model);
37323
37419
  let valid = true;
37324
37420
  for (let index = 0;index < projectedMessages.length; index++) {
37325
37421
  const message = projectedMessages[index];
37326
- const source = object10(message);
37422
+ const source = object11(message);
37327
37423
  if (rows.length === 0 && (source?.role === "system" || source?.role === "developer"))
37328
37424
  continue;
37329
37425
  if ((source?.role === "bashExecution" || source?.role === "pythonExecution") && source.excludeFromContext === true)
@@ -37347,7 +37443,7 @@ function buildPiPreparedStructure(messages, model, prepareUser, host = "omp") {
37347
37443
  "azure-openai-responses",
37348
37444
  "openai-codex-responses"
37349
37445
  ].includes(model?.api ?? "") && (source?.role === "user" || source?.role === "developer") && (typeof source.content === "string" ? !source.content.trim() : Array.isArray(source.content) && !source.content.some((value) => {
37350
- const block = object10(value);
37446
+ const block = object11(value);
37351
37447
  return block?.type === "image" || block?.type === "text" && typeof block.text === "string" && block.text.trim();
37352
37448
  })))
37353
37449
  continue;
@@ -37379,6 +37475,8 @@ function buildPiPreparedStructure(messages, model, prepareUser, host = "omp") {
37379
37475
  row.wireResults = row.results.map((id) => toolIds.has(id) ? toolIds.get(id) : responsesToolIds.get(id.split("|", 1)[0]));
37380
37476
  }
37381
37477
  rows.push(row);
37478
+ if (source?.role === "user")
37479
+ firstUserRow ??= row;
37382
37480
  byIndex.set(index, row);
37383
37481
  piRecordImages(imageBudget, row, source);
37384
37482
  }
@@ -37389,12 +37487,12 @@ function buildPiPreparedStructure(messages, model, prepareUser, host = "omp") {
37389
37487
  const positionedRows = [...byIndex];
37390
37488
  for (let position = positionedRows.length - 1;position >= 0; position--) {
37391
37489
  const [index, row] = positionedRows[position];
37392
- const source = object10(projectedMessages[index]);
37490
+ const source = object11(projectedMessages[index]);
37393
37491
  if (!source)
37394
37492
  return;
37395
37493
  const content = source.content;
37396
37494
  const parts = typeof content === "string" ? [{ type: "text", text: content }] : content;
37397
- const textOnly = Array.isArray(parts) && parts.every((part) => object10(part)?.type === "text" && typeof object10(part)?.text === "string");
37495
+ const textOnly = Array.isArray(parts) && parts.every((part) => object11(part)?.type === "text" && typeof object11(part)?.text === "string");
37398
37496
  const systemTexts = () => {
37399
37497
  const texts = parts.map((part) => part.text);
37400
37498
  return model?.api === "anthropic-messages" ? texts.filter((text) => text.trim()).map((text) => new TextDecoder().decode(new TextEncoder().encode(text))) : texts;
@@ -37402,7 +37500,7 @@ function buildPiPreparedStructure(messages, model, prepareUser, host = "omp") {
37402
37500
  if (piIsDeveloperHistory(source) && source.attribution !== "user") {
37403
37501
  const previous = rows[position - 1];
37404
37502
  const next = rows[position + 1];
37405
- const anthropicPromotable = model?.api === "anthropic-messages" && object10(model.compat)?.supportsMidConversationSystem === true && textOnly;
37503
+ const anthropicPromotable = model?.api === "anthropic-messages" && object11(model.compat)?.supportsMidConversationSystem === true && textOnly;
37406
37504
  if (anthropicPromotable)
37407
37505
  promotable.set(row, systemTexts());
37408
37506
  if (model?.api === "ollama-chat" || anthropicPromotable && (previous?.role === "user" || previous?.role === "toolResult") && (!next || next.role === "assistant"))
@@ -37493,7 +37591,7 @@ function buildPiPreparedStructure(messages, model, prepareUser, host = "omp") {
37493
37591
  }
37494
37592
  return [row];
37495
37593
  });
37496
- return {
37594
+ const prepared = {
37497
37595
  messages: rows,
37498
37596
  ...imageBudget?.count ? { imageBudget } : {},
37499
37597
  ...responsesApi && !responsesMessages ? { structuralSkipReason: "Responses history transform is not modeled" } : model?.api === "openai-completions" && !chatMessages ? { structuralSkipReason: "Chat history transform is not modeled" } : {},
@@ -37504,9 +37602,17 @@ function buildPiPreparedStructure(messages, model, prepareUser, host = "omp") {
37504
37602
  ...modelsContinuePad ? { anthropicContinuePad: true } : {},
37505
37603
  ...modelsContinuePad && baseRows.some((row) => row.optionalThinking) ? { anthropicOptional: { rows: baseRows, promotable } } : {},
37506
37604
  ...model?.api?.startsWith("google-") ? {
37507
- googleFunctionIds: object10(model.compat)?.supportsFunctionPartId === true
37605
+ googleFunctionIds: object11(model.compat)?.supportsFunctionPartId === true
37508
37606
  } : {}
37509
37607
  };
37608
+ if (host === "omp" && PI_DATE_REMINDER_APIS.has(model?.api ?? ""))
37609
+ dateReminderPlans.set(prepared, {
37610
+ ...modelsContinuePad ? { plan: { rows: baseRows, promotable } } : {},
37611
+ firstUser: firstUserRow ? baseRows.indexOf(firstUserRow) : -1,
37612
+ midConversationSystem: object11(model?.compat)?.supportsMidConversationSystem === true,
37613
+ developerRole: object11(model?.compat)?.supportsDeveloperRole === true
37614
+ });
37615
+ return prepared;
37510
37616
  }
37511
37617
  function responsesLane(api) {
37512
37618
  return [
@@ -37516,7 +37622,7 @@ function responsesLane(api) {
37516
37622
  ].includes(api ?? "");
37517
37623
  }
37518
37624
  function payloadStructure(payload, ollama = false, responsesItems = false, imageProjection = false) {
37519
- const body = object10(payload);
37625
+ const body = object11(payload);
37520
37626
  if (!body)
37521
37627
  return;
37522
37628
  const google = piGoogleConversation(payload);
@@ -37531,12 +37637,12 @@ function payloadStructure(payload, ollama = false, responsesItems = false, image
37531
37637
  return;
37532
37638
  const rows = [];
37533
37639
  for (const value of messages) {
37534
- const message = object10(value);
37640
+ const message = object11(value);
37535
37641
  if (!message)
37536
37642
  return;
37537
37643
  if (rows.length === 0 && (message.role === "system" || message.role === "developer"))
37538
37644
  continue;
37539
- if (message.role === "system" && Array.isArray(message.content) && message.content.every((block) => ["tool_addition", "tool_removal"].includes(String(object10(block)?.type))))
37645
+ if (message.role === "system" && Array.isArray(message.content) && message.content.every((block) => ["tool_addition", "tool_removal"].includes(String(object11(block)?.type))))
37540
37646
  continue;
37541
37647
  if (responses && message.type === "reasoning")
37542
37648
  continue;
@@ -37593,7 +37699,7 @@ function payloadStructure(payload, ollama = false, responsesItems = false, image
37593
37699
  continue;
37594
37700
  }
37595
37701
  if (message.role === "user" && Array.isArray(message.content)) {
37596
- const results = message.content.filter((block) => object10(block)?.type === "tool_result" || bedrock && object10(block)?.toolResult);
37702
+ const results = message.content.filter((block) => object11(block)?.type === "tool_result" || bedrock && object11(block)?.toolResult);
37597
37703
  if (results.length) {
37598
37704
  for (const block of results) {
37599
37705
  const id = bedrock ? block.toolResult?.toolUseId : block.tool_use_id;
@@ -37640,11 +37746,11 @@ function payloadStructure(payload, ollama = false, responsesItems = false, image
37640
37746
  }
37641
37747
  if (Array.isArray(message.tool_calls)) {
37642
37748
  for (const call of message.tool_calls) {
37643
- const source = object10(call);
37749
+ const source = object11(call);
37644
37750
  if (!source)
37645
37751
  return;
37646
37752
  if (source.id === undefined && ollama) {
37647
- const fn = object10(source.function);
37753
+ const fn = object11(source.function);
37648
37754
  if (typeof fn?.name !== "string")
37649
37755
  return;
37650
37756
  row.calls.push("");
@@ -37680,7 +37786,7 @@ function googleStructure(contents, imageProjection = false) {
37680
37786
  return;
37681
37787
  const rows = [];
37682
37788
  for (const value of contents) {
37683
- const message = object10(value);
37789
+ const message = object11(value);
37684
37790
  if (!message || !Array.isArray(message.parts))
37685
37791
  return;
37686
37792
  if (message.role !== "user" && message.role !== "model")
@@ -37695,11 +37801,11 @@ function googleStructure(contents, imageProjection = false) {
37695
37801
  };
37696
37802
  const results = [];
37697
37803
  for (const value of message.parts) {
37698
- const part = object10(value);
37804
+ const part = object11(value);
37699
37805
  if (!part)
37700
37806
  return;
37701
37807
  if (part.functionCall) {
37702
- const call = object10(part.functionCall);
37808
+ const call = object11(part.functionCall);
37703
37809
  if (row.role !== "assistant" || typeof call?.name !== "string" || call.id !== undefined && typeof call.id !== "string")
37704
37810
  return;
37705
37811
  row.calls.push(call.id ?? "");
@@ -37707,7 +37813,7 @@ function googleStructure(contents, imageProjection = false) {
37707
37813
  row.callNames.push(call.name);
37708
37814
  }
37709
37815
  if (part.functionResponse) {
37710
- const result = object10(part.functionResponse);
37816
+ const result = object11(part.functionResponse);
37711
37817
  if (row.role !== "user" || typeof result?.name !== "string" || result.id !== undefined && typeof result.id !== "string")
37712
37818
  return;
37713
37819
  results.push({
@@ -37741,11 +37847,11 @@ function matchesUserText(content, text, api, responses, googleOrBedrock) {
37741
37847
  if (responses || googleOrBedrock) {
37742
37848
  if (!Array.isArray(content) || content.length !== 1)
37743
37849
  return false;
37744
- const block = object10(content[0]);
37850
+ const block = object11(content[0]);
37745
37851
  return !!block && block.text === text && (responses ? block.type === "input_text" : Object.keys(block).length === 1);
37746
37852
  }
37747
37853
  if ((api === "anthropic-messages" || api === "factory-droid-agent") && Array.isArray(content)) {
37748
- const block = content.length === 1 ? object10(content[0]) : undefined;
37854
+ const block = content.length === 1 ? object11(content[0]) : undefined;
37749
37855
  return block?.type === "text" && block.text === text;
37750
37856
  }
37751
37857
  return content === text;
@@ -37798,7 +37904,7 @@ function trimPreparedImageRows(rows, budget, drops) {
37798
37904
  flush();
37799
37905
  return projected;
37800
37906
  }
37801
- function countAnthropicOptionalAlignments(plan, base, wire, compare) {
37907
+ function countAnthropicOptionalAlignments(plan, base, wire, compare, reminders, firstUser = -1) {
37802
37908
  const pad = {
37803
37909
  role: "user",
37804
37910
  calls: [],
@@ -37830,11 +37936,16 @@ function countAnthropicOptionalAlignments(plan, base, wire, compare) {
37830
37936
  const place = (next) => {
37831
37937
  if (current < 0)
37832
37938
  return at;
37833
- const nextRole = next === undefined ? undefined : role(next);
37939
+ let after = at + 1;
37940
+ while (after < wire.length && reminders?.has(wire[after]))
37941
+ after++;
37942
+ const controls = after > at + 1;
37943
+ if (controls && (firstUser < 0 || current < firstUser))
37944
+ return;
37945
+ const nextRole = controls ? wire[at + 1].role : next === undefined ? undefined : role(next);
37834
37946
  if (!matches(final(current, previous, nextRole), at))
37835
37947
  return;
37836
- let after = at + 1;
37837
- if (role(current) === "assistant" && nextRole === "assistant") {
37948
+ if (!controls && role(current) === "assistant" && nextRole === "assistant") {
37838
37949
  if (!matches(pad, after))
37839
37950
  return;
37840
37951
  after++;
@@ -37844,7 +37955,7 @@ function countAnthropicOptionalAlignments(plan, base, wire, compare) {
37844
37955
  for (let next = current + 1;next < base.length; next++) {
37845
37956
  const after = place(next);
37846
37957
  if (after !== undefined)
37847
- add(next, current < 0 ? undefined : role(current), after, count);
37958
+ add(next, current < 0 ? undefined : wire[after - 1]?.role, after, count);
37848
37959
  if (!base[next].optionalThinking)
37849
37960
  return;
37850
37961
  }
@@ -37854,7 +37965,7 @@ function countAnthropicOptionalAlignments(plan, base, wire, compare) {
37854
37965
  return;
37855
37966
  }
37856
37967
  const after = place(undefined);
37857
- if (after === wire.length || after === wire.length - 1 && role(current) === "assistant" && isAnthropicContinuePadRow(wire[after]))
37968
+ if (after === wire.length || after === wire.length - 1 && wire[after - 1]?.role === "assistant" && isAnthropicContinuePadRow(wire[after]))
37858
37969
  complete = Math.min(2, complete + count);
37859
37970
  };
37860
37971
  advance(-1, undefined, 0, 1);
@@ -37872,6 +37983,70 @@ function countAnthropicOptionalAlignments(plan, base, wire, compare) {
37872
37983
  return complete;
37873
37984
  }
37874
37985
  function piPreparedStructureMismatch(payload, prepared, onImageTrim) {
37986
+ const plan = prepared && dateReminderPlans.get(prepared);
37987
+ try {
37988
+ const messages = plan ? object11(payload)?.messages : undefined;
37989
+ if (Array.isArray(messages)) {
37990
+ for (const value of messages) {
37991
+ const message = object11(value);
37992
+ if (message?.role !== "system" && message?.role !== "developer")
37993
+ break;
37994
+ if (piDateReminderWireText(message.content, plan?.cwd) !== undefined)
37995
+ return "comparison=role";
37996
+ }
37997
+ }
37998
+ } catch {}
37999
+ const mismatch = preparedStructureMismatch(payload, prepared, onImageTrim);
38000
+ if (!mismatch)
38001
+ return mismatch;
38002
+ try {
38003
+ if (!prepared || !plan)
38004
+ return mismatch;
38005
+ if (!plan.plan) {
38006
+ if (plan.firstUser < 0)
38007
+ return mismatch;
38008
+ const root = prepared.messages[plan.firstUser];
38009
+ const body = object11(payload);
38010
+ const routeRows = Array.isArray(body?.input) ? prepared.responsesMessages ?? prepared.messages : prepared.api === "openai-completions" ? prepared.chatMessages ?? prepared.messages : prepared.messages;
38011
+ const firstUser = routeRows.indexOf(root);
38012
+ if (firstUser < 0)
38013
+ return mismatch;
38014
+ const filtered = piWithoutDateReminders(payload, prepared.api ?? "", plan.cwd, plan.developerRole, (prefix) => {
38015
+ const rows = payloadStructure(prefix, prepared.api === "ollama-chat", !!prepared.responsesMessages);
38016
+ return !!rows && rows.length > firstUser;
38017
+ });
38018
+ return filtered === undefined ? mismatch : preparedStructureMismatch(filtered, prepared, onImageTrim);
38019
+ }
38020
+ const messages = object11(payload)?.messages;
38021
+ if (!Array.isArray(messages))
38022
+ return mismatch;
38023
+ for (const value of messages) {
38024
+ const message = object11(value);
38025
+ if (piDateReminderWireText(message?.content, plan.cwd) !== undefined && Object.keys(message ?? {}).some((key) => !["role", "content"].includes(key)))
38026
+ return mismatch;
38027
+ }
38028
+ const wire = payloadStructure(payload, false, false, !!prepared.imageBudget && piWireImageCount(payload) < prepared.imageBudget.count);
38029
+ if (!wire)
38030
+ return mismatch;
38031
+ const reminders = new Set(wire.filter((row) => piDateReminderWireText(row.wireContent, plan.cwd) !== undefined));
38032
+ if (!reminders.size)
38033
+ return mismatch;
38034
+ for (let index = 0;index < wire.length; index++) {
38035
+ const row = wire[index];
38036
+ if (!reminders.has(row))
38037
+ continue;
38038
+ const previous = wire[index - 1];
38039
+ const next = wire[index + 1];
38040
+ const promoted = plan.midConversationSystem && (previous?.role === "user" || previous?.role === "toolResult") && (!next || next.role === "assistant");
38041
+ if (row.wireRole !== (promoted ? "system" : "user") || row.calls.length || row.results.length)
38042
+ return mismatch;
38043
+ }
38044
+ return preparedStructureMismatch(payload, { ...prepared, anthropicOptional: plan.plan }, onImageTrim, reminders, wire, plan.firstUser);
38045
+ } catch {
38046
+ return mismatch;
38047
+ }
38048
+ }
38049
+ function preparedStructureMismatch(payload, prepared, onImageTrim, reminders, reminderWire, firstUser) {
37875
38050
  let stage = "image count";
37876
38051
  let row = 0;
37877
38052
  let expectedRows;
@@ -37886,10 +38061,10 @@ function piPreparedStructureMismatch(payload, prepared, onImageTrim) {
37886
38061
  return "comparison=image count";
37887
38062
  const imageProjection = trimmed > 0;
37888
38063
  stage = "wire rows";
37889
- const body = object10(payload);
38064
+ const body = object11(payload);
37890
38065
  const ollama = prepared?.api === "ollama-chat" && !!body && Array.isArray(body.messages) && body.input === undefined && body.system === undefined && body.inferenceConfig === undefined;
37891
38066
  const responses = body?.messages === undefined && Array.isArray(body?.input);
37892
- rows = payloadStructure(payload, ollama, responses && !!prepared?.responsesMessages, imageProjection);
38067
+ rows = reminderWire ?? payloadStructure(payload, ollama, responses && !!prepared?.responsesMessages, imageProjection);
37893
38068
  const chat = !!body && Array.isArray(body.messages) && (prepared?.api === "openai-completions" || body.system === undefined) && body.input === undefined && body.inferenceConfig === undefined;
37894
38069
  stage = "prepared rows";
37895
38070
  expectedRows = responses && prepared?.responsesMessages ? prepared.responsesMessages : chat && prepared?.chatMessages ? prepared.chatMessages : prepared?.messages;
@@ -37913,7 +38088,7 @@ function piPreparedStructureMismatch(payload, prepared, onImageTrim) {
37913
38088
  if (expected.systemText !== undefined) {
37914
38089
  const texts = expected.systemText;
37915
38090
  const content = actual.wireContent;
37916
- const actualTexts = typeof content === "string" ? [content] : Array.isArray(content) && content.every((part) => object10(part)?.type === "text" && typeof object10(part)?.text === "string") ? content.map((part) => part.text) : undefined;
38091
+ const actualTexts = typeof content === "string" ? [content] : Array.isArray(content) && content.every((part) => object11(part)?.type === "text" && typeof object11(part)?.text === "string") ? content.map((part) => part.text) : undefined;
37917
38092
  if (!actualTexts || (typeof content === "string" ? content !== texts.join(`
37918
38093
  `) : JSON.stringify(actualTexts) !== JSON.stringify(texts)))
37919
38094
  return "content";
@@ -37944,7 +38119,7 @@ function piPreparedStructureMismatch(payload, prepared, onImageTrim) {
37944
38119
  };
37945
38120
  if (optionalPlan) {
37946
38121
  stage = "optional assistants";
37947
- const alignments = countAnthropicOptionalAlignments(optionalPlan, imageProjection && imageBudget ? trimPreparedImageRows(optionalPlan.rows, imageBudget, trimmed) : optionalPlan.rows, rows, compareRow);
38122
+ const alignments = countAnthropicOptionalAlignments(optionalPlan, imageProjection && imageBudget ? trimPreparedImageRows(optionalPlan.rows, imageBudget, trimmed) : optionalPlan.rows, rows, compareRow, reminders, firstUser);
37948
38123
  if (alignments > 1)
37949
38124
  return structureDetail(0, expectedRows, rows, "alignment");
37950
38125
  if (alignments === 1) {
@@ -39704,7 +39879,7 @@ function registerPiGuardedContext(pi, handler, options = {}) {
39704
39879
  }
39705
39880
  const result = await budget.waitMandatory(Promise.resolve(withSqliteTurnDeadline2(() => Math.max(0, budget.remainingOutcome() - PI_CONTEXT_BUDGET.completionReserveMs), () => withSqliteTransformPass2(() => handler(event, ctx, budget)))));
39706
39881
  if (result?.messages) {
39707
- const prepared = preparePiDispatch(result.messages, fenceEnabled ? ctx.model : undefined, fenceEnabled);
39882
+ const prepared = preparePiDispatch(result.messages, fenceEnabled ? ctx.model : undefined, fenceEnabled, ctx.cwd);
39708
39883
  if (prepared.messages !== result.messages)
39709
39884
  result.messages = prepared.messages;
39710
39885
  active.managedSignature = piManagedSignature(result.messages);
@@ -42883,7 +43058,7 @@ function createPiAssistantPart(working, messageIndex, partIndex, markDirty) {
42883
43058
  setToolOutput() {
42884
43059
  throw new Error("setToolOutput on assistant part");
42885
43060
  },
42886
- getToolMetadata() {
43061
+ getToolMetadata(options) {
42887
43062
  const current = working[messageIndex].content;
42888
43063
  const p = current[partIndex];
42889
43064
  if (p?.type !== "toolCall") {
@@ -42894,7 +43069,7 @@ function createPiAssistantPart(working, messageIndex, partIndex, markDirty) {
42894
43069
  try {
42895
43070
  const serialized = JSON.stringify(p.arguments);
42896
43071
  inputByteSize = serialized.length;
42897
- inputTokenCount = serialized ? estimateTokens(serialized) : 0;
43072
+ inputTokenCount = serialized && !options?.skipInputTokenCount ? estimateTokens(serialized) : 0;
42898
43073
  } catch {
42899
43074
  inputByteSize = 0;
42900
43075
  inputTokenCount = 0;
@@ -43255,6 +43430,7 @@ function buildPiTextIdentityPlan(db, sessionId, tagger, transcript, reuseCandida
43255
43430
  sourceCache.set(tagId, source);
43256
43431
  }
43257
43432
  const driftedMessageIds = new Set;
43433
+ const reusableTextMessageIds = new Set;
43258
43434
  const legacyReminderTagNumbers = new Set;
43259
43435
  for (const [messageId, currentSources] of currentSourcesByMessageId) {
43260
43436
  const legacyRows = legacyRowsByMessageId.get(messageId) ?? [];
@@ -43282,6 +43458,8 @@ function buildPiTextIdentityPlan(db, sessionId, tagger, transcript, reuseCandida
43282
43458
  });
43283
43459
  if (!vectorMatches)
43284
43460
  driftedMessageIds.add(messageId);
43461
+ else if (!messageId.startsWith("pi-msg-") && legacyRows.every((row) => sourceCache.has(row.tagId) && !legacyReminderTagNumbers.has(row.tagId)))
43462
+ reusableTextMessageIds.add(messageId);
43285
43463
  }
43286
43464
  const reusableMessageIds = new Set;
43287
43465
  for (const messageId of reuseCandidates) {
@@ -43292,7 +43470,8 @@ function buildPiTextIdentityPlan(db, sessionId, tagger, transcript, reuseCandida
43292
43470
  driftedMessageIds,
43293
43471
  legacyReminderTagNumbers,
43294
43472
  reusableMessageIds,
43295
- sourceCache
43473
+ sourceCache,
43474
+ reusableTextMessageIds
43296
43475
  };
43297
43476
  }
43298
43477
  var piBranchProjectionBySession = new Map;
@@ -44746,6 +44925,27 @@ function registerPiContextHandler(pi, baseOptions) {
44746
44925
  }
44747
44926
  return s;
44748
44927
  };
44928
+ pi.on("session_tree", (event, ctx) => {
44929
+ if (event.oldLeafId === event.newLeafId)
44930
+ return;
44931
+ const sessionId = resolveSessionId2(ctx);
44932
+ if (!sessionId)
44933
+ return;
44934
+ let entries = [];
44935
+ let offset = 0;
44936
+ scheduleClearAndReindex(baseOptions.db, sessionId, {
44937
+ prepare: async () => {
44938
+ if (resolveSessionId2(ctx) !== sessionId)
44939
+ return false;
44940
+ entries = ctx.sessionManager.getBranch();
44941
+ const alignment = resolvePiOrdinalAlignment(baseOptions.db, sessionId, entries);
44942
+ offset = alignment.offset;
44943
+ return !isPiOrdinalAlignmentUnanchored(alignment);
44944
+ },
44945
+ getCount: () => countPiRawMessages(entries, offset),
44946
+ readPage: (_session, after, limit, watermark) => convertEntriesToRawMessagePage(entries, after, limit, watermark, offset)
44947
+ });
44948
+ });
44749
44949
  pi.on("thinking_level_select", async (event, ctx) => {
44750
44950
  if (event.previousLevel === event.level)
44751
44951
  return;
@@ -44839,7 +45039,7 @@ function registerPiContextHandler(pi, baseOptions) {
44839
45039
  withoutSqliteTransformPass2(() => options.maybeAutoEmbedSession?.(sessionId, projectDirectory, projectIdentity));
44840
45040
  if (!options.compactionOff) {
44841
45041
  budget.stage = "tag snapshot hydration";
44842
- const hydration = ensurePiTagSnapshotReady(options.db, sessionId, budget);
45042
+ const hydration = ensurePiTagSnapshotReady(options.db, sessionId, budget, "pass");
44843
45043
  if (hydration)
44844
45044
  await guardAwait(hydration);
44845
45045
  }
@@ -46071,7 +46271,7 @@ function registerPiContextHandler(pi, baseOptions) {
46071
46271
  budget.failureReason = err.message;
46072
46272
  if (sessionIdForError) {
46073
46273
  try {
46074
- prewarmPiTagSnapshot(lkgOptions.db, sessionIdForError);
46274
+ prewarmPiTagSnapshot(lkgOptions.db, sessionIdForError, "pass");
46075
46275
  } catch {}
46076
46276
  }
46077
46277
  throw err;
@@ -46137,7 +46337,7 @@ function registerPiContextHandler(pi, baseOptions) {
46137
46337
  })
46138
46338
  });
46139
46339
  assertPiTagSnapshotReady(lkgOptions.db, sessionIdForError);
46140
- const drops = getPiTagSnapshotView(lkgOptions.db, sessionIdForError).filter((tag) => tag.status === "dropped");
46340
+ const drops = projectPiReplayDrops(recoveryTranscript, getPiPassTagSnapshotView(lkgOptions.db, sessionIdForError));
46141
46341
  const changed = applyFlushedStatuses(sessionIdForError, lkgOptions.db, buildPersistedDropTargets(recoveryTranscript, drops, {
46142
46342
  allowReasoningPrefixRewrite: true
46143
46343
  }), drops);
@@ -47136,6 +47336,21 @@ async function runPipeline(args) {
47136
47336
  try {
47137
47337
  nativeRemovalInputs = getNativeReplayState(args.db, args.sessionId).toolInputs;
47138
47338
  } catch {}
47339
+ const removalBatch = (edit) => withPiToolRemovalBatch({ db: args.db, sessionId: args.sessionId, saved: nativeRemovalInputs }, edit);
47340
+ const applyToolRemovalGroup = (edit) => {
47341
+ const savedRemovalInputs = nativeRemovalInputs;
47342
+ nativeRemovalInputs = savedRemovalInputs && new Map(savedRemovalInputs);
47343
+ try {
47344
+ return args.db.transaction(() => removalBatch((flush) => {
47345
+ const result = edit();
47346
+ flush();
47347
+ return result;
47348
+ })).immediate();
47349
+ } catch (cause) {
47350
+ nativeRemovalInputs = savedRemovalInputs;
47351
+ throw cause instanceof PiToolRemovalBatchError ? cause : new PiToolRemovalBatchError(cause);
47352
+ }
47353
+ };
47139
47354
  const tTranscriptBuild = performance.now();
47140
47355
  const transcript = createPiTranscript(args.messages, args.sessionId, args.messages.map(stableIdResolver), {
47141
47356
  preserveReasoningToolArcs: args.reasoningClearing?.preserveReasoningToolArcs,
@@ -47328,6 +47543,7 @@ async function runPipeline(args) {
47328
47543
  preserveTagOnlyAssistantText: true,
47329
47544
  entryFingerprintByMessageId,
47330
47545
  reuseMessageIds: textIdentityPlan.reusableMessageIds,
47546
+ reuseTextMessageIds: textIdentityPlan.reusableTextMessageIds,
47331
47547
  textIdentityDriftMessageIds: textIdentityPlan.driftedMessageIds,
47332
47548
  textIdentitySourceCache: textIdentityPlan.sourceCache,
47333
47549
  textTokenCache: tagTextTokenCache,
@@ -47408,21 +47624,40 @@ async function runPipeline(args) {
47408
47624
  message.content = content;
47409
47625
  });
47410
47626
  }
47627
+ const tLegacyToolConversion = performance.now();
47411
47628
  if (foldBustsServedPrefixThisPass) {
47629
+ const savedRemovalInputs = nativeRemovalInputs;
47412
47630
  try {
47631
+ nativeRemovalInputs = savedRemovalInputs && new Map(savedRemovalInputs);
47413
47632
  let converted = 0;
47414
- args.db.transaction(() => {
47633
+ args.db.transaction(() => removalBatch((flush) => {
47415
47634
  converted = convertLegacyToolSkeletons(args.db, args.sessionId, targets, {
47416
- keepFullDrop: (callId) => nativeRemovalInputs === undefined || callId !== null && nativeRemovalInputs.get(callId) === NATIVE_TOOL_REMOVAL_MARKER
47635
+ prepareRemovals: (rows) => preparePiToolRemovalChecks({
47636
+ db: args.db,
47637
+ rows,
47638
+ targets,
47639
+ messages: args.messages,
47640
+ prepare: transcript.prepareToolRemovalMeasurements
47641
+ }),
47642
+ keepFullDrop: (callId) => nativeRemovalInputs === undefined || callId !== null && authorizePiToolRemoval({
47643
+ db: args.db,
47644
+ sessionId: args.sessionId,
47645
+ callId,
47646
+ saved: nativeRemovalInputs,
47647
+ canApply: false
47648
+ }) === true
47417
47649
  }).size;
47418
- }).immediate();
47650
+ flush();
47651
+ })).immediate();
47419
47652
  if (converted > 0) {
47420
47653
  sessionLog2(args.sessionId, `pi HARD fold converted ${converted} legacy dropped-tool skeleton(s) to real-or-absent`);
47421
47654
  }
47422
47655
  } catch (error) {
47656
+ nativeRemovalInputs = savedRemovalInputs;
47423
47657
  sessionLog2(args.sessionId, `pi legacy dropped-tool skeleton conversion failed (kept legacy bytes): ${error instanceof Error ? error.message : String(error)}`);
47424
47658
  }
47425
47659
  }
47660
+ logTransformTiming(args.sessionId, "convertLegacyToolSkeletons", tLegacyToolConversion);
47426
47661
  try {
47427
47662
  if (!args.sessionMeta.isSubagent) {
47428
47663
  const hasRecentCommit = detectRecentCommit(args.messages);
@@ -47440,7 +47675,9 @@ async function runPipeline(args) {
47440
47675
  const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
47441
47676
  const shouldReadPendingOps = !args.compactionOff && (publishedWorkDrainAllowed || args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal || foldExecutedThisPass || firstRenderBust);
47442
47677
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
47678
+ const tReclaimDistance = performance.now();
47443
47679
  const reclaimDistance = isCacheBustingPass ? toolReclaimDistanceEntries(mutationView, targets) : [];
47680
+ logTransformTiming(args.sessionId, "toolReclaimDistanceEntries", tReclaimDistance);
47444
47681
  const protectedToolTags = protectedToolTagNumbers(getActiveTagsBySession2(args.db, args.sessionId), args.protectedTools);
47445
47682
  for (const number of identityAdoption.protectedTagNumbers)
47446
47683
  protectedToolTags.add(number);
@@ -47477,13 +47714,14 @@ async function runPipeline(args) {
47477
47714
  try {
47478
47715
  nativeRemovalInputs = saved && new Map(saved);
47479
47716
  probingExecuteRemoval = true;
47480
- args.db.transaction(() => {
47717
+ args.db.transaction(() => removalBatch((flush) => {
47481
47718
  for (const [number, target] of targets) {
47482
47719
  if (target.prepareDrop?.() !== false)
47483
47720
  allowed.add(number);
47484
47721
  }
47722
+ flush();
47485
47723
  throw rollback;
47486
- }).immediate();
47724
+ })).immediate();
47487
47725
  } catch (error) {
47488
47726
  if (error !== rollback)
47489
47727
  allowed.clear();
@@ -47522,13 +47760,13 @@ async function runPipeline(args) {
47522
47760
  pendingDecisionLogObserverForTests?.(pendingDecisionLog);
47523
47761
  try {
47524
47762
  const tApplyPending = performance.now();
47525
- pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, newTargets, new Set([
47763
+ pendingOpsDidMutate = applyToolRemovalGroup(() => applyPendingOperations(args.sessionId, args.db, newTargets, new Set([
47526
47764
  ...args.contextUsage.percentage >= 95 ? [] : protectedTagNumbersForPass,
47527
47765
  ...protectedToolTags,
47528
47766
  ...identityAdoption.protectedTagNumbers
47529
47767
  ]), pendingOperationTags, pendingOps, [], new Set, (reduction) => droppedTokenReductions.push(reduction), undefined, (eligible) => {
47530
47768
  eligiblePendingDropTagIds = eligible;
47531
- });
47769
+ }));
47532
47770
  if (pendingOpsDidMutate) {
47533
47771
  droppedCount += pendingOps.length;
47534
47772
  }
@@ -47558,7 +47796,26 @@ async function runPipeline(args) {
47558
47796
  const flushedDroppedTags = getDroppedTagsByNumbers2(args.db, args.sessionId, targetTagNumbers);
47559
47797
  logTransformTiming(args.sessionId, "getDroppedTagsByNumbers", tGetTags, `targets=${targetTagNumbers.length} fetched=${flushedDroppedTags.length}`);
47560
47798
  const tFlushed = performance.now();
47561
- runPersistedReplayStage("flushed-status-failure", undefined, () => applyFlushedStatuses(args.sessionId, args.db, targets, flushedDroppedTags));
47799
+ runPersistedReplayStage("flushed-status-failure", undefined, () => {
47800
+ const render = () => applyFlushedStatuses(args.sessionId, args.db, targets, flushedDroppedTags);
47801
+ const savedRemovalInputs = nativeRemovalInputs;
47802
+ const needsRemovalPreparation = savedRemovalInputs !== undefined && flushedDroppedTags.some((tag) => tag.type === "tool" && tag.dropMode === "full" && savedRemovalInputs.get(tag.messageId) !== NATIVE_TOOL_REMOVAL_MARKER);
47803
+ if (!isCacheBustingPass || !needsRemovalPreparation)
47804
+ return render();
47805
+ try {
47806
+ nativeRemovalInputs = savedRemovalInputs && new Map(savedRemovalInputs);
47807
+ return args.db.transaction(() => removalBatch((flush) => {
47808
+ prepareFlushedToolRemovals(targets, flushedDroppedTags);
47809
+ flush();
47810
+ return render();
47811
+ })).immediate();
47812
+ } catch (error) {
47813
+ nativeRemovalInputs = savedRemovalInputs;
47814
+ if (error instanceof PiToolRemovalBatchError)
47815
+ return render();
47816
+ throw error;
47817
+ }
47818
+ });
47562
47819
  logTransformTiming(args.sessionId, "applyFlushedStatuses", tFlushed);
47563
47820
  logTransformTiming(args.sessionId, "batchFinalize:flushed", tFlushed);
47564
47821
  const messageIdToMaxTag = buildMessageIdToMaxTag(targets);
@@ -47607,7 +47864,7 @@ async function runPipeline(args) {
47607
47864
  let routineCleanupApplied = false;
47608
47865
  let heuristicsResult = null;
47609
47866
  const tActiveTags = performance.now();
47610
- const allTagsForPass = getPiTagSnapshotView(args.db, args.sessionId);
47867
+ const allTagsForPass = getPiPassTagSnapshotView(args.db, args.sessionId);
47611
47868
  const activeTags = getPiActiveTagSnapshotView(args.db, args.sessionId, allTagsForPass);
47612
47869
  logTransformTiming(args.sessionId, "getTagsBySessionSnapshot", tActiveTags, `all=${allTagsForPass.length} active=${activeTags.length}`);
47613
47870
  if (shouldRunHeuristics) {
@@ -47629,7 +47886,7 @@ async function runPipeline(args) {
47629
47886
  clearEmergencyDropSample(args.db, args.sessionId);
47630
47887
  }
47631
47888
  routineCleanupApplied = (emergencyDropEligible ? args.contextUsage.percentage >= 95 || getEmergencyInputSample(args.db, args.sessionId) === 0 : args.sessionMeta.isSubagent || !routinePressureAlreadyApplied) || hasPendingMaterializeSignal || rideSignals.explicitFlush || deferredMaterialize || independentMutationBeforeHeuristics;
47632
- heuristicsResult = applyPiHeuristicCleanup(args.sessionId, args.db, newTargets, args.messages, {
47889
+ heuristicsResult = applyToolRemovalGroup(() => applyPiHeuristicCleanup(args.sessionId, args.db, newTargets, args.messages, {
47633
47890
  protectedTags: args.protectedTags,
47634
47891
  prepareToolRemovalMeasurements: transcript.prepareToolRemovalMeasurements,
47635
47892
  protectedToolTags,
@@ -47643,18 +47900,18 @@ async function runPipeline(args) {
47643
47900
  usagePercentage: args.contextUsage.percentage,
47644
47901
  passAlreadyPriced: independentMutationBeforeHeuristics
47645
47902
  } : undefined,
47646
- caveman: args.isSubagent ? undefined : args.heuristics.caveman
47647
- }, activeTags, stableIdResolver);
47903
+ caveman: args.isSubagent ? undefined : args.heuristics?.caveman
47904
+ }, activeTags, stableIdResolver));
47648
47905
  if (!routineCleanupApplied && heuristicsResult.emergencyDroppedTools > 0) {
47649
- const ridingCleanup = applyPiHeuristicCleanup(args.sessionId, args.db, newTargets, args.messages, {
47906
+ const ridingCleanup = applyToolRemovalGroup(() => applyPiHeuristicCleanup(args.sessionId, args.db, newTargets, args.messages, {
47650
47907
  protectedTags: args.protectedTags,
47651
47908
  protectedToolTags,
47652
47909
  protectedCutoff: usesTokenProtection ? protectionWindowForPass.cutoff : undefined,
47653
47910
  routine: true,
47654
47911
  staleReduceStripEnabled: true,
47655
47912
  onStaleReduceEdit: recordStaleReduceEdit,
47656
- caveman: args.isSubagent ? undefined : args.heuristics.caveman
47657
- }, getActiveTagsBySession2(args.db, args.sessionId), stableIdResolver);
47913
+ caveman: args.isSubagent ? undefined : args.heuristics?.caveman
47914
+ }, getActiveTagsBySession2(args.db, args.sessionId), stableIdResolver));
47658
47915
  heuristicsResult = {
47659
47916
  droppedTools: heuristicsResult.droppedTools + ridingCleanup.droppedTools,
47660
47917
  deduplicatedTools: heuristicsResult.deduplicatedTools + ridingCleanup.deduplicatedTools,
@@ -47693,6 +47950,8 @@ async function runPipeline(args) {
47693
47950
  }
47694
47951
  logTransformTiming(args.sessionId, "applyHeuristicCleanup", tHeuristic, `droppedTools=${heuristicsResult.droppedTools} deduplicatedTools=${heuristicsResult.deduplicatedTools} droppedInjections=${heuristicsResult.droppedInjections} staleReduce=${heuristicsResult.droppedStaleReduceCalls} compressedTextTags=${heuristicsResult.compressedTextTags} mutatedTextTags=${heuristicsResult.mutatedTextTags}`);
47695
47952
  } catch (err) {
47953
+ if (err instanceof PiToolRemovalBatchError)
47954
+ throw err;
47696
47955
  sessionLog2(args.sessionId, `heuristic cleanup failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
47697
47956
  }
47698
47957
  }
@@ -47831,7 +48090,7 @@ async function runPipeline(args) {
47831
48090
  }
47832
48091
  autoReclaimTargetCount = syntheticPendingOps.length;
47833
48092
  if (syntheticPendingOps.length > 0) {
47834
- autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, newTargets, protectedTagNumbersForPass, undefined, [], syntheticPendingOps, editMarkerTagIds, (reduction) => droppedTokenReductions.push(reduction));
48093
+ autoReclaimDidMutate = applyToolRemovalGroup(() => applyPendingOperations(args.sessionId, args.db, newTargets, protectedTagNumbersForPass, undefined, [], syntheticPendingOps, editMarkerTagIds, (reduction) => droppedTokenReductions.push(reduction)));
47835
48094
  if (autoReclaimDidMutate) {
47836
48095
  droppedCount += syntheticPendingOps.length;
47837
48096
  autoReclaimDidMutateThisPass = true;
@@ -47852,10 +48111,7 @@ async function runPipeline(args) {
47852
48111
  noteImagePosition(message.info.id, tagNumber);
47853
48112
  }
47854
48113
  }
47855
- const imageToolTags = new Map(allTagsForPass.filter((tag) => tag.type === "tool").map((tag) => [
47856
- `${tag.toolOwnerMessageId ?? ""}\x00${tag.messageId}`,
47857
- tag.tagNumber
47858
- ]));
48114
+ const imageToolCoordinates = [];
47859
48115
  const imageToolOwners = new Map;
47860
48116
  for (let index = 0;index < workingMessages.length; index++) {
47861
48117
  const message = workingMessages[index];
@@ -47865,12 +48121,26 @@ async function runPipeline(args) {
47865
48121
  if (part.type !== "toolCall")
47866
48122
  continue;
47867
48123
  imageToolOwners.set(part.id, id ?? "");
47868
- noteImagePosition(id, imageToolTags.get(`${id ?? ""}\x00${part.id}`) ?? 0);
48124
+ imageToolCoordinates.push({ id, key: `${id ?? ""}\x00${part.id}` });
47869
48125
  }
47870
48126
  } else if (message.role === "toolResult") {
47871
- noteImagePosition(id, imageToolTags.get(`${imageToolOwners.get(message.toolCallId) ?? ""}\x00${message.toolCallId}`) ?? 0);
48127
+ imageToolCoordinates.push({
48128
+ id,
48129
+ key: `${imageToolOwners.get(message.toolCallId) ?? ""}\x00${message.toolCallId}`
48130
+ });
47872
48131
  }
47873
48132
  }
48133
+ const imageToolKeys = new Set(imageToolCoordinates.map(({ key }) => key));
48134
+ const imageToolTags = new Map;
48135
+ for (const tag of allTagsForPass) {
48136
+ if (tag.type !== "tool")
48137
+ continue;
48138
+ const key = `${tag.toolOwnerMessageId ?? ""}\x00${tag.messageId}`;
48139
+ if (imageToolKeys.has(key))
48140
+ imageToolTags.set(key, tag.tagNumber);
48141
+ }
48142
+ for (const { id, key } of imageToolCoordinates)
48143
+ noteImagePosition(id, imageToolTags.get(key) ?? 0);
47874
48144
  const protectedImageToolKeys = new Set(activeTags.filter((tag) => tag.type === "tool" && protectedToolTags.has(tag.tagNumber)).map((tag) => tag.toolOwnerMessageId ? `${tag.toolOwnerMessageId}\x00${tag.messageId}` : tag.messageId));
47875
48145
  const imageResult = stripPiProcessedImages({
47876
48146
  db: args.db,
@@ -48205,7 +48475,7 @@ async function runPipeline(args) {
48205
48475
  onAdopt: (message) => sessionLog2(args.sessionId, message)
48206
48476
  });
48207
48477
  protectionFloorResolution = resolveProtectionFloor();
48208
- const protectedTagNumbers = usesTokenProtection ? computeProtectionWindow(allTagsForPass, protectionFloorResolution.floor, activeCalibration.toolsRatio).protectedTagNumbers : newestActiveTagNumbersByCount(activeTags, args.protectedTags);
48478
+ const protectedTagNumbers = usesTokenProtection ? protectedPiPassTagNumbers(allTagsForPass, protectionFloorResolution.floor, activeCalibration.toolsRatio) : newestActiveTagNumbersByCount(activeTags, args.protectedTags);
48209
48479
  const channelPendingOps = shouldApplyPendingOps ? getPendingOps(args.db, args.sessionId) : shouldReadPendingOps ? pendingOps : getPendingOps(args.db, args.sessionId);
48210
48480
  const channelBaselineSnapshot = {
48211
48481
  tagCacheKey: fallbackCache.index,
@@ -50892,7 +51162,7 @@ function buildStatusDetail(pi, ctx, deps, sessionId, state, host = readStatusHos
50892
51162
  enabled: deps.dreamer?.runnable === true,
50893
51163
  scheduleSummary: deps.dreamer?.scheduleSummary ?? null,
50894
51164
  lastRunAt: safeRead(() => getMostRecentTaskRunAt(deps.db, deps.projectIdentity), null),
50895
- backlog: safeRead(() => getDreamTaskBacklogs(deps.db, deps.projectIdentity, CANONICAL_DREAM_TASKS.filter((task) => deps.smartNotesEnabled !== false || task !== "evaluate-smart-notes")), {}),
51165
+ backlog: safeRead(() => getDreamTaskBacklogs(deps.db, deps.projectIdentity, CANONICAL_DREAM_TASKS.filter((task) => deps.smartNotesEnabled !== false || task !== "evaluate-smart-notes"), { display: true }), {}),
50896
51166
  failures: safeRead(() => getFailingDreamTasks(deps.db, deps.projectIdentity).filter((state) => deps.smartNotesEnabled !== false || state.task !== "evaluate-smart-notes"), []),
50897
51167
  skipped: safeRead(() => getSkippedDreamTasks(deps.db, deps.projectIdentity).filter((task) => deps.smartNotesEnabled !== false || task !== "evaluate-smart-notes"), []),
50898
51168
  tickFailure: safeRead(() => getDreamerTickFailure(deps.db), null)
@@ -52775,7 +53045,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
52775
53045
  return;
52776
53046
  }
52777
53047
  const emptyHistorian = empty.find((chain) => chain.owner === "historian");
52778
- const historianLine = historian ? `registered historian trigger (model=${historian.model}${historian.fallbackModels?.length ? `, fallbacks=${historian.fallbackModels.join(",")}` : ""}, executeThreshold=${formatExecuteThresholdForLog(historian.executeThresholdPercentage)})` : emptyHistorian ? `registered historian trigger: DISABLED (no configured model is registered in Pi: ${formatEmptyPiModelChain(emptyHistorian)})` : undefined;
53048
+ const historianLine = historian ? `registered historian trigger (model=${historian.model}${historian.fallbackModels?.length ? `, fallbacks=${historian.fallbackModels.map(formatPiModelForLog).join(",")}` : ""}, executeThreshold=${formatExecuteThresholdForLog(historian.executeThresholdPercentage)})` : emptyHistorian ? `registered historian trigger: DISABLED (no configured model is registered in Pi: ${formatEmptyPiModelChain(emptyHistorian)})` : undefined;
52779
53049
  if (historianLine && !loggedPiModelChainLines.has(historianLine)) {
52780
53050
  loggedPiModelChainLines.add(historianLine);
52781
53051
  info(historianLine);
@@ -52899,7 +53169,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
52899
53169
  registerPiCloneSessionTransitions(pi.on.bind(pi), {
52900
53170
  db,
52901
53171
  signalPendingMarker: signalPiDeferredCompactionMarkerDrain,
52902
- onInherited: (sessionId) => prewarmPiTagSnapshot(db, sessionId)
53172
+ onInherited: (sessionId) => prewarmPiTagSnapshot(db, sessionId, "pass")
52903
53173
  });
52904
53174
  pi.on("session_start", async (event, ctx) => {
52905
53175
  bindStaleBuildNotice(ctx, import.meta.url);
@@ -52921,7 +53191,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
52921
53191
  await handlePiCloneSessionStart(event, ctx, {
52922
53192
  db,
52923
53193
  signalPendingMarker: signalPiDeferredCompactionMarkerDrain,
52924
- onInherited: (sessionId) => prewarmPiTagSnapshot(db, sessionId)
53194
+ onInherited: (sessionId) => prewarmPiTagSnapshot(db, sessionId, "pass")
52925
53195
  });
52926
53196
  const sessionId = resolveSessionId(ctx);
52927
53197
  if (!piMarkerRehydrationLogged && pendingPiMarkerSessions.length > 0 && sessionId) {
@@ -52938,7 +53208,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
52938
53208
  });
52939
53209
  }
52940
53210
  if (sessionId)
52941
- prewarmPiTagSnapshot(db, sessionId);
53211
+ prewarmPiTagSnapshot(db, sessionId, "pass");
52942
53212
  });
52943
53213
  pi.on("agent_start", (_event, ctx) => {
52944
53214
  setEmbeddingSessionBusy2(ctx.sessionManager.getSessionId(), true);
@@ -53514,7 +53784,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
53514
53784
  try {
53515
53785
  const incomingSessionId = readSessionId(ctx);
53516
53786
  if (incomingSessionId && _event?.reason !== "fork")
53517
- prewarmPiTagSnapshot(db, incomingSessionId);
53787
+ prewarmPiTagSnapshot(db, incomingSessionId, "pass");
53518
53788
  if (!outgoingSessionId || outgoingSessionId === readSessionId(ctx))
53519
53789
  return;
53520
53790
  clearPiSystemPromptSession(outgoingSessionId);
@@ -53535,6 +53805,11 @@ function formatExecuteThresholdForLog(value) {
53535
53805
  const base = `${value.default}%`;
53536
53806
  return overrides.length > 0 ? `${base} (${overrides.join(", ")})` : base;
53537
53807
  }
53808
+ function formatPiModelForLog(entry) {
53809
+ if (typeof entry === "string")
53810
+ return entry;
53811
+ return `${entry.model}${entry.qualifier ? ` (thinking_level=${entry.qualifier})` : ""}`;
53812
+ }
53538
53813
  export {
53539
53814
  __test,
53540
53815
  canonicalPiModelKey,