@cortexkit/pi-magic-context 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -141212,6 +141212,24 @@ class ToolMutationBatch {
141212
141212
  }
141213
141213
 
141214
141214
  // ../plugin/src/hooks/magic-context/read-session-chunk.ts
141215
+ var BLOCK_TOKEN_MEMO_MAX = 2048;
141216
+ var blockTokenMemo = new Map;
141217
+ function estimateBlockTokens(blockText) {
141218
+ const cached = blockTokenMemo.get(blockText);
141219
+ if (cached !== undefined) {
141220
+ blockTokenMemo.delete(blockText);
141221
+ blockTokenMemo.set(blockText, cached);
141222
+ return cached;
141223
+ }
141224
+ const count = estimateTokens(blockText);
141225
+ if (blockTokenMemo.size >= BLOCK_TOKEN_MEMO_MAX) {
141226
+ const oldest = blockTokenMemo.keys().next().value;
141227
+ if (oldest !== undefined)
141228
+ blockTokenMemo.delete(oldest);
141229
+ }
141230
+ blockTokenMemo.set(blockText, count);
141231
+ return count;
141232
+ }
141215
141233
  var activeRawMessageCache = null;
141216
141234
  var activeAbsoluteCountCache = null;
141217
141235
  var sessionProviders = new Map;
@@ -141394,7 +141412,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
141394
141412
  if (!currentBlock)
141395
141413
  return true;
141396
141414
  const blockText = formatBlock(currentBlock);
141397
- const blockTokens = estimateTokens(blockText);
141415
+ const blockTokens = estimateBlockTokens(blockText);
141398
141416
  if (totalTokens + blockTokens > tokenBudget && totalTokens > 0) {
141399
141417
  return false;
141400
141418
  }
@@ -141999,6 +142017,8 @@ var SESSION_META_SELECT_COLUMNS = [
141999
142017
  "recovery_no_eligible_head_count",
142000
142018
  "force_emergency_bypass_window_start",
142001
142019
  "force_emergency_bypass_used",
142020
+ "emergency_drain_active",
142021
+ "historian_drain_failure_at",
142002
142022
  "upgrade_reminded_at",
142003
142023
  "pi_stable_id_scheme"
142004
142024
  ];
@@ -142048,6 +142068,8 @@ var META_COLUMNS = {
142048
142068
  recoveryNoEligibleHeadCount: "recovery_no_eligible_head_count",
142049
142069
  forceEmergencyBypassWindowStart: "force_emergency_bypass_window_start",
142050
142070
  forceEmergencyBypassUsed: "force_emergency_bypass_used",
142071
+ emergencyDrainActive: "emergency_drain_active",
142072
+ historianDrainFailureAt: "historian_drain_failure_at",
142051
142073
  upgradeRemindedAt: "upgrade_reminded_at",
142052
142074
  piStableIdScheme: "pi_stable_id_scheme"
142053
142075
  };
@@ -142949,8 +142971,9 @@ function backfillToolOwnersInChunks(db, result) {
142949
142971
  var databases = new Map;
142950
142972
  var persistenceByDatabase = new WeakMap;
142951
142973
  var persistenceErrorByDatabase = new WeakMap;
142974
+ var pathByDatabase = new WeakMap;
142952
142975
  var lastSchemaFenceRejection = null;
142953
- var LATEST_SUPPORTED_VERSION = 36;
142976
+ var LATEST_SUPPORTED_VERSION = 38;
142954
142977
  function resolveDatabasePath(dbPathOverride) {
142955
142978
  if (dbPathOverride) {
142956
142979
  return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
@@ -142963,6 +142986,9 @@ function resolveDatabasePath(dbPathOverride) {
142963
142986
  const dbDir = getMagicContextStorageDir();
142964
142987
  return { dbDir, dbPath: join5(dbDir, "context.db") };
142965
142988
  }
142989
+ function getDatabasePath(db) {
142990
+ return pathByDatabase.get(db) ?? null;
142991
+ }
142966
142992
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
142967
142993
  if (existsSync4(targetDbPath))
142968
142994
  return;
@@ -143477,6 +143503,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143477
143503
  recovery_no_eligible_head_count INTEGER NOT NULL DEFAULT 0,
143478
143504
  force_emergency_bypass_window_start INTEGER NOT NULL DEFAULT 0,
143479
143505
  force_emergency_bypass_used INTEGER NOT NULL DEFAULT 0,
143506
+ emergency_drain_active INTEGER NOT NULL DEFAULT 0,
143507
+ historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
143480
143508
  cached_m0_materialized_at INTEGER,
143481
143509
  cached_m0_session_facts_version INTEGER,
143482
143510
  cached_m0_upgrade_state TEXT,
@@ -143540,6 +143568,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143540
143568
  CREATE INDEX IF NOT EXISTS idx_historian_runs_status
143541
143569
  ON historian_runs(status, created_at DESC);
143542
143570
 
143571
+ CREATE TABLE IF NOT EXISTS transform_decisions (
143572
+ session_id TEXT NOT NULL,
143573
+ harness TEXT NOT NULL DEFAULT 'opencode',
143574
+ message_id TEXT NOT NULL,
143575
+ ts_ms INTEGER NOT NULL,
143576
+ decision TEXT NOT NULL,
143577
+ materialized INTEGER NOT NULL DEFAULT 0,
143578
+ materialize_reason TEXT,
143579
+ emergency INTEGER NOT NULL DEFAULT 0,
143580
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
143581
+ dropped_count INTEGER NOT NULL DEFAULT 0,
143582
+ input_tokens INTEGER NOT NULL DEFAULT 0,
143583
+ PRIMARY KEY (session_id, harness, message_id)
143584
+ );
143585
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
143586
+ ON transform_decisions(session_id, harness);
143587
+
143543
143588
  CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
143544
143589
  CREATE INDEX IF NOT EXISTS idx_tags_session_message_id ON tags(session_id, message_id);
143545
143590
  CREATE INDEX IF NOT EXISTS idx_pending_ops_session ON pending_ops(session_id);
@@ -143691,6 +143736,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143691
143736
  ensureColumn(db, "session_meta", "recovery_no_eligible_head_count", "INTEGER NOT NULL DEFAULT 0");
143692
143737
  ensureColumn(db, "session_meta", "force_emergency_bypass_window_start", "INTEGER NOT NULL DEFAULT 0");
143693
143738
  ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
143739
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
143740
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
143694
143741
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
143695
143742
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
143696
143743
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -143769,6 +143816,22 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143769
143816
  failed_at INTEGER NOT NULL,
143770
143817
  UNIQUE(table_name, row_id)
143771
143818
  );
143819
+ CREATE TABLE IF NOT EXISTS transform_decisions (
143820
+ session_id TEXT NOT NULL,
143821
+ harness TEXT NOT NULL DEFAULT 'opencode',
143822
+ message_id TEXT NOT NULL,
143823
+ ts_ms INTEGER NOT NULL,
143824
+ decision TEXT NOT NULL,
143825
+ materialized INTEGER NOT NULL DEFAULT 0,
143826
+ materialize_reason TEXT,
143827
+ emergency INTEGER NOT NULL DEFAULT 0,
143828
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
143829
+ dropped_count INTEGER NOT NULL DEFAULT 0,
143830
+ input_tokens INTEGER NOT NULL DEFAULT 0,
143831
+ PRIMARY KEY (session_id, harness, message_id)
143832
+ );
143833
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
143834
+ ON transform_decisions(session_id, harness);
143772
143835
  `);
143773
143836
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
143774
143837
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -143855,7 +143918,9 @@ function healNullIntegerColumns(db) {
143855
143918
  ["protected_tail_drain_tokens", 0],
143856
143919
  ["recovery_no_eligible_head_count", 0],
143857
143920
  ["force_emergency_bypass_window_start", 0],
143858
- ["force_emergency_bypass_used", 0]
143921
+ ["force_emergency_bypass_used", 0],
143922
+ ["emergency_drain_active", 0],
143923
+ ["historian_drain_failure_at", 0]
143859
143924
  ];
143860
143925
  for (const [column, fallback] of columns) {
143861
143926
  try {
@@ -143931,6 +143996,7 @@ function openDatabase(dbPathOrOptions) {
143931
143996
  setDatabase(db);
143932
143997
  loadToolDefinitionMeasurements(db);
143933
143998
  databases.set(dbPath, db);
143999
+ pathByDatabase.set(db, dbPath);
143934
144000
  persistenceByDatabase.set(db, true);
143935
144001
  persistenceErrorByDatabase.delete(db);
143936
144002
  return db;
@@ -145172,6 +145238,41 @@ var MIGRATIONS = [
145172
145238
  `);
145173
145239
  }
145174
145240
  }
145241
+ },
145242
+ {
145243
+ version: 37,
145244
+ description: "emergency drain catch-up latch + historian drain failure backoff",
145245
+ up: (db) => {
145246
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta'").get();
145247
+ if (!hasSessionMeta)
145248
+ return;
145249
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
145250
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
145251
+ }
145252
+ },
145253
+ {
145254
+ version: 38,
145255
+ description: "durable transform decisions for cache-event cause attribution",
145256
+ up: (db) => {
145257
+ db.exec(`
145258
+ CREATE TABLE IF NOT EXISTS transform_decisions (
145259
+ session_id TEXT NOT NULL,
145260
+ harness TEXT NOT NULL DEFAULT 'opencode',
145261
+ message_id TEXT NOT NULL,
145262
+ ts_ms INTEGER NOT NULL,
145263
+ decision TEXT NOT NULL,
145264
+ materialized INTEGER NOT NULL DEFAULT 0,
145265
+ materialize_reason TEXT,
145266
+ emergency INTEGER NOT NULL DEFAULT 0,
145267
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
145268
+ dropped_count INTEGER NOT NULL DEFAULT 0,
145269
+ input_tokens INTEGER NOT NULL DEFAULT 0,
145270
+ PRIMARY KEY (session_id, harness, message_id)
145271
+ );
145272
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
145273
+ ON transform_decisions(session_id, harness);
145274
+ `);
145275
+ }
145175
145276
  }
145176
145277
  ];
145177
145278
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -145603,7 +145704,9 @@ var DEFAULT_PROTECTED_TAIL_META = {
145603
145704
  protectedTailDrainTokens: 0,
145604
145705
  recoveryNoEligibleHeadCount: 0,
145605
145706
  forceEmergencyBypassWindowStart: 0,
145606
- forceEmergencyBypassUsed: 0
145707
+ forceEmergencyBypassUsed: 0,
145708
+ emergencyDrainActive: 0,
145709
+ historianDrainFailureAt: 0
145607
145710
  };
145608
145711
  function toProtectedTailMeta(row) {
145609
145712
  if (row === null || typeof row !== "object")
@@ -145617,7 +145720,9 @@ function toProtectedTailMeta(row) {
145617
145720
  protectedTailDrainTokens: numberOr(r.protected_tail_drain_tokens, 0),
145618
145721
  recoveryNoEligibleHeadCount: numberOr(r.recovery_no_eligible_head_count, 0),
145619
145722
  forceEmergencyBypassWindowStart: numberOr(r.force_emergency_bypass_window_start, 0),
145620
- forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0)
145723
+ forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0),
145724
+ emergencyDrainActive: numberOr(r.emergency_drain_active, 0),
145725
+ historianDrainFailureAt: numberOr(r.historian_drain_failure_at, 0)
145621
145726
  };
145622
145727
  }
145623
145728
  function loadProtectedTailMeta(db, sessionId) {
@@ -145625,7 +145730,7 @@ function loadProtectedTailMeta(db, sessionId) {
145625
145730
  const row = db.prepare(`SELECT prior_boundary_ordinal, protected_tail_policy_version,
145626
145731
  protected_tail_drain_window_started_at, protected_tail_drain_tokens,
145627
145732
  recovery_no_eligible_head_count, force_emergency_bypass_window_start,
145628
- force_emergency_bypass_used
145733
+ force_emergency_bypass_used, emergency_drain_active, historian_drain_failure_at
145629
145734
  FROM session_meta WHERE session_id = ?`).get(sessionId);
145630
145735
  return toProtectedTailMeta(row);
145631
145736
  }
@@ -145669,6 +145774,17 @@ function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
145669
145774
  return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
145670
145775
  return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
145671
145776
  }
145777
+ var EMERGENCY_DRAIN_ENTER_PERCENTAGE = 95;
145778
+ var EMERGENCY_DRAIN_EXIT_MARGIN = 10;
145779
+ var EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE = 55;
145780
+ var EMERGENCY_DRAIN_FAILURE_BACKOFF_MS = 60000;
145781
+ var EMERGENCY_DRAIN_MAX_LATCH_MS = 30 * 60 * 1000;
145782
+ function emergencyDrainExitThreshold(executeThresholdPercentage) {
145783
+ if (!Number.isFinite(executeThresholdPercentage) || executeThresholdPercentage <= 0) {
145784
+ return EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE;
145785
+ }
145786
+ return Math.max(0, executeThresholdPercentage - EMERGENCY_DRAIN_EXIT_MARGIN);
145787
+ }
145672
145788
  function reserveProtectedTailDrainTokens(args) {
145673
145789
  const now = args.now ?? Date.now();
145674
145790
  const requested = Math.max(0, Math.floor(args.trueRawTokens));
@@ -145687,18 +145803,30 @@ function reserveProtectedTailDrainTokens(args) {
145687
145803
  let meta = loadProtectedTailMeta(args.db, args.sessionId);
145688
145804
  if (now - meta.protectedTailDrainWindowStartedAt > DRAIN_WINDOW_MS) {
145689
145805
  args.db.prepare(`UPDATE session_meta
145690
- SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0,
145691
- force_emergency_bypass_window_start = ?, force_emergency_bypass_used = 0
145692
- WHERE session_id = ?`).run(now, now, args.sessionId);
145806
+ SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0
145807
+ WHERE session_id = ?`).run(now, args.sessionId);
145693
145808
  meta = loadProtectedTailMeta(args.db, args.sessionId);
145694
145809
  }
145810
+ const exitThreshold = emergencyDrainExitThreshold(args.executeThresholdPercentage);
145811
+ let latchActiveSince = meta.emergencyDrainActive;
145812
+ if (args.usagePercentage >= EMERGENCY_DRAIN_ENTER_PERCENTAGE) {
145813
+ if (latchActiveSince <= 0)
145814
+ latchActiveSince = now;
145815
+ } else if (latchActiveSince > 0) {
145816
+ const expired = now - latchActiveSince > EMERGENCY_DRAIN_MAX_LATCH_MS;
145817
+ if (args.usagePercentage < exitThreshold || expired)
145818
+ latchActiveSince = 0;
145819
+ }
145820
+ if (latchActiveSince !== meta.emergencyDrainActive) {
145821
+ args.db.prepare("UPDATE session_meta SET emergency_drain_active = ? WHERE session_id = ?").run(latchActiveSince, args.sessionId);
145822
+ }
145823
+ const latchActive = latchActiveSince > 0;
145695
145824
  const budget = protectedTailWindowBudget(args.usagePercentage, args.usable, args.perRunCap);
145696
145825
  const remaining = Math.max(0, budget - meta.protectedTailDrainTokens);
145697
145826
  let reserved = Math.min(requested, args.perRunCap, remaining);
145698
145827
  let bypass = false;
145699
- const bypassWindowExpired = now - meta.forceEmergencyBypassWindowStart > DRAIN_WINDOW_MS;
145700
- const bypassUsed = bypassWindowExpired ? 0 : meta.forceEmergencyBypassUsed;
145701
- if (reserved <= 0 && args.usagePercentage >= 95 && bypassUsed === 0) {
145828
+ const inFailureBackoff = meta.historianDrainFailureAt > 0 && now - meta.historianDrainFailureAt < EMERGENCY_DRAIN_FAILURE_BACKOFF_MS;
145829
+ if (reserved <= 0 && latchActive && !inFailureBackoff) {
145702
145830
  reserved = Math.min(requested, args.perRunCap);
145703
145831
  bypass = true;
145704
145832
  }
@@ -145706,10 +145834,8 @@ function reserveProtectedTailDrainTokens(args) {
145706
145834
  return;
145707
145835
  args.db.prepare(`UPDATE session_meta
145708
145836
  SET protected_tail_drain_window_started_at = CASE WHEN protected_tail_drain_window_started_at = 0 THEN ? ELSE protected_tail_drain_window_started_at END,
145709
- protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?,
145710
- force_emergency_bypass_window_start = CASE WHEN ? THEN ? ELSE force_emergency_bypass_window_start END,
145711
- force_emergency_bypass_used = CASE WHEN ? THEN 1 ELSE force_emergency_bypass_used END
145712
- WHERE session_id = ?`).run(now, reserved, bypass ? 1 : 0, now, bypass ? 1 : 0, args.sessionId);
145837
+ protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?
145838
+ WHERE session_id = ?`).run(now, reserved, args.sessionId);
145713
145839
  result = {
145714
145840
  ok: true,
145715
145841
  reservedTokens: reserved,
@@ -145719,6 +145845,25 @@ function reserveProtectedTailDrainTokens(args) {
145719
145845
  })();
145720
145846
  return result;
145721
145847
  }
145848
+ function clearEmergencyDrainLatch(db, sessionId) {
145849
+ db.transaction(() => {
145850
+ ensureSessionMetaRow(db, sessionId);
145851
+ db.prepare("UPDATE session_meta SET emergency_drain_active = 0 WHERE session_id = ?").run(sessionId);
145852
+ })();
145853
+ }
145854
+ function recordHistorianDrainFailure(db, sessionId, now) {
145855
+ const ts = now ?? Date.now();
145856
+ db.transaction(() => {
145857
+ ensureSessionMetaRow(db, sessionId);
145858
+ db.prepare("UPDATE session_meta SET historian_drain_failure_at = ? WHERE session_id = ?").run(ts, sessionId);
145859
+ })();
145860
+ }
145861
+ function clearHistorianDrainFailure(db, sessionId) {
145862
+ db.transaction(() => {
145863
+ ensureSessionMetaRow(db, sessionId);
145864
+ db.prepare("UPDATE session_meta SET historian_drain_failure_at = 0 WHERE session_id = ?").run(sessionId);
145865
+ })();
145866
+ }
145722
145867
  function rollbackProtectedTailDrainReservation(db, reservation) {
145723
145868
  if (!reservation || reservation.tokens <= 0)
145724
145869
  return;
@@ -146740,12 +146885,17 @@ function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, li
146740
146885
  toolName: typeof row.tool_name === "string" ? row.tool_name : null
146741
146886
  }));
146742
146887
  }
146743
- function getTriggerTagTokenUpperBound(db, sessionId) {
146744
- const row = db.prepare(`SELECT
146888
+ function getTriggerTagTokenUpperBound(db, sessionId, floor = 0) {
146889
+ const sql = floor > 0 ? `SELECT
146745
146890
  COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
146746
146891
  COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
146747
146892
  FROM tags
146748
- WHERE session_id = ? AND status IN ('active', 'dropped')`).get(sessionId);
146893
+ WHERE session_id = ? AND status IN ('active', 'dropped') AND tag_number >= ?` : `SELECT
146894
+ COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
146895
+ COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
146896
+ FROM tags
146897
+ WHERE session_id = ? AND status IN ('active', 'dropped')`;
146898
+ const row = floor > 0 ? db.prepare(sql).get(sessionId, floor) : db.prepare(sql).get(sessionId);
146749
146899
  return { bound: row?.bound ?? 0, nullCount: row?.null_count ?? 0 };
146750
146900
  }
146751
146901
  function updateTagInputByteSize(db, sessionId, tagNumber, newInputByteSize) {
@@ -146772,10 +146922,12 @@ function getUpdateTagInputTokenCountStatement(db) {
146772
146922
  function updateTagTokenCount(db, sessionId, tagNumber, newTokenCount) {
146773
146923
  getUpdateTagTokenCountStatement(db).run(newTokenCount, sessionId, tagNumber);
146774
146924
  }
146775
- function getAllStatusTagTokenTotalsFlat(db, sessionId) {
146776
- const rows = db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
146777
- FROM tags
146778
- WHERE session_id = ?`).all(sessionId);
146925
+ function getAllStatusTagTokenTotalsFlat(db, sessionId, floor = 0) {
146926
+ const rows = floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
146927
+ FROM tags
146928
+ WHERE session_id = ? AND tag_number >= ?`).all(sessionId, floor) : db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
146929
+ FROM tags
146930
+ WHERE session_id = ?`).all(sessionId);
146779
146931
  const totals = new Map;
146780
146932
  const nullMessageIds = new Set;
146781
146933
  for (const row of rows) {
@@ -146894,6 +147046,52 @@ function getTagNumberByMessageId(db, sessionId, messageId) {
146894
147046
  const row = getTagNumberByMessageIdStatement(db).get(sessionId, messageId);
146895
147047
  return isTagNumberRow(row) ? row.tag_number : null;
146896
147048
  }
147049
+ var getMinMessageTagNumberForRawIdStatements = new WeakMap;
147050
+ function isMinTagNumberRow(row) {
147051
+ return row !== null && typeof row === "object" && "m" in row;
147052
+ }
147053
+ function getMinMessageTagNumberForRawId(db, sessionId, rawId) {
147054
+ if (rawId.includes(":"))
147055
+ return null;
147056
+ let stmt = getMinMessageTagNumberForRawIdStatements.get(db);
147057
+ if (!stmt) {
147058
+ stmt = db.prepare("SELECT MIN(tag_number) AS m FROM tags WHERE session_id = ? AND message_id >= ? AND message_id < ?");
147059
+ getMinMessageTagNumberForRawIdStatements.set(db, stmt);
147060
+ }
147061
+ const row = stmt.get(sessionId, `${rawId}:`, `${rawId};`);
147062
+ return isMinTagNumberRow(row) && typeof row.m === "number" ? row.m : null;
147063
+ }
147064
+ var TAGGER_FLOOR_SCAN_MESSAGES = 8;
147065
+ var TAGGER_FLOOR_MAX_PROBES = 64;
147066
+ var TAGGER_FLOOR_SAFETY_MARGIN = 256;
147067
+ var TAGGER_FLOOR_PER_SKIP_MARGIN = 64;
147068
+ function deriveTagLoadFloor(db, sessionId, rawIds) {
147069
+ let min = Number.POSITIVE_INFINITY;
147070
+ let probes = 0;
147071
+ let hits = 0;
147072
+ let skippedBeforeFirstHit = 0;
147073
+ for (const rawId of rawIds) {
147074
+ if (typeof rawId !== "string" || rawId.length === 0)
147075
+ continue;
147076
+ if (probes >= TAGGER_FLOOR_MAX_PROBES)
147077
+ break;
147078
+ probes++;
147079
+ const m = getMinMessageTagNumberForRawId(db, sessionId, rawId);
147080
+ if (m === null) {
147081
+ if (hits === 0)
147082
+ skippedBeforeFirstHit++;
147083
+ continue;
147084
+ }
147085
+ if (m < min)
147086
+ min = m;
147087
+ if (++hits >= TAGGER_FLOOR_SCAN_MESSAGES)
147088
+ break;
147089
+ }
147090
+ if (!Number.isFinite(min))
147091
+ return 0;
147092
+ const margin = TAGGER_FLOOR_SAFETY_MARGIN + skippedBeforeFirstHit * TAGGER_FLOOR_PER_SKIP_MARGIN;
147093
+ return Math.max(0, min - margin);
147094
+ }
146897
147095
  var TAG_SELECT_COLUMNS = "id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth, tool_owner_message_id";
146898
147096
  function getTagsBySession(db, sessionId) {
146899
147097
  const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC`).all(sessionId).filter(isTagRow);
@@ -146997,6 +147195,11 @@ init_logger();
146997
147195
  import { createHash as createHash5 } from "node:crypto";
146998
147196
  import { realpathSync as realpathSync2 } from "node:fs";
146999
147197
  import path5 from "node:path";
147198
+
147199
+ // ../plugin/src/features/magic-context/memory/relocate-memory.ts
147200
+ var memoryCopyColumnsCache = new WeakMap;
147201
+
147202
+ // ../plugin/src/features/magic-context/v22-deferred-backfill.ts
147000
147203
  var BATCH_SIZE = 25;
147001
147204
  var YIELD_EVERY_N_ROWS = 5;
147002
147205
  var BACKFILL_META_KEY = "v22_legacy_memory_backfill";
@@ -147212,65 +147415,6 @@ async function runDeferredV22Backfill(db, options = {}) {
147212
147415
  };
147213
147416
  }
147214
147417
 
147215
- // ../plugin/src/agents/historian.ts
147216
- var HISTORIAN_AGENT = "historian";
147217
- var HISTORIAN_EDITOR_AGENT = "historian-editor";
147218
-
147219
- // ../plugin/src/agents/dreamer.ts
147220
- var DREAMER_AGENT = "dreamer";
147221
-
147222
- // ../plugin/src/agents/sidekick.ts
147223
- var SIDEKICK_AGENT = "sidekick";
147224
-
147225
- // ../plugin/src/shared/model-requirements.ts
147226
- var HISTORIAN_FALLBACK_CHAIN = [
147227
- { providers: ["github-copilot", "anthropic", "opencode"], model: "claude-sonnet-4-6" },
147228
- { providers: ["opencode-go"], model: "minimax-m2.7" },
147229
- {
147230
- providers: ["zai-coding-plan", "bailian-coding-plan", "opencode-go", "opencode"],
147231
- model: "glm-5"
147232
- },
147233
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4" },
147234
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3.1-pro" }
147235
- ];
147236
- var DREAMER_FALLBACK_CHAIN = [
147237
- { providers: ["github-copilot", "anthropic", "opencode"], model: "claude-sonnet-4-6" },
147238
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
147239
- {
147240
- providers: ["zai-coding-plan", "bailian-coding-plan", "opencode-go", "opencode"],
147241
- model: "glm-5"
147242
- },
147243
- { providers: ["opencode-go"], model: "minimax-m2.7" },
147244
- { providers: ["github-copilot", "openai", "opencode"], model: "gpt-5.4-mini" }
147245
- ];
147246
- var SIDEKICK_FALLBACK_CHAIN = [
147247
- { providers: ["cerebras"], model: "qwen-3-235b-a22b-instruct-2507" },
147248
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
147249
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.4-mini" },
147250
- { providers: ["opencode"], model: "gpt-5-nano" }
147251
- ];
147252
- var AGENT_MODEL_REQUIREMENTS = {
147253
- [HISTORIAN_AGENT]: { fallbackChain: HISTORIAN_FALLBACK_CHAIN },
147254
- [HISTORIAN_EDITOR_AGENT]: { fallbackChain: HISTORIAN_FALLBACK_CHAIN },
147255
- [DREAMER_AGENT]: { fallbackChain: DREAMER_FALLBACK_CHAIN },
147256
- [SIDEKICK_AGENT]: { fallbackChain: SIDEKICK_FALLBACK_CHAIN }
147257
- };
147258
- function expandFallbackChain(chain) {
147259
- const models = [];
147260
- for (const entry of chain) {
147261
- for (const provider of entry.providers) {
147262
- models.push(`${provider}/${entry.model}`);
147263
- }
147264
- }
147265
- return models;
147266
- }
147267
- function getAgentFallbackModels(agent) {
147268
- const requirement = AGENT_MODEL_REQUIREMENTS[agent];
147269
- if (!requirement)
147270
- return;
147271
- return expandFallbackChain(requirement.fallbackChain);
147272
- }
147273
-
147274
147418
  // ../plugin/src/shared/models-dev-cache.ts
147275
147419
  init_data_path();
147276
147420
  init_logger();
@@ -147361,25 +147505,9 @@ function resolveHistorianContextLimit(historianModelOverride) {
147361
147505
  return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
147362
147506
  }
147363
147507
  if (typeof historianModelOverride === "string" && historianModelOverride.trim() !== "") {
147364
- console.warn(`[magic-context] historian.model "${historianModelOverride}" lacks provider prefix ("provider/model-id"); using fallback chain for chunk-budget derivation.`);
147508
+ console.warn(`[magic-context] historian.model "${historianModelOverride}" lacks provider prefix ("provider/model-id"); using the default context limit for chunk-budget derivation.`);
147365
147509
  }
147366
- const chain = AGENT_MODEL_REQUIREMENTS[HISTORIAN_AGENT]?.fallbackChain;
147367
- if (!chain || chain.length === 0)
147368
- return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
147369
- const expanded = expandFallbackChain(chain);
147370
- let minLimit;
147371
- for (const key of expanded) {
147372
- const [providerID, ...rest] = key.split("/");
147373
- const modelID = rest.join("/");
147374
- if (!providerID || !modelID)
147375
- continue;
147376
- const limit = getSdkContextLimit(providerID, modelID);
147377
- if (typeof limit !== "number" || limit <= 0)
147378
- continue;
147379
- if (minLimit === undefined || limit < minLimit)
147380
- minLimit = limit;
147381
- }
147382
- return minLimit ?? DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
147510
+ return DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
147383
147511
  }
147384
147512
 
147385
147513
  // ../plugin/src/hooks/magic-context/event-resolvers.ts
@@ -147792,13 +147920,13 @@ async function maybeSendUpgradeReminder(deps, sessionId) {
147792
147920
  init_data_path();
147793
147921
  import * as fs2 from "node:fs";
147794
147922
  import * as path6 from "node:path";
147795
- var ANNOUNCEMENT_VERSION = "0.25.0";
147923
+ var ANNOUNCEMENT_VERSION = "0.26.0";
147796
147924
  var ANNOUNCEMENT_FEATURES = [
147797
- "Old tool output is now reclaimed automatically: once a file read / search / command output has gone a full execute cycle unused, it's dropped on the next one — no need to call ctx_reduce for stale results.",
147798
- "Recover anything that was dropped: ctx_expand({ message: N }) returns a dropped message's full content (every tool call's input + output) from storage. ctx_expand({ start, end, verbose: true }) lists a range message-by-message to find it.",
147799
- "Searchable history made reliable: /ctx-embed shows embedding coverage and runs a resilient backfill (retries transient failures, no longer bails on the first hiccup); the active session now auto-embeds in the background. ctx_reduce guidance also reframed as deferred + recoverable so models trim spent output earlier.",
147800
- "Pi: fixed /ctx-dream (was failing with 'Unknown named parameter') and local-embedding load failures on Windows/Desktop (#151, #128).",
147801
- "Runaway background agents on weak/local models are now capped and force-stopped (#154, #152). Plus several prompt-cache busts removed."
147925
+ "Faster on large sessions: per-message transform overhead is at least 2x lower on typical passes and up to ~10x lower when history summarization fires (no more multi-second pause on big sessions).",
147926
+ "No more surprise models: the built-in fallback chain is gone. Hidden agents only use the model (and fallback_models) you configure — no confusing 'model not found' for providers you never set up. `doctor` now records every historian run so real failures are visible.",
147927
+ "Anthropic thinking-block fix: clearing old reasoning no longer risks a stale-signature rejection on Claude / Bedrock / proxied-Claude routes. Plus fewer prompt-cache busts.",
147928
+ "Community fixes: TUI crash on the upgrade progress panel (#168), historian.disallowed_tools for weak models that loop on tool calls (#166), and a Pi-only config key leak (#167).",
147929
+ "New: doctor migrate-session re-homes a session (and optionally its memories) to another project, with a dry-run preview."
147802
147930
  ];
147803
147931
  var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
147804
147932
  var STATE_FILENAME = "last_announced_version";
@@ -147857,15 +147985,9 @@ function shouldKeepSubagents() {
147857
147985
  init_logger();
147858
147986
 
147859
147987
  // ../plugin/src/shared/resolve-fallbacks.ts
147860
- function resolveFallbackChain(agentName, userFallbacks) {
147988
+ function resolveFallbackChain(userFallbacks) {
147861
147989
  const userList = normalizeUserFallbacks(userFallbacks);
147862
- if (userList.length > 0) {
147863
- return dedupe(userList.filter(isValidModelSpec));
147864
- }
147865
- const builtin = getAgentFallbackModels(agentName);
147866
- if (!builtin || builtin.length === 0)
147867
- return [];
147868
- return dedupe(builtin.filter(isValidModelSpec));
147990
+ return dedupe(userList.filter(isValidModelSpec));
147869
147991
  }
147870
147992
  function normalizeUserFallbacks(userFallbacks) {
147871
147993
  if (!userFallbacks)
@@ -148804,6 +148926,9 @@ init_logger();
148804
148926
  import { existsSync as existsSync8 } from "node:fs";
148805
148927
  import { join as join11 } from "node:path";
148806
148928
 
148929
+ // ../plugin/src/agents/dreamer.ts
148930
+ var DREAMER_AGENT = "dreamer";
148931
+
148807
148932
  // ../plugin/src/shared/index.ts
148808
148933
  init_logger();
148809
148934
 
@@ -150604,6 +150729,7 @@ ${modeIntro}
150604
150729
  4. **Write or update** using the Write tool. Always write to project root, NOT to .planning/.
150605
150730
 
150606
150731
  ### Rules
150732
+ - **NEVER touch protected regions**: any content between \`<!-- mc:protected START ... -->\` and \`<!-- mc:protected END -->\` is hand-authored and cache-critical. Reproduce it BYTE-FOR-BYTE in your rewrite — do not edit, reword, reorder, summarize, trim, or drop a single line of it, and keep the marker comments themselves. Only a human edits that region.
150607
150733
  - **Be prescriptive**: "Use X pattern" not "X pattern is used"
150608
150734
  - **Always include file paths** in backticks
150609
150735
  - **Write current state only**: no temporal language, no history
@@ -166242,14 +166368,16 @@ var SidekickConfigSchema = AgentOverrideConfigSchema.extend({
166242
166368
  }).optional();
166243
166369
  var HistorianConfigSchema = AgentOverrideConfigSchema.extend({
166244
166370
  two_pass: exports_external.boolean().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
166245
- thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh")
166371
+ thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh"),
166372
+ disallowed_tools: exports_external.array(exports_external.enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"])).default([]).describe(`OpenCode only. Tools to REMOVE from the historian's default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])`)
166246
166373
  }).optional();
166247
166374
  var BaseEmbeddingConfigSchema = exports_external.object({
166248
166375
  provider: exports_external.enum(["local", "openai-compatible", "off"]).default("local").describe("Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'off' disables embeddings."),
166249
166376
  model: exports_external.string().optional().describe("Embedding model name. Required for openai-compatible, ignored for local."),
166250
166377
  endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
166251
166378
  api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
166252
- input_type: exports_external.string().optional().describe("Optional input_type sent in the embedding request body. Required by some openai-compatible providers (e.g. NVIDIA NIM expects 'query' or 'passage'). Omitted from the request when unset."),
166379
+ input_type: exports_external.string().optional().describe("Default input_type for stored/indexed (passage) embeddings in the request body. Required by some openai-compatible providers (e.g. NVIDIA NIM). Omitted from the request when unset."),
166380
+ query_input_type: exports_external.string().optional().describe("Optional input_type for query (search) embeddings on asymmetric models (e.g. NVIDIA NIM 'query'). When unset, query embeddings use embedding.input_type. Passage/stored content always uses embedding.input_type."),
166253
166381
  truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset."),
166254
166382
  max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
166255
166383
  }).superRefine((data, ctx) => {
@@ -166279,6 +166407,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
166279
166407
  if (data.provider === "openai-compatible") {
166280
166408
  const apiKey = data.api_key?.trim();
166281
166409
  const inputType = data.input_type?.trim();
166410
+ const queryInputType = data.query_input_type?.trim();
166282
166411
  const truncate = data.truncate?.trim();
166283
166412
  return {
166284
166413
  provider: "openai-compatible",
@@ -166286,6 +166415,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
166286
166415
  endpoint: data.endpoint?.trim() ?? "",
166287
166416
  ...apiKey ? { api_key: apiKey } : {},
166288
166417
  ...inputType ? { input_type: inputType } : {},
166418
+ ...queryInputType ? { query_input_type: queryInputType } : {},
166289
166419
  ...truncate ? { truncate } : {},
166290
166420
  ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
166291
166421
  };
@@ -166562,6 +166692,16 @@ function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal)
166562
166692
  return lines.join(`
166563
166693
  `);
166564
166694
  }
166695
+ function buildCompartmentSummaryFallbackText(db, compartmentId) {
166696
+ const row = db.prepare("SELECT title, p1, content FROM compartments WHERE id = ?").get(compartmentId);
166697
+ if (!row)
166698
+ return "";
166699
+ const title = typeof row.title === "string" ? row.title.trim() : "";
166700
+ const p1 = typeof row.p1 === "string" ? row.p1.trim() : "";
166701
+ const body = p1.length > 0 ? p1 : typeof row.content === "string" ? row.content.trim() : "";
166702
+ return [title, body].filter((s) => s.length > 0).join(`
166703
+ `);
166704
+ }
166565
166705
  function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
166566
166706
  const lines = [];
166567
166707
  for (const rawLine of chunkText.split(/\r?\n/)) {
@@ -167146,7 +167286,7 @@ class LocalEmbeddingProvider {
167146
167286
  waiter();
167147
167287
  }
167148
167288
  }
167149
- async embed(text, signal) {
167289
+ async embed(text, signal, _purpose) {
167150
167290
  if (signal?.aborted)
167151
167291
  return null;
167152
167292
  if (this.disposing)
@@ -167172,7 +167312,7 @@ class LocalEmbeddingProvider {
167172
167312
  this.finishInFlight();
167173
167313
  }
167174
167314
  }
167175
- async embedBatch(texts, signal) {
167315
+ async embedBatch(texts, signal, _purpose) {
167176
167316
  if (texts.length === 0) {
167177
167317
  return [];
167178
167318
  }
@@ -167311,6 +167451,7 @@ class OpenAICompatibleEmbeddingProvider {
167311
167451
  model;
167312
167452
  apiKey;
167313
167453
  inputType;
167454
+ queryInputType;
167314
167455
  truncate;
167315
167456
  initialized = false;
167316
167457
  failureTimes = [];
@@ -167323,6 +167464,7 @@ class OpenAICompatibleEmbeddingProvider {
167323
167464
  this.model = options.model?.trim() ?? "";
167324
167465
  this.apiKey = options.apiKey?.trim() ?? "";
167325
167466
  this.inputType = options.inputType?.trim() ?? "";
167467
+ this.queryInputType = options.queryInputType?.trim() ?? "";
167326
167468
  this.truncate = options.truncate?.trim() ?? "";
167327
167469
  this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
167328
167470
  this.modelId = getEmbeddingProviderIdentity({
@@ -167350,11 +167492,17 @@ class OpenAICompatibleEmbeddingProvider {
167350
167492
  this.initialized = true;
167351
167493
  return true;
167352
167494
  }
167353
- async embed(text, signal) {
167354
- const [embedding] = await this.embedBatch([text], signal);
167495
+ resolveInputTypeForPurpose(purpose = "passage") {
167496
+ if (purpose === "query") {
167497
+ return this.queryInputType || this.inputType;
167498
+ }
167499
+ return this.inputType;
167500
+ }
167501
+ async embed(text, signal, purpose) {
167502
+ const [embedding] = await this.embedBatch([text], signal, purpose);
167355
167503
  return embedding ?? null;
167356
167504
  }
167357
- async embedBatch(texts, signal) {
167505
+ async embedBatch(texts, signal, purpose) {
167358
167506
  if (texts.length === 0) {
167359
167507
  return [];
167360
167508
  }
@@ -167380,6 +167528,7 @@ class OpenAICompatibleEmbeddingProvider {
167380
167528
  if (signal) {
167381
167529
  signal.addEventListener("abort", onOuterAbort, { once: true });
167382
167530
  }
167531
+ const inputTypeForRequest = this.resolveInputTypeForPurpose(purpose);
167383
167532
  const response = await fetch(`${this.endpoint}/embeddings`, {
167384
167533
  method: "POST",
167385
167534
  headers: {
@@ -167389,7 +167538,7 @@ class OpenAICompatibleEmbeddingProvider {
167389
167538
  body: JSON.stringify({
167390
167539
  model: this.model,
167391
167540
  input: texts,
167392
- ...this.inputType ? { input_type: this.inputType } : {},
167541
+ ...inputTypeForRequest ? { input_type: inputTypeForRequest } : {},
167393
167542
  ...this.truncate ? { truncate: this.truncate } : {}
167394
167543
  }),
167395
167544
  redirect: "error",
@@ -167963,6 +168112,7 @@ function resolveEmbeddingConfig(config2) {
167963
168112
  if (config2.provider === "openai-compatible") {
167964
168113
  const apiKey = config2.api_key?.trim();
167965
168114
  const inputType = config2.input_type?.trim();
168115
+ const queryInputType = config2.query_input_type?.trim();
167966
168116
  const truncate = config2.truncate?.trim();
167967
168117
  return {
167968
168118
  provider: "openai-compatible",
@@ -167970,6 +168120,7 @@ function resolveEmbeddingConfig(config2) {
167970
168120
  endpoint: config2.endpoint.trim(),
167971
168121
  ...apiKey ? { api_key: apiKey } : {},
167972
168122
  ...inputType ? { input_type: inputType } : {},
168123
+ ...queryInputType ? { query_input_type: queryInputType } : {},
167973
168124
  ...truncate ? { truncate } : {},
167974
168125
  ...config2.max_input_tokens ? {
167975
168126
  max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
@@ -167991,6 +168142,7 @@ function createProvider(config2) {
167991
168142
  model: config2.model,
167992
168143
  apiKey: config2.api_key,
167993
168144
  inputType: config2.input_type,
168145
+ queryInputType: config2.query_input_type,
167994
168146
  truncate: config2.truncate,
167995
168147
  maxInputTokens: config2.max_input_tokens
167996
168148
  });
@@ -168173,7 +168325,7 @@ function getOrCreateProjectProvider(registration) {
168173
168325
  registration.provider = provider;
168174
168326
  return provider;
168175
168327
  }
168176
- async function embedTextForProject(projectIdentity, text, signal) {
168328
+ async function embedTextForProject(projectIdentity, text, signal, purpose = "passage") {
168177
168329
  const registration = projectRegistrations.get(projectIdentity);
168178
168330
  if (!registration)
168179
168331
  return null;
@@ -168182,7 +168334,7 @@ async function embedTextForProject(projectIdentity, text, signal) {
168182
168334
  const provider = getOrCreateProjectProvider(registration);
168183
168335
  if (!provider)
168184
168336
  return null;
168185
- const vector = await provider.embed(text, signal);
168337
+ const vector = await provider.embed(text, signal, purpose);
168186
168338
  if (!vector)
168187
168339
  return null;
168188
168340
  const current = projectRegistrations.get(projectIdentity);
@@ -168191,7 +168343,7 @@ async function embedTextForProject(projectIdentity, text, signal) {
168191
168343
  }
168192
168344
  return { vector, modelId, generation };
168193
168345
  }
168194
- async function embedBatchForProject(projectIdentity, texts, signal) {
168346
+ async function embedBatchForProject(projectIdentity, texts, signal, purpose = "passage") {
168195
168347
  if (texts.length === 0) {
168196
168348
  const registration2 = projectRegistrations.get(projectIdentity);
168197
168349
  if (!registration2 || registration2.observationMode)
@@ -168207,7 +168359,7 @@ async function embedBatchForProject(projectIdentity, texts, signal) {
168207
168359
  const provider = getOrCreateProjectProvider(registration);
168208
168360
  if (!provider)
168209
168361
  return null;
168210
- const vectors = await provider.embedBatch(texts, signal);
168362
+ const vectors = await provider.embedBatch(texts, signal, purpose);
168211
168363
  const current = projectRegistrations.get(projectIdentity);
168212
168364
  if (!current || current.generation !== generation || current.runtimeFingerprint !== runtimeFingerprint) {
168213
168365
  return null;
@@ -168264,7 +168416,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
168264
168416
  const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
168265
168417
  const prepared = [];
168266
168418
  for (const candidate of candidates) {
168267
- const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
168419
+ const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage) || buildCompartmentSummaryFallbackText(db, candidate.id);
168268
168420
  if (canonicalText.length === 0) {
168269
168421
  noWork.push(candidate.id);
168270
168422
  continue;
@@ -168473,6 +168625,7 @@ function createProvider2(config2) {
168473
168625
  model: config2.model,
168474
168626
  apiKey: config2.api_key,
168475
168627
  inputType: config2.input_type,
168628
+ queryInputType: config2.query_input_type,
168476
168629
  truncate: config2.truncate,
168477
168630
  maxInputTokens: config2.max_input_tokens
168478
168631
  });
@@ -168909,7 +169062,7 @@ async function sweepProject(reg, origin, db, gitCommitEnabled = getProjectEmbedd
168909
169062
  experimentalPinKeyFiles: reg.experimentalPinKeyFiles,
168910
169063
  projectIdentity: reg.projectIdentity,
168911
169064
  sessionDirectoryOverride: reg.directory,
168912
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, reg.dreamerConfig.fallback_models)
169065
+ fallbackModels: resolveFallbackChain(reg.dreamerConfig.fallback_models)
168913
169066
  });
168914
169067
  } catch (error51) {
168915
169068
  log(`[dreamer] timer-triggered queue processing failed for ${reg.projectIdentity}:`, error51);
@@ -169785,7 +169938,7 @@ async function awaitInFlightDreamers() {
169785
169938
  function createPiDreamerClient(opts) {
169786
169939
  const runner2 = piSubagentRunnerFactory();
169787
169940
  const model = opts.config.model;
169788
- const fallbackModels = resolveFallbackChain(DREAMER_AGENT, opts.config.fallback_models);
169941
+ const fallbackModels = resolveFallbackChain(opts.config.fallback_models);
169789
169942
  const session = {
169790
169943
  create: async (args) => {
169791
169944
  const sessionId = `magic-context-pi-dream-${++sessionCounter}`;
@@ -170346,10 +170499,9 @@ function makeToolCompositeKey(ownerMsgId, callId) {
170346
170499
  }
170347
170500
  var GET_COUNTER_SQL = `SELECT counter FROM session_meta WHERE session_id = ?`;
170348
170501
  var GET_ASSIGNMENTS_SQL = "SELECT message_id, tag_number, type, tool_owner_message_id FROM tags WHERE session_id = ? ORDER BY tag_number ASC";
170502
+ var GET_ASSIGNMENTS_SCOPED_SQL = "SELECT message_id, tag_number, type, tool_owner_message_id FROM tags WHERE session_id = ? AND tag_number >= ? ORDER BY tag_number ASC";
170349
170503
  var PROBE_DATA_VERSION_SQL = "PRAGMA main.data_version";
170350
- var PROBE_TOTAL_CHANGES_SQL = "SELECT total_changes() AS tc";
170351
170504
  var probeDataVersionStatements = new WeakMap;
170352
- var probeTotalChangesStatements = new WeakMap;
170353
170505
  function getProbeDataVersionStatement(db) {
170354
170506
  let stmt = probeDataVersionStatements.get(db);
170355
170507
  if (!stmt) {
@@ -170358,14 +170510,6 @@ function getProbeDataVersionStatement(db) {
170358
170510
  }
170359
170511
  return stmt;
170360
170512
  }
170361
- function getProbeTotalChangesStatement(db) {
170362
- let stmt = probeTotalChangesStatements.get(db);
170363
- if (!stmt) {
170364
- stmt = db.prepare(PROBE_TOTAL_CHANGES_SQL);
170365
- probeTotalChangesStatements.set(db, stmt);
170366
- }
170367
- return stmt;
170368
- }
170369
170513
  function isAssignmentRow(row) {
170370
170514
  if (row === null || typeof row !== "object") {
170371
170515
  return false;
@@ -170558,20 +170702,18 @@ function createTagger() {
170558
170702
  }
170559
170703
  function probeSignature(db) {
170560
170704
  const dvRow = getProbeDataVersionStatement(db).get();
170561
- const tcRow = getProbeTotalChangesStatement(db).get();
170562
170705
  return {
170563
- dataVersion: dvRow?.data_version ?? 0,
170564
- totalChanges: tcRow?.tc ?? 0
170706
+ dataVersion: dvRow?.data_version ?? 0
170565
170707
  };
170566
170708
  }
170567
- function initFromDb(sessionId, db) {
170709
+ function initFromDb(sessionId, db, floor = 0) {
170568
170710
  const probe = probeSignature(db);
170569
170711
  const cached2 = loadSignatures.get(sessionId);
170570
- if (cached2 !== undefined && cached2.db === db && cached2.dataVersion === probe.dataVersion && cached2.totalChanges === probe.totalChanges) {
170712
+ if (cached2 !== undefined && cached2.db === db && cached2.dataVersion === probe.dataVersion && cached2.floor === floor) {
170571
170713
  return;
170572
170714
  }
170573
170715
  const row = db.prepare(GET_COUNTER_SQL).get(sessionId);
170574
- const assignmentRows = db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId).filter(isAssignmentRow);
170716
+ const assignmentRows = (floor > 0 ? db.prepare(GET_ASSIGNMENTS_SCOPED_SQL).all(sessionId, floor) : db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId)).filter(isAssignmentRow);
170575
170717
  const sessionAssignments = getSessionAssignments(sessionId);
170576
170718
  sessionAssignments.clear();
170577
170719
  let maxTagNumber = 0;
@@ -170592,7 +170734,7 @@ function createTagger() {
170592
170734
  loadSignatures.set(sessionId, {
170593
170735
  db,
170594
170736
  dataVersion: probe.dataVersion,
170595
- totalChanges: probe.totalChanges
170737
+ floor
170596
170738
  });
170597
170739
  }
170598
170740
  function cleanup(sessionId) {
@@ -170616,6 +170758,162 @@ function createTagger() {
170616
170758
  };
170617
170759
  }
170618
170760
 
170761
+ // ../plugin/src/features/magic-context/transform-decision-log.ts
170762
+ var canonicalReasons = new Set([
170763
+ "system_hash",
170764
+ "model_change",
170765
+ "project_memory_epoch",
170766
+ "ttl_idle",
170767
+ "explicit_flush",
170768
+ "max_mutation_id",
170769
+ "first_render",
170770
+ "pressure_refold",
170771
+ "upgrade_state",
170772
+ "cached_m1_missing"
170773
+ ]);
170774
+ var piReasonAliases = {
170775
+ project_memory_change: "project_memory_epoch",
170776
+ pending_mutations: "max_mutation_id",
170777
+ renderer_upgrade: "upgrade_state",
170778
+ cache_invalid: "cached_m1_missing",
170779
+ drift: "pressure_refold"
170780
+ };
170781
+ var sharedReasonAliases = {
170782
+ model_key: "model_change",
170783
+ pressure: "pressure_refold"
170784
+ };
170785
+ var pendingDecisionBySession = new Map;
170786
+ var pendingPiDecisionBySession = new Map;
170787
+ var lastBoundMessageIdBySession = new Map;
170788
+ var scheduledWriteTokensBySession = new Map;
170789
+ var writerOverrideForTests = null;
170790
+ function normalizeMaterializeReason(harness, reason, rematerialized) {
170791
+ const raw = typeof reason === "string" ? reason.trim() : "";
170792
+ if (raw.length > 0) {
170793
+ const alias = sharedReasonAliases[raw] ?? (harness === "pi" ? piReasonAliases[raw] : undefined) ?? undefined;
170794
+ if (alias)
170795
+ return alias;
170796
+ if (canonicalReasons.has(raw))
170797
+ return raw;
170798
+ return null;
170799
+ }
170800
+ return rematerialized ? "pressure_refold" : null;
170801
+ }
170802
+ function recordPendingPiTransformDecision(sessionId, decision, snapshotNewestAssistantEntryId) {
170803
+ if (!decision.bustedThisPass)
170804
+ return;
170805
+ pendingPiDecisionBySession.set(sessionId, {
170806
+ ...decision,
170807
+ snapshotNewestAssistantEntryId
170808
+ });
170809
+ }
170810
+ function findNewestPiAssistantEntryId(entries) {
170811
+ if (!Array.isArray(entries))
170812
+ return null;
170813
+ for (let i = entries.length - 1;i >= 0; i--) {
170814
+ const entry = entries[i];
170815
+ if (!entry || typeof entry !== "object")
170816
+ continue;
170817
+ const row = entry;
170818
+ if (row.type !== "message" || typeof row.id !== "string" || row.id.length === 0) {
170819
+ continue;
170820
+ }
170821
+ const message = row.message;
170822
+ if (message && typeof message === "object" && message.role === "assistant") {
170823
+ return row.id;
170824
+ }
170825
+ }
170826
+ return null;
170827
+ }
170828
+ function schedulePiTransformDecisionResolve(args) {
170829
+ const pending = pendingPiDecisionBySession.get(args.sessionId);
170830
+ if (!pending)
170831
+ return false;
170832
+ const targetMessageId = findNewestPiAssistantEntryIdAfter(args.branchEntries, pending.snapshotNewestAssistantEntryId);
170833
+ if (!targetMessageId)
170834
+ return false;
170835
+ const dbPath = getDatabasePath(args.db);
170836
+ if (!dbPath)
170837
+ return false;
170838
+ pendingPiDecisionBySession.delete(args.sessionId);
170839
+ const token = addScheduledWriteToken(args.sessionId);
170840
+ setTimeout(() => {
170841
+ try {
170842
+ if (!hasScheduledWriteToken(args.sessionId, token))
170843
+ return;
170844
+ writeTransformDecisionBestEffort(dbPath, {
170845
+ ...pending,
170846
+ sessionId: args.sessionId,
170847
+ harness: "pi",
170848
+ messageId: targetMessageId
170849
+ });
170850
+ } finally {
170851
+ deleteScheduledWriteToken(args.sessionId, token);
170852
+ }
170853
+ }, 0);
170854
+ return true;
170855
+ }
170856
+ function addScheduledWriteToken(sessionId) {
170857
+ const token = Symbol(sessionId);
170858
+ let tokens = scheduledWriteTokensBySession.get(sessionId);
170859
+ if (!tokens) {
170860
+ tokens = new Set;
170861
+ scheduledWriteTokensBySession.set(sessionId, tokens);
170862
+ }
170863
+ tokens.add(token);
170864
+ return token;
170865
+ }
170866
+ function hasScheduledWriteToken(sessionId, token) {
170867
+ return scheduledWriteTokensBySession.get(sessionId)?.has(token) === true;
170868
+ }
170869
+ function deleteScheduledWriteToken(sessionId, token) {
170870
+ const tokens = scheduledWriteTokensBySession.get(sessionId);
170871
+ if (!tokens)
170872
+ return;
170873
+ tokens.delete(token);
170874
+ if (tokens.size === 0)
170875
+ scheduledWriteTokensBySession.delete(sessionId);
170876
+ }
170877
+ function findNewestPiAssistantEntryIdAfter(entries, snapshotNewestAssistantEntryId) {
170878
+ if (!Array.isArray(entries))
170879
+ return null;
170880
+ for (let i = entries.length - 1;i >= 0; i--) {
170881
+ const entry = entries[i];
170882
+ if (!entry || typeof entry !== "object")
170883
+ continue;
170884
+ const row = entry;
170885
+ if (row.type !== "message" || typeof row.id !== "string" || row.id.length === 0) {
170886
+ continue;
170887
+ }
170888
+ if (snapshotNewestAssistantEntryId !== null && row.id === snapshotNewestAssistantEntryId) {
170889
+ continue;
170890
+ }
170891
+ const message = row.message;
170892
+ if (message && typeof message === "object" && message.role === "assistant") {
170893
+ return row.id;
170894
+ }
170895
+ }
170896
+ return null;
170897
+ }
170898
+ function writeTransformDecisionBestEffort(dbPath, row) {
170899
+ try {
170900
+ const writer = writerOverrideForTests ?? writeTransformDecisionRow;
170901
+ writer(dbPath, row);
170902
+ } catch {}
170903
+ }
170904
+ function writeTransformDecisionRow(dbPath, row) {
170905
+ const db = new Database(dbPath);
170906
+ try {
170907
+ db.exec("PRAGMA busy_timeout=0");
170908
+ db.prepare(`INSERT OR REPLACE INTO transform_decisions (
170909
+ session_id, harness, message_id, ts_ms, decision, materialized,
170910
+ materialize_reason, emergency, dropped_tokens, dropped_count, input_tokens
170911
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(row.sessionId, row.harness, row.messageId, row.tsMs, row.decision, row.materialized ? 1 : 0, row.materializeReason, row.emergency ? 1 : 0, Math.max(0, Math.floor(row.droppedTokens)), Math.max(0, Math.floor(row.droppedCount)), Math.max(0, Math.floor(row.inputTokens)));
170912
+ } finally {
170913
+ closeQuietly(db);
170914
+ }
170915
+ }
170916
+
170619
170917
  // ../plugin/src/features/magic-context/work-metrics.ts
170620
170918
  function asNumber2(value) {
170621
170919
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
@@ -171947,7 +172245,7 @@ function resolveBoundaryContext(args) {
171947
172245
  }
171948
172246
  let storedTokenTotals;
171949
172247
  try {
171950
- storedTokenTotals = getAllStatusTagTokenTotalsFlat(args.db, args.sessionId).totals;
172248
+ storedTokenTotals = getAllStatusTagTokenTotalsFlat(args.db, args.sessionId, args.taggerFloor ?? 0).totals;
171951
172249
  } catch (error51) {
171952
172250
  sessionLog(args.sessionId, "protected-tail stored-token map unavailable (live fallback):", error51);
171953
172251
  }
@@ -172064,6 +172362,38 @@ var DEFAULT_MIN_COMMIT_CLUSTERS_FOR_TRIGGER = 3;
172064
172362
  var TAIL_SIZE_TRIGGER_MULTIPLIER = 3;
172065
172363
  var FORCE_COMPARTMENT_PERCENTAGE = 80;
172066
172364
  var BLOCK_UNTIL_DONE_PERCENTAGE = 95;
172365
+ var CONTENT_TAG_OWNER_SUFFIX = /:(?:p|file)\d+$/;
172366
+ function tagOwnerMessageId(row) {
172367
+ if (row.type === "tool")
172368
+ return row.tool_owner_message_id ?? row.message_id;
172369
+ return row.message_id.replace(CONTENT_TAG_OWNER_SUFFIX, "");
172370
+ }
172371
+ function getActiveOrDroppedTagOwnerMessageIds(db, sessionId, floor = 0) {
172372
+ const rows = floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id
172373
+ FROM tags
172374
+ WHERE session_id = ? AND status IN ('active', 'dropped') AND tag_number >= ?`).all(sessionId, floor) : db.prepare(`SELECT type, message_id, tool_owner_message_id
172375
+ FROM tags
172376
+ WHERE session_id = ? AND status IN ('active', 'dropped')`).all(sessionId);
172377
+ const owners = new Set;
172378
+ for (const row of rows)
172379
+ owners.add(tagOwnerMessageId(row));
172380
+ return owners;
172381
+ }
172382
+ function estimateUntaggedInMemoryTailUpperBound(db, sessionId, inMemoryTail, taggerFloor = 0) {
172383
+ const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
172384
+ const coveredOwnerMessageIds = getActiveOrDroppedTagOwnerMessageIds(db, sessionId, taggerFloor);
172385
+ let total = 0;
172386
+ for (const message of inMemoryTail.messages) {
172387
+ if (message.ordinal <= lastCompartmentEnd)
172388
+ continue;
172389
+ if (coveredOwnerMessageIds.has(message.id))
172390
+ continue;
172391
+ total += estimateTrueRawMessageTokens(message, {
172392
+ providerShapeVersion: "opencode-v1"
172393
+ }).total;
172394
+ }
172395
+ return total;
172396
+ }
172067
172397
  function getProactiveCompartmentTriggerPercentage(executeThresholdPercentage) {
172068
172398
  return Math.max(0, executeThresholdPercentage - PROACTIVE_TRIGGER_OFFSET_PERCENTAGE);
172069
172399
  }
@@ -172117,7 +172447,7 @@ function resolveBoundaryContextLimit(usage, fallbackContextLimit) {
172117
172447
  }
172118
172448
  return 128000;
172119
172449
  }
172120
- function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail) {
172450
+ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail, taggerFloor = 0) {
172121
172451
  return withRawSessionMessageCache(() => {
172122
172452
  try {
172123
172453
  const memoryPrimed = inMemoryTail ? primeInMemoryTailRawMessageCache({
@@ -172146,7 +172476,8 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
172146
172476
  contextLimit: resolveBoundaryContextLimit(usage, contextLimit),
172147
172477
  executeThresholdPercentage,
172148
172478
  usage,
172149
- usageSource: "live"
172479
+ usageSource: "live",
172480
+ taggerFloor
172150
172481
  });
172151
172482
  const hasProtectedEligibleHead = boundary.offset < boundary.protectedTailStart;
172152
172483
  if (!hasProtectedEligibleHead) {
@@ -172177,7 +172508,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
172177
172508
  }
172178
172509
  });
172179
172510
  }
172180
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail) {
172511
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride) {
172181
172512
  if (sessionMeta.compartmentInProgress) {
172182
172513
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
172183
172514
  return { shouldFire: false };
@@ -172191,14 +172522,17 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
172191
172522
  inMemoryTail = undefined;
172192
172523
  }
172193
172524
  }
172525
+ const taggerFloor = taggerFloorOverride !== undefined && taggerFloorOverride > 0 ? taggerFloorOverride : inMemoryTail ? deriveTagLoadFloor(db, sessionId, inMemoryTail.messages.map((m) => m.id)) : 0;
172194
172526
  const proactiveFloorForGate = getProactiveCompartmentTriggerPercentage(executeThresholdPercentage);
172195
- if (!inMemoryTail && usage.percentage < proactiveFloorForGate) {
172527
+ if (usage.percentage < proactiveFloorForGate) {
172196
172528
  try {
172197
- const { bound, nullCount } = getTriggerTagTokenUpperBound(db, sessionId);
172529
+ const { bound: persistedBound, nullCount } = getTriggerTagTokenUpperBound(db, sessionId, taggerFloor);
172198
172530
  if (nullCount === 0) {
172199
- const eligibleUpperBound = bound;
172531
+ const untaggedUpperBound = inMemoryTail ? estimateUntaggedInMemoryTailUpperBound(db, sessionId, inMemoryTail, taggerFloor) : 0;
172532
+ const eligibleUpperBound = persistedBound + untaggedUpperBound;
172200
172533
  if (eligibleUpperBound < triggerBudget) {
172201
- sessionLog(sessionId, `compartment trigger: cheap-skip at ${usage.percentage.toFixed(1)}% (below proactive floor ${proactiveFloorForGate}%) — live-tail upper bound ${eligibleUpperBound} < triggerBudget ${triggerBudget}; no size trigger possible, skipped full raw read`);
172534
+ const memorySuffix = inMemoryTail ? ` (persisted=${persistedBound}, untagged-memory≤${untaggedUpperBound})` : "";
172535
+ sessionLog(sessionId, `compartment trigger: cheap-skip at ${usage.percentage.toFixed(1)}% (below proactive floor ${proactiveFloorForGate}%) — live-tail upper bound ${eligibleUpperBound}${memorySuffix} < triggerBudget ${triggerBudget}; no size trigger possible, skipped full raw read`);
172202
172536
  return { shouldFire: false };
172203
172537
  }
172204
172538
  }
@@ -172206,7 +172540,7 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
172206
172540
  sessionLog(sessionId, `compartment trigger: cheap-gate skipped (falling through to full read): ${error51 instanceof Error ? error51.message : String(error51)}`);
172207
172541
  }
172208
172542
  }
172209
- const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail);
172543
+ const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThresholdPercentage, contextLimit, inMemoryTail, taggerFloor);
172210
172544
  if (!tailInfo.hasNewRawHistory) {
172211
172545
  try {
172212
172546
  const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
@@ -174520,7 +174854,7 @@ async function runAutoSearchHintForPi(args) {
174520
174854
  embeddingEnabled,
174521
174855
  gitCommitsEnabled,
174522
174856
  embedQuery: async (text, signal) => {
174523
- const result = await embedTextForProject(options.projectPath, text, signal);
174857
+ const result = await embedTextForProject(options.projectPath, text, signal, "query");
174524
174858
  return result?.vector ?? null;
174525
174859
  },
174526
174860
  isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
@@ -175150,6 +175484,7 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config2, pr
175150
175484
  const protectedCutoff = maxTag - config2.protectedTags;
175151
175485
  const toolAgeCutoff = protectedCutoff;
175152
175486
  let droppedTools = 0;
175487
+ let emergencyDroppedTools = 0;
175153
175488
  let deduplicatedTools = 0;
175154
175489
  let droppedInjections = 0;
175155
175490
  let droppedStaleReduceCalls = 0;
@@ -175182,6 +175517,7 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config2, pr
175182
175517
  updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
175183
175518
  updateTagDropMode(db, sessionId, tag.tagNumber, "full");
175184
175519
  droppedTools++;
175520
+ emergencyDroppedTools++;
175185
175521
  }
175186
175522
  }
175187
175523
  setEmergencyDropSample(db, sessionId, emergency.currentTotalInputTokens);
@@ -175310,6 +175646,7 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config2, pr
175310
175646
  deduplicatedTools,
175311
175647
  droppedInjections,
175312
175648
  droppedStaleReduceCalls,
175649
+ emergencyDroppedTools,
175313
175650
  compressedTextTags,
175314
175651
  mutatedTextTags
175315
175652
  };
@@ -176607,7 +176944,7 @@ async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compar
176607
176944
  for (const compartment of compartments) {
176608
176945
  try {
176609
176946
  const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
176610
- const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
176947
+ const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage) || buildCompartmentSummaryFallbackText(db, compartment.id);
176611
176948
  if (canonicalText.length === 0)
176612
176949
  continue;
176613
176950
  const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
@@ -179800,6 +180137,7 @@ async function runPiHistorian(deps) {
179800
180137
  } else {
179801
180138
  recordHighPressureNoEligibleHead(db, boundarySnapshot);
179802
180139
  }
180140
+ clearEmergencyDrainLatch(db, sessionId);
179803
180141
  return;
179804
180142
  }
179805
180143
  const perRunCap = selectPerRunCap(boundarySnapshot);
@@ -179811,7 +180149,8 @@ async function runPiHistorian(deps) {
179811
180149
  trueRawTokens: boundarySnapshot.trueRawEligibleTokens,
179812
180150
  usagePercentage: boundarySnapshot.usagePercentage,
179813
180151
  usable,
179814
- perRunCap
180152
+ perRunCap,
180153
+ executeThresholdPercentage: boundarySnapshot.executeThresholdPercentage
179815
180154
  });
179816
180155
  if (!reserve.ok) {
179817
180156
  sessionLog(sessionId, `historian rate-limit skip: ${reserve.skippedReason ?? "quota exhausted"}`);
@@ -179828,6 +180167,7 @@ async function runPiHistorian(deps) {
179828
180167
  } else {
179829
180168
  recordHighPressureNoEligibleHead(db, boundarySnapshot);
179830
180169
  }
180170
+ clearEmergencyDrainLatch(db, sessionId);
179831
180171
  telemetry.status = "noop";
179832
180172
  telemetry.failureReason = "chunk empty after filtering";
179833
180173
  rollbackDrainReservation();
@@ -180059,6 +180399,7 @@ ${chunkText}`,
180059
180399
  }
180060
180400
  appendCompartments(db, sessionId, newCompartments);
180061
180401
  clearHistorianFailureState(db, sessionId);
180402
+ clearHistorianDrainFailure(db, sessionId);
180062
180403
  recordProtectedTailPublicationFloor(db, sessionId, lastNewEnd + 1);
180063
180404
  clearEmergencyRecovery(db, sessionId);
180064
180405
  if (firstKeptEntryId && lastNewEndMessageId) {
@@ -180155,8 +180496,12 @@ ${chunkText}`,
180155
180496
  await notify(buildHistorianFailureNotice(failCount, desc.brief));
180156
180497
  }
180157
180498
  } finally {
180158
- if (!completedSuccessfully && !retainDrainReservationForRetryThrottle) {
180159
- rollbackDrainReservation();
180499
+ if (!completedSuccessfully) {
180500
+ if (!retainDrainReservationForRetryThrottle) {
180501
+ rollbackDrainReservation();
180502
+ } else {
180503
+ recordHistorianDrainFailure(db, sessionId);
180504
+ }
180160
180505
  }
180161
180506
  updateSessionMeta(db, sessionId, { compartmentInProgress: false });
180162
180507
  try {
@@ -180395,7 +180740,7 @@ var INLINE_THINKING_PATTERNS = [
180395
180740
  /<thinking>[\s\S]*?<\/thinking>\s*/gi,
180396
180741
  /<think>[\s\S]*?<\/think>\s*/gi
180397
180742
  ];
180398
- var CLEARED = "[cleared]";
180743
+ var CLEARED = "";
180399
180744
  function stripInlineThinkingMarkup(text) {
180400
180745
  let cleaned = text;
180401
180746
  for (const pattern of INLINE_THINKING_PATTERNS) {
@@ -180444,8 +180789,11 @@ function clearOldReasoningPi(args) {
180444
180789
  for (const part of msg.content) {
180445
180790
  if (part && typeof part === "object" && part.type === "thinking") {
180446
180791
  const tp = part;
180447
- if (tp.thinking !== CLEARED) {
180792
+ if (tp.redacted)
180793
+ continue;
180794
+ if (tp.thinking !== CLEARED || tp.thinkingSignature !== undefined) {
180448
180795
  tp.thinking = CLEARED;
180796
+ tp.thinkingSignature = undefined;
180449
180797
  cleared++;
180450
180798
  }
180451
180799
  }
@@ -180523,8 +180871,11 @@ function replayClearedReasoningPi(args) {
180523
180871
  for (const part of msg.content) {
180524
180872
  if (part && typeof part === "object" && part.type === "thinking") {
180525
180873
  const tp = part;
180526
- if (tp.thinking !== CLEARED) {
180874
+ if (tp.redacted)
180875
+ continue;
180876
+ if (tp.thinking !== CLEARED || tp.thinkingSignature !== undefined) {
180527
180877
  tp.thinking = CLEARED;
180878
+ tp.thinkingSignature = undefined;
180528
180879
  cleared++;
180529
180880
  }
180530
180881
  }
@@ -181839,6 +182190,11 @@ function registerPiContextHandler(pi, baseOptions) {
181839
182190
  updateSessionProjectTracking(sessionId, projectIdentity, options.db);
181840
182191
  logTransformTiming(sessionId, "findSessionId", tFindSession, `messages=${event.messages.length}`);
181841
182192
  const branchEntries = readPiBranchEntriesForContext(ctx, sessionId);
182193
+ schedulePiTransformDecisionResolve({
182194
+ db: options.db,
182195
+ sessionId,
182196
+ branchEntries
182197
+ });
181842
182198
  const rawMessageProvider = {
181843
182199
  readMessages: () => branchEntries !== null ? convertEntriesToRawMessages([...branchEntries]) : readPiSessionMessages(ctx),
181844
182200
  readMessageById: (messageId) => readPiSessionMessageById(ctx, messageId)
@@ -182075,6 +182431,20 @@ function registerPiContextHandler(pi, baseOptions) {
182075
182431
  appendCompaction: resolvePiAppendCompaction(ctx),
182076
182432
  readBranchEntries: resolvePiReadBranchEntries(ctx)
182077
182433
  });
182434
+ const piDecisionSnapshotNewestAssistant = branchEntries === null ? undefined : findNewestPiAssistantEntryId(branchEntries);
182435
+ if (result.bustedThisPass && piDecisionSnapshotNewestAssistant !== undefined) {
182436
+ recordPendingPiTransformDecision(sessionId, {
182437
+ tsMs: Date.now(),
182438
+ decision: schedulerDecision,
182439
+ materialized: result.materialized,
182440
+ materializeReason: normalizeMaterializeReason("pi", result.materializeReason, result.materialized),
182441
+ emergency: result.emergency,
182442
+ droppedTokens: result.droppedTokens,
182443
+ droppedCount: result.droppedCount,
182444
+ inputTokens: usageInputTokens,
182445
+ bustedThisPass: true
182446
+ }, piDecisionSnapshotNewestAssistant);
182447
+ }
182078
182448
  if (options.historian) {
182079
182449
  maybeFireHistorian({
182080
182450
  ctx,
@@ -182571,6 +182941,11 @@ async function runPipeline(args) {
182571
182941
  let pendingOpsAppliedThisPass = false;
182572
182942
  let pendingOpsDidMutate = false;
182573
182943
  let heuristicOrReasoningDidMutate = false;
182944
+ let didMutateFromFlushedStatuses = false;
182945
+ let droppedCount = 0;
182946
+ const droppedTokens = 0;
182947
+ let emergency = false;
182948
+ let autoReclaimDidMutateThisPass = false;
182574
182949
  let suppressDeferredHistoryDrain = false;
182575
182950
  let casLost = false;
182576
182951
  const deferredHistoryWasPendingAtPassStart = deferredHistoryRefreshSessions.has(args.sessionId);
@@ -182657,6 +183032,9 @@ async function runPipeline(args) {
182657
183032
  try {
182658
183033
  const tApplyPending = performance.now();
182659
183034
  pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, targets, args.protectedTags, undefined, pendingOps);
183035
+ if (pendingOpsDidMutate) {
183036
+ droppedCount += pendingOps.length;
183037
+ }
182660
183038
  logTransformTiming(args.sessionId, "applyPendingOperations", tApplyPending);
182661
183039
  executedWorkThisPass = true;
182662
183040
  materializationSatisfiedThisPass = true;
@@ -182678,7 +183056,7 @@ async function runPipeline(args) {
182678
183056
  const flushedSliceTags = getTagsByNumbers(args.db, args.sessionId, targetTagNumbers);
182679
183057
  logTransformTiming(args.sessionId, "getTagsByNumbers", tGetTags, `targets=${targetTagNumbers.length} fetched=${flushedSliceTags.length}`);
182680
183058
  const tFlushed = performance.now();
182681
- applyFlushedStatuses(args.sessionId, args.db, targets, flushedSliceTags);
183059
+ didMutateFromFlushedStatuses = applyFlushedStatuses(args.sessionId, args.db, targets, flushedSliceTags);
182682
183060
  logTransformTiming(args.sessionId, "applyFlushedStatuses", tFlushed);
182683
183061
  logTransformTiming(args.sessionId, "batchFinalize:flushed", tFlushed);
182684
183062
  const messageIdToMaxTag = buildMessageIdToMaxTag(targets);
@@ -182741,6 +183119,8 @@ async function runPipeline(args) {
182741
183119
  caveman: args.heuristics.caveman
182742
183120
  }, activeTags, stableIdResolver);
182743
183121
  const heuristicMutationCount = heuristicsResult.droppedTools + heuristicsResult.deduplicatedTools + heuristicsResult.droppedInjections + heuristicsResult.droppedStaleReduceCalls + heuristicsResult.mutatedTextTags;
183122
+ droppedCount += heuristicsResult.droppedTools + heuristicsResult.deduplicatedTools + heuristicsResult.droppedInjections + heuristicsResult.droppedStaleReduceCalls + heuristicsResult.mutatedTextTags;
183123
+ emergency ||= heuristicsResult.emergencyDroppedTools > 0;
182744
183124
  if (heuristicMutationCount > 0)
182745
183125
  heuristicOrReasoningDidMutate = true;
182746
183126
  heuristicsExecuted = true;
@@ -182790,6 +183170,7 @@ async function runPipeline(args) {
182790
183170
  logTransformTiming(args.sessionId, "watermarkCleanup", tClearReasoning);
182791
183171
  if (clearOutcome.cleared > 0 || stripOutcome.stripped > 0) {
182792
183172
  heuristicOrReasoningDidMutate = true;
183173
+ droppedCount += clearOutcome.cleared + stripOutcome.stripped;
182793
183174
  }
182794
183175
  if (combinedWatermark > prevWatermark || clearOutcome.cleared > 0 || stripOutcome.stripped > 0) {
182795
183176
  executedWorkThisPass = true;
@@ -182815,6 +183196,10 @@ async function runPipeline(args) {
182815
183196
  autoReclaimTargetCount = syntheticPendingOps.length;
182816
183197
  if (syntheticPendingOps.length > 0) {
182817
183198
  autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, targets, args.protectedTags, undefined, [], syntheticPendingOps);
183199
+ if (autoReclaimDidMutate) {
183200
+ droppedCount += syntheticPendingOps.length;
183201
+ autoReclaimDidMutateThisPass = true;
183202
+ }
182818
183203
  }
182819
183204
  }
182820
183205
  transcript.commit();
@@ -182923,6 +183308,9 @@ async function runPipeline(args) {
182923
183308
  } catch (err) {
182924
183309
  sessionLog(args.sessionId, `token accounting failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
182925
183310
  }
183311
+ const materialized = injectionResult?.m0Materialized === true;
183312
+ const materializeReason = injectionResult?.m0Reason ?? null;
183313
+ const bustedThisPass = didMutateFromFlushedStatuses || pendingOpsDidMutate || heuristicOrReasoningDidMutate || autoReclaimDidMutateThisPass || materialized || historyWasConsumedThisPass;
182926
183314
  return {
182927
183315
  messages: outputMessages,
182928
183316
  heuristicsExecuted,
@@ -182931,6 +183319,12 @@ async function runPipeline(args) {
182931
183319
  syntheticLeadingCount: injectionResult?.syntheticLeadingCount ?? 0,
182932
183320
  heuristicsResult,
182933
183321
  injectionResult,
183322
+ materialized,
183323
+ materializeReason,
183324
+ droppedTokens,
183325
+ droppedCount,
183326
+ emergency,
183327
+ bustedThisPass,
182934
183328
  targetCount: targets.size,
182935
183329
  reasoningWatermark: getOrCreateSessionMeta(args.db, args.sessionId).clearedReasoningThroughTag ?? 0,
182936
183330
  activeTags,
@@ -183357,6 +183751,12 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
183357
183751
  // ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
183358
183752
  import { mkdirSync as mkdirSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
183359
183753
  import { join as join16 } from "node:path";
183754
+
183755
+ // ../plugin/src/agents/historian.ts
183756
+ var HISTORIAN_AGENT = "historian";
183757
+ var HISTORIAN_EDITOR_AGENT = "historian-editor";
183758
+
183759
+ // ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
183360
183760
  init_data_path();
183361
183761
  function historianResponseDumpDir(directory) {
183362
183762
  return getProjectMagicContextHistorianDir(directory);
@@ -185610,7 +186010,7 @@ function formatThresholdPercent(value) {
185610
186010
  // package.json
185611
186011
  var package_default = {
185612
186012
  name: "@cortexkit/pi-magic-context",
185613
- version: "0.25.0",
186013
+ version: "0.26.0",
185614
186014
  type: "module",
185615
186015
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
185616
186016
  main: "dist/index.js",
@@ -191485,7 +191885,7 @@ function createCtxSearchTool(deps) {
191485
191885
  memoryEnabled,
191486
191886
  embeddingEnabled,
191487
191887
  embedQuery: async (text, signal) => {
191488
- const result = await embedTextForProject(projectIdentity, text, signal);
191888
+ const result = await embedTextForProject(projectIdentity, text, signal, "query");
191489
191889
  return result?.vector ?? null;
191490
191890
  },
191491
191891
  isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
@@ -191713,7 +192113,7 @@ function resolveSidekickFromConfig(config2) {
191713
192113
  systemPrompt: sidekick.system_prompt,
191714
192114
  timeoutMs: sidekick.timeout_ms,
191715
192115
  thinking_level: sidekick.thinking_level,
191716
- fallbackModels: resolveFallbackChain("sidekick", sidekick.fallback_models)
192116
+ fallbackModels: resolveFallbackChain(sidekick.fallback_models)
191717
192117
  };
191718
192118
  }
191719
192119
  function resolveHistorianFromConfig(config2) {
@@ -191725,7 +192125,7 @@ function resolveHistorianFromConfig(config2) {
191725
192125
  return;
191726
192126
  const historianContextLimit = resolveHistorianContextLimit(model);
191727
192127
  const historianChunkTokens = deriveHistorianChunkTokens(historianContextLimit);
191728
- const fallbackModels = resolveFallbackChain("historian", historian?.fallback_models);
192128
+ const fallbackModels = resolveFallbackChain(historian?.fallback_models);
191729
192129
  return {
191730
192130
  runner: new PiSubagentRunner,
191731
192131
  model,