billion-context-pi 0.1.37 → 0.1.39
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/README.md +2 -51
- package/README.zh-CN.md +2 -51
- package/dist/config.d.ts +33 -4
- package/dist/density.d.ts +19 -0
- package/dist/index.js +503 -198
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +12 -0
- package/dist/tokens.d.ts +6 -0
- package/package.json +8 -2
package/dist/index.js
CHANGED
|
@@ -76,6 +76,7 @@ function createInitialState() {
|
|
|
76
76
|
return {
|
|
77
77
|
blocks: [],
|
|
78
78
|
messageRefs: { byRaw: {}, byRef: {} },
|
|
79
|
+
tokenSnapshot: {},
|
|
79
80
|
nudge: {
|
|
80
81
|
lastPerMessageNudgeTokens: 0,
|
|
81
82
|
lastNudgeShownTokens: 0,
|
|
@@ -245,11 +246,23 @@ function syncBlocks(messages, state) {
|
|
|
245
246
|
byRaw: { ...state.messageRefs.byRaw },
|
|
246
247
|
byRef: { ...state.messageRefs.byRef }
|
|
247
248
|
},
|
|
249
|
+
// Snapshot is keyed by ref with primitive values — shallow copy suffices.
|
|
250
|
+
tokenSnapshot: { ...state.tokenSnapshot ?? {} },
|
|
248
251
|
nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
|
|
249
252
|
stats: { ...state.stats },
|
|
250
253
|
nextBlockId: state.nextBlockId,
|
|
251
254
|
nextRunId: state.nextRunId
|
|
252
255
|
};
|
|
256
|
+
const liveRefs = new Set(
|
|
257
|
+
messages.map((m) => result.messageRefs.byRaw[m.id]).filter((r) => typeof r === "string")
|
|
258
|
+
);
|
|
259
|
+
if (Object.keys(result.tokenSnapshot).length !== liveRefs.size) {
|
|
260
|
+
const pruned = {};
|
|
261
|
+
for (const [ref, n] of Object.entries(result.tokenSnapshot)) {
|
|
262
|
+
if (liveRefs.has(ref)) pruned[ref] = n;
|
|
263
|
+
}
|
|
264
|
+
result.tokenSnapshot = pruned;
|
|
265
|
+
}
|
|
253
266
|
const consumedBlockIds = /* @__PURE__ */ new Set();
|
|
254
267
|
for (const block of result.blocks) {
|
|
255
268
|
for (const consumedId of block.directBlockIds) {
|
|
@@ -293,7 +306,8 @@ function defaultConfig(modelContextLimit, overrides = {}) {
|
|
|
293
306
|
growthCap: 5e4,
|
|
294
307
|
minGrowthFloor: 2e4,
|
|
295
308
|
minGrowthRatio: 0.45,
|
|
296
|
-
emergencyThresholdPct: 0.95
|
|
309
|
+
emergencyThresholdPct: 0.95,
|
|
310
|
+
tier2GrowthMultiplier: 1.5
|
|
297
311
|
},
|
|
298
312
|
promotionThreshold: 5,
|
|
299
313
|
truncate: { threshold: 0.95 },
|
|
@@ -723,7 +737,7 @@ var TAG_CLOSE = LT + "/acp" + GT;
|
|
|
723
737
|
function acpTag(ref, tokens, type) {
|
|
724
738
|
return TAG_OPEN + 'tokens="' + formatTokens(tokens) + '" type="' + type + '"' + GT + ref + TAG_CLOSE;
|
|
725
739
|
}
|
|
726
|
-
function renderMessage(message, map, countTokens, strategy) {
|
|
740
|
+
function renderMessage(message, map, countTokens, strategy, snapshot = null) {
|
|
727
741
|
const ref = refForRaw(map, message.id);
|
|
728
742
|
if (!ref || ref === BLOCKED_REF) return message;
|
|
729
743
|
if (strategy === "none") return message;
|
|
@@ -734,26 +748,33 @@ function renderMessage(message, map, countTokens, strategy) {
|
|
|
734
748
|
"^" + escapeRegex(TAG_OPEN) + "[^>]*" + GT + escapeRegex(ref) + escapeRegex(TAG_CLOSE) + "\\n?"
|
|
735
749
|
);
|
|
736
750
|
const cleanText = (message.text || "").replace(ownTagRe, "");
|
|
737
|
-
const tokens = countTokens(cleanText);
|
|
751
|
+
const tokens = snapshot ? snapshot[ref] ?? (snapshot[ref] = countTokens(cleanText)) : countTokens(cleanText);
|
|
738
752
|
const type = classifyType(message);
|
|
739
753
|
const prefix = acpTag(ref, tokens, type) + "\n";
|
|
740
754
|
if (!cleanText) return { ...message, text: prefix };
|
|
741
755
|
return { ...message, text: prefix + cleanText };
|
|
742
756
|
}
|
|
743
|
-
function
|
|
757
|
+
function renderWithSnapshot(messages, state, countTokens = (text) => Math.ceil(text.length / 4), strategy = "all") {
|
|
744
758
|
const map = state.messageRefs;
|
|
745
|
-
|
|
746
|
-
|
|
759
|
+
const snapshot = { ...state.tokenSnapshot ?? {} };
|
|
760
|
+
const rendered = messages.map(
|
|
761
|
+
(message) => renderMessage(message, map, countTokens, strategy, snapshot)
|
|
747
762
|
);
|
|
763
|
+
return { messages: rendered, tokenSnapshot: snapshot };
|
|
748
764
|
}
|
|
749
765
|
function createRenderRefsNode(strategy) {
|
|
750
766
|
return {
|
|
751
767
|
name: "render-refs",
|
|
752
768
|
run(io, ctx) {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
769
|
+
const { messages, tokenSnapshot } = renderWithSnapshot(
|
|
770
|
+
io.messages,
|
|
771
|
+
io.state,
|
|
772
|
+
ctx.countTokens,
|
|
773
|
+
strategy
|
|
774
|
+
);
|
|
775
|
+
const prev = io.state.tokenSnapshot;
|
|
776
|
+
const changed = !prev || Object.keys(tokenSnapshot).length !== Object.keys(prev).length;
|
|
777
|
+
return changed ? { ...io, messages, state: { ...io.state, tokenSnapshot } } : { ...io, messages };
|
|
757
778
|
}
|
|
758
779
|
};
|
|
759
780
|
}
|
|
@@ -949,6 +970,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
|
|
|
949
970
|
ref,
|
|
950
971
|
refNum: rn,
|
|
951
972
|
tokens: countTokens(msg.text ?? ""),
|
|
973
|
+
chars: (msg.text ?? "").length,
|
|
952
974
|
isTool: isToolMessage(msg),
|
|
953
975
|
isUser: msg.role === "user"
|
|
954
976
|
});
|
|
@@ -969,6 +991,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
|
|
|
969
991
|
endRef: info.ref,
|
|
970
992
|
count: 1,
|
|
971
993
|
tokens: info.tokens,
|
|
994
|
+
chars: info.chars,
|
|
972
995
|
toolPct: info.isTool ? 100 : 0,
|
|
973
996
|
textPct: info.isTool ? 0 : 100
|
|
974
997
|
};
|
|
@@ -976,6 +999,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
|
|
|
976
999
|
cur.endRef = info.ref;
|
|
977
1000
|
cur.count++;
|
|
978
1001
|
cur.tokens += info.tokens;
|
|
1002
|
+
cur.chars = (cur.chars ?? 0) + info.chars;
|
|
979
1003
|
if (info.isTool) {
|
|
980
1004
|
cur.toolPct = Math.round((cur.toolPct * (cur.count - 1) + 100) / cur.count);
|
|
981
1005
|
} else {
|
|
@@ -1018,6 +1042,51 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
|
|
|
1018
1042
|
protected: protectedRanges
|
|
1019
1043
|
};
|
|
1020
1044
|
}
|
|
1045
|
+
function mergeBatch(batch) {
|
|
1046
|
+
const first = batch[0];
|
|
1047
|
+
const last = batch[batch.length - 1];
|
|
1048
|
+
const count = batch.reduce((s, r) => s + r.count, 0);
|
|
1049
|
+
const tokens = batch.reduce((s, r) => s + r.tokens, 0);
|
|
1050
|
+
const chars = batch.reduce((s, r) => s + rangeChars(r), 0);
|
|
1051
|
+
const toolPct = Math.round(
|
|
1052
|
+
batch.reduce((s, r) => s + r.toolPct * r.count, 0) / count
|
|
1053
|
+
);
|
|
1054
|
+
const merged = {
|
|
1055
|
+
startRef: first.startRef,
|
|
1056
|
+
endRef: last.endRef,
|
|
1057
|
+
count,
|
|
1058
|
+
tokens,
|
|
1059
|
+
chars,
|
|
1060
|
+
toolPct,
|
|
1061
|
+
textPct: 100 - toolPct
|
|
1062
|
+
};
|
|
1063
|
+
if (batch.some((r) => r.dangerous === true)) {
|
|
1064
|
+
merged.dangerous = true;
|
|
1065
|
+
}
|
|
1066
|
+
return merged;
|
|
1067
|
+
}
|
|
1068
|
+
function rangeChars(r) {
|
|
1069
|
+
return r.chars ?? r.tokens * 4;
|
|
1070
|
+
}
|
|
1071
|
+
function mergeRangesToThreshold(ranges, minChars) {
|
|
1072
|
+
if (minChars <= 0 || ranges.length === 0) return ranges;
|
|
1073
|
+
const result = [];
|
|
1074
|
+
let batch = [];
|
|
1075
|
+
let batchChars = 0;
|
|
1076
|
+
for (const r of ranges) {
|
|
1077
|
+
batch.push(r);
|
|
1078
|
+
batchChars += rangeChars(r);
|
|
1079
|
+
if (batchChars >= minChars) {
|
|
1080
|
+
result.push(mergeBatch(batch));
|
|
1081
|
+
batch = [];
|
|
1082
|
+
batchChars = 0;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
if (batch.length > 0) {
|
|
1086
|
+
result.push(mergeBatch(batch));
|
|
1087
|
+
}
|
|
1088
|
+
return result;
|
|
1089
|
+
}
|
|
1021
1090
|
function runPipeline(nodes, initial, ctx) {
|
|
1022
1091
|
let io = initial;
|
|
1023
1092
|
for (const node of nodes) {
|
|
@@ -1297,7 +1366,10 @@ var recommendNode = {
|
|
|
1297
1366
|
const nothingToCompress = contextRanges.compressible.length === 0;
|
|
1298
1367
|
const recommendation = {
|
|
1299
1368
|
contextRanges,
|
|
1300
|
-
recommendedRanges:
|
|
1369
|
+
recommendedRanges: mergeRangesToThreshold(
|
|
1370
|
+
contextRanges.compressible,
|
|
1371
|
+
ctx.config.compress.minCompressRange
|
|
1372
|
+
),
|
|
1301
1373
|
nothingToCompress
|
|
1302
1374
|
};
|
|
1303
1375
|
return { ...io, effects: { ...io.effects, recommendation } };
|
|
@@ -1323,6 +1395,7 @@ var nudgeNode = {
|
|
|
1323
1395
|
if (baseline > 0 && ctx.tokenCount < baseline - nudgeGrowthTokens) {
|
|
1324
1396
|
stamped.lastPerMessageNudgeTokens = ctx.tokenCount;
|
|
1325
1397
|
stamped.lastNudgeShownTokens = 0;
|
|
1398
|
+
stamped.lastShownByTier = {};
|
|
1326
1399
|
}
|
|
1327
1400
|
if (stamped.lastPerMessageNudgeTokens === 0) {
|
|
1328
1401
|
stamped.lastPerMessageNudgeTokens = ctx.tokenCount;
|
|
@@ -1591,10 +1664,11 @@ function resolveAdaptiveGrowth(modelContextLimit, nudge) {
|
|
|
1591
1664
|
)
|
|
1592
1665
|
);
|
|
1593
1666
|
}
|
|
1594
|
-
function pendingByTier(state, recommendation, countTokens) {
|
|
1667
|
+
function pendingByTier(state, recommendation, countTokens, minCompressRange) {
|
|
1595
1668
|
const out = {};
|
|
1596
|
-
const
|
|
1597
|
-
|
|
1669
|
+
const merged = recommendation?.recommendedRanges ?? [];
|
|
1670
|
+
const effective = minCompressRange > 0 ? merged.filter((r) => (r.chars ?? r.tokens * 4) >= minCompressRange) : merged;
|
|
1671
|
+
out[1] = { pending: effective.reduce((s, r) => s + r.tokens, 0), targetBlocks: [] };
|
|
1598
1672
|
const active = activeBlocks(state);
|
|
1599
1673
|
const t1 = active.filter((b) => b.tier === 1);
|
|
1600
1674
|
const t2 = active.filter((b) => b.tier === 2);
|
|
@@ -1609,6 +1683,7 @@ function decideNudge(input) {
|
|
|
1609
1683
|
const nudgeGrowthTokens = resolveAdaptiveGrowth(limit, config.nudge);
|
|
1610
1684
|
const overLimit = usage >= config.nudge.maxContextLimitPct;
|
|
1611
1685
|
const emergencyOverride = usage >= config.nudge.emergencyThresholdPct;
|
|
1686
|
+
const pressure = overLimit || emergencyOverride;
|
|
1612
1687
|
const baseline = state.nudge.lastPerMessageNudgeTokens;
|
|
1613
1688
|
const hadPendingNudge = state.nudge.lastNudgeShownTokens > 0;
|
|
1614
1689
|
const hasPendingNudge = hadPendingNudge;
|
|
@@ -1620,44 +1695,67 @@ function decideNudge(input) {
|
|
|
1620
1695
|
);
|
|
1621
1696
|
const growthSinceReference = tokenCount - growthReference;
|
|
1622
1697
|
const rec = recommendation;
|
|
1623
|
-
const tiers = pendingByTier(
|
|
1698
|
+
const tiers = pendingByTier(
|
|
1699
|
+
state,
|
|
1700
|
+
rec,
|
|
1701
|
+
countTokens,
|
|
1702
|
+
config.compress.minCompressRange
|
|
1703
|
+
);
|
|
1704
|
+
const tier2Threshold = Math.round(
|
|
1705
|
+
nudgeGrowthTokens * (config.nudge.tier2GrowthMultiplier ?? 1.5)
|
|
1706
|
+
);
|
|
1624
1707
|
let injectedTier = null;
|
|
1625
1708
|
let injectedReason = "";
|
|
1626
1709
|
const growthReady = growthSinceReference >= growthFloor;
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1710
|
+
const t1Eff = tiers[1]?.pending ?? 0;
|
|
1711
|
+
const t2Pen = tiers[2]?.pending ?? 0;
|
|
1712
|
+
const t3Pen = tiers[3]?.pending ?? 0;
|
|
1713
|
+
if (pressure) {
|
|
1714
|
+
const candidates = [1];
|
|
1715
|
+
if (config.tiers.enabled) {
|
|
1716
|
+
candidates.push(2, 3);
|
|
1717
|
+
}
|
|
1718
|
+
let best = null;
|
|
1719
|
+
let bestPending = 0;
|
|
1720
|
+
for (const t of candidates) {
|
|
1721
|
+
const p = tiers[t]?.pending ?? 0;
|
|
1722
|
+
if (p > bestPending) {
|
|
1723
|
+
bestPending = p;
|
|
1724
|
+
best = t;
|
|
1725
|
+
}
|
|
1638
1726
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1727
|
+
if (best !== null && bestPending > 0) {
|
|
1728
|
+
injectedTier = best;
|
|
1729
|
+
const label = emergencyOverride ? "EMERGENCY" : "OVER-LIMIT";
|
|
1730
|
+
injectedReason = best === 1 ? `${label} T1: max effective pending ${bestPending}, usage ${Math.round(usage * 100)}%` : `${label} T${best} distill: max pending ${bestPending} (T1 effective ${t1Eff}, T2 ${t2Pen}, T3 ${t3Pen}), usage ${Math.round(usage * 100)}%`;
|
|
1731
|
+
}
|
|
1732
|
+
} else if (growthReady) {
|
|
1733
|
+
if (t1Eff >= nudgeGrowthTokens) {
|
|
1734
|
+
injectedTier = 1;
|
|
1735
|
+
injectedReason = `T1 effective ${t1Eff} >= ${nudgeGrowthTokens}, growth ${growthSinceReference}, usage ${Math.round(usage * 100)}%`;
|
|
1736
|
+
} else if (config.tiers.enabled && t2Pen >= tier2Threshold && t2Pen > t1Eff) {
|
|
1737
|
+
const lastShown = state.nudge.lastShownByTier[2] ?? 0;
|
|
1738
|
+
const cadenceMet = lastShown === 0 || tokenCount - lastShown >= growthFloor;
|
|
1739
|
+
if (cadenceMet) {
|
|
1740
|
+
injectedTier = 2;
|
|
1741
|
+
injectedReason = `T2 distill ready: ${tiers[2].targetBlocks.length} tier-1 blocks (${t2Pen} tokens) >= ${tier2Threshold} (1.5x) and > T1 effective ${t1Eff}, usage ${Math.round(usage * 100)}%`;
|
|
1742
|
+
}
|
|
1743
|
+
} else if (config.tiers.enabled && t3Pen >= tier2Threshold && t3Pen > t2Pen && t3Pen > t1Eff) {
|
|
1744
|
+
const lastShown = state.nudge.lastShownByTier[3] ?? 0;
|
|
1745
|
+
const cadenceMet = lastShown === 0 || tokenCount - lastShown >= growthFloor;
|
|
1746
|
+
if (cadenceMet) {
|
|
1747
|
+
injectedTier = 3;
|
|
1748
|
+
injectedReason = `T3 condense ready: ${tiers[3].targetBlocks.length} tier-2 blocks (${t3Pen} tokens) >= ${tier2Threshold} (1.5x) and > T2 ${t2Pen} and > T1 effective ${t1Eff}, usage ${Math.round(usage * 100)}%`;
|
|
1749
|
+
}
|
|
1647
1750
|
}
|
|
1648
1751
|
}
|
|
1649
|
-
const shouldInject = injectedTier !== null
|
|
1752
|
+
const shouldInject = injectedTier !== null;
|
|
1650
1753
|
let reason;
|
|
1651
|
-
if (
|
|
1652
|
-
reason = injectedReason;
|
|
1653
|
-
} else if (emergencyOverride) {
|
|
1654
|
-
reason = `EMERGENCY: usage ${Math.round(usage * 100)}% >= ${Math.round(config.nudge.emergencyThresholdPct * 100)}% (no compressible content)`;
|
|
1655
|
-
} else if (overLimit && injectedTier !== null) {
|
|
1656
|
-
reason = injectedReason;
|
|
1657
|
-
} else if (overLimit) {
|
|
1658
|
-
reason = `OVER-LIMIT: usage ${Math.round(usage * 100)}% >= ${Math.round(config.nudge.maxContextLimitPct * 100)}% (no compressible content)`;
|
|
1659
|
-
} else if (injectedTier !== null) {
|
|
1754
|
+
if (injectedTier !== null) {
|
|
1660
1755
|
reason = injectedReason;
|
|
1756
|
+
} else if (pressure) {
|
|
1757
|
+
const label = emergencyOverride ? "EMERGENCY" : "OVER-LIMIT";
|
|
1758
|
+
reason = `${label}: usage ${Math.round(usage * 100)}% but no tier has effective compressible content (T1 effective ${t1Eff}, T2 ${t2Pen}, T3 ${t3Pen}) \u2014 nudge suppressed to avoid offering ranges below minCompressRange`;
|
|
1661
1759
|
} else {
|
|
1662
1760
|
const tiersList = [1, 2, 3];
|
|
1663
1761
|
const eligible = tiersList.filter((t) => config.tiers.enabled || t === 1);
|
|
@@ -1731,6 +1829,7 @@ function cloneState(state) {
|
|
|
1731
1829
|
byRaw: { ...state.messageRefs.byRaw },
|
|
1732
1830
|
byRef: { ...state.messageRefs.byRef }
|
|
1733
1831
|
},
|
|
1832
|
+
tokenSnapshot: { ...state.tokenSnapshot ?? {} },
|
|
1734
1833
|
nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
|
|
1735
1834
|
stats: { ...state.stats },
|
|
1736
1835
|
nextBlockId: state.nextBlockId,
|
|
@@ -2006,20 +2105,23 @@ ${lines.join("\n")}`;
|
|
|
2006
2105
|
function renderNudgeText(decision, prompts = defaultPrompts) {
|
|
2007
2106
|
const breakdownStr = formatBreakdown(decision.contextBreakdown);
|
|
2008
2107
|
const rangesStr = formatRanges(decision.compressibleRanges, decision.protectedRanges ?? []);
|
|
2108
|
+
const isEmergency = !!decision.breakdown?.emergencyOverride || !!decision.breakdown?.overLimit;
|
|
2009
2109
|
if (decision.tier !== null && decision.tier >= 2) {
|
|
2010
2110
|
const isT2 = decision.tier === 2;
|
|
2011
2111
|
const targets = decision.tierTargetBlocks ?? [];
|
|
2012
2112
|
const blockList = formatTierTargetBlocks(targets);
|
|
2013
2113
|
const startId = targets[0]?.blockId ?? "b1";
|
|
2014
2114
|
const endId = targets[targets.length - 1]?.blockId ?? "b5";
|
|
2115
|
+
const voice = isEmergency ? "emergency" : "gentle";
|
|
2116
|
+
const triggerLine = isEmergency ? `[EMERGENCY \u2014 TIER ${decision.tier} ${isT2 ? "DISTILLATION" : "CONDENSATION"}] Context limit reached \u2014 distill NOW into a denser summary to reclaim tokens.` : `[TIER ${decision.tier} ${isT2 ? "DISTILLATION" : "CONDENSATION"} TRIGGER]`;
|
|
2015
2117
|
return {
|
|
2016
|
-
voice
|
|
2118
|
+
voice,
|
|
2017
2119
|
text: [
|
|
2018
2120
|
efficiencyNote(prompts),
|
|
2019
2121
|
"",
|
|
2020
2122
|
breakdownStr,
|
|
2021
2123
|
"",
|
|
2022
|
-
|
|
2124
|
+
triggerLine,
|
|
2023
2125
|
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.`,
|
|
2024
2126
|
blockList,
|
|
2025
2127
|
`Example: compress({ content: [{ startId: "${startId}", endId: "${endId}", summary: "..." }] })`,
|
|
@@ -2030,7 +2132,6 @@ function renderNudgeText(decision, prompts = defaultPrompts) {
|
|
|
2030
2132
|
].join("\n")
|
|
2031
2133
|
};
|
|
2032
2134
|
}
|
|
2033
|
-
const isEmergency = !!decision.breakdown?.emergencyOverride || !!decision.breakdown?.overLimit;
|
|
2034
2135
|
if (isEmergency) {
|
|
2035
2136
|
return {
|
|
2036
2137
|
voice: "emergency",
|
|
@@ -2601,7 +2702,20 @@ function resolveDelegate(adapter) {
|
|
|
2601
2702
|
displayUsage: adapter.displayUsage ?? "separate"
|
|
2602
2703
|
};
|
|
2603
2704
|
}
|
|
2604
|
-
function
|
|
2705
|
+
function mergeCompress(global, provider, model) {
|
|
2706
|
+
return {
|
|
2707
|
+
maxContextLimit: model?.maxContextLimit ?? provider?.maxContextLimit ?? global?.maxContextLimit,
|
|
2708
|
+
emergencyThresholdPercent: model?.emergencyThresholdPercent ?? provider?.emergencyThresholdPercent ?? global?.emergencyThresholdPercent,
|
|
2709
|
+
nudgeGrowthTokens: model?.nudgeGrowthTokens ?? provider?.nudgeGrowthTokens ?? global?.nudgeGrowthTokens
|
|
2710
|
+
};
|
|
2711
|
+
}
|
|
2712
|
+
function resolveCompress(compress, provider, modelId) {
|
|
2713
|
+
if (!compress) return {};
|
|
2714
|
+
const prov = provider ? compress.providers?.[provider] : void 0;
|
|
2715
|
+
const model = prov && modelId ? prov.models?.[modelId] : void 0;
|
|
2716
|
+
return mergeCompress(compress, prov, model);
|
|
2717
|
+
}
|
|
2718
|
+
function resolveConfig(adapter, liveContextLimit, provider, modelId) {
|
|
2605
2719
|
const envLimit = process.env.ACP_MODEL_CONTEXT_LIMIT;
|
|
2606
2720
|
const envLimitNum = envLimit ? Number(envLimit) : NaN;
|
|
2607
2721
|
const FALLBACK_LIMIT = 15e4;
|
|
@@ -2611,14 +2725,14 @@ function resolveConfig(adapter, liveContextLimit) {
|
|
|
2611
2725
|
preserveRecentMessages: adapter.preserveRecentMessages ?? 5,
|
|
2612
2726
|
...adapter.coreOverrides
|
|
2613
2727
|
});
|
|
2614
|
-
const c = adapter.compress;
|
|
2615
|
-
if (c
|
|
2616
|
-
if (c
|
|
2728
|
+
const c = resolveCompress(adapter.compress, provider, modelId);
|
|
2729
|
+
if (c.maxContextLimit !== void 0) config.nudge.maxContextLimitPct = parsePercent(c.maxContextLimit);
|
|
2730
|
+
if (c.emergencyThresholdPercent !== void 0) {
|
|
2617
2731
|
const pct2 = parsePercent(c.emergencyThresholdPercent);
|
|
2618
2732
|
config.nudge.emergencyThresholdPct = pct2;
|
|
2619
2733
|
config.truncate.threshold = pct2;
|
|
2620
2734
|
}
|
|
2621
|
-
if (c
|
|
2735
|
+
if (c.nudgeGrowthTokens !== void 0) {
|
|
2622
2736
|
config.nudge.growthFloor = c.nudgeGrowthTokens;
|
|
2623
2737
|
config.nudge.growthCap = c.nudgeGrowthTokens;
|
|
2624
2738
|
}
|
|
@@ -2631,6 +2745,89 @@ function parsePercent(v) {
|
|
|
2631
2745
|
return Number(s);
|
|
2632
2746
|
}
|
|
2633
2747
|
|
|
2748
|
+
// src/density.ts
|
|
2749
|
+
var DENSITY_MIN = 0.5;
|
|
2750
|
+
var DENSITY_MAX = 2.5;
|
|
2751
|
+
var MIN_DELTA_EST = 50;
|
|
2752
|
+
var CONFIRM_RATIO = 0.2;
|
|
2753
|
+
var INITIAL_DENSITY = 1;
|
|
2754
|
+
var DensityEstimator = class {
|
|
2755
|
+
models = /* @__PURE__ */ new Map();
|
|
2756
|
+
/** 重置指定模型(模型切换/会话开始时调用)。 */
|
|
2757
|
+
resetModel(modelId) {
|
|
2758
|
+
this.models.delete(modelId);
|
|
2759
|
+
}
|
|
2760
|
+
/** 返回当前密度系数(未知模型返回初始 1)。 */
|
|
2761
|
+
densityFor(modelId) {
|
|
2762
|
+
return this.models.get(modelId)?.density ?? INITIAL_DENSITY;
|
|
2763
|
+
}
|
|
2764
|
+
/**
|
|
2765
|
+
* 每轮 context 事件调用。realTotal 为 provider 真实 usage(可空),
|
|
2766
|
+
* estTotal 为本地估算总 token。postCompression 为压缩刚发生标志。
|
|
2767
|
+
*/
|
|
2768
|
+
update(modelId, realTotal, estTotal, postCompression = false) {
|
|
2769
|
+
if (realTotal === null) return;
|
|
2770
|
+
let est = this.models.get(modelId);
|
|
2771
|
+
if (!est) {
|
|
2772
|
+
est = {
|
|
2773
|
+
density: INITIAL_DENSITY,
|
|
2774
|
+
anchorReal: null,
|
|
2775
|
+
anchorEst: null,
|
|
2776
|
+
pendingDensity: null,
|
|
2777
|
+
confirmCount: 0,
|
|
2778
|
+
postCompressionSkip: false
|
|
2779
|
+
};
|
|
2780
|
+
this.models.set(modelId, est);
|
|
2781
|
+
}
|
|
2782
|
+
if (postCompression) {
|
|
2783
|
+
est.postCompressionSkip = true;
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
if (est.postCompressionSkip) {
|
|
2787
|
+
est.postCompressionSkip = false;
|
|
2788
|
+
est.anchorReal = realTotal;
|
|
2789
|
+
est.anchorEst = estTotal;
|
|
2790
|
+
est.pendingDensity = null;
|
|
2791
|
+
est.confirmCount = 0;
|
|
2792
|
+
return;
|
|
2793
|
+
}
|
|
2794
|
+
if (est.anchorReal === null || est.anchorEst === null) {
|
|
2795
|
+
est.anchorReal = realTotal;
|
|
2796
|
+
est.anchorEst = estTotal;
|
|
2797
|
+
return;
|
|
2798
|
+
}
|
|
2799
|
+
const dReal = realTotal - est.anchorReal;
|
|
2800
|
+
const dEst = estTotal - est.anchorEst;
|
|
2801
|
+
if (dEst < MIN_DELTA_EST) return;
|
|
2802
|
+
est.anchorReal = realTotal;
|
|
2803
|
+
est.anchorEst = estTotal;
|
|
2804
|
+
const instant = clamp(dReal / dEst, DENSITY_MIN, DENSITY_MAX);
|
|
2805
|
+
if (est.pendingDensity === null) {
|
|
2806
|
+
est.pendingDensity = instant;
|
|
2807
|
+
est.confirmCount = 1;
|
|
2808
|
+
} else if (Math.abs(instant - est.pendingDensity) / est.pendingDensity <= CONFIRM_RATIO) {
|
|
2809
|
+
est.confirmCount += 1;
|
|
2810
|
+
} else {
|
|
2811
|
+
est.pendingDensity = instant;
|
|
2812
|
+
est.confirmCount = 1;
|
|
2813
|
+
}
|
|
2814
|
+
if (est.confirmCount >= 2) {
|
|
2815
|
+
est.density = est.pendingDensity;
|
|
2816
|
+
est.confirmCount = 0;
|
|
2817
|
+
est.pendingDensity = null;
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
/** 注入器:估算文本 token = defaultCountTokens × density。 */
|
|
2821
|
+
estimateWithDensity(modelId, text) {
|
|
2822
|
+
const d = this.densityFor(modelId);
|
|
2823
|
+
if (d === 1) return defaultCountTokens(text);
|
|
2824
|
+
return Math.round(defaultCountTokens(text) * d);
|
|
2825
|
+
}
|
|
2826
|
+
};
|
|
2827
|
+
function clamp(v, lo, hi) {
|
|
2828
|
+
return v < lo ? lo : v > hi ? hi : v;
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2634
2831
|
// src/messages.ts
|
|
2635
2832
|
var REF_TAG_SOURCE = "(?:<acp\\s[^>]*>m\\d{5}</acp>|\\[m\\d{1,5}\\])";
|
|
2636
2833
|
var REF_TAG = new RegExp(`^${REF_TAG_SOURCE}\\s?\\n?`);
|
|
@@ -3136,6 +3333,7 @@ function mergeInitialState(parsed) {
|
|
|
3136
3333
|
return {
|
|
3137
3334
|
blocks: parsed.blocks ?? fresh.blocks,
|
|
3138
3335
|
messageRefs: parsed.messageRefs ?? fresh.messageRefs,
|
|
3336
|
+
tokenSnapshot: parsed.tokenSnapshot ?? fresh.tokenSnapshot,
|
|
3139
3337
|
nudge: { ...fresh.nudge, ...parsed.nudge ?? {} },
|
|
3140
3338
|
stats: { ...fresh.stats, ...parsed.stats ?? {} },
|
|
3141
3339
|
nextBlockId: parsed.nextBlockId ?? fresh.nextBlockId,
|
|
@@ -3358,8 +3556,14 @@ function pruneOrphanRefs(state, messages) {
|
|
|
3358
3556
|
}
|
|
3359
3557
|
}
|
|
3360
3558
|
function createRuntime(adapter) {
|
|
3361
|
-
const
|
|
3559
|
+
const density = new DensityEstimator();
|
|
3560
|
+
let countModelId = "default";
|
|
3561
|
+
const core = createCore({
|
|
3562
|
+
// 密度校准版 countTokens(Phase 2):默认回落 defaultCountTokens(density=1)
|
|
3563
|
+
countTokens: (text) => density.estimateWithDensity(countModelId, text)
|
|
3564
|
+
});
|
|
3362
3565
|
const store = new SessionStateStore();
|
|
3566
|
+
const lastActiveBlockIds = /* @__PURE__ */ new Map();
|
|
3363
3567
|
const locks = /* @__PURE__ */ new Map();
|
|
3364
3568
|
let adapterRef = adapter;
|
|
3365
3569
|
let promptsRef = defaultPrompts;
|
|
@@ -3384,7 +3588,8 @@ function createRuntime(adapter) {
|
|
|
3384
3588
|
return m?.contextWindow ?? 0;
|
|
3385
3589
|
}
|
|
3386
3590
|
function configFor(ctx) {
|
|
3387
|
-
|
|
3591
|
+
const m = ctx.model;
|
|
3592
|
+
return resolveConfig(adapterRef, liveContextLimit(ctx), m?.provider, m?.id);
|
|
3388
3593
|
}
|
|
3389
3594
|
async function stateFor(ctx, liveMessages) {
|
|
3390
3595
|
const sm = ctx.sessionManager;
|
|
@@ -3407,7 +3612,19 @@ function createRuntime(adapter) {
|
|
|
3407
3612
|
const sm = ctx.sessionManager;
|
|
3408
3613
|
await store.save(state, sm.getSessionFile() ?? void 0, sm.getSessionId());
|
|
3409
3614
|
}
|
|
3410
|
-
|
|
3615
|
+
function noteActiveBlocks(sid, activeBlockIds) {
|
|
3616
|
+
const current = new Set(activeBlockIds);
|
|
3617
|
+
const prev = lastActiveBlockIds.get(sid);
|
|
3618
|
+
const isNew = prev !== void 0 && activeBlockIds.some((id) => !prev.has(id));
|
|
3619
|
+
lastActiveBlockIds.set(sid, current);
|
|
3620
|
+
return isNew;
|
|
3621
|
+
}
|
|
3622
|
+
function clearSessionTracking(sid) {
|
|
3623
|
+
lastActiveBlockIds.delete(sid);
|
|
3624
|
+
}
|
|
3625
|
+
return { core, store, density, setCountModel: (m) => {
|
|
3626
|
+
countModelId = m;
|
|
3627
|
+
}, noteActiveBlocks, clearSessionTracking, get adapter() {
|
|
3411
3628
|
return adapterRef;
|
|
3412
3629
|
}, setAdapter: (a) => {
|
|
3413
3630
|
adapterRef = a;
|
|
@@ -7834,6 +8051,9 @@ function estimateTokens(messages, coveredIds) {
|
|
|
7834
8051
|
}
|
|
7835
8052
|
return tokens;
|
|
7836
8053
|
}
|
|
8054
|
+
function calibrateTokens(estimate, density) {
|
|
8055
|
+
return density === 1 ? estimate : Math.round(estimate * density);
|
|
8056
|
+
}
|
|
7837
8057
|
function lastUserMessageId(entries) {
|
|
7838
8058
|
for (let i = entries.length - 1; i >= 0; i--) {
|
|
7839
8059
|
const e = entries[i];
|
|
@@ -7842,6 +8062,23 @@ function lastUserMessageId(entries) {
|
|
|
7842
8062
|
return void 0;
|
|
7843
8063
|
}
|
|
7844
8064
|
|
|
8065
|
+
// src/compat.ts
|
|
8066
|
+
function normalizeSystemPrompt(input) {
|
|
8067
|
+
if (input === void 0) return "";
|
|
8068
|
+
if (Array.isArray(input)) return input.join("\n");
|
|
8069
|
+
return input;
|
|
8070
|
+
}
|
|
8071
|
+
function formatSystemPromptForEvent(base, append) {
|
|
8072
|
+
const normalized = normalizeSystemPrompt(base);
|
|
8073
|
+
return `${normalized}
|
|
8074
|
+
|
|
8075
|
+
${append}`;
|
|
8076
|
+
}
|
|
8077
|
+
function getSystemPromptText(ctx) {
|
|
8078
|
+
const result = ctx.getSystemPrompt?.();
|
|
8079
|
+
return normalizeSystemPrompt(result);
|
|
8080
|
+
}
|
|
8081
|
+
|
|
7845
8082
|
// src/compress-tool.ts
|
|
7846
8083
|
function formatK2(n) {
|
|
7847
8084
|
return n >= 1e3 ? `${(n / 1e3).toFixed(1)}K` : String(n);
|
|
@@ -7887,21 +8124,26 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
|
7887
8124
|
if (ranges.length === 0) return "No ranges provided.";
|
|
7888
8125
|
const { state: initialState, coreMessages } = await runtime.stateFor(ctx);
|
|
7889
8126
|
const config = runtime.configFor(ctx);
|
|
7890
|
-
const
|
|
7891
|
-
const
|
|
8127
|
+
const modelId = ctx.model?.id ?? "default";
|
|
8128
|
+
const systemPromptText = getSystemPromptText(ctx);
|
|
8129
|
+
const systemPromptTokens = systemPromptText ? defaultCountTokens(systemPromptText) : 0;
|
|
8130
|
+
const sentTokens = estimateTokens(coreMessages, collectCoveredMessageIds(initialState)) + systemPromptTokens;
|
|
7892
8131
|
const turn = runtime.core.processTurn({
|
|
7893
8132
|
messages: coreMessages,
|
|
7894
8133
|
state: initialState,
|
|
7895
8134
|
config,
|
|
7896
|
-
tokenCount:
|
|
8135
|
+
tokenCount: calibrateTokens(sentTokens, runtime.density.densityFor(modelId))
|
|
7897
8136
|
});
|
|
7898
8137
|
const state = turn.state;
|
|
7899
8138
|
const messages = turn.messages;
|
|
7900
|
-
const
|
|
8139
|
+
const density = runtime.density.densityFor(modelId);
|
|
8140
|
+
const beforeTokens = calibrateTokens(estimateTokens(messages, collectCoveredMessageIds(state)), density);
|
|
7901
8141
|
const summaryMaxChars = args.summaryMaxChars;
|
|
7902
8142
|
const topLevelTopic = args.topic;
|
|
7903
8143
|
debug.event("compress-in", {
|
|
7904
8144
|
sid: ctx.sessionManager.getSessionId(),
|
|
8145
|
+
modelId,
|
|
8146
|
+
density,
|
|
7905
8147
|
ranges: ranges.length,
|
|
7906
8148
|
spans: ranges.map((r) => ({ span: `${r.startId}..${r.endId}`, summaryLen: r.summary.length, summary: r.summary, topic: r.topic ?? topLevelTopic ?? null })),
|
|
7907
8149
|
blocksBefore: state.blocks.length,
|
|
@@ -7958,7 +8200,8 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
|
7958
8200
|
|
|
7959
8201
|
// src/decompress-tool.ts
|
|
7960
8202
|
import { writeFile, mkdir } from "fs/promises";
|
|
7961
|
-
import {
|
|
8203
|
+
import { existsSync as existsSync2, lstatSync, readlinkSync, realpathSync } from "fs";
|
|
8204
|
+
import { resolve, relative, isAbsolute, join as join3, basename as basename2, dirname as dirname3 } from "path";
|
|
7962
8205
|
import { tmpdir, homedir as homedir2 } from "os";
|
|
7963
8206
|
var AUTO_DIR = join3(homedir2() || tmpdir(), ".cache", "pi", "acp-decompress");
|
|
7964
8207
|
var PREVIEW_CHARS = 600;
|
|
@@ -8002,14 +8245,39 @@ var ALLOWED_DIRS = [
|
|
|
8002
8245
|
function resolveToFilePath(targetPath) {
|
|
8003
8246
|
const expanded = targetPath.startsWith("~/") ? join3(homedir2(), targetPath.slice(2)) : targetPath;
|
|
8004
8247
|
const resolved = resolve(expanded);
|
|
8005
|
-
|
|
8006
|
-
|
|
8248
|
+
let probe = resolved;
|
|
8249
|
+
const suffix = [];
|
|
8250
|
+
while (!existsSync2(probe) && probe !== dirname3(probe)) {
|
|
8251
|
+
suffix.unshift(basename2(probe));
|
|
8252
|
+
probe = dirname3(probe);
|
|
8253
|
+
}
|
|
8254
|
+
const real = existsSync2(probe) ? realpathSync(probe) : probe;
|
|
8255
|
+
let checked = real;
|
|
8256
|
+
for (const part of suffix) {
|
|
8257
|
+
checked = join3(checked, part);
|
|
8258
|
+
try {
|
|
8259
|
+
if (lstatSync(checked).isSymbolicLink()) {
|
|
8260
|
+
const target = readlinkSync(checked);
|
|
8261
|
+
checked = isAbsolute(target) ? resolve(target) : resolve(dirname3(checked), target);
|
|
8262
|
+
}
|
|
8263
|
+
} catch {
|
|
8264
|
+
}
|
|
8265
|
+
}
|
|
8266
|
+
const allowed = ALLOWED_DIRS.map((d) => {
|
|
8267
|
+
try {
|
|
8268
|
+
return realpathSync(d);
|
|
8269
|
+
} catch {
|
|
8270
|
+
return d;
|
|
8271
|
+
}
|
|
8272
|
+
});
|
|
8273
|
+
const isAllowed = allowed.some((dir) => {
|
|
8274
|
+
const rel = relative(dir, checked);
|
|
8007
8275
|
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
8008
8276
|
});
|
|
8009
8277
|
if (!isAllowed) {
|
|
8010
8278
|
return { error: `Error: toFile path must be under ${tmpdir()}, ~/.cache/opencode, or ~/.cache/pi. Got: ${targetPath}` };
|
|
8011
8279
|
}
|
|
8012
|
-
return
|
|
8280
|
+
return checked;
|
|
8013
8281
|
}
|
|
8014
8282
|
function autoFilePath(blockId) {
|
|
8015
8283
|
return join3(AUTO_DIR, `${blockId}-${Date.now()}.txt`);
|
|
@@ -8075,7 +8343,7 @@ ${text}`;
|
|
|
8075
8343
|
}
|
|
8076
8344
|
async function handleDecompress(args, runtime, ctx) {
|
|
8077
8345
|
const { state, coreMessages } = await runtime.stateFor(ctx);
|
|
8078
|
-
const arg = args.blockId.trim();
|
|
8346
|
+
const arg = (args.blockId ?? "").trim();
|
|
8079
8347
|
const owner = state.blocks.find((b) => b.effectiveMessageIds.includes(arg));
|
|
8080
8348
|
if (owner) {
|
|
8081
8349
|
return handleMessageRef(arg, owner.blockId, args, ctx);
|
|
@@ -8247,20 +8515,125 @@ function formatSize(tokens) {
|
|
|
8247
8515
|
return `${(tokens / 1e6).toFixed(1)}M`;
|
|
8248
8516
|
}
|
|
8249
8517
|
|
|
8518
|
+
// node_modules/billion-context-kit/dist/index.js
|
|
8519
|
+
var VIABLE_RANGE_MIN_TOKENS = 200;
|
|
8520
|
+
function viableRanges(ranges) {
|
|
8521
|
+
return ranges.filter((r) => r.tokens >= VIABLE_RANGE_MIN_TOKENS);
|
|
8522
|
+
}
|
|
8523
|
+
function topicFallback(summary) {
|
|
8524
|
+
const first = summary.split(/[.\n]/)[0] ?? "";
|
|
8525
|
+
const t = first.trim().replace(/^["'`]+/, "").trim();
|
|
8526
|
+
return t.length <= 30 ? t : `${t.slice(0, 30).trimEnd()}\u2026`;
|
|
8527
|
+
}
|
|
8528
|
+
function formatCompactTokens(count) {
|
|
8529
|
+
if (count < 1e3) return count.toString();
|
|
8530
|
+
if (count < 1e4) return `${(count / 1e3).toFixed(1)}k`;
|
|
8531
|
+
if (count < 1e6) return `${Math.round(count / 1e3)}k`;
|
|
8532
|
+
if (count < 1e7) return `${(count / 1e6).toFixed(1)}M`;
|
|
8533
|
+
return `${Math.round(count / 1e6)}M`;
|
|
8534
|
+
}
|
|
8535
|
+
function bar(value, total, width = 20) {
|
|
8536
|
+
if (total === 0) return "";
|
|
8537
|
+
const filled = Math.max(0, Math.min(width, Math.round(value / total * width)));
|
|
8538
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
8539
|
+
}
|
|
8540
|
+
function buildStatusPanel(input) {
|
|
8541
|
+
const { tokenCount, state, nudge, modelContextLimit } = input;
|
|
8542
|
+
const fmt2 = input.fmtTokens ?? formatCompactTokens;
|
|
8543
|
+
const bd = nudge?.contextBreakdown;
|
|
8544
|
+
const limit = modelContextLimit;
|
|
8545
|
+
const classified = bd ? bd.system + bd.tool + bd.summaries + bd.code + bd.text : 0;
|
|
8546
|
+
const systemPromptTokens = input.systemPromptTokens;
|
|
8547
|
+
const sentTotal = classified + systemPromptTokens;
|
|
8548
|
+
const sessionOnly = input.unprunedTokens !== void 0 ? Math.max(0, input.unprunedTokens - sentTotal) : 0;
|
|
8549
|
+
const displayTotal = tokenCount;
|
|
8550
|
+
const displayPct = limit > 0 ? Math.round(displayTotal / limit * 100) : 0;
|
|
8551
|
+
const sentPct = limit > 0 ? Math.round(sentTotal / limit * 100) : 0;
|
|
8552
|
+
const activeBlocksList = state.blocks.filter((b) => b.active);
|
|
8553
|
+
const totalBlocksList = state.blocks;
|
|
8554
|
+
const lines = [];
|
|
8555
|
+
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");
|
|
8556
|
+
lines.push("\u2502 ACP Context Analysis \u2502");
|
|
8557
|
+
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");
|
|
8558
|
+
if (input.version) lines.push(input.version);
|
|
8559
|
+
lines.push("");
|
|
8560
|
+
lines.push(`Context (session accounting, host footer scale): ${displayPct}% (${fmt2(displayTotal)} / ${fmt2(limit)}) \u2014 never shrinks; includes compressed originals`);
|
|
8561
|
+
if (nudge && bd) {
|
|
8562
|
+
const growth = bd.growth;
|
|
8563
|
+
if (growth > 0 && displayTotal > 0) {
|
|
8564
|
+
lines.push(`Growth: +${fmt2(growth)} since last nudge`);
|
|
8565
|
+
}
|
|
8566
|
+
lines.push("");
|
|
8567
|
+
lines.push(`Sent to LLM (after compression, est.): ${fmt2(sentTotal)}${limit > 0 ? ` (${sentPct}% of limit)` : ""}`);
|
|
8568
|
+
if (input.unprunedTokens !== void 0 && sessionOnly > 0) {
|
|
8569
|
+
lines.push(`Session-only (compressed originals, est.): ${fmt2(sessionOnly)} \u2014 pruned from every request; the footer/nudge still count them`);
|
|
8570
|
+
}
|
|
8571
|
+
lines.push("");
|
|
8572
|
+
lines.push("Token Breakdown (sent view):");
|
|
8573
|
+
const categories = [
|
|
8574
|
+
{ label: "Tool", value: bd.tool },
|
|
8575
|
+
{ label: "SysPrompt", value: systemPromptTokens },
|
|
8576
|
+
{ label: "Text", value: bd.text },
|
|
8577
|
+
{ label: "Code", value: bd.code },
|
|
8578
|
+
{ label: "Summaries", value: bd.summaries }
|
|
8579
|
+
];
|
|
8580
|
+
for (const cat of categories) {
|
|
8581
|
+
if (cat.value <= 0) continue;
|
|
8582
|
+
const pct2 = sentTotal > 0 ? Math.round(cat.value / sentTotal * 100) : 0;
|
|
8583
|
+
const b = bar(cat.value, sentTotal);
|
|
8584
|
+
lines.push(` ${cat.label.padEnd(10)} ${b} ${String(pct2).padStart(3)}% ${fmt2(cat.value)}`);
|
|
8585
|
+
}
|
|
8586
|
+
}
|
|
8587
|
+
lines.push("");
|
|
8588
|
+
if (nudge) {
|
|
8589
|
+
if (nudge.shouldInject) {
|
|
8590
|
+
const tierInfo = nudge.tier ? ` [T${nudge.tier} distillation]` : "";
|
|
8591
|
+
lines.push(`Nudge: ACTIVE${tierInfo} \u2014 ${nudge.reason}`);
|
|
8592
|
+
} else {
|
|
8593
|
+
lines.push(`Nudge: idle \u2014 ${nudge.reason}`);
|
|
8594
|
+
}
|
|
8595
|
+
}
|
|
8596
|
+
const ranges = viableRanges(nudge?.compressibleRanges ?? []);
|
|
8597
|
+
const protectedRanges = nudge?.protectedRanges ?? [];
|
|
8598
|
+
if (ranges.length > 0 || protectedRanges.length > 0) {
|
|
8599
|
+
lines.push("");
|
|
8600
|
+
lines.push(formatRanges(ranges, protectedRanges));
|
|
8601
|
+
}
|
|
8602
|
+
if (activeBlocksList.length > 0) {
|
|
8603
|
+
lines.push("");
|
|
8604
|
+
lines.push(`Blocks: ${activeBlocksList.length} active / ${totalBlocksList.length} total (${fmt2(state.stats.tokensCompressed)} tokens compressed)`);
|
|
8605
|
+
for (const b of activeBlocksList) {
|
|
8606
|
+
const topic = b.topic ? `: ${b.topic}` : `: ${topicFallback(b.summary || "")}`;
|
|
8607
|
+
const summaryTok = defaultCountTokens(b.summary || "");
|
|
8608
|
+
const origTok = b.compressedTokens > 0 ? b.compressedTokens : summaryTok;
|
|
8609
|
+
lines.push(` [${b.blockId}] T${b.tier} ${fmt2(origTok)}\u2192${fmt2(summaryTok)}${topic}`);
|
|
8610
|
+
}
|
|
8611
|
+
} else if (totalBlocksList.length > 0) {
|
|
8612
|
+
lines.push("");
|
|
8613
|
+
lines.push(`Blocks: 0 active / ${totalBlocksList.length} total (${fmt2(state.stats.tokensCompressed)} tokens compressed)`);
|
|
8614
|
+
} else {
|
|
8615
|
+
lines.push("");
|
|
8616
|
+
lines.push("Blocks: none (nothing compressed yet)");
|
|
8617
|
+
}
|
|
8618
|
+
lines.push("");
|
|
8619
|
+
lines.push("Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal.");
|
|
8620
|
+
return lines.join("\n");
|
|
8621
|
+
}
|
|
8622
|
+
|
|
8250
8623
|
// src/delegate-tool.ts
|
|
8251
8624
|
import {
|
|
8252
8625
|
spawn
|
|
8253
8626
|
} from "child_process";
|
|
8254
|
-
import { createWriteStream, existsSync as
|
|
8627
|
+
import { createWriteStream, existsSync as existsSync3 } from "fs";
|
|
8255
8628
|
import { mkdir as mkdir2, mkdtemp, writeFile as writeFile2, rm, appendFile } from "fs/promises";
|
|
8256
8629
|
import { tmpdir as tmpdir2 } from "os";
|
|
8257
|
-
import { dirname as
|
|
8630
|
+
import { dirname as dirname4, join as join4, resolve as resolvePath } from "path";
|
|
8258
8631
|
|
|
8259
8632
|
// src/footer-status.ts
|
|
8260
8633
|
var FOOTER_STATUS_KEY = "billion-context-pi";
|
|
8261
8634
|
var ui;
|
|
8262
8635
|
var lastFooterText = "";
|
|
8263
|
-
function
|
|
8636
|
+
function formatCompactTokens2(count) {
|
|
8264
8637
|
if (count < 1e3) return count.toString();
|
|
8265
8638
|
if (count < 1e4) return `${(count / 1e3).toFixed(1)}k`;
|
|
8266
8639
|
if (count < 1e6) return `${Math.round(count / 1e3)}k`;
|
|
@@ -8277,7 +8650,7 @@ function updateFooterStatus() {
|
|
|
8277
8650
|
let text;
|
|
8278
8651
|
if (usage && usage.totalTokens > 0) {
|
|
8279
8652
|
const costStr = usage.cost.total > 0 ? ` ($${usage.cost.total.toFixed(4)})` : "";
|
|
8280
|
-
text = `sub-agents \u2191${
|
|
8653
|
+
text = `sub-agents \u2191${formatCompactTokens2(usage.input)} \u2193${formatCompactTokens2(usage.output)}${costStr}`;
|
|
8281
8654
|
}
|
|
8282
8655
|
if ((text ?? "") === lastFooterText) return;
|
|
8283
8656
|
lastFooterText = text ?? "";
|
|
@@ -8670,11 +9043,11 @@ function delegateSpawnOptions(cwd, env) {
|
|
|
8670
9043
|
var PI_CLI_ENTRY_RE = /[\\/]pi-coding-agent[\\/]dist[\\/]cli\.js$/;
|
|
8671
9044
|
var PI_PACKAGE_REL = join4("@earendil-works", "pi-coding-agent", "dist", "cli.js");
|
|
8672
9045
|
function probeUpFromArgv(argv1) {
|
|
8673
|
-
let dir = resolvePath(
|
|
9046
|
+
let dir = resolvePath(dirname4(argv1) || process.cwd());
|
|
8674
9047
|
for (; ; ) {
|
|
8675
9048
|
const candidate = join4(dir, "node_modules", PI_PACKAGE_REL);
|
|
8676
|
-
if (
|
|
8677
|
-
const parent =
|
|
9049
|
+
if (existsSync3(candidate)) return candidate;
|
|
9050
|
+
const parent = dirname4(dir);
|
|
8678
9051
|
if (parent === dir) return null;
|
|
8679
9052
|
dir = parent;
|
|
8680
9053
|
}
|
|
@@ -8699,7 +9072,7 @@ function resolvePiCliEntry(argv1, env = process.env, piHost = true) {
|
|
|
8699
9072
|
const probed = probeUpFromArgv(argv1);
|
|
8700
9073
|
if (probed) return probed;
|
|
8701
9074
|
for (const candidate of piCliGlobalCandidates(env)) {
|
|
8702
|
-
if (
|
|
9075
|
+
if (existsSync3(candidate)) return candidate;
|
|
8703
9076
|
}
|
|
8704
9077
|
logWarn("delegate", { event: "cli-entry-unresolved", argv1, fallback: "argv[1]" });
|
|
8705
9078
|
}
|
|
@@ -9499,13 +9872,16 @@ function makeStatusTool(runtime) {
|
|
|
9499
9872
|
async function handleStatus(args, runtime, ctx) {
|
|
9500
9873
|
const { state, coreMessages } = await runtime.stateFor(ctx);
|
|
9501
9874
|
const config = runtime.configFor(ctx);
|
|
9502
|
-
const
|
|
9503
|
-
const
|
|
9875
|
+
const coveredIds = collectCoveredMessageIds(state);
|
|
9876
|
+
const modelId = ctx.model?.id ?? "default";
|
|
9877
|
+
const systemPromptText = getSystemPromptText(ctx);
|
|
9878
|
+
const systemPromptTokens = systemPromptText ? defaultCountTokens(systemPromptText) : 0;
|
|
9879
|
+
const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
|
|
9504
9880
|
const turn = runtime.core.processTurn({
|
|
9505
9881
|
messages: coreMessages,
|
|
9506
9882
|
state,
|
|
9507
9883
|
config,
|
|
9508
|
-
tokenCount:
|
|
9884
|
+
tokenCount: calibrateTokens(sentTokens, runtime.density.densityFor(modelId))
|
|
9509
9885
|
});
|
|
9510
9886
|
const processed = turn.messages;
|
|
9511
9887
|
const base = buildStatusReport(turn.state, processed, defaultCountTokens, {
|
|
@@ -9517,7 +9893,7 @@ async function handleStatus(args, runtime, ctx) {
|
|
|
9517
9893
|
});
|
|
9518
9894
|
if (args.scope) return base;
|
|
9519
9895
|
const nudge = turn.nudge;
|
|
9520
|
-
const ranges = nudge?.compressibleRanges ?? [];
|
|
9896
|
+
const ranges = viableRanges(nudge?.compressibleRanges ?? []);
|
|
9521
9897
|
const protectedRanges = nudge?.protectedRanges ?? [];
|
|
9522
9898
|
const extra = [];
|
|
9523
9899
|
if (nudge) {
|
|
@@ -9548,23 +9924,6 @@ async function handleStatus(args, runtime, ctx) {
|
|
|
9548
9924
|
${extra.join("\n")}` : base;
|
|
9549
9925
|
}
|
|
9550
9926
|
|
|
9551
|
-
// src/compat.ts
|
|
9552
|
-
function normalizeSystemPrompt(input) {
|
|
9553
|
-
if (input === void 0) return "";
|
|
9554
|
-
if (Array.isArray(input)) return input.join("\n");
|
|
9555
|
-
return input;
|
|
9556
|
-
}
|
|
9557
|
-
function formatSystemPromptForEvent(base, append) {
|
|
9558
|
-
const normalized = normalizeSystemPrompt(base);
|
|
9559
|
-
return `${normalized}
|
|
9560
|
-
|
|
9561
|
-
${append}`;
|
|
9562
|
-
}
|
|
9563
|
-
function getSystemPromptText(ctx) {
|
|
9564
|
-
const result = ctx.getSystemPrompt?.();
|
|
9565
|
-
return normalizeSystemPrompt(result);
|
|
9566
|
-
}
|
|
9567
|
-
|
|
9568
9927
|
// src/commands.ts
|
|
9569
9928
|
function makeCommands(runtime) {
|
|
9570
9929
|
return [
|
|
@@ -9632,106 +9991,35 @@ ${text}`);
|
|
|
9632
9991
|
}
|
|
9633
9992
|
];
|
|
9634
9993
|
}
|
|
9635
|
-
function fmtTokens(n) {
|
|
9636
|
-
return formatCompactTokens(n);
|
|
9637
|
-
}
|
|
9638
|
-
function bar(value, total, width = 20) {
|
|
9639
|
-
if (total === 0) return "";
|
|
9640
|
-
const filled = Math.max(0, Math.min(width, Math.round(value / total * width)));
|
|
9641
|
-
return "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
9642
|
-
}
|
|
9643
9994
|
async function statusReport(runtime, ctx) {
|
|
9644
9995
|
const { state, coreMessages } = await runtime.stateFor(ctx);
|
|
9645
9996
|
const config = runtime.configFor(ctx);
|
|
9646
9997
|
const realUsage = ctx.getContextUsage?.();
|
|
9647
|
-
const tokenCount = realUsage?.tokens && realUsage.tokens > 0 ? realUsage.tokens : defaultCountTokens(coreMessages.map((m) => m.text ?? "").join("\n"));
|
|
9648
|
-
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount });
|
|
9649
|
-
const nudge = turn.nudge;
|
|
9650
|
-
const bd = nudge?.contextBreakdown;
|
|
9651
|
-
const limit = config.modelContextLimit;
|
|
9652
|
-
const classified = bd ? bd.system + bd.tool + bd.summaries + bd.code + bd.text : 0;
|
|
9653
9998
|
const systemPromptText = getSystemPromptText(ctx);
|
|
9654
9999
|
const systemPromptTokens = systemPromptText ? defaultCountTokens(systemPromptText) : 0;
|
|
9655
|
-
const
|
|
9656
|
-
const
|
|
9657
|
-
const
|
|
9658
|
-
const
|
|
9659
|
-
const
|
|
9660
|
-
const
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
|
|
9666
|
-
|
|
9667
|
-
|
|
9668
|
-
|
|
9669
|
-
|
|
9670
|
-
if (growth > 0 && displayTotal > 0) {
|
|
9671
|
-
lines.push(`Growth: +${fmtTokens(growth)} since last nudge`);
|
|
9672
|
-
}
|
|
9673
|
-
if (displayTotal > 0) {
|
|
9674
|
-
lines.push("");
|
|
9675
|
-
lines.push("Token Breakdown:");
|
|
9676
|
-
const categories = [
|
|
9677
|
-
{ label: "Tool", value: bd.tool },
|
|
9678
|
-
{ label: "SysPrompt", value: systemPromptTokens },
|
|
9679
|
-
{ label: "Framework", value: framework },
|
|
9680
|
-
{ label: "Text", value: bd.text },
|
|
9681
|
-
{ label: "Code", value: bd.code },
|
|
9682
|
-
{ label: "Summaries", value: bd.summaries }
|
|
9683
|
-
];
|
|
9684
|
-
for (const cat of categories) {
|
|
9685
|
-
if (cat.value <= 0) continue;
|
|
9686
|
-
const pct2 = displayTotal > 0 ? Math.round(cat.value / displayTotal * 100) : 0;
|
|
9687
|
-
const b = bar(cat.value, displayTotal);
|
|
9688
|
-
lines.push(` ${cat.label.padEnd(10)} ${b} ${String(pct2).padStart(3)}% ${fmtTokens(cat.value)}`);
|
|
9689
|
-
}
|
|
9690
|
-
}
|
|
9691
|
-
}
|
|
9692
|
-
lines.push("");
|
|
9693
|
-
if (nudge) {
|
|
9694
|
-
if (nudge.shouldInject) {
|
|
9695
|
-
const tierInfo = nudge.tier ? ` [T${nudge.tier} distillation]` : "";
|
|
9696
|
-
lines.push(`Nudge: ACTIVE${tierInfo} \u2014 ${nudge.reason}`);
|
|
9697
|
-
} else {
|
|
9698
|
-
lines.push(`Nudge: idle \u2014 ${nudge.reason}`);
|
|
9699
|
-
}
|
|
9700
|
-
}
|
|
9701
|
-
const ranges = nudge?.compressibleRanges ?? [];
|
|
9702
|
-
const protectedRanges = nudge?.protectedRanges ?? [];
|
|
9703
|
-
if (ranges.length > 0 || protectedRanges.length > 0) {
|
|
9704
|
-
lines.push("");
|
|
9705
|
-
lines.push(formatRanges(ranges, protectedRanges));
|
|
9706
|
-
}
|
|
9707
|
-
if (activeBlocksList.length > 0) {
|
|
9708
|
-
lines.push("");
|
|
9709
|
-
lines.push(`Blocks: ${activeBlocksList.length} active / ${totalBlocksList.length} total (${fmtTokens(state.stats.tokensCompressed)} tokens compressed)`);
|
|
9710
|
-
for (const b of activeBlocksList) {
|
|
9711
|
-
const topic = b.topic ? `: ${b.topic}` : "";
|
|
9712
|
-
const summaryTok = defaultCountTokens(b.summary || "");
|
|
9713
|
-
const origTok = b.compressedTokens > 0 ? b.compressedTokens : summaryTok;
|
|
9714
|
-
lines.push(` [${b.blockId}] T${b.tier} ${fmtTokens(origTok)}\u2192${fmtTokens(summaryTok)}${topic}`);
|
|
9715
|
-
}
|
|
9716
|
-
} else if (totalBlocksList.length > 0) {
|
|
9717
|
-
lines.push("");
|
|
9718
|
-
lines.push(`Blocks: 0 active / ${totalBlocksList.length} total (${fmtTokens(state.stats.tokensCompressed)} tokens compressed)`);
|
|
9719
|
-
} else {
|
|
9720
|
-
lines.push("");
|
|
9721
|
-
lines.push("Blocks: none (nothing compressed yet)");
|
|
9722
|
-
}
|
|
9723
|
-
lines.push("");
|
|
10000
|
+
const sessionTokens = realUsage?.tokens && realUsage.tokens > 0 ? realUsage.tokens : defaultCountTokens(coreMessages.map((m) => m.text ?? "").join("\n"));
|
|
10001
|
+
const coveredIds = collectCoveredMessageIds(state);
|
|
10002
|
+
const modelId = ctx.model?.id ?? "default";
|
|
10003
|
+
const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
|
|
10004
|
+
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: calibrateTokens(sentTokens, runtime.density.densityFor(modelId)) });
|
|
10005
|
+
const versionStr = "0.1.39" ? `billion-context-pi@${"0.1.39"}` : void 0;
|
|
10006
|
+
let text = buildStatusPanel({
|
|
10007
|
+
version: versionStr,
|
|
10008
|
+
tokenCount: sessionTokens,
|
|
10009
|
+
systemPromptTokens,
|
|
10010
|
+
state: turn.state,
|
|
10011
|
+
nudge: turn.nudge,
|
|
10012
|
+
modelContextLimit: config.modelContextLimit,
|
|
10013
|
+
unprunedTokens: coreMessages.reduce((sum, m) => sum + defaultCountTokens(m.text ?? ""), 0)
|
|
10014
|
+
});
|
|
9724
10015
|
const delegateUsage = getDelegateUsage();
|
|
9725
10016
|
if (delegateUsage && delegateUsage.totalTokens > 0) {
|
|
9726
|
-
lines.push("");
|
|
9727
10017
|
const cost = delegateUsage.cost.total;
|
|
9728
10018
|
const costStr = cost > 0 ? ` ($${cost.toFixed(4)})` : "";
|
|
9729
|
-
|
|
9730
|
-
|
|
10019
|
+
text += "\n\n\u2500\u2500 Session delegate usage (excluded from main totals) \u2500\u2500\n";
|
|
10020
|
+
text += `Tokens: ${delegateUsage.input.toLocaleString()} in, ${delegateUsage.output.toLocaleString()} out (${delegateUsage.totalTokens.toLocaleString()} total)${costStr}`;
|
|
9731
10021
|
}
|
|
9732
|
-
|
|
9733
|
-
lines.push("Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal.");
|
|
9734
|
-
return lines.join("\n");
|
|
10022
|
+
return text;
|
|
9735
10023
|
}
|
|
9736
10024
|
|
|
9737
10025
|
// src/system-prompt.ts
|
|
@@ -9927,7 +10215,7 @@ function wireToolGuardrails(pi, runtime) {
|
|
|
9927
10215
|
|
|
9928
10216
|
// src/update.ts
|
|
9929
10217
|
import { readFile, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
9930
|
-
import { join as join5, dirname as
|
|
10218
|
+
import { join as join5, dirname as dirname5 } from "path";
|
|
9931
10219
|
import { fileURLToPath } from "url";
|
|
9932
10220
|
import { execFile } from "child_process";
|
|
9933
10221
|
import { homedir as homedir3 } from "os";
|
|
@@ -9960,7 +10248,7 @@ async function readLastCheck() {
|
|
|
9960
10248
|
}
|
|
9961
10249
|
async function writeLastCheck(timestamp) {
|
|
9962
10250
|
try {
|
|
9963
|
-
await mkdir3(
|
|
10251
|
+
await mkdir3(dirname5(THROTTLE_FILE), { recursive: true });
|
|
9964
10252
|
await writeFile3(THROTTLE_FILE, String(timestamp), "utf-8");
|
|
9965
10253
|
} catch {
|
|
9966
10254
|
}
|
|
@@ -9974,20 +10262,20 @@ async function readPackageJson(path4) {
|
|
|
9974
10262
|
}
|
|
9975
10263
|
}
|
|
9976
10264
|
function findNpmRoot(extDir) {
|
|
9977
|
-
let dir =
|
|
10265
|
+
let dir = dirname5(extDir);
|
|
9978
10266
|
for (; ; ) {
|
|
9979
|
-
if (dir.endsWith("node_modules")) return
|
|
9980
|
-
const parent =
|
|
10267
|
+
if (dir.endsWith("node_modules")) return dirname5(dir);
|
|
10268
|
+
const parent = dirname5(dir);
|
|
9981
10269
|
if (parent === dir) return void 0;
|
|
9982
10270
|
dir = parent;
|
|
9983
10271
|
}
|
|
9984
10272
|
}
|
|
9985
10273
|
async function findExtensionDir() {
|
|
9986
|
-
let dir =
|
|
10274
|
+
let dir = dirname5(fileURLToPath(import.meta.url));
|
|
9987
10275
|
for (; ; ) {
|
|
9988
10276
|
const pkg = await readPackageJson(join5(dir, "package.json"));
|
|
9989
10277
|
if (pkg?.name === PACKAGE_NAME) return dir;
|
|
9990
|
-
const parent =
|
|
10278
|
+
const parent = dirname5(dir);
|
|
9991
10279
|
if (parent === dir) return void 0;
|
|
9992
10280
|
dir = parent;
|
|
9993
10281
|
}
|
|
@@ -10036,7 +10324,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
10036
10324
|
const data = await res.json();
|
|
10037
10325
|
const latest = data.version;
|
|
10038
10326
|
if (!latest) return;
|
|
10039
|
-
const current = runtimeVersion ?? "0.1.
|
|
10327
|
+
const current = runtimeVersion ?? "0.1.39";
|
|
10040
10328
|
const hasUpdate = isNewer(latest, current);
|
|
10041
10329
|
debug.event("update-check", {
|
|
10042
10330
|
current,
|
|
@@ -10072,7 +10360,7 @@ async function getRuntimeVersion() {
|
|
|
10072
10360
|
|
|
10073
10361
|
// src/setup-subagent-tools.ts
|
|
10074
10362
|
import { readFile as readFile2, writeFile as writeFile4, stat, copyFile, rename } from "fs/promises";
|
|
10075
|
-
import { existsSync as
|
|
10363
|
+
import { existsSync as existsSync4 } from "fs";
|
|
10076
10364
|
import { homedir as homedir4 } from "os";
|
|
10077
10365
|
import { join as join6 } from "path";
|
|
10078
10366
|
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME3 } from "@earendil-works/pi-coding-agent";
|
|
@@ -10137,7 +10425,7 @@ async function ensureSubagentAcpTools(settingsPath) {
|
|
|
10137
10425
|
return { path: path4, action: "skipped", reason: "all builtin agents already have ACP tools" };
|
|
10138
10426
|
}
|
|
10139
10427
|
const backupPath = `${path4}.acp-bak`;
|
|
10140
|
-
if (!
|
|
10428
|
+
if (!existsSync4(backupPath)) {
|
|
10141
10429
|
try {
|
|
10142
10430
|
await copyFile(path4, backupPath);
|
|
10143
10431
|
} catch {
|
|
@@ -10284,10 +10572,14 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
10284
10572
|
pi.on("session_start", async (_event, ctx) => {
|
|
10285
10573
|
runtime.store.invalidate();
|
|
10286
10574
|
runtime.clearNudgeTracking();
|
|
10575
|
+
const modelId = ctx.model?.id ?? "default";
|
|
10576
|
+
runtime.density.resetModel(modelId);
|
|
10287
10577
|
resetDelegateUsage();
|
|
10288
10578
|
setDelegateDisplayUsage("separate");
|
|
10289
10579
|
const sid = ctx.sessionManager.getSessionId();
|
|
10290
|
-
|
|
10580
|
+
runtime.clearSessionTracking(sid);
|
|
10581
|
+
const modelInfo = ctx.model;
|
|
10582
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.39" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
|
|
10291
10583
|
try {
|
|
10292
10584
|
const user = await loadUserConfig(ctx.cwd);
|
|
10293
10585
|
runtime.setAdapter(applyUserConfig(runtime.adapter, user));
|
|
@@ -10323,29 +10615,39 @@ function wireContextTransform(pi, runtime) {
|
|
|
10323
10615
|
const sid = ctx.sessionManager.getSessionId();
|
|
10324
10616
|
const release = await runtime.acquireLock(sid);
|
|
10325
10617
|
try {
|
|
10618
|
+
const modelId = ctx.model?.id ?? "default";
|
|
10619
|
+
runtime.setCountModel(modelId);
|
|
10326
10620
|
const { state, coreMessages, entries } = await runtime.stateFor(ctx, event.messages);
|
|
10327
10621
|
const config = runtime.configFor(ctx);
|
|
10328
10622
|
const coveredIds = collectCoveredMessageIds(state);
|
|
10329
10623
|
const realUsage = ctx.getContextUsage?.();
|
|
10330
|
-
const
|
|
10331
|
-
const
|
|
10624
|
+
const systemPromptText = getSystemPromptText(ctx);
|
|
10625
|
+
const systemPromptTokens = systemPromptText ? defaultCountTokens(systemPromptText) : 0;
|
|
10626
|
+
const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
|
|
10627
|
+
const tokenCount = calibrateTokens(sentTokens, runtime.density.densityFor(modelId));
|
|
10628
|
+
const postCompression = runtime.noteActiveBlocks(
|
|
10629
|
+
sid,
|
|
10630
|
+
state.blocks.filter((b) => b.active).map((b) => b.blockId)
|
|
10631
|
+
);
|
|
10332
10632
|
debug.event("context-in", {
|
|
10333
10633
|
sid,
|
|
10634
|
+
modelId,
|
|
10635
|
+
density: runtime.density.densityFor(modelId),
|
|
10334
10636
|
eventMsgs: event.messages?.length ?? 0,
|
|
10335
10637
|
entries: entries.length,
|
|
10336
10638
|
coreMsgs: coreMessages.length,
|
|
10337
10639
|
tokenCount,
|
|
10338
|
-
|
|
10339
|
-
realTokens: realUsage?.tokens ?? null,
|
|
10340
|
-
realPercent: realUsage?.percent ?? null,
|
|
10640
|
+
sessionTokens: realUsage?.tokens ?? null,
|
|
10341
10641
|
limit: config.modelContextLimit,
|
|
10342
10642
|
blocksBefore: state.blocks.length,
|
|
10343
10643
|
activeBefore: state.blocks.filter((b) => b.active).length
|
|
10344
10644
|
});
|
|
10345
10645
|
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount });
|
|
10346
10646
|
await runtime.save(turn.state, ctx);
|
|
10647
|
+
runtime.density.update(modelId, realUsage?.tokens ?? null, sentTokens, postCompression);
|
|
10347
10648
|
logInfo("turn", {
|
|
10348
10649
|
sid,
|
|
10650
|
+
model: ctx.model?.id ?? null,
|
|
10349
10651
|
inMsgs: coreMessages.length,
|
|
10350
10652
|
outMsgs: turn.messages.length,
|
|
10351
10653
|
tokens: tokenCount,
|
|
@@ -10357,6 +10659,8 @@ function wireContextTransform(pi, runtime) {
|
|
|
10357
10659
|
activeBlocks: turn.state.blocks.filter((b) => b.active).length
|
|
10358
10660
|
});
|
|
10359
10661
|
debug.event("processTurn", {
|
|
10662
|
+
modelId,
|
|
10663
|
+
density: runtime.density.densityFor(modelId),
|
|
10360
10664
|
outMsgs: turn.messages.length,
|
|
10361
10665
|
summaryMsgs: turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
|
|
10362
10666
|
prunedMsgs: coreMessages.length - turn.messages.length + turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
|
|
@@ -10376,6 +10680,7 @@ function wireContextTransform(pi, runtime) {
|
|
|
10376
10680
|
const debugOn2 = debug.enabled;
|
|
10377
10681
|
if (turn.nudge?.shouldInject) {
|
|
10378
10682
|
const emergency = turn.nudge.breakdown?.emergencyOverride === 1;
|
|
10683
|
+
turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
|
|
10379
10684
|
const turnKey = lastUserMessageId(entries) ?? sid;
|
|
10380
10685
|
const alreadyShown = !emergency && runtime.nudgeShownFor(turnKey);
|
|
10381
10686
|
if (!alreadyShown) {
|