@ponythewhite/base-context 1.0.10 → 1.0.12

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 (125) hide show
  1. package/CHANGELOG.md +22 -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/amazon-bedrock.js +3 -3
  6. package/dist/bundle/{anthropic-5PSCZEER.js → anthropic-BJVPUMPB.js} +2 -2
  7. package/dist/bundle/{azure-openai-responses-AYTLJR33.js → azure-openai-responses-ERRMAXK6.js} +4 -5
  8. package/dist/bundle/{bundled-modules-MX6YNAM2.js → bundled-modules-WCGPZI2H.js} +5 -5
  9. package/dist/bundle/{chunk-D3KOF57W.js → chunk-25VYRAC6.js} +14 -1
  10. package/dist/bundle/{chunk-2IPDSTDR.js → chunk-AEMRBMI2.js} +9 -9
  11. package/dist/bundle/{chunk-Q3MBSBEB.js → chunk-FOGKLC7V.js} +1 -1
  12. package/dist/bundle/{chunk-UHLGPYMI.js → chunk-IAKHCQA2.js} +185 -39
  13. package/dist/bundle/{chunk-KT2BNEPE.js → chunk-MUFZODP5.js} +1 -1
  14. package/dist/bundle/{chunk-QKIFBA7N.js → chunk-Q6UAHLII.js} +2 -2
  15. package/dist/bundle/{chunk-CDXQNS5P.js → chunk-YGV3Y4AD.js} +1009 -185
  16. package/dist/bundle/{cli-main-D7W3WWCV.js → cli-main-CTYDQHFE.js} +4 -4
  17. package/dist/bundle/cli.js +1 -1
  18. package/dist/bundle/{google-HTMCUJ7X.js → google-4GA4YMUX.js} +2 -2
  19. package/dist/bundle/{google-vertex-ZQO65AXF.js → google-vertex-7AMALD7D.js} +2 -2
  20. package/dist/bundle/{main-5J3QBZ5Y.js → main-GVGK354K.js} +5 -5
  21. package/dist/bundle/{mistral-SB7LU56G.js → mistral-74BXMNRM.js} +1 -1
  22. package/dist/bundle/{openai-codex-responses-5CEW4VN3.js → openai-codex-responses-COXNC4IH.js} +2 -2
  23. package/dist/bundle/{openai-completions-BAZJQSS2.js → openai-completions-BCSA5Q6S.js} +2 -2
  24. package/dist/bundle/{openai-responses-VHOE427P.js → openai-responses-ONCIZSJS.js} +3 -3
  25. package/dist/core/agent-session.d.ts +6 -1
  26. package/dist/core/agent-session.d.ts.map +1 -1
  27. package/dist/core/agent-session.js +445 -146
  28. package/dist/core/agent-session.js.map +1 -1
  29. package/dist/core/canonical-context.d.ts +19 -3
  30. package/dist/core/canonical-context.d.ts.map +1 -1
  31. package/dist/core/canonical-context.js +130 -9
  32. package/dist/core/canonical-context.js.map +1 -1
  33. package/dist/core/compaction/compaction.d.ts +9 -1
  34. package/dist/core/compaction/compaction.d.ts.map +1 -1
  35. package/dist/core/compaction/compaction.js +29 -3
  36. package/dist/core/compaction/compaction.js.map +1 -1
  37. package/dist/core/context-epoch-copy.d.ts +1 -1
  38. package/dist/core/context-epoch-copy.d.ts.map +1 -1
  39. package/dist/core/context-epoch-copy.js +18 -7
  40. package/dist/core/context-epoch-copy.js.map +1 -1
  41. package/dist/core/context-epoch.d.ts +4 -0
  42. package/dist/core/context-epoch.d.ts.map +1 -1
  43. package/dist/core/context-epoch.js +8 -1
  44. package/dist/core/context-epoch.js.map +1 -1
  45. package/dist/core/context-tree.d.ts +14 -11
  46. package/dist/core/context-tree.d.ts.map +1 -1
  47. package/dist/core/context-tree.js +145 -9
  48. package/dist/core/context-tree.js.map +1 -1
  49. package/dist/core/history-index-worker.d.ts.map +1 -1
  50. package/dist/core/history-index-worker.js +59 -6
  51. package/dist/core/history-index-worker.js.map +1 -1
  52. package/dist/core/history-index.d.ts +17 -0
  53. package/dist/core/history-index.d.ts.map +1 -1
  54. package/dist/core/history-index.js +22 -0
  55. package/dist/core/history-index.js.map +1 -1
  56. package/dist/core/inference-coordinator.d.ts +1 -1
  57. package/dist/core/inference-coordinator.d.ts.map +1 -1
  58. package/dist/core/inference-coordinator.js +23 -6
  59. package/dist/core/inference-coordinator.js.map +1 -1
  60. package/dist/core/messages.d.ts +2 -0
  61. package/dist/core/messages.d.ts.map +1 -1
  62. package/dist/core/messages.js +2 -0
  63. package/dist/core/messages.js.map +1 -1
  64. package/dist/core/refinement/refinement.d.ts +2 -0
  65. package/dist/core/refinement/refinement.d.ts.map +1 -1
  66. package/dist/core/refinement/refinement.js +10 -1
  67. package/dist/core/refinement/refinement.js.map +1 -1
  68. package/dist/core/request-usage.d.ts +34 -0
  69. package/dist/core/request-usage.d.ts.map +1 -0
  70. package/dist/core/request-usage.js +111 -0
  71. package/dist/core/request-usage.js.map +1 -0
  72. package/dist/core/request-view-selection.d.ts +2 -1
  73. package/dist/core/request-view-selection.d.ts.map +1 -1
  74. package/dist/core/request-view-selection.js +29 -2
  75. package/dist/core/request-view-selection.js.map +1 -1
  76. package/dist/core/session-fork-messages.d.ts +5 -0
  77. package/dist/core/session-fork-messages.d.ts.map +1 -1
  78. package/dist/core/session-fork-messages.js +44 -0
  79. package/dist/core/session-fork-messages.js.map +1 -1
  80. package/dist/core/session-history-index.d.ts +5 -0
  81. package/dist/core/session-history-index.d.ts.map +1 -1
  82. package/dist/core/session-history-index.js +7 -0
  83. package/dist/core/session-history-index.js.map +1 -1
  84. package/dist/core/session-manager.d.ts +2 -0
  85. package/dist/core/session-manager.d.ts.map +1 -1
  86. package/dist/core/session-manager.js +155 -13
  87. package/dist/core/session-manager.js.map +1 -1
  88. package/dist/core/session-tree.d.ts +9 -0
  89. package/dist/core/session-tree.d.ts.map +1 -1
  90. package/dist/core/session-tree.js +71 -11
  91. package/dist/core/session-tree.js.map +1 -1
  92. package/dist/core/settings-manager.d.ts +3 -0
  93. package/dist/core/settings-manager.d.ts.map +1 -1
  94. package/dist/core/settings-manager.js +7 -0
  95. package/dist/core/settings-manager.js.map +1 -1
  96. package/dist/core/system-prompt.d.ts +2 -0
  97. package/dist/core/system-prompt.d.ts.map +1 -1
  98. package/dist/core/system-prompt.js +4 -2
  99. package/dist/core/system-prompt.js.map +1 -1
  100. package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
  101. package/dist/modes/agent-connection/daemon-agent-connection.js +8 -1
  102. package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
  103. package/dist/modes/agent-connection/in-process-agent-connection.d.ts.map +1 -1
  104. package/dist/modes/agent-connection/in-process-agent-connection.js +4 -4
  105. package/dist/modes/agent-connection/in-process-agent-connection.js.map +1 -1
  106. package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
  107. package/dist/modes/daemon/daemon-mode.js +4 -4
  108. package/dist/modes/daemon/daemon-mode.js.map +1 -1
  109. package/dist/modes/daemon/daemon-protocol.d.ts +13 -3
  110. package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
  111. package/dist/modes/daemon/daemon-protocol.js +10 -2
  112. package/dist/modes/daemon/daemon-protocol.js.map +1 -1
  113. package/dist/modes/daemon/daemon-session-summarizer.d.ts +3 -0
  114. package/dist/modes/daemon/daemon-session-summarizer.d.ts.map +1 -1
  115. package/dist/modes/daemon/daemon-session-summarizer.js +71 -32
  116. package/dist/modes/daemon/daemon-session-summarizer.js.map +1 -1
  117. package/dist/modes/interactive/components/context-tree-format.d.ts.map +1 -1
  118. package/dist/modes/interactive/components/context-tree-format.js +49 -0
  119. package/dist/modes/interactive/components/context-tree-format.js.map +1 -1
  120. package/docs/compaction.md +27 -3
  121. package/docs/context-management.md +17 -1
  122. package/docs/rlm.md +1 -1
  123. package/docs/settings.md +12 -0
  124. package/docs/usage.md +24 -1
  125. package/package.json +4 -4
@@ -32,7 +32,7 @@ import {
32
32
  typebox_exports,
33
33
  validateToolArguments,
34
34
  waitForChildProcess
35
- } from "./chunk-2IPDSTDR.js";
35
+ } from "./chunk-AEMRBMI2.js";
36
36
  import {
37
37
  cleanupSessionResources,
38
38
  registerSessionResourceCleanup
@@ -67,7 +67,7 @@ import {
67
67
  requestTokenRouteIdentity,
68
68
  supportsFastMode,
69
69
  withRequestBody
70
- } from "./chunk-D3KOF57W.js";
70
+ } from "./chunk-25VYRAC6.js";
71
71
  import {
72
72
  __commonJS,
73
73
  __export,
@@ -10887,8 +10887,8 @@ var DAEMON_PROTOCOL_NAME = PRODUCT.daemonService;
10887
10887
  var DAEMON_PROTOCOL_VERSION = 13;
10888
10888
  var DAEMON_LEGACY_INSPECTION_PROTOCOL_VERSIONS = [8, 9, 10];
10889
10889
  var DAEMON_COMMAND_ENVELOPE_MIN_PROTOCOL_VERSION = 8;
10890
- var DAEMON_SCHEMA_REVISION = 49;
10891
- var DAEMON_SCHEMA_ID = "protocol-13-schema-49-subagent-capacity";
10890
+ var DAEMON_SCHEMA_REVISION = 50;
10891
+ var DAEMON_SCHEMA_ID = "protocol-13-schema-50-context-request-usage";
10892
10892
  var DAEMON_PROTOCOL_INFO = {
10893
10893
  name: DAEMON_PROTOCOL_NAME,
10894
10894
  version: DAEMON_PROTOCOL_VERSION
@@ -10913,6 +10913,7 @@ var DAEMON_DEFAULT_SERVER_CAPABILITIES = [
10913
10913
  "cron_resume",
10914
10914
  "agent_results",
10915
10915
  "model_catalog",
10916
+ "context_request_usage",
10916
10917
  "side_question_transcript",
10917
10918
  "transient_bash",
10918
10919
  "session_input_admission",
@@ -27790,6 +27791,12 @@ function readContextEpoch(details, maxBytes) {
27790
27791
  throw new Error("Invalid committed context epoch");
27791
27792
  return snapshotContextEpoch(value, maxBytes);
27792
27793
  }
27794
+ var UnsupportedContextEpochConfigurationError = class extends Error {
27795
+ constructor() {
27796
+ super("Unsupported context epoch request configuration");
27797
+ this.name = "UnsupportedContextEpochConfigurationError";
27798
+ }
27799
+ };
27793
27800
  function contextEpochRepresentation(request, assessment, maxBytes, unbudgetedPublic = false, responseItemIdentity) {
27794
27801
  if (!assessment && !unbudgetedPublic || assessment && (!assessment.profile || assessment.limitSource !== "explicit-profile" || !assessment.route || !assessment.model) || request.body === void 0)
27795
27802
  throw new Error("Committed context epoch requires its explicit request profile");
@@ -27827,7 +27834,7 @@ function contextEpochRepresentation(request, assessment, maxBytes, unbudgetedPub
27827
27834
  if (["input", "messages", "previous_response_id", "prompt_cache_key"].includes(key2))
27828
27835
  continue;
27829
27836
  if (!fields.has(key2))
27830
- throw new Error("Unsupported context epoch request configuration");
27837
+ throw new UnsupportedContextEpochConfigurationError();
27831
27838
  configuration[key2] = value;
27832
27839
  }
27833
27840
  const input = "input" in body ? body.input : "messages" in body ? body.messages : void 0;
@@ -28079,6 +28086,7 @@ var SESSION_SLASH_COMMAND_CUSTOM_TYPE = "session_slash_command";
28079
28086
  var SESSION_SLASH_COMMAND_RESULT_CUSTOM_TYPE = "session_slash_command_result";
28080
28087
  var COMPACTION_OUTCOME_CUSTOM_TYPE = "compaction_outcome";
28081
28088
  var REFINEMENT_OUTCOME_CUSTOM_TYPE = "refinement_outcome";
28089
+ var HARNESS_SNAPSHOT_CUSTOM_TYPE = "harness_snapshot";
28082
28090
  var RLM_CHILD_FAILURE_CUSTOM_TYPE = "rlm_child_failure";
28083
28091
  var RLM_CHILD_TERMINAL_NOTICE_CUSTOM_TYPE = "rlm_child_terminal_notice";
28084
28092
  function createRlmChildFailureMessage(details, timestamp = Date.now()) {
@@ -29066,6 +29074,15 @@ var HistoryIndex = class _HistoryIndex {
29066
29074
  snapshot: target
29067
29075
  });
29068
29076
  }
29077
+ /** Whole-source own usage for exactly the current acknowledged owner snapshot. */
29078
+ async currentSourceUsage(sessionId, snapshot) {
29079
+ return await this.request({
29080
+ id: this.nextId++,
29081
+ action: "current_source_usage",
29082
+ sessionId,
29083
+ snapshot
29084
+ });
29085
+ }
29069
29086
  /** Latest label control for this source target, including a clear. */
29070
29087
  async sourceLabel(sessionId, targetId, through) {
29071
29088
  return await this.request({ id: this.nextId++, action: "source_label", sessionId, targetId, through });
@@ -29080,6 +29097,17 @@ var HistoryIndex = class _HistoryIndex {
29080
29097
  through
29081
29098
  });
29082
29099
  }
29100
+ /** All matching source update refs, including off-branch and older revisions. */
29101
+ async sourceContextUpdates(sessionId, target, through, after = 0) {
29102
+ return await this.request({
29103
+ id: this.nextId++,
29104
+ action: "source_context_updates",
29105
+ sessionId,
29106
+ target: target.kind === "assistant-usage" ? { kind: target.kind, targetId: target.targetId } : { kind: target.kind, toolCallId: target.toolCallId },
29107
+ through,
29108
+ after
29109
+ });
29110
+ }
29083
29111
  async get(sessionId, eventId, scope) {
29084
29112
  return await this.request({
29085
29113
  id: this.nextId++,
@@ -29402,6 +29430,7 @@ function createSessionHistoryReadScope(index, source, query, scope) {
29402
29430
  }),
29403
29431
  sourceLabel: (targetId) => query(() => index.sourceLabel(sessionId, targetId, source.sourceSequence)),
29404
29432
  sourceAssistantUsage: (targetId) => query(() => index.sourceAssistantUsage(sessionId, targetId, source.sourceSequence)),
29433
+ sourceContextUpdates: (target, after = 0) => query(() => index.sourceContextUpdates(sessionId, target, source.sourceSequence, after)),
29405
29434
  ipythonSentMessages: (toolCallId, options = {}) => query(() => index.ipythonSentMessages(sessionId, branch, toolCallId, options)),
29406
29435
  get,
29407
29436
  page,
@@ -29495,6 +29524,12 @@ var SessionHistoryIndex = class {
29495
29524
  const index = await this.synchronize(captured);
29496
29525
  return index.currentSourceBootstrap(this.sessionId, captured);
29497
29526
  }
29527
+ /** Caller holds the owner queue until the exact current projection is read. */
29528
+ async currentSourceUsage(snapshot) {
29529
+ const captured = { ...snapshot };
29530
+ const index = await this.synchronize(captured);
29531
+ return index.currentSourceUsage(this.sessionId, captured);
29532
+ }
29498
29533
  /** Finish accepted indexing, then wait for the external worker to close. */
29499
29534
  close() {
29500
29535
  this.closing ??= (async () => {
@@ -31574,7 +31609,19 @@ function prepareCanonicalEpoch(messages, selectedUnitIds, representation, maxByt
31574
31609
  messages: chosen
31575
31610
  };
31576
31611
  }
31577
- function canonicalRecoveryBoundary(messages) {
31612
+ var MissingRecoveryReplayContractError = class extends Error {
31613
+ constructor() {
31614
+ super("Recovery compaction requires an accepted replay contract for its selected results");
31615
+ this.name = "MissingRecoveryReplayContractError";
31616
+ }
31617
+ };
31618
+ function sameRecoverySource(left, right, ownerStillCurrent = false) {
31619
+ return JSON.stringify(left) === JSON.stringify(right) || ownerStillCurrent && left.sessionId === right.sessionId && left.sessionFile === right.sessionFile && left.persistent === right.persistent;
31620
+ }
31621
+ function sameRecoveryReference(left, right, ownerStillCurrent = false) {
31622
+ return sameRecoverySource(left.source, right.source, ownerStillCurrent) && JSON.stringify(left.ref) === JSON.stringify(right.ref) && left.sourceRevision === right.sourceRevision;
31623
+ }
31624
+ function canonicalRecoveryBoundary(messages, authorization) {
31578
31625
  const context = compiledEpochContexts.get(messages);
31579
31626
  const units = getCanonicalViewUnits(messages);
31580
31627
  if (!context || !units)
@@ -31584,15 +31631,22 @@ function canonicalRecoveryBoundary(messages) {
31584
31631
  const recoveries = units.flatMap((unit, index) => unit.kind === "recovery" ? [context.references[index]] : []);
31585
31632
  if (!recoveries.length)
31586
31633
  return;
31634
+ if (authorization) {
31635
+ const ownerStillCurrent = authorization.isSourceCurrent?.();
31636
+ 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))))
31637
+ throw new Error("Recovery compaction authorization no longer matches its captured source");
31638
+ return latestLiteralReference(context.references)?.ref.entryId;
31639
+ }
31587
31640
  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");
31641
+ const inherited = checkpoint?.includeSummary === true && checkpoint.replayContract === "message-groups";
31642
+ 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)))))
31643
+ throw new MissingRecoveryReplayContractError();
31590
31644
  return checkpoint.literalTailId;
31591
31645
  }
31592
- function prepareRecoveryCompaction(messages, firstKeptEntryId, maxBytes) {
31593
- const boundary = canonicalRecoveryBoundary(messages);
31646
+ function prepareRecoveryCompaction(messages, firstKeptEntryId, maxBytes, authorization) {
31647
+ const boundary = canonicalRecoveryBoundary(messages, authorization);
31594
31648
  const context = compiledEpochContexts.get(messages);
31595
- const publicWindow = context?.checkpoint?.publicWindow === true && context.checkpoint.replayContract === "message-groups";
31649
+ const publicWindow = authorization ? authorization.publicWindow : context?.checkpoint?.publicWindow === true && context.checkpoint.replayContract === "message-groups";
31596
31650
  if (!boundary && !publicWindow && !context?.selectedSkills?.length && !context?.toolContinuations?.length)
31597
31651
  return;
31598
31652
  if (!context)
@@ -31676,7 +31730,7 @@ var CanonicalContextCompiler = class {
31676
31730
  hasActiveEntry(entryId) {
31677
31731
  return this.entries.has(entryId);
31678
31732
  }
31679
- async compile(view, limits, omittedAssistantIds = /* @__PURE__ */ new Set(), frameOptions = {}, resourceCapture, initialContextMode = "on", allowPendingToolPublic = false, purpose = "request") {
31733
+ async compile(view, limits, omittedAssistantIds = /* @__PURE__ */ new Set(), frameOptions = {}, resourceCapture, initialContextMode = "on", allowPendingToolPublic = false, purpose2 = "request") {
31680
31734
  const generation = this.generation;
31681
31735
  const frameLimits = taskFrameLimits(frameOptions);
31682
31736
  const previousSource = this.source;
@@ -31814,7 +31868,7 @@ var CanonicalContextCompiler = class {
31814
31868
  const referenceFrame = resetFrame ? checkpoint?.taskFrame : previousFrame;
31815
31869
  if (resetFrame || referenceFrame && referenceFrame.messages.length <= 1)
31816
31870
  this.forceTaskFrameRebase = false;
31817
- const forceRebase = purpose === "request" && this.forceTaskFrameRebase;
31871
+ const forceRebase = purpose2 === "request" && this.forceTaskFrameRebase;
31818
31872
  let taskFrame = tasks ? compileTaskFrame(tasks, frameLimits, forceRebase ? void 0 : referenceFrame) : void 0;
31819
31873
  const taskFrameRebased = Boolean(mode === "on" && referenceFrame && taskFrame !== referenceFrame && (!taskFrame || taskFrame.messages.length === 1));
31820
31874
  const resource = mode === "on" && resourceCapture && (resourceCapture.enabled || checkpoint) ? renderResourceView(resourceCapture) : void 0;
@@ -32146,7 +32200,7 @@ ${JSON.stringify(selections.map((skill) => ({
32146
32200
  });
32147
32201
  if (frozenGroups.length !== candidates.filter((candidate) => candidate.prior).length)
32148
32202
  throw new Error("Committed tool continuation lost its original group");
32149
- if (purpose === "request" && candidates.length && (!allowPendingToolPublic || mode === "off"))
32203
+ if (purpose2 === "request" && candidates.length && (!allowPendingToolPublic || mode === "off"))
32150
32204
  throw new Error("Tool continuation requires an enabled native public request boundary");
32151
32205
  const readToolEvidence = async (metadata) => {
32152
32206
  const cached = next.get(metadata.id);
@@ -32324,11 +32378,84 @@ ${JSON.stringify(selections.map((skill) => ({
32324
32378
  units: selectionUnits,
32325
32379
  limits: unitLimits,
32326
32380
  ...mode === "on" && (taskFrameRebased || checkpoint) ? { requiresEpoch: true } : {},
32381
+ ...mode === "on" && sourceUnits.some((unit) => unit.kind === "recovery") ? { recoveryContractRequested: true } : {},
32327
32382
  ...pendingPublicMessageGroups.length ? { pendingPublicMessageGroups } : {}
32328
32383
  }
32329
32384
  });
32385
+ const inheritedRecoveryCoverage = [];
32386
+ if (checkpoint?.includeSummary && checkpoint.replayContract === "message-groups" && closedUnits.some((unit) => unit.kind === "recovery")) {
32387
+ const prefix = await view.atSnapshot(checkpoint.source);
32388
+ const suffix = /* @__PURE__ */ new Map();
32389
+ const frozenViews = /* @__PURE__ */ new Map();
32390
+ let capturedMessages = 0;
32391
+ let retained = false;
32392
+ let cursor2;
32393
+ for (; ; ) {
32394
+ const page = await prefix.contextManifest({ cursor: cursor2, limit: 128 });
32395
+ if (page.selection !== "known")
32396
+ throw new Error("Summary recovery source is unavailable");
32397
+ if (!cursor2 && page.summaryRef) {
32398
+ const entry = await hydrate(page.summaryRef, void 0, prefix);
32399
+ const metadata = await prefix.get(page.summaryRef.entryId);
32400
+ const prior = entry.type === "compaction" && metadata?.qualification === "native-context-epoch" && metadata.retention !== "retained-import" ? readContextEpoch(entry.details, maxSourceBytes) : void 0;
32401
+ if ((!prior || prior.includeSummary) && page.summaryRef.entryId === checkpoint.literalTailId)
32402
+ retained = true;
32403
+ capturedMessages += prior?.views.length ?? 0;
32404
+ for (const pinned of prior?.views ?? []) {
32405
+ if (pinned.ref.entryId === checkpoint.literalTailId)
32406
+ retained = true;
32407
+ if (retained) {
32408
+ suffix.set(pinned.ref.entryId, pinned.ref);
32409
+ frozenViews.set(pinned.ref.entryId, pinned);
32410
+ }
32411
+ }
32412
+ }
32413
+ for (const ref of page.refs) {
32414
+ if (ref.entryId === checkpoint.literalTailId)
32415
+ retained = true;
32416
+ if (retained)
32417
+ suffix.set(ref.entryId, ref);
32418
+ }
32419
+ capturedMessages += page.refs.length;
32420
+ if (capturedMessages > maxMessages)
32421
+ throw new Error("Summary recovery source exceeds its message budget");
32422
+ if (!page.nextCursor)
32423
+ break;
32424
+ cursor2 = page.nextCursor;
32425
+ }
32426
+ for (const [index, message2] of closedMessages.entries()) {
32427
+ if (closedUnits[index].kind !== "recovery")
32428
+ continue;
32429
+ const reference = epochReferences.get(message2);
32430
+ if (checkpoint.views.some((covered) => sameRecoveryReference(reference, covered))) {
32431
+ inheritedRecoveryCoverage.push(reference);
32432
+ continue;
32433
+ }
32434
+ const frozen = suffix.get(reference.ref.entryId);
32435
+ if (!frozen || JSON.stringify(frozen) !== JSON.stringify(reference.ref))
32436
+ continue;
32437
+ const pinned = frozenViews.get(frozen.entryId);
32438
+ if (pinned) {
32439
+ if (reference.sourceRevision === pinned.sourceRevision)
32440
+ inheritedRecoveryCoverage.push(reference);
32441
+ continue;
32442
+ }
32443
+ const revisions = [frozen.revision];
32444
+ const entry = next.get(frozen.entryId)?.entry;
32445
+ if (entry?.type === "message" && entry.message.role === "toolResult" && entry.message.toolName === "ipython") {
32446
+ const updates = await prefix.contextUpdates({
32447
+ kind: "ipython-sent-message",
32448
+ toolCallId: entry.message.toolCallId
32449
+ });
32450
+ revisions.push(...updates.refs.map((update) => update.revision));
32451
+ }
32452
+ if (reference.sourceRevision === JSON.stringify(revisions))
32453
+ inheritedRecoveryCoverage.push(reference);
32454
+ }
32455
+ }
32330
32456
  compiledEpochContexts.set(closedMessages, {
32331
- ...purpose === "read" ? { readOnly: true } : {},
32457
+ ...inheritedRecoveryCoverage.length ? { inheritedRecoveryCoverage } : {},
32458
+ ...purpose2 === "read" ? { readOnly: true } : {},
32332
32459
  mode,
32333
32460
  source: { ...view.source },
32334
32461
  checkpoint,
@@ -32348,7 +32475,7 @@ ${JSON.stringify(selections.map((skill) => ({
32348
32475
  this.source = view.source;
32349
32476
  this.sourceBytes = sourceBytes;
32350
32477
  this.messageCount = messageCount;
32351
- return purpose === "read" && pendingPublicMessageGroups.length ? renderToolContinuationWindow(closedMessages).messages : closedMessages;
32478
+ return purpose2 === "read" && pendingPublicMessageGroups.length ? renderToolContinuationWindow(closedMessages).messages : closedMessages;
32352
32479
  }
32353
32480
  };
32354
32481
 
@@ -32381,6 +32508,10 @@ var PublicContextBudgetError = class extends RequestTokenBudgetError {
32381
32508
  this.#summaryCapacity = summaryCapacity;
32382
32509
  }
32383
32510
  };
32511
+ var recoveryCompactionAuthorizations = /* @__PURE__ */ new WeakMap();
32512
+ function getRecoveryCompactionAuthorization(error) {
32513
+ return error ? recoveryCompactionAuthorizations.get(error) : void 0;
32514
+ }
32384
32515
  function captureRequestViewBoundary(messages, commit, validate2, fixedPrepare, isSourceCurrent) {
32385
32516
  const source = getCanonicalViewSelectionSource(messages);
32386
32517
  if (!source)
@@ -32479,7 +32610,7 @@ function publicBudgetFailure(boundary, messages, request, projection, budget, as
32479
32610
  });
32480
32611
  };
32481
32612
  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([
32613
+ const error = new PublicContextBudgetError(boundary.source, assessment, original, budget.measure(minimum), (context.taskFrame?.messages.length ?? 0) > 1, JSON.stringify([
32483
32614
  boundary.source.sessionId,
32484
32615
  boundary.source.sessionFile,
32485
32616
  source.units.map((unit) => [unit.id, unit.sourceRevision]),
@@ -32498,6 +32629,21 @@ function publicBudgetFailure(boundary, messages, request, projection, budget, as
32498
32629
  const measured = budget.measure(withRequestBody(request, JSON.stringify({ ...body, [inputKey]: kept })));
32499
32630
  return measured.status === "unknown" || measured.availableInputTokens === null || measured.estimatedInputTokens === null ? void 0 : Math.floor(measured.availableInputTokens - measured.estimatedInputTokens);
32500
32631
  }, boundary.isSourceCurrent);
32632
+ if (projection.replayContract === "message-groups") {
32633
+ const originalContext = getCanonicalEpochContext(boundary.messages);
32634
+ const recoveries = boundary.units.flatMap((unit, index) => unit.kind === "recovery" && originalContext.references[index] ? [originalContext.references[index]] : []);
32635
+ if (recoveries.length) {
32636
+ recoveryCompactionAuthorizations.set(error, {
32637
+ source: originalContext.source,
32638
+ recoveries,
32639
+ resourceRevision: originalContext.resourceRevision,
32640
+ // Do not extend a partial public conversion to native groups the encoder did not replace.
32641
+ publicWindow: messages !== boundary.messages && projection.publicWindow === true && boundary.units.every((unit, index) => !["recovery", "replay-group"].includes(unit.kind) || context.references[index]?.rendering !== void 0),
32642
+ isSourceCurrent: boundary.isSourceCurrent
32643
+ });
32644
+ }
32645
+ }
32646
+ return error;
32501
32647
  }
32502
32648
  async function prepareFixedRequestView(boundary, request, projection, assessment) {
32503
32649
  projection = canonicalRequestProjection(boundary, projection);
@@ -32570,7 +32716,7 @@ async function selectRequestView(boundary, request, projection, budget, allowShr
32570
32716
  const inputKey = requestInputKey(request, projection);
32571
32717
  if (budget && full?.limitSource !== "explicit-profile" || !inputKey)
32572
32718
  return;
32573
- if (!budget && !boundary.requiresEpoch && !boundary.pendingPublicMessageGroups?.length)
32719
+ if (!budget && !boundary.requiresEpoch && !boundary.recoveryContractRequested && !boundary.pendingPublicMessageGroups?.length)
32574
32720
  return;
32575
32721
  const payload = JSON.parse(request.body);
32576
32722
  const input = payload[inputKey];
@@ -32999,6 +33145,9 @@ function wrapStreamFnWithSemanticEdges(streamFn, recorder) {
32999
33145
  }
33000
33146
 
33001
33147
  // dist/core/inference-coordinator.js
33148
+ function isPrimaryRequest(purpose2) {
33149
+ return purpose2 === "main" || purpose2 === "child";
33150
+ }
33002
33151
  var REQUEST_STREAM_BINDING = /* @__PURE__ */ Symbol("base-context.request-stream-binding");
33003
33152
  var captureNativeCompactionRequests = /* @__PURE__ */ Symbol("base-context.native-compaction-requests");
33004
33153
  var captureNativeBranchRequests = /* @__PURE__ */ Symbol("base-context.native-branch-requests");
@@ -33230,7 +33379,7 @@ var InferenceCoordinator = class _InferenceCoordinator {
33230
33379
  this.notifyActivity();
33231
33380
  return captured;
33232
33381
  }
33233
- /** Explicit Root-owned epoch boundary, on this same captured MAIN source only. */
33382
+ /** Explicit session-owned epoch boundary, on this same captured primary source only. */
33234
33383
  bindRequestViewBoundary(messages, commit, validate2, fixedPrepare, isSourceCurrent) {
33235
33384
  this.assertAdmission();
33236
33385
  if (!this.capturedSink)
@@ -33448,7 +33597,7 @@ var InferenceCoordinator = class _InferenceCoordinator {
33448
33597
  activeUser = true;
33449
33598
  this.releaseCapture();
33450
33599
  this.finishCapturePending?.();
33451
- if (this.work.budget || this.requestViewBoundary && operation.metadata.purpose === "main") {
33600
+ if (this.work.budget || this.requestViewBoundary && isPrimaryRequest(operation.metadata.purpose)) {
33452
33601
  model = structuredClone(model);
33453
33602
  context = structuredClone({
33454
33603
  ...context,
@@ -33481,7 +33630,7 @@ var InferenceCoordinator = class _InferenceCoordinator {
33481
33630
  if (!this.work.admissionOpen)
33482
33631
  throw new Error("Inference owner is closing");
33483
33632
  const parentBudget = this.work.budget;
33484
- const boundary = operation.metadata.purpose === "main" ? this.requestViewBoundary : void 0;
33633
+ const boundary = isPrimaryRequest(operation.metadata.purpose) ? this.requestViewBoundary : void 0;
33485
33634
  const budget = boundary ? parentBudget?.capture() : parentBudget;
33486
33635
  let measuredForAdmission = false;
33487
33636
  let countingInput = false;
@@ -33527,7 +33676,7 @@ var InferenceCoordinator = class _InferenceCoordinator {
33527
33676
  } : void 0;
33528
33677
  const requiredPublic = Boolean(boundary?.pendingPublicMessageGroups?.length);
33529
33678
  const requiredEpoch = boundary?.requiresEpoch === true;
33530
- const canSelect = (budget || boundary?.fixedPrepare || requiredPublic || requiredEpoch) && boundary && matchesRequestView(boundary, source, context);
33679
+ const canSelect = (budget || boundary?.fixedPrepare || requiredPublic || requiredEpoch || boundary?.recoveryContractRequested) && boundary && matchesRequestView(boundary, source, context);
33531
33680
  if (requiredPublic && (!canSelect || boundary?.fixedPrepare))
33532
33681
  throw new Error("Tool continuation requires a selectable native public request boundary");
33533
33682
  const responsesMessageIds = canSelect && !boundary.fixedPrepare && (model.api === "openai-responses" || model.api === "openai-codex-responses") ? boundary.providerMessageIndices.map((index) => {
@@ -33663,7 +33812,14 @@ var InferenceCoordinator = class _InferenceCoordinator {
33663
33812
  }
33664
33813
  };
33665
33814
  const signal = options?.signal ? AbortSignal.any([options.signal, this.work.cancellation.signal]) : this.work.cancellation.signal;
33666
- const events = await send(model, context, { ...options, signal, attempts, requireProviderAttempts: true });
33815
+ const sessionId = options?.sessionId ?? (isPrimaryRequest(operation.metadata.purpose) ? source.sessionId : `${operation.metadata.purpose}:${source.sessionId}`);
33816
+ const events = await send(model, context, {
33817
+ ...options,
33818
+ sessionId,
33819
+ signal,
33820
+ attempts,
33821
+ requireProviderAttempts: true
33822
+ });
33667
33823
  localSimulation = isLocalFauxStream(events);
33668
33824
  const settled = settle(events.result());
33669
33825
  events.result = async () => (await settled).message;
@@ -33782,7 +33938,7 @@ var InferenceCoordinator = class _InferenceCoordinator {
33782
33938
  if (captured || previous?.metadata.operationId !== operationId) {
33783
33939
  previous = executor.bindOperation(model, { ...request, semanticEdgeId }, operationId);
33784
33940
  }
33785
- return (await executor.execute(previous, model, context, options, inner, captured !== void 0 && request.purpose === "main")).events;
33941
+ return (await executor.execute(previous, model, context, options, inner, captured !== void 0 && isPrimaryRequest(request.purpose))).events;
33786
33942
  };
33787
33943
  wrapped[REQUEST_STREAM_BINDING] = { coordinator: this, inner };
33788
33944
  return wrapped;
@@ -34034,12 +34190,31 @@ function estimateContextTokens(messages) {
34034
34190
  lastUsageIndex: usageInfo.index
34035
34191
  };
34036
34192
  }
34037
- function shouldCompact(contextTokens, contextWindow, settings) {
34193
+ function shouldCompact(contextTokens, contextWindow, settings, fixedContextTokens = 0) {
34038
34194
  if (!settings.enabled)
34039
34195
  return false;
34040
34196
  if (contextWindow <= 0)
34041
34197
  return false;
34042
- return contextTokens > contextWindow - settings.reserveTokens;
34198
+ const modelLimit = contextWindow - settings.reserveTokens;
34199
+ const target = settings.targetTokens === "model-limit" ? modelLimit : Math.max(settings.targetTokens ?? Math.min(96e3, contextWindow / 2), fixedContextTokens + 4 * settings.keepRecentTokens);
34200
+ return contextTokens > Math.min(target, modelLimit);
34201
+ }
34202
+ function estimateFixedCompactionTokens(systemPrompt, tools, messages) {
34203
+ const toolSchemas = tools.map(({ name, description, parameters }) => ({ name, description, parameters }));
34204
+ let tokens = Math.ceil((systemPrompt.length + (tools.length ? JSON.stringify(toolSchemas).length : 0)) / 4);
34205
+ let hasHarnessSnapshot = false;
34206
+ for (let index = messages.length - 1; index >= 0; index--) {
34207
+ const message2 = messages[index];
34208
+ if (message2.role !== "custom")
34209
+ continue;
34210
+ if (message2.customType === TASK_FRAME_CUSTOM_TYPE)
34211
+ tokens += estimateTokens(message2);
34212
+ else if (message2.customType === HARNESS_SNAPSHOT_CUSTOM_TYPE && !hasHarnessSnapshot) {
34213
+ tokens += estimateTokens(message2);
34214
+ hasHarnessSnapshot = true;
34215
+ }
34216
+ }
34217
+ return tokens;
34043
34218
  }
34044
34219
  function compactionTokenScale(messages) {
34045
34220
  const usageInfo = getLastAssistantUsageInfo(messages);
@@ -34627,7 +34802,7 @@ function captureEpochCopyEntry(entry, source) {
34627
34802
  ...updateTarget ? { updateTarget } : {}
34628
34803
  };
34629
34804
  }
34630
- async function rebuildCopiedContextEpoch(history, copied, limits) {
34805
+ async function rebuildCopiedContextEpoch(history, copied, limits, metadataMaxBytes = limits.maxSourceBytes) {
34631
34806
  const view = history.branchContext;
34632
34807
  const manifest = await view.contextManifest({ limit: 1 });
34633
34808
  if (manifest.selection !== "known")
@@ -34656,15 +34831,26 @@ async function rebuildCopiedContextEpoch(history, copied, limits) {
34656
34831
  throw new Error("Tool continuation recipes require their original native execution source");
34657
34832
  if (!checkpoint || checkpoint.literalTailId !== entry.firstKeptEntryId || !view.atSnapshot)
34658
34833
  throw new Error("Copied context epoch boundary is unavailable");
34659
- if (copied.entries.length > limits.maxEntries || checkpoint.views.length > limits.maxEntries)
34834
+ if (checkpoint.views.length > limits.maxEntries)
34660
34835
  throw new Error("Copied context epoch item budget exceeded");
34661
- stringifyBoundedJson(copied, limits.maxSourceBytes);
34836
+ stringifyBoundedJson(copied, metadataMaxBytes);
34662
34837
  const oldByRevision = new Map([...oldById.values()].map((source) => [source.revision, source]));
34663
34838
  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);
34839
+ let after = 0;
34840
+ for (; ; ) {
34841
+ const page = await history.page(after, 128);
34842
+ if (page.indexedThrough < history.source.sourceSequence)
34843
+ throw new Error("Copied context destination has incomplete index coverage");
34844
+ for (const actual of page.events) {
34845
+ if (!oldById.has(actual.id))
34846
+ continue;
34847
+ if (destination.size >= limits.maxEntries)
34848
+ throw new Error("Copied context epoch item budget exceeded");
34849
+ destination.set(actual.id, actual);
34850
+ }
34851
+ if (page.nextAfter === null)
34852
+ break;
34853
+ after = page.nextAfter;
34668
34854
  }
34669
34855
  const prefixViews = /* @__PURE__ */ new Map();
34670
34856
  const prefix = async (source) => {
@@ -36655,6 +36841,7 @@ var DEFAULT_MANAGER_HISTORY_LIMITS = {
36655
36841
  maxEntries: 16384,
36656
36842
  maxSourceBytes: 64 * 1024 * 1024
36657
36843
  };
36844
+ var FORK_SOURCE_METADATA_MAX_BYTES = 64 * 1024 * 1024;
36658
36845
  async function readOwnedSessionHeader(snapshot) {
36659
36846
  const handle = await openFile(snapshot.journalPath, "r");
36660
36847
  let capturedHeader;
@@ -37182,6 +37369,19 @@ var SessionManager = class _SessionManager {
37182
37369
  readSourceHistory(read2) {
37183
37370
  return this._runHistoryRead(this._bindHistorySource((index, source, query) => createSessionHistoryReadScope(index, source, query, "source")), read2);
37184
37371
  }
37372
+ /** Read the owner-maintained own-spend projection without hydrating the source. */
37373
+ async readOwnUsageSummary() {
37374
+ this._assertMutable();
37375
+ if (!this.supportsCapturedHistoryReads())
37376
+ throw new Error("Own usage projection requires an owned native source");
37377
+ const state = this.writeState;
37378
+ return this._enqueue(state, 0, async () => {
37379
+ await state.owner.flush();
37380
+ const snapshot = state.owner.getSnapshot();
37381
+ await this._acknowledgedHistory(state, snapshot);
37382
+ return state.history.currentSourceUsage(snapshot);
37383
+ });
37384
+ }
37185
37385
  /** Complete bounded structured task reduction on one captured native branch. */
37186
37386
  async readTaskState(limits = {}) {
37187
37387
  const captured = taskStateReadLimits(limits);
@@ -38921,6 +39121,8 @@ var SessionManager = class _SessionManager {
38921
39121
  }
38922
39122
  async _captureForkInput(target, options) {
38923
39123
  const limits = { ...options.limits ?? DEFAULT_MANAGER_HISTORY_LIMITS };
39124
+ if (!Number.isSafeInteger(limits.maxEntries) || limits.maxEntries <= 0 || !Number.isSafeInteger(limits.maxSourceBytes) || limits.maxSourceBytes <= 0)
39125
+ throw new Error("Invalid fork source limits");
38924
39126
  const sourceFile = this.sessionFile;
38925
39127
  const header = JSON.parse(stringifyBoundedJson(this.getHeader(), limits.maxSourceBytes));
38926
39128
  const settings = {
@@ -39032,32 +39234,143 @@ var SessionManager = class _SessionManager {
39032
39234
  if (headerBytes >= limits.maxSourceBytes)
39033
39235
  throw new Error("Fork source byte budget exceeded");
39034
39236
  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");
39237
+ const metadata = /* @__PURE__ */ new Map();
39238
+ let metadataBytes = 0;
39239
+ let after = 0;
39240
+ for (; ; ) {
39241
+ const page2 = await history.page(after, 128);
39242
+ if (page2.indexedThrough < history.source.sourceSequence)
39243
+ throw new Error("Captured fork history has incomplete index coverage");
39244
+ for (const reference of page2.events) {
39245
+ const source = {
39246
+ id: reference.id,
39247
+ parentId: reference.parentId,
39248
+ kind: reference.kind,
39249
+ sequence: reference.sequence,
39250
+ revision: reference.revision,
39251
+ locator: { ...reference.locator },
39252
+ retention: reference.retention,
39253
+ qualification: reference.qualification
39254
+ };
39255
+ metadataBytes += Buffer.byteLength(JSON.stringify(source)) + 1;
39256
+ if (metadataBytes > FORK_SOURCE_METADATA_MAX_BYTES)
39257
+ throw new Error("Fork source metadata byte budget exceeded");
39258
+ metadata.set(source.id, source);
39259
+ }
39260
+ if (page2.nextAfter === null)
39261
+ break;
39262
+ after = page2.nextAfter;
39263
+ }
39264
+ const hasEpoch = [...metadata.values()].some((entry) => entry.kind === "compaction" && entry.qualification === "native-context-epoch");
39265
+ const loaded = /* @__PURE__ */ new Map();
39266
+ let sourceBytes = headerBytes;
39267
+ const load = async (id) => {
39268
+ const existing = loaded.get(id);
39269
+ if (existing)
39270
+ return existing;
39271
+ const reference = metadata.get(id);
39272
+ if (!reference)
39273
+ throw new Error("Fork selected source is unavailable");
39274
+ if (loaded.size >= limits.maxEntries)
39275
+ throw new Error("Fork entry budget exceeded");
39276
+ const remaining = limits.maxSourceBytes - sourceBytes;
39277
+ if (reference.locator.length > remaining)
39278
+ throw new Error("Fork source byte budget exceeded");
39279
+ const hydrated = await history.hydrateEntry(id, remaining);
39280
+ if (!hydrated)
39281
+ throw new Error("Fork selected source is unavailable");
39282
+ const entry = withEntryRetention(hydrated.entry, hydrated.source.retention, hydrated.source.qualification);
39283
+ loaded.set(id, entry);
39284
+ metadata.set(id, captureEpochCopyEntry(entry, hydrated.source));
39285
+ sourceBytes += reference.locator.length;
39286
+ return entry;
39287
+ };
39288
+ if ("entryId" in target && !metadata.has(target.entryId))
39289
+ throw new Error("Invalid entry ID for forking");
39290
+ const selected = "entryId" in target ? await load(target.entryId) : void 0;
39291
+ if ("entryId" in target && target.position === "before" && (selected?.type !== "message" || selected.message.role !== "user"))
39292
+ throw new Error("Invalid entry ID for forking");
39293
+ const leafId = "entryId" in target ? target.position === "at" ? selected.id : selected.parentId : target.leafId;
39294
+ const path6 = [];
39295
+ let page = await history.parentPathFrom(leafId);
39296
+ for (; ; ) {
39297
+ if (page.totalEntries > limits.maxEntries)
39298
+ throw new Error("Fork entry budget exceeded");
39299
+ for (const reference of page.events)
39300
+ path6.push(await load(reference.id));
39301
+ if (!page.nextCursor)
39302
+ break;
39303
+ page = await history.parentPathFrom(leafId, { cursor: page.nextCursor });
39304
+ }
39305
+ const copied = path6.filter((entry) => entry.type !== "label");
39306
+ const ids = new Set(copied.map((entry) => entry.id));
39307
+ if (hasEpoch) {
39308
+ for (const entry of copied) {
39309
+ if (entry.type !== "message")
39310
+ continue;
39311
+ if (entry.execution && "invocationId" in entry.execution)
39312
+ ids.add(entry.execution.invocationId);
39313
+ 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;
39314
+ if (!updateTarget)
39315
+ continue;
39316
+ let after2 = 0;
39317
+ for (; ; ) {
39318
+ const updates = await history.sourceContextUpdates(updateTarget, after2);
39319
+ if (updates.indexedThrough < history.source.sourceSequence)
39320
+ throw new Error("Captured fork updates have incomplete index coverage");
39321
+ for (const reference of updates.events)
39322
+ ids.add(reference.id);
39323
+ if (updates.nextAfter === null)
39324
+ break;
39325
+ after2 = updates.nextAfter;
39326
+ }
39327
+ }
39328
+ for (const id of ids) {
39329
+ const reference = metadata.get(id);
39330
+ if (!reference)
39331
+ throw new Error("Fork related source is unavailable");
39332
+ if (reference.parentId !== null)
39333
+ ids.add(reference.parentId);
39334
+ }
39335
+ for (const id of ids)
39336
+ await load(id);
39337
+ } else {
39338
+ for (const entry of copied) {
39339
+ if (entry.type !== "message" || entry.message.role !== "assistant")
39340
+ continue;
39341
+ const latest = await history.sourceAssistantUsage(entry.id);
39342
+ if (latest)
39343
+ await load(latest.id);
39344
+ }
39345
+ }
39346
+ for (const id of ids) {
39347
+ const label = await history.sourceLabel(id);
39348
+ if (label)
39349
+ await load(label.id);
39350
+ }
39351
+ const entries = [...loaded.values()].sort((left, right) => metadata.get(left.id).sequence - metadata.get(right.id).sequence);
39042
39352
  if (!hasEpoch)
39043
39353
  applyChildUsageAttributions(entries);
39044
- return finish(entries, history, hasEpoch ? {
39354
+ const epochCopy = hasEpoch ? {
39045
39355
  sessionId: history.source.sessionId,
39046
39356
  sessionFile: history.source.sessionFile,
39047
39357
  through: history.source.sourceSequence,
39048
- entries: sourceEntries,
39358
+ entries: [...metadata.values()],
39049
39359
  retained: false
39050
- } : void 0);
39360
+ } : void 0;
39361
+ if (epochCopy)
39362
+ stringifyBoundedJson(epochCopy, FORK_SOURCE_METADATA_MAX_BYTES);
39363
+ return finish(entries, history, epochCopy);
39051
39364
  });
39052
39365
  }
39053
- async _rebuildCopiedEpoch(copied, limits) {
39366
+ async _rebuildCopiedEpoch(copied, limits, metadataMaxBytes = limits.maxSourceBytes) {
39054
39367
  if (!copied.entries.some((entry) => entry.kind === "compaction" && entry.qualification === "native-context-epoch"))
39055
39368
  return;
39056
39369
  if (!this.supportsCapturedHistoryReads())
39057
39370
  throw new Error("Copied context epochs require an owned persistent source");
39058
39371
  const sink = this.bindCompactionSink(limits);
39059
39372
  await this._runHistoryRead({ ...sink, readHistory: (read2) => sink[readCopiedEpochSource](read2) }, async (history) => {
39060
- const rebuilt = await rebuildCopiedContextEpoch(history, copied, limits);
39373
+ const rebuilt = await rebuildCopiedContextEpoch(history, copied, limits, metadataMaxBytes);
39061
39374
  if (rebuilt)
39062
39375
  await sink[appendContextEpoch](rebuilt.checkpoint, rebuilt.tokensBefore, rebuilt.summary);
39063
39376
  });
@@ -39094,7 +39407,7 @@ var SessionManager = class _SessionManager {
39094
39407
  if (input.epochCopy) {
39095
39408
  try {
39096
39409
  await next.branchTo(input.leafId ?? null);
39097
- await next._rebuildCopiedEpoch(input.epochCopy, input.limits);
39410
+ await next._rebuildCopiedEpoch(input.epochCopy, input.limits, FORK_SOURCE_METADATA_MAX_BYTES);
39098
39411
  } catch (error) {
39099
39412
  try {
39100
39413
  await next.close();
@@ -39487,13 +39800,6 @@ function parseBoundedSessionEntries(text2, maxEntries) {
39487
39800
  }
39488
39801
  return parseSessionEntries(text2);
39489
39802
  }
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
39803
  async function readExportHistory(inputPath, limits) {
39498
39804
  limits = { ...limits };
39499
39805
  const captured = await readSessionHistoryImage(inputPath, limits.maxSourceBytes);
@@ -42810,6 +43116,99 @@ ${instructions}`;
42810
43116
  // dist/core/context-tree.js
42811
43117
  import { existsSync as existsSync14, opendirSync, statSync as statSync6 } from "node:fs";
42812
43118
  import { basename as basename6, join as join20 } from "node:path";
43119
+
43120
+ // dist/core/request-usage.js
43121
+ function emptyRequestUsageTotals() {
43122
+ return {
43123
+ attempts: 0,
43124
+ settledAttempts: 0,
43125
+ partialUsageAttempts: 0,
43126
+ missingUsageAttempts: 0,
43127
+ unsettledAttempts: 0,
43128
+ unpricedAttempts: 0,
43129
+ input: 0,
43130
+ inputTotal: 0,
43131
+ output: 0,
43132
+ cacheRead: 0,
43133
+ cacheWrite: 0,
43134
+ processedTokens: 0,
43135
+ catalogEstimateUsd: 0
43136
+ };
43137
+ }
43138
+ function addRequestUsageTotals(total, usage) {
43139
+ for (const field of Object.keys(total))
43140
+ total[field] += usage[field];
43141
+ }
43142
+ function purpose(event) {
43143
+ if (event.purpose === "native-control" && event.purposeDetail === "daemon-status")
43144
+ return "status";
43145
+ if (event.purpose === "summary" && (event.purposeDetail === "compaction" || event.purposeDetail === "compaction-turn-prefix"))
43146
+ return "compaction";
43147
+ return event.purpose;
43148
+ }
43149
+ function inputTotal(usage) {
43150
+ if (usage.inputTotal !== void 0)
43151
+ return usage.inputTotal;
43152
+ if (usage.input !== void 0 && usage.cacheRead !== void 0 && usage.cacheWrite !== void 0)
43153
+ return usage.input + usage.cacheRead + usage.cacheWrite;
43154
+ if (usage.totalTokens !== void 0 && usage.output !== void 0)
43155
+ return usage.totalTokens - usage.output;
43156
+ return void 0;
43157
+ }
43158
+ var RequestUsageAccumulator = class {
43159
+ sessionId;
43160
+ attempts = /* @__PURE__ */ new Map();
43161
+ constructor(sessionId) {
43162
+ this.sessionId = sessionId;
43163
+ }
43164
+ add(event) {
43165
+ if (event.source.sessionId !== this.sessionId || event.purpose === "native-control" && event.purposeDetail === "input-token-count")
43166
+ return;
43167
+ const previous = this.attempts.get(event.attemptId);
43168
+ if (event.type === "attempt_admitted" && previous)
43169
+ return;
43170
+ const totals = emptyRequestUsageTotals();
43171
+ totals.attempts = 1;
43172
+ if (event.type === "attempt_admitted") {
43173
+ totals.unsettledAttempts = 1;
43174
+ } else {
43175
+ totals.settledAttempts = 1;
43176
+ const { usage, usageCompleteness } = event.receipt;
43177
+ const incompleteBuckets = [usage.input, usage.output, usage.cacheRead, usage.cacheWrite].some((value) => value === void 0);
43178
+ totals.partialUsageAttempts = usageCompleteness === "partial" || usageCompleteness !== "none" && incompleteBuckets ? 1 : 0;
43179
+ totals.missingUsageAttempts = usageCompleteness === "none" ? 1 : 0;
43180
+ totals.input = usage.input ?? 0;
43181
+ totals.inputTotal = inputTotal(usage) ?? (usage.input ?? 0) + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);
43182
+ totals.output = usage.output ?? 0;
43183
+ totals.cacheRead = usage.cacheRead ?? 0;
43184
+ totals.cacheWrite = usage.cacheWrite ?? 0;
43185
+ const input = inputTotal(usage);
43186
+ totals.processedTokens = input !== void 0 && usage.output !== void 0 ? input + usage.output : usage.totalTokens ?? totals.inputTotal + totals.output;
43187
+ const pricing = event.modelContract.pricing;
43188
+ const rates = pricing.status !== "unavailable" && pricing.currency === "USD" && pricing.unit === "million-tokens" ? pricing.catalogRates : void 0;
43189
+ if (rates && usage.input !== void 0 && usage.output !== void 0 && usage.cacheRead !== void 0 && usage.cacheWrite !== void 0) {
43190
+ totals.catalogEstimateUsd = (usage.input * rates.input + usage.output * rates.output + usage.cacheRead * rates.cacheRead + usage.cacheWrite * rates.cacheWrite) / 1e6;
43191
+ } else {
43192
+ totals.unpricedAttempts = 1;
43193
+ }
43194
+ }
43195
+ this.attempts.set(event.attemptId, { purpose: purpose(event), totals });
43196
+ }
43197
+ finish() {
43198
+ if (this.attempts.size === 0)
43199
+ return void 0;
43200
+ const result = { sessionId: this.sessionId, byPurpose: {}, total: emptyRequestUsageTotals() };
43201
+ for (const attempt of this.attempts.values()) {
43202
+ const bucket = result.byPurpose[attempt.purpose] ?? emptyRequestUsageTotals();
43203
+ result.byPurpose[attempt.purpose] = bucket;
43204
+ addRequestUsageTotals(bucket, attempt.totals);
43205
+ addRequestUsageTotals(result.total, attempt.totals);
43206
+ }
43207
+ return result;
43208
+ }
43209
+ };
43210
+
43211
+ // dist/core/context-tree.js
42813
43212
  var ContextTreeLimitError = class extends Error {
42814
43213
  };
42815
43214
  var ContextTreeRequest = class {
@@ -42903,6 +43302,11 @@ function computeOwnAndTotalUsage(branch, allEntries) {
42903
43302
  }
42904
43303
  function readResidentContextTreeUsage(manager, limits = { maxEntries: 16384, maxSourceBytes: 64 * 1024 * 1024 }, availabilityMaxSourceBytes) {
42905
43304
  const snapshot = manager.materializeResidentHistory(limits);
43305
+ const receipts = new RequestUsageAccumulator(manager.getSessionId());
43306
+ for (const entry of snapshot.entries)
43307
+ if (entry.type === "request")
43308
+ receipts.add(entry.request);
43309
+ const ownRequestUsage = receipts.finish();
42906
43310
  const branch = branchEntries(snapshot.entries, snapshot.leafId, availabilityMaxSourceBytes !== void 0);
42907
43311
  if (availabilityMaxSourceBytes !== void 0) {
42908
43312
  if (!Number.isSafeInteger(availabilityMaxSourceBytes) || availabilityMaxSourceBytes <= 0)
@@ -42916,19 +43320,67 @@ function readResidentContextTreeUsage(manager, limits = { maxEntries: 16384, max
42916
43320
  }
42917
43321
  return {
42918
43322
  ...computeOwnAndTotalUsage(branch, snapshot.entries),
43323
+ ...ownRequestUsage ? { ownRequestUsage } : {},
42919
43324
  ...availabilityMaxSourceBytes === void 0 ? {} : { hasPostCompactionUsage: hasPostCompactionUsage(branch) }
42920
43325
  };
42921
43326
  }
43327
+ function isContextTreeUsageReference(reference) {
43328
+ return reference.kind === "message" && reference.authority === "assistant" || reference.kind === "compaction" || reference.kind === "branch_summary" || reference.kind === "child_usage_attributed";
43329
+ }
42922
43330
  async function readContextTreeUsage(manager, limits = { maxEntries: 16384, maxSourceBytes: 64 * 1024 * 1024 }, request, availabilityMaxSourceBytes) {
42923
43331
  if (!manager.supportsCapturedHistoryReads())
42924
43332
  return void 0;
42925
43333
  const sourceLimits = request?.limits ?? limits;
42926
43334
  const capturedLimits = { maxEntries: sourceLimits.maxEntries, maxSourceBytes: sourceLimits.maxSourceBytes };
43335
+ if (!Object.values(capturedLimits).every((value) => Number.isSafeInteger(value) && value > 0))
43336
+ throw new Error("Invalid history materialization limits");
42927
43337
  return manager.readSourceHistory((history) => {
42928
43338
  request?.retainMetadata(history.source);
42929
43339
  const reduce = async () => {
42930
- const materialized = await history.materialize(capturedLimits);
42931
- const allEntries = materialized.entries.map(({ entry }) => entry);
43340
+ const allEntries = [];
43341
+ let receipts = new RequestUsageAccumulator(history.source.sessionId);
43342
+ let requestEntries = 0;
43343
+ let requestBytes = 0;
43344
+ let sourceBytes = 0;
43345
+ let after = 0;
43346
+ for (; ; ) {
43347
+ const page = await history.page(after);
43348
+ if (page.indexedThrough < history.source.sourceSequence)
43349
+ throw new Error("Captured history has incomplete index coverage");
43350
+ for (const reference of page.events) {
43351
+ if (reference.kind === "request" && receipts) {
43352
+ requestEntries++;
43353
+ requestBytes += reference.locator.length;
43354
+ if (requestEntries > capturedLimits.maxEntries || requestBytes > capturedLimits.maxSourceBytes) {
43355
+ receipts = void 0;
43356
+ } else {
43357
+ try {
43358
+ const hydrated2 = await history.hydrateEntry(reference.id, reference.locator.length);
43359
+ if (hydrated2?.entry.type !== "request")
43360
+ receipts = void 0;
43361
+ else
43362
+ receipts.add(hydrated2.entry.request);
43363
+ } catch {
43364
+ receipts = void 0;
43365
+ }
43366
+ }
43367
+ }
43368
+ if (!isContextTreeUsageReference(reference))
43369
+ continue;
43370
+ if (allEntries.length >= capturedLimits.maxEntries)
43371
+ throw new Error("History entry budget exceeded");
43372
+ if (sourceBytes + reference.locator.length > capturedLimits.maxSourceBytes)
43373
+ throw new Error("History source byte budget exceeded");
43374
+ const hydrated = await history.hydrateEntry(reference.id, capturedLimits.maxSourceBytes - sourceBytes);
43375
+ if (!hydrated)
43376
+ throw new Error("Context-tree usage entry source is unavailable");
43377
+ allEntries.push(hydrated.entry);
43378
+ sourceBytes += reference.locator.length;
43379
+ }
43380
+ if (page.nextAfter === null)
43381
+ break;
43382
+ after = page.nextAfter;
43383
+ }
42932
43384
  applyChildUsageAttributions(allEntries);
42933
43385
  const byId = new Map(allEntries.map((entry) => [entry.id, entry]));
42934
43386
  const branch = [];
@@ -42936,6 +43388,8 @@ async function readContextTreeUsage(manager, limits = { maxEntries: 16384, maxSo
42936
43388
  do {
42937
43389
  const page = await history.parentPath({ cursor });
42938
43390
  for (const reference of page.events) {
43391
+ if (!isContextTreeUsageReference(reference))
43392
+ continue;
42939
43393
  const entry = byId.get(reference.id);
42940
43394
  if (!entry)
42941
43395
  throw new Error("Context-tree parent-path entry source is unavailable");
@@ -42962,8 +43416,10 @@ async function readContextTreeUsage(manager, limits = { maxEntries: 16384, maxSo
42962
43416
  available = calculateContextTokens(assistant.message.usage) > 0;
42963
43417
  }
42964
43418
  }
43419
+ const ownRequestUsage = receipts?.finish();
42965
43420
  const usage = {
42966
43421
  ...computeOwnAndTotalUsage(branch, allEntries),
43422
+ ...ownRequestUsage ? { ownRequestUsage } : {},
42967
43423
  ...available === void 0 ? {} : { hasPostCompactionUsage: available }
42968
43424
  };
42969
43425
  request?.retainMetadata(usage);
@@ -42998,7 +43454,7 @@ function computeContextUsageFromEntries(allEntries, branch, contextWindow) {
42998
43454
  if (!hasPostCompactionUsage(branch)) {
42999
43455
  return { tokens: null, contextWindow, percent: null };
43000
43456
  }
43001
- const estimate = estimateContextTokens(buildSessionContext(allEntries).messages);
43457
+ const estimate = estimateContextTokens(buildSessionContext(allEntries, branch.at(-1)?.id ?? null).messages);
43002
43458
  if (estimate.tokens <= 0) {
43003
43459
  return void 0;
43004
43460
  }
@@ -43125,10 +43581,77 @@ function listChildSessionDirs(rlmSessionDir, request) {
43125
43581
  });
43126
43582
  return { paths, bytes };
43127
43583
  }
43584
+ async function readContextTreeProjectionFromDisk(sessionFile, request) {
43585
+ const entries = [];
43586
+ const hiddenParents = /* @__PURE__ */ new Map();
43587
+ let leafId = null;
43588
+ let hasHeader = false;
43589
+ let receipts;
43590
+ let requestEntries = 0;
43591
+ let requestBytes = 0;
43592
+ let sourceBytes = 0;
43593
+ let metadataBytes = 0;
43594
+ try {
43595
+ await readCapturedSessionJournal(sessionFile, (record2) => {
43596
+ const value = record2.entry;
43597
+ if (!value || typeof value !== "object" || !("type" in value) || typeof value.type !== "string")
43598
+ throw new Error("Invalid session journal entry");
43599
+ const entry = value;
43600
+ if (!hasHeader) {
43601
+ if (entry.type !== "session" || typeof entry.id !== "string")
43602
+ throw new Error("Session source has no valid header");
43603
+ hasHeader = true;
43604
+ receipts = new RequestUsageAccumulator(entry.id);
43605
+ }
43606
+ if (entry.type === "request" && receipts) {
43607
+ requestEntries++;
43608
+ requestBytes += record2.source?.locator.length ?? Buffer.byteLength(record2.json) + 1;
43609
+ if (requestEntries > request.limits.maxEntries || requestBytes > request.limits.maxSourceBytes)
43610
+ receipts = void 0;
43611
+ else
43612
+ receipts.add(entry.request);
43613
+ }
43614
+ if (entry.type !== "session")
43615
+ leafId = entry.id;
43616
+ if (entry.type === "request" || entry.type === "tool_intent") {
43617
+ metadataBytes += request.retainMetadata([entry.id, entry.parentId]);
43618
+ hiddenParents.set(entry.id, entry.parentId);
43619
+ return;
43620
+ }
43621
+ const bytes = record2.source?.locator.length ?? Buffer.byteLength(record2.json) + 1;
43622
+ if (sourceBytes + bytes > request.limits.maxSourceBytes)
43623
+ throw new ContextTreeLimitError("Context tree source byte budget exceeded");
43624
+ sourceBytes += bytes;
43625
+ if (entry.type === "session")
43626
+ return;
43627
+ if (entries.length >= request.limits.maxEntries)
43628
+ throw new ContextTreeLimitError("Context tree entry budget exceeded");
43629
+ entries.push(entry);
43630
+ });
43631
+ const visibleParent = (id) => {
43632
+ let remaining = hiddenParents.size;
43633
+ while (id !== null && hiddenParents.has(id)) {
43634
+ if (remaining-- === 0)
43635
+ throw new Error("Parent path lineage is unresolved");
43636
+ id = hiddenParents.get(id);
43637
+ }
43638
+ return id;
43639
+ };
43640
+ for (const entry of entries)
43641
+ entry.parentId = visibleParent(entry.parentId);
43642
+ const hasSourceLeaf = leafId !== null;
43643
+ leafId = visibleParent(leafId);
43644
+ applyChildUsageAttributions(entries);
43645
+ const ownRequestUsage = receipts?.finish();
43646
+ return { entries, leafId, hasSourceLeaf, ...ownRequestUsage ? { ownRequestUsage } : {} };
43647
+ } finally {
43648
+ request.releaseMetadata(metadataBytes);
43649
+ }
43650
+ }
43128
43651
  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) {
43652
+ const { entries: allEntries, leafId, hasSourceLeaf, ownRequestUsage } = await readContextTreeProjectionFromDisk(sessionFile, request);
43653
+ const branch = branchEntries(allEntries, leafId);
43654
+ if (branch.length === 0 && !hasSourceLeaf) {
43132
43655
  return void 0;
43133
43656
  }
43134
43657
  const { ownUsage, totalUsage } = computeOwnAndTotalUsage(branch, allEntries);
@@ -43157,9 +43680,10 @@ async function readContextTreeChildNodeFromDisk(childSessionDir, sessionFile, re
43157
43680
  model,
43158
43681
  ownUsage,
43159
43682
  totalUsage,
43683
+ ...ownRequestUsage ? { ownRequestUsage } : {},
43160
43684
  contextUsage: computeContextUsageFromEntries(allEntries, branch, contextWindow)
43161
43685
  };
43162
- request.retainMetadata(identity ? { model, ownUsage, totalUsage, contextUsage: metadata.contextUsage } : metadata);
43686
+ request.retainMetadata(identity ? { model, ownUsage, totalUsage, ownRequestUsage, contextUsage: metadata.contextUsage } : metadata);
43163
43687
  return { ...metadata, children: [] };
43164
43688
  }
43165
43689
  async function loadContextTreeChildFromDisk(childSessionDir, resolveContextWindow, limits = {}, identity) {
@@ -45559,7 +46083,7 @@ async function loadExtensionModule(extensionPath) {
45559
46083
  // (file-path aliases would load a second, divergent copy of each package).
45560
46084
  // Also disable tryNative so jiti handles ALL imports (not just the entry point)
45561
46085
  // 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 } : {
46086
+ ...isBunBinary || isBundledCli ? { virtualModules: (await import("./bundled-modules-WCGPZI2H.js")).VIRTUAL_MODULES, tryNative: false } : {
45563
46087
  alias: getAliases(),
45564
46088
  virtualModules: {
45565
46089
  "@ponythewhite/base-context-ai": src_exports,
@@ -47298,6 +47822,15 @@ function formatHarnessStateForPrompt(state, options = {}) {
47298
47822
  includeIpythonExamples ? "Call contract: read each installed Python skill's SKILL.md and call its documented module function in the Python REPL; do not assume a `.run` entrypoint. Use `<skill_import> ...` in shell when a CLI exists. Continual harness skill entries are Python REPL skills with an explicit Python `reference` and `arguments` contract. Spawn a continual harness subagent spec by composing a concise task prompt and calling `handle = await rlm('sub-task')`; admission returns immediately with `rlm_child_id`, `name`, `session_dir`, and `model`, never the child's answer. Results arrive only through explicit `agent_message` replies or files; children reply with `await agent_message.send(message, receiver_role='parent')`. Use `await rlm.list_subagents()` to recover direct child handles and `await agent_message.send(..., receiver_role='child', receiver_name=handle.name)` for follow-ups. Do not invent wrappers such as `call_skill(...)`, `run_subagent(...)`, or named subagent registries." : options.includeShellExamples ? "Call contract: use installed skills as shell commands when available (for example `<skill_import> ...`). Continual harness entries are routing/context hints only in sessions without the Python REPL; do not use Python `await`, `asyncio`, or `rlm` examples unless the prompt also documents a Python kernel." : "Call contract: continual harness entries are routing/context hints only in sessions without the Python REPL or shell access; do not use Python `await`, `asyncio`, `rlm`, or shell skill commands unless the prompt also documents those interfaces.",
47299
47823
  ""
47300
47824
  ];
47825
+ if (options.section === "instructions") {
47826
+ lines.push("The latest Continual Harness Snapshot in the conversation is the current compact state. It supersedes all earlier snapshots, including removed entries and advice. Do not revive deleted or rolled-back instructions from older snapshots or summaries.");
47827
+ if (options.errorFixSelection?.enabled && includeIpythonExamples)
47828
+ lines.push("", ERROR_FIX_CREATION_GUIDANCE);
47829
+ return lines.join("\n").trim();
47830
+ }
47831
+ if (options.section === "entries") {
47832
+ lines.splice(0, lines.length, "# Continual Harness Snapshot", "This is the complete current compact harness overview and selected error-fix advice. It supersedes all earlier snapshots, including deletions, rollbacks, and empty state. Treat entries as routing/context advice; system instructions and the current task take precedence. Earlier snapshots and summaries are not current harness advice.", "");
47833
+ }
47301
47834
  let totalEntries = 0;
47302
47835
  for (const kind of Object.keys(state.entries)) {
47303
47836
  const entries = Object.values(state.entries[kind]).filter((entry) => !isErrorFixMemory(entry)).sort((a, b2) => [a.path, a.title, a.id].join("\0").localeCompare([b2.path, b2.title, b2.id].join("\0")));
@@ -47322,7 +47855,7 @@ function formatHarnessStateForPrompt(state, options = {}) {
47322
47855
  lines.push("No saved harness entries yet.", "");
47323
47856
  }
47324
47857
  if (options.errorFixSelection?.enabled) {
47325
- if (includeIpythonExamples)
47858
+ if (includeIpythonExamples && options.section !== "entries")
47326
47859
  lines.push("", ERROR_FIX_CREATION_GUIDANCE);
47327
47860
  const advice = selectErrorFixAdvice(state, options.errorFixSelection);
47328
47861
  if (advice)
@@ -48316,6 +48849,9 @@ var DEFAULT_FORK_MESSAGE_LIMITS = Object.freeze({
48316
48849
  async function readUserMessagesForForking(manager, limits = DEFAULT_FORK_MESSAGE_LIMITS) {
48317
48850
  const capturedLimits = { ...limits };
48318
48851
  const entries = manager.supportsCapturedHistoryReads() ? (await manager.materializeSourceHistory(capturedLimits)).entries.map(({ entry }) => entry) : manager.materializeResidentHistory(capturedLimits).entries;
48852
+ return projectUserMessages(entries);
48853
+ }
48854
+ function projectUserMessages(entries) {
48319
48855
  const result = [];
48320
48856
  for (const entry of entries) {
48321
48857
  if (entry.type !== "message" || entry.message.role !== "user")
@@ -48332,6 +48868,40 @@ async function readUserMessagesForForking(manager, limits = DEFAULT_FORK_MESSAGE
48332
48868
  }
48333
48869
  return result;
48334
48870
  }
48871
+ async function readVisibleUserMessagesForForking(manager, limits = DEFAULT_FORK_MESSAGE_LIMITS) {
48872
+ const { maxEntries, maxSourceBytes } = limits;
48873
+ if (!Number.isSafeInteger(maxEntries) || maxEntries <= 0 || !Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0)
48874
+ throw new Error("Invalid history materialization limits");
48875
+ if (!manager.supportsCapturedHistoryReads())
48876
+ return readUserMessagesForForking(manager, { maxEntries, maxSourceBytes });
48877
+ return manager.readSourceHistory(async (history) => {
48878
+ const entries = [];
48879
+ let sourceBytes = 0;
48880
+ let after = 0;
48881
+ for (; ; ) {
48882
+ const page = await history.page(after);
48883
+ if (page.indexedThrough < history.source.sourceSequence)
48884
+ throw new Error("Captured history has incomplete index coverage");
48885
+ for (const reference of page.events) {
48886
+ if (reference.kind !== "message" || reference.authority === "assistant" || reference.authority === "runtime")
48887
+ continue;
48888
+ if (entries.length >= maxEntries)
48889
+ throw new Error("History entry budget exceeded");
48890
+ if (sourceBytes + reference.locator.length > maxSourceBytes)
48891
+ throw new Error("History source byte budget exceeded");
48892
+ const hydrated = await history.hydrateEntry(reference.id, maxSourceBytes - sourceBytes);
48893
+ if (!hydrated)
48894
+ throw new Error("Fork message source is unavailable");
48895
+ sourceBytes += reference.locator.length;
48896
+ entries.push(hydrated.entry);
48897
+ }
48898
+ if (page.nextAfter === null)
48899
+ break;
48900
+ after = page.nextAfter;
48901
+ }
48902
+ return projectUserMessages(entries);
48903
+ });
48904
+ }
48335
48905
 
48336
48906
  // dist/core/session-jsonl-export.js
48337
48907
  import { mkdir as mkdir3, open as open4, unlink } from "node:fs/promises";
@@ -49394,6 +49964,8 @@ var IMPLEMENTATION_CONTRACT = [
49394
49964
  "Preserve earlier requirements unless later instructions replace them. Apply stated eligibility, priorities, and decision order literally, even when a different policy seems simpler or more sensible; reevaluate later decisions when earlier actions change their inputs.",
49395
49965
  "The required commands must implement the stated workflow from its stated starting state, without development-only state or extra steps.",
49396
49966
  "During tool-based inspection of large datasets, request schemas or small samples. Process full inputs in local code instead of printing entire datasets into the conversation.",
49967
+ "Read long text in bounded pages; use a character limit as well as a line limit when lines are long. If output is truncated, page the retained result instead of repeating the original command or printing the whole file again.",
49968
+ "Batch nonurgent child updates. Send results, blockers, or decisions that need action rather than acknowledgements and repeated status requests. Continue independent work while children run, and report meaningful milestones to the user.",
49397
49969
  "Do not repeat a successful check without a concrete reason, such as changed input, an edit, or an observed failure.",
49398
49970
  "Choose algorithms whose time and memory costs fit the stated input limits.",
49399
49971
  "For constrained search, prune known-impossible partial states before expanding them; do not postpone all feasibility checks until completed candidates.",
@@ -49457,7 +50029,7 @@ ${childDoctrine}`;
49457
50029
  if (harnessState) {
49458
50030
  prompt2 += `
49459
50031
 
49460
- ${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill, errorFixSelection: options.errorFixSelection })}`;
50032
+ ${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill, errorFixSelection: options.errorFixSelection, section: options.harnessSection })}`;
49461
50033
  }
49462
50034
  if (genericMcpSection) {
49463
50035
  prompt2 += `
@@ -49496,7 +50068,7 @@ ${buildSubagentGuidance({
49496
50068
  if (harnessState) {
49497
50069
  prompt += `
49498
50070
 
49499
- ${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill, errorFixSelection: options.errorFixSelection })}`;
50071
+ ${formatHarnessStateForPrompt(harnessState, { includeIpythonExamples: hasIpython, includeShellExamples: hasBash, includeRefineExamples: hasIpython && hasRefineSkill, errorFixSelection: options.errorFixSelection, section: options.harnessSection })}`;
49500
50072
  }
49501
50073
  if (genericMcpSection) {
49502
50074
  prompt += `
@@ -58610,6 +59182,7 @@ var StaleCompactionOwnerError = class extends Error {
58610
59182
  function createPostCompactionContinuationSettlement(resume) {
58611
59183
  return { ...createAgentMessageDeferred(), resume, settled: false };
58612
59184
  }
59185
+ var RLM_PARENT_USAGE_CUSTOM_TYPE = "rlm_parent_usage";
58613
59186
  var KERNEL_STATE_LISTING_TIMEOUT_MS = 5e3;
58614
59187
  var RLM_MAX_DEPTH_STATE_CUSTOM_TYPE = "rlm_max_depth_state";
58615
59188
  function noopRlmChildAbort() {
@@ -58847,6 +59420,8 @@ var AgentSession = class _AgentSession {
58847
59420
  // Kept alive for retained children so nested updates (e.g. a grandchild cancel)
58848
59421
  // still forward to root; torn down when the retained child is disposed.
58849
59422
  _rlmChildUnsubscribes = /* @__PURE__ */ new Map();
59423
+ _rlmChildUsageSources = /* @__PURE__ */ new Map();
59424
+ _rlmParentUsageAttribution;
58850
59425
  /** Latest recap for this session, written by the daemon summarizer; read by a parent to label its child snapshots. */
58851
59426
  _currentRecap;
58852
59427
  _initialGoal;
@@ -58962,10 +59537,12 @@ var AgentSession = class _AgentSession {
58962
59537
  await this._goalResumeOperation;
58963
59538
  await this._waitForAgentEventsBeforeContext();
58964
59539
  await this._waitForChildUsageWrites();
59540
+ const assertHarnessSourceCurrent = await this._appendHarnessSnapshotIfChanged();
58965
59541
  await this.sessionManager.flushNow();
59542
+ assertHarnessSourceCurrent();
58966
59543
  if (!this.sessionManager.isPersisted()) {
58967
59544
  if (!this._compactionSetupFailure)
58968
- return;
59545
+ return { messages: this.agent.state.messages, adoptMessages: true };
58969
59546
  const rebuilt = await readSessionBootstrap(this.sessionManager, this.settingsManager.getCanonicalContextLimits());
58970
59547
  this._compactionSetupFailure = void 0;
58971
59548
  return { messages: rebuilt.context.messages, adoptMessages: true };
@@ -59019,7 +59596,7 @@ var AgentSession = class _AgentSession {
59019
59596
  const epochContext = getCanonicalEpochContext(messages);
59020
59597
  if (epochContext)
59021
59598
  this._contextMode = epochContext.mode;
59022
- const unbudgetedPublic = !contextEpochsEnabled && Boolean(epochContext?.toolContinuations?.length || epochContext?.taskFrameRebased || epochContext?.checkpoint);
59599
+ const unbudgetedPublic = !contextEpochsEnabled && Boolean(epochContext?.toolContinuations?.length || epochContext?.taskFrameRebased || epochContext?.checkpoint || getCanonicalViewSelectionSource(messages)?.recoveryContractRequested);
59023
59600
  const nativeSkills = Boolean(contextEpochsEnabled || epochContext?.checkpoint || unbudgetedPublic);
59024
59601
  const skillPolicy = nativeSkills ? this._nativeRecoveryEnabled() ? "enabled" : "unavailable" : void 0;
59025
59602
  if (this._baseSystemPromptOptions.nativeSkillSelection !== skillPolicy) {
@@ -59055,7 +59632,19 @@ var AgentSession = class _AgentSession {
59055
59632
  if (epochContext.toolContinuations?.length && (!candidate.publicMessages || JSON.stringify(getCanonicalEpochContext(candidate.publicMessages)?.toolContinuations) !== JSON.stringify(epochContext.toolContinuations) || candidate.projection.pendingPublicMessageGroups?.length))
59056
59633
  throw new Error("Tool continuation requires its exact public candidate before epoch ACK");
59057
59634
  assertResourceCurrent(resource);
59058
- const representation = contextEpochRepresentation(candidate.request, candidate.assessment, limits.maxSourceBytes, unbudgetedPublic, candidate.responseItemIdentity);
59635
+ let representation;
59636
+ try {
59637
+ representation = contextEpochRepresentation(candidate.request, candidate.assessment, limits.maxSourceBytes, unbudgetedPublic, candidate.responseItemIdentity);
59638
+ } catch (error) {
59639
+ if (error instanceof UnsupportedContextEpochConfigurationError && !contextEpochsEnabled && !candidate.assessment && !committed && !acknowledged && !epochContext.taskFrameRebased && !epochContext.selectedSkills?.length && !epochContext.toolContinuations?.length && !candidate.publicMessages) {
59640
+ const source = getCanonicalViewSelectionSource(messages);
59641
+ const selected = new Set(candidate.selectedUnitIds);
59642
+ 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))) {
59643
+ return;
59644
+ }
59645
+ }
59646
+ throw error;
59647
+ }
59059
59648
  const replayContract = "replayContract" in candidate.projection && candidate.projection.replayContract === "message-groups" ? "message-groups" : "complete-context";
59060
59649
  const publicWindow = "publicWindow" in candidate.projection && candidate.projection.publicWindow === true;
59061
59650
  const selection = JSON.stringify([
@@ -61040,7 +61629,7 @@ var AgentSession = class _AgentSession {
61040
61629
  if (compactionTimestamp !== void 0 && context.message.timestamp <= compactionTimestamp)
61041
61630
  return false;
61042
61631
  const contextTokens = this._getThresholdContextTokens(context.message, compactionTimestamp);
61043
- if (contextTokens === void 0 || !shouldCompact(contextTokens, contextWindow, settings))
61632
+ if (contextTokens === void 0 || !shouldCompact(contextTokens, contextWindow, settings, estimateFixedCompactionTokens(this.systemPrompt, this.agent.state.tools, this.messages)))
61044
61633
  return false;
61045
61634
  if (this._hasFailedThresholdCompaction())
61046
61635
  return false;
@@ -61373,7 +61962,7 @@ var AgentSession = class _AgentSession {
61373
61962
  }
61374
61963
  return {
61375
61964
  scheduled: true,
61376
- note: "Refinement runs when the current turn ends; the harness rebuilds the system prompt and resumes you automatically. Continue working normally."
61965
+ note: "Refinement runs when the current turn ends; fresh harness advice is added to the next request and you resume automatically. Continue working normally."
61377
61966
  };
61378
61967
  }
61379
61968
  default:
@@ -62316,6 +62905,7 @@ var AgentSession = class _AgentSession {
62316
62905
  for (const { session } of this._rlmChildSessions.values())
62317
62906
  await drain(() => session.disposeAsync());
62318
62907
  this._rlmChildSessions.clear();
62908
+ this._rlmChildUsageSources.clear();
62319
62909
  this._rlmChildCleanupFailures.clear();
62320
62910
  this._deletedRlmChildIds.clear();
62321
62911
  await drain(() => this._ipythonKernelProvisioner?.dispose({ snapshot: kernelSnapshot }));
@@ -62405,6 +62995,7 @@ var AgentSession = class _AgentSession {
62405
62995
  session.dispose();
62406
62996
  }
62407
62997
  this._rlmChildSessions.clear();
62998
+ this._rlmChildUsageSources.clear();
62408
62999
  this._rlmChildCleanupFailures.clear();
62409
63000
  this._deletedRlmChildIds.clear();
62410
63001
  this._pendingNextTurnMessages = [];
@@ -62639,6 +63230,7 @@ var AgentSession = class _AgentSession {
62639
63230
  rlmDepth: this._rlmDepth,
62640
63231
  rlmParentAgent: this._rlmParentAgent,
62641
63232
  harnessState: this._loadMergedHarnessState(),
63233
+ harnessSection: "instructions",
62642
63234
  errorFixSelection: {
62643
63235
  enabled: this.settingsManager.getLearningEnabled(),
62644
63236
  tools: validToolNames,
@@ -62651,6 +63243,106 @@ var AgentSession = class _AgentSession {
62651
63243
  };
62652
63244
  return buildSystemPrompt(this._baseSystemPromptOptions);
62653
63245
  }
63246
+ /** Read only snapshot candidates in the active literal tail and accepted epoch recipes. */
63247
+ async _readHarnessSnapshot(view) {
63248
+ const { maxMessages, maxSourceBytes } = this.settingsManager.getCanonicalContextLimits();
63249
+ const refs = [];
63250
+ let summary = null;
63251
+ let cursor;
63252
+ let count = 0;
63253
+ let bytes = 0;
63254
+ do {
63255
+ const page = await view.contextManifest({ cursor, limit: 128 });
63256
+ if (page.selection !== "known")
63257
+ throw new Error(`Harness snapshot context selection is ${page.selection}`);
63258
+ summary = page.summaryRef;
63259
+ count += page.refs.length;
63260
+ if (count + (summary ? 1 : 0) > maxMessages)
63261
+ throw new Error("Harness snapshot context message budget exceeded");
63262
+ refs.push(...page.refs.filter((ref) => ref.kind === "custom_message"));
63263
+ cursor = page.nextCursor ?? void 0;
63264
+ } while (cursor);
63265
+ const read2 = async (ref, source = view) => {
63266
+ bytes += ref.locator.length;
63267
+ if (bytes > maxSourceBytes)
63268
+ throw new Error("Harness snapshot source byte budget exceeded");
63269
+ const metadata = await source.get(ref.entryId);
63270
+ if (!metadata || metadata.revision !== ref.revision)
63271
+ throw new Error("Harness snapshot source is unavailable");
63272
+ const hydrated = await hydrateCapturedHistoryEntry(metadata, ref.locator.length, source.readPayload);
63273
+ if (!hydrated)
63274
+ throw new Error("Harness snapshot payload is unavailable");
63275
+ return hydrated.entry;
63276
+ };
63277
+ const content = (entry2) => entry2.type === "custom_message" && entry2.customType === HARNESS_SNAPSHOT_CUSTOM_TYPE && typeof entry2.content === "string" ? entry2.content : void 0;
63278
+ for (const ref of refs.reverse()) {
63279
+ const snapshot = content(await read2(ref));
63280
+ if (snapshot !== void 0)
63281
+ return snapshot;
63282
+ }
63283
+ if (!summary)
63284
+ return;
63285
+ const entry = await read2(summary);
63286
+ if (entry.type !== "compaction" || summary.qualification !== "native-context-epoch" || summary.retention === "retained-import")
63287
+ return;
63288
+ const checkpoint = readContextEpoch(entry.details, maxSourceBytes);
63289
+ if (!checkpoint)
63290
+ return;
63291
+ if (count + checkpoint.views.length > maxMessages)
63292
+ throw new Error("Harness snapshot context message budget exceeded");
63293
+ for (const pinned of [...checkpoint.views].reverse()) {
63294
+ if (pinned.ref.kind !== "custom_message")
63295
+ continue;
63296
+ if (!view.atSnapshot)
63297
+ throw new Error("Harness snapshot epoch requires its captured source");
63298
+ const snapshot = content(await read2(pinned.ref, await view.atSnapshot(pinned.source)));
63299
+ if (snapshot !== void 0)
63300
+ return snapshot;
63301
+ }
63302
+ }
63303
+ /** Persist mutable advice before the request owner captures its source and epoch ACK boundary. */
63304
+ async _appendHarnessSnapshotIfChanged() {
63305
+ const manager = this.sessionManager;
63306
+ let leafId = manager.getLeafId();
63307
+ const sourceIsCurrent = manager.captureCompactionSourceOwner();
63308
+ const assertCurrent = () => {
63309
+ if (this._disposed || this.sessionManager !== manager || !sourceIsCurrent() || manager.getLeafId() !== leafId)
63310
+ throw new Error("Harness snapshot source changed before request ownership");
63311
+ };
63312
+ let previous;
63313
+ if (manager.isPersisted()) {
63314
+ previous = await manager.readBranchHistory((view) => this._readHarnessSnapshot(view.branchContext));
63315
+ } else {
63316
+ const snapshot = manager.buildSessionContext().messages.reverse().find((message2) => message2.role === "custom" && message2.customType === HARNESS_SNAPSHOT_CUSTOM_TYPE);
63317
+ if (snapshot?.role === "custom")
63318
+ previous = snapshot.content;
63319
+ }
63320
+ assertCurrent();
63321
+ const options = this._baseSystemPromptOptions;
63322
+ const tools = options.selectedTools ?? [];
63323
+ const hasIpython = tools.includes("ipython");
63324
+ const content = formatHarnessStateForPrompt(this._loadMergedHarnessState(), {
63325
+ section: "entries",
63326
+ includeIpythonExamples: hasIpython,
63327
+ includeShellExamples: tools.includes("bash"),
63328
+ errorFixSelection: options.errorFixSelection ? { ...options.errorFixSelection, enabled: this.settingsManager.getLearningEnabled() } : void 0
63329
+ });
63330
+ if (previous === content)
63331
+ return assertCurrent;
63332
+ const entryId = await manager.appendCustomMessageEntryWithRollback(HARNESS_SNAPSHOT_CUSTOM_TYPE, content, false);
63333
+ if (this._disposed || this.sessionManager !== manager || !sourceIsCurrent() || manager.getLeafId() !== entryId)
63334
+ throw new Error("Harness snapshot source changed during append");
63335
+ if (!manager.isPersisted())
63336
+ this.agent.state.messages.push({
63337
+ role: "custom",
63338
+ customType: HARNESS_SNAPSHOT_CUSTOM_TYPE,
63339
+ content,
63340
+ display: false,
63341
+ timestamp: Date.now()
63342
+ });
63343
+ leafId = entryId;
63344
+ return assertCurrent;
63345
+ }
62654
63346
  _refreshExtensionSystemPrompt(extensionPrompt, baseSnapshot) {
62655
63347
  if (this._baseSystemPrompt === baseSnapshot) {
62656
63348
  return extensionPrompt;
@@ -62704,7 +63396,7 @@ var AgentSession = class _AgentSession {
62704
63396
  async _runPreTurnCompaction() {
62705
63397
  const lastAssistant = this._findLastAssistantMessage();
62706
63398
  if (lastAssistant)
62707
- await this._checkCompaction(lastAssistant, false, false);
63399
+ await this._checkCompaction(lastAssistant, false, false, void 0, true);
62708
63400
  }
62709
63401
  async _prepareForCommit(policy, steps) {
62710
63402
  if (policy.initialRefineBarrier === "always" || policy.initialRefineBarrier === "ifInFlight" && this._refineInFlight) {
@@ -65384,7 +66076,7 @@ ${parsed.args}` : block;
65384
66076
  }
65385
66077
  }
65386
66078
  /** 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) {
66079
+ async _prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner = this._captureCompactionOwner(), allowShortSession = false, budgetPressure = false, capacity) {
65388
66080
  this._assertCompactionOwner(owner);
65389
66081
  const limits = this.settingsManager.getCanonicalContextLimits();
65390
66082
  const resource = this._captureKernelResource();
@@ -65401,10 +66093,11 @@ ${parsed.args}` : block;
65401
66093
  const context = getCanonicalEpochContext(messages);
65402
66094
  if (context.checkpoint?.includeSummary && pathEntries.at(-1)?.type === "compaction")
65403
66095
  return { preparation: void 0, maxSourceBytes: limits.maxSourceBytes };
65404
- const boundary = canonicalRecoveryBoundary(messages);
66096
+ const authorization = getRecoveryCompactionAuthorization(capacity);
66097
+ const boundary = canonicalRecoveryBoundary(messages, authorization);
65405
66098
  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
66099
  if (preparation)
65407
- prepareRecoveryCompaction(messages, preparation.firstKeptEntryId, limits.maxSourceBytes);
66100
+ prepareRecoveryCompaction(messages, preparation.firstKeptEntryId, limits.maxSourceBytes, authorization);
65408
66101
  return {
65409
66102
  preparation,
65410
66103
  messages,
@@ -65420,7 +66113,7 @@ ${parsed.args}` : block;
65420
66113
  */
65421
66114
  async _performCompaction(options) {
65422
66115
  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);
66116
+ const prepared = await this._prepareCapturedCompaction(pathEntries, settings, requests, compaction, owner, allowShortSession, budgetPressure, options.capacity);
65424
66117
  this._assertCompactionOwner(owner);
65425
66118
  if (prepared.resource)
65426
66119
  assertResourceCurrent(prepared.resource);
@@ -65501,7 +66194,7 @@ ${parsed.args}` : block;
65501
66194
  }
65502
66195
  this._assertCompactionOwner(owner);
65503
66196
  const result = JSON.parse(JSON.stringify({ summary, firstKeptEntryId, tokensBefore, details }));
65504
- const recovery = prepared.messages ? prepareRecoveryCompaction(prepared.messages, firstKeptEntryId, prepared.maxSourceBytes) : void 0;
66197
+ const recovery = prepared.messages ? prepareRecoveryCompaction(prepared.messages, firstKeptEntryId, prepared.maxSourceBytes, getRecoveryCompactionAuthorization(options.capacity)) : void 0;
65505
66198
  if (prepared.resource)
65506
66199
  assertResourceCurrent(prepared.resource);
65507
66200
  if (recovery) {
@@ -66124,7 +66817,30 @@ ${parsed.args}` : block;
66124
66817
  const sessionHistory = (async () => {
66125
66818
  if (residentEntries !== void 0)
66126
66819
  return residentEntries;
66127
- return (await this.sessionManager.materializeSourceHistory(limits)).entries.map(({ entry }) => entry);
66820
+ return this.sessionManager.readSourceHistory(async (history) => {
66821
+ const entries = [];
66822
+ let sourceBytes = 0;
66823
+ let after = 0;
66824
+ for (; ; ) {
66825
+ const page = await history.page(after, 128);
66826
+ if (page.indexedThrough < history.source.sourceSequence)
66827
+ throw new Error("Captured refinement history has incomplete index coverage");
66828
+ for (const reference of page.events) {
66829
+ if (reference.kind !== "custom")
66830
+ continue;
66831
+ if (entries.length >= limits.maxEntries)
66832
+ throw new Error("Refinement history entry budget exceeded");
66833
+ if (sourceBytes + reference.locator.length > limits.maxSourceBytes)
66834
+ throw new Error("Refinement history source byte budget exceeded");
66835
+ const hydrated = await hydrateCapturedHistoryEntry(reference, limits.maxSourceBytes - sourceBytes, history.readPayload);
66836
+ entries.push(hydrated.entry);
66837
+ sourceBytes += reference.locator.length;
66838
+ }
66839
+ if (page.nextAfter === null)
66840
+ return entries;
66841
+ after = page.nextAfter;
66842
+ }
66843
+ });
66128
66844
  })();
66129
66845
  const [globalResult, sessionResult] = await Promise.allSettled([globalHistory, sessionHistory]);
66130
66846
  if (globalResult.status === "rejected") {
@@ -66391,8 +67107,10 @@ ${parsed.args}` : block;
66391
67107
  }
66392
67108
  if (refinementAuditAppendError)
66393
67109
  throw refinementAuditAppendError.error;
66394
- this._baseSystemPrompt = this._rebuildSystemPrompt(this.getActiveToolNames());
66395
- this.agent.state.systemPrompt = this._baseSystemPrompt;
67110
+ this._baseSystemPromptOptions = {
67111
+ ...this._baseSystemPromptOptions,
67112
+ harnessState: this._loadMergedHarnessState()
67113
+ };
66396
67114
  try {
66397
67115
  this._emit({ type: "refine_complete", result });
66398
67116
  } catch {
@@ -66445,7 +67163,7 @@ ${parsed.args}` : block;
66445
67163
  return void 0;
66446
67164
  return calculateContextTokens(assistantMessage.usage);
66447
67165
  }
66448
- async _checkCompaction(assistantMessage, skipAbortedCheck = true, queueAutonomousContinuation = true, invocationOwner) {
67166
+ async _checkCompaction(assistantMessage, skipAbortedCheck = true, queueAutonomousContinuation = true, invocationOwner, beforeNextTurn = false) {
66449
67167
  if (this._compactionSetupFailure)
66450
67168
  return false;
66451
67169
  if (invocationOwner && !this._isCompactionSourceOwnerCurrent(invocationOwner))
@@ -66518,7 +67236,7 @@ ${parsed.args}` : block;
66518
67236
  if (messages.length > 0 && messages[messages.length - 1].role === "assistant") {
66519
67237
  this._removeLastAssistantFromContext();
66520
67238
  }
66521
- return await this._runAutoCompaction("overflow", true, owner);
67239
+ return await this._runAutoCompaction("overflow", true, owner, false, void 0, beforeNextTurn);
66522
67240
  }
66523
67241
  if (this._pendingRequestedCompaction !== void 0) {
66524
67242
  return await this._runAutoCompaction("requested", false, owner);
@@ -66530,7 +67248,7 @@ ${parsed.args}` : block;
66530
67248
  const contextTokens = this._getThresholdContextTokens(assistantMessage, compactionTimestamp);
66531
67249
  if (contextTokens === void 0)
66532
67250
  return false;
66533
- if (shouldCompact(contextTokens, contextWindow, settings)) {
67251
+ if (shouldCompact(contextTokens, contextWindow, settings, estimateFixedCompactionTokens(this.systemPrompt, this.agent.state.tools, this.messages))) {
66534
67252
  if (this._hasFailedThresholdCompaction())
66535
67253
  return false;
66536
67254
  if (!this._pendingCheckpoint && queueAutonomousContinuation) {
@@ -66540,7 +67258,7 @@ ${parsed.args}` : block;
66540
67258
  }
66541
67259
  if (!this._isCompactionOwnerCurrent(owner) || !this._contextOptimizationAllowed())
66542
67260
  return false;
66543
- return await this._runAutoCompaction("threshold", false, owner);
67261
+ return await this._runAutoCompaction("threshold", false, owner, false, void 0, beforeNextTurn);
66544
67262
  }
66545
67263
  return false;
66546
67264
  }
@@ -66586,7 +67304,7 @@ This compaction outcome could not be saved to session history: ${persistenceErro
66586
67304
  this._emit({ type: "message_start", message: outcomeMessage });
66587
67305
  this._emit({ type: "message_end", message: outcomeMessage });
66588
67306
  }
66589
- async _runAutoCompaction(reason, willRetry, capturedOwner, resumeInPlace = false, capacity) {
67307
+ async _runAutoCompaction(reason, willRetry, capturedOwner, resumeInPlace = false, capacity, beforeNextTurn = false) {
66590
67308
  const checkpoint = this._pendingCheckpoint;
66591
67309
  const pending = this._pendingRequestedCompaction;
66592
67310
  const owner = checkpoint?.owner ?? pending?.owner ?? capturedOwner ?? this._captureCompactionOwner();
@@ -66699,6 +67417,12 @@ This compaction outcome could not be saved to session history: ${persistenceErro
66699
67417
  if (!this._isCompactionSourceOwnerCurrent(owner))
66700
67418
  throw failure2;
66701
67419
  this._clearQueuedAutonomousContinuationsAfterSkippedThresholdCompaction(reason === "threshold" && shouldContinueAfterCompaction, queuedAutonomousContinuationsForThisCompaction);
67420
+ if (beforeNextTurn && error instanceof MissingRecoveryReplayContractError) {
67421
+ if (reason === "overflow")
67422
+ this._overflowRecovery = "idle";
67423
+ await this._endCompactionUnsuccessfully(reason, "skipped", "Compaction deferred until the next native request establishes recovery replay coverage.", { errorSeverity: "warning", customInstructions, owner });
67424
+ return false;
67425
+ }
66702
67426
  const errorMessage4 = error instanceof Error ? error.message : "compaction failed";
66703
67427
  const aborted = errorMessage4 === "Compaction cancelled" || error instanceof Error && error.name === "AbortError" || abort.signal.aborted;
66704
67428
  if (aborted) {
@@ -67947,6 +68671,7 @@ This compaction outcome could not be saved to session history: ${persistenceErro
67947
68671
  this._rlmChildUnsubscribes.get(childId)?.();
67948
68672
  this._rlmChildUnsubscribes.delete(childId);
67949
68673
  this._rlmChildSessions.delete(childId);
68674
+ this._rlmChildUsageSources.delete(childId);
67950
68675
  this._rlmChildCleanupFailures.delete(childId);
67951
68676
  this._abandonedRlmQuiescenceChildIds.delete(childId);
67952
68677
  if (!run2 || this._activeRlmChildRuns.get(childId) === run2) {
@@ -68021,6 +68746,145 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68021
68746
  this._removeRlmSubagentTracking(childId);
68022
68747
  return { subagent };
68023
68748
  }
68749
+ async _restoreRlmChildUsageSource(childId, child) {
68750
+ if (this._rlmChildUsageSources.has(childId))
68751
+ return;
68752
+ const readSource = (entry) => {
68753
+ if (entry.type !== "custom" || entry.customType !== RLM_PARENT_USAGE_CUSTOM_TYPE)
68754
+ return;
68755
+ const data = entry.data;
68756
+ if (!data || data.sessionId !== this.sessionId || data.sessionFile !== this.sessionFile || typeof data.entryId !== "string")
68757
+ return;
68758
+ return { sessionId: data.sessionId, sessionFile: data.sessionFile, entryId: data.entryId };
68759
+ };
68760
+ const source = child.sessionManager.supportsCapturedHistoryReads() ? await child.sessionManager.readBranchHistory(async (history) => {
68761
+ let after = 0;
68762
+ while (true) {
68763
+ const page = await history.page(after, 64);
68764
+ for (const ref of page.events) {
68765
+ if (ref.kind !== "custom" || ref.locator.length > 16 * 1024)
68766
+ continue;
68767
+ const record2 = await history.hydrateEntry(ref.id, 16 * 1024);
68768
+ const source2 = record2 && readSource(record2.entry);
68769
+ if (source2)
68770
+ return source2;
68771
+ }
68772
+ if (page.nextAfter === null)
68773
+ return;
68774
+ after = page.nextAfter;
68775
+ }
68776
+ }) : child.sessionManager.getBranch().map(readSource).find((source2) => source2 !== void 0);
68777
+ if (!source || source.sessionId !== this.sessionId || source.sessionFile !== this.sessionFile)
68778
+ return;
68779
+ const target = await this.sessionManager.readEntry(source.entryId);
68780
+ if (target?.type !== "message" || target.message.role !== "assistant")
68781
+ return;
68782
+ if (source.sessionId !== this.sessionId || source.sessionFile !== this.sessionFile)
68783
+ return;
68784
+ this._rlmChildUsageSources.set(childId, source);
68785
+ }
68786
+ _subscribeRlmChildEvents(childId, child, run2, onUsageWrite) {
68787
+ let runningToolCount = 0;
68788
+ const emitChildUpdate = () => {
68789
+ if (run2)
68790
+ run2.emitUpdate?.();
68791
+ else
68792
+ this._emit({ type: "rlm_child_update", child: this._rlmChildSnapshotForSession(childId, child) });
68793
+ };
68794
+ const attributeUsage = (usage, origin) => {
68795
+ const source = this._rlmChildUsageSources.get(childId);
68796
+ if (!source || source.sessionId !== this.sessionId || source.sessionFile !== this.sessionFile)
68797
+ return Promise.resolve();
68798
+ const delta = structuredClone(usage);
68799
+ const target = this.messages.find((message2) => message2.role === "assistant" && this._findAssistantEntryIdForMessage(message2) === source.entryId);
68800
+ const refreshOutput = this._refreshInvocationOutput;
68801
+ const forwardUsage = this._rlmParentUsageAttribution;
68802
+ const write2 = this.sessionManager.appendChildUsageAttributionWithAggregate(source.entryId, delta, void 0, origin).then(async ({ aggregateUsage }) => {
68803
+ if (target) {
68804
+ target.usage = structuredClone(aggregateUsage);
68805
+ refreshOutput?.(target);
68806
+ }
68807
+ await forwardUsage?.(delta, origin);
68808
+ });
68809
+ this._childUsageWrites.add(write2);
68810
+ onUsageWrite?.(write2);
68811
+ void write2.then(() => this._childUsageWrites.delete(write2), (error) => {
68812
+ this._childUsageWrites.delete(write2);
68813
+ if (run2)
68814
+ run2.error = `Child usage attribution was not acknowledged: ${this._asError(error).message}`;
68815
+ this._surfaceSessionInputError(error);
68816
+ });
68817
+ return write2;
68818
+ };
68819
+ child._rlmParentUsageAttribution = attributeUsage;
68820
+ const unsubscribe = child.subscribe((event) => {
68821
+ if (event.type === "rlm_child_update") {
68822
+ this._emit(event);
68823
+ return;
68824
+ }
68825
+ if (event.type === "agent_start") {
68826
+ if (run2)
68827
+ run2.activity = { kind: "waiting" };
68828
+ emitChildUpdate();
68829
+ } else if (event.type === "agent_end") {
68830
+ if (run2)
68831
+ run2.activity = void 0;
68832
+ emitChildUpdate();
68833
+ } else if (event.type === "message_end" && event.message.role === "assistant") {
68834
+ const assistant = event.message;
68835
+ if (run2) {
68836
+ run2.terminalAssistantOutcome = {
68837
+ stopReason: assistant.stopReason,
68838
+ errorMessage: assistant.errorMessage
68839
+ };
68840
+ }
68841
+ const update = () => {
68842
+ const text2 = compactRlmText(readAssistantText(assistant));
68843
+ if (run2 && text2)
68844
+ run2.answerPreview = text2;
68845
+ emitChildUpdate();
68846
+ };
68847
+ if (assistant.stopReason !== "error" && assistant.stopReason !== "aborted") {
68848
+ const messages = child.messages;
68849
+ const precedingPrompt = messages.slice(0, messages.lastIndexOf(assistant)).reverse().find((message2) => message2.role === "user" || message2.role === "custom" && message2.customType !== HARNESS_SNAPSHOT_CUSTOM_TYPE);
68850
+ const origin = precedingPrompt?.role === "custom" && isAgentSessionMessage(precedingPrompt) ? precedingPrompt.details.id.startsWith("spawn:") ? "spawn_task" : "agent_message" : "direct_user";
68851
+ void attributeUsage(assistant.usage, origin).then(update, () => {
68852
+ });
68853
+ } else
68854
+ update();
68855
+ } else if (event.type === "message_start" || event.type === "message_update") {
68856
+ if (event.message.role === "assistant") {
68857
+ if (run2) {
68858
+ const text2 = compactRlmText(readAssistantText(event.message));
68859
+ if (text2)
68860
+ run2.answerPreview = text2;
68861
+ run2.activity = { kind: "writing" };
68862
+ }
68863
+ emitChildUpdate();
68864
+ }
68865
+ } else if (event.type === "tool_execution_start") {
68866
+ if (run2) {
68867
+ run2.toolUseCount++;
68868
+ runningToolCount++;
68869
+ run2.activity = { kind: "executing", toolName: event.toolName };
68870
+ }
68871
+ emitChildUpdate();
68872
+ } else if (event.type === "tool_execution_end") {
68873
+ if (run2) {
68874
+ runningToolCount = Math.max(0, runningToolCount - 1);
68875
+ if (runningToolCount === 0)
68876
+ run2.activity = { kind: "waiting" };
68877
+ }
68878
+ emitChildUpdate();
68879
+ } else if (event.type === "session_info_changed" || event.type === "recap_update")
68880
+ emitChildUpdate();
68881
+ });
68882
+ return () => {
68883
+ unsubscribe();
68884
+ if (child._rlmParentUsageAttribution === attributeUsage)
68885
+ child._rlmParentUsageAttribution = void 0;
68886
+ };
68887
+ }
68024
68888
  /**
68025
68889
  * Retain a finished child session for the parent lifetime so inspectors and
68026
68890
  * daemon-hosted agent messaging can keep addressing it. Returns false (and disposes
@@ -68050,10 +68914,24 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68050
68914
  }
68051
68915
  }
68052
68916
  }
68053
- this._rlmChildSessions.set(childId, { session, run: this._activeRlmChildRuns.get(childId) });
68054
- if (unsubscribe) {
68055
- this._rlmChildUnsubscribes.set(childId, unsubscribe);
68917
+ await this._restoreRlmChildUsageSource(childId, session);
68918
+ if (this._disposed || this._disposing) {
68919
+ await session.disposeAsync();
68920
+ return false;
68056
68921
  }
68922
+ if (this._deletingRlmChildren.has(childId) || this._deletedRlmChildIds.has(childId))
68923
+ return false;
68924
+ const retained = this._rlmChildSessions.get(childId);
68925
+ const run2 = this._activeRlmChildRuns.get(childId);
68926
+ if (!run2?.unsubscribe && (retained?.session !== session || !this._rlmChildUnsubscribes.has(childId))) {
68927
+ this._rlmChildUnsubscribes.get(childId)?.();
68928
+ const ownedUnsubscribe = this._subscribeRlmChildEvents(childId, session);
68929
+ this._rlmChildUnsubscribes.set(childId, () => {
68930
+ ownedUnsubscribe();
68931
+ unsubscribe?.();
68932
+ });
68933
+ }
68934
+ this._rlmChildSessions.set(childId, { session, run: run2 });
68057
68935
  return true;
68058
68936
  }
68059
68937
  releaseRlmChildSession(childId, session) {
@@ -68061,8 +68939,10 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68061
68939
  if (run2?.session === session && run2.status === "done") {
68062
68940
  const unsubscribe2 = run2.unsubscribe ?? noopRlmChildEventUnsubscribe;
68063
68941
  return () => {
68064
- run2.unsubscribe = void 0;
68065
- this._activeRlmChildRuns.delete(childId);
68942
+ if (run2.unsubscribe === unsubscribe2)
68943
+ run2.unsubscribe = void 0;
68944
+ if (this._activeRlmChildRuns.get(childId) === run2)
68945
+ this._activeRlmChildRuns.delete(childId);
68066
68946
  unsubscribe2();
68067
68947
  };
68068
68948
  }
@@ -68070,8 +68950,10 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68070
68950
  return false;
68071
68951
  const unsubscribe = this._rlmChildUnsubscribes.get(childId) ?? noopRlmChildEventUnsubscribe;
68072
68952
  return () => {
68073
- this._rlmChildUnsubscribes.delete(childId);
68074
- this._rlmChildSessions.delete(childId);
68953
+ if (this._rlmChildSessions.get(childId)?.session === session && this._rlmChildUnsubscribes.get(childId) === unsubscribe) {
68954
+ this._rlmChildUnsubscribes.delete(childId);
68955
+ this._rlmChildSessions.delete(childId);
68956
+ }
68075
68957
  unsubscribe();
68076
68958
  };
68077
68959
  }
@@ -68191,7 +69073,7 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68191
69073
  return [...sessions];
68192
69074
  }
68193
69075
  _hasUnsettledRlmQuiescenceWork() {
68194
- if (this.requests.hasPending)
69076
+ if (this.requests.hasPending || this._childUsageWrites.size > 0)
68195
69077
  return true;
68196
69078
  if (this._hasDeferredRlmTerminalNotices())
68197
69079
  return true;
@@ -68235,6 +69117,7 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68235
69117
  return;
68236
69118
  await wait(Promise.all([
68237
69119
  ...unsettledRuns.map((run2) => run2.settlement.promise),
69120
+ ...this._childUsageWrites,
68238
69121
  ...childSessions.map((child) => child.waitForRlmQuiescence(cancellation.signal))
68239
69122
  ]));
68240
69123
  }
@@ -68389,6 +69272,12 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68389
69272
  async _startRlmChildRun(prompt, admission, kwargs = {}, spawnCode) {
68390
69273
  const spawnedByRequestId = this.isStreaming ? this._semanticEdges.lastTurnRequestId : void 0;
68391
69274
  const parentAssistantForUsage = this._findLastAssistantMessage();
69275
+ const parentEntryId = parentAssistantForUsage && this._findAssistantEntryIdForMessage(parentAssistantForUsage);
69276
+ const usageSource = parentEntryId ? {
69277
+ sessionId: this.sessionId,
69278
+ sessionFile: this.sessionFile,
69279
+ entryId: parentEntryId
69280
+ } : void 0;
68392
69281
  const { name: rawName, model: rawModel, thinking: rawThinking, ...unsupported } = kwargs;
68393
69282
  const unsupportedKwargs = Object.keys(unsupported);
68394
69283
  if (unsupportedKwargs.length > 0) {
@@ -68433,7 +69322,6 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68433
69322
  await this._assertRlmSubagentSessionNameAvailable(sessionName);
68434
69323
  admission.assertCurrent();
68435
69324
  const startedAt = Date.now();
68436
- let runningToolCount = 0;
68437
69325
  let childSession;
68438
69326
  let usageSettlement = Promise.resolve();
68439
69327
  const run2 = {
@@ -68455,6 +69343,8 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68455
69343
  throw new Error(run2.error ?? "RLM child cancelled");
68456
69344
  };
68457
69345
  this._activeRlmChildRuns.set(run2.id, run2);
69346
+ if (usageSource)
69347
+ this._rlmChildUsageSources.set(run2.id, usageSource);
68458
69348
  this._unsettledRlmChildRuns.add(run2);
68459
69349
  const emitChildUpdate = () => {
68460
69350
  const child = this._rlmChildSnapshotForRun(run2);
@@ -68537,73 +69427,12 @@ This compaction outcome could not be saved to session history: ${persistenceErro
68537
69427
  throwIfCancelled();
68538
69428
  run2.status = "running";
68539
69429
  emitChildUpdate();
68540
- const unsubscribeChildEvents = child.subscribe((event) => {
68541
- if (event.type === "rlm_child_update") {
68542
- this._emit(event);
68543
- return;
68544
- }
68545
- if (event.type === "agent_start") {
68546
- run2.activity = { kind: "waiting" };
68547
- emitChildUpdate();
68548
- } else if (event.type === "agent_end") {
68549
- run2.activity = void 0;
68550
- emitChildUpdate();
68551
- } else if (event.type === "message_end" && event.message.role === "assistant") {
68552
- const assistant = event.message;
68553
- if (assistant.stopReason !== "error" && assistant.stopReason !== "aborted") {
68554
- if (parentAssistantForUsage) {
68555
- const parentEntryId = this._findAssistantEntryIdForMessage(parentAssistantForUsage);
68556
- if (parentEntryId) {
68557
- const messages = child.messages;
68558
- const assistantIndex = messages.lastIndexOf(assistant);
68559
- const precedingPrompt = messages.slice(0, assistantIndex).reverse().find((message2) => message2.role === "user" || message2.role === "custom");
68560
- const origin = precedingPrompt?.role === "custom" && isAgentSessionMessage(precedingPrompt) ? precedingPrompt.details.id.startsWith("spawn:") ? "spawn_task" : "agent_message" : "direct_user";
68561
- const text3 = compactRlmText(readAssistantText(assistant));
68562
- const refreshOutput = this._refreshInvocationOutput;
68563
- const write2 = this.sessionManager.appendChildUsageAttributionWithAggregate(parentEntryId, assistant.usage, void 0, origin).then(({ aggregateUsage }) => {
68564
- parentAssistantForUsage.usage = structuredClone(aggregateUsage);
68565
- refreshOutput?.(parentAssistantForUsage);
68566
- if (text3)
68567
- run2.answerPreview = text3;
68568
- emitChildUpdate();
68569
- });
68570
- this._childUsageWrites.add(write2);
68571
- usageSettlement = Promise.all([usageSettlement, write2]).then(() => void 0);
68572
- void usageSettlement.catch(() => void 0);
68573
- void write2.then(() => this._childUsageWrites.delete(write2), (error) => {
68574
- this._childUsageWrites.delete(write2);
68575
- run2.error = `Child usage attribution was not acknowledged: ${this._asError(error).message}`;
68576
- this._surfaceSessionInputError(error);
68577
- });
68578
- return;
68579
- }
68580
- }
68581
- }
68582
- const text2 = compactRlmText(readAssistantText(assistant));
68583
- if (text2)
68584
- run2.answerPreview = text2;
68585
- emitChildUpdate();
68586
- } else if (event.type === "message_start" || event.type === "message_update") {
68587
- if (event.message.role === "assistant") {
68588
- const text2 = compactRlmText(readAssistantText(event.message));
68589
- if (text2)
68590
- run2.answerPreview = text2;
68591
- run2.activity = { kind: "writing" };
68592
- emitChildUpdate();
68593
- }
68594
- } else if (event.type === "tool_execution_start") {
68595
- run2.toolUseCount += 1;
68596
- runningToolCount += 1;
68597
- run2.activity = { kind: "executing", toolName: event.toolName };
68598
- emitChildUpdate();
68599
- } else if (event.type === "tool_execution_end") {
68600
- runningToolCount = Math.max(0, runningToolCount - 1);
68601
- if (runningToolCount === 0)
68602
- run2.activity = { kind: "waiting" };
68603
- emitChildUpdate();
68604
- } else if (event.type === "session_info_changed" || event.type === "recap_update") {
68605
- emitChildUpdate();
68606
- }
69430
+ if (usageSource) {
69431
+ await child.sessionManager.appendCustomEntry(RLM_PARENT_USAGE_CUSTOM_TYPE, usageSource);
69432
+ }
69433
+ const unsubscribeChildEvents = this._subscribeRlmChildEvents(run2.id, child, run2, (write2) => {
69434
+ usageSettlement = Promise.all([usageSettlement, write2]).then(() => void 0);
69435
+ void usageSettlement.catch(() => void 0);
68607
69436
  });
68608
69437
  run2.unsubscribe = unsubscribeChildEvents;
68609
69438
  const content = `[task from parent]
@@ -68633,8 +69462,17 @@ ${prompt}`;
68633
69462
  source: "extension",
68634
69463
  customMessage: spawnMessage
68635
69464
  });
69465
+ const terminal = run2.terminalAssistantOutcome;
69466
+ if (terminal?.stopReason === "aborted") {
69467
+ run2.status = "cancelled";
69468
+ run2.error ??= terminal.errorMessage || "RLM child aborted";
69469
+ }
69470
+ throwIfCancelled();
69471
+ if (terminal?.stopReason === "error")
69472
+ throw new Error(terminal.errorMessage || "RLM child inference failed");
68636
69473
  await child.waitForRlmQuiescence();
68637
69474
  await usageSettlement;
69475
+ throwIfCancelled();
68638
69476
  if (run2.error)
68639
69477
  throw new Error(run2.error);
68640
69478
  run2.status = "done";
@@ -69462,34 +70300,13 @@ ${command}` : command;
69462
70300
  _contextWindowResolver() {
69463
70301
  return (provider, modelId) => this._modelRegistry.find(provider, modelId)?.contextWindow;
69464
70302
  }
69465
- _ownUsageMemo;
69466
70303
  // Whole-source own spend, identical to the catalog reduction at passivation.
69467
70304
  async getOwnUsageSummary() {
69468
70305
  if (!this.sessionManager.supportsCapturedHistoryReads()) {
69469
- const entries = await this.sessionManager.readEntries();
70306
+ const entries = this.sessionManager.getEntries();
69470
70307
  return sessionUsageSummaryFrom(computeOwnAndTotalUsage(entries, entries).ownUsage);
69471
70308
  }
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
- });
70309
+ return this.sessionManager.readOwnUsageSummary();
69493
70310
  }
69494
70311
  /**
69495
70312
  * Build the agent context overview for /context: this session as the root
@@ -69544,7 +70361,12 @@ ${command}` : command;
69544
70361
  if (!usage)
69545
70362
  throw new Error("Context tree usage source is unavailable");
69546
70363
  const contextUsage = estimate ? usage.hasPostCompactionUsage ? { tokens: estimate.tokens, contextWindow, percent: estimate.tokens / contextWindow * 100 } : { tokens: null, contextWindow, percent: null } : void 0;
69547
- const usageMetadata = { ownUsage: usage.ownUsage, totalUsage: usage.totalUsage, contextUsage };
70364
+ const usageMetadata = {
70365
+ ownUsage: usage.ownUsage,
70366
+ totalUsage: usage.totalUsage,
70367
+ ...usage.ownRequestUsage ? { ownRequestUsage: usage.ownRequestUsage } : {},
70368
+ contextUsage
70369
+ };
69548
70370
  request.retainMetadata({ contextUsage });
69549
70371
  return {
69550
70372
  ...rootNode,
@@ -70090,7 +70912,7 @@ import { resolve as resolve15 } from "node:path";
70090
70912
  var BASE_CONTEXT_BUILD_ID_ENV = "BASE_CONTEXT_BUILD_ID";
70091
70913
  var BASE_CONTEXT_LAUNCHER_PATH_ENV = "BASE_CONTEXT_LAUNCHER_PATH";
70092
70914
  function bundledBuildId() {
70093
- return false ? void 0 : "v1.0.9-1-ge86dce7cb";
70915
+ return false ? void 0 : "v1.0.11-2-g8a0001383";
70094
70916
  }
70095
70917
  function getDaemonRuntimeIdentity(environment = process.env) {
70096
70918
  const entrypoint = process.argv[1];
@@ -70795,6 +71617,8 @@ export {
70795
71617
  collectEntriesForBranchSummary,
70796
71618
  prepareBranchEntries,
70797
71619
  generateBranchSummary,
71620
+ emptyRequestUsageTotals,
71621
+ addRequestUsageTotals,
70798
71622
  SESSION_SCHEDULED_JOBS_FILENAME,
70799
71623
  DEFAULT_HEARTBEAT_SCHEDULE,
70800
71624
  DEFAULT_HEARTBEAT_DELIVERY_MODE,
@@ -70917,7 +71741,7 @@ export {
70917
71741
  passivatedWorkerRosterEntry,
70918
71742
  sessionSummaryFromRosterEntry,
70919
71743
  AgentRoster,
70920
- readUserMessagesForForking,
71744
+ readVisibleUserMessagesForForking,
70921
71745
  SERPER_CREDENTIAL_ID,
70922
71746
  SERPER_CREDENTIAL_NAME,
70923
71747
  PromptAdmissionCancelledError,