billion-context-dsh 0.2.19 → 0.2.20
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.en.md +5 -5
- package/README.md +5 -5
- package/dist/index.d.ts +25 -1
- package/dist/index.js +58 -11
- package/dist/index.js.map +1 -1
- package/dist/window.d.ts +43 -5
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[English](./README.en.md) | [中文](./README.md)
|
|
4
4
|
|
|
5
5
|
> **⚠️ Beta notice — not for production use**
|
|
6
|
-
> This project (**v0.2.
|
|
6
|
+
> This project (**v0.2.20**) is a work-in-progress beta. The [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) itself is also in **public beta**. **Do not use either in engineering / production environments** — expect breaking changes and rough edges.
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
9
|
<strong>Built with gratitude on top of these projects</strong> — please give them a ⭐:
|
|
@@ -98,7 +98,7 @@ This only installs the package into your project/global store; it does **not** t
|
|
|
98
98
|
**Install from the git source (`github:` spec — the form the plugin store shows).** The prebuilt `dist/` artifacts are committed to this repository, so a git-source install also works out of the box — **no build step needed**, and pnpm 11's default build-script blocking (`allowBuilds`) never applies to this package:
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
dsh plugin --profile web add github:Tyan66666/billion-context-dsh#v0.2.
|
|
101
|
+
dsh plugin --profile web add github:Tyan66666/billion-context-dsh#v0.2.20
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
Prefer a `#<tag>` ref to get artifacts identical to that npm release; without a ref you get the latest default-branch build. Only building the repo yourself (`npm run build`) requires approving build scripts. Background and trade-offs: [docs/git-source-install-design.md](docs/git-source-install-design.md) (issue #92).
|
|
@@ -216,8 +216,8 @@ This project reuses `acp-kernel`'s compression core and `billion-context-pi`'s d
|
|
|
216
216
|
|
|
217
217
|
| Key | Default | Meaning |
|
|
218
218
|
|---|---|---|
|
|
219
|
-
| `modelContextLimit` | auto-detected (fallback `128000`) | Context window used for the kernel's pressure decisions; an explicit value wins and skips detection. When omitted, the host session projection `contextPressure.contextWindow` is read first — the capacity disclosed for the **current real route** (a session that switched models follows automatically, no restart needed) — and the model API is probed only when the projection discloses no window |
|
|
220
|
-
| `autoModelContextLimit` | `true` | Resolve the real context window automatically: the host projection first (`windowFor` → `projectedContextWindow`, `src/window.ts`), then the model API probe (`agent.ctx.llm.resolveModelInfo`); both are skipped when `autoModelContextLimit: false`. On probe failure it falls back to the default, and the `/acp` command shows the window source (the `acp_status` model tool carries no window info). A failed probe is surfaced in the host log and the `/acp` panel (`restart to re-probe`) — the failure is cached like a success, so fixing the gateway requires a restart or an explicit `modelContextLimit` before the probe retries |
|
|
219
|
+
| `modelContextLimit` | auto-detected (fallback `128000`) | Context window used for the kernel's pressure decisions; an explicit value wins and skips detection. When omitted, the host session projection `contextPressure.contextWindow` is read first — the capacity disclosed for the **current real route** (a session that switched models follows automatically, no restart needed) — and the model API is probed only when the projection discloses no window; an explicit value also skips the output-reservation subtraction (the operator owns the denominator) |
|
|
220
|
+
| `autoModelContextLimit` | `true` | Resolve the real context window automatically: the host projection first (`windowFor` → `projectedContextWindow`, `src/window.ts`), then the model API probe (`agent.ctx.llm.resolveModelInfo`); both are skipped when `autoModelContextLimit: false`. On probe failure it falls back to the default, and the `/acp` command shows the window source (the `acp_status` model tool carries no window info). A failed probe is surfaced in the host log and the `/acp` panel (`restart to re-probe`) — the failure is cached like a success, so fixing the gateway requires a restart or an explicit `modelContextLimit` before the probe retries. On a successful probe the adapter's per-request output cap (`defaultMaxTokens` — the output reservation the provider guarantees at the end of the window) is SUBTRACTED, so every downstream pressure decision (nudge tiers, truncate, growth) measures usage against the SUSTAINABLE input budget (window − reservation): a 96K window with a 16K cap carries at most 80K of input, and the raw denominator understated usage by cap/window (≈17% there — and the ratio is far higher on short-window models, where the same cap is a quarter or more of the window). When the cap is undisclosed, the limit is explicit, or the probe fails, the raw-window behavior is kept; `/acp status` shows the subtraction (raw − reservation) |
|
|
221
221
|
| `nudgeMinContextLimitPct` | kernel default `0.45` | Nudge window lower bound (usage fraction) — validation only; the growth-driven trigger has no percentage floor — same default as billion-context-pi |
|
|
222
222
|
| `nudgeMaxContextLimitPct` | engine default `0.70` (kernel/pi default `0.75`) | Over-limit line: above this the nudge fires regardless of growth — deliberately below the host compaction-basic 80% auto-compaction line so the forced nudge fires first; an explicit value wins (a same-name key in `coreOverrides.nudge` outranks it — see below) |
|
|
223
223
|
| `nudgeEmergencyThresholdPct` | engine default `0.85` (kernel/pi default `0.95`) | Emergency nudge (bypasses the per-turn dedup) — lowered from `0.95`: at 95% the model has no room to act and the 80% auto-compaction line shadows it; an explicit value wins (a same-name key in `coreOverrides.nudge` outranks it — see below) |
|
|
@@ -250,7 +250,7 @@ src/
|
|
|
250
250
|
├── nudge.ts # M4: kernel pressure decision → injected advisory nudge
|
|
251
251
|
├── system-prompt.ts# M4: one-time ACP guidance section (keeps nudges short)
|
|
252
252
|
├── config.ts # kernel config assembly (thresholds + coreOverrides)
|
|
253
|
-
├── window.ts # auto context-window detection (session projection first, LLM runtime probe fallback, default 128000)
|
|
253
|
+
├── window.ts # auto context-window detection (session projection first, LLM runtime probe fallback, default 128000) + output-reservation probe (defaultMaxTokens, subtracted in windowFor)
|
|
254
254
|
└── commands.ts # M4: /acp slash command
|
|
255
255
|
```
|
|
256
256
|
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[中文](./README.md) | [English](./README.en.md)
|
|
4
4
|
|
|
5
5
|
> **⚠️ 测试版声明——请勿用于生产环境**
|
|
6
|
-
> 本项目(**v0.2.
|
|
6
|
+
> 本项目(**v0.2.20**)仍处于开发中的测试版。[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 本身也处于**公开测试版**阶段。**请勿将两者用于工程化 / 生产环境**——预期会有破坏性变更与粗糙之处。
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
9
|
<strong>衷心感谢以下项目——请给它们一个 ⭐:</strong>
|
|
@@ -97,7 +97,7 @@ npm install billion-context-dsh
|
|
|
97
97
|
**git 源安装(`github:` 规格,插件商店展示的形态)。** 预构建产物 `dist/` 已提交到仓库,从 git 源安装同样开箱即用——**无需任何构建步骤**,pnpm 11 默认拦截构建脚本(`allowBuilds`)的机制对这个包不构成障碍:
|
|
98
98
|
|
|
99
99
|
```bash
|
|
100
|
-
dsh plugin --profile web add github:Tyan66666/billion-context-dsh#v0.2.
|
|
100
|
+
dsh plugin --profile web add github:Tyan66666/billion-context-dsh#v0.2.20
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
建议带 `#<tag>` 安装,拿到与对应 npm 版本完全一致的产物;不带 ref 则装默认分支的最新构建。只有 clone 仓库自行从源码构建(`npm run build`)才需要放行构建。背景与方案取舍见 [docs/git-source-install-design.md](docs/git-source-install-design.md)(issue #92)。
|
|
@@ -213,8 +213,8 @@ DSH 的每个模型请求都派生自其 append-only 会话日志(*surface*)
|
|
|
213
213
|
|
|
214
214
|
| 键 | 默认值 | 含义 |
|
|
215
215
|
|---|---|---|
|
|
216
|
-
| `modelContextLimit` | 自动探测(回退 `128000`) | 用于内核压力决策的上下文窗口;显式配置时优先且跳过探测。省略时优先读宿主会话投影 `contextPressure.contextWindow`(按**当前真实路由**披露的新窗口,切模型会话自动跟随,无需重启),无投影时再从模型 API
|
|
217
|
-
| `autoModelContextLimit` | `true` | 从模型 API 自动探测真实窗口(`agent.ctx.llm.resolveModelInfo`);探测失败回退默认值,`/acp` 命令展示窗口来源(模型工具 `acp_status` 不含窗口信息)。省略时窗口先读宿主投影(`windowFor` → `projectedContextWindow`,`src/window.ts`)再走探测;投影与探测在 `autoModelContextLimit: false` 时均跳过。探测失败会在宿主日志与 `/acp` 面板提示(`restart to re-probe`)——失败结果同样被缓存,修复网关后需重启或显式设置 `modelContextLimit`
|
|
216
|
+
| `modelContextLimit` | 自动探测(回退 `128000`) | 用于内核压力决策的上下文窗口;显式配置时优先且跳过探测。省略时优先读宿主会话投影 `contextPressure.contextWindow`(按**当前真实路由**披露的新窗口,切模型会话自动跟随,无需重启),无投影时再从模型 API 探测;显式配置同样跳过输出预留扣减(分母完全由操作者定义) |
|
|
217
|
+
| `autoModelContextLimit` | `true` | 从模型 API 自动探测真实窗口(`agent.ctx.llm.resolveModelInfo`);探测失败回退默认值,`/acp` 命令展示窗口来源(模型工具 `acp_status` 不含窗口信息)。省略时窗口先读宿主投影(`windowFor` → `projectedContextWindow`,`src/window.ts`)再走探测;投影与探测在 `autoModelContextLimit: false` 时均跳过。探测失败会在宿主日志与 `/acp` 面板提示(`restart to re-probe`)——失败结果同样被缓存,修复网关后需重启或显式设置 `modelContextLimit` 才会重新探测。探测成功后还会**扣减 adapter 的每请求输出上限**(`defaultMaxTokens`,窗口末端每请求保证的输出预留):所有下游压力决策(nudge 档位、truncate、growth)以「可持续输入预算」(窗口 − 输出预留)为分母——96K 窗口 + 16K 上限实际最多承载 80K 输入,原裸窗口分母会把用量低估 cap/window(此处 ≈17%;小上下文窗口模型比例更高);上限未披露、显式配置或探测失败时保持裸窗口行为,`/acp status` 展示扣减明细(raw − reservation) |
|
|
218
218
|
| `nudgeMinContextLimitPct` | 内核默认 `0.45` | Nudge 窗口下界(用量占比)——仅作配置校验,增长路径的触发没有百分比下限——与 billion-context-pi 相同的默认值 |
|
|
219
219
|
| `nudgeMaxContextLimitPct` | engine 默认 `0.70`(内核/pi 默认 `0.75`) | 过限线:超过此值则无论增长与否都触发 nudge——刻意低于宿主 compaction-basic 的 80% 自动压缩线,保证强制 nudge 先触发;显式配置优先(`coreOverrides.nudge` 同名键优先级更高,见下) |
|
|
220
220
|
| `nudgeEmergencyThresholdPct` | engine 默认 `0.85`(内核/pi 默认 `0.95`) | 紧急 nudge(绕过每轮去重)——从 `0.95` 下调:95% 时模型已无操作空间且会被 80% 自动压缩线遮蔽;显式配置优先(`coreOverrides.nudge` 同名键优先级更高,见下) |
|
|
@@ -247,7 +247,7 @@ src/
|
|
|
247
247
|
├── nudge.ts # M4: 内核压力决策 → 注入的建议式 nudge
|
|
248
248
|
├── system-prompt.ts# M4: 一次性 ACP 指引段(让 nudge 保持简短)
|
|
249
249
|
├── config.ts # 内核配置组装(阈值 + coreOverrides)
|
|
250
|
-
├── window.ts # 自动上下文窗口探测(宿主投影优先,LLM 运行时探测回退,兜底 128000
|
|
250
|
+
├── window.ts # 自动上下文窗口探测(宿主投影优先,LLM 运行时探测回退,兜底 128000)+ 输出预留探测(defaultMaxTokens,windowFor 内扣除)
|
|
251
251
|
└── commands.ts # M4: /acp 斜杠命令
|
|
252
252
|
```
|
|
253
253
|
|
package/dist/index.d.ts
CHANGED
|
@@ -128,6 +128,8 @@ export declare class AcpCompactionEngine extends CompactionEngine {
|
|
|
128
128
|
private readonly compressCallIdsToHide;
|
|
129
129
|
/** Per provider/model route the resolved window (probe failures cached too). */
|
|
130
130
|
private readonly windowCache;
|
|
131
|
+
/** Per route the adapter's per-request output cap (the output reservation); null = undisclosed. */
|
|
132
|
+
private readonly outputReservationCache;
|
|
131
133
|
constructor(ctx: Context, config?: Partial<AcpConfig>);
|
|
132
134
|
/**
|
|
133
135
|
* Resolve the effective context window for an agent. An explicitly
|
|
@@ -138,9 +140,31 @@ export declare class AcpCompactionEngine extends CompactionEngine {
|
|
|
138
140
|
* projectedContextWindow). Falls back to probing the model's real window
|
|
139
141
|
* via `agent.ctx.llm.resolveModelInfo` (cached per provider/model route,
|
|
140
142
|
* probe failures cached too) and finally to DEFAULT_CONTEXT_WINDOW when
|
|
141
|
-
* auto-detection is disabled or unavailable.
|
|
143
|
+
* auto-detection is disabled or unavailable. On the auto-detected paths the
|
|
144
|
+
* adapter's per-request output cap is then SUBTRACTED from the window
|
|
145
|
+
* (applyReservation): every downstream usage computation must run against
|
|
146
|
+
* the SUSTAINABLE input budget (window minus output reservation), not the
|
|
147
|
+
* raw window — a 96K window with a 16K cap carries at most 80K of input,
|
|
148
|
+
* so the raw denominator understates usage by cap/window (≈17% there, and
|
|
149
|
+
* far worse on short-window models). An explicit limit keeps the operator's
|
|
150
|
+
* exact value (they own the denominator); a failed probe keeps the raw
|
|
151
|
+
* fallback.
|
|
142
152
|
*/
|
|
143
153
|
windowFor(agent: Agent): Promise<AcpWindow>;
|
|
154
|
+
/**
|
|
155
|
+
* The adapter's per-request output cap for a route, from one
|
|
156
|
+
* probeModelWindow call (a local catalog lookup — no request is sent),
|
|
157
|
+
* cached per route like the window itself.
|
|
158
|
+
*/
|
|
159
|
+
private outputCapFor;
|
|
160
|
+
/**
|
|
161
|
+
* Subtract the output reservation from a resolved window: `limit` becomes
|
|
162
|
+
* the SUSTAINABLE input budget (`rawLimit - outputReserved`) that every
|
|
163
|
+
* downstream usage computation (nudge tiers, truncate, growth) measures
|
|
164
|
+
* against. No-op when the cap is unknown or not smaller than the window
|
|
165
|
+
* (degenerate config) — the raw-window behavior is preserved.
|
|
166
|
+
*/
|
|
167
|
+
private applyReservation;
|
|
144
168
|
/** ACP is model-driven: automatic pressure policy never summarizes by itself. */
|
|
145
169
|
compactIfNeeded(_agent: CompactionAgentContext, _trigger: CompactionTrigger, signal: AbortSignal): Promise<CompactionResult | null>;
|
|
146
170
|
/** Explicit idle-session compaction: ACP leaves the decision to the model. */
|
package/dist/index.js
CHANGED
|
@@ -4383,18 +4383,24 @@ function projectedContextWindow(agent) {
|
|
|
4383
4383
|
if (typeof window === "number" && Number.isInteger(window) && window > 0) return window;
|
|
4384
4384
|
return null;
|
|
4385
4385
|
}
|
|
4386
|
-
async function
|
|
4386
|
+
async function probeModelWindow(agent, provider, model) {
|
|
4387
4387
|
const llm = agent.ctx?.get?.("llm");
|
|
4388
|
-
if (llm?.resolveModelInfo === void 0) return null;
|
|
4388
|
+
if (llm?.resolveModelInfo === void 0) return { contextWindow: null, outputReservation: null };
|
|
4389
4389
|
try {
|
|
4390
4390
|
const info = await llm.resolveModelInfo(provider, model);
|
|
4391
4391
|
const window = info?.context?.contextWindow;
|
|
4392
|
-
|
|
4393
|
-
return
|
|
4392
|
+
const cap = info?.defaultMaxTokens;
|
|
4393
|
+
return {
|
|
4394
|
+
contextWindow: typeof window === "number" && Number.isInteger(window) && window > 0 ? window : null,
|
|
4395
|
+
outputReservation: typeof cap === "number" && Number.isInteger(cap) && cap > 0 ? cap : null
|
|
4396
|
+
};
|
|
4394
4397
|
} catch {
|
|
4395
|
-
return null;
|
|
4398
|
+
return { contextWindow: null, outputReservation: null };
|
|
4396
4399
|
}
|
|
4397
4400
|
}
|
|
4401
|
+
async function detectContextWindow(agent, provider, model) {
|
|
4402
|
+
return (await probeModelWindow(agent, provider, model)).contextWindow;
|
|
4403
|
+
}
|
|
4398
4404
|
|
|
4399
4405
|
// src/commands.ts
|
|
4400
4406
|
async function statusText(env, agent) {
|
|
@@ -4406,12 +4412,13 @@ async function statusText(env, agent) {
|
|
|
4406
4412
|
const estimated = resolveTokenCount(agent, surfaceMessages);
|
|
4407
4413
|
const window = await resolveEffectiveWindow(env, agent);
|
|
4408
4414
|
const limit = window.limit;
|
|
4415
|
+
const windowLine = window.rawLimit !== void 0 && window.outputReserved !== void 0 ? ` context window: ${limit} (raw ${window.rawLimit} \u2212 ${window.outputReserved} output reservation; ${windowSourceLabel(window)})` : ` context window: ${limit} (${windowSourceLabel(window)})`;
|
|
4409
4416
|
const lines = [
|
|
4410
4417
|
`ACP status \u2014 session ${session.id}`,
|
|
4411
4418
|
` blocks: ${ledger.length}`,
|
|
4412
4419
|
` tokens compressed: ${totalTokens}`,
|
|
4413
4420
|
` estimated context: ${estimated} / ${limit} (${Math.round(estimated / limit * 100)}%)`,
|
|
4414
|
-
|
|
4421
|
+
windowLine
|
|
4415
4422
|
];
|
|
4416
4423
|
if (window.probeFailed === true) {
|
|
4417
4424
|
lines.push(` \u26A0 window auto-detection failed \u2014 using the ${limit} fallback (restart to re-probe, or set modelContextLimit explicitly)`);
|
|
@@ -4540,6 +4547,8 @@ var AcpCompactionEngine = class extends CompactionEngine {
|
|
|
4540
4547
|
compressCallIdsToHide = /* @__PURE__ */ new Set();
|
|
4541
4548
|
/** Per provider/model route the resolved window (probe failures cached too). */
|
|
4542
4549
|
windowCache = /* @__PURE__ */ new Map();
|
|
4550
|
+
/** Per route the adapter's per-request output cap (the output reservation); null = undisclosed. */
|
|
4551
|
+
outputReservationCache = /* @__PURE__ */ new Map();
|
|
4543
4552
|
constructor(ctx, config = {}) {
|
|
4544
4553
|
super(ctx);
|
|
4545
4554
|
this.config = resolveAcpConfig(config);
|
|
@@ -4648,7 +4657,15 @@ var AcpCompactionEngine = class extends CompactionEngine {
|
|
|
4648
4657
|
* projectedContextWindow). Falls back to probing the model's real window
|
|
4649
4658
|
* via `agent.ctx.llm.resolveModelInfo` (cached per provider/model route,
|
|
4650
4659
|
* probe failures cached too) and finally to DEFAULT_CONTEXT_WINDOW when
|
|
4651
|
-
* auto-detection is disabled or unavailable.
|
|
4660
|
+
* auto-detection is disabled or unavailable. On the auto-detected paths the
|
|
4661
|
+
* adapter's per-request output cap is then SUBTRACTED from the window
|
|
4662
|
+
* (applyReservation): every downstream usage computation must run against
|
|
4663
|
+
* the SUSTAINABLE input budget (window minus output reservation), not the
|
|
4664
|
+
* raw window — a 96K window with a 16K cap carries at most 80K of input,
|
|
4665
|
+
* so the raw denominator understates usage by cap/window (≈17% there, and
|
|
4666
|
+
* far worse on short-window models). An explicit limit keeps the operator's
|
|
4667
|
+
* exact value (they own the denominator); a failed probe keeps the raw
|
|
4668
|
+
* fallback.
|
|
4652
4669
|
*/
|
|
4653
4670
|
async windowFor(agent) {
|
|
4654
4671
|
if (this.config.modelContextLimit !== void 0) {
|
|
@@ -4660,28 +4677,58 @@ var AcpCompactionEngine = class extends CompactionEngine {
|
|
|
4660
4677
|
if (this.config.autoModelContextLimit) {
|
|
4661
4678
|
const projected = projectedContextWindow(agent);
|
|
4662
4679
|
if (projected !== null) {
|
|
4663
|
-
|
|
4680
|
+
const cap2 = await this.outputCapFor(agent, provider, model);
|
|
4681
|
+
return this.applyReservation({ limit: projected, source: "projection", provider, model }, cap2);
|
|
4664
4682
|
}
|
|
4665
4683
|
}
|
|
4666
4684
|
const cached = this.windowCache.get(key);
|
|
4667
4685
|
if (cached !== void 0) return cached;
|
|
4668
4686
|
let window;
|
|
4687
|
+
let cap = null;
|
|
4669
4688
|
if (!this.config.autoModelContextLimit) {
|
|
4670
4689
|
window = { limit: DEFAULT_CONTEXT_WINDOW, source: "default", provider, model };
|
|
4671
4690
|
} else {
|
|
4672
|
-
const
|
|
4673
|
-
|
|
4691
|
+
const probe = await probeModelWindow(agent, provider, model);
|
|
4692
|
+
cap = probe.outputReservation;
|
|
4693
|
+
if (probe.contextWindow === null) {
|
|
4674
4694
|
this.ctx.logger.warn(
|
|
4675
4695
|
`billion-context-dsh: context-window auto-detection failed for ${provider}/${model} \u2014 using the ${DEFAULT_CONTEXT_WINDOW} fallback (restart to re-probe, or set modelContextLimit explicitly)`
|
|
4676
4696
|
);
|
|
4677
4697
|
window = { limit: DEFAULT_CONTEXT_WINDOW, source: "default", provider, model, probeFailed: true };
|
|
4698
|
+
cap = null;
|
|
4678
4699
|
} else {
|
|
4679
|
-
window = { limit:
|
|
4700
|
+
window = { limit: probe.contextWindow, source: "auto", provider, model };
|
|
4680
4701
|
}
|
|
4681
4702
|
}
|
|
4703
|
+
window = this.applyReservation(window, cap);
|
|
4682
4704
|
this.windowCache.set(key, window);
|
|
4683
4705
|
return window;
|
|
4684
4706
|
}
|
|
4707
|
+
/**
|
|
4708
|
+
* The adapter's per-request output cap for a route, from one
|
|
4709
|
+
* probeModelWindow call (a local catalog lookup — no request is sent),
|
|
4710
|
+
* cached per route like the window itself.
|
|
4711
|
+
*/
|
|
4712
|
+
async outputCapFor(agent, provider, model) {
|
|
4713
|
+
if (provider === "" || model === "") return null;
|
|
4714
|
+
const key = `${provider}\0${model}`;
|
|
4715
|
+
const known = this.outputReservationCache.get(key);
|
|
4716
|
+
if (known !== void 0) return known;
|
|
4717
|
+
const cap = (await probeModelWindow(agent, provider, model)).outputReservation;
|
|
4718
|
+
this.outputReservationCache.set(key, cap);
|
|
4719
|
+
return cap;
|
|
4720
|
+
}
|
|
4721
|
+
/**
|
|
4722
|
+
* Subtract the output reservation from a resolved window: `limit` becomes
|
|
4723
|
+
* the SUSTAINABLE input budget (`rawLimit - outputReserved`) that every
|
|
4724
|
+
* downstream usage computation (nudge tiers, truncate, growth) measures
|
|
4725
|
+
* against. No-op when the cap is unknown or not smaller than the window
|
|
4726
|
+
* (degenerate config) — the raw-window behavior is preserved.
|
|
4727
|
+
*/
|
|
4728
|
+
applyReservation(window, cap) {
|
|
4729
|
+
if (cap === null || cap >= window.limit) return window;
|
|
4730
|
+
return { ...window, rawLimit: window.limit, outputReserved: cap, limit: window.limit - cap };
|
|
4731
|
+
}
|
|
4685
4732
|
/** ACP is model-driven: automatic pressure policy never summarizes by itself. */
|
|
4686
4733
|
async compactIfNeeded(_agent, _trigger, signal) {
|
|
4687
4734
|
signal.throwIfAborted();
|