billion-context-pi 0.1.59 → 0.1.60-pr.337.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.d.ts CHANGED
@@ -206,6 +206,12 @@ export interface AdapterConfig {
206
206
  * disables) or a ThrottleRetryConfig object. Default: enabled, 10 retries,
207
207
  * 60s exponential base capped at 300s per kick. */
208
208
  throttleRetry?: boolean | ThrottleRetryConfig;
209
+ /** Cap on the output-headroom reservation as a fraction of the context
210
+ * window: reserved = min(model.maxTokens, pct * window). Accepts a ratio
211
+ * (0.25) or percent string ("25%"). Default: 0.25. Set 0 to disable the
212
+ * reservation entirely; >= 1 restores the legacy full-capability
213
+ * reservation (issue #207). */
214
+ outputHeadroomMaxPct?: number | string;
209
215
  /** Generic tool-call repetition guard (see RepetitionGuardConfig). Accepts a
210
216
  * boolean shorthand (`false` disables) or an object. Default: enabled,
211
217
  * warn=3, abort=5. Stops greedy small models looping on byte-identical
package/dist/index.js CHANGED
@@ -4192,10 +4192,10 @@ var SessionStateStore = class {
4192
4192
  }
4193
4193
  async save(state, sessionFile, sessionId) {
4194
4194
  const file = stateFileFor(sessionFile);
4195
- if (!file) return;
4196
4195
  const key = cacheKey(sessionFile, sessionId);
4197
4196
  const liveRefOrigins = this.cache.get(key)?.liveRefOrigins ?? [];
4198
4197
  this.cache.set(key, { state, liveRefOrigins });
4198
+ if (!file) return;
4199
4199
  const dir = path2.dirname(file);
4200
4200
  await fs.mkdir(dir, { recursive: true }).catch((e) => {
4201
4201
  logError("state", { event: "save-mkdir-failed", dir, error: e instanceof Error ? e.message : String(e) });
@@ -4462,6 +4462,7 @@ var KNOWN = /* @__PURE__ */ new Set([
4462
4462
  "compress",
4463
4463
  "displayUsage",
4464
4464
  "throttleRetry",
4465
+ "outputHeadroomMaxPct",
4465
4466
  "prompts",
4466
4467
  "acknowledgePromptsRisk"
4467
4468
  ]);
@@ -4699,19 +4700,25 @@ function toTokenNumber(raw) {
4699
4700
  const n = Number(raw.replace(/,/g, ""));
4700
4701
  return Number.isFinite(n) && n >= 1e3 ? n : void 0;
4701
4702
  }
4702
- function reserveOutputHeadroom(window, maxOutput) {
4703
+ var DEFAULT_OUTPUT_HEADROOM_MAX_PCT = 0.25;
4704
+ function resolveOutputHeadroomCap(value) {
4705
+ return value === void 0 ? DEFAULT_OUTPUT_HEADROOM_MAX_PCT : parsePercent(value);
4706
+ }
4707
+ function reserveOutputHeadroom(window, maxOutput, capPct = 1) {
4703
4708
  if (Number.isFinite(window) && window > 0 && Number.isFinite(maxOutput) && maxOutput > 0 && maxOutput < window) {
4704
- return window - maxOutput;
4709
+ const cap = Number.isFinite(capPct) ? Math.max(0, Math.min(capPct, 1)) : 1;
4710
+ const reserved = Math.min(maxOutput, cap * window);
4711
+ return reserved > 0 ? window - reserved : window;
4705
4712
  }
4706
4713
  return window;
4707
4714
  }
4708
4715
  function shouldReserveOutputHeadroom(api) {
4709
4716
  return api !== "anthropic-messages";
4710
4717
  }
4711
- function applyOutputHeadroom(config, model) {
4718
+ function applyOutputHeadroom(config, model, capPct = 1) {
4712
4719
  const maxOutput = model?.maxTokens ?? 0;
4713
4720
  if (shouldReserveOutputHeadroom(model?.api)) {
4714
- const reserved = reserveOutputHeadroom(config.modelContextLimit, maxOutput);
4721
+ const reserved = reserveOutputHeadroom(config.modelContextLimit, maxOutput, capPct);
4715
4722
  if (reserved !== config.modelContextLimit) return { ...config, modelContextLimit: reserved };
4716
4723
  }
4717
4724
  return config;
@@ -9851,6 +9858,9 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
9851
9858
  logWarn("compress", { sid: ctx.sessionManager.getSessionId(), event: "warnings", count: warnings.length, warnings: warnings.slice(0, 5) });
9852
9859
  }
9853
9860
  const lines = [`\u25A3 ACP | ${formatK2(beforeTokens)} \u2192 ${formatK2(afterTokens)} tokens (~${formatK2(reclaimed)} reclaimed, ${blocksCreated} block${blocksCreated > 1 ? "s" : ""})`];
9861
+ if (blocksCreated > 0) {
9862
+ lines.push(`Compressed: ${newBlocks.map((b2) => `${b2.blockId} (${b2.startRef ?? "?"}..${b2.endRef ?? "?"})`).join(", ")} \u2014 these refs are now consumed; do not compress them again.`);
9863
+ }
9854
9864
  if (warnings.length > 0) lines.push("\u26A0\uFE0F " + warnings.join("; "));
9855
9865
  if (errors.length > 0) lines.push("Errors: " + errors.join("; "));
9856
9866
  return lines.join("\n");
@@ -12025,7 +12035,7 @@ function makeStatusTool(runtime) {
12025
12035
  }
12026
12036
  async function handleStatus(args, runtime, ctx) {
12027
12037
  const { state, coreMessages, entries } = await runtime.stateFor(ctx);
12028
- const config = applyOutputHeadroom(runtime.configFor(ctx), ctx.model);
12038
+ const config = applyOutputHeadroom(runtime.configFor(ctx), ctx.model, resolveOutputHeadroomCap(runtime.adapter.outputHeadroomMaxPct));
12029
12039
  const coveredIds = collectCoveredMessageIds(state);
12030
12040
  const systemPromptText = getSystemPromptText(ctx);
12031
12041
  const systemPromptTokens = systemPromptText ? defaultCountTokens(systemPromptText) : 0;
@@ -16521,7 +16531,7 @@ ${text}`);
16521
16531
  }
16522
16532
  async function statusReport(runtime, ctx) {
16523
16533
  const { state, coreMessages, entries } = await runtime.stateFor(ctx);
16524
- const config = applyOutputHeadroom(runtime.configFor(ctx), ctx.model);
16534
+ const config = applyOutputHeadroom(runtime.configFor(ctx), ctx.model, resolveOutputHeadroomCap(runtime.adapter.outputHeadroomMaxPct));
16525
16535
  const realUsage = ctx.getContextUsage?.();
16526
16536
  const anchorStale = usageAnchorPredatesCompression(entries ?? []);
16527
16537
  const systemPromptText = getSystemPromptText(ctx);
@@ -16533,7 +16543,7 @@ async function statusReport(runtime, ctx) {
16533
16543
  const sentTokens = estimateTokens(coreMessages, coveredIds, imageTokens) + systemPromptTokens;
16534
16544
  const viewSentTokens = adjustedTokenCount(runtime.core, coreMessages, state, config, sentTokens, imageTokens, systemPromptTokens);
16535
16545
  const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: anchorStale ? viewSentTokens : Math.max(viewSentTokens, realUsage?.tokens ?? 0) });
16536
- const versionStr = "0.1.59" ? `billion-context-pi@${"0.1.59"}` : void 0;
16546
+ const versionStr = "0.1.60" ? `billion-context-pi@${"0.1.60"}` : void 0;
16537
16547
  let text = buildStatusPanel({
16538
16548
  version: versionStr,
16539
16549
  tokenCount: sessionTokens,
@@ -17067,7 +17077,7 @@ async function autoInstallLatest(latest, extDirOverride) {
17067
17077
  "--no-fund",
17068
17078
  "--no-save"
17069
17079
  ];
17070
- const prevVersion = (await readPackageJson(join11(extDir, "package.json")))?.version ?? "0.1.59";
17080
+ const prevVersion = (await readPackageJson(join11(extDir, "package.json")))?.version ?? "0.1.60";
17071
17081
  const { code, stderr } = await runNpmImpl(installArgs(latest), { cwd: npmDir, timeout: 6e4 });
17072
17082
  if (code !== 0) {
17073
17083
  logWarn("update", {
@@ -17085,7 +17095,7 @@ async function autoInstallLatest(latest, extDirOverride) {
17085
17095
  }
17086
17096
  const verify = await verifyInstall(npmDir, latest);
17087
17097
  if (!verify.ok) {
17088
- const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.1.59";
17098
+ const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.1.60";
17089
17099
  logWarn("update", { event: "auto-install-verify-failed", latest, reason: verify.reason, rollbackTo });
17090
17100
  const rb = await runNpmImpl(installArgs(rollbackTo), { cwd: npmDir, timeout: 6e4 });
17091
17101
  logInfo("update", { event: "rollback", from: latest, to: rollbackTo, ok: rb.code === 0 });
@@ -17160,7 +17170,7 @@ async function checkForUpdate(autoUpdate, notify) {
17160
17170
  }
17161
17171
  const latest = await fetchLatestVersion(tag);
17162
17172
  if (!latest) return;
17163
- const current = runtimeVersion ?? "0.1.59";
17173
+ const current = runtimeVersion ?? "0.1.60";
17164
17174
  const hasUpdate = isVersionNewer(latest, current);
17165
17175
  debug.event("update-check", {
17166
17176
  current,
@@ -17338,7 +17348,7 @@ function wireSessionLifecycle(pi, runtime, standDownIfProxied) {
17338
17348
  setDelegatePolicy(DEFAULT_DELEGATE_POLICY);
17339
17349
  const sid = ctx.sessionManager.getSessionId();
17340
17350
  const modelInfo = ctx.model;
17341
- logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.59" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
17351
+ logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.60" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
17342
17352
  try {
17343
17353
  await runtime.reloadConfig(ctx.cwd);
17344
17354
  const delegateCfg = resolveDelegate(runtime.adapter);
@@ -17399,10 +17409,11 @@ function wireContextTransform(pi, runtime, standDownIfProxied) {
17399
17409
  config = { ...config, modelContextLimit: learnedWindow };
17400
17410
  logInfo("overflow-selfheal", { sid, modelId, event: "window-recenter", resolved: configBase.modelContextLimit, learned: learnedWindow });
17401
17411
  }
17402
- const beforeHeadroom = config.modelContextLimit;
17403
- config = applyOutputHeadroom(config, ctx.model);
17404
- if (config.modelContextLimit !== beforeHeadroom) {
17405
- logInfo("overflow-selfheal", { sid, event: "output-headroom", before: beforeHeadroom, after: config.modelContextLimit, maxOutput: ctx.model?.maxTokens ?? 0 });
17412
+ const headroomCap = resolveOutputHeadroomCap(runtime.adapter.outputHeadroomMaxPct);
17413
+ const fullWindow = config.modelContextLimit;
17414
+ config = applyOutputHeadroom(config, ctx.model, headroomCap);
17415
+ if (config.modelContextLimit !== fullWindow) {
17416
+ logInfo("overflow-selfheal", { sid, event: "output-headroom", before: fullWindow, after: config.modelContextLimit, maxOutput: ctx.model?.maxTokens ?? 0, cap: headroomCap });
17406
17417
  }
17407
17418
  const coveredIds = collectCoveredMessageIds(state);
17408
17419
  const realUsage = ctx.getContextUsage?.();
@@ -17456,6 +17467,7 @@ function wireContextTransform(pi, runtime, standDownIfProxied) {
17456
17467
  tokens: tokenCount,
17457
17468
  pct: config.modelContextLimit > 0 ? Number((tokenCount / config.modelContextLimit * 100).toFixed(2)) : null,
17458
17469
  limit: config.modelContextLimit,
17470
+ ...fullWindow !== config.modelContextLimit ? { fullWindow } : {},
17459
17471
  nudge: turn.nudge?.shouldInject ? turn.nudge.breakdown?.emergencyOverride === 1 ? "emergency" : "active" : "idle",
17460
17472
  nudgeReason: turn.nudge?.reason ?? null,
17461
17473
  blocks: turn.state.blocks.length,