billion-context-pi 0.1.30 → 0.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +108 -36
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -463,14 +463,49 @@ function truncateLargeToolOutputs(messages, tokenCount, config, countTokens, opt
|
|
|
463
463
|
return { messages: updated, truncatedCount, savedTokens };
|
|
464
464
|
}
|
|
465
465
|
var KEEP_LAST_ORPHANED = 0;
|
|
466
|
+
function rangeKey(startRef, endRef) {
|
|
467
|
+
return `${startRef}::${endRef}`;
|
|
468
|
+
}
|
|
469
|
+
function rewriteCompressText(text, liveKeys) {
|
|
470
|
+
let parsed;
|
|
471
|
+
try {
|
|
472
|
+
parsed = JSON.parse(text ?? "");
|
|
473
|
+
} catch {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
477
|
+
const obj = parsed;
|
|
478
|
+
const content = obj.content;
|
|
479
|
+
if (!Array.isArray(content) || content.length === 0) return null;
|
|
480
|
+
const kept = content.filter((entry) => {
|
|
481
|
+
if (!entry || typeof entry !== "object") return false;
|
|
482
|
+
const s = typeof entry.startId === "string" ? entry.startId : typeof entry.messageId === "string" ? entry.messageId : "";
|
|
483
|
+
const e = typeof entry.endId === "string" ? entry.endId : typeof entry.messageId === "string" ? entry.messageId : "";
|
|
484
|
+
return liveKeys.has(rangeKey(s, e));
|
|
485
|
+
});
|
|
486
|
+
if (kept.length === content.length || kept.length === 0) return null;
|
|
487
|
+
return JSON.stringify({ ...obj, content: kept });
|
|
488
|
+
}
|
|
466
489
|
function hideConsumedCompressCalls(state, messages) {
|
|
467
|
-
const activeCallIds = /* @__PURE__ */ new Set();
|
|
468
490
|
const allBlockCallIds = /* @__PURE__ */ new Set();
|
|
491
|
+
const activeCallIds = /* @__PURE__ */ new Set();
|
|
492
|
+
const liveRangeKeysByCallId = /* @__PURE__ */ new Map();
|
|
493
|
+
const legacyLiveByCallId = /* @__PURE__ */ new Set();
|
|
469
494
|
for (const block of state.blocks) {
|
|
470
|
-
if (block.compressCallId)
|
|
471
|
-
|
|
472
|
-
|
|
495
|
+
if (!block.compressCallId) continue;
|
|
496
|
+
allBlockCallIds.add(block.compressCallId);
|
|
497
|
+
if (!block.active) continue;
|
|
498
|
+
activeCallIds.add(block.compressCallId);
|
|
499
|
+
if (block.startRef === void 0 || block.endRef === void 0) {
|
|
500
|
+
legacyLiveByCallId.add(block.compressCallId);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
let keys = liveRangeKeysByCallId.get(block.compressCallId);
|
|
504
|
+
if (!keys) {
|
|
505
|
+
keys = /* @__PURE__ */ new Set();
|
|
506
|
+
liveRangeKeysByCallId.set(block.compressCallId, keys);
|
|
473
507
|
}
|
|
508
|
+
keys.add(rangeKey(block.startRef, block.endRef));
|
|
474
509
|
}
|
|
475
510
|
const lastOrphanedCallIds = [];
|
|
476
511
|
for (let i = messages.length - 1; i >= 0 && lastOrphanedCallIds.length < KEEP_LAST_ORPHANED; i--) {
|
|
@@ -499,6 +534,16 @@ function hideConsumedCompressCalls(state, messages) {
|
|
|
499
534
|
hidden++;
|
|
500
535
|
continue;
|
|
501
536
|
}
|
|
537
|
+
if (message.toolName === "compress" && message.contentType === "tool-call" && message.toolCallId && keepCallIds.has(message.toolCallId)) {
|
|
538
|
+
const liveKeys = liveRangeKeysByCallId.get(message.toolCallId);
|
|
539
|
+
if (liveKeys && liveKeys.size > 0 && !legacyLiveByCallId.has(message.toolCallId)) {
|
|
540
|
+
const rewritten = rewriteCompressText(message.text, liveKeys);
|
|
541
|
+
if (rewritten !== null) {
|
|
542
|
+
result.push({ ...message, text: rewritten });
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
502
547
|
result.push(message);
|
|
503
548
|
}
|
|
504
549
|
return { messages: result, hidden };
|
|
@@ -732,8 +777,8 @@ function refNum(ref) {
|
|
|
732
777
|
const n = parseInt(ref.slice(1), 10);
|
|
733
778
|
return Number.isNaN(n) ? -1 : n;
|
|
734
779
|
}
|
|
735
|
-
function
|
|
736
|
-
return Math.ceil(
|
|
780
|
+
function estimateTextTokens(text) {
|
|
781
|
+
return Math.ceil(text.length / 4);
|
|
737
782
|
}
|
|
738
783
|
function isToolMessage(message) {
|
|
739
784
|
return message.contentType === "tool-call" || message.contentType === "tool-result";
|
|
@@ -745,7 +790,7 @@ function isSyntheticOrPruned(message, state) {
|
|
|
745
790
|
}
|
|
746
791
|
return false;
|
|
747
792
|
}
|
|
748
|
-
function computeProtectedRefs(messages, state, config) {
|
|
793
|
+
function computeProtectedRefs(messages, state, config, countTokens = estimateTextTokens) {
|
|
749
794
|
const preserveN = config.preserveRecentMessages;
|
|
750
795
|
const preserveTokens = config.preserveRecentTokens;
|
|
751
796
|
const result = /* @__PURE__ */ new Set();
|
|
@@ -755,7 +800,7 @@ function computeProtectedRefs(messages, state, config) {
|
|
|
755
800
|
if (isNeverPreserveRecent(msg)) continue;
|
|
756
801
|
const ref = state.messageRefs.byRaw[msg.id];
|
|
757
802
|
if (!ref || ref === "BLOCKED") continue;
|
|
758
|
-
visible.push({ ref, tokens:
|
|
803
|
+
visible.push({ ref, tokens: countTokens(msg.text ?? "") });
|
|
759
804
|
}
|
|
760
805
|
if (preserveN > 0) {
|
|
761
806
|
for (const m of visible.slice(-preserveN)) {
|
|
@@ -780,7 +825,7 @@ function computeProtectedRefs(messages, state, config) {
|
|
|
780
825
|
}
|
|
781
826
|
return result;
|
|
782
827
|
}
|
|
783
|
-
function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
828
|
+
function buildCompressibleRanges(messages, state, config, protectedZoneRefs, countTokens = estimateTextTokens) {
|
|
784
829
|
const compressibleMsgs = [];
|
|
785
830
|
const protectedMsgs = [];
|
|
786
831
|
const protectedCallIds = collectProtectedToolCallIds(messages, config);
|
|
@@ -793,7 +838,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
|
793
838
|
protectedMsgs.push({
|
|
794
839
|
ref,
|
|
795
840
|
refNum: rn,
|
|
796
|
-
tokens:
|
|
841
|
+
tokens: countTokens(msg.text ?? ""),
|
|
797
842
|
tools: msg.toolName ? [msg.toolName] : []
|
|
798
843
|
});
|
|
799
844
|
continue;
|
|
@@ -804,7 +849,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
|
804
849
|
compressibleMsgs.push({
|
|
805
850
|
ref,
|
|
806
851
|
refNum: rn,
|
|
807
|
-
tokens:
|
|
852
|
+
tokens: countTokens(msg.text ?? ""),
|
|
808
853
|
isTool: isToolMessage(msg),
|
|
809
854
|
isUser: msg.role === "user"
|
|
810
855
|
});
|
|
@@ -891,7 +936,7 @@ function createCore(ports = {}) {
|
|
|
891
936
|
let tokensCompressed = 0;
|
|
892
937
|
const errors = [];
|
|
893
938
|
const warnings = [];
|
|
894
|
-
const protectedMessageIds = input.protectedMessageIds ?? computeProtectedRefs(input.messages, input.state, input.config);
|
|
939
|
+
const protectedMessageIds = input.protectedMessageIds ?? computeProtectedRefs(input.messages, input.state, input.config, countTokens);
|
|
895
940
|
const preExistingCoverage = collectCoverage(state);
|
|
896
941
|
const rangeIndexSets = [];
|
|
897
942
|
for (const spec of input.ranges) {
|
|
@@ -916,29 +961,25 @@ function createCore(ports = {}) {
|
|
|
916
961
|
const bMin = b.indices.length > 0 ? Math.min(...b.indices) : Infinity;
|
|
917
962
|
return aMin - bMin;
|
|
918
963
|
});
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
const
|
|
923
|
-
const
|
|
924
|
-
if (
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
errors: [
|
|
931
|
-
`content: range (${prev.spec.startRef}..${prev.spec.endRef}) overlaps (${curr.spec.startRef}..${curr.spec.endRef}). Overlapping ranges cannot be compressed in the same batch.`
|
|
932
|
-
],
|
|
933
|
-
warnings: []
|
|
934
|
-
}
|
|
935
|
-
};
|
|
964
|
+
const skipSpecs = /* @__PURE__ */ new Set();
|
|
965
|
+
let acceptedMaxIndex = -1;
|
|
966
|
+
for (const entry of sortedRanges) {
|
|
967
|
+
const entryMax = entry.indices.length > 0 ? Math.max(...entry.indices) : -1;
|
|
968
|
+
const entryMin = entry.indices.length > 0 ? Math.min(...entry.indices) : -1;
|
|
969
|
+
if (entryMin >= 0 && entryMin <= acceptedMaxIndex) {
|
|
970
|
+
skipSpecs.add(entry.spec);
|
|
971
|
+
warnings.push(
|
|
972
|
+
`Skipped range (${entry.spec.startRef}..${entry.spec.endRef}) \u2014 overlaps an earlier range in the batch; the earlier range takes precedence. Keep ranges disjoint.`
|
|
973
|
+
);
|
|
974
|
+
continue;
|
|
936
975
|
}
|
|
976
|
+
if (entryMax > acceptedMaxIndex) acceptedMaxIndex = entryMax;
|
|
937
977
|
}
|
|
938
978
|
if (input.config.compress.minCompressRange > 0 && input.ranges.length > 0) {
|
|
939
979
|
let totalRangeChars = 0;
|
|
940
980
|
let hasBlockBoundaryRange = false;
|
|
941
981
|
for (const spec of input.ranges) {
|
|
982
|
+
if (skipSpecs.has(spec)) continue;
|
|
942
983
|
let resolved;
|
|
943
984
|
try {
|
|
944
985
|
resolved = resolveBoundaries({
|
|
@@ -974,6 +1015,7 @@ function createCore(ports = {}) {
|
|
|
974
1015
|
}
|
|
975
1016
|
}
|
|
976
1017
|
for (const spec of input.ranges) {
|
|
1018
|
+
if (skipSpecs.has(spec)) continue;
|
|
977
1019
|
try {
|
|
978
1020
|
const outcome = applySingleRange({
|
|
979
1021
|
spec,
|
|
@@ -1114,13 +1156,15 @@ var recommendNode = {
|
|
|
1114
1156
|
const protectedRefs = computeProtectedRefs(
|
|
1115
1157
|
io.messages,
|
|
1116
1158
|
io.state,
|
|
1117
|
-
ctx.config
|
|
1159
|
+
ctx.config,
|
|
1160
|
+
ctx.countTokens
|
|
1118
1161
|
);
|
|
1119
1162
|
const contextRanges = buildCompressibleRanges(
|
|
1120
1163
|
io.messages,
|
|
1121
1164
|
io.state,
|
|
1122
1165
|
ctx.config,
|
|
1123
|
-
protectedRefs
|
|
1166
|
+
protectedRefs,
|
|
1167
|
+
ctx.countTokens
|
|
1124
1168
|
);
|
|
1125
1169
|
const nothingToCompress = contextRanges.compressible.length === 0;
|
|
1126
1170
|
const recommendation = {
|
|
@@ -1298,7 +1342,9 @@ function applySingleRange(input) {
|
|
|
1298
1342
|
survivedCount: 0,
|
|
1299
1343
|
generation: "young",
|
|
1300
1344
|
active: true,
|
|
1301
|
-
compressCallId: input.spec.compressCallId
|
|
1345
|
+
compressCallId: input.spec.compressCallId,
|
|
1346
|
+
startRef: input.spec.startRef,
|
|
1347
|
+
endRef: input.spec.endRef
|
|
1302
1348
|
};
|
|
1303
1349
|
input.state.blocks.push(block);
|
|
1304
1350
|
for (const consumedId of consumedBlockIds) {
|
|
@@ -1789,7 +1835,7 @@ function renderNudgeText(decision) {
|
|
|
1789
1835
|
breakdownStr,
|
|
1790
1836
|
"",
|
|
1791
1837
|
`[TIER ${decision.tier} ${isT2 ? "DISTILLATION" : "CONDENSATION"} TRIGGER]`,
|
|
1792
|
-
isT2 ? `Your tier-1 compression summaries have accumulated. Distill them into a single denser tier-2 summary. Use block IDs as boundaries.` : `Your tier-2 compression summaries have accumulated. Condense them further into a tier-3 ultra-condensed summary. Use block IDs as boundaries.`,
|
|
1838
|
+
isT2 ? `Your tier-1 compression summaries have accumulated. Distill them into a single denser tier-2 summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-2 block as well \u2014 apply HOW TO COMPRESS to those raw messages and the TIER 2 distillation rules to the existing summaries, so the whole span is covered and nothing is lost.` : `Your tier-2 compression summaries have accumulated. Condense them further into a tier-3 ultra-condensed summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-3 block as well \u2014 apply HOW TO COMPRESS to those raw messages and the TIER 3 condensation rules to the existing summaries, so the whole span is covered and nothing is lost.`,
|
|
1793
1839
|
blockList,
|
|
1794
1840
|
`Example: compress({ content: [{ startId: "${startId}", endId: "${endId}", summary: "..." }] })`,
|
|
1795
1841
|
"",
|
|
@@ -2537,6 +2583,15 @@ function patchRefTag(original, core) {
|
|
|
2537
2583
|
if (!tag) return original;
|
|
2538
2584
|
const base = original;
|
|
2539
2585
|
if (base.role === "assistant") return original;
|
|
2586
|
+
const tagCore = tag.replace(/\s+$/, "");
|
|
2587
|
+
let bodyStart = tagCore.length;
|
|
2588
|
+
if (core.text && core.text.charAt(bodyStart) === "\n") bodyStart += 1;
|
|
2589
|
+
const coreBody = core.text ? core.text.slice(bodyStart) : "";
|
|
2590
|
+
const originalBody = extractText(base.content);
|
|
2591
|
+
const trimEnd = (s) => s.replace(/\s+$/, "");
|
|
2592
|
+
if (coreBody && trimEnd(coreBody) !== trimEnd(originalBody)) {
|
|
2593
|
+
return rebuildBodyFromCore(original, coreBody, tag);
|
|
2594
|
+
}
|
|
2540
2595
|
const rawBlocks = Array.isArray(base.content) ? base.content : typeof base.content === "string" ? [{ type: "text", text: base.content }] : [];
|
|
2541
2596
|
const peeled = peelRefTagBlocks(rawBlocks);
|
|
2542
2597
|
const newBlocks = [...peeled];
|
|
@@ -2560,6 +2615,23 @@ ${tag}` : tag };
|
|
|
2560
2615
|
content: [...peeled, { type: "text", text: tag }]
|
|
2561
2616
|
};
|
|
2562
2617
|
}
|
|
2618
|
+
function rebuildBodyFromCore(original, coreBody, tag) {
|
|
2619
|
+
const base = original;
|
|
2620
|
+
const text = `${coreBody.replace(/\s+$/, "")}
|
|
2621
|
+
|
|
2622
|
+
${tag}`;
|
|
2623
|
+
if (typeof base.content === "string") {
|
|
2624
|
+
return { ...original, content: text };
|
|
2625
|
+
}
|
|
2626
|
+
if (Array.isArray(base.content)) {
|
|
2627
|
+
const nonText = base.content.filter((b) => b.type !== "text");
|
|
2628
|
+
return {
|
|
2629
|
+
...original,
|
|
2630
|
+
content: [...nonText, { type: "text", text }]
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
return { ...original, content: [{ type: "text", text }] };
|
|
2634
|
+
}
|
|
2563
2635
|
function peelRefTagBlocks(blocks) {
|
|
2564
2636
|
const out = [];
|
|
2565
2637
|
for (const block of blocks) {
|
|
@@ -8718,7 +8790,7 @@ async function statusReport(runtime, ctx) {
|
|
|
8718
8790
|
const activeBlocksList = state.blocks.filter((b) => b.active);
|
|
8719
8791
|
const totalBlocksList = state.blocks;
|
|
8720
8792
|
const lines = [];
|
|
8721
|
-
const versionStr = "0.1.
|
|
8793
|
+
const versionStr = "0.1.32" ? `billion-context-pi@${"0.1.32"}` : "";
|
|
8722
8794
|
lines.push("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E");
|
|
8723
8795
|
lines.push("\u2502 ACP Context Analysis \u2502");
|
|
8724
8796
|
lines.push("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F");
|
|
@@ -9084,7 +9156,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
9084
9156
|
const data = await res.json();
|
|
9085
9157
|
const latest = data.version;
|
|
9086
9158
|
if (!latest) return;
|
|
9087
|
-
const current = runtimeVersion ?? "0.1.
|
|
9159
|
+
const current = runtimeVersion ?? "0.1.32";
|
|
9088
9160
|
const hasUpdate = isNewer(latest, current);
|
|
9089
9161
|
debug.event("update-check", {
|
|
9090
9162
|
current,
|
|
@@ -9323,7 +9395,7 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
9323
9395
|
runtime.store.invalidate();
|
|
9324
9396
|
runtime.clearNudgeTracking();
|
|
9325
9397
|
const sid = ctx.sessionManager.getSessionId();
|
|
9326
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.
|
|
9398
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.32" : null });
|
|
9327
9399
|
try {
|
|
9328
9400
|
const user = await loadUserConfig(ctx.cwd);
|
|
9329
9401
|
runtime.setAdapter(applyUserConfig(runtime.adapter, user));
|