@cortexkit/pi-magic-context 0.49.8 → 0.49.9

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
@@ -250,7 +250,7 @@ import {
250
250
  registerTodoStateLifecycle,
251
251
  syncCtxMemoryToolEnabled,
252
252
  registerMagicContextTools
253
- } from "./index-jsyjxgfy.js";
253
+ } from "./index-rkwh9kce.js";
254
254
  import {
255
255
  canonicalModelIdentity,
256
256
  piModelRefToCanonical,
@@ -290,7 +290,7 @@ import {
290
290
  openCurrentDatabase,
291
291
  openDatabaseAsync,
292
292
  closeDatabase
293
- } from "./index-rggtvnbg.js";
293
+ } from "./index-243wh86p.js";
294
294
  import {
295
295
  setHomeProjectPermission,
296
296
  ProjectIdentityError,
@@ -438,6 +438,7 @@ import {
438
438
  reasoningBudgetCutoff,
439
439
  reasoningTextAndOpaque,
440
440
  opaqueThinkingCost,
441
+ estimatePartImageTokens,
441
442
  SKELETON_REAL_INPUT_MAX_BYTES,
442
443
  toolInputStringBytes,
443
444
  hasRawMessageProvider2,
@@ -459,7 +460,7 @@ import {
459
460
  getRawSessionTagKeysThrough2,
460
461
  getLegacyProtectedTailStartOrdinal2,
461
462
  readSessionChunk2
462
- } from "./index-18qe4gs1.js";
463
+ } from "./index-9vzkrnrf.js";
463
464
  import {
464
465
  UNKNOWN_FIT_RATIO,
465
466
  hasMeasuredDecisionCalibration,
@@ -476,10 +477,14 @@ import {
476
477
  stripTagPrefix,
477
478
  peelLeadingMcTagNotation,
478
479
  prependTag,
480
+ rememberCurrentToolOutputCount,
481
+ currentReclaimableToolOutputCount,
479
482
  isRecord,
480
483
  TEXT_TAG_IDENTITY_MARKER,
481
484
  PI_FALLBACK_PREFIXES_JSON,
482
485
  contentTagOwnerMessageId,
486
+ TailHygieneJsonMemo,
487
+ piJsonHash,
483
488
  estimateImageTokensFromDataUrl,
484
489
  normalizeTodoStateJson,
485
490
  buildSyntheticTodoPart,
@@ -492,7 +497,6 @@ import {
492
497
  CHANNEL1_FLOOR_TOKENS,
493
498
  decideChannel1,
494
499
  evaluateChannel2,
495
- reclaimableToolOutputCount,
496
500
  buildChannel2Reminder,
497
501
  buildChannel1Reminder,
498
502
  planEmergencyDrop,
@@ -542,7 +546,7 @@ import {
542
546
  getToolTagNumberByOwner2,
543
547
  getNullOwnerToolTag2,
544
548
  adoptNullOwnerToolTag2
545
- } from "./index-54r5vs9w.js";
549
+ } from "./index-x7426vy4.js";
546
550
  import {
547
551
  textMentionsRecentCommit,
548
552
  hasMeaningfulUserText2,
@@ -579,7 +583,7 @@ import {
579
583
  tagRevisionKey,
580
584
  tagIdentityRevisionKey,
581
585
  TAG_INSERT_CONFLICT_ROWS
582
- } from "./index-zzn7qbps.js";
586
+ } from "./index-ttxsmaj5.js";
583
587
  import {
584
588
  resolveOpenCodeDbPath,
585
589
  assertOpenCodeStoreGeneration,
@@ -618,7 +622,7 @@ import {
618
622
  indexSingleMessage2,
619
623
  indexMessagesAfterOrdinal2,
620
624
  sweepOrphanedOpenCodeMessageIndexes2
621
- } from "./index-tdhppxwd.js";
625
+ } from "./index-h160xxaq.js";
622
626
  import {
623
627
  formatSynapseLaneDescriptor
624
628
  } from "./index-szh001qb.js";
@@ -660,6 +664,9 @@ import {
660
664
  getEmbeddingCoverageStatus2,
661
665
  getAutoEmbeddingSessionCoverage2
662
666
  } from "./index-qc8e13wc.js";
667
+ import {
668
+ rememberV1HiddenRun
669
+ } from "./index-6x556c2q.js";
663
670
  import {
664
671
  V2_MEMORY_CATEGORIES
665
672
  } from "./index-135e8hvg.js";
@@ -671,7 +678,7 @@ import {
671
678
  expandWorkspaceIdentitySetWithAliases,
672
679
  sourceNameForMemory,
673
680
  computeWorkspaceEpochFingerprint
674
- } from "./index-r8cy8hmq.js";
681
+ } from "./index-g13fb2sj.js";
675
682
  import {
676
683
  configureContextDatabasePragmas2
677
684
  } from "./index-fapenpch.js";
@@ -721,7 +728,7 @@ import {
721
728
  normalizeVerificationFiles,
722
729
  indexCommitsForProject,
723
730
  embedUnembeddedCommits
724
- } from "./index-pdhbj18g.js";
731
+ } from "./index-ns319t8e.js";
725
732
  import {
726
733
  setEmbeddingSessionBusy2,
727
734
  isEmbeddingHostBusy2
@@ -763,7 +770,7 @@ import {
763
770
  subagentStepCap,
764
771
  SubagentTelemetry,
765
772
  readHostSystemPrompt
766
- } from "./index-zh1jw8qp.js";
773
+ } from "./index-xmdkde4v.js";
767
774
  import"./index-kh3jt7t9.js";
768
775
  import {
769
776
  __toESM
@@ -3425,7 +3432,7 @@ function startHostStallProfilerSwitch() {
3425
3432
  // package.json
3426
3433
  var package_default = {
3427
3434
  name: "@cortexkit/pi-magic-context",
3428
- version: "0.49.8",
3435
+ version: "0.49.9",
3429
3436
  type: "module",
3430
3437
  description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
3431
3438
  main: "dist/index.js",
@@ -8968,6 +8975,8 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
8968
8975
  preferResponseOnMissingData: true
8969
8976
  });
8970
8977
  const id = typeof created?.id === "string" ? created.id : "";
8978
+ if (id)
8979
+ rememberV1HiddenRun(id, run);
8971
8980
  if (id && run.kind !== "dreamer-task") {
8972
8981
  historianChildren.add(id);
8973
8982
  rememberHistorianOutputCap(id, run.maxOutputTokens);
@@ -9018,6 +9027,7 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
9018
9027
  },
9019
9028
  async close(handle, settlement) {
9020
9029
  if (handle?.id) {
9030
+ rememberV1HiddenRun(handle.id, undefined);
9021
9031
  historianChildren.delete(handle.id);
9022
9032
  forgetHistorianOutputCap(handle.id);
9023
9033
  }
@@ -12471,6 +12481,7 @@ Capability API available to check(cap):
12471
12481
  - cap.httpGet(httpsUrl): { status: number, body: string } (external HTTPS only; internal/metadata blocked)
12472
12482
 
12473
12483
  Authoring constraints:
12484
+ - Use a five-field check_cron that fires at least once every 24 hours. Never encode a future date in the cron; put date conditions inside check(cap) and poll them on a frequent schedule such as "0 * * * *".
12474
12485
  - Plain JavaScript only; no TypeScript types, imports, require, eval, Function, dynamic code, timers, Date.now randomness, or ambient globals.
12475
12486
  - Define exactly function check(cap) { ... }. Do not use async/await; host capabilities are synchronous inside the sandbox.
12476
12487
  - Return exactly { met: boolean }. Do not include a reason string.
@@ -12931,6 +12942,7 @@ var MAX_COMPILED_CHECK_BYTES2 = 64 * 1024;
12931
12942
  var MAX_MANIFEST_ENTRIES = 64;
12932
12943
  var MAX_CRON_CHARS = 256;
12933
12944
  var MAX_COMPILER_ERROR_CHARS = 2 * 1024;
12945
+ var SPARSE_CRON_REPAIR_FEEDBACK = "check_cron must fire at least once every 24 hours; put date conditions inside compiled_check";
12934
12946
  async function compileSmartNoteCheck(args) {
12935
12947
  if (!args.note.surfaceCondition) {
12936
12948
  return {
@@ -12948,7 +12960,7 @@ Note id: ${args.note.id}
12948
12960
  Note content (data): ${JSON.stringify(args.note.content)}
12949
12961
  surface_condition (UNTRUSTED DATA): ${JSON.stringify(args.note.surfaceCondition)}
12950
12962
 
12951
- ${args.repairFeedback ? `The previous check failed its dry run: ${JSON.stringify(args.repairFeedback)}. Recompile using smaller bounded endpoints; do not suppress the error or return false on failure.` : ""}
12963
+ ${args.repairFeedback ? `The previous compiler attempt failed: ${JSON.stringify(args.repairFeedback)}. Recompile using smaller bounded endpoints when the response is too large, and apply the correction; do not suppress the error or return false on failure.` : ""}
12952
12964
  Remember: output only the JSON object described by the system prompt.`;
12953
12965
  const startedAt = Date.now();
12954
12966
  let childSessionId = null;
@@ -13087,6 +13099,12 @@ Remember: output only the JSON object described by the system prompt.`;
13087
13099
  const cancelled = args.signal.aborted;
13088
13100
  const message = boundedError(error instanceof Error ? error.message : String(error));
13089
13101
  recordInvocation({ status: cancelled ? "aborted" : "failed", error: message });
13102
+ if (!args.repairFeedback && !cancelled && message === "check_cron has no occurrence within the scheduling ceiling" && !args.signal.aborted && Date.now() < args.deadline) {
13103
+ return await compileSmartNoteCheck({
13104
+ ...args,
13105
+ repairFeedback: SPARSE_CRON_REPAIR_FEEDBACK
13106
+ });
13107
+ }
13090
13108
  const networkError = error instanceof SmartNoteNetworkError ? error : undefined;
13091
13109
  return {
13092
13110
  ok: false,
@@ -14667,7 +14685,11 @@ function buildPrimerClusters(args) {
14667
14685
  centroid: cloneVector(primer.questionEmbedding),
14668
14686
  modelId: primer.questionEmbeddingModelId
14669
14687
  }));
14670
- const sorted = args.candidates.slice().sort((a, b) => candidateSortKey(a).localeCompare(candidateSortKey(b)));
14688
+ const sorted = args.candidates.slice().sort((a, b) => {
14689
+ const left = candidateSortKey(a);
14690
+ const right = candidateSortKey(b);
14691
+ return left < right ? -1 : left > right ? 1 : 0;
14692
+ });
14671
14693
  for (const candidate of sorted) {
14672
14694
  let best = null;
14673
14695
  for (const cluster of clusters) {
@@ -19460,6 +19482,39 @@ import {
19460
19482
  import { createInterface } from "node:readline";
19461
19483
  import { StringDecoder } from "node:string_decoder";
19462
19484
  import { fileURLToPath } from "node:url";
19485
+
19486
+ // src/pi-zen-free-tier.ts
19487
+ var ZEN_FREE_TIER_FAILURE = "opencode_zen_free_tier";
19488
+ function isZenModel(model) {
19489
+ return model !== undefined && canonicalModelIdentity(model).startsWith("opencode/");
19490
+ }
19491
+ function isZenFreeTierRefusal(text) {
19492
+ return /\bFreeTierError\b/.test(text) || /\b403\b/.test(text) && /OpenCode's free tier can only be used from within OpenCode/i.test(text);
19493
+ }
19494
+ function zenFreeTierMessage(agent, harness) {
19495
+ const task = agent.includes("historian") ? "historian" : "dreamer";
19496
+ const host = harness === "omp" ? "Oh My Pi" : "Pi";
19497
+ return `${ZEN_FREE_TIER_FAILURE}: OpenCode Zen free models only run inside OpenCode; choose another ${task} model for ${host} (FreeTierError).`;
19498
+ }
19499
+ function classifyZenFreeTierFailure(result, model, agent, harness) {
19500
+ if (result.ok || !isZenModel(model))
19501
+ return result;
19502
+ const stderr = typeof result.meta?.stderr === "string" ? result.meta.stderr : "";
19503
+ if (!isZenFreeTierRefusal(result.error) && !isZenFreeTierRefusal(stderr))
19504
+ return result;
19505
+ return {
19506
+ ...result,
19507
+ error: zenFreeTierMessage(agent, harness),
19508
+ meta: {
19509
+ failureClass: ZEN_FREE_TIER_FAILURE,
19510
+ errorClass: "FreeTierError",
19511
+ ...typeof result.meta?.exitCode === "number" ? { exitCode: result.meta.exitCode } : {},
19512
+ ...typeof result.meta?.sawProtocolOutput === "boolean" ? { sawProtocolOutput: result.meta.sawProtocolOutput } : {}
19513
+ }
19514
+ };
19515
+ }
19516
+
19517
+ // src/subagent-runner.ts
19463
19518
  var PI_CODING_AGENT_MODULE = "@earendil-works/pi-coding-agent";
19464
19519
  var PI_CODING_AGENT_PACKAGE_NAMES = new Set([
19465
19520
  PI_CODING_AGENT_MODULE,
@@ -20011,6 +20066,9 @@ class PiSubagentRunner {
20011
20066
  }
20012
20067
  async runOnce(options, runMode, modelRefOverride) {
20013
20068
  const startTime = Date.now();
20069
+ const zenChild = STRICT_TOOL_ALLOWLIST.has(options.agent) && isZenModel(options.model);
20070
+ let deferredZenStderr = "";
20071
+ let reportedZenStderr = false;
20014
20072
  let recordedAccounting = false;
20015
20073
  const cap = subagentStepCap(options.agent);
20016
20074
  const budget = options.tokenBudget ? createDreamTokenBudget(options.tokenBudget) : undefined;
@@ -20034,7 +20092,7 @@ class PiSubagentRunner {
20034
20092
  subagent: options.accountingSubagent ?? inferAccountingSubagent(options.agent),
20035
20093
  task: options.accountingTask ?? null,
20036
20094
  startedAt: startTime,
20037
- status: result.ok ? "completed" : result.reason === "abort" ? "aborted" : result.reason === "timeout" ? "timed_out" : result.reason === "no_assistant" || result.reason === "truncated" ? "empty" : "failed",
20095
+ status: result.ok ? "completed" : result.meta?.failureClass === ZEN_FREE_TIER_FAILURE ? "failed" : result.reason === "abort" ? "aborted" : result.reason === "timeout" ? "timed_out" : result.reason === "no_assistant" || result.reason === "truncated" ? "empty" : "failed",
20038
20096
  messages,
20039
20097
  providerId: hasProvider ? modelRef?.slice(0, providerSeparator) : undefined,
20040
20098
  modelId: hasProvider ? modelRef?.slice(providerSeparator + 1) : modelRef,
@@ -20139,7 +20197,20 @@ class PiSubagentRunner {
20139
20197
  if (settled)
20140
20198
  return;
20141
20199
  settled = true;
20142
- if (isMemoryMapper) {
20200
+ if (zenChild) {
20201
+ const classified = classifyZenFreeTierFailure(result, options.model, options.agent, this.invocation.targetHarness);
20202
+ if (classified !== result && !classified.ok) {
20203
+ sessionLog2(options.accountingSessionId ?? "subagent", classified.error);
20204
+ }
20205
+ result = classified;
20206
+ if (deferredZenStderr && !reportedZenStderr) {
20207
+ emitProgress({
20208
+ type: "stderr",
20209
+ chunk: result.meta?.failureClass === ZEN_FREE_TIER_FAILURE ? zenFreeTierMessage(options.agent, this.invocation.targetHarness) : deferredZenStderr
20210
+ });
20211
+ }
20212
+ }
20213
+ if (isMemoryMapper && result.meta?.failureClass !== ZEN_FREE_TIER_FAILURE) {
20143
20214
  result = {
20144
20215
  ...result,
20145
20216
  meta: { ...result.meta, mappingMessages: [...mappingMessages] }
@@ -20169,6 +20240,12 @@ class PiSubagentRunner {
20169
20240
  const emitProgress = (event) => {
20170
20241
  if (!options.onProgress)
20171
20242
  return;
20243
+ if (zenChild && event.type === "raw_event" && isZenFreeTierRefusal(JSON.stringify(event.event))) {
20244
+ event = {
20245
+ ...event,
20246
+ event: { type: event.eventType, error: { type: "FreeTierError" } }
20247
+ };
20248
+ }
20172
20249
  try {
20173
20250
  options.onProgress(event);
20174
20251
  } catch {}
@@ -20282,7 +20359,17 @@ class PiSubagentRunner {
20282
20359
  if (stderr.length > 16000) {
20283
20360
  stderr = `…[truncated]${stderr.slice(-16000)}`;
20284
20361
  }
20285
- emitProgress({ type: "stderr", chunk: text });
20362
+ if (zenChild) {
20363
+ deferredZenStderr = stderr;
20364
+ if (!reportedZenStderr && isZenFreeTierRefusal(stderr)) {
20365
+ reportedZenStderr = true;
20366
+ emitProgress({
20367
+ type: "stderr",
20368
+ chunk: zenFreeTierMessage(options.agent, this.invocation.targetHarness)
20369
+ });
20370
+ }
20371
+ } else
20372
+ emitProgress({ type: "stderr", chunk: text });
20286
20373
  });
20287
20374
  child.stderr?.on("error", () => {});
20288
20375
  let finalAssistantText = null;
@@ -25711,7 +25798,7 @@ function buildEditSupersessionReclaim(input) {
25711
25798
  seenFile.add(filePath);
25712
25799
  continue;
25713
25800
  }
25714
- if (input.recentMessageIds && (tag.toolOwnerMessageId === null || input.recentMessageIds.has(tag.toolOwnerMessageId))) {
25801
+ if (tag.tagNumber > input.watermark || input.recentMessageIds && (tag.toolOwnerMessageId === null || input.recentMessageIds.has(tag.toolOwnerMessageId))) {
25715
25802
  continue;
25716
25803
  }
25717
25804
  if (realPendingTagIds.has(tag.tagNumber))
@@ -25809,6 +25896,51 @@ function readServedTemporalDecisions(db, sessionId, runtime, messageIds) {
25809
25896
  return result;
25810
25897
  }
25811
25898
 
25899
+ // ../plugin/src/shared/reclaim-distance.ts
25900
+ var RECLAIM_DISTANCE_USER_TURNS = 3;
25901
+ var RECLAIM_DISTANCE_WINDOW_FRACTION = 0.25;
25902
+ function isReclaimUserTurn(args) {
25903
+ return args.role === "user" && !args.syntheticHead && !args.synthetic && !args.ignored && args.parts.some((part) => {
25904
+ if (part.synthetic || part.ignored)
25905
+ return false;
25906
+ if (part.kind !== "text" && part.kind !== "image" && part.kind !== "file")
25907
+ return false;
25908
+ if (part.kind !== "text")
25909
+ return true;
25910
+ return stripReclaimMcText(part.text ?? "").trim().length > 0;
25911
+ });
25912
+ }
25913
+ function stripReclaimMcText(text) {
25914
+ return text.replace(/^§\d+§\s*/, "").replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, (reminder) => /^(?:Your next step: call ctx_reduce on the outputs you've already used|Still unstamped:|Housekeeping: .* are reclaimable\. Stamp each output with ctx_reduce|.* are reclaimable\. Make a ctx_reduce pass now|.* are still unstamped\. Call ctx_reduce now)/.test(reminder.slice("<system-reminder>".length).trimStart()) ? "" : reminder).replace(/<instruction name="deferred_notes">[\s\S]*?<\/instruction>/g, "");
25915
+ }
25916
+ function farBehindToolBookmark(entries, usableWindow) {
25917
+ let newerTurns = 0;
25918
+ let newerTokens = 0;
25919
+ const farTags = [];
25920
+ let firstYoungTag = Infinity;
25921
+ const seenOutputs = new Set;
25922
+ const tokenDistance = usableWindow > 0 && Number.isFinite(usableWindow) ? usableWindow * RECLAIM_DISTANCE_WINDOW_FRACTION : Infinity;
25923
+ for (let index = entries.length - 1;index >= 0; index--) {
25924
+ const entry = entries[index];
25925
+ if (!entry)
25926
+ continue;
25927
+ const tag = entry.toolOutputTag;
25928
+ if (tag !== undefined && !seenOutputs.has(tag)) {
25929
+ seenOutputs.add(tag);
25930
+ if (newerTurns >= RECLAIM_DISTANCE_USER_TURNS || newerTokens >= tokenDistance) {
25931
+ farTags.push(tag);
25932
+ } else {
25933
+ firstYoungTag = Math.min(firstYoungTag, tag);
25934
+ }
25935
+ }
25936
+ if (entry.userTurn)
25937
+ newerTurns++;
25938
+ if (Number.isFinite(entry.tokens) && entry.tokens > 0)
25939
+ newerTokens += entry.tokens;
25940
+ }
25941
+ return farTags.reduce((bookmark, tag) => tag < firstYoungTag ? Math.max(bookmark, tag) : bookmark, 0);
25942
+ }
25943
+
25812
25944
  // ../plugin/src/hooks/magic-context/tool-reclaim.ts
25813
25945
  function buildSyntheticToolReclaimOps(input) {
25814
25946
  const watermark = Math.max(0, input.watermark);
@@ -25840,10 +25972,74 @@ function buildSyntheticToolReclaimOps(input) {
25840
25972
  }
25841
25973
  return synthetic;
25842
25974
  }
25843
- function advanceToolReclaimWatermarkToCurrentMax(db, sessionId) {
25844
- const maxTagNumber = getMaxTagNumberBySession2(db, sessionId);
25845
- advanceToolReclaimWatermark(db, sessionId, maxTagNumber);
25846
- return maxTagNumber;
25975
+ function advanceToolReclaimWatermarkByDistance(db, sessionId, entries, usableWindow) {
25976
+ const bookmark = farBehindToolBookmark(entries, usableWindow);
25977
+ advanceToolReclaimWatermark(db, sessionId, bookmark);
25978
+ return bookmark;
25979
+ }
25980
+ function toolReclaimDistanceEntries(messages, targets) {
25981
+ const outputTags = new Map;
25982
+ for (const [tag, target] of targets) {
25983
+ for (const location of target.mutationParts ?? []) {
25984
+ const part = distancePart(location.part);
25985
+ if (part.kind === "tool_result" || part.kind === "tool")
25986
+ outputTags.set(location.part, tag);
25987
+ }
25988
+ }
25989
+ const entries = [];
25990
+ for (const message of messages) {
25991
+ const parts = message.parts.map(distancePart);
25992
+ let userTurn = isReclaimUserTurn({ ...message.info, parts });
25993
+ for (const [index, part] of parts.entries()) {
25994
+ const authored = isReclaimUserTurn({ role: "user", parts: [part] });
25995
+ entries.push({
25996
+ tokens: message.info.syntheticHead ? 0 : estimateTokens(stripReclaimMcText(part.text ?? "")) + part.imageTokens,
25997
+ userTurn: userTurn && authored,
25998
+ toolOutputTag: outputTags.get(message.parts[index])
25999
+ });
26000
+ if (authored)
26001
+ userTurn = false;
26002
+ }
26003
+ }
26004
+ return entries;
26005
+ }
26006
+ function distancePart(raw) {
26007
+ if (!raw || typeof raw !== "object")
26008
+ return { kind: "structural", imageTokens: 0 };
26009
+ const part = raw;
26010
+ const provenance = { synthetic: part.synthetic === true, ignored: part.ignored === true };
26011
+ if (typeof part.getText === "function") {
26012
+ const text = part.getText();
26013
+ return {
26014
+ ...provenance,
26015
+ kind: String(part.kind),
26016
+ text: typeof text === "string" ? text : undefined,
26017
+ imageTokens: typeof part.imageTokens === "function" ? Number(part.imageTokens()) : 0
26018
+ };
26019
+ }
26020
+ const metadata = { ...provenance, imageTokens: estimatePartImageTokens(raw) };
26021
+ if (part.type === "tool") {
26022
+ const state = part.state;
26023
+ return {
26024
+ ...metadata,
26025
+ kind: "tool",
26026
+ text: `${JSON.stringify(state?.input ?? {})}
26027
+ ${typeof state?.output === "string" ? state.output : JSON.stringify(state?.output ?? "")}`
26028
+ };
26029
+ }
26030
+ if (part.type === "tool_use")
26031
+ return { ...metadata, kind: "tool_use", text: JSON.stringify(part.input ?? {}) };
26032
+ if (part.type === "tool_result")
26033
+ return {
26034
+ ...metadata,
26035
+ kind: "tool_result",
26036
+ text: typeof part.content === "string" ? part.content : JSON.stringify(part.content ?? "")
26037
+ };
26038
+ return {
26039
+ ...metadata,
26040
+ kind: String(part.type),
26041
+ text: typeof part.text === "string" ? part.text : typeof part.thinking === "string" ? part.thinking : undefined
26042
+ };
25847
26043
  }
25848
26044
 
25849
26045
  // ../plugin/src/shared/recovery-reasoning-prefix.ts
@@ -28606,6 +28802,8 @@ ${chunkText}`,
28606
28802
  }
28607
28803
  }
28608
28804
  function piSubagentFailureReason(failure) {
28805
+ if (failure.meta?.failureClass === ZEN_FREE_TIER_FAILURE)
28806
+ return ZEN_FREE_TIER_FAILURE;
28609
28807
  if (PRODUCER_PROMPT_FIT_FAILURE_PATTERN.test(failure.error))
28610
28808
  return failure.error;
28611
28809
  if (["step_limit", "token_budget", "invalid_prompt"].includes(failure.reason)) {
@@ -28914,6 +29112,59 @@ function recordPiTransformTiming(sample) {
28914
29112
  // src/ctx-reduce-nudge-pi.ts
28915
29113
  import { randomUUID as randomUUID3 } from "node:crypto";
28916
29114
 
29115
+ // src/provider-visible-parts-pi.ts
29116
+ function isRecord4(value) {
29117
+ return value !== null && typeof value === "object" && !Array.isArray(value);
29118
+ }
29119
+ var PART_FIELDS = {
29120
+ text: ["type", "text", "textSignature"],
29121
+ thinking: ["type", "thinking", "thinkingSignature", "redacted"],
29122
+ image: ["type", "data", "mimeType"],
29123
+ toolCall: [
29124
+ "type",
29125
+ "id",
29126
+ "name",
29127
+ "arguments",
29128
+ "thoughtSignature",
29129
+ "namespace"
29130
+ ]
29131
+ };
29132
+ var MESSAGE_FIELDS = [
29133
+ "role",
29134
+ "provider",
29135
+ "api",
29136
+ "model",
29137
+ "stopReason",
29138
+ "toolCallId",
29139
+ "toolName",
29140
+ "isError"
29141
+ ];
29142
+ function pick(value, fields) {
29143
+ const view = {};
29144
+ for (const field of fields) {
29145
+ if (Object.hasOwn(value, field))
29146
+ view[field] = value[field];
29147
+ }
29148
+ return view;
29149
+ }
29150
+ function providerVisiblePiPart(value, providerApi) {
29151
+ if (providerApi === "pi-messages")
29152
+ return value;
29153
+ if (Array.isArray(value))
29154
+ return value.map((part) => providerVisiblePiPart(part, providerApi));
29155
+ if (!isRecord4(value))
29156
+ return value;
29157
+ if (typeof value.role === "string") {
29158
+ const view = pick(value, MESSAGE_FIELDS);
29159
+ if (Object.hasOwn(value, "content")) {
29160
+ view.content = Array.isArray(value.content) ? value.content.map((part) => providerVisiblePiPart(part, providerApi)) : typeof value.content === "string" ? value.content : undefined;
29161
+ }
29162
+ return view;
29163
+ }
29164
+ const type = typeof value.type === "string" ? value.type : "";
29165
+ return pick(value, Object.hasOwn(PART_FIELDS, type) ? PART_FIELDS[type] : ["type"]);
29166
+ }
29167
+
28917
29168
  // src/tail-hygiene-walk-pi.ts
28918
29169
  var TAG_PREFIX = /^§(\d+)§\s*/;
28919
29170
  var SYNTHETIC_TODO_PREFIX = "mc_synthetic_todo_";
@@ -28927,7 +29178,7 @@ function clearPiTailHygieneContentMemo() {
28927
29178
  }
28928
29179
  var FNV1A_32_OFFSET = 2166136261;
28929
29180
  var FNV1A_32_PRIME = 16777619;
28930
- function isRecord4(value) {
29181
+ function isRecord5(value) {
28931
29182
  return value !== null && typeof value === "object";
28932
29183
  }
28933
29184
  function fnv1a32(value) {
@@ -28942,7 +29193,7 @@ function safeStableStringify(value) {
28942
29193
  const seen = new Set;
28943
29194
  try {
28944
29195
  return JSON.stringify(value, (_key, current) => {
28945
- if (!isRecord4(current) || Array.isArray(current))
29196
+ if (!isRecord5(current) || Array.isArray(current))
28946
29197
  return current;
28947
29198
  if (seen.has(current))
28948
29199
  return "[Circular]";
@@ -29001,7 +29252,7 @@ function messageIdentity(message, index, stableId) {
29001
29252
  const resolved = stableId?.(message, index);
29002
29253
  if (resolved)
29003
29254
  return resolved;
29004
- if (isRecord4(message)) {
29255
+ if (isRecord5(message)) {
29005
29256
  if (typeof message.responseId === "string" && message.responseId.length > 0) {
29006
29257
  return `response:${message.responseId}`;
29007
29258
  }
@@ -29061,13 +29312,13 @@ function collectToolArcs(input) {
29061
29312
  const messageIds = input.messages.map((message, index) => messageIdentity(message, index, input.stableId));
29062
29313
  for (let messageIndex = 0;messageIndex < input.messages.length; messageIndex += 1) {
29063
29314
  const raw = input.messages[messageIndex];
29064
- if (!isRecord4(raw))
29315
+ if (!isRecord5(raw))
29065
29316
  continue;
29066
29317
  const role = raw.role;
29067
29318
  if (role === "assistant" && Array.isArray(raw.content)) {
29068
29319
  for (let partIndex = 0;partIndex < raw.content.length; partIndex += 1) {
29069
29320
  const part = raw.content[partIndex];
29070
- if (!isRecord4(part) || part.type !== "toolCall")
29321
+ if (!isRecord5(part) || part.type !== "toolCall")
29071
29322
  continue;
29072
29323
  if (typeof part.id !== "string" || part.id.length === 0)
29073
29324
  continue;
@@ -29078,7 +29329,7 @@ function collectToolArcs(input) {
29078
29329
  ownerId,
29079
29330
  ownerIndex: messageIndex,
29080
29331
  toolName: typeof part.name === "string" ? part.name : null,
29081
- sentinel: isRecord4(part.arguments) && typeof part.arguments.__magic_context_dropped__ === "string",
29332
+ sentinel: isRecord5(part.arguments) && typeof part.arguments.__magic_context_dropped__ === "string",
29082
29333
  parts: [part]
29083
29334
  };
29084
29335
  arcs.push(arc);
@@ -29110,7 +29361,7 @@ function collectToolArcs(input) {
29110
29361
  if (!Array.isArray(raw.content))
29111
29362
  continue;
29112
29363
  for (const part of raw.content) {
29113
- if (!isRecord4(part))
29364
+ if (!isRecord5(part))
29114
29365
  continue;
29115
29366
  arc.parts.push(part);
29116
29367
  arcByPart.set(part, arc);
@@ -29311,11 +29562,20 @@ function attributeTags(input, arcs, messageIds) {
29311
29562
  }
29312
29563
  return { messageTags, tagsByNumber };
29313
29564
  }
29314
- function excludedDraft(key, value) {
29565
+ var partJsonMemo = new TailHygieneJsonMemo;
29566
+ var excludedViews = new WeakMap;
29567
+ function excludedDraftForApi(key, value, providerApi) {
29568
+ let view = value !== null && typeof value === "object" ? excludedViews.get(value) : undefined;
29569
+ if (view === undefined) {
29570
+ view = providerVisiblePiPart(value, providerApi);
29571
+ if (value !== null && typeof value === "object")
29572
+ excludedViews.set(value, view);
29573
+ }
29315
29574
  return {
29316
29575
  key,
29317
29576
  kind: "excluded",
29318
- content: typeof value === "string" ? value : safeStableStringify(value),
29577
+ content: "",
29578
+ contentHash: partJsonMemo.get(key, view, () => typeof view === "string" ? partHash("excluded", view) : piJsonHash(view, () => safeStableStringify(view)), true),
29319
29579
  tokens: 0
29320
29580
  };
29321
29581
  }
@@ -29340,7 +29600,7 @@ function finalizeParts(drafts, pendingDropTagNumbers, protectedTagNumbers, newes
29340
29600
  u += uTokens;
29341
29601
  return {
29342
29602
  key: draft.key,
29343
- contentHash: partHash(draft.kind, draft.content),
29603
+ contentHash: draft.contentHash ?? partHash(draft.kind, draft.content),
29344
29604
  kind: draft.kind,
29345
29605
  tokens,
29346
29606
  uTokens,
@@ -29360,6 +29620,19 @@ function finalizeParts(drafts, pendingDropTagNumbers, protectedTagNumbers, newes
29360
29620
  };
29361
29621
  }
29362
29622
  function measurePiTailHygiene(input) {
29623
+ partJsonMemo.beginPass();
29624
+ excludedViews = new WeakMap;
29625
+ let providerApi = input.providerApi;
29626
+ if (providerApi === undefined) {
29627
+ for (let index = input.messages.length - 1;index >= 0; index--) {
29628
+ const message = input.messages[index];
29629
+ if (isRecord5(message) && message.role === "assistant" && typeof message.api === "string") {
29630
+ providerApi = message.api;
29631
+ break;
29632
+ }
29633
+ }
29634
+ }
29635
+ const excludedDraft = (key, value) => excludedDraftForApi(key, value, providerApi);
29363
29636
  const { arcs, arcByPart, messageIds } = collectToolArcs(input);
29364
29637
  const { messageTags, tagsByNumber } = attributeTags(input, arcs, messageIds);
29365
29638
  const drafts = [];
@@ -29370,7 +29643,7 @@ function measurePiTailHygiene(input) {
29370
29643
  if (messageIndex === input.messages.length - 1)
29371
29644
  newestMessagePartStart = drafts.length;
29372
29645
  const messageKey = messageIds[messageIndex] ?? `pi-message:${messageIndex}`;
29373
- if (!isRecord4(raw)) {
29646
+ if (!isRecord5(raw)) {
29374
29647
  drafts.push(excludedDraft(`${messageKey}\x00excluded`, raw));
29375
29648
  continue;
29376
29649
  }
@@ -29409,7 +29682,7 @@ function measurePiTailHygiene(input) {
29409
29682
  for (let partIndex = 0;partIndex < raw.content.length; partIndex += 1) {
29410
29683
  const part = raw.content[partIndex];
29411
29684
  const key = `${messageKey}\x00${partIndex}`;
29412
- if (!isRecord4(part)) {
29685
+ if (!isRecord5(part)) {
29413
29686
  drafts.push(excludedDraft(`${key}\x00excluded`, part));
29414
29687
  continue;
29415
29688
  }
@@ -29479,7 +29752,7 @@ function measurePiTailHygiene(input) {
29479
29752
  drafts.push(excludedDraft(`${key}\x00toolInput`, part));
29480
29753
  continue;
29481
29754
  }
29482
- const content = safeStableStringify(part.arguments);
29755
+ const content = partJsonMemo.get(`${key}\x00input`, part.arguments, () => safeStableStringify(part.arguments));
29483
29756
  if (!content) {
29484
29757
  drafts.push(excludedDraft(`${key}\x00toolInput`, part));
29485
29758
  } else {
@@ -29529,7 +29802,7 @@ function refreshPiTailHygieneBaseline(input) {
29529
29802
  })
29530
29803
  };
29531
29804
  const now = input.now ?? Date.now();
29532
- const refrozen = (mismatch) => ({
29805
+ const refrozen = (mismatch) => rememberCurrentToolOutputCount({
29533
29806
  ...freezeTailHygieneMeasurement(measured),
29534
29807
  protectedToolsPolicy,
29535
29808
  hygieneUnitsVersion: frozenCalibration.hygieneUnitsVersion,
@@ -29543,7 +29816,7 @@ function refreshPiTailHygieneBaseline(input) {
29543
29816
  channel1PostReduceGrace: input.previous?.channel1PostReduceGrace,
29544
29817
  lastPrefixMismatch: mismatch,
29545
29818
  realUserTurnCount: rawMeasured.realUserTurnCount
29546
- });
29819
+ }, measured);
29547
29820
  if (input.cacheBusting || !input.previous)
29548
29821
  return refrozen();
29549
29822
  const prefix = compareMeasuredTailPrefix(input.previous.baselineParts, measured.parts);
@@ -29557,7 +29830,7 @@ function refreshPiTailHygieneBaseline(input) {
29557
29830
  if (part.kind !== "toolOutput" || !part.protected)
29558
29831
  turnDeltaU += part.uTokens;
29559
29832
  }
29560
- return {
29833
+ return rememberCurrentToolOutputCount({
29561
29834
  ...input.previous,
29562
29835
  protectedToolsPolicy,
29563
29836
  turnDeltaU,
@@ -29567,7 +29840,7 @@ function refreshPiTailHygieneBaseline(input) {
29567
29840
  contentSignature: measured.contentSignature,
29568
29841
  lastPrefixMismatch: undefined,
29569
29842
  realUserTurnCount: rawMeasured.realUserTurnCount
29570
- };
29843
+ }, measured);
29571
29844
  }
29572
29845
  function effectivePiTailHygiene(baseline) {
29573
29846
  const t = Math.ceil(Math.max(0, baseline.baselineT + baseline.turnDeltaT));
@@ -29577,7 +29850,7 @@ function effectivePiTailHygiene(baseline) {
29577
29850
  function measurePiToolResultDelta(content) {
29578
29851
  let tokens = 0;
29579
29852
  for (const part of content) {
29580
- if (!isRecord4(part))
29853
+ if (!isRecord5(part))
29581
29854
  continue;
29582
29855
  if (part.type === "text" && typeof part.text === "string") {
29583
29856
  const text = stripChannel1ReminderSpans(part.text);
@@ -29680,7 +29953,7 @@ function maybeChannel1ReminderForToolResult(args) {
29680
29953
  }
29681
29954
  const block = {
29682
29955
  type: "text",
29683
- text: buildChannel1Reminder(decision.level, decision.undroppedTokens, reclaimableToolOutputCount(state.baselineParts), currentReclaimHints(db, sessionId, state.oldestReclaimableToolTags), decision.sticky)
29956
+ text: buildChannel1Reminder(decision.level, decision.undroppedTokens, currentReclaimableToolOutputCount(state), currentReclaimHints(db, sessionId, state.oldestReclaimableToolTags), decision.sticky)
29684
29957
  };
29685
29958
  setChannel1NudgeState(db, sessionId, {
29686
29959
  ...nextNudgeState,
@@ -29718,7 +29991,7 @@ function maybeDeliverChannel2Pi(pi, db, sessionId) {
29718
29991
  try {
29719
29992
  const message = {
29720
29993
  customType: CHANNEL2_NUDGE_CUSTOM_TYPE,
29721
- content: buildChannel2Reminder(undropped, reclaimableToolOutputCount(baseline.baselineParts), currentReclaimHints(db, sessionId, baseline.oldestReclaimableToolTags)),
29994
+ content: buildChannel2Reminder(undropped, currentReclaimableToolOutputCount(baseline), currentReclaimHints(db, sessionId, baseline.oldestReclaimableToolTags)),
29722
29995
  display: false,
29723
29996
  details: { kind: "channel-2-ceiling-nudge" }
29724
29997
  };
@@ -35649,6 +35922,7 @@ function createPiFallbackIndex() {
35649
35922
  import { createHash as createHash12, randomUUID as randomUUID4 } from "node:crypto";
35650
35923
 
35651
35924
  // src/tokenize-pi-messages.ts
35925
+ var PI_IMAGE_TOKENS = 1200;
35652
35926
  function tokenizePiMessages(messages, options) {
35653
35927
  let conversation = 0;
35654
35928
  let toolCall = 0;
@@ -35706,7 +35980,7 @@ function tokenizePiMessages(messages, options) {
35706
35980
  }
35707
35981
  break;
35708
35982
  case "image":
35709
- conversation += 1200;
35983
+ conversation += PI_IMAGE_TOKENS;
35710
35984
  break;
35711
35985
  case "toolCall":
35712
35986
  if (typeof p.name === "string")
@@ -35735,7 +36009,7 @@ function tokenizePiMessages(messages, options) {
35735
36009
  if (p.type === "text" && typeof p.text === "string") {
35736
36010
  toolCall += estimateTokens(p.text);
35737
36011
  } else if (p.type === "image") {
35738
- toolCall += 1200;
36012
+ toolCall += PI_IMAGE_TOKENS;
35739
36013
  }
35740
36014
  }
35741
36015
  }
@@ -38309,6 +38583,13 @@ function stripThinkingParts(message) {
38309
38583
  assistant.content = strippedContent;
38310
38584
  return before - strippedContent.length;
38311
38585
  }
38586
+
38587
+ class PiThinkingBindingRecoveryRefusal extends EmergencyFailClosedError {
38588
+ constructor() {
38589
+ super("Pi thinking-binding recovery has no valid new strip shape; this turn was not sent. Send a new message or start a new session.", { code: "pi_thinking_binding_no_valid_shape" });
38590
+ this.name = "PiThinkingBindingRecoveryRefusal";
38591
+ }
38592
+ }
38312
38593
  function applyPiThinkingBindingRecovery(args) {
38313
38594
  const protectedMessages = latestAssistantTurnMessages(args.messages);
38314
38595
  const frozenEntryIds = frozenBindingEntryIds(args.db, args.sessionId);
@@ -38318,14 +38599,17 @@ function applyPiThinkingBindingRecovery(args) {
38318
38599
  if (flagTarget) {
38319
38600
  const entryIds = new Set;
38320
38601
  for (let index = 0;index < args.messages.length; index += 1) {
38321
- if (protectedMessages.has(args.messages[index]))
38602
+ if (!hasThinkingPart(args.messages[index]))
38322
38603
  continue;
38323
38604
  const entryId = args.entryIds[index];
38324
- if (entryId && hasThinkingPart(args.messages[index]))
38325
- entryIds.add(entryId);
38605
+ if (!entryId)
38606
+ throw new PiThinkingBindingRecoveryRefusal;
38607
+ entryIds.add(entryId);
38326
38608
  }
38327
38609
  const newEntryIds = [...entryIds].filter((id) => !frozenEntryIds.has(id));
38328
- if (newEntryIds.length === 0 || addMergedReasoningStrippedIds(args.db, args.sessionId, [
38610
+ if (newEntryIds.length === 0)
38611
+ throw new PiThinkingBindingRecoveryRefusal;
38612
+ if (addMergedReasoningStrippedIds(args.db, args.sessionId, [
38329
38613
  ...newEntryIds.map(thinkingBindingRecoveryFrozenId),
38330
38614
  ...args.endOfPassOrder ? [THINKING_BINDING_STRIP_ORDER_END_MARKER] : []
38331
38615
  ])) {
@@ -38333,7 +38617,8 @@ function applyPiThinkingBindingRecovery(args) {
38333
38617
  frozenEntryIds.add(id);
38334
38618
  applied = { flagTarget, entryIds: [...entryIds] };
38335
38619
  reportBindingRecovery(args.sessionId, args.report, `thinking-binding recovery consumed on context pass target=${flagTarget} entries=${applied.entryIds.length} [${applied.entryIds.join(",")}]`);
38336
- }
38620
+ } else
38621
+ throw new PiThinkingBindingRecoveryRefusal;
38337
38622
  }
38338
38623
  const restoringActiveTurn = latestThinkingRecoveryCoversActiveTurn({
38339
38624
  db: args.db,
@@ -38350,6 +38635,12 @@ function applyPiThinkingBindingRecovery(args) {
38350
38635
  }
38351
38636
  return applied;
38352
38637
  }
38638
+ function hasUnfrozenPiThinking(args) {
38639
+ return isPrefixBoundThinkingModel(args.provider, args.model) && args.messages.some((message, index) => {
38640
+ const entryId = args.entryIds[index];
38641
+ return hasThinkingPart(message) && (!entryId || !args.frozen.has(entryId));
38642
+ });
38643
+ }
38353
38644
  function applyPiProactiveThinkingStrip(args) {
38354
38645
  if (!args.cacheBustingPass)
38355
38646
  return null;
@@ -39606,6 +39897,12 @@ function createOpaqueTranscriptMessage(working, index, sessionId, _markDirty, en
39606
39897
  function createPiUserStringPart(working, messageIndex, markDirty) {
39607
39898
  return {
39608
39899
  kind: "text",
39900
+ get synthetic() {
39901
+ return working[messageIndex].synthetic;
39902
+ },
39903
+ get ignored() {
39904
+ return working[messageIndex].ignored;
39905
+ },
39609
39906
  id: undefined,
39610
39907
  getText() {
39611
39908
  const msg = working[messageIndex];
@@ -39645,6 +39942,12 @@ function createPiUserArrayPart(working, messageIndex, partIndex, markDirty) {
39645
39942
  const kind = classifyContent(part);
39646
39943
  return {
39647
39944
  kind,
39945
+ synthetic: msg.synthetic || part?.synthetic,
39946
+ ignored: msg.ignored || part?.ignored,
39947
+ imageTokens() {
39948
+ const current = working[messageIndex].content;
39949
+ return Array.isArray(current) && current[partIndex]?.type === "image" ? PI_IMAGE_TOKENS : 0;
39950
+ },
39648
39951
  id: undefined,
39649
39952
  getText() {
39650
39953
  const current = working[messageIndex].content;
@@ -39851,6 +40154,9 @@ function createPiToolResultPart(working, messageIndex, partIndex, markDirty) {
39851
40154
  return {
39852
40155
  kind,
39853
40156
  id: msg.toolCallId,
40157
+ imageTokens() {
40158
+ return working[messageIndex].content[partIndex]?.type === "image" ? PI_IMAGE_TOKENS : 0;
40159
+ },
39854
40160
  remove() {
39855
40161
  return markToolRemoval(working, messageIndex, partIndex);
39856
40162
  },
@@ -39995,6 +40301,15 @@ var afterFallbackAdoptionForTests;
39995
40301
  var pendingDecisionLogObserverForTests;
39996
40302
  var mutationGateObserverForTests;
39997
40303
  var lkgRecoveryLogObserverForTests;
40304
+ var pipelineResultObserverForTests;
40305
+ function observePipelineResultForTests(sessionId, result) {
40306
+ pipelineResultObserverForTests?.(sessionId, {
40307
+ prefixBustPermitted: result.prefixBustPermitted,
40308
+ bustedThisPass: result.bustedThisPass,
40309
+ identityRebuilt: result.identityRebuilt,
40310
+ signedPrefixRewritten: result.signedPrefixRewritten
40311
+ });
40312
+ }
39998
40313
  var variantChangeLogObserverForTests;
39999
40314
  var beforePipelineForTests;
40000
40315
  function logPiLkgRecovery(sessionId, message) {
@@ -42186,6 +42501,7 @@ function registerPiContextHandler(pi, baseOptions) {
42186
42501
  protectedTokens: options.protectedTokens,
42187
42502
  protectedTokenTierOverrides: options.protectedTokenTierOverrides,
42188
42503
  usableSoft: windowGeometry?.usableSoft ?? usageContextLimit ?? 200000,
42504
+ reclaimUsableWindow: windowGeometry?.usableSoft ?? usageContextLimit ?? 0,
42189
42505
  heuristics: options.heuristics,
42190
42506
  emergencyCeilingTokens,
42191
42507
  injection: options.injection ? {
@@ -42257,6 +42573,7 @@ function registerPiContextHandler(pi, baseOptions) {
42257
42573
  }
42258
42574
  };
42259
42575
  let result = await budget.waitMandatory(runPipeline(pipelineArgs));
42576
+ observePipelineResultForTests(sessionId, result);
42260
42577
  logTransformTiming(sessionId, "runPipeline", tRunPipeline);
42261
42578
  if (result.identityRebuilt || result.lkgFrozenReleaseReason)
42262
42579
  schedulerDecision = "execute";
@@ -42432,7 +42749,7 @@ function registerPiContextHandler(pi, baseOptions) {
42432
42749
  hostEditBeforeNewestThinking = stickyBefore === null || [...stickyAfter].some((key) => !stickyBefore.has(key)) || JSON.stringify(getPersistedTodoSyntheticAnchor(options.db, sessionId)) !== todoAnchorBefore;
42433
42750
  } catch {}
42434
42751
  const outputEntryIds = resolvePiLkgOutputEntryIds(outputMessages, result.syntheticLeadingCount, (message) => result.lkgEntryIdByRef.get(message) ?? result.postCommitEntryIdByRef.get(message) ?? bindingEntryIdByRef.get(message)).map((entryId) => entryId ?? undefined);
42435
- const thinkingBindingRecoveryApplied = bindingStripOrder === "end" && !result.signedPrefixRewritten ? applyPiThinkingBindingRecovery({
42752
+ const thinkingBindingRecoveryApplied = bindingStripOrder === "end" && (!result.signedPrefixRewritten || !result.prefixBustPermitted) ? applyPiThinkingBindingRecovery({
42436
42753
  db: options.db,
42437
42754
  sessionId,
42438
42755
  messages: outputMessages,
@@ -42454,7 +42771,7 @@ function registerPiContextHandler(pi, baseOptions) {
42454
42771
  entryIds: outputEntryIds,
42455
42772
  provider: lkgProviderKey ?? undefined,
42456
42773
  model: ctx.model?.id,
42457
- cacheBustingPass: !!recovery.rebuildReason || result.signedPrefixRewritten || result.prefixBustPermitted && !result.strictThinkingKept && (isCacheBusting || result.prefixRebuildAlreadyPriced || result.executedWorkThisPass && (result.prefixEditBesidesReasoningTrim || hostEditBeforeNewestThinking)),
42774
+ cacheBustingPass: result.prefixBustPermitted && !result.strictThinkingKept && (result.signedPrefixRewritten || isCacheBusting || result.prefixRebuildAlreadyPriced || result.executedWorkThisPass && (result.prefixEditBesidesReasoningTrim || hostEditBeforeNewestThinking)),
42458
42775
  stripActiveTurn: result.signedPrefixRewritten,
42459
42776
  requirePersistence: !!recovery.rebuildReason,
42460
42777
  report: (line) => sessionLog2(sessionId, line)
@@ -42497,6 +42814,7 @@ function registerPiContextHandler(pi, baseOptions) {
42497
42814
  const previousBaseline = getPiChannel1Baseline(sessionId);
42498
42815
  const baseline = refreshPiTailHygieneBaseline({
42499
42816
  messages: outputMessages,
42817
+ providerApi: ctx.model?.api,
42500
42818
  tags,
42501
42819
  tagCacheKey: result.channelBaselineSnapshot.tagCacheKey,
42502
42820
  protectedTagNumbers,
@@ -42636,6 +42954,7 @@ function registerPiContextHandler(pi, baseOptions) {
42636
42954
  percentage: Math.max(95, pipelineArgs.contextUsage.percentage)
42637
42955
  }
42638
42956
  }));
42957
+ observePipelineResultForTests(sessionId, result);
42639
42958
  fitReclaimedThisPass = true;
42640
42959
  inputForFitReclaim = undefined;
42641
42960
  outputMessages = result.messages;
@@ -42647,7 +42966,7 @@ function registerPiContextHandler(pi, baseOptions) {
42647
42966
  entryIds: retryIds.map((id) => id ?? undefined),
42648
42967
  provider: ctx.model?.provider,
42649
42968
  model: ctx.model?.id,
42650
- cacheBustingPass: true,
42969
+ cacheBustingPass: result.prefixBustPermitted,
42651
42970
  stripActiveTurn: true
42652
42971
  });
42653
42972
  estimate = estimatePiOutgoingInputTokens(outputMessages, envelope, undefined, rawFallbackLimit);
@@ -42748,6 +43067,7 @@ function registerPiContextHandler(pi, baseOptions) {
42748
43067
  }
42749
43068
  }));
42750
43069
  outputMessages = result.messages;
43070
+ observePipelineResultForTests(sessionId, result);
42751
43071
  injectTodo();
42752
43072
  if (upperCursor)
42753
43073
  recordPiUpperEstimateReclaim(options.db, currentUpperCursor() ?? upperCursor, reservation);
@@ -42759,7 +43079,7 @@ function registerPiContextHandler(pi, baseOptions) {
42759
43079
  entryIds: resolvePiLkgOutputEntryIds(outputMessages, result.syntheticLeadingCount, (message) => result.lkgEntryIdByRef.get(message) ?? result.postCommitEntryIdByRef.get(message)).map((id) => id ?? undefined),
42760
43080
  provider: ctx.model?.provider,
42761
43081
  model: ctx.model?.id,
42762
- cacheBustingPass: result.bustedThisPass,
43082
+ cacheBustingPass: result.prefixBustPermitted,
42763
43083
  stripActiveTurn: result.signedPrefixRewritten
42764
43084
  });
42765
43085
  estimate = estimatePiOutgoingInputTokens(outputMessages, envelope, undefined, outgoingFitLimit);
@@ -43631,29 +43951,37 @@ async function runPipeline(args) {
43631
43951
  let activeThinkingTurn = hasActiveAnthropicThinkingTurn(args.messages, args.resolvedProviderID, args.resolvedModelID);
43632
43952
  let protectedSignedPrefix = activeThinkingTurn && args.reasoningClearing?.prefixBound === true;
43633
43953
  let rewritingSignedPrefix = false;
43954
+ let isCacheBustingPass = args.recoveryRebuildReason === "lkg_recovery_input_rebuild" || (!!args.recoveryRebuildReason || args.forceSignedRebuildForFit === true) && hasUnfrozenPiThinking({
43955
+ messages: args.messages,
43956
+ entryIds: args.messages.map((message, index) => args.lkgEntryIds?.[index] ?? resolvePiRealStableId(message, index, args.entryIds, args.entryIdByRef ?? undefined)),
43957
+ frozen: frozenBindingEntryIds(args.db, args.sessionId),
43958
+ provider: args.resolvedProviderID,
43959
+ model: args.resolvedModelID
43960
+ });
43634
43961
  let workingForRewrite;
43635
- const stripForPrefixRewrite = () => {
43962
+ const stripForPrefixRewrite = (permitRewrite = true) => {
43963
+ isCacheBustingPass ||= permitRewrite;
43636
43964
  const messages = workingForRewrite ?? args.messages;
43637
43965
  const result = applyPiProactiveThinkingStrip({
43638
43966
  db: args.db,
43639
43967
  sessionId: args.sessionId,
43640
43968
  messages,
43641
- entryIds: messages.map((message, index) => resolvePiStableId(message, index, args.entryIds, args.entryIdByRef ?? undefined)),
43969
+ entryIds: messages.map((message, index) => args.lkgEntryIds?.[index] ?? resolvePiRealStableId(message, index, args.entryIds, args.entryIdByRef ?? undefined)),
43642
43970
  provider: args.resolvedProviderID,
43643
43971
  model: args.resolvedModelID,
43644
- cacheBustingPass: true,
43972
+ cacheBustingPass: isCacheBustingPass,
43645
43973
  stripActiveTurn: true,
43646
43974
  persistOnly: true,
43647
43975
  requirePersistence: !!args.recoveryRebuildReason
43648
43976
  });
43649
- if (activeThinkingTurn && !result)
43977
+ if (activeThinkingTurn && isCacheBustingPass && !result)
43650
43978
  throw new Error("Cannot persist signed thinking omission before prefix rewrite");
43651
43979
  rewritingSignedPrefix = true;
43652
43980
  activeThinkingTurn = false;
43653
43981
  protectedSignedPrefix = false;
43654
43982
  };
43655
43983
  if (args.recoveryRebuildReason || args.forceSignedRebuildForFit && protectedSignedPrefix)
43656
- stripForPrefixRewrite();
43984
+ stripForPrefixRewrite(isCacheBustingPass);
43657
43985
  const realStableId = (msg, index) => resolvePiRealStableId(msg, index, args.entryIds, args.entryIdByRef ?? undefined);
43658
43986
  const passFallbackIds = settlePiFallbackOccurrences(args.db, args.sessionId, piContentFallbackIds(args.messages, realStableId));
43659
43987
  const stableIdResolver = (msg, index) => realStableId(msg, index) ?? passFallbackIds[index] ?? resolvePiStableId(msg, index);
@@ -43888,13 +44216,13 @@ async function runPipeline(args) {
43888
44216
  const heldIdleExpiryRebuild = protectedSignedPrefix && piHardSignals?.cacheExpired === true;
43889
44217
  const rideSignals = {
43890
44218
  subagentExecute: args.sessionMeta.isSubagent && args.schedulerDecision === "execute",
43891
- hardFold: foldBustsServedPrefixThisPass || firstRenderBust || heldIdleExpiryRebuild,
44219
+ hardFold: foldBustsServedPrefixThisPass || firstRenderBust || heldIdleExpiryRebuild || isCacheBustingPass,
43892
44220
  force: (args.forceMaterialization === true || emergencyDropEligible) && (args.contextUsage.percentage >= 95 || getEmergencyInputSample(args.db, args.sessionId) === 0),
43893
44221
  explicitFlush: hasPendingMaterializeSignal || deferredMaterializeEligible && !prefixPreflightContended,
43894
44222
  publishedHistory: !prefixPreflightContended && (args.isCacheBusting || publishedM1RefreshedThisPass || canConsumeDeferredLate && deferredHistoryWasPendingAtPassStart)
43895
44223
  };
43896
44224
  let prefixMutationAllowed = !protectedSignedPrefix || firstRenderBust || heldIdleExpiryRebuild || emergencyDropEligible;
43897
- let isCacheBustingPass = prefixMutationAllowed && hasReclaimRide(rideSignals);
44225
+ isCacheBustingPass = prefixMutationAllowed && hasReclaimRide(rideSignals);
43898
44226
  let publishedWorkDrainAllowed = isCacheBustingPass;
43899
44227
  const usesTokenProtection = args.protectedTokenTierOverrides !== undefined || args.protectedTokens !== undefined;
43900
44228
  const resolveProtectionFloor = () => resolveEpochFloorForPass(args.db, args.sessionId, {
@@ -43905,7 +44233,7 @@ async function runPipeline(args) {
43905
44233
  onRejectedProjectOverride: (warning) => sessionLog2(args.sessionId, warning)
43906
44234
  });
43907
44235
  let protectionFloorResolution = resolveProtectionFloor();
43908
- let shouldRunHeuristics = args.heuristics !== undefined && isCacheBustingPass && (rideSignals.publishedHistory || args.forceMaterialization === true || hasPendingMaterializeSignal || deferredMaterializeEligible || foldBustsServedPrefixThisPass || firstRenderBust || heldIdleExpiryRebuild || rideSignals.subagentExecute || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
44236
+ let shouldRunHeuristics = args.heuristics !== undefined && isCacheBustingPass && (rideSignals.publishedHistory || args.forceMaterialization === true || hasPendingMaterializeSignal || deferredMaterializeEligible || foldBustsServedPrefixThisPass || firstRenderBust || heldIdleExpiryRebuild || args.recoveryRebuildReason !== undefined && isCacheBustingPass || rideSignals.subagentExecute || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
43909
44237
  let unavoidableCarriedIdentityRebuild = false;
43910
44238
  if (protectedSignedPrefix && readPiIdentityRebuilds(args.db, args.sessionId).length > 0) {
43911
44239
  args.tryReplayHeldIdentityRebuild?.();
@@ -44138,6 +44466,7 @@ async function runPipeline(args) {
44138
44466
  const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
44139
44467
  const shouldReadPendingOps = !args.compactionOff && (publishedWorkDrainAllowed || args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal || foldExecutedThisPass || firstRenderBust);
44140
44468
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
44469
+ const reclaimDistance = isCacheBustingPass ? toolReclaimDistanceEntries(mutationView, targets) : [];
44141
44470
  const protectedToolTags = protectedToolTagNumbers(getActiveTagsBySession2(args.db, args.sessionId), args.protectedTools);
44142
44471
  for (const number of identityAdoption.protectedTagNumbers)
44143
44472
  protectedToolTags.add(number);
@@ -44452,6 +44781,7 @@ async function runPipeline(args) {
44452
44781
  }
44453
44782
  }
44454
44783
  const editReclaim = buildEditSupersessionReclaim({
44784
+ watermark: reclaimMeta.toolReclaimWatermark ?? 0,
44455
44785
  db: args.db,
44456
44786
  sessionId: args.sessionId,
44457
44787
  targets: newTargets,
@@ -44579,7 +44909,7 @@ async function runPipeline(args) {
44579
44909
  setEmergencyDropSample(args.db, args.sessionId, args.contextUsage.inputTokens);
44580
44910
  }
44581
44911
  if (toolReclaimApplicationOpportunity) {
44582
- advanceToolReclaimWatermarkToCurrentMax(args.db, args.sessionId);
44912
+ advanceToolReclaimWatermarkByDistance(args.db, args.sessionId, reclaimDistance, args.reclaimUsableWindow ?? 0);
44583
44913
  }
44584
44914
  if (autoReclaimTargetCount > 0) {
44585
44915
  sessionLog2(args.sessionId, `tool reclaim auto-drop: targets=${autoReclaimTargetCount} mutated=${autoReclaimDidMutate}`);
@@ -44879,7 +45209,7 @@ async function runPipeline(args) {
44879
45209
  prefixMutationAllowed,
44880
45210
  strictThinkingKept: protectedSignedPrefix,
44881
45211
  signedPrefixRewritten: rewritingSignedPrefix,
44882
- prefixRebuildAlreadyPriced: firstRenderBust || heldIdleExpiryRebuild,
45212
+ prefixRebuildAlreadyPriced: firstRenderBust || heldIdleExpiryRebuild || !!args.recoveryRebuildReason && isCacheBustingPass,
44883
45213
  identityRebuilt: identityRebuild,
44884
45214
  servedTagNumbers,
44885
45215
  heuristicsExecuted,
@@ -46099,7 +46429,7 @@ function formatThresholdPercent(value) {
46099
46429
  }
46100
46430
 
46101
46431
  // ../plugin/src/shared/status-view-check.ts
46102
- function isRecord5(value) {
46432
+ function isRecord6(value) {
46103
46433
  return typeof value === "object" && value !== null && !Array.isArray(value);
46104
46434
  }
46105
46435
  function isNumber(value) {
@@ -46177,28 +46507,28 @@ class OptionalFields {
46177
46507
  }
46178
46508
  }
46179
46509
  function isWindowGeometry(value) {
46180
- if (!isRecord5(value) || !isNumber(value.usableSoft) || !isRecord5(value.derivation))
46510
+ if (!isRecord6(value) || !isNumber(value.usableSoft) || !isRecord6(value.derivation))
46181
46511
  return false;
46182
46512
  const derivation = value.derivation;
46183
46513
  return isNumber(derivation.window) && isNumber(derivation.reserve) && isString(derivation.reserveSource);
46184
46514
  }
46185
46515
  function isTailHygiene(value) {
46186
- return isRecord5(value) && isNumber(value.u) && isNumber(value.t) && isNumber(value.severity) && isBoolean(value.evaluable);
46516
+ return isRecord6(value) && isNumber(value.u) && isNumber(value.t) && isNumber(value.severity) && isBoolean(value.evaluable);
46187
46517
  }
46188
46518
  function isCompactionMarker(value) {
46189
- return isRecord5(value) && (value.code === null || value.code === "MC-C11") && isNumber(value.attempts) && (value.lastError === null || isString(value.lastError));
46519
+ return isRecord6(value) && (value.code === null || value.code === "MC-C11") && isNumber(value.attempts) && (value.lastError === null || isString(value.lastError));
46190
46520
  }
46191
46521
  function isTickFailure(value) {
46192
- return isRecord5(value) && isString(value.stage) && isNumber(value.at);
46522
+ return isRecord6(value) && isString(value.stage) && isNumber(value.at);
46193
46523
  }
46194
46524
  function isConfigParseFailure(value) {
46195
- return isRecord5(value);
46525
+ return isRecord6(value);
46196
46526
  }
46197
46527
  function isConfigReloadFailure(value) {
46198
- return isRecord5(value) && isString(value.path) && isString(value.message);
46528
+ return isRecord6(value) && isString(value.path) && isString(value.message);
46199
46529
  }
46200
46530
  function isUnconfirmedMigrationHolders(value) {
46201
- return isRecord5(value) && Array.isArray(value.pids) && value.pids.every(isNumber) && isNumber(value.fromVersion) && isNumber(value.toVersion);
46531
+ return isRecord6(value) && Array.isArray(value.pids) && value.pids.every(isNumber) && isNumber(value.fromVersion) && isNumber(value.toVersion);
46202
46532
  }
46203
46533
  function isNullableNumber(value) {
46204
46534
  return value === null || isNumber(value);
@@ -46210,7 +46540,7 @@ function isCacheTtlSource(value) {
46210
46540
  return isString(value);
46211
46541
  }
46212
46542
  function checkStatusViewSource(candidate) {
46213
- if (!isRecord5(candidate))
46543
+ if (!isRecord6(candidate))
46214
46544
  return { ok: false, fields: ["(the payload is not an object)"] };
46215
46545
  const missing = [];
46216
46546
  const numbers = {};
@@ -46249,7 +46579,7 @@ function checkStatusViewSource(candidate) {
46249
46579
  lastDreamerRunAt: optional.read("lastDreamerRunAt", isNullableNumber),
46250
46580
  dreamerUnsupportedTasks: optional.readArray("dreamerUnsupportedTasks", isString),
46251
46581
  dreamerSkipped: optional.readArray("dreamerSkipped", isString),
46252
- dreamerFailures: optional.readArray("dreamerFailures", (value) => isRecord5(value) && isString(value.task) && isString(value.error)),
46582
+ dreamerFailures: optional.readArray("dreamerFailures", (value) => isRecord6(value) && isString(value.task) && isString(value.error)),
46253
46583
  dreamerTickFailure: optional.read("dreamerTickFailure", (value) => value === null || isTickFailure(value)),
46254
46584
  sessionNoteCount: optional.read("sessionNoteCount", isNumber),
46255
46585
  readySmartNoteCount: optional.read("readySmartNoteCount", isNumber),