@ponythewhite/base-context 1.0.10 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/base-context-runtime/pyproject.toml +1 -1
  3. package/dist/base-context-runtime/uv.lock +1 -1
  4. package/dist/build-info.json +1 -1
  5. package/dist/bundle/{bundled-modules-MX6YNAM2.js → bundled-modules-PEFT72QN.js} +2 -2
  6. package/dist/bundle/{chunk-UHLGPYMI.js → chunk-JZHGOOFM.js} +68 -18
  7. package/dist/bundle/{chunk-CDXQNS5P.js → chunk-TOOVREMP.js} +498 -82
  8. package/dist/bundle/{cli-main-D7W3WWCV.js → cli-main-BRXGYTGK.js} +2 -2
  9. package/dist/bundle/cli.js +1 -1
  10. package/dist/bundle/{main-5J3QBZ5Y.js → main-POUXGEL6.js} +2 -2
  11. package/dist/core/agent-session.d.ts +0 -1
  12. package/dist/core/agent-session.d.ts.map +1 -1
  13. package/dist/core/agent-session.js +85 -45
  14. package/dist/core/agent-session.js.map +1 -1
  15. package/dist/core/canonical-context.d.ts +19 -3
  16. package/dist/core/canonical-context.d.ts.map +1 -1
  17. package/dist/core/canonical-context.js +130 -9
  18. package/dist/core/canonical-context.js.map +1 -1
  19. package/dist/core/context-epoch-copy.d.ts +1 -1
  20. package/dist/core/context-epoch-copy.d.ts.map +1 -1
  21. package/dist/core/context-epoch-copy.js +18 -7
  22. package/dist/core/context-epoch-copy.js.map +1 -1
  23. package/dist/core/context-epoch.d.ts +4 -0
  24. package/dist/core/context-epoch.d.ts.map +1 -1
  25. package/dist/core/context-epoch.js +8 -1
  26. package/dist/core/context-epoch.js.map +1 -1
  27. package/dist/core/context-tree.d.ts +1 -1
  28. package/dist/core/context-tree.d.ts.map +1 -1
  29. package/dist/core/context-tree.js +98 -8
  30. package/dist/core/context-tree.js.map +1 -1
  31. package/dist/core/history-index-worker.d.ts.map +1 -1
  32. package/dist/core/history-index-worker.js +59 -6
  33. package/dist/core/history-index-worker.js.map +1 -1
  34. package/dist/core/history-index.d.ts +17 -0
  35. package/dist/core/history-index.d.ts.map +1 -1
  36. package/dist/core/history-index.js +22 -0
  37. package/dist/core/history-index.js.map +1 -1
  38. package/dist/core/inference-coordinator.d.ts.map +1 -1
  39. package/dist/core/inference-coordinator.js +5 -1
  40. package/dist/core/inference-coordinator.js.map +1 -1
  41. package/dist/core/request-view-selection.d.ts +2 -1
  42. package/dist/core/request-view-selection.d.ts.map +1 -1
  43. package/dist/core/request-view-selection.js +29 -2
  44. package/dist/core/request-view-selection.js.map +1 -1
  45. package/dist/core/session-fork-messages.d.ts +5 -0
  46. package/dist/core/session-fork-messages.d.ts.map +1 -1
  47. package/dist/core/session-fork-messages.js +44 -0
  48. package/dist/core/session-fork-messages.js.map +1 -1
  49. package/dist/core/session-history-index.d.ts +5 -0
  50. package/dist/core/session-history-index.d.ts.map +1 -1
  51. package/dist/core/session-history-index.js +7 -0
  52. package/dist/core/session-history-index.js.map +1 -1
  53. package/dist/core/session-manager.d.ts +2 -0
  54. package/dist/core/session-manager.d.ts.map +1 -1
  55. package/dist/core/session-manager.js +155 -13
  56. package/dist/core/session-manager.js.map +1 -1
  57. package/dist/core/session-tree.d.ts +9 -0
  58. package/dist/core/session-tree.d.ts.map +1 -1
  59. package/dist/core/session-tree.js +71 -11
  60. package/dist/core/session-tree.js.map +1 -1
  61. package/dist/modes/agent-connection/in-process-agent-connection.d.ts.map +1 -1
  62. package/dist/modes/agent-connection/in-process-agent-connection.js +4 -4
  63. package/dist/modes/agent-connection/in-process-agent-connection.js.map +1 -1
  64. package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
  65. package/dist/modes/daemon/daemon-mode.js +4 -4
  66. package/dist/modes/daemon/daemon-mode.js.map +1 -1
  67. package/package.json +4 -4
@@ -27790,6 +27790,12 @@ function readContextEpoch(details, maxBytes) {
27790
27790
  throw new Error("Invalid committed context epoch");
27791
27791
  return snapshotContextEpoch(value, maxBytes);
27792
27792
  }
27793
+ var UnsupportedContextEpochConfigurationError = class extends Error {
27794
+ constructor() {
27795
+ super("Unsupported context epoch request configuration");
27796
+ this.name = "UnsupportedContextEpochConfigurationError";
27797
+ }
27798
+ };
27793
27799
  function contextEpochRepresentation(request, assessment, maxBytes, unbudgetedPublic = false, responseItemIdentity) {
27794
27800
  if (!assessment && !unbudgetedPublic || assessment && (!assessment.profile || assessment.limitSource !== "explicit-profile" || !assessment.route || !assessment.model) || request.body === void 0)
27795
27801
  throw new Error("Committed context epoch requires its explicit request profile");
@@ -27827,7 +27833,7 @@ function contextEpochRepresentation(request, assessment, maxBytes, unbudgetedPub
27827
27833
  if (["input", "messages", "previous_response_id", "prompt_cache_key"].includes(key2))
27828
27834
  continue;
27829
27835
  if (!fields.has(key2))
27830
- throw new Error("Unsupported context epoch request configuration");
27836
+ throw new UnsupportedContextEpochConfigurationError();
27831
27837
  configuration[key2] = value;
27832
27838
  }
27833
27839
  const input = "input" in body ? body.input : "messages" in body ? body.messages : void 0;
@@ -29066,6 +29072,15 @@ var HistoryIndex = class _HistoryIndex {
29066
29072
  snapshot: target
29067
29073
  });
29068
29074
  }
29075
+ /** Whole-source own usage for exactly the current acknowledged owner snapshot. */
29076
+ async currentSourceUsage(sessionId, snapshot) {
29077
+ return await this.request({
29078
+ id: this.nextId++,
29079
+ action: "current_source_usage",
29080
+ sessionId,
29081
+ snapshot
29082
+ });
29083
+ }
29069
29084
  /** Latest label control for this source target, including a clear. */
29070
29085
  async sourceLabel(sessionId, targetId, through) {
29071
29086
  return await this.request({ id: this.nextId++, action: "source_label", sessionId, targetId, through });
@@ -29080,6 +29095,17 @@ var HistoryIndex = class _HistoryIndex {
29080
29095
  through
29081
29096
  });
29082
29097
  }
29098
+ /** All matching source update refs, including off-branch and older revisions. */
29099
+ async sourceContextUpdates(sessionId, target, through, after = 0) {
29100
+ return await this.request({
29101
+ id: this.nextId++,
29102
+ action: "source_context_updates",
29103
+ sessionId,
29104
+ target: target.kind === "assistant-usage" ? { kind: target.kind, targetId: target.targetId } : { kind: target.kind, toolCallId: target.toolCallId },
29105
+ through,
29106
+ after
29107
+ });
29108
+ }
29083
29109
  async get(sessionId, eventId, scope) {
29084
29110
  return await this.request({
29085
29111
  id: this.nextId++,
@@ -29402,6 +29428,7 @@ function createSessionHistoryReadScope(index, source, query, scope) {
29402
29428
  }),
29403
29429
  sourceLabel: (targetId) => query(() => index.sourceLabel(sessionId, targetId, source.sourceSequence)),
29404
29430
  sourceAssistantUsage: (targetId) => query(() => index.sourceAssistantUsage(sessionId, targetId, source.sourceSequence)),
29431
+ sourceContextUpdates: (target, after = 0) => query(() => index.sourceContextUpdates(sessionId, target, source.sourceSequence, after)),
29405
29432
  ipythonSentMessages: (toolCallId, options = {}) => query(() => index.ipythonSentMessages(sessionId, branch, toolCallId, options)),
29406
29433
  get,
29407
29434
  page,
@@ -29495,6 +29522,12 @@ var SessionHistoryIndex = class {
29495
29522
  const index = await this.synchronize(captured);
29496
29523
  return index.currentSourceBootstrap(this.sessionId, captured);
29497
29524
  }
29525
+ /** Caller holds the owner queue until the exact current projection is read. */
29526
+ async currentSourceUsage(snapshot) {
29527
+ const captured = { ...snapshot };
29528
+ const index = await this.synchronize(captured);
29529
+ return index.currentSourceUsage(this.sessionId, captured);
29530
+ }
29498
29531
  /** Finish accepted indexing, then wait for the external worker to close. */
29499
29532
  close() {
29500
29533
  this.closing ??= (async () => {
@@ -31574,7 +31607,19 @@ function prepareCanonicalEpoch(messages, selectedUnitIds, representation, maxByt
31574
31607
  messages: chosen
31575
31608
  };
31576
31609
  }
31577
- function canonicalRecoveryBoundary(messages) {
31610
+ var MissingRecoveryReplayContractError = class extends Error {
31611
+ constructor() {
31612
+ super("Recovery compaction requires an accepted replay contract for its selected results");
31613
+ this.name = "MissingRecoveryReplayContractError";
31614
+ }
31615
+ };
31616
+ function sameRecoverySource(left, right, ownerStillCurrent = false) {
31617
+ return JSON.stringify(left) === JSON.stringify(right) || ownerStillCurrent && left.sessionId === right.sessionId && left.sessionFile === right.sessionFile && left.persistent === right.persistent;
31618
+ }
31619
+ function sameRecoveryReference(left, right, ownerStillCurrent = false) {
31620
+ return sameRecoverySource(left.source, right.source, ownerStillCurrent) && JSON.stringify(left.ref) === JSON.stringify(right.ref) && left.sourceRevision === right.sourceRevision;
31621
+ }
31622
+ function canonicalRecoveryBoundary(messages, authorization) {
31578
31623
  const context = compiledEpochContexts.get(messages);
31579
31624
  const units = getCanonicalViewUnits(messages);
31580
31625
  if (!context || !units)
@@ -31584,15 +31629,22 @@ function canonicalRecoveryBoundary(messages) {
31584
31629
  const recoveries = units.flatMap((unit, index) => unit.kind === "recovery" ? [context.references[index]] : []);
31585
31630
  if (!recoveries.length)
31586
31631
  return;
31632
+ if (authorization) {
31633
+ const ownerStillCurrent = authorization.isSourceCurrent?.();
31634
+ if (ownerStillCurrent === false || !sameRecoverySource(context.source, authorization.source, ownerStillCurrent === true) || context.resourceRevision !== authorization.resourceRevision || recoveries.length !== authorization.recoveries.length || recoveries.some((reference) => !reference || !authorization.recoveries.some((covered) => sameRecoveryReference(reference, covered, ownerStillCurrent === true))))
31635
+ throw new Error("Recovery compaction authorization no longer matches its captured source");
31636
+ return latestLiteralReference(context.references)?.ref.entryId;
31637
+ }
31587
31638
  const checkpoint = context.checkpoint;
31588
- if (!checkpoint?.representation || checkpoint.replayContract !== "message-groups" || recoveries.some((reference) => !reference || reference.ref.sequence > checkpoint.source.sourceSequence))
31589
- throw new Error("Recovery compaction requires an accepted replay contract for its selected results");
31639
+ const inherited = checkpoint?.includeSummary === true && checkpoint.replayContract === "message-groups";
31640
+ if (checkpoint?.replayContract !== "message-groups" || recoveries.some((reference) => !reference || (checkpoint.representation ? reference.ref.sequence > checkpoint.source.sourceSequence : !inherited || !context.inheritedRecoveryCoverage?.some((covered) => sameRecoveryReference(reference, covered)))))
31641
+ throw new MissingRecoveryReplayContractError();
31590
31642
  return checkpoint.literalTailId;
31591
31643
  }
31592
- function prepareRecoveryCompaction(messages, firstKeptEntryId, maxBytes) {
31593
- const boundary = canonicalRecoveryBoundary(messages);
31644
+ function prepareRecoveryCompaction(messages, firstKeptEntryId, maxBytes, authorization) {
31645
+ const boundary = canonicalRecoveryBoundary(messages, authorization);
31594
31646
  const context = compiledEpochContexts.get(messages);
31595
- const publicWindow = context?.checkpoint?.publicWindow === true && context.checkpoint.replayContract === "message-groups";
31647
+ const publicWindow = authorization ? authorization.publicWindow : context?.checkpoint?.publicWindow === true && context.checkpoint.replayContract === "message-groups";
31596
31648
  if (!boundary && !publicWindow && !context?.selectedSkills?.length && !context?.toolContinuations?.length)
31597
31649
  return;
31598
31650
  if (!context)
@@ -32324,10 +32376,83 @@ ${JSON.stringify(selections.map((skill) => ({
32324
32376
  units: selectionUnits,
32325
32377
  limits: unitLimits,
32326
32378
  ...mode === "on" && (taskFrameRebased || checkpoint) ? { requiresEpoch: true } : {},
32379
+ ...mode === "on" && sourceUnits.some((unit) => unit.kind === "recovery") ? { recoveryContractRequested: true } : {},
32327
32380
  ...pendingPublicMessageGroups.length ? { pendingPublicMessageGroups } : {}
32328
32381
  }
32329
32382
  });
32383
+ const inheritedRecoveryCoverage = [];
32384
+ if (checkpoint?.includeSummary && checkpoint.replayContract === "message-groups" && closedUnits.some((unit) => unit.kind === "recovery")) {
32385
+ const prefix = await view.atSnapshot(checkpoint.source);
32386
+ const suffix = /* @__PURE__ */ new Map();
32387
+ const frozenViews = /* @__PURE__ */ new Map();
32388
+ let capturedMessages = 0;
32389
+ let retained = false;
32390
+ let cursor2;
32391
+ for (; ; ) {
32392
+ const page = await prefix.contextManifest({ cursor: cursor2, limit: 128 });
32393
+ if (page.selection !== "known")
32394
+ throw new Error("Summary recovery source is unavailable");
32395
+ if (!cursor2 && page.summaryRef) {
32396
+ const entry = await hydrate(page.summaryRef, void 0, prefix);
32397
+ const metadata = await prefix.get(page.summaryRef.entryId);
32398
+ const prior = entry.type === "compaction" && metadata?.qualification === "native-context-epoch" && metadata.retention !== "retained-import" ? readContextEpoch(entry.details, maxSourceBytes) : void 0;
32399
+ if ((!prior || prior.includeSummary) && page.summaryRef.entryId === checkpoint.literalTailId)
32400
+ retained = true;
32401
+ capturedMessages += prior?.views.length ?? 0;
32402
+ for (const pinned of prior?.views ?? []) {
32403
+ if (pinned.ref.entryId === checkpoint.literalTailId)
32404
+ retained = true;
32405
+ if (retained) {
32406
+ suffix.set(pinned.ref.entryId, pinned.ref);
32407
+ frozenViews.set(pinned.ref.entryId, pinned);
32408
+ }
32409
+ }
32410
+ }
32411
+ for (const ref of page.refs) {
32412
+ if (ref.entryId === checkpoint.literalTailId)
32413
+ retained = true;
32414
+ if (retained)
32415
+ suffix.set(ref.entryId, ref);
32416
+ }
32417
+ capturedMessages += page.refs.length;
32418
+ if (capturedMessages > maxMessages)
32419
+ throw new Error("Summary recovery source exceeds its message budget");
32420
+ if (!page.nextCursor)
32421
+ break;
32422
+ cursor2 = page.nextCursor;
32423
+ }
32424
+ for (const [index, message2] of closedMessages.entries()) {
32425
+ if (closedUnits[index].kind !== "recovery")
32426
+ continue;
32427
+ const reference = epochReferences.get(message2);
32428
+ if (checkpoint.views.some((covered) => sameRecoveryReference(reference, covered))) {
32429
+ inheritedRecoveryCoverage.push(reference);
32430
+ continue;
32431
+ }
32432
+ const frozen = suffix.get(reference.ref.entryId);
32433
+ if (!frozen || JSON.stringify(frozen) !== JSON.stringify(reference.ref))
32434
+ continue;
32435
+ const pinned = frozenViews.get(frozen.entryId);
32436
+ if (pinned) {
32437
+ if (reference.sourceRevision === pinned.sourceRevision)
32438
+ inheritedRecoveryCoverage.push(reference);
32439
+ continue;
32440
+ }
32441
+ const revisions = [frozen.revision];
32442
+ const entry = next.get(frozen.entryId)?.entry;
32443
+ if (entry?.type === "message" && entry.message.role === "toolResult" && entry.message.toolName === "ipython") {
32444
+ const updates = await prefix.contextUpdates({
32445
+ kind: "ipython-sent-message",
32446
+ toolCallId: entry.message.toolCallId
32447
+ });
32448
+ revisions.push(...updates.refs.map((update) => update.revision));
32449
+ }
32450
+ if (reference.sourceRevision === JSON.stringify(revisions))
32451
+ inheritedRecoveryCoverage.push(reference);
32452
+ }
32453
+ }
32330
32454
  compiledEpochContexts.set(closedMessages, {
32455
+ ...inheritedRecoveryCoverage.length ? { inheritedRecoveryCoverage } : {},
32331
32456
  ...purpose === "read" ? { readOnly: true } : {},
32332
32457
  mode,
32333
32458
  source: { ...view.source },
@@ -32381,6 +32506,10 @@ var PublicContextBudgetError = class extends RequestTokenBudgetError {
32381
32506
  this.#summaryCapacity = summaryCapacity;
32382
32507
  }
32383
32508
  };
32509
+ var recoveryCompactionAuthorizations = /* @__PURE__ */ new WeakMap();
32510
+ function getRecoveryCompactionAuthorization(error) {
32511
+ return error ? recoveryCompactionAuthorizations.get(error) : void 0;
32512
+ }
32384
32513
  function captureRequestViewBoundary(messages, commit, validate2, fixedPrepare, isSourceCurrent) {
32385
32514
  const source = getCanonicalViewSelectionSource(messages);
32386
32515
  if (!source)
@@ -32479,7 +32608,7 @@ function publicBudgetFailure(boundary, messages, request, projection, budget, as
32479
32608
  });
32480
32609
  };
32481
32610
  const minimum = withRequestBody(request, JSON.stringify({ ...body, [inputKey]: retainedInput(/* @__PURE__ */ new Set()) }));
32482
- return new PublicContextBudgetError(boundary.source, assessment, original, budget.measure(minimum), (context.taskFrame?.messages.length ?? 0) > 1, JSON.stringify([
32611
+ const error = new PublicContextBudgetError(boundary.source, assessment, original, budget.measure(minimum), (context.taskFrame?.messages.length ?? 0) > 1, JSON.stringify([
32483
32612
  boundary.source.sessionId,
32484
32613
  boundary.source.sessionFile,
32485
32614
  source.units.map((unit) => [unit.id, unit.sourceRevision]),
@@ -32498,6 +32627,21 @@ function publicBudgetFailure(boundary, messages, request, projection, budget, as
32498
32627
  const measured = budget.measure(withRequestBody(request, JSON.stringify({ ...body, [inputKey]: kept })));
32499
32628
  return measured.status === "unknown" || measured.availableInputTokens === null || measured.estimatedInputTokens === null ? void 0 : Math.floor(measured.availableInputTokens - measured.estimatedInputTokens);
32500
32629
  }, boundary.isSourceCurrent);
32630
+ if (projection.replayContract === "message-groups") {
32631
+ const originalContext = getCanonicalEpochContext(boundary.messages);
32632
+ const recoveries = boundary.units.flatMap((unit, index) => unit.kind === "recovery" && originalContext.references[index] ? [originalContext.references[index]] : []);
32633
+ if (recoveries.length) {
32634
+ recoveryCompactionAuthorizations.set(error, {
32635
+ source: originalContext.source,
32636
+ recoveries,
32637
+ resourceRevision: originalContext.resourceRevision,
32638
+ // Do not extend a partial public conversion to native groups the encoder did not replace.
32639
+ publicWindow: messages !== boundary.messages && projection.publicWindow === true && boundary.units.every((unit, index) => !["recovery", "replay-group"].includes(unit.kind) || context.references[index]?.rendering !== void 0),
32640
+ isSourceCurrent: boundary.isSourceCurrent
32641
+ });
32642
+ }
32643
+ }
32644
+ return error;
32501
32645
  }
32502
32646
  async function prepareFixedRequestView(boundary, request, projection, assessment) {
32503
32647
  projection = canonicalRequestProjection(boundary, projection);
@@ -32570,7 +32714,7 @@ async function selectRequestView(boundary, request, projection, budget, allowShr
32570
32714
  const inputKey = requestInputKey(request, projection);
32571
32715
  if (budget && full?.limitSource !== "explicit-profile" || !inputKey)
32572
32716
  return;
32573
- if (!budget && !boundary.requiresEpoch && !boundary.pendingPublicMessageGroups?.length)
32717
+ if (!budget && !boundary.requiresEpoch && !boundary.recoveryContractRequested && !boundary.pendingPublicMessageGroups?.length)
32574
32718
  return;
32575
32719
  const payload = JSON.parse(request.body);
32576
32720
  const input = payload[inputKey];
@@ -33527,7 +33671,7 @@ var InferenceCoordinator = class _InferenceCoordinator {
33527
33671
  } : void 0;
33528
33672
  const requiredPublic = Boolean(boundary?.pendingPublicMessageGroups?.length);
33529
33673
  const requiredEpoch = boundary?.requiresEpoch === true;
33530
- const canSelect = (budget || boundary?.fixedPrepare || requiredPublic || requiredEpoch) && boundary && matchesRequestView(boundary, source, context);
33674
+ const canSelect = (budget || boundary?.fixedPrepare || requiredPublic || requiredEpoch || boundary?.recoveryContractRequested) && boundary && matchesRequestView(boundary, source, context);
33531
33675
  if (requiredPublic && (!canSelect || boundary?.fixedPrepare))
33532
33676
  throw new Error("Tool continuation requires a selectable native public request boundary");
33533
33677
  const responsesMessageIds = canSelect && !boundary.fixedPrepare && (model.api === "openai-responses" || model.api === "openai-codex-responses") ? boundary.providerMessageIndices.map((index) => {
@@ -34627,7 +34771,7 @@ function captureEpochCopyEntry(entry, source) {
34627
34771
  ...updateTarget ? { updateTarget } : {}
34628
34772
  };
34629
34773
  }
34630
- async function rebuildCopiedContextEpoch(history, copied, limits) {
34774
+ async function rebuildCopiedContextEpoch(history, copied, limits, metadataMaxBytes = limits.maxSourceBytes) {
34631
34775
  const view = history.branchContext;
34632
34776
  const manifest = await view.contextManifest({ limit: 1 });
34633
34777
  if (manifest.selection !== "known")
@@ -34656,15 +34800,26 @@ async function rebuildCopiedContextEpoch(history, copied, limits) {
34656
34800
  throw new Error("Tool continuation recipes require their original native execution source");
34657
34801
  if (!checkpoint || checkpoint.literalTailId !== entry.firstKeptEntryId || !view.atSnapshot)
34658
34802
  throw new Error("Copied context epoch boundary is unavailable");
34659
- if (copied.entries.length > limits.maxEntries || checkpoint.views.length > limits.maxEntries)
34803
+ if (checkpoint.views.length > limits.maxEntries)
34660
34804
  throw new Error("Copied context epoch item budget exceeded");
34661
- stringifyBoundedJson(copied, limits.maxSourceBytes);
34805
+ stringifyBoundedJson(copied, metadataMaxBytes);
34662
34806
  const oldByRevision = new Map([...oldById.values()].map((source) => [source.revision, source]));
34663
34807
  const destination = /* @__PURE__ */ new Map();
34664
- for (const source of oldById.values()) {
34665
- const actual = await history.get(source.id);
34666
- if (actual)
34667
- destination.set(source.id, actual);
34808
+ let after = 0;
34809
+ for (; ; ) {
34810
+ const page = await history.page(after, 128);
34811
+ if (page.indexedThrough < history.source.sourceSequence)
34812
+ throw new Error("Copied context destination has incomplete index coverage");
34813
+ for (const actual of page.events) {
34814
+ if (!oldById.has(actual.id))
34815
+ continue;
34816
+ if (destination.size >= limits.maxEntries)
34817
+ throw new Error("Copied context epoch item budget exceeded");
34818
+ destination.set(actual.id, actual);
34819
+ }
34820
+ if (page.nextAfter === null)
34821
+ break;
34822
+ after = page.nextAfter;
34668
34823
  }
34669
34824
  const prefixViews = /* @__PURE__ */ new Map();
34670
34825
  const prefix = async (source) => {
@@ -36655,6 +36810,7 @@ var DEFAULT_MANAGER_HISTORY_LIMITS = {
36655
36810
  maxEntries: 16384,
36656
36811
  maxSourceBytes: 64 * 1024 * 1024
36657
36812
  };
36813
+ var FORK_SOURCE_METADATA_MAX_BYTES = 64 * 1024 * 1024;
36658
36814
  async function readOwnedSessionHeader(snapshot) {
36659
36815
  const handle = await openFile(snapshot.journalPath, "r");
36660
36816
  let capturedHeader;
@@ -37182,6 +37338,19 @@ var SessionManager = class _SessionManager {
37182
37338
  readSourceHistory(read2) {
37183
37339
  return this._runHistoryRead(this._bindHistorySource((index, source, query) => createSessionHistoryReadScope(index, source, query, "source")), read2);
37184
37340
  }
37341
+ /** Read the owner-maintained own-spend projection without hydrating the source. */
37342
+ async readOwnUsageSummary() {
37343
+ this._assertMutable();
37344
+ if (!this.supportsCapturedHistoryReads())
37345
+ throw new Error("Own usage projection requires an owned native source");
37346
+ const state = this.writeState;
37347
+ return this._enqueue(state, 0, async () => {
37348
+ await state.owner.flush();
37349
+ const snapshot = state.owner.getSnapshot();
37350
+ await this._acknowledgedHistory(state, snapshot);
37351
+ return state.history.currentSourceUsage(snapshot);
37352
+ });
37353
+ }
37185
37354
  /** Complete bounded structured task reduction on one captured native branch. */
37186
37355
  async readTaskState(limits = {}) {
37187
37356
  const captured = taskStateReadLimits(limits);
@@ -38921,6 +39090,8 @@ var SessionManager = class _SessionManager {
38921
39090
  }
38922
39091
  async _captureForkInput(target, options) {
38923
39092
  const limits = { ...options.limits ?? DEFAULT_MANAGER_HISTORY_LIMITS };
39093
+ if (!Number.isSafeInteger(limits.maxEntries) || limits.maxEntries <= 0 || !Number.isSafeInteger(limits.maxSourceBytes) || limits.maxSourceBytes <= 0)
39094
+ throw new Error("Invalid fork source limits");
38924
39095
  const sourceFile = this.sessionFile;
38925
39096
  const header = JSON.parse(stringifyBoundedJson(this.getHeader(), limits.maxSourceBytes));
38926
39097
  const settings = {
@@ -39032,32 +39203,143 @@ var SessionManager = class _SessionManager {
39032
39203
  if (headerBytes >= limits.maxSourceBytes)
39033
39204
  throw new Error("Fork source byte budget exceeded");
39034
39205
  return this.readSourceHistory(async (history) => {
39035
- const materialized = await history.materialize({
39036
- ...limits,
39037
- maxSourceBytes: limits.maxSourceBytes - headerBytes
39038
- });
39039
- const entries = materialized.entries.map(({ entry, source }) => withEntryRetention(entry, source.retention, source.qualification));
39040
- const sourceEntries = materialized.entries.map(({ entry, source }) => captureEpochCopyEntry(entry, source));
39041
- const hasEpoch = sourceEntries.some((entry) => entry.kind === "compaction" && entry.qualification === "native-context-epoch");
39206
+ const metadata = /* @__PURE__ */ new Map();
39207
+ let metadataBytes = 0;
39208
+ let after = 0;
39209
+ for (; ; ) {
39210
+ const page2 = await history.page(after, 128);
39211
+ if (page2.indexedThrough < history.source.sourceSequence)
39212
+ throw new Error("Captured fork history has incomplete index coverage");
39213
+ for (const reference of page2.events) {
39214
+ const source = {
39215
+ id: reference.id,
39216
+ parentId: reference.parentId,
39217
+ kind: reference.kind,
39218
+ sequence: reference.sequence,
39219
+ revision: reference.revision,
39220
+ locator: { ...reference.locator },
39221
+ retention: reference.retention,
39222
+ qualification: reference.qualification
39223
+ };
39224
+ metadataBytes += Buffer.byteLength(JSON.stringify(source)) + 1;
39225
+ if (metadataBytes > FORK_SOURCE_METADATA_MAX_BYTES)
39226
+ throw new Error("Fork source metadata byte budget exceeded");
39227
+ metadata.set(source.id, source);
39228
+ }
39229
+ if (page2.nextAfter === null)
39230
+ break;
39231
+ after = page2.nextAfter;
39232
+ }
39233
+ const hasEpoch = [...metadata.values()].some((entry) => entry.kind === "compaction" && entry.qualification === "native-context-epoch");
39234
+ const loaded = /* @__PURE__ */ new Map();
39235
+ let sourceBytes = headerBytes;
39236
+ const load = async (id) => {
39237
+ const existing = loaded.get(id);
39238
+ if (existing)
39239
+ return existing;
39240
+ const reference = metadata.get(id);
39241
+ if (!reference)
39242
+ throw new Error("Fork selected source is unavailable");
39243
+ if (loaded.size >= limits.maxEntries)
39244
+ throw new Error("Fork entry budget exceeded");
39245
+ const remaining = limits.maxSourceBytes - sourceBytes;
39246
+ if (reference.locator.length > remaining)
39247
+ throw new Error("Fork source byte budget exceeded");
39248
+ const hydrated = await history.hydrateEntry(id, remaining);
39249
+ if (!hydrated)
39250
+ throw new Error("Fork selected source is unavailable");
39251
+ const entry = withEntryRetention(hydrated.entry, hydrated.source.retention, hydrated.source.qualification);
39252
+ loaded.set(id, entry);
39253
+ metadata.set(id, captureEpochCopyEntry(entry, hydrated.source));
39254
+ sourceBytes += reference.locator.length;
39255
+ return entry;
39256
+ };
39257
+ if ("entryId" in target && !metadata.has(target.entryId))
39258
+ throw new Error("Invalid entry ID for forking");
39259
+ const selected = "entryId" in target ? await load(target.entryId) : void 0;
39260
+ if ("entryId" in target && target.position === "before" && (selected?.type !== "message" || selected.message.role !== "user"))
39261
+ throw new Error("Invalid entry ID for forking");
39262
+ const leafId = "entryId" in target ? target.position === "at" ? selected.id : selected.parentId : target.leafId;
39263
+ const path6 = [];
39264
+ let page = await history.parentPathFrom(leafId);
39265
+ for (; ; ) {
39266
+ if (page.totalEntries > limits.maxEntries)
39267
+ throw new Error("Fork entry budget exceeded");
39268
+ for (const reference of page.events)
39269
+ path6.push(await load(reference.id));
39270
+ if (!page.nextCursor)
39271
+ break;
39272
+ page = await history.parentPathFrom(leafId, { cursor: page.nextCursor });
39273
+ }
39274
+ const copied = path6.filter((entry) => entry.type !== "label");
39275
+ const ids = new Set(copied.map((entry) => entry.id));
39276
+ if (hasEpoch) {
39277
+ for (const entry of copied) {
39278
+ if (entry.type !== "message")
39279
+ continue;
39280
+ if (entry.execution && "invocationId" in entry.execution)
39281
+ ids.add(entry.execution.invocationId);
39282
+ const updateTarget = entry.message.role === "assistant" ? { kind: "assistant-usage", targetId: entry.id } : entry.message.role === "toolResult" ? { kind: "ipython-sent-message", toolCallId: entry.message.toolCallId } : void 0;
39283
+ if (!updateTarget)
39284
+ continue;
39285
+ let after2 = 0;
39286
+ for (; ; ) {
39287
+ const updates = await history.sourceContextUpdates(updateTarget, after2);
39288
+ if (updates.indexedThrough < history.source.sourceSequence)
39289
+ throw new Error("Captured fork updates have incomplete index coverage");
39290
+ for (const reference of updates.events)
39291
+ ids.add(reference.id);
39292
+ if (updates.nextAfter === null)
39293
+ break;
39294
+ after2 = updates.nextAfter;
39295
+ }
39296
+ }
39297
+ for (const id of ids) {
39298
+ const reference = metadata.get(id);
39299
+ if (!reference)
39300
+ throw new Error("Fork related source is unavailable");
39301
+ if (reference.parentId !== null)
39302
+ ids.add(reference.parentId);
39303
+ }
39304
+ for (const id of ids)
39305
+ await load(id);
39306
+ } else {
39307
+ for (const entry of copied) {
39308
+ if (entry.type !== "message" || entry.message.role !== "assistant")
39309
+ continue;
39310
+ const latest = await history.sourceAssistantUsage(entry.id);
39311
+ if (latest)
39312
+ await load(latest.id);
39313
+ }
39314
+ }
39315
+ for (const id of ids) {
39316
+ const label = await history.sourceLabel(id);
39317
+ if (label)
39318
+ await load(label.id);
39319
+ }
39320
+ const entries = [...loaded.values()].sort((left, right) => metadata.get(left.id).sequence - metadata.get(right.id).sequence);
39042
39321
  if (!hasEpoch)
39043
39322
  applyChildUsageAttributions(entries);
39044
- return finish(entries, history, hasEpoch ? {
39323
+ const epochCopy = hasEpoch ? {
39045
39324
  sessionId: history.source.sessionId,
39046
39325
  sessionFile: history.source.sessionFile,
39047
39326
  through: history.source.sourceSequence,
39048
- entries: sourceEntries,
39327
+ entries: [...metadata.values()],
39049
39328
  retained: false
39050
- } : void 0);
39329
+ } : void 0;
39330
+ if (epochCopy)
39331
+ stringifyBoundedJson(epochCopy, FORK_SOURCE_METADATA_MAX_BYTES);
39332
+ return finish(entries, history, epochCopy);
39051
39333
  });
39052
39334
  }
39053
- async _rebuildCopiedEpoch(copied, limits) {
39335
+ async _rebuildCopiedEpoch(copied, limits, metadataMaxBytes = limits.maxSourceBytes) {
39054
39336
  if (!copied.entries.some((entry) => entry.kind === "compaction" && entry.qualification === "native-context-epoch"))
39055
39337
  return;
39056
39338
  if (!this.supportsCapturedHistoryReads())
39057
39339
  throw new Error("Copied context epochs require an owned persistent source");
39058
39340
  const sink = this.bindCompactionSink(limits);
39059
39341
  await this._runHistoryRead({ ...sink, readHistory: (read2) => sink[readCopiedEpochSource](read2) }, async (history) => {
39060
- const rebuilt = await rebuildCopiedContextEpoch(history, copied, limits);
39342
+ const rebuilt = await rebuildCopiedContextEpoch(history, copied, limits, metadataMaxBytes);
39061
39343
  if (rebuilt)
39062
39344
  await sink[appendContextEpoch](rebuilt.checkpoint, rebuilt.tokensBefore, rebuilt.summary);
39063
39345
  });
@@ -39094,7 +39376,7 @@ var SessionManager = class _SessionManager {
39094
39376
  if (input.epochCopy) {
39095
39377
  try {
39096
39378
  await next.branchTo(input.leafId ?? null);
39097
- await next._rebuildCopiedEpoch(input.epochCopy, input.limits);
39379
+ await next._rebuildCopiedEpoch(input.epochCopy, input.limits, FORK_SOURCE_METADATA_MAX_BYTES);
39098
39380
  } catch (error) {
39099
39381
  try {
39100
39382
  await next.close();
@@ -39487,13 +39769,6 @@ function parseBoundedSessionEntries(text2, maxEntries) {
39487
39769
  }
39488
39770
  return parseSessionEntries(text2);
39489
39771
  }
39490
- async function readSessionHistoryFile(inputPath, limits) {
39491
- limits = { ...limits };
39492
- const captured = await readSessionHistoryImage(inputPath, limits.maxSourceBytes);
39493
- const complete = captured.subarray(0, captured.lastIndexOf(10) + 1);
39494
- const text2 = new TextDecoder3("utf-8", { fatal: true, ignoreBOM: true }).decode(complete);
39495
- return parseBoundedSessionEntries(text2, limits.maxEntries);
39496
- }
39497
39772
  async function readExportHistory(inputPath, limits) {
39498
39773
  limits = { ...limits };
39499
39774
  const captured = await readSessionHistoryImage(inputPath, limits.maxSourceBytes);
@@ -42919,16 +43194,43 @@ function readResidentContextTreeUsage(manager, limits = { maxEntries: 16384, max
42919
43194
  ...availabilityMaxSourceBytes === void 0 ? {} : { hasPostCompactionUsage: hasPostCompactionUsage(branch) }
42920
43195
  };
42921
43196
  }
43197
+ function isContextTreeUsageReference(reference) {
43198
+ return reference.kind === "message" && reference.authority === "assistant" || reference.kind === "compaction" || reference.kind === "branch_summary" || reference.kind === "child_usage_attributed";
43199
+ }
42922
43200
  async function readContextTreeUsage(manager, limits = { maxEntries: 16384, maxSourceBytes: 64 * 1024 * 1024 }, request, availabilityMaxSourceBytes) {
42923
43201
  if (!manager.supportsCapturedHistoryReads())
42924
43202
  return void 0;
42925
43203
  const sourceLimits = request?.limits ?? limits;
42926
43204
  const capturedLimits = { maxEntries: sourceLimits.maxEntries, maxSourceBytes: sourceLimits.maxSourceBytes };
43205
+ if (!Object.values(capturedLimits).every((value) => Number.isSafeInteger(value) && value > 0))
43206
+ throw new Error("Invalid history materialization limits");
42927
43207
  return manager.readSourceHistory((history) => {
42928
43208
  request?.retainMetadata(history.source);
42929
43209
  const reduce = async () => {
42930
- const materialized = await history.materialize(capturedLimits);
42931
- const allEntries = materialized.entries.map(({ entry }) => entry);
43210
+ const allEntries = [];
43211
+ let sourceBytes = 0;
43212
+ let after = 0;
43213
+ for (; ; ) {
43214
+ const page = await history.page(after);
43215
+ if (page.indexedThrough < history.source.sourceSequence)
43216
+ throw new Error("Captured history has incomplete index coverage");
43217
+ for (const reference of page.events) {
43218
+ if (!isContextTreeUsageReference(reference))
43219
+ continue;
43220
+ if (allEntries.length >= capturedLimits.maxEntries)
43221
+ throw new Error("History entry budget exceeded");
43222
+ if (sourceBytes + reference.locator.length > capturedLimits.maxSourceBytes)
43223
+ throw new Error("History source byte budget exceeded");
43224
+ const hydrated = await history.hydrateEntry(reference.id, capturedLimits.maxSourceBytes - sourceBytes);
43225
+ if (!hydrated)
43226
+ throw new Error("Context-tree usage entry source is unavailable");
43227
+ allEntries.push(hydrated.entry);
43228
+ sourceBytes += reference.locator.length;
43229
+ }
43230
+ if (page.nextAfter === null)
43231
+ break;
43232
+ after = page.nextAfter;
43233
+ }
42932
43234
  applyChildUsageAttributions(allEntries);
42933
43235
  const byId = new Map(allEntries.map((entry) => [entry.id, entry]));
42934
43236
  const branch = [];
@@ -42936,6 +43238,8 @@ async function readContextTreeUsage(manager, limits = { maxEntries: 16384, maxSo
42936
43238
  do {
42937
43239
  const page = await history.parentPath({ cursor });
42938
43240
  for (const reference of page.events) {
43241
+ if (!isContextTreeUsageReference(reference))
43242
+ continue;
42939
43243
  const entry = byId.get(reference.id);
42940
43244
  if (!entry)
42941
43245
  throw new Error("Context-tree parent-path entry source is unavailable");
@@ -42998,7 +43302,7 @@ function computeContextUsageFromEntries(allEntries, branch, contextWindow) {
42998
43302
  if (!hasPostCompactionUsage(branch)) {
42999
43303
  return { tokens: null, contextWindow, percent: null };
43000
43304
  }
43001
- const estimate = estimateContextTokens(buildSessionContext(allEntries).messages);
43305
+ const estimate = estimateContextTokens(buildSessionContext(allEntries, branch.at(-1)?.id ?? null).messages);
43002
43306
  if (estimate.tokens <= 0) {
43003
43307
  return void 0;
43004
43308
  }
@@ -43125,10 +43429,64 @@ function listChildSessionDirs(rlmSessionDir, request) {
43125
43429
  });
43126
43430
  return { paths, bytes };
43127
43431
  }
43432
+ async function readContextTreeProjectionFromDisk(sessionFile, request) {
43433
+ const entries = [];
43434
+ const hiddenParents = /* @__PURE__ */ new Map();
43435
+ let leafId = null;
43436
+ let hasHeader = false;
43437
+ let sourceBytes = 0;
43438
+ let metadataBytes = 0;
43439
+ try {
43440
+ await readCapturedSessionJournal(sessionFile, (record2) => {
43441
+ const value = record2.entry;
43442
+ if (!value || typeof value !== "object" || !("type" in value) || typeof value.type !== "string")
43443
+ throw new Error("Invalid session journal entry");
43444
+ const entry = value;
43445
+ if (!hasHeader) {
43446
+ if (entry.type !== "session" || typeof entry.id !== "string")
43447
+ throw new Error("Session source has no valid header");
43448
+ hasHeader = true;
43449
+ }
43450
+ if (entry.type !== "session")
43451
+ leafId = entry.id;
43452
+ if (entry.type === "request" || entry.type === "tool_intent") {
43453
+ metadataBytes += request.retainMetadata([entry.id, entry.parentId]);
43454
+ hiddenParents.set(entry.id, entry.parentId);
43455
+ return;
43456
+ }
43457
+ const bytes = record2.source?.locator.length ?? Buffer.byteLength(record2.json) + 1;
43458
+ if (sourceBytes + bytes > request.limits.maxSourceBytes)
43459
+ throw new ContextTreeLimitError("Context tree source byte budget exceeded");
43460
+ sourceBytes += bytes;
43461
+ if (entry.type === "session")
43462
+ return;
43463
+ if (entries.length >= request.limits.maxEntries)
43464
+ throw new ContextTreeLimitError("Context tree entry budget exceeded");
43465
+ entries.push(entry);
43466
+ });
43467
+ const visibleParent = (id) => {
43468
+ let remaining = hiddenParents.size;
43469
+ while (id !== null && hiddenParents.has(id)) {
43470
+ if (remaining-- === 0)
43471
+ throw new Error("Parent path lineage is unresolved");
43472
+ id = hiddenParents.get(id);
43473
+ }
43474
+ return id;
43475
+ };
43476
+ for (const entry of entries)
43477
+ entry.parentId = visibleParent(entry.parentId);
43478
+ const hasSourceLeaf = leafId !== null;
43479
+ leafId = visibleParent(leafId);
43480
+ applyChildUsageAttributions(entries);
43481
+ return { entries, leafId, hasSourceLeaf };
43482
+ } finally {
43483
+ request.releaseMetadata(metadataBytes);
43484
+ }
43485
+ }
43128
43486
  async function readContextTreeChildNodeFromDisk(childSessionDir, sessionFile, resolveContextWindow, request, identity) {
43129
- const allEntries = (await readSessionHistoryFile(sessionFile, request.limits)).filter((entry) => entry.type !== "session");
43130
- const branch = branchEntries(allEntries);
43131
- if (branch.length === 0) {
43487
+ const { entries: allEntries, leafId, hasSourceLeaf } = await readContextTreeProjectionFromDisk(sessionFile, request);
43488
+ const branch = branchEntries(allEntries, leafId);
43489
+ if (branch.length === 0 && !hasSourceLeaf) {
43132
43490
  return void 0;
43133
43491
  }
43134
43492
  const { ownUsage, totalUsage } = computeOwnAndTotalUsage(branch, allEntries);
@@ -45559,7 +45917,7 @@ async function loadExtensionModule(extensionPath) {
45559
45917
  // (file-path aliases would load a second, divergent copy of each package).
45560
45918
  // Also disable tryNative so jiti handles ALL imports (not just the entry point)
45561
45919
  // Node/dev must also share the native AI registry and implementation identities.
45562
- ...isBunBinary || isBundledCli ? { virtualModules: (await import("./bundled-modules-MX6YNAM2.js")).VIRTUAL_MODULES, tryNative: false } : {
45920
+ ...isBunBinary || isBundledCli ? { virtualModules: (await import("./bundled-modules-PEFT72QN.js")).VIRTUAL_MODULES, tryNative: false } : {
45563
45921
  alias: getAliases(),
45564
45922
  virtualModules: {
45565
45923
  "@ponythewhite/base-context-ai": src_exports,
@@ -48316,6 +48674,9 @@ var DEFAULT_FORK_MESSAGE_LIMITS = Object.freeze({
48316
48674
  async function readUserMessagesForForking(manager, limits = DEFAULT_FORK_MESSAGE_LIMITS) {
48317
48675
  const capturedLimits = { ...limits };
48318
48676
  const entries = manager.supportsCapturedHistoryReads() ? (await manager.materializeSourceHistory(capturedLimits)).entries.map(({ entry }) => entry) : manager.materializeResidentHistory(capturedLimits).entries;
48677
+ return projectUserMessages(entries);
48678
+ }
48679
+ function projectUserMessages(entries) {
48319
48680
  const result = [];
48320
48681
  for (const entry of entries) {
48321
48682
  if (entry.type !== "message" || entry.message.role !== "user")
@@ -48332,6 +48693,40 @@ async function readUserMessagesForForking(manager, limits = DEFAULT_FORK_MESSAGE
48332
48693
  }
48333
48694
  return result;
48334
48695
  }
48696
+ async function readVisibleUserMessagesForForking(manager, limits = DEFAULT_FORK_MESSAGE_LIMITS) {
48697
+ const { maxEntries, maxSourceBytes } = limits;
48698
+ if (!Number.isSafeInteger(maxEntries) || maxEntries <= 0 || !Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)
48699
+ throw new Error("Invalid history materialization limits");
48700
+ if (!manager.supportsCapturedHistoryReads())
48701
+ return readUserMessagesForForking(manager, { maxEntries, maxSourceBytes });
48702
+ return manager.readSourceHistory(async (history) => {
48703
+ const entries = [];
48704
+ let sourceBytes = 0;
48705
+ let after = 0;
48706
+ for (; ; ) {
48707
+ const page = await history.page(after);
48708
+ if (page.indexedThrough < history.source.sourceSequence)
48709
+ throw new Error("Captured history has incomplete index coverage");
48710
+ for (const reference of page.events) {
48711
+ if (reference.kind !== "message" || reference.authority === "assistant" || reference.authority === "runtime")
48712
+ continue;
48713
+ if (entries.length >= maxEntries)
48714
+ throw new Error("History entry budget exceeded");
48715
+ if (sourceBytes + reference.locator.length > maxSourceBytes)
48716
+ throw new Error("History source byte budget exceeded");
48717
+ const hydrated = await history.hydrateEntry(reference.id, maxSourceBytes - sourceBytes);
48718
+ if (!hydrated)
48719
+ throw new Error("Fork message source is unavailable");
48720
+ sourceBytes += reference.locator.length;
48721
+ entries.push(hydrated.entry);
48722
+ }
48723
+ if (page.nextAfter === null)
48724
+ break;
48725
+ after = page.nextAfter;
48726
+ }
48727
+ return projectUserMessages(entries);
48728
+ });
48729
+ }
48335
48730
 
48336
48731
  // dist/core/session-jsonl-export.js
48337
48732
  import { mkdir as mkdir3, open as open4, unlink } from "node:fs/promises";
@@ -59019,7 +59414,7 @@ var AgentSession = class _AgentSession {
59019
59414
  const epochContext = getCanonicalEpochContext(messages);
59020
59415
  if (epochContext)
59021
59416
  this._contextMode = epochContext.mode;
59022
- const unbudgetedPublic = !contextEpochsEnabled && Boolean(epochContext?.toolContinuations?.length || epochContext?.taskFrameRebased || epochContext?.checkpoint);
59417
+ const unbudgetedPublic = !contextEpochsEnabled && Boolean(epochContext?.toolContinuations?.length || epochContext?.taskFrameRebased || epochContext?.checkpoint || getCanonicalViewSelectionSource(messages)?.recoveryContractRequested);
59023
59418
  const nativeSkills = Boolean(contextEpochsEnabled || epochContext?.checkpoint || unbudgetedPublic);
59024
59419
  const skillPolicy = nativeSkills ? this._nativeRecoveryEnabled() ? "enabled" : "unavailable" : void 0;
59025
59420
  if (this._baseSystemPromptOptions.nativeSkillSelection !== skillPolicy) {
@@ -59055,7 +59450,19 @@ var AgentSession = class _AgentSession {
59055
59450
  if (epochContext.toolContinuations?.length && (!candidate.publicMessages || JSON.stringify(getCanonicalEpochContext(candidate.publicMessages)?.toolContinuations) !== JSON.stringify(epochContext.toolContinuations) || candidate.projection.pendingPublicMessageGroups?.length))
59056
59451
  throw new Error("Tool continuation requires its exact public candidate before epoch ACK");
59057
59452
  assertResourceCurrent(resource);
59058
- const representation = contextEpochRepresentation(candidate.request, candidate.assessment, limits.maxSourceBytes, unbudgetedPublic, candidate.responseItemIdentity);
59453
+ let representation;
59454
+ try {
59455
+ representation = contextEpochRepresentation(candidate.request, candidate.assessment, limits.maxSourceBytes, unbudgetedPublic, candidate.responseItemIdentity);
59456
+ } catch (error) {
59457
+ if (error instanceof UnsupportedContextEpochConfigurationError && !contextEpochsEnabled && !candidate.assessment && !committed && !acknowledged && !epochContext.taskFrameRebased && !epochContext.selectedSkills?.length && !epochContext.toolContinuations?.length && !candidate.publicMessages) {
59458
+ const source = getCanonicalViewSelectionSource(messages);
59459
+ const selected = new Set(candidate.selectedUnitIds);
59460
+ if (source.recoveryContractRequested && !source.requiresEpoch && !source.pendingPublicMessageGroups?.length && this.sessionManager === epochManager && compaction.isCurrent() && JSON.stringify(candidate.source) === JSON.stringify(source.source) && candidate.selectedUnitIds.length === source.units.length && selected.size === source.units.length && source.units.every((unit) => selected.has(unit.id))) {
59461
+ return;
59462
+ }
59463
+ }
59464
+ throw error;
59465
+ }
59059
59466
  const replayContract = "replayContract" in candidate.projection && candidate.projection.replayContract === "message-groups" ? "message-groups" : "complete-context";
59060
59467
  const publicWindow = "publicWindow" in candidate.projection && candidate.projection.publicWindow === true;
59061
59468
  const selection = JSON.stringify([
@@ -62704,7 +63111,7 @@ var AgentSession = class _AgentSession {
62704
63111
  async _runPreTurnCompaction() {
62705
63112
  const lastAssistant = this._findLastAssistantMessage();
62706
63113
  if (lastAssistant)
62707
- await this._checkCompaction(lastAssistant, false, false);
63114
+ await this._checkCompaction(lastAssistant, false, false, void 0, true);
62708
63115
  }
62709
63116
  async _prepareForCommit(policy, steps) {
62710
63117
  if (policy.initialRefineBarrier === "always" || policy.initialRefineBarrier === "ifInFlight" && this._refineInFlight) {
@@ -65384,7 +65791,7 @@ ${parsed.args}` : block;
65384
65791
  }
65385
65792
  }
65386
65793
  /** A private compiled context keeps extension summary edits separate from retained source recipes. */
65387
- async _prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner = this._captureCompactionOwner(), allowShortSession = false, budgetPressure = false) {
65794
+ async _prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner = this._captureCompactionOwner(), allowShortSession = false, budgetPressure = false, capacity) {
65388
65795
  this._assertCompactionOwner(owner);
65389
65796
  const limits = this.settingsManager.getCanonicalContextLimits();
65390
65797
  const resource = this._captureKernelResource();
@@ -65401,10 +65808,11 @@ ${parsed.args}` : block;
65401
65808
  const context = getCanonicalEpochContext(messages);
65402
65809
  if (context.checkpoint?.includeSummary && pathEntries.at(-1)?.type === "compaction")
65403
65810
  return { preparation: void 0, maxSourceBytes: limits.maxSourceBytes };
65404
- const boundary = canonicalRecoveryBoundary(messages);
65811
+ const authorization = getRecoveryCompactionAuthorization(capacity);
65812
+ const boundary = canonicalRecoveryBoundary(messages, authorization);
65405
65813
  const preparation = budgetPressure || context.checkpoint || boundary ? prepareViewCompaction(messages, context.references.map((ref) => ref?.ref.entryId), pathEntries, settings, boundary, allowShortSession, budgetPressure) : prepareCompaction(pathEntries, settings, allowShortSession);
65406
65814
  if (preparation)
65407
- prepareRecoveryCompaction(messages, preparation.firstKeptEntryId, limits.maxSourceBytes);
65815
+ prepareRecoveryCompaction(messages, preparation.firstKeptEntryId, limits.maxSourceBytes, authorization);
65408
65816
  return {
65409
65817
  preparation,
65410
65818
  messages,
@@ -65420,7 +65828,7 @@ ${parsed.args}` : block;
65420
65828
  */
65421
65829
  async _performCompaction(options) {
65422
65830
  const { model, apiKey, headers, customInstructions, signal, thinkingLevel, requests, compaction, semanticEdges, pathEntries, settings, owner = this._captureCompactionOwner(), allowShortSession = false, budgetPressure = false } = options;
65423
- const prepared = await this._prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner, allowShortSession, budgetPressure);
65831
+ const prepared = await this._prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner, allowShortSession, budgetPressure, options.capacity);
65424
65832
  this._assertCompactionOwner(owner);
65425
65833
  if (prepared.resource)
65426
65834
  assertResourceCurrent(prepared.resource);
@@ -65501,7 +65909,7 @@ ${parsed.args}` : block;
65501
65909
  }
65502
65910
  this._assertCompactionOwner(owner);
65503
65911
  const result = JSON.parse(JSON.stringify({ summary, firstKeptEntryId, tokensBefore, details }));
65504
- const recovery = prepared.messages ? prepareRecoveryCompaction(prepared.messages, firstKeptEntryId, prepared.maxSourceBytes) : void 0;
65912
+ const recovery = prepared.messages ? prepareRecoveryCompaction(prepared.messages, firstKeptEntryId, prepared.maxSourceBytes, getRecoveryCompactionAuthorization(options.capacity)) : void 0;
65505
65913
  if (prepared.resource)
65506
65914
  assertResourceCurrent(prepared.resource);
65507
65915
  if (recovery) {
@@ -66124,7 +66532,30 @@ ${parsed.args}` : block;
66124
66532
  const sessionHistory = (async () => {
66125
66533
  if (residentEntries !== void 0)
66126
66534
  return residentEntries;
66127
- return (await this.sessionManager.materializeSourceHistory(limits)).entries.map(({ entry }) => entry);
66535
+ return this.sessionManager.readSourceHistory(async (history) => {
66536
+ const entries = [];
66537
+ let sourceBytes = 0;
66538
+ let after = 0;
66539
+ for (; ; ) {
66540
+ const page = await history.page(after, 128);
66541
+ if (page.indexedThrough < history.source.sourceSequence)
66542
+ throw new Error("Captured refinement history has incomplete index coverage");
66543
+ for (const reference of page.events) {
66544
+ if (reference.kind !== "custom")
66545
+ continue;
66546
+ if (entries.length >= limits.maxEntries)
66547
+ throw new Error("Refinement history entry budget exceeded");
66548
+ if (sourceBytes + reference.locator.length > limits.maxSourceBytes)
66549
+ throw new Error("Refinement history source byte budget exceeded");
66550
+ const hydrated = await hydrateCapturedHistoryEntry(reference, limits.maxSourceBytes - sourceBytes, history.readPayload);
66551
+ entries.push(hydrated.entry);
66552
+ sourceBytes += reference.locator.length;
66553
+ }
66554
+ if (page.nextAfter === null)
66555
+ return entries;
66556
+ after = page.nextAfter;
66557
+ }
66558
+ });
66128
66559
  })();
66129
66560
  const [globalResult, sessionResult] = await Promise.allSettled([globalHistory, sessionHistory]);
66130
66561
  if (globalResult.status === "rejected") {
@@ -66445,7 +66876,7 @@ ${parsed.args}` : block;
66445
66876
  return void 0;
66446
66877
  return calculateContextTokens(assistantMessage.usage);
66447
66878
  }
66448
- async _checkCompaction(assistantMessage, skipAbortedCheck = true, queueAutonomousContinuation = true, invocationOwner) {
66879
+ async _checkCompaction(assistantMessage, skipAbortedCheck = true, queueAutonomousContinuation = true, invocationOwner, beforeNextTurn = false) {
66449
66880
  if (this._compactionSetupFailure)
66450
66881
  return false;
66451
66882
  if (invocationOwner && !this._isCompactionSourceOwnerCurrent(invocationOwner))
@@ -66518,7 +66949,7 @@ ${parsed.args}` : block;
66518
66949
  if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
66519
66950
  this._removeLastAssistantFromContext();
66520
66951
  }
66521
- return await this._runAutoCompaction("overflow", true, owner);
66952
+ return await this._runAutoCompaction("overflow", true, owner, false, void 0, beforeNextTurn);
66522
66953
  }
66523
66954
  if (this._pendingRequestedCompaction !== void 0) {
66524
66955
  return await this._runAutoCompaction("requested", false, owner);
@@ -66540,7 +66971,7 @@ ${parsed.args}` : block;
66540
66971
  }
66541
66972
  if (!this._isCompactionOwnerCurrent(owner) || !this._contextOptimizationAllowed())
66542
66973
  return false;
66543
- return await this._runAutoCompaction("threshold", false, owner);
66974
+ return await this._runAutoCompaction("threshold", false, owner, false, void 0, beforeNextTurn);
66544
66975
  }
66545
66976
  return false;
66546
66977
  }
@@ -66586,7 +67017,7 @@ This compaction outcome could not be saved to session history: ${persistenceErro
66586
67017
  this._emit({ type: "message_start", message: outcomeMessage });
66587
67018
  this._emit({ type: "message_end", message: outcomeMessage });
66588
67019
  }
66589
- async _runAutoCompaction(reason, willRetry, capturedOwner, resumeInPlace = false, capacity) {
67020
+ async _runAutoCompaction(reason, willRetry, capturedOwner, resumeInPlace = false, capacity, beforeNextTurn = false) {
66590
67021
  const checkpoint = this._pendingCheckpoint;
66591
67022
  const pending = this._pendingRequestedCompaction;
66592
67023
  const owner = checkpoint?.owner ?? pending?.owner ?? capturedOwner ?? this._captureCompactionOwner();
@@ -66699,6 +67130,12 @@ This compaction outcome could not be saved to session history: ${persistenceErro
66699
67130
  if (!this._isCompactionSourceOwnerCurrent(owner))
66700
67131
  throw failure2;
66701
67132
  this._clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(reason === "threshold" && shouldContinueAfterCompaction, queuedAutonomousContinuationsForThisCompaction);
67133
+ if (beforeNextTurn && error instanceof MissingRecoveryReplayContractError) {
67134
+ if (reason === "overflow")
67135
+ this._overflowRecovery = "idle";
67136
+ await this._endCompactionUnsuccessfully(reason, "skipped", "Compaction deferred until the next native request establishes recovery replay coverage.", { errorSeverity: "warning", customInstructions, owner });
67137
+ return false;
67138
+ }
66702
67139
  const errorMessage4 = error instanceof Error ? error.message : "compaction failed";
66703
67140
  const aborted = errorMessage4 === "Compaction cancelled" || error instanceof Error && error.name === "AbortError" || abort.signal.aborted;
66704
67141
  if (aborted) {
@@ -69462,34 +69899,13 @@ ${command}` : command;
69462
69899
  _contextWindowResolver() {
69463
69900
  return (provider, modelId) => this._modelRegistry.find(provider, modelId)?.contextWindow;
69464
69901
  }
69465
- _ownUsageMemo;
69466
69902
  // Whole-source own spend, identical to the catalog reduction at passivation.
69467
69903
  async getOwnUsageSummary() {
69468
69904
  if (!this.sessionManager.supportsCapturedHistoryReads()) {
69469
- const entries = await this.sessionManager.readEntries();
69905
+ const entries = this.sessionManager.getEntries();
69470
69906
  return sessionUsageSummaryFrom(computeOwnAndTotalUsage(entries, entries).ownUsage);
69471
69907
  }
69472
- const limits = { maxEntries: 16384, maxSourceBytes: 64 * 1024 * 1024 };
69473
- return this.sessionManager.readSourceHistory(async (history) => {
69474
- const { sessionId, sessionFile, sourceSequence } = history.source;
69475
- const memo = this._ownUsageMemo;
69476
- if (memo && memo.sessionId === sessionId && memo.sessionFile === sessionFile && memo.sourceSequence === sourceSequence && memo.count <= limits.maxEntries && memo.sourceBytes <= limits.maxSourceBytes) {
69477
- return memo.usage ? { ...memo.usage } : void 0;
69478
- }
69479
- const materialized = await history.materialize(limits);
69480
- const entries = materialized.entries.map(({ entry }) => entry);
69481
- applyChildUsageAttributions(entries);
69482
- const usage = sessionUsageSummaryFrom(computeOwnAndTotalUsage(entries, entries).ownUsage);
69483
- this._ownUsageMemo = {
69484
- sessionId,
69485
- sessionFile,
69486
- sourceSequence,
69487
- count: entries.length,
69488
- sourceBytes: materialized.sourceBytes,
69489
- usage
69490
- };
69491
- return usage ? { ...usage } : void 0;
69492
- });
69908
+ return this.sessionManager.readOwnUsageSummary();
69493
69909
  }
69494
69910
  /**
69495
69911
  * Build the agent context overview for /context: this session as the root
@@ -70090,7 +70506,7 @@ import { resolve as resolve15 } from "node:path";
70090
70506
  var BASE_CONTEXT_BUILD_ID_ENV = "BASE_CONTEXT_BUILD_ID";
70091
70507
  var BASE_CONTEXT_LAUNCHER_PATH_ENV = "BASE_CONTEXT_LAUNCHER_PATH";
70092
70508
  function bundledBuildId() {
70093
- return false ? void 0 : "v1.0.9-1-ge86dce7cb";
70509
+ return false ? void 0 : "v1.0.10-1-g67d926ccc";
70094
70510
  }
70095
70511
  function getDaemonRuntimeIdentity(environment = process.env) {
70096
70512
  const entrypoint = process.argv[1];
@@ -70917,7 +71333,7 @@ export {
70917
71333
  passivatedWorkerRosterEntry,
70918
71334
  sessionSummaryFromRosterEntry,
70919
71335
  AgentRoster,
70920
- readUserMessagesForForking,
71336
+ readVisibleUserMessagesForForking,
70921
71337
  SERPER_CREDENTIAL_ID,
70922
71338
  SERPER_CREDENTIAL_NAME,
70923
71339
  PromptAdmissionCancelledError,