billion-context-pi 0.1.70 → 0.1.71-pr.233.261
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 +4 -0
- package/README.zh-CN.md +4 -0
- package/dist/config.d.ts +10 -0
- package/dist/index.js +198 -80
- package/dist/index.js.map +1 -1
- package/dist/omp.d.ts +10 -0
- package/dist/proxy-detect.d.ts +13 -0
- package/dist/runtime.d.ts +35 -4
- package/dist/setup-subagent-tools.d.ts +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,6 +79,8 @@ That's it. The extension auto-loads on next Pi startup. No configuration needed
|
|
|
79
79
|
> **Using another sub-agent extension?** billion-context-pi ships its own `acp_delegate` sub-agent tool (see below) at a fraction of the context cost (~600 tok vs ~7K tok/turn). Two delegation tools in one session only make the model's choice noisier, so pick one:
|
|
80
80
|
> - **Use ACP's delegate** — remove the other extension: `pi remove npm:pi-subagents`
|
|
81
81
|
> - **Keep your own sub-agent** — turn ACP's delegate off in `acp.json`: `{ "delegate": false }` (see *Using your own sub-agent instead* below)
|
|
82
|
+
>
|
|
83
|
+
> If you keep `pi-subagents` installed, billion-context-pi detects it at session start: a **project-level** install (`<cwd>/.pi/npm` or the project extensions dir) automatically stands `acp_delegate` down for that project — a reminder then tells you how to give pi-subagents' agents ACP compression via `/acp-subagents`. A **user-level-only** install (`~/.pi/npm`, user extensions dir) leaves `acp_delegate` active and logs a warning instead. Set `"delegate": { "forceEnable": true }` in `acp.json` to keep `acp_delegate` active regardless of detection.
|
|
82
84
|
|
|
83
85
|
## How it works
|
|
84
86
|
|
|
@@ -120,6 +122,8 @@ billion-context-pi is built for the **Pi** coding agent (`@earendil-works/pi-cod
|
|
|
120
122
|
|
|
121
123
|
- **Coexisting with the [billion-context](https://github.com/ranxianglei/billion-context) wire proxy** — running both on the same session double-compresses every request (wasted tokens, nested summaries, two ref coordinate systems). This is prevented automatically: launcher paths (`bili pi`, …) export `BILLION_CONTEXT_PROXY`, and models whose `baseUrl` routes through the proxy (`…/bili/https://upstream…`) are detected at session start — in both cases billion-context-pi stands down with a warning and leaves the proxy as the sole compressor. One exception: transparent mode, where traffic reaches the proxy via `HTTPS_PROXY` so the URL carries no `/bili/` prefix — that is undetectable from the URL, so export `BILLION_CONTEXT_PROXY=1` before starting pi in that case.
|
|
122
124
|
|
|
125
|
+
- **Reverse collision — the `billion-context` thin plugin shadows `/acp`.** If the pi plugin shipped inside [`billion-context`](https://github.com/ranxianglei/billion-context) is also installed (an entry pointing at a `billion-context` install in `"packages"` of `~/.pi/agent/settings.json`, e.g. from `bili plugin install pi`), it registers its own `/acp` command, and Pi has no duplicate-command guard — which one answers depends on load order. Telling symptom: on a plain `pi` launch, typing `/acp` shows ``bili: no proxy detected (run via `bili <client>` or set a /bili/ baseURL)`` — that string is emitted by the thin plugin, **not** by billion-context-pi, and pi does not need `bili` running. Fix: the collision only bites when you launch plain `pi` — remove the thin plugin there (`bili plugin remove pi`, or drop the non-`npm:billion-context-pi` entry from that settings file) so billion-context-pi owns `/acp`. If you launch via `bili pi` instead, nothing needs removing: the launcher exports `BILLION_CONTEXT_PROXY` and billion-context-pi stands down entirely (bullet above), so both plugins may stay installed side by side. Note: `bili plugin install pi` removes an existing `npm:billion-context-pi` entry from that file without saying so ([billion-context#788](https://github.com/ranxianglei/billion-context/issues/788)).
|
|
126
|
+
|
|
123
127
|
## Model-facing tools
|
|
124
128
|
|
|
125
129
|
| Tool | What it does |
|
package/README.zh-CN.md
CHANGED
|
@@ -78,6 +78,8 @@ pi install npm:billion-context-pi
|
|
|
78
78
|
> **你另有子代理扩展?** billion-context-pi 自带 `acp_delegate` 子代理工具(见下文),上下文成本极低(~600 tok vs ~7K tok/轮)。同一会话里两套委派工具只会让模型的选择更混乱,二选一:
|
|
79
79
|
> - **用 ACP 的 delegate** —— 卸载另一个扩展:`pi remove npm:pi-subagents`
|
|
80
80
|
> - **保留你自己的子代理** —— 在 `acp.json` 里关掉 ACP 的 delegate:`{ "delegate": false }`(见下文*改用你自己的子代理*)
|
|
81
|
+
>
|
|
82
|
+
> 若保留已安装的 `pi-subagents`,billion-context-pi 会在会话启动时检测:**项目级**安装(`<cwd>/.pi/npm` 或项目内 extensions 目录)会自动停用该项目的 `acp_delegate`,并提醒你运行 `/acp-subagents` 让 pi-subagents 的子代理获得 ACP 压缩;仅**用户级**(全局)安装时只记一条警告日志,`acp_delegate` 保持启用。在 `acp.json` 中设置 `"delegate": { "forceEnable": true }` 可在检测到第三方子代理时仍强制保留 `acp_delegate`。
|
|
81
83
|
|
|
82
84
|
## 工作原理
|
|
83
85
|
|
|
@@ -119,6 +121,8 @@ billion-context-pi 面向 **Pi** 编码代理(`@earendil-works/pi-coding-agent`)
|
|
|
119
121
|
|
|
120
122
|
- **与 [billion-context](https://github.com/ranxianglei/billion-context) 线代理共存** —— 两者同时作用于同一会话会对每个请求双重压缩(token 浪费、嵌套摘要、两套 ref 坐标系)。这会被自动防止:launcher 路径(`bili pi` 等)导出 `BILLION_CONTEXT_PROXY`;模型 `baseUrl` 经代理路由(`…/bili/https://upstream…`)时在会话开始即被检测到 —— 两种情况下 billion-context-pi 都会带警告让位,由代理独占压缩。一个例外:透明模式(流量经 `HTTPS_PROXY` 到达代理、URL 无 `/bili/` 前缀)无法从 URL 识别 —— 此时请在启动 pi 前导出 `BILLION_CONTEXT_PROXY=1`。
|
|
121
123
|
|
|
124
|
+
- **反向冲突 —— `billion-context` 薄插件抢占 `/acp`。** 如果 [`billion-context`](https://github.com/ranxianglei/billion-context) 内置的 pi 插件也被安装了(`~/.pi/agent/settings.json` 的 `"packages"` 里存在指向某个 `billion-context` 安装目录的条目,例如来自 `bili plugin install pi`),它会注册自己的 `/acp` 命令,而 Pi 没有重复命令防护 —— 哪个生效取决于加载顺序。典型症状:在普通 `pi` 启动下输入 `/acp` 显示 ``bili: no proxy detected (run via `bili <client>` or set a /bili/ baseURL)`` —— 这行字符串由薄插件发出,**不是** billion-context-pi 发出的,而且 pi 并不需要运行 `bili`。修复:该冲突只在你用普通 `pi` 启动时才有实际影响 —— 移除薄插件(`bili plugin remove pi`,或从该设置文件中删除除 `npm:billion-context-pi` 之外的条目),让 `/acp` 由 billion-context-pi 接管;若改用 `bili pi` 启动则无需移除任何东西:launcher 会导出 `BILLION_CONTEXT_PROXY`,billion-context-pi 整体让位(见上一条),两个插件可以并存。注意:`bili plugin install pi` 会静默删除该文件中已有的 `npm:billion-context-pi` 条目且不提示([billion-context#788](https://github.com/ranxianglei/billion-context/issues/788))。
|
|
125
|
+
|
|
122
126
|
## 模型工具
|
|
123
127
|
|
|
124
128
|
| 工具 | 作用 |
|
package/dist/config.d.ts
CHANGED
|
@@ -29,6 +29,13 @@ export interface DelegateConfig {
|
|
|
29
29
|
/** Enable acp_delegate tools (delegate/wait/cancel) and their system-prompt
|
|
30
30
|
* section. Default: true. Set `enabled: false` to skip registering them. */
|
|
31
31
|
enabled?: boolean;
|
|
32
|
+
/** Keep acp_delegate active even when a third-party subagent extension
|
|
33
|
+
* (pi-subagents) is installed. Default: false — when pi-subagents is
|
|
34
|
+
* detected at session start, acp_delegate stands down (tools, fleet
|
|
35
|
+
* shortcut and system-prompt section skipped) to avoid two overlapping
|
|
36
|
+
* sub-agent systems, and a reminder points at /acp-subagents so the
|
|
37
|
+
* third-party agents can still get ACP compression tools (#415). */
|
|
38
|
+
forceEnable?: boolean;
|
|
32
39
|
/** How delegate usage is reported back to the main session.
|
|
33
40
|
* "separate" (default) — delegate tokens tracked in a separate accumulator;
|
|
34
41
|
* main session totals stay clean, delegate usage shows as its own block in
|
|
@@ -89,6 +96,9 @@ export interface DelegateConfig {
|
|
|
89
96
|
* corresponding timeout/watchdog is disabled. */
|
|
90
97
|
export interface DelegatePolicy {
|
|
91
98
|
enabled: boolean;
|
|
99
|
+
/** Resolved delegate.forceEnable (default false): keep acp_delegate even
|
|
100
|
+
* when a third-party subagent extension (pi-subagents) is installed (#415). */
|
|
101
|
+
forceEnable: boolean;
|
|
92
102
|
displayUsage: "merged" | "separate";
|
|
93
103
|
maxDepth: number;
|
|
94
104
|
syncTimeoutMs: number | null;
|
package/dist/index.js
CHANGED
|
@@ -4532,6 +4532,7 @@ var debug = {
|
|
|
4532
4532
|
var DEFAULT_FLEET_SHORTCUT = "ctrl+alt+d";
|
|
4533
4533
|
var DEFAULT_DELEGATE_POLICY = {
|
|
4534
4534
|
enabled: true,
|
|
4535
|
+
forceEnable: false,
|
|
4535
4536
|
displayUsage: "separate",
|
|
4536
4537
|
maxDepth: 2,
|
|
4537
4538
|
syncTimeoutMs: 5 * 6e4,
|
|
@@ -4565,19 +4566,28 @@ function resolveDelegate(adapter) {
|
|
|
4565
4566
|
DEFAULT_DELEGATE_POLICY.asyncTimeoutMs
|
|
4566
4567
|
);
|
|
4567
4568
|
const maxConcurrent = resolveMaxConcurrent(process.env.PI_ACP_DELEGATE_MAX_CONCURRENT, cfg.maxConcurrent);
|
|
4569
|
+
const forceEnable = resolveForceEnable(process.env.PI_ACP_DELEGATE_FORCE_ENABLE, cfg.forceEnable);
|
|
4568
4570
|
if (idleMs === null) {
|
|
4569
4571
|
logWarn("config", {
|
|
4570
4572
|
event: "delegate-idle-watchdog-disabled",
|
|
4571
4573
|
hint: "no-output watchdog is off; hung async runs must be cancelled manually via acp_delegate_cancel"
|
|
4572
4574
|
});
|
|
4573
4575
|
}
|
|
4574
|
-
return { enabled, displayUsage, maxDepth, syncTimeoutMs, idleMs, asyncTimeoutMs, maxConcurrent, thinkingLevel: cfg.thinkingLevel, agents: cfg.agents, notifyIfRead: cfg.notifyIfRead ?? "skip", fleetShortcut: resolveFleetShortcut(cfg.fleetShortcut) };
|
|
4576
|
+
return { enabled, forceEnable, displayUsage, maxDepth, syncTimeoutMs, idleMs, asyncTimeoutMs, maxConcurrent, thinkingLevel: cfg.thinkingLevel, agents: cfg.agents, notifyIfRead: cfg.notifyIfRead ?? "skip", fleetShortcut: resolveFleetShortcut(cfg.fleetShortcut) };
|
|
4575
4577
|
}
|
|
4576
4578
|
function resolveFleetShortcut(value) {
|
|
4577
4579
|
if (typeof value === "string") return value;
|
|
4578
4580
|
if (value !== void 0) logWarn("config", { event: "delegate-config-invalid", field: "fleetShortcut", value: String(value), fallback: DEFAULT_FLEET_SHORTCUT });
|
|
4579
4581
|
return DEFAULT_FLEET_SHORTCUT;
|
|
4580
4582
|
}
|
|
4583
|
+
function resolveForceEnable(envValue, cfgValue) {
|
|
4584
|
+
if (envValue === "true") return true;
|
|
4585
|
+
if (envValue === "false") return false;
|
|
4586
|
+
if (envValue !== void 0) {
|
|
4587
|
+
logWarn("config", { event: "delegate-config-invalid", field: "forceEnable", value: envValue, fallback: cfgValue === true });
|
|
4588
|
+
}
|
|
4589
|
+
return cfgValue === true;
|
|
4590
|
+
}
|
|
4581
4591
|
function resolveMaxDepth(value) {
|
|
4582
4592
|
if (value === void 0) return DEFAULT_DELEGATE_POLICY.maxDepth;
|
|
4583
4593
|
const n = Number(value);
|
|
@@ -6016,6 +6026,25 @@ var OverflowEpisode = class {
|
|
|
6016
6026
|
}
|
|
6017
6027
|
};
|
|
6018
6028
|
|
|
6029
|
+
// src/turn-boundary.ts
|
|
6030
|
+
function isTurnBoundary(entry, policy = {}) {
|
|
6031
|
+
if (entry.message?.role === "user") return true;
|
|
6032
|
+
return policy.countCustomMessages === true && isCustomMessageEntry(entry);
|
|
6033
|
+
}
|
|
6034
|
+
function lastTurnBoundaryId(entries, policy) {
|
|
6035
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
6036
|
+
const e = entries[i];
|
|
6037
|
+
if (isTurnBoundary(e, policy)) return e.id;
|
|
6038
|
+
}
|
|
6039
|
+
return void 0;
|
|
6040
|
+
}
|
|
6041
|
+
function lastTurnBoundaryIndex(entries, policy) {
|
|
6042
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
6043
|
+
if (isTurnBoundary(entries[i], policy)) return i;
|
|
6044
|
+
}
|
|
6045
|
+
return -1;
|
|
6046
|
+
}
|
|
6047
|
+
|
|
6019
6048
|
// src/runtime.ts
|
|
6020
6049
|
function readContextEntries(sm) {
|
|
6021
6050
|
const source = sm;
|
|
@@ -6027,6 +6056,9 @@ function isPiHost(sm) {
|
|
|
6027
6056
|
const source = sm;
|
|
6028
6057
|
return typeof source.buildContextEntries === "function";
|
|
6029
6058
|
}
|
|
6059
|
+
function retryBreakerKey(sm, policy) {
|
|
6060
|
+
return lastTurnBoundaryId(readContextEntries(sm), policy);
|
|
6061
|
+
}
|
|
6030
6062
|
function mergeLiveEntries(entries, live, state, origins) {
|
|
6031
6063
|
const persisted = entries.filter((e) => e.type === "message");
|
|
6032
6064
|
const liveIdentities = live.map(messageIdentity);
|
|
@@ -6230,6 +6262,40 @@ function createRuntime(adapter) {
|
|
|
6230
6262
|
function dropTokenScale(sid) {
|
|
6231
6263
|
tokenScaleStale.delete(sid);
|
|
6232
6264
|
}
|
|
6265
|
+
const HOST_USAGE_WINDOW = 4;
|
|
6266
|
+
const HOST_USAGE_MIN_SAMPLES = 3;
|
|
6267
|
+
const HOST_USAGE_SPREAD_MAX = 0.25;
|
|
6268
|
+
const hostUsageSamples = /* @__PURE__ */ new Map();
|
|
6269
|
+
function noteHostUsage(sid, tokens) {
|
|
6270
|
+
if (tokens <= 0) return false;
|
|
6271
|
+
let win = hostUsageSamples.get(sid);
|
|
6272
|
+
if (!win) {
|
|
6273
|
+
win = [];
|
|
6274
|
+
hostUsageSamples.set(sid, win);
|
|
6275
|
+
}
|
|
6276
|
+
win.push(tokens);
|
|
6277
|
+
if (win.length > HOST_USAGE_WINDOW) win.shift();
|
|
6278
|
+
if (win.length < HOST_USAGE_MIN_SAMPLES) return false;
|
|
6279
|
+
const lo = Math.min(...win);
|
|
6280
|
+
const hi = Math.max(...win);
|
|
6281
|
+
return (hi - lo) / lo <= HOST_USAGE_SPREAD_MAX;
|
|
6282
|
+
}
|
|
6283
|
+
function dropHostUsageSamples(sid) {
|
|
6284
|
+
hostUsageSamples.delete(sid);
|
|
6285
|
+
}
|
|
6286
|
+
const sizeDivergenceStreaks = /* @__PURE__ */ new Map();
|
|
6287
|
+
function noteSizeDivergence(sid, divergent) {
|
|
6288
|
+
if (!divergent) {
|
|
6289
|
+
sizeDivergenceStreaks.delete(sid);
|
|
6290
|
+
return false;
|
|
6291
|
+
}
|
|
6292
|
+
const streak = (sizeDivergenceStreaks.get(sid) ?? 0) + 1;
|
|
6293
|
+
sizeDivergenceStreaks.set(sid, streak);
|
|
6294
|
+
return streak === 3;
|
|
6295
|
+
}
|
|
6296
|
+
function dropSizeDivergence(sid) {
|
|
6297
|
+
sizeDivergenceStreaks.delete(sid);
|
|
6298
|
+
}
|
|
6233
6299
|
const strictEchoLogged = /* @__PURE__ */ new Set();
|
|
6234
6300
|
const compressOutcomes = /* @__PURE__ */ new Map();
|
|
6235
6301
|
function compressTrackerFor(sid) {
|
|
@@ -6379,6 +6445,7 @@ function createRuntime(adapter) {
|
|
|
6379
6445
|
}
|
|
6380
6446
|
let refused = false;
|
|
6381
6447
|
let refusalMessage = null;
|
|
6448
|
+
let delegateStoodDown = false;
|
|
6382
6449
|
return { core, store, get refused() {
|
|
6383
6450
|
return refused;
|
|
6384
6451
|
}, set refused(v2) {
|
|
@@ -6387,6 +6454,10 @@ function createRuntime(adapter) {
|
|
|
6387
6454
|
return refusalMessage;
|
|
6388
6455
|
}, set refusalMessage(v2) {
|
|
6389
6456
|
refusalMessage = v2;
|
|
6457
|
+
}, get delegateStoodDown() {
|
|
6458
|
+
return delegateStoodDown;
|
|
6459
|
+
}, set delegateStoodDown(v2) {
|
|
6460
|
+
delegateStoodDown = v2;
|
|
6390
6461
|
}, get adapter() {
|
|
6391
6462
|
return adapterRef;
|
|
6392
6463
|
}, setAdapter: (a) => {
|
|
@@ -6395,7 +6466,7 @@ function createRuntime(adapter) {
|
|
|
6395
6466
|
return promptsRef;
|
|
6396
6467
|
}, setPrompts: (p) => {
|
|
6397
6468
|
promptsRef = p;
|
|
6398
|
-
}, markNudgeShown, nudgeShownFor, nudgeShownTokensFor, clearNudgeTracking, clearNudgeTokenStamps, noteCompressOutcomes, compressRetryCappedFor, clearCompressRetryTracking, liveContextLimit, configFor, reasoningDropFor, reloadConfig, stateFor, save, deriveChildState: deriveChild, acquireLock, overflowFor, overflowDrop, noteDeadCompress, clearDeadCompress, throttleFor, throttleDrop, noteTokenScale, dropTokenScale };
|
|
6469
|
+
}, markNudgeShown, nudgeShownFor, nudgeShownTokensFor, clearNudgeTracking, clearNudgeTokenStamps, noteCompressOutcomes, compressRetryCappedFor, clearCompressRetryTracking, liveContextLimit, configFor, reasoningDropFor, reloadConfig, stateFor, save, deriveChildState: deriveChild, acquireLock, overflowFor, overflowDrop, noteDeadCompress, clearDeadCompress, throttleFor, throttleDrop, noteTokenScale, dropTokenScale, noteHostUsage, dropHostUsageSamples, noteSizeDivergence, dropSizeDivergence };
|
|
6399
6470
|
}
|
|
6400
6471
|
|
|
6401
6472
|
// node_modules/typebox/build/system/memory/memory.mjs
|
|
@@ -10792,6 +10863,15 @@ __export(typebox_exports, {
|
|
|
10792
10863
|
With: () => With2
|
|
10793
10864
|
});
|
|
10794
10865
|
|
|
10866
|
+
// src/host.ts
|
|
10867
|
+
function isDeclaredForkHost() {
|
|
10868
|
+
const v2 = process.env.PI_ACP_FORK_HOST;
|
|
10869
|
+
return v2 === "1" || v2?.toLowerCase() === "true";
|
|
10870
|
+
}
|
|
10871
|
+
function isUnsupportedHost(sm) {
|
|
10872
|
+
return !isPiHost(sm) && !isDeclaredForkHost();
|
|
10873
|
+
}
|
|
10874
|
+
|
|
10795
10875
|
// src/tokens.ts
|
|
10796
10876
|
function collectCoveredMessageIds(state) {
|
|
10797
10877
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -10840,25 +10920,6 @@ function adjustedTokenCount(core, messages, state, config, prelim, imageTokensBy
|
|
|
10840
10920
|
return view.drifted ? view.viewTokens : prelim;
|
|
10841
10921
|
}
|
|
10842
10922
|
|
|
10843
|
-
// src/turn-boundary.ts
|
|
10844
|
-
function isTurnBoundary(entry, policy = {}) {
|
|
10845
|
-
if (entry.message?.role === "user") return true;
|
|
10846
|
-
return policy.countCustomMessages === true && isCustomMessageEntry(entry);
|
|
10847
|
-
}
|
|
10848
|
-
function lastTurnBoundaryId(entries, policy) {
|
|
10849
|
-
for (let i = entries.length - 1; i >= 0; i--) {
|
|
10850
|
-
const e = entries[i];
|
|
10851
|
-
if (isTurnBoundary(e, policy)) return e.id;
|
|
10852
|
-
}
|
|
10853
|
-
return void 0;
|
|
10854
|
-
}
|
|
10855
|
-
function lastTurnBoundaryIndex(entries, policy) {
|
|
10856
|
-
for (let i = entries.length - 1; i >= 0; i--) {
|
|
10857
|
-
if (isTurnBoundary(entries[i], policy)) return i;
|
|
10858
|
-
}
|
|
10859
|
-
return -1;
|
|
10860
|
-
}
|
|
10861
|
-
|
|
10862
10923
|
// src/compat.ts
|
|
10863
10924
|
function normalizeSystemPrompt(input) {
|
|
10864
10925
|
if (input === void 0) return "";
|
|
@@ -10887,6 +10948,12 @@ var UNSUPPORTED_HOST_MESSAGE = [
|
|
|
10887
10948
|
" bili omp",
|
|
10888
10949
|
"Docs: https://github.com/ranxianglei/billion-context"
|
|
10889
10950
|
].join("\n");
|
|
10951
|
+
var FORK_HOST_WARNING_MESSAGE = [
|
|
10952
|
+
'[billion-context-pi] Running on a declared fork host (PI_ACP_FORK_HOST). Known limitation: live-tail refs can drift as the session grows, so compress calls may start failing with "does not exist in this session" (#454). Root fix tracked in #459.',
|
|
10953
|
+
"For long sessions on this host, prefer the billion-context proxy \u2014 it runs compression server-side and owns the ref coordinate space:",
|
|
10954
|
+
" npm install -g billion-context",
|
|
10955
|
+
" bili omp"
|
|
10956
|
+
].join("\n");
|
|
10890
10957
|
|
|
10891
10958
|
// src/compress-tool.ts
|
|
10892
10959
|
function formatK2(n) {
|
|
@@ -11158,7 +11225,7 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
|
11158
11225
|
}
|
|
11159
11226
|
return s.text === r.summary ? r : { ...r, summary: s.text };
|
|
11160
11227
|
});
|
|
11161
|
-
const turnKey =
|
|
11228
|
+
const turnKey = retryBreakerKey(ctx.sessionManager, resolveHostSession(runtime.adapter)) ?? sid;
|
|
11162
11229
|
const snapshot = compressibleSnapshotText(turn.nudge);
|
|
11163
11230
|
if (runtime.compressRetryCappedFor(sid, turnKey)) {
|
|
11164
11231
|
logWarn("compress", { sid, event: "capped-reject", turnKey });
|
|
@@ -11247,6 +11314,9 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
|
11247
11314
|
});
|
|
11248
11315
|
if (errors.length > 0) {
|
|
11249
11316
|
logError("compress", { sid: ctx.sessionManager.getSessionId(), event: "errors", count: errors.length, errors: errors.slice(0, 5) });
|
|
11317
|
+
if (blocksCreated === 0 && isDeclaredForkHost() && !isPiHost(ctx.sessionManager) && /does not exist|cannot be anchored|is unknown|unknown refs/i.test(errors.join(" "))) {
|
|
11318
|
+
logWarn("compress", { sid: ctx.sessionManager.getSessionId(), event: "fork-ref-drift-suspected", seeIssue: "#459", errors: errors.slice(0, 3) });
|
|
11319
|
+
}
|
|
11250
11320
|
}
|
|
11251
11321
|
if (warnings.length > 0) {
|
|
11252
11322
|
logWarn("compress", { sid: ctx.sessionManager.getSessionId(), event: "warnings", count: warnings.length, warnings: warnings.slice(0, 5) });
|
|
@@ -11602,7 +11672,7 @@ function resolveActivePack(adapter, cwd, provider, modelId, resolver) {
|
|
|
11602
11672
|
}
|
|
11603
11673
|
var HOST_VERSION = (() => {
|
|
11604
11674
|
try {
|
|
11605
|
-
return "0.1.
|
|
11675
|
+
return "0.1.71";
|
|
11606
11676
|
} catch {
|
|
11607
11677
|
return "dev";
|
|
11608
11678
|
}
|
|
@@ -13560,7 +13630,7 @@ function makeStatusTool(runtime, overrides) {
|
|
|
13560
13630
|
name: "acp_status",
|
|
13561
13631
|
label: "ACP Status",
|
|
13562
13632
|
description: "Context status: overview, compressed blocks, or uncompressed ranges/messages. No args = overview + totals + compressible ranges. scope:'uncompressed' + view:'messages' for per-message listing. scope:'compressed' for block drilldown.",
|
|
13563
|
-
promptSnippet: 'acp_status({}) or acp_status({ scope: "uncompressed"
|
|
13633
|
+
promptSnippet: 'acp_status({}) or acp_status({ scope: "uncompressed" })',
|
|
13564
13634
|
promptGuidelines: [
|
|
13565
13635
|
"Call with no args for a quick overview of context usage.",
|
|
13566
13636
|
"Use scope:'uncompressed' to find the largest compressible ranges.",
|
|
@@ -17897,6 +17967,11 @@ import * as fs6 from "fs";
|
|
|
17897
17967
|
import * as os2 from "os";
|
|
17898
17968
|
import * as path11 from "path";
|
|
17899
17969
|
var ACP_TOOLS3 = ["compress", "decompress", "search_context", "acp_status"];
|
|
17970
|
+
var DELEGATE_STAND_DOWN_MESSAGE = [
|
|
17971
|
+
"[billion-context-pi] pi-subagents detected \u2014 acp_delegate has been automatically disabled to avoid two overlapping sub-agent systems.",
|
|
17972
|
+
"pi-subagents' agents do NOT get ACP context compression by default. Run /acp-subagents to inject compress/decompress/search_context/acp_status into its agent overrides.",
|
|
17973
|
+
'To keep acp_delegate despite pi-subagents being installed, set "delegate": { "forceEnable": true } in acp.json.'
|
|
17974
|
+
].join("\n");
|
|
17900
17975
|
function resolveAgentDir() {
|
|
17901
17976
|
const envDir = process.env.PI_CODING_AGENT_DIR;
|
|
17902
17977
|
if (envDir) {
|
|
@@ -17927,38 +18002,39 @@ function parseFrontmatterTools(content) {
|
|
|
17927
18002
|
if (!name) return null;
|
|
17928
18003
|
return tools ? { name, tools } : { name };
|
|
17929
18004
|
}
|
|
17930
|
-
function
|
|
17931
|
-
const
|
|
17932
|
-
|
|
17933
|
-
|
|
17934
|
-
|
|
17935
|
-
|
|
17936
|
-
|
|
17937
|
-
|
|
17938
|
-
|
|
17939
|
-
|
|
17940
|
-
if (fs6.existsSync(path11.join(dir, "package.json"))) return dir;
|
|
18005
|
+
function npmInstallAt(base) {
|
|
18006
|
+
const dir = path11.join(base, "npm", "node_modules", "pi-subagents");
|
|
18007
|
+
return fs6.existsSync(path11.join(dir, "package.json")) ? dir : null;
|
|
18008
|
+
}
|
|
18009
|
+
function extensionInstallUnder(root) {
|
|
18010
|
+
let entries;
|
|
18011
|
+
try {
|
|
18012
|
+
entries = fs6.readdirSync(root, { withFileTypes: true });
|
|
18013
|
+
} catch {
|
|
18014
|
+
return null;
|
|
17941
18015
|
}
|
|
17942
|
-
for (const
|
|
17943
|
-
|
|
18016
|
+
for (const entry of entries) {
|
|
18017
|
+
if (!entry.isDirectory()) continue;
|
|
18018
|
+
const pkgPath = path11.join(root, entry.name, "package.json");
|
|
17944
18019
|
try {
|
|
17945
|
-
|
|
17946
|
-
|
|
17947
|
-
continue;
|
|
17948
|
-
}
|
|
17949
|
-
for (const entry of entries) {
|
|
17950
|
-
if (!entry.isDirectory()) continue;
|
|
17951
|
-
const pkgPath = path11.join(root, entry.name, "package.json");
|
|
17952
|
-
try {
|
|
17953
|
-
if (JSON.parse(fs6.readFileSync(pkgPath, "utf-8")).name === "pi-subagents") {
|
|
17954
|
-
return path11.join(root, entry.name);
|
|
17955
|
-
}
|
|
17956
|
-
} catch {
|
|
18020
|
+
if (JSON.parse(fs6.readFileSync(pkgPath, "utf-8")).name === "pi-subagents") {
|
|
18021
|
+
return path11.join(root, entry.name);
|
|
17957
18022
|
}
|
|
18023
|
+
} catch {
|
|
17958
18024
|
}
|
|
17959
18025
|
}
|
|
17960
18026
|
return null;
|
|
17961
18027
|
}
|
|
18028
|
+
function findPiSubagentsInstall(agentDir, cwd) {
|
|
18029
|
+
return npmInstallAt(agentDir) ?? npmInstallAt(path11.join(cwd, CONFIG_DIR_NAME2)) ?? extensionInstallUnder(path11.join(agentDir, "extensions")) ?? extensionInstallUnder(path11.join(cwd, CONFIG_DIR_NAME2, "extensions"));
|
|
18030
|
+
}
|
|
18031
|
+
function findPiSubagentsInstalls(agentDir, cwd) {
|
|
18032
|
+
const pick = (paths) => paths.filter((p) => p !== null);
|
|
18033
|
+
return {
|
|
18034
|
+
user: pick([npmInstallAt(agentDir), extensionInstallUnder(path11.join(agentDir, "extensions"))]),
|
|
18035
|
+
project: pick([npmInstallAt(path11.join(cwd, CONFIG_DIR_NAME2)), extensionInstallUnder(path11.join(cwd, CONFIG_DIR_NAME2, "extensions"))])
|
|
18036
|
+
};
|
|
18037
|
+
}
|
|
17962
18038
|
function discoverBuiltinAgents(installDir) {
|
|
17963
18039
|
const agentsDir = path11.join(installDir, "agents");
|
|
17964
18040
|
let entries;
|
|
@@ -18256,7 +18332,7 @@ async function statusReport(runtime, ctx) {
|
|
|
18256
18332
|
const sentTokens = estimateTokens(coreMessages, coveredIds, imageTokens) + systemPromptTokens;
|
|
18257
18333
|
const viewSentTokens = adjustedTokenCount(runtime.core, coreMessages, state, config, sentTokens, imageTokens, systemPromptTokens);
|
|
18258
18334
|
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: anchorStale ? viewSentTokens : Math.max(viewSentTokens, realUsage?.tokens ?? 0) });
|
|
18259
|
-
const versionStr = "0.1.
|
|
18335
|
+
const versionStr = "0.1.71" ? `billion-context-pi@${"0.1.71"} \xB7 pack: ${resolveSurfaceMeta(runtime.adapter, ctx?.cwd ?? process.cwd(), ctx?.model?.provider, ctx?.model?.id).pack}` : void 0;
|
|
18260
18336
|
let text = buildStatusPanel({
|
|
18261
18337
|
version: versionStr,
|
|
18262
18338
|
tokenCount: sessionTokens,
|
|
@@ -18868,7 +18944,7 @@ async function autoInstallLatest(latest, extDirOverride) {
|
|
|
18868
18944
|
"--no-fund",
|
|
18869
18945
|
"--no-save"
|
|
18870
18946
|
];
|
|
18871
|
-
const prevVersion = (await readPackageJson(join15(extDir, "package.json")))?.version ?? "0.1.
|
|
18947
|
+
const prevVersion = (await readPackageJson(join15(extDir, "package.json")))?.version ?? "0.1.71";
|
|
18872
18948
|
const { code, stderr } = await runNpmImpl(installArgs(latest), { cwd: npmDir, timeout: 6e4 });
|
|
18873
18949
|
if (code !== 0) {
|
|
18874
18950
|
logWarn("update", {
|
|
@@ -18886,7 +18962,7 @@ async function autoInstallLatest(latest, extDirOverride) {
|
|
|
18886
18962
|
}
|
|
18887
18963
|
const verify = await verifyInstall(npmDir, latest);
|
|
18888
18964
|
if (!verify.ok) {
|
|
18889
|
-
const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.1.
|
|
18965
|
+
const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.1.71";
|
|
18890
18966
|
logWarn("update", { event: "auto-install-verify-failed", latest, reason: verify.reason, rollbackTo });
|
|
18891
18967
|
const rb = await runNpmImpl(installArgs(rollbackTo), { cwd: npmDir, timeout: 6e4 });
|
|
18892
18968
|
logInfo("update", { event: "rollback", from: latest, to: rollbackTo, ok: rb.code === 0 });
|
|
@@ -18961,7 +19037,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
18961
19037
|
}
|
|
18962
19038
|
const latest = await fetchLatestVersion(tag);
|
|
18963
19039
|
if (!latest) return;
|
|
18964
|
-
const current = runtimeVersion ?? "0.1.
|
|
19040
|
+
const current = runtimeVersion ?? "0.1.71";
|
|
18965
19041
|
const hasUpdate = isVersionNewer(latest, current);
|
|
18966
19042
|
debug.event("update-check", {
|
|
18967
19043
|
current,
|
|
@@ -19019,15 +19095,6 @@ async function getInstalledSpec() {
|
|
|
19019
19095
|
return hostPkg?.dependencies?.[PACKAGE_NAME];
|
|
19020
19096
|
}
|
|
19021
19097
|
|
|
19022
|
-
// src/host.ts
|
|
19023
|
-
function isDeclaredForkHost() {
|
|
19024
|
-
const v2 = process.env.PI_ACP_FORK_HOST;
|
|
19025
|
-
return v2 === "1" || v2?.toLowerCase() === "true";
|
|
19026
|
-
}
|
|
19027
|
-
function isUnsupportedHost(sm) {
|
|
19028
|
-
return !isPiHost(sm) && !isDeclaredForkHost();
|
|
19029
|
-
}
|
|
19030
|
-
|
|
19031
19098
|
// src/proxy-detect.ts
|
|
19032
19099
|
function isBiliProxyBaseUrl(baseUrl) {
|
|
19033
19100
|
if (!baseUrl) return false;
|
|
@@ -19048,6 +19115,13 @@ var PROXY_STAND_DOWN_MESSAGE = [
|
|
|
19048
19115
|
"If your traffic reaches the proxy via HTTPS_PROXY instead (no /bili/ prefix in the URL), export BILLION_CONTEXT_PROXY=1 before starting pi.",
|
|
19049
19116
|
"Docs: https://github.com/ranxianglei/billion-context"
|
|
19050
19117
|
].join("\n");
|
|
19118
|
+
function nativeStandDownMessage(host) {
|
|
19119
|
+
return [
|
|
19120
|
+
`[billion-context-pi] billion-context native host detected (BILLION_CONTEXT_NATIVE=${host}) \u2014 the in-process native plugin proxies model API traffic and owns compression.`,
|
|
19121
|
+
"ACP client-side compression has been disabled for this session to avoid double compression; nothing else to configure.",
|
|
19122
|
+
"Docs: https://github.com/ranxianglei/billion-context"
|
|
19123
|
+
].join("\n");
|
|
19124
|
+
}
|
|
19051
19125
|
|
|
19052
19126
|
// src/index.ts
|
|
19053
19127
|
function createAcpExtension(adapter = {}) {
|
|
@@ -19061,16 +19135,18 @@ function createAcpExtension(adapter = {}) {
|
|
|
19061
19135
|
return;
|
|
19062
19136
|
}
|
|
19063
19137
|
const runtime = createRuntime(adapter);
|
|
19064
|
-
let
|
|
19138
|
+
let standDownWarned = false;
|
|
19065
19139
|
const standDownIfProxied = (ctx) => {
|
|
19066
|
-
|
|
19140
|
+
const nativeHost = process.env.BILLION_CONTEXT_NATIVE || void 0;
|
|
19141
|
+
if (nativeHost === void 0 && !process.env.BILLION_CONTEXT_PROXY && !isBiliProxyBaseUrl(ctx.model?.baseUrl)) return false;
|
|
19142
|
+
const message = nativeHost !== void 0 ? nativeStandDownMessage(nativeHost) : PROXY_STAND_DOWN_MESSAGE;
|
|
19067
19143
|
runtime.refused = true;
|
|
19068
|
-
runtime.refusalMessage =
|
|
19069
|
-
if (!
|
|
19070
|
-
|
|
19071
|
-
logWarn("host", { event: "
|
|
19072
|
-
if (ctx.hasUI) ctx.ui.notify(
|
|
19073
|
-
else console.error(
|
|
19144
|
+
runtime.refusalMessage = message;
|
|
19145
|
+
if (!standDownWarned) {
|
|
19146
|
+
standDownWarned = true;
|
|
19147
|
+
logWarn("host", { event: nativeHost !== void 0 ? "native-host-detected" : "proxy-detected", sid: ctx.sessionManager.getSessionId(), action: "refused", native: nativeHost ?? null });
|
|
19148
|
+
if (ctx.hasUI) ctx.ui.notify(message, "warning");
|
|
19149
|
+
else console.error(message);
|
|
19074
19150
|
}
|
|
19075
19151
|
return true;
|
|
19076
19152
|
};
|
|
@@ -19127,6 +19203,8 @@ function wireDelegateReadTracking(pi) {
|
|
|
19127
19203
|
}
|
|
19128
19204
|
function wireSessionLifecycle(pi, runtime, standDownIfProxied) {
|
|
19129
19205
|
let ompWarned = false;
|
|
19206
|
+
let forkWarned = false;
|
|
19207
|
+
let subagentStandDownWarned = false;
|
|
19130
19208
|
pi.on("session_start", async (_event, ctx) => {
|
|
19131
19209
|
if (isUnsupportedHost(ctx.sessionManager)) {
|
|
19132
19210
|
runtime.refused = true;
|
|
@@ -19139,17 +19217,29 @@ function wireSessionLifecycle(pi, runtime, standDownIfProxied) {
|
|
|
19139
19217
|
}
|
|
19140
19218
|
return;
|
|
19141
19219
|
}
|
|
19220
|
+
if (isDeclaredForkHost() && !isPiHost(ctx.sessionManager)) {
|
|
19221
|
+
const sid2 = ctx.sessionManager.getSessionId();
|
|
19222
|
+
logWarn("host", { event: "fork-host-admitted", sid: sid2, knownLimitation: "ref-drift", seeIssue: "#454", rootFix: "#459" });
|
|
19223
|
+
if (!forkWarned) {
|
|
19224
|
+
forkWarned = true;
|
|
19225
|
+
if (ctx.hasUI) ctx.ui.notify(FORK_HOST_WARNING_MESSAGE, "warning");
|
|
19226
|
+
else console.error(FORK_HOST_WARNING_MESSAGE);
|
|
19227
|
+
}
|
|
19228
|
+
}
|
|
19142
19229
|
if (standDownIfProxied(ctx)) return;
|
|
19143
19230
|
runtime.store.invalidate();
|
|
19144
19231
|
runtime.clearNudgeTracking(ctx.sessionManager.getSessionId());
|
|
19145
19232
|
runtime.throttleFor(ctx.sessionManager.getSessionId()).reset();
|
|
19146
19233
|
runtime.clearCompressRetryTracking(ctx.sessionManager.getSessionId());
|
|
19234
|
+
runtime.dropHostUsageSamples(ctx.sessionManager.getSessionId());
|
|
19235
|
+
runtime.dropSizeDivergence(ctx.sessionManager.getSessionId());
|
|
19147
19236
|
resetDelegateUsage();
|
|
19148
19237
|
setDelegateDisplayUsage("separate");
|
|
19149
19238
|
setDelegatePolicy(DEFAULT_DELEGATE_POLICY);
|
|
19150
19239
|
const sid = ctx.sessionManager.getSessionId();
|
|
19151
19240
|
const modelInfo = ctx.model;
|
|
19152
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.
|
|
19241
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.71" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
|
|
19242
|
+
let delegateStoodDown = false;
|
|
19153
19243
|
try {
|
|
19154
19244
|
await runtime.reloadConfig(ctx.cwd);
|
|
19155
19245
|
const delegateCfg = resolveDelegate(runtime.adapter);
|
|
@@ -19157,9 +19247,24 @@ function wireSessionLifecycle(pi, runtime, standDownIfProxied) {
|
|
|
19157
19247
|
setDelegatePolicy(delegateCfg);
|
|
19158
19248
|
setDelegateDefaults({ thinkingLevel: delegateCfg.thinkingLevel, agents: delegateCfg.agents });
|
|
19159
19249
|
setDelegateNotifyIfRead(delegateCfg.notifyIfRead);
|
|
19250
|
+
if (delegateCfg.enabled && !delegateCfg.forceEnable) {
|
|
19251
|
+
const scopes = findPiSubagentsInstalls(resolveAgentDir(), ctx.cwd ?? process.cwd());
|
|
19252
|
+
if (scopes.project[0] !== void 0) {
|
|
19253
|
+
delegateStoodDown = true;
|
|
19254
|
+
logWarn("delegate", { event: "delegate-auto-disabled", sid, install: scopes.project[0], scope: "project", hint: "run /acp-subagents to give its agents ACP compression tools; delegate.forceEnable=true keeps acp_delegate" });
|
|
19255
|
+
if (!subagentStandDownWarned) {
|
|
19256
|
+
subagentStandDownWarned = true;
|
|
19257
|
+
if (ctx.hasUI) ctx.ui.notify(DELEGATE_STAND_DOWN_MESSAGE, "warning");
|
|
19258
|
+
else console.error(DELEGATE_STAND_DOWN_MESSAGE);
|
|
19259
|
+
}
|
|
19260
|
+
} else if (scopes.user[0] !== void 0) {
|
|
19261
|
+
logWarn("delegate", { event: "delegate-user-scope-detected", sid, install: scopes.user[0], action: "warn-only", hint: "user-level pi-subagents does not disable acp_delegate; run /acp-subagents to give its agents ACP compression tools" });
|
|
19262
|
+
}
|
|
19263
|
+
}
|
|
19160
19264
|
} catch (e) {
|
|
19161
19265
|
logThrow("config", e, { sid, phase: "session_start" });
|
|
19162
19266
|
}
|
|
19267
|
+
runtime.delegateStoodDown = delegateStoodDown;
|
|
19163
19268
|
try {
|
|
19164
19269
|
runtime.setPrompts(resolvePrompts(runtime.adapter.prompts, { acknowledgeRisk: runtime.adapter.acknowledgePromptsRisk === true }));
|
|
19165
19270
|
} catch (e) {
|
|
@@ -19167,7 +19272,7 @@ function wireSessionLifecycle(pi, runtime, standDownIfProxied) {
|
|
|
19167
19272
|
runtime.setPrompts(defaultPrompts);
|
|
19168
19273
|
}
|
|
19169
19274
|
const delegatePolicy2 = resolveDelegate(runtime.adapter);
|
|
19170
|
-
if (delegatePolicy2.enabled) {
|
|
19275
|
+
if (delegatePolicy2.enabled && !runtime.delegateStoodDown) {
|
|
19171
19276
|
pi.registerTool(makeDelegateTool(pi));
|
|
19172
19277
|
pi.registerTool(makeDelegateWaitTool(pi));
|
|
19173
19278
|
pi.registerTool(makeDelegateCancelTool(pi));
|
|
@@ -19192,6 +19297,8 @@ function wireSessionLifecycle(pi, runtime, standDownIfProxied) {
|
|
|
19192
19297
|
runtime.dropTokenScale(sid);
|
|
19193
19298
|
runtime.clearNudgeTracking(sid);
|
|
19194
19299
|
runtime.clearCompressRetryTracking(sid);
|
|
19300
|
+
runtime.dropHostUsageSamples(sid);
|
|
19301
|
+
runtime.dropSizeDivergence(sid);
|
|
19195
19302
|
delegateStatusWidget.dispose();
|
|
19196
19303
|
closeLogStream();
|
|
19197
19304
|
});
|
|
@@ -19235,7 +19342,9 @@ function wireContextTransform(pi, runtime, standDownIfProxied) {
|
|
|
19235
19342
|
}
|
|
19236
19343
|
const hostFloorActive = !usageAnchorPredatesCompression(entries);
|
|
19237
19344
|
const realPromptTokens = realUsage?.tokens ?? 0;
|
|
19238
|
-
const
|
|
19345
|
+
const hostUsageStable = hostFloorActive && realPromptTokens > 0 ? runtime.noteHostUsage(sid, realPromptTokens) : false;
|
|
19346
|
+
const calibrate = (base) => hostUsageStable ? Math.min(base, Math.ceil(realPromptTokens * 1.2)) : base;
|
|
19347
|
+
const applyFloors = (base) => Math.max(calibrate(base), hostFloorActive ? realPromptTokens : 0, armedFloor);
|
|
19239
19348
|
let tokenCount = applyFloors(sentTokens);
|
|
19240
19349
|
if (state.blocks.some((b2) => b2.active && b2.effectiveMessageIds.length > 0)) {
|
|
19241
19350
|
const view = sentViewTokenCount(runtime.core, coreMessages, state, config, tokenCount, imageTokens, systemPromptTokens);
|
|
@@ -19244,12 +19353,20 @@ function wireContextTransform(pi, runtime, standDownIfProxied) {
|
|
|
19244
19353
|
logInfo("turn", { sid, event: "view-recount", prelim: sentTokens, viewTokens: view.viewTokens, tokenCount });
|
|
19245
19354
|
}
|
|
19246
19355
|
}
|
|
19356
|
+
const sizeDivergent = hostFloorActive && realPromptTokens > 0 && Math.abs(tokenCount - realPromptTokens) / realPromptTokens > 0.5;
|
|
19357
|
+
if (runtime.noteSizeDivergence(sid, sizeDivergent)) {
|
|
19358
|
+
logWarn("turn", { sid, event: "size-divergence", est: tokenCount, host: realPromptTokens, ratio: Number((tokenCount / realPromptTokens).toFixed(2)), stable: hostUsageStable });
|
|
19359
|
+
}
|
|
19247
19360
|
if (runtime.noteTokenScale(sid, !hostFloorActive)) {
|
|
19248
|
-
state.nudge.lastNudgeShownTokens = 0;
|
|
19249
|
-
state.nudge.lastPerMessageNudgeTokens = 0;
|
|
19250
|
-
|
|
19361
|
+
state.nudge.lastNudgeShownTokens = state.nudge.lastNudgeShownTokens > 0 ? tokenCount : 0;
|
|
19362
|
+
state.nudge.lastPerMessageNudgeTokens = state.nudge.lastPerMessageNudgeTokens > 0 ? tokenCount : 0;
|
|
19363
|
+
const reanchored = {};
|
|
19364
|
+
for (const [tier, shown] of Object.entries(state.nudge.lastShownByTier)) {
|
|
19365
|
+
if (shown > 0) reanchored[Number(tier)] = tokenCount;
|
|
19366
|
+
}
|
|
19367
|
+
state.nudge.lastShownByTier = reanchored;
|
|
19251
19368
|
runtime.clearNudgeTokenStamps(sid);
|
|
19252
|
-
logInfo("growth-scale", { sid, event: "scale-flip-
|
|
19369
|
+
logInfo("growth-scale", { sid, event: "scale-flip-reanchor", anchorStale: !hostFloorActive, tokenCount });
|
|
19253
19370
|
}
|
|
19254
19371
|
debug.event("context-in", {
|
|
19255
19372
|
sid,
|
|
@@ -19330,8 +19447,9 @@ function wireContextTransform(pi, runtime, standDownIfProxied) {
|
|
|
19330
19447
|
const debugOn2 = debug.enabled;
|
|
19331
19448
|
const turnPolicy = resolveHostSession(runtime.adapter);
|
|
19332
19449
|
const turnKey = lastTurnBoundaryId(entries, turnPolicy) ?? sid;
|
|
19450
|
+
const retryTurnKey = retryBreakerKey(ctx.sessionManager, turnPolicy) ?? sid;
|
|
19333
19451
|
const compressOutcomes = collectCompressOutcomes(entries, lastTurnBoundaryIndex(entries, turnPolicy));
|
|
19334
|
-
const outcome = compressOutcomes.length > 0 ? runtime.noteCompressOutcomes(sid,
|
|
19452
|
+
const outcome = compressOutcomes.length > 0 ? runtime.noteCompressOutcomes(sid, retryTurnKey, compressOutcomes) : null;
|
|
19335
19453
|
const adaptiveGrowth = !config.modelContextLimit || config.modelContextLimit <= 0 ? config.nudge.growthFloor : Math.min(
|
|
19336
19454
|
config.nudge.growthCap,
|
|
19337
19455
|
Math.max(config.nudge.growthFloor, Math.round(config.modelContextLimit * config.nudge.growthRatio))
|
|
@@ -19346,7 +19464,7 @@ function wireContextTransform(pi, runtime, standDownIfProxied) {
|
|
|
19346
19464
|
if (turn.nudge?.shouldInject) {
|
|
19347
19465
|
const emergency = turn.nudge.breakdown?.emergencyOverride === 1;
|
|
19348
19466
|
turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
|
|
19349
|
-
const retryCapped = runtime.compressRetryCappedFor(sid,
|
|
19467
|
+
const retryCapped = runtime.compressRetryCappedFor(sid, retryTurnKey);
|
|
19350
19468
|
const reInjectReady = shownAt === void 0 || tokenCount - shownAt >= reInjectFloor;
|
|
19351
19469
|
const alreadyShown = retryCapped || !emergency && runtime.nudgeShownFor(sid, turnKey) && !reInjectReady;
|
|
19352
19470
|
if (!alreadyShown) {
|
|
@@ -19414,7 +19532,7 @@ function wireSystemPrompt(pi, runtime) {
|
|
|
19414
19532
|
}
|
|
19415
19533
|
runtime.setPrompts(defaultPrompts);
|
|
19416
19534
|
}
|
|
19417
|
-
const delegate = resolveDelegate(runtime.adapter).enabled;
|
|
19535
|
+
const delegate = resolveDelegate(runtime.adapter).enabled && !runtime.delegateStoodDown;
|
|
19418
19536
|
const acp = buildAcpSystemPrompt(runtime.prompts, merged.promptSections);
|
|
19419
19537
|
const delegateText = merged.delegatePrompt !== void 0 ? merged.delegatePrompt : ACP_DELEGATE_PROMPT;
|
|
19420
19538
|
const prompt = delegate && delegateText !== null ? `${acp}
|