@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.
@@ -9582,6 +9582,41 @@ var MIGRATIONS = [
9582
9582
  `);
9583
9583
  }
9584
9584
  }
9585
+ },
9586
+ {
9587
+ version: 37,
9588
+ description: "emergency drain catch-up latch + historian drain failure backoff",
9589
+ up: (db) => {
9590
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta'").get();
9591
+ if (!hasSessionMeta)
9592
+ return;
9593
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
9594
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
9595
+ }
9596
+ },
9597
+ {
9598
+ version: 38,
9599
+ description: "durable transform decisions for cache-event cause attribution",
9600
+ up: (db) => {
9601
+ db.exec(`
9602
+ CREATE TABLE IF NOT EXISTS transform_decisions (
9603
+ session_id TEXT NOT NULL,
9604
+ harness TEXT NOT NULL DEFAULT 'opencode',
9605
+ message_id TEXT NOT NULL,
9606
+ ts_ms INTEGER NOT NULL,
9607
+ decision TEXT NOT NULL,
9608
+ materialized INTEGER NOT NULL DEFAULT 0,
9609
+ materialize_reason TEXT,
9610
+ emergency INTEGER NOT NULL DEFAULT 0,
9611
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
9612
+ dropped_count INTEGER NOT NULL DEFAULT 0,
9613
+ input_tokens INTEGER NOT NULL DEFAULT 0,
9614
+ PRIMARY KEY (session_id, harness, message_id)
9615
+ );
9616
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
9617
+ ON transform_decisions(session_id, harness);
9618
+ `);
9619
+ }
9585
9620
  }
9586
9621
  ];
9587
9622
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -142558,8 +142593,9 @@ function backfillToolOwnersInChunks(db, result) {
142558
142593
  var databases = new Map;
142559
142594
  var persistenceByDatabase = new WeakMap;
142560
142595
  var persistenceErrorByDatabase = new WeakMap;
142596
+ var pathByDatabase = new WeakMap;
142561
142597
  var lastSchemaFenceRejection = null;
142562
- var LATEST_SUPPORTED_VERSION = 36;
142598
+ var LATEST_SUPPORTED_VERSION = 38;
142563
142599
  function resolveDatabasePath(dbPathOverride) {
142564
142600
  if (dbPathOverride) {
142565
142601
  return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
@@ -142572,6 +142608,9 @@ function resolveDatabasePath(dbPathOverride) {
142572
142608
  const dbDir = getMagicContextStorageDir();
142573
142609
  return { dbDir, dbPath: join4(dbDir, "context.db") };
142574
142610
  }
142611
+ function getDatabasePath(db) {
142612
+ return pathByDatabase.get(db) ?? null;
142613
+ }
142575
142614
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
142576
142615
  if (existsSync3(targetDbPath))
142577
142616
  return;
@@ -143086,6 +143125,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143086
143125
  recovery_no_eligible_head_count INTEGER NOT NULL DEFAULT 0,
143087
143126
  force_emergency_bypass_window_start INTEGER NOT NULL DEFAULT 0,
143088
143127
  force_emergency_bypass_used INTEGER NOT NULL DEFAULT 0,
143128
+ emergency_drain_active INTEGER NOT NULL DEFAULT 0,
143129
+ historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
143089
143130
  cached_m0_materialized_at INTEGER,
143090
143131
  cached_m0_session_facts_version INTEGER,
143091
143132
  cached_m0_upgrade_state TEXT,
@@ -143149,6 +143190,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143149
143190
  CREATE INDEX IF NOT EXISTS idx_historian_runs_status
143150
143191
  ON historian_runs(status, created_at DESC);
143151
143192
 
143193
+ CREATE TABLE IF NOT EXISTS transform_decisions (
143194
+ session_id TEXT NOT NULL,
143195
+ harness TEXT NOT NULL DEFAULT 'opencode',
143196
+ message_id TEXT NOT NULL,
143197
+ ts_ms INTEGER NOT NULL,
143198
+ decision TEXT NOT NULL,
143199
+ materialized INTEGER NOT NULL DEFAULT 0,
143200
+ materialize_reason TEXT,
143201
+ emergency INTEGER NOT NULL DEFAULT 0,
143202
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
143203
+ dropped_count INTEGER NOT NULL DEFAULT 0,
143204
+ input_tokens INTEGER NOT NULL DEFAULT 0,
143205
+ PRIMARY KEY (session_id, harness, message_id)
143206
+ );
143207
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
143208
+ ON transform_decisions(session_id, harness);
143209
+
143152
143210
  CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
143153
143211
  CREATE INDEX IF NOT EXISTS idx_tags_session_message_id ON tags(session_id, message_id);
143154
143212
  CREATE INDEX IF NOT EXISTS idx_pending_ops_session ON pending_ops(session_id);
@@ -143300,6 +143358,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143300
143358
  ensureColumn(db, "session_meta", "recovery_no_eligible_head_count", "INTEGER NOT NULL DEFAULT 0");
143301
143359
  ensureColumn(db, "session_meta", "force_emergency_bypass_window_start", "INTEGER NOT NULL DEFAULT 0");
143302
143360
  ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
143361
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
143362
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
143303
143363
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
143304
143364
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
143305
143365
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -143378,6 +143438,22 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143378
143438
  failed_at INTEGER NOT NULL,
143379
143439
  UNIQUE(table_name, row_id)
143380
143440
  );
143441
+ CREATE TABLE IF NOT EXISTS transform_decisions (
143442
+ session_id TEXT NOT NULL,
143443
+ harness TEXT NOT NULL DEFAULT 'opencode',
143444
+ message_id TEXT NOT NULL,
143445
+ ts_ms INTEGER NOT NULL,
143446
+ decision TEXT NOT NULL,
143447
+ materialized INTEGER NOT NULL DEFAULT 0,
143448
+ materialize_reason TEXT,
143449
+ emergency INTEGER NOT NULL DEFAULT 0,
143450
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
143451
+ dropped_count INTEGER NOT NULL DEFAULT 0,
143452
+ input_tokens INTEGER NOT NULL DEFAULT 0,
143453
+ PRIMARY KEY (session_id, harness, message_id)
143454
+ );
143455
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
143456
+ ON transform_decisions(session_id, harness);
143381
143457
  `);
143382
143458
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
143383
143459
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -143464,7 +143540,9 @@ function healNullIntegerColumns(db) {
143464
143540
  ["protected_tail_drain_tokens", 0],
143465
143541
  ["recovery_no_eligible_head_count", 0],
143466
143542
  ["force_emergency_bypass_window_start", 0],
143467
- ["force_emergency_bypass_used", 0]
143543
+ ["force_emergency_bypass_used", 0],
143544
+ ["emergency_drain_active", 0],
143545
+ ["historian_drain_failure_at", 0]
143468
143546
  ];
143469
143547
  for (const [column, fallback] of columns) {
143470
143548
  try {
@@ -143540,6 +143618,7 @@ function openDatabase(dbPathOrOptions) {
143540
143618
  setDatabase(db);
143541
143619
  loadToolDefinitionMeasurements(db);
143542
143620
  databases.set(dbPath, db);
143621
+ pathByDatabase.set(db, dbPath);
143543
143622
  persistenceByDatabase.set(db, true);
143544
143623
  persistenceErrorByDatabase.delete(db);
143545
143624
  return db;
@@ -158137,14 +158216,16 @@ var SidekickConfigSchema = AgentOverrideConfigSchema.extend({
158137
158216
  }).optional();
158138
158217
  var HistorianConfigSchema = AgentOverrideConfigSchema.extend({
158139
158218
  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)"),
158140
- 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")
158219
+ 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"),
158220
+ 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: [])`)
158141
158221
  }).optional();
158142
158222
  var BaseEmbeddingConfigSchema = exports_external.object({
158143
158223
  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."),
158144
158224
  model: exports_external.string().optional().describe("Embedding model name. Required for openai-compatible, ignored for local."),
158145
158225
  endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
158146
158226
  api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
158147
- 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."),
158227
+ 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."),
158228
+ 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."),
158148
158229
  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."),
158149
158230
  max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
158150
158231
  }).superRefine((data, ctx) => {
@@ -158174,6 +158255,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
158174
158255
  if (data.provider === "openai-compatible") {
158175
158256
  const apiKey = data.api_key?.trim();
158176
158257
  const inputType = data.input_type?.trim();
158258
+ const queryInputType = data.query_input_type?.trim();
158177
158259
  const truncate = data.truncate?.trim();
158178
158260
  return {
158179
158261
  provider: "openai-compatible",
@@ -158181,6 +158263,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
158181
158263
  endpoint: data.endpoint?.trim() ?? "",
158182
158264
  ...apiKey ? { api_key: apiKey } : {},
158183
158265
  ...inputType ? { input_type: inputType } : {},
158266
+ ...queryInputType ? { query_input_type: queryInputType } : {},
158184
158267
  ...truncate ? { truncate } : {},
158185
158268
  ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
158186
158269
  };
@@ -158901,6 +158984,16 @@ function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal)
158901
158984
  return lines.join(`
158902
158985
  `);
158903
158986
  }
158987
+ function buildCompartmentSummaryFallbackText(db, compartmentId) {
158988
+ const row = db.prepare("SELECT title, p1, content FROM compartments WHERE id = ?").get(compartmentId);
158989
+ if (!row)
158990
+ return "";
158991
+ const title = typeof row.title === "string" ? row.title.trim() : "";
158992
+ const p1 = typeof row.p1 === "string" ? row.p1.trim() : "";
158993
+ const body = p1.length > 0 ? p1 : typeof row.content === "string" ? row.content.trim() : "";
158994
+ return [title, body].filter((s) => s.length > 0).join(`
158995
+ `);
158996
+ }
158904
158997
  function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
158905
158998
  const lines = [];
158906
158999
  for (const rawLine of chunkText.split(/\r?\n/)) {
@@ -159495,7 +159588,7 @@ class LocalEmbeddingProvider {
159495
159588
  waiter();
159496
159589
  }
159497
159590
  }
159498
- async embed(text, signal) {
159591
+ async embed(text, signal, _purpose) {
159499
159592
  if (signal?.aborted)
159500
159593
  return null;
159501
159594
  if (this.disposing)
@@ -159521,7 +159614,7 @@ class LocalEmbeddingProvider {
159521
159614
  this.finishInFlight();
159522
159615
  }
159523
159616
  }
159524
- async embedBatch(texts, signal) {
159617
+ async embedBatch(texts, signal, _purpose) {
159525
159618
  if (texts.length === 0) {
159526
159619
  return [];
159527
159620
  }
@@ -159660,6 +159753,7 @@ class OpenAICompatibleEmbeddingProvider {
159660
159753
  model;
159661
159754
  apiKey;
159662
159755
  inputType;
159756
+ queryInputType;
159663
159757
  truncate;
159664
159758
  initialized = false;
159665
159759
  failureTimes = [];
@@ -159672,6 +159766,7 @@ class OpenAICompatibleEmbeddingProvider {
159672
159766
  this.model = options.model?.trim() ?? "";
159673
159767
  this.apiKey = options.apiKey?.trim() ?? "";
159674
159768
  this.inputType = options.inputType?.trim() ?? "";
159769
+ this.queryInputType = options.queryInputType?.trim() ?? "";
159675
159770
  this.truncate = options.truncate?.trim() ?? "";
159676
159771
  this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
159677
159772
  this.modelId = getEmbeddingProviderIdentity({
@@ -159699,11 +159794,17 @@ class OpenAICompatibleEmbeddingProvider {
159699
159794
  this.initialized = true;
159700
159795
  return true;
159701
159796
  }
159702
- async embed(text, signal) {
159703
- const [embedding] = await this.embedBatch([text], signal);
159797
+ resolveInputTypeForPurpose(purpose = "passage") {
159798
+ if (purpose === "query") {
159799
+ return this.queryInputType || this.inputType;
159800
+ }
159801
+ return this.inputType;
159802
+ }
159803
+ async embed(text, signal, purpose) {
159804
+ const [embedding] = await this.embedBatch([text], signal, purpose);
159704
159805
  return embedding ?? null;
159705
159806
  }
159706
- async embedBatch(texts, signal) {
159807
+ async embedBatch(texts, signal, purpose) {
159707
159808
  if (texts.length === 0) {
159708
159809
  return [];
159709
159810
  }
@@ -159729,6 +159830,7 @@ class OpenAICompatibleEmbeddingProvider {
159729
159830
  if (signal) {
159730
159831
  signal.addEventListener("abort", onOuterAbort, { once: true });
159731
159832
  }
159833
+ const inputTypeForRequest = this.resolveInputTypeForPurpose(purpose);
159732
159834
  const response = await fetch(`${this.endpoint}/embeddings`, {
159733
159835
  method: "POST",
159734
159836
  headers: {
@@ -159738,7 +159840,7 @@ class OpenAICompatibleEmbeddingProvider {
159738
159840
  body: JSON.stringify({
159739
159841
  model: this.model,
159740
159842
  input: texts,
159741
- ...this.inputType ? { input_type: this.inputType } : {},
159843
+ ...inputTypeForRequest ? { input_type: inputTypeForRequest } : {},
159742
159844
  ...this.truncate ? { truncate: this.truncate } : {}
159743
159845
  }),
159744
159846
  redirect: "error",
@@ -160442,6 +160544,7 @@ function resolveEmbeddingConfig(config2) {
160442
160544
  if (config2.provider === "openai-compatible") {
160443
160545
  const apiKey = config2.api_key?.trim();
160444
160546
  const inputType = config2.input_type?.trim();
160547
+ const queryInputType = config2.query_input_type?.trim();
160445
160548
  const truncate = config2.truncate?.trim();
160446
160549
  return {
160447
160550
  provider: "openai-compatible",
@@ -160449,6 +160552,7 @@ function resolveEmbeddingConfig(config2) {
160449
160552
  endpoint: config2.endpoint.trim(),
160450
160553
  ...apiKey ? { api_key: apiKey } : {},
160451
160554
  ...inputType ? { input_type: inputType } : {},
160555
+ ...queryInputType ? { query_input_type: queryInputType } : {},
160452
160556
  ...truncate ? { truncate } : {},
160453
160557
  ...config2.max_input_tokens ? {
160454
160558
  max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
@@ -160470,6 +160574,7 @@ function createProvider(config2) {
160470
160574
  model: config2.model,
160471
160575
  apiKey: config2.api_key,
160472
160576
  inputType: config2.input_type,
160577
+ queryInputType: config2.query_input_type,
160473
160578
  truncate: config2.truncate,
160474
160579
  maxInputTokens: config2.max_input_tokens
160475
160580
  });
@@ -160652,7 +160757,7 @@ function getOrCreateProjectProvider(registration) {
160652
160757
  registration.provider = provider;
160653
160758
  return provider;
160654
160759
  }
160655
- async function embedTextForProject(projectIdentity, text, signal) {
160760
+ async function embedTextForProject(projectIdentity, text, signal, purpose = "passage") {
160656
160761
  const registration = projectRegistrations.get(projectIdentity);
160657
160762
  if (!registration)
160658
160763
  return null;
@@ -160661,7 +160766,7 @@ async function embedTextForProject(projectIdentity, text, signal) {
160661
160766
  const provider = getOrCreateProjectProvider(registration);
160662
160767
  if (!provider)
160663
160768
  return null;
160664
- const vector = await provider.embed(text, signal);
160769
+ const vector = await provider.embed(text, signal, purpose);
160665
160770
  if (!vector)
160666
160771
  return null;
160667
160772
  const current = projectRegistrations.get(projectIdentity);
@@ -160670,7 +160775,7 @@ async function embedTextForProject(projectIdentity, text, signal) {
160670
160775
  }
160671
160776
  return { vector, modelId, generation };
160672
160777
  }
160673
- async function embedBatchForProject(projectIdentity, texts, signal) {
160778
+ async function embedBatchForProject(projectIdentity, texts, signal, purpose = "passage") {
160674
160779
  if (texts.length === 0) {
160675
160780
  const registration2 = projectRegistrations.get(projectIdentity);
160676
160781
  if (!registration2 || registration2.observationMode)
@@ -160686,7 +160791,7 @@ async function embedBatchForProject(projectIdentity, texts, signal) {
160686
160791
  const provider = getOrCreateProjectProvider(registration);
160687
160792
  if (!provider)
160688
160793
  return null;
160689
- const vectors = await provider.embedBatch(texts, signal);
160794
+ const vectors = await provider.embedBatch(texts, signal, purpose);
160690
160795
  const current = projectRegistrations.get(projectIdentity);
160691
160796
  if (!current || current.generation !== generation || current.runtimeFingerprint !== runtimeFingerprint) {
160692
160797
  return null;
@@ -160743,7 +160848,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
160743
160848
  const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
160744
160849
  const prepared = [];
160745
160850
  for (const candidate of candidates) {
160746
- const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
160851
+ const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage) || buildCompartmentSummaryFallbackText(db, candidate.id);
160747
160852
  if (canonicalText.length === 0) {
160748
160853
  noWork.push(candidate.id);
160749
160854
  continue;
@@ -160952,6 +161057,7 @@ function createProvider2(config2) {
160952
161057
  model: config2.model,
160953
161058
  apiKey: config2.api_key,
160954
161059
  inputType: config2.input_type,
161060
+ queryInputType: config2.query_input_type,
160955
161061
  truncate: config2.truncate,
160956
161062
  maxInputTokens: config2.max_input_tokens
160957
161063
  });
@@ -161187,6 +161293,8 @@ var SESSION_META_SELECT_COLUMNS = [
161187
161293
  "recovery_no_eligible_head_count",
161188
161294
  "force_emergency_bypass_window_start",
161189
161295
  "force_emergency_bypass_used",
161296
+ "emergency_drain_active",
161297
+ "historian_drain_failure_at",
161190
161298
  "upgrade_reminded_at",
161191
161299
  "pi_stable_id_scheme"
161192
161300
  ];
@@ -161236,6 +161344,8 @@ var META_COLUMNS = {
161236
161344
  recoveryNoEligibleHeadCount: "recovery_no_eligible_head_count",
161237
161345
  forceEmergencyBypassWindowStart: "force_emergency_bypass_window_start",
161238
161346
  forceEmergencyBypassUsed: "force_emergency_bypass_used",
161347
+ emergencyDrainActive: "emergency_drain_active",
161348
+ historianDrainFailureAt: "historian_drain_failure_at",
161239
161349
  upgradeRemindedAt: "upgrade_reminded_at",
161240
161350
  piStableIdScheme: "pi_stable_id_scheme"
161241
161351
  };
@@ -161937,6 +162047,24 @@ class ToolMutationBatch {
161937
162047
  }
161938
162048
 
161939
162049
  // ../plugin/src/hooks/magic-context/read-session-chunk.ts
162050
+ var BLOCK_TOKEN_MEMO_MAX = 2048;
162051
+ var blockTokenMemo = new Map;
162052
+ function estimateBlockTokens(blockText) {
162053
+ const cached2 = blockTokenMemo.get(blockText);
162054
+ if (cached2 !== undefined) {
162055
+ blockTokenMemo.delete(blockText);
162056
+ blockTokenMemo.set(blockText, cached2);
162057
+ return cached2;
162058
+ }
162059
+ const count = estimateTokens(blockText);
162060
+ if (blockTokenMemo.size >= BLOCK_TOKEN_MEMO_MAX) {
162061
+ const oldest = blockTokenMemo.keys().next().value;
162062
+ if (oldest !== undefined)
162063
+ blockTokenMemo.delete(oldest);
162064
+ }
162065
+ blockTokenMemo.set(blockText, count);
162066
+ return count;
162067
+ }
161940
162068
  var activeRawMessageCache = null;
161941
162069
  var activeAbsoluteCountCache = null;
161942
162070
  var sessionProviders = new Map;
@@ -162119,7 +162247,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
162119
162247
  if (!currentBlock)
162120
162248
  return true;
162121
162249
  const blockText = formatBlock(currentBlock);
162122
- const blockTokens = estimateTokens(blockText);
162250
+ const blockTokens = estimateBlockTokens(blockText);
162123
162251
  if (totalTokens + blockTokens > tokenBudget && totalTokens > 0) {
162124
162252
  return false;
162125
162253
  }
@@ -168069,7 +168197,9 @@ var DEFAULT_PROTECTED_TAIL_META = {
168069
168197
  protectedTailDrainTokens: 0,
168070
168198
  recoveryNoEligibleHeadCount: 0,
168071
168199
  forceEmergencyBypassWindowStart: 0,
168072
- forceEmergencyBypassUsed: 0
168200
+ forceEmergencyBypassUsed: 0,
168201
+ emergencyDrainActive: 0,
168202
+ historianDrainFailureAt: 0
168073
168203
  };
168074
168204
  function toProtectedTailMeta(row) {
168075
168205
  if (row === null || typeof row !== "object")
@@ -168083,7 +168213,9 @@ function toProtectedTailMeta(row) {
168083
168213
  protectedTailDrainTokens: numberOr(r.protected_tail_drain_tokens, 0),
168084
168214
  recoveryNoEligibleHeadCount: numberOr(r.recovery_no_eligible_head_count, 0),
168085
168215
  forceEmergencyBypassWindowStart: numberOr(r.force_emergency_bypass_window_start, 0),
168086
- forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0)
168216
+ forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0),
168217
+ emergencyDrainActive: numberOr(r.emergency_drain_active, 0),
168218
+ historianDrainFailureAt: numberOr(r.historian_drain_failure_at, 0)
168087
168219
  };
168088
168220
  }
168089
168221
  function loadProtectedTailMeta(db, sessionId) {
@@ -168091,7 +168223,7 @@ function loadProtectedTailMeta(db, sessionId) {
168091
168223
  const row = db.prepare(`SELECT prior_boundary_ordinal, protected_tail_policy_version,
168092
168224
  protected_tail_drain_window_started_at, protected_tail_drain_tokens,
168093
168225
  recovery_no_eligible_head_count, force_emergency_bypass_window_start,
168094
- force_emergency_bypass_used
168226
+ force_emergency_bypass_used, emergency_drain_active, historian_drain_failure_at
168095
168227
  FROM session_meta WHERE session_id = ?`).get(sessionId);
168096
168228
  return toProtectedTailMeta(row);
168097
168229
  }
@@ -168135,6 +168267,17 @@ function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
168135
168267
  return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
168136
168268
  return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
168137
168269
  }
168270
+ var EMERGENCY_DRAIN_ENTER_PERCENTAGE = 95;
168271
+ var EMERGENCY_DRAIN_EXIT_MARGIN = 10;
168272
+ var EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE = 55;
168273
+ var EMERGENCY_DRAIN_FAILURE_BACKOFF_MS = 60000;
168274
+ var EMERGENCY_DRAIN_MAX_LATCH_MS = 30 * 60 * 1000;
168275
+ function emergencyDrainExitThreshold(executeThresholdPercentage) {
168276
+ if (!Number.isFinite(executeThresholdPercentage) || executeThresholdPercentage <= 0) {
168277
+ return EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE;
168278
+ }
168279
+ return Math.max(0, executeThresholdPercentage - EMERGENCY_DRAIN_EXIT_MARGIN);
168280
+ }
168138
168281
  function reserveProtectedTailDrainTokens(args) {
168139
168282
  const now = args.now ?? Date.now();
168140
168283
  const requested = Math.max(0, Math.floor(args.trueRawTokens));
@@ -168153,18 +168296,30 @@ function reserveProtectedTailDrainTokens(args) {
168153
168296
  let meta3 = loadProtectedTailMeta(args.db, args.sessionId);
168154
168297
  if (now - meta3.protectedTailDrainWindowStartedAt > DRAIN_WINDOW_MS) {
168155
168298
  args.db.prepare(`UPDATE session_meta
168156
- SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0,
168157
- force_emergency_bypass_window_start = ?, force_emergency_bypass_used = 0
168158
- WHERE session_id = ?`).run(now, now, args.sessionId);
168299
+ SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0
168300
+ WHERE session_id = ?`).run(now, args.sessionId);
168159
168301
  meta3 = loadProtectedTailMeta(args.db, args.sessionId);
168160
168302
  }
168303
+ const exitThreshold = emergencyDrainExitThreshold(args.executeThresholdPercentage);
168304
+ let latchActiveSince = meta3.emergencyDrainActive;
168305
+ if (args.usagePercentage >= EMERGENCY_DRAIN_ENTER_PERCENTAGE) {
168306
+ if (latchActiveSince <= 0)
168307
+ latchActiveSince = now;
168308
+ } else if (latchActiveSince > 0) {
168309
+ const expired = now - latchActiveSince > EMERGENCY_DRAIN_MAX_LATCH_MS;
168310
+ if (args.usagePercentage < exitThreshold || expired)
168311
+ latchActiveSince = 0;
168312
+ }
168313
+ if (latchActiveSince !== meta3.emergencyDrainActive) {
168314
+ args.db.prepare("UPDATE session_meta SET emergency_drain_active = ? WHERE session_id = ?").run(latchActiveSince, args.sessionId);
168315
+ }
168316
+ const latchActive = latchActiveSince > 0;
168161
168317
  const budget = protectedTailWindowBudget(args.usagePercentage, args.usable, args.perRunCap);
168162
168318
  const remaining = Math.max(0, budget - meta3.protectedTailDrainTokens);
168163
168319
  let reserved = Math.min(requested, args.perRunCap, remaining);
168164
168320
  let bypass = false;
168165
- const bypassWindowExpired = now - meta3.forceEmergencyBypassWindowStart > DRAIN_WINDOW_MS;
168166
- const bypassUsed = bypassWindowExpired ? 0 : meta3.forceEmergencyBypassUsed;
168167
- if (reserved <= 0 && args.usagePercentage >= 95 && bypassUsed === 0) {
168321
+ const inFailureBackoff = meta3.historianDrainFailureAt > 0 && now - meta3.historianDrainFailureAt < EMERGENCY_DRAIN_FAILURE_BACKOFF_MS;
168322
+ if (reserved <= 0 && latchActive && !inFailureBackoff) {
168168
168323
  reserved = Math.min(requested, args.perRunCap);
168169
168324
  bypass = true;
168170
168325
  }
@@ -168172,10 +168327,8 @@ function reserveProtectedTailDrainTokens(args) {
168172
168327
  return;
168173
168328
  args.db.prepare(`UPDATE session_meta
168174
168329
  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,
168175
- protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?,
168176
- force_emergency_bypass_window_start = CASE WHEN ? THEN ? ELSE force_emergency_bypass_window_start END,
168177
- force_emergency_bypass_used = CASE WHEN ? THEN 1 ELSE force_emergency_bypass_used END
168178
- WHERE session_id = ?`).run(now, reserved, bypass ? 1 : 0, now, bypass ? 1 : 0, args.sessionId);
168330
+ protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?
168331
+ WHERE session_id = ?`).run(now, reserved, args.sessionId);
168179
168332
  result = {
168180
168333
  ok: true,
168181
168334
  reservedTokens: reserved,
@@ -168185,6 +168338,25 @@ function reserveProtectedTailDrainTokens(args) {
168185
168338
  })();
168186
168339
  return result;
168187
168340
  }
168341
+ function clearEmergencyDrainLatch(db, sessionId) {
168342
+ db.transaction(() => {
168343
+ ensureSessionMetaRow(db, sessionId);
168344
+ db.prepare("UPDATE session_meta SET emergency_drain_active = 0 WHERE session_id = ?").run(sessionId);
168345
+ })();
168346
+ }
168347
+ function recordHistorianDrainFailure(db, sessionId, now) {
168348
+ const ts = now ?? Date.now();
168349
+ db.transaction(() => {
168350
+ ensureSessionMetaRow(db, sessionId);
168351
+ db.prepare("UPDATE session_meta SET historian_drain_failure_at = ? WHERE session_id = ?").run(ts, sessionId);
168352
+ })();
168353
+ }
168354
+ function clearHistorianDrainFailure(db, sessionId) {
168355
+ db.transaction(() => {
168356
+ ensureSessionMetaRow(db, sessionId);
168357
+ db.prepare("UPDATE session_meta SET historian_drain_failure_at = 0 WHERE session_id = ?").run(sessionId);
168358
+ })();
168359
+ }
168188
168360
  function rollbackProtectedTailDrainReservation(db, reservation) {
168189
168361
  if (!reservation || reservation.tokens <= 0)
168190
168362
  return;
@@ -169206,12 +169378,17 @@ function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, li
169206
169378
  toolName: typeof row.tool_name === "string" ? row.tool_name : null
169207
169379
  }));
169208
169380
  }
169209
- function getTriggerTagTokenUpperBound(db, sessionId) {
169210
- const row = db.prepare(`SELECT
169381
+ function getTriggerTagTokenUpperBound(db, sessionId, floor = 0) {
169382
+ const sql = floor > 0 ? `SELECT
169211
169383
  COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
169212
169384
  COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
169213
169385
  FROM tags
169214
- WHERE session_id = ? AND status IN ('active', 'dropped')`).get(sessionId);
169386
+ WHERE session_id = ? AND status IN ('active', 'dropped') AND tag_number >= ?` : `SELECT
169387
+ COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
169388
+ COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
169389
+ FROM tags
169390
+ WHERE session_id = ? AND status IN ('active', 'dropped')`;
169391
+ const row = floor > 0 ? db.prepare(sql).get(sessionId, floor) : db.prepare(sql).get(sessionId);
169215
169392
  return { bound: row?.bound ?? 0, nullCount: row?.null_count ?? 0 };
169216
169393
  }
169217
169394
  function updateTagInputByteSize(db, sessionId, tagNumber, newInputByteSize) {
@@ -169238,10 +169415,12 @@ function getUpdateTagInputTokenCountStatement(db) {
169238
169415
  function updateTagTokenCount(db, sessionId, tagNumber, newTokenCount) {
169239
169416
  getUpdateTagTokenCountStatement(db).run(newTokenCount, sessionId, tagNumber);
169240
169417
  }
169241
- function getAllStatusTagTokenTotalsFlat(db, sessionId) {
169242
- const rows = db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
169243
- FROM tags
169244
- WHERE session_id = ?`).all(sessionId);
169418
+ function getAllStatusTagTokenTotalsFlat(db, sessionId, floor = 0) {
169419
+ const rows = floor > 0 ? db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
169420
+ FROM tags
169421
+ 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
169422
+ FROM tags
169423
+ WHERE session_id = ?`).all(sessionId);
169245
169424
  const totals = new Map;
169246
169425
  const nullMessageIds = new Set;
169247
169426
  for (const row of rows) {
@@ -169360,6 +169539,52 @@ function getTagNumberByMessageId(db, sessionId, messageId) {
169360
169539
  const row = getTagNumberByMessageIdStatement(db).get(sessionId, messageId);
169361
169540
  return isTagNumberRow(row) ? row.tag_number : null;
169362
169541
  }
169542
+ var getMinMessageTagNumberForRawIdStatements = new WeakMap;
169543
+ function isMinTagNumberRow(row) {
169544
+ return row !== null && typeof row === "object" && "m" in row;
169545
+ }
169546
+ function getMinMessageTagNumberForRawId(db, sessionId, rawId) {
169547
+ if (rawId.includes(":"))
169548
+ return null;
169549
+ let stmt = getMinMessageTagNumberForRawIdStatements.get(db);
169550
+ if (!stmt) {
169551
+ stmt = db.prepare("SELECT MIN(tag_number) AS m FROM tags WHERE session_id = ? AND message_id >= ? AND message_id < ?");
169552
+ getMinMessageTagNumberForRawIdStatements.set(db, stmt);
169553
+ }
169554
+ const row = stmt.get(sessionId, `${rawId}:`, `${rawId};`);
169555
+ return isMinTagNumberRow(row) && typeof row.m === "number" ? row.m : null;
169556
+ }
169557
+ var TAGGER_FLOOR_SCAN_MESSAGES = 8;
169558
+ var TAGGER_FLOOR_MAX_PROBES = 64;
169559
+ var TAGGER_FLOOR_SAFETY_MARGIN = 256;
169560
+ var TAGGER_FLOOR_PER_SKIP_MARGIN = 64;
169561
+ function deriveTagLoadFloor(db, sessionId, rawIds) {
169562
+ let min = Number.POSITIVE_INFINITY;
169563
+ let probes = 0;
169564
+ let hits = 0;
169565
+ let skippedBeforeFirstHit = 0;
169566
+ for (const rawId of rawIds) {
169567
+ if (typeof rawId !== "string" || rawId.length === 0)
169568
+ continue;
169569
+ if (probes >= TAGGER_FLOOR_MAX_PROBES)
169570
+ break;
169571
+ probes++;
169572
+ const m = getMinMessageTagNumberForRawId(db, sessionId, rawId);
169573
+ if (m === null) {
169574
+ if (hits === 0)
169575
+ skippedBeforeFirstHit++;
169576
+ continue;
169577
+ }
169578
+ if (m < min)
169579
+ min = m;
169580
+ if (++hits >= TAGGER_FLOOR_SCAN_MESSAGES)
169581
+ break;
169582
+ }
169583
+ if (!Number.isFinite(min))
169584
+ return 0;
169585
+ const margin = TAGGER_FLOOR_SAFETY_MARGIN + skippedBeforeFirstHit * TAGGER_FLOOR_PER_SKIP_MARGIN;
169586
+ return Math.max(0, min - margin);
169587
+ }
169363
169588
  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";
169364
169589
  function getTagsBySession(db, sessionId) {
169365
169590
  const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC`).all(sessionId).filter(isTagRow);
@@ -172098,7 +172323,7 @@ function createCtxSearchTool(deps) {
172098
172323
  memoryEnabled,
172099
172324
  embeddingEnabled,
172100
172325
  embedQuery: async (text, signal) => {
172101
- const result = await embedTextForProject(projectIdentity, text, signal);
172326
+ const result = await embedTextForProject(projectIdentity, text, signal, "query");
172102
172327
  return result?.vector ?? null;
172103
172328
  },
172104
172329
  isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/pi-magic-context",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "type": "module",
5
5
  "description": "Pi coding agent extension for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",