billion-context-pi 0.1.66 → 0.1.67-pr.355.167
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 +6 -0
- package/README.zh-CN.md +6 -0
- package/dist/index.js +77 -45
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,12 @@ The model decides <em>when</em> and <em>what</em> to compress — not a hard lim
|
|
|
24
24
|
|
|
25
25
|
> **Host support:** this plugin is for **Pi**. It does **not** support **OMP (oh-my-pi)** — on an OMP host it refuses to run. OMP users: use [billion-context](https://github.com/ranxianglei/billion-context) instead (`bili omp`, built-in plugin). Full client → package table: see [Which do I need?](#which-do-i-need); OMP details: [docs/omp.md](./docs/omp.md).
|
|
26
26
|
|
|
27
|
+
## Community
|
|
28
|
+
|
|
29
|
+
Discussion, help, and updates on QQ — one group covers all three projects (`billion-context`, `billion-context-pi`, `opencode-acp`):
|
|
30
|
+
|
|
31
|
+
**QQ Group: 1056132097**
|
|
32
|
+
|
|
27
33
|
## Why?
|
|
28
34
|
|
|
29
35
|
When conversations get long, the model runs out of context. Most tools hard-truncate — silently dropping earlier messages. **billion-context** gives the model a `compress` tool: the LLM decides **when** and **what** to compress into high-fidelity summaries, preserving critical details (file paths, decisions, error strings) while reclaiming context space.
|
package/README.zh-CN.md
CHANGED
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
|
|
23
23
|
> **宿主支持:** 本插件面向 **Pi**。它**不支持 OMP(oh-my-pi)** —— 在 OMP 宿主上会拒绝运行。OMP 用户请直接改用 [billion-context](https://github.com/ranxianglei/billion-context)(启动命令 bili omp);其他客户端的完整对照见[该选哪个?](#该选哪个)。OMP 详细说明:[docs/omp.zh-CN.md](./docs/omp.zh-CN.md)。
|
|
24
24
|
|
|
25
|
+
## 社区
|
|
26
|
+
|
|
27
|
+
交流、求助与更新都在 QQ——同一个群覆盖三个项目(`billion-context`、`billion-context-pi`、`opencode-acp`):
|
|
28
|
+
|
|
29
|
+
**QQ 群:1056132097**
|
|
30
|
+
|
|
25
31
|
## 为什么选择 billion-context
|
|
26
32
|
|
|
27
33
|
当对话变长,模型的上下文会耗尽。多数工具采用硬截断 —— 静默丢弃早期消息。**billion-context** 把 `compress` 工具交给模型:由 LLM 决定**何时**压缩、压缩**什么**,将内容压缩成高保真摘要,在回收上下文空间的同时保留关键细节(文件路径、决策、错误字符串)。
|
package/dist/index.js
CHANGED
|
@@ -5282,8 +5282,37 @@ function createRuntime(adapter) {
|
|
|
5282
5282
|
let adapterRef = adapter;
|
|
5283
5283
|
let lastUserConfigKey;
|
|
5284
5284
|
let promptsRef = defaultPrompts;
|
|
5285
|
-
const nudgeShownTurns = /* @__PURE__ */ new
|
|
5285
|
+
const nudgeShownTurns = /* @__PURE__ */ new Map();
|
|
5286
5286
|
const nudgeShownTokens = /* @__PURE__ */ new Map();
|
|
5287
|
+
function markNudgeShown(sid, turnKey, tokenCount) {
|
|
5288
|
+
let turns = nudgeShownTurns.get(sid);
|
|
5289
|
+
if (!turns) {
|
|
5290
|
+
turns = /* @__PURE__ */ new Set();
|
|
5291
|
+
nudgeShownTurns.set(sid, turns);
|
|
5292
|
+
}
|
|
5293
|
+
turns.add(turnKey);
|
|
5294
|
+
if (tokenCount !== void 0) {
|
|
5295
|
+
let toks = nudgeShownTokens.get(sid);
|
|
5296
|
+
if (!toks) {
|
|
5297
|
+
toks = /* @__PURE__ */ new Map();
|
|
5298
|
+
nudgeShownTokens.set(sid, toks);
|
|
5299
|
+
}
|
|
5300
|
+
toks.set(turnKey, tokenCount);
|
|
5301
|
+
}
|
|
5302
|
+
}
|
|
5303
|
+
function nudgeShownFor(sid, turnKey) {
|
|
5304
|
+
return nudgeShownTurns.get(sid)?.has(turnKey) ?? false;
|
|
5305
|
+
}
|
|
5306
|
+
function nudgeShownTokensFor(sid, turnKey) {
|
|
5307
|
+
return nudgeShownTokens.get(sid)?.get(turnKey);
|
|
5308
|
+
}
|
|
5309
|
+
function clearNudgeTracking(sid) {
|
|
5310
|
+
nudgeShownTurns.delete(sid);
|
|
5311
|
+
nudgeShownTokens.delete(sid);
|
|
5312
|
+
}
|
|
5313
|
+
function clearNudgeTokenStamps(sid) {
|
|
5314
|
+
nudgeShownTokens.delete(sid);
|
|
5315
|
+
}
|
|
5287
5316
|
const overflowEpisodes = /* @__PURE__ */ new Map();
|
|
5288
5317
|
function overflowFor(sid) {
|
|
5289
5318
|
let ep = overflowEpisodes.get(sid);
|
|
@@ -5333,34 +5362,40 @@ function createRuntime(adapter) {
|
|
|
5333
5362
|
function dropTokenScale(sid) {
|
|
5334
5363
|
tokenScaleStale.delete(sid);
|
|
5335
5364
|
}
|
|
5336
|
-
const
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5365
|
+
const compressOutcomes = /* @__PURE__ */ new Map();
|
|
5366
|
+
function compressTrackerFor(sid) {
|
|
5367
|
+
let t = compressOutcomes.get(sid);
|
|
5368
|
+
if (!t) {
|
|
5369
|
+
t = { seen: /* @__PURE__ */ new Set(), failTurnKey: null, failCount: 0 };
|
|
5370
|
+
compressOutcomes.set(sid, t);
|
|
5371
|
+
}
|
|
5372
|
+
return t;
|
|
5373
|
+
}
|
|
5374
|
+
function noteCompressOutcomes(sid, turnKey, outcomes) {
|
|
5375
|
+
const t = compressTrackerFor(sid);
|
|
5376
|
+
if (t.failTurnKey !== turnKey) {
|
|
5377
|
+
t.failTurnKey = turnKey;
|
|
5378
|
+
t.failCount = 0;
|
|
5343
5379
|
}
|
|
5344
|
-
const prevCount =
|
|
5380
|
+
const prevCount = t.failCount;
|
|
5345
5381
|
for (const o of outcomes) {
|
|
5346
|
-
if (
|
|
5347
|
-
|
|
5382
|
+
if (t.seen.has(o.toolCallId)) continue;
|
|
5383
|
+
t.seen.add(o.toolCallId);
|
|
5348
5384
|
if (o.isError || o.noop === true) {
|
|
5349
|
-
|
|
5385
|
+
t.failCount += 1;
|
|
5350
5386
|
} else if (o.success) {
|
|
5351
|
-
|
|
5387
|
+
t.failCount = 0;
|
|
5352
5388
|
}
|
|
5353
5389
|
}
|
|
5354
|
-
const cappedNow =
|
|
5355
|
-
return { count:
|
|
5390
|
+
const cappedNow = t.failCount >= MAX_COMPRESS_ATTEMPTS && prevCount < MAX_COMPRESS_ATTEMPTS;
|
|
5391
|
+
return { count: t.failCount, cappedNow };
|
|
5356
5392
|
}
|
|
5357
|
-
function compressRetryCappedFor(turnKey) {
|
|
5358
|
-
|
|
5393
|
+
function compressRetryCappedFor(sid, turnKey) {
|
|
5394
|
+
const t = compressOutcomes.get(sid);
|
|
5395
|
+
return t !== void 0 && t.failTurnKey === turnKey && t.failCount >= MAX_COMPRESS_ATTEMPTS;
|
|
5359
5396
|
}
|
|
5360
|
-
function clearCompressRetryTracking() {
|
|
5361
|
-
|
|
5362
|
-
compressFailTurnKey = null;
|
|
5363
|
-
compressFailCount = 0;
|
|
5397
|
+
function clearCompressRetryTracking(sid) {
|
|
5398
|
+
compressOutcomes.delete(sid);
|
|
5364
5399
|
}
|
|
5365
5400
|
async function acquireLock(sid) {
|
|
5366
5401
|
const prev = locks.get(sid) ?? Promise.resolve();
|
|
@@ -5461,13 +5496,7 @@ function createRuntime(adapter) {
|
|
|
5461
5496
|
return promptsRef;
|
|
5462
5497
|
}, setPrompts: (p) => {
|
|
5463
5498
|
promptsRef = p;
|
|
5464
|
-
}, markNudgeShown
|
|
5465
|
-
nudgeShownTurns.add(k);
|
|
5466
|
-
if (t !== void 0) nudgeShownTokens.set(k, t);
|
|
5467
|
-
}, nudgeShownFor: (k) => nudgeShownTurns.has(k), nudgeShownTokensFor: (k) => nudgeShownTokens.get(k), clearNudgeTracking: () => {
|
|
5468
|
-
nudgeShownTurns.clear();
|
|
5469
|
-
nudgeShownTokens.clear();
|
|
5470
|
-
}, clearNudgeTokenStamps: () => nudgeShownTokens.clear(), noteCompressOutcomes, compressRetryCappedFor, clearCompressRetryTracking, liveContextLimit, configFor, reasoningDropFor, reloadConfig, stateFor, save, acquireLock, overflowFor, overflowDrop, noteDeadCompress, clearDeadCompress, throttleFor, throttleDrop, noteTokenScale, dropTokenScale };
|
|
5499
|
+
}, markNudgeShown, nudgeShownFor, nudgeShownTokensFor, clearNudgeTracking, clearNudgeTokenStamps, noteCompressOutcomes, compressRetryCappedFor, clearCompressRetryTracking, liveContextLimit, configFor, reasoningDropFor, reloadConfig, stateFor, save, acquireLock, overflowFor, overflowDrop, noteDeadCompress, clearDeadCompress, throttleFor, throttleDrop, noteTokenScale, dropTokenScale };
|
|
5471
5500
|
}
|
|
5472
5501
|
|
|
5473
5502
|
// node_modules/typebox/build/system/memory/memory.mjs
|
|
@@ -10190,7 +10219,7 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
|
10190
10219
|
});
|
|
10191
10220
|
const turnKey = lastUserMessageId(entries) ?? sid;
|
|
10192
10221
|
const snapshot = compressibleSnapshotText(turn.nudge);
|
|
10193
|
-
if (runtime.compressRetryCappedFor(turnKey)) {
|
|
10222
|
+
if (runtime.compressRetryCappedFor(sid, turnKey)) {
|
|
10194
10223
|
logWarn("compress", { sid, event: "capped-reject", turnKey });
|
|
10195
10224
|
return cappedRejectionText(snapshot);
|
|
10196
10225
|
}
|
|
@@ -16965,7 +16994,7 @@ async function statusReport(runtime, ctx) {
|
|
|
16965
16994
|
const sentTokens = estimateTokens(coreMessages, coveredIds, imageTokens) + systemPromptTokens;
|
|
16966
16995
|
const viewSentTokens = adjustedTokenCount(runtime.core, coreMessages, state, config, sentTokens, imageTokens, systemPromptTokens);
|
|
16967
16996
|
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: anchorStale ? viewSentTokens : Math.max(viewSentTokens, realUsage?.tokens ?? 0) });
|
|
16968
|
-
const versionStr = "0.1.
|
|
16997
|
+
const versionStr = "0.1.67" ? `billion-context-pi@${"0.1.67"}` : void 0;
|
|
16969
16998
|
let text = buildStatusPanel({
|
|
16970
16999
|
version: versionStr,
|
|
16971
17000
|
tokenCount: sessionTokens,
|
|
@@ -17663,7 +17692,7 @@ async function autoInstallLatest(latest, extDirOverride) {
|
|
|
17663
17692
|
"--no-fund",
|
|
17664
17693
|
"--no-save"
|
|
17665
17694
|
];
|
|
17666
|
-
const prevVersion = (await readPackageJson(join11(extDir, "package.json")))?.version ?? "0.1.
|
|
17695
|
+
const prevVersion = (await readPackageJson(join11(extDir, "package.json")))?.version ?? "0.1.67";
|
|
17667
17696
|
const { code, stderr } = await runNpmImpl(installArgs(latest), { cwd: npmDir, timeout: 6e4 });
|
|
17668
17697
|
if (code !== 0) {
|
|
17669
17698
|
logWarn("update", {
|
|
@@ -17681,7 +17710,7 @@ async function autoInstallLatest(latest, extDirOverride) {
|
|
|
17681
17710
|
}
|
|
17682
17711
|
const verify = await verifyInstall(npmDir, latest);
|
|
17683
17712
|
if (!verify.ok) {
|
|
17684
|
-
const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.1.
|
|
17713
|
+
const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.1.67";
|
|
17685
17714
|
logWarn("update", { event: "auto-install-verify-failed", latest, reason: verify.reason, rollbackTo });
|
|
17686
17715
|
const rb = await runNpmImpl(installArgs(rollbackTo), { cwd: npmDir, timeout: 6e4 });
|
|
17687
17716
|
logInfo("update", { event: "rollback", from: latest, to: rollbackTo, ok: rb.code === 0 });
|
|
@@ -17756,7 +17785,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
17756
17785
|
}
|
|
17757
17786
|
const latest = await fetchLatestVersion(tag);
|
|
17758
17787
|
if (!latest) return;
|
|
17759
|
-
const current = runtimeVersion ?? "0.1.
|
|
17788
|
+
const current = runtimeVersion ?? "0.1.67";
|
|
17760
17789
|
const hasUpdate = isVersionNewer(latest, current);
|
|
17761
17790
|
debug.event("update-check", {
|
|
17762
17791
|
current,
|
|
@@ -17926,15 +17955,15 @@ function wireSessionLifecycle(pi, runtime, standDownIfProxied) {
|
|
|
17926
17955
|
}
|
|
17927
17956
|
if (standDownIfProxied(ctx)) return;
|
|
17928
17957
|
runtime.store.invalidate();
|
|
17929
|
-
runtime.clearNudgeTracking();
|
|
17958
|
+
runtime.clearNudgeTracking(ctx.sessionManager.getSessionId());
|
|
17930
17959
|
runtime.throttleFor(ctx.sessionManager.getSessionId()).reset();
|
|
17931
|
-
runtime.clearCompressRetryTracking();
|
|
17960
|
+
runtime.clearCompressRetryTracking(ctx.sessionManager.getSessionId());
|
|
17932
17961
|
resetDelegateUsage();
|
|
17933
17962
|
setDelegateDisplayUsage("separate");
|
|
17934
17963
|
setDelegatePolicy(DEFAULT_DELEGATE_POLICY);
|
|
17935
17964
|
const sid = ctx.sessionManager.getSessionId();
|
|
17936
17965
|
const modelInfo = ctx.model;
|
|
17937
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.
|
|
17966
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.67" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
|
|
17938
17967
|
try {
|
|
17939
17968
|
await runtime.reloadConfig(ctx.cwd);
|
|
17940
17969
|
const delegateCfg = resolveDelegate(runtime.adapter);
|
|
@@ -17971,8 +18000,11 @@ function wireSessionLifecycle(pi, runtime, standDownIfProxied) {
|
|
|
17971
18000
|
delegateStatusWidget.setContext(ctx, runningRunsSnapshot);
|
|
17972
18001
|
});
|
|
17973
18002
|
pi.on("session_shutdown", (_event, ctx) => {
|
|
17974
|
-
|
|
17975
|
-
runtime.
|
|
18003
|
+
const sid = ctx.sessionManager.getSessionId();
|
|
18004
|
+
runtime.clearDeadCompress(sid);
|
|
18005
|
+
runtime.dropTokenScale(sid);
|
|
18006
|
+
runtime.clearNudgeTracking(sid);
|
|
18007
|
+
runtime.clearCompressRetryTracking(sid);
|
|
17976
18008
|
delegateStatusWidget.dispose();
|
|
17977
18009
|
closeLogStream();
|
|
17978
18010
|
});
|
|
@@ -18029,7 +18061,7 @@ function wireContextTransform(pi, runtime, standDownIfProxied) {
|
|
|
18029
18061
|
state.nudge.lastNudgeShownTokens = 0;
|
|
18030
18062
|
state.nudge.lastPerMessageNudgeTokens = 0;
|
|
18031
18063
|
state.nudge.lastShownByTier = {};
|
|
18032
|
-
runtime.clearNudgeTokenStamps();
|
|
18064
|
+
runtime.clearNudgeTokenStamps(sid);
|
|
18033
18065
|
logInfo("growth-scale", { sid, event: "scale-flip-reset", anchorStale: !hostFloorActive });
|
|
18034
18066
|
}
|
|
18035
18067
|
debug.event("context-in", {
|
|
@@ -18111,24 +18143,24 @@ function wireContextTransform(pi, runtime, standDownIfProxied) {
|
|
|
18111
18143
|
const debugOn2 = debug.enabled;
|
|
18112
18144
|
const turnKey = lastUserMessageId(entries) ?? sid;
|
|
18113
18145
|
const compressOutcomes = collectCompressOutcomes(entries, turnStartIndex(entries));
|
|
18114
|
-
const outcome = compressOutcomes.length > 0 ? runtime.noteCompressOutcomes(turnKey, compressOutcomes) : null;
|
|
18146
|
+
const outcome = compressOutcomes.length > 0 ? runtime.noteCompressOutcomes(sid, turnKey, compressOutcomes) : null;
|
|
18115
18147
|
const adaptiveGrowth = !config.modelContextLimit || config.modelContextLimit <= 0 ? config.nudge.growthFloor : Math.min(
|
|
18116
18148
|
config.nudge.growthCap,
|
|
18117
18149
|
Math.max(config.nudge.growthFloor, Math.round(config.modelContextLimit * config.nudge.growthRatio))
|
|
18118
18150
|
);
|
|
18119
18151
|
const reInjectFloor = Math.max(config.nudge.minGrowthFloor, config.nudge.minGrowthRatio * adaptiveGrowth);
|
|
18120
|
-
let shownAt = runtime.nudgeShownTokensFor(turnKey);
|
|
18152
|
+
let shownAt = runtime.nudgeShownTokensFor(sid, turnKey);
|
|
18121
18153
|
if (shownAt !== void 0 && tokenCount < shownAt - adaptiveGrowth) {
|
|
18122
18154
|
logInfo("nudge", { sid: ctx.sessionManager.getSessionId(), event: "drop-reanchor", turnKey, from: shownAt, to: tokenCount });
|
|
18123
18155
|
shownAt = tokenCount;
|
|
18124
|
-
runtime.markNudgeShown(turnKey, tokenCount);
|
|
18156
|
+
runtime.markNudgeShown(sid, turnKey, tokenCount);
|
|
18125
18157
|
}
|
|
18126
18158
|
if (turn.nudge?.shouldInject) {
|
|
18127
18159
|
const emergency = turn.nudge.breakdown?.emergencyOverride === 1;
|
|
18128
18160
|
turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
|
|
18129
|
-
const retryCapped = runtime.compressRetryCappedFor(turnKey);
|
|
18161
|
+
const retryCapped = runtime.compressRetryCappedFor(sid, turnKey);
|
|
18130
18162
|
const reInjectReady = shownAt === void 0 || tokenCount - shownAt >= reInjectFloor;
|
|
18131
|
-
const alreadyShown = retryCapped || !emergency && runtime.nudgeShownFor(turnKey) && !reInjectReady;
|
|
18163
|
+
const alreadyShown = retryCapped || !emergency && runtime.nudgeShownFor(sid, turnKey) && !reInjectReady;
|
|
18132
18164
|
if (!alreadyShown) {
|
|
18133
18165
|
rebuilt.push(nudgeMessage(turn.nudge, turn.state.blocks.filter((b2) => b2.active), runtime.prompts));
|
|
18134
18166
|
const rendered = renderNudgeText(turn.nudge, runtime.prompts);
|
|
@@ -18143,7 +18175,7 @@ Example: compress({ content: [{ startId: "${top.startRef}", endId: "${top.endRef
|
|
|
18143
18175
|
ctx.ui.notify(`[ACP nudge \u2192 context]${emergency ? " [EMERGENCY]" : ""}
|
|
18144
18176
|
${rendered.text}${example}`);
|
|
18145
18177
|
}
|
|
18146
|
-
if (!emergency) runtime.markNudgeShown(turnKey, tokenCount);
|
|
18178
|
+
if (!emergency) runtime.markNudgeShown(sid, turnKey, tokenCount);
|
|
18147
18179
|
debug.event("nudge-injected", { sid: ctx.sessionManager.getSessionId(), voice: rendered.voice, channels: ["context", debugOn2 ? "terminal" : null].filter(Boolean), emergency, turnKey, reInject: shownAt !== void 0, text: rendered.text + example });
|
|
18148
18180
|
} else {
|
|
18149
18181
|
debug.event("nudge-suppressed", { sid: ctx.sessionManager.getSessionId(), turnKey, reason: turn.nudge.reason, shownAt: shownAt ?? null, tokenCount, adaptiveGrowth, reInjectFloor });
|