billion-context-dsh 0.2.9 → 0.2.11
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 +4 -4
- package/README.md +4 -4
- package/dist/commands.d.ts +1 -1
- package/dist/index.js +35 -11
- package/dist/index.js.map +1 -1
- package/dist/prompts.d.ts +1 -1
- package/dist/tools.d.ts +9 -0
- package/dist/window.d.ts +9 -1
- 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.11**) 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 ⭐:
|
|
@@ -130,7 +130,7 @@ DSH derives every model request from its append-only session log (the *surface*)
|
|
|
130
130
|
| nudge ("efficiency note — compress early and keep context lean") | injected at `agent/pre-step` by the kernel's pressure decision — efficiency note + context breakdown + compression rules, tone aligned with kernel/pi; never an order |
|
|
131
131
|
| `decompress` | read-only recovery of shadowed originals from the log |
|
|
132
132
|
| `search_context` | scores a unified doc set (block summaries + shadowed originals) rebuilt from the log via acp-kernel `searchBlocks` (hybrid: stemming + CJK bigrams + char n-gram fuzzy); hits link back to the owning block |
|
|
133
|
-
| `acp_status` | CONTEXT BREAKDOWN (tool/text/summaries shares of the visible total) + compressed-block ledger + nudge decision line; no context-window rows; scope/view/tool/sort/limit drilldown supported |
|
|
133
|
+
| `acp_status` | CONTEXT BREAKDOWN (tool/text/summaries shares of the visible total) + compressed-block ledger + nudge decision line + a `Checkpoint seqs` row mapping each ACTIVE block's kernel ref (`bN`) to its checkpoint summary seq — compressing a checkpoint seq distills that block (issue #60); no context-window rows; scope/view/tool/sort/limit drilldown supported |
|
|
134
134
|
| block state | in-memory kernel state + **log-rebuilt ledger** (no sidecar files) |
|
|
135
135
|
| tiered distillation (T2/T3) | re-compressing a block's summary node distills that block (tier 2); distilling a tier-2 block yields tier 3. Tier + kernel block ids are persisted to the log, so kernel state rehydrates from the log after a restart and stays distillable |
|
|
136
136
|
| compression accounting (shadow price) | `shadowedTokenCount` (what the host occupancy display deducts) is priced in the **host token-meter's vocabulary** (`ctx.tokenMeter.measure` preferred; exact mirror in `src/host-tokens.ts` as fallback) — never the plugin's internal CJK-aware estimate (that is display currency; mixing it into the host ledger can drive `messageTokens` negative and brick a CJK-heavy session, issue #54) |
|
|
@@ -150,7 +150,7 @@ A walkthrough of the ACP philosophy this project inherits — how active context
|
|
|
150
150
|
| `compress` | Replace a seq range with a dense summary you write (edges auto-balanced to tool-pair boundaries); re-compressing a block's summary node distills it (tier 2/3) |
|
|
151
151
|
| `decompress` | Restore a previously compressed block's original content (read-only); accepts the `bN` ref shown by acp_status or a compaction id |
|
|
152
152
|
| `search_context` | Search compressed block summaries and originals by keyword (acp-kernel hybrid retrieval: stemming + CJK bigrams + fuzzy); hits link back to the owning block |
|
|
153
|
-
| `acp_status` | CONTEXT BREAKDOWN (tool/text/summaries shares of the visible total) + compressed-block ledger + nudge decision line; no context-window rows. Drilldown supported: `scope:"compressed"` per block, `scope:"uncompressed"` + `view:"messages"`/`"ranges"` per message/range, with `tool` filter, `sort` order and `limit` cap. Drilldown row refs are kernel ids (mN) — feed them straight to `compress` as `startSeq`/`endSeq` (auto-mapped to the live surface seq); `Surface:` seqs work too |
|
|
153
|
+
| `acp_status` | CONTEXT BREAKDOWN (tool/text/summaries shares of the visible total) + compressed-block ledger + nudge decision line + a `Checkpoint seqs` row mapping each ACTIVE block's kernel ref (`bN`) to its checkpoint summary seq (the distill entry point, issue #60); no context-window rows. Drilldown supported: `scope:"compressed"` per block, `scope:"uncompressed"` + `view:"messages"`/`"ranges"` per message/range, with `tool` filter, `sort` order and `limit` cap. Drilldown row refs are kernel ids (mN) — feed them straight to `compress` as `startSeq`/`endSeq` (auto-mapped to the live surface seq); `Surface:` seqs work too |
|
|
154
154
|
| `/acp` | status / compress / decompress from the command bar; status also shows human-side window info (estimated context, window source, compressed-block ledger, and **nudge arbitration** — `nudge: idle/ACTIVE — reason` plus how many tokens remain until the next nudge, decided by the same kernel turn as the nudge path) |
|
|
155
155
|
|
|
156
156
|
## Upstream & credits
|
|
@@ -171,7 +171,7 @@ This project reuses `acp-kernel`'s compression core and `billion-context-pi`'s d
|
|
|
171
171
|
| Key | Default | Meaning |
|
|
172
172
|
|---|---|---|
|
|
173
173
|
| `modelContextLimit` | auto-detected (fallback `128000`) | Context window used for the kernel's pressure decisions; an explicit value wins and skips the probe |
|
|
174
|
-
| `autoModelContextLimit` | `true` | Probe the model's real window from the model API (`agent.ctx.llm.resolveModelInfo`); fall back to the default on failure, the `/acp` command shows the window source (the `acp_status` model tool carries no window info) |
|
|
174
|
+
| `autoModelContextLimit` | `true` | Probe the model's real window from the model API (`agent.ctx.llm.resolveModelInfo`); fall back to the default on failure, 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 |
|
|
175
175
|
| `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 |
|
|
176
176
|
| `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 |
|
|
177
177
|
| `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 |
|
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.11**)仍处于开发中的测试版。[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 本身也处于**公开测试版**阶段。**请勿将两者用于工程化 / 生产环境**——预期会有破坏性变更与粗糙之处。
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
9
|
<strong>衷心感谢以下项目——请给它们一个 ⭐:</strong>
|
|
@@ -131,7 +131,7 @@ DSH 的每个模型请求都派生自其 append-only 会话日志(*surface*)
|
|
|
131
131
|
| nudge("效率提示——尽早压缩保持精简") | 由内核的压力决策在 `agent/pre-step` 注入——效率通知 + 上下文分解 + 压缩规则,语气对齐 kernel/pi;绝非命令 |
|
|
132
132
|
| `decompress` | 从日志只读恢复被遮蔽的原文 |
|
|
133
133
|
| `search_context` | 从日志重建块摘要 + 被遮蔽原文的统一文档集,交 acp-kernel `searchBlocks`(hybrid:词干化 + CJK bigram + 字符 n-gram 模糊)打分;命中回链所属块 |
|
|
134
|
-
| `acp_status` | CONTEXT BREAKDOWN(tool/text/summaries 占可见总量)+ 压缩块账本 + nudge
|
|
134
|
+
| `acp_status` | CONTEXT BREAKDOWN(tool/text/summaries 占可见总量)+ 压缩块账本 + nudge 决策行 + `Checkpoint seqs` 行(active 块的 `bN → seq` 映射——压缩某个 checkpoint seq 即蒸馏该块,issue #60);不含上下文窗口;支持 scope/view/tool/sort/limit 钻取 |
|
|
135
135
|
| 块状态 | 内存内核状态 + **日志重建账本**(无旁车文件) |
|
|
136
136
|
| 分层蒸馏(T2/T3) | 再次压缩某块的摘要节点 = 蒸馏该块(tier 2),蒸馏 tier-2 块得 tier 3;tier 与内核块 id 持久化进日志,重启后内核状态从日志再水合、可继续蒸馏 |
|
|
137
137
|
| 压缩记账(影子价格) | `shadowedTokenCount`(宿主占用率据此扣减)**用宿主 token-meter 的词汇计价**(`ctx.tokenMeter.measure` 优先,`src/host-tokens.ts` 精确镜像兜底)——绝不混用插件内部的 CJK 感知估算(那是展示货币,混用会把宿主账本扣成负数、卡死中文会话,issue #54) |
|
|
@@ -151,7 +151,7 @@ DSH 的每个模型请求都派生自其 append-only 会话日志(*surface*)
|
|
|
151
151
|
| `compress` | 用你书写的紧凑摘要替换 seq 范围(边界自动平衡到 tool-call/result 配对点);对某块的摘要节点再次压缩 = 分层蒸馏(tier 2/3) |
|
|
152
152
|
| `decompress` | 恢复已压缩块的原始内容(只读);接受 acp_status 显示的 `bN` 或 compaction id |
|
|
153
153
|
| `search_context` | 按关键词搜索压缩块摘要与原文(acp-kernel hybrid 检索:词干化 + CJK bigram + 模糊);命中回链所属块 |
|
|
154
|
-
| `acp_status` | CONTEXT BREAKDOWN(tool/text/summaries 占可见总量)+ 压缩块账本 + nudge
|
|
154
|
+
| `acp_status` | CONTEXT BREAKDOWN(tool/text/summaries 占可见总量)+ 压缩块账本 + nudge 决策行 + `Checkpoint seqs` 行(active 块的 `bN → seq` 蒸馏入口,issue #60);不含上下文窗口。支持钻取:`scope:"compressed"` 逐块、`scope:"uncompressed"` + `view:"messages"`/`"ranges"` 逐消息/区间,`tool` 过滤、`sort` 排序、`limit` 截断。钻取行 ref 是内核 mN——可直接作为 `compress` 的 `startSeq`/`endSeq`(自动映射为 live surface seq);`Surface:` 的 seq 同样可用 |
|
|
155
155
|
| `/acp` | 从命令栏执行 status / compress / decompress;status 额外展示 human-side 窗口信息(estimated context、context window 来源、压缩账本、**nudge 仲裁**——`nudge: idle/ACTIVE — reason` 及距下一次 nudge 还差多少 token,与 nudge 路径同一内核判定) |
|
|
156
156
|
|
|
157
157
|
## 上游项目与致谢
|
|
@@ -172,7 +172,7 @@ DSH 的每个模型请求都派生自其 append-only 会话日志(*surface*)
|
|
|
172
172
|
| 键 | 默认值 | 含义 |
|
|
173
173
|
|---|---|---|
|
|
174
174
|
| `modelContextLimit` | 自动探测(回退 `128000`) | 用于内核压力决策的上下文窗口;显式配置时优先且跳过探测 |
|
|
175
|
-
| `autoModelContextLimit` | `true` | 从模型 API 自动探测真实窗口(`agent.ctx.llm.resolveModelInfo`);探测失败回退默认值,`/acp` 命令展示窗口来源(模型工具 `acp_status`
|
|
175
|
+
| `autoModelContextLimit` | `true` | 从模型 API 自动探测真实窗口(`agent.ctx.llm.resolveModelInfo`);探测失败回退默认值,`/acp` 命令展示窗口来源(模型工具 `acp_status` 不含窗口信息)。探测失败会在宿主日志与 `/acp` 面板提示(`restart to re-probe`)——失败结果同样被缓存,修复网关后需重启或显式设置 `modelContextLimit` 才会重新探测 |
|
|
176
176
|
| `nudgeMinContextLimitPct` | 内核默认 `0.45` | Nudge 窗口下界(用量占比)——仅作配置校验,增长路径的触发没有百分比下限——与 billion-context-pi 相同的默认值 |
|
|
177
177
|
| `nudgeMaxContextLimitPct` | engine 默认 `0.70`(内核/pi 默认 `0.75`) | 过限线:超过此值则无论增长与否都触发 nudge——刻意低于宿主 compaction-basic 的 80% 自动压缩线,保证强制 nudge 先触发;显式配置优先 |
|
|
178
178
|
| `nudgeEmergencyThresholdPct` | engine 默认 `0.85`(内核/pi 默认 `0.95`) | 紧急 nudge(绕过每轮去重)——从 `0.95` 下调:95% 时模型已无操作空间且会被 80% 自动压缩线遮蔽;显式配置优先 |
|
package/dist/commands.d.ts
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* @module billion-context-dsh/commands
|
|
5
5
|
*/
|
|
6
6
|
import type { CommandDefinition } from '@deepseek-ai/dsh-commands';
|
|
7
|
-
import type
|
|
7
|
+
import { type ToolEnvironment } from './tools.ts';
|
|
8
8
|
/** Register the /acp command (idempotent per engine). */
|
|
9
9
|
export declare function acpCommand(env: ToolEnvironment): CommandDefinition;
|
package/dist/index.js
CHANGED
|
@@ -3525,7 +3525,7 @@ var NUDGE_ALLOWED = {
|
|
|
3525
3525
|
normal: /* @__PURE__ */ new Set(["pct", "philosophy"]),
|
|
3526
3526
|
emergency: /* @__PURE__ */ new Set(["pct", "philosophy"]),
|
|
3527
3527
|
guidance: /* @__PURE__ */ new Set(),
|
|
3528
|
-
tier: /* @__PURE__ */ new Set(["tier", "count", "prevTier", "tokens", "seqs"]),
|
|
3528
|
+
tier: /* @__PURE__ */ new Set(["tier", "count", "prevTier", "tokens", "seqs", "firstSeq", "lastSeq"]),
|
|
3529
3529
|
breakdown: /* @__PURE__ */ new Set(["system", "tool", "summaries", "code", "text"]),
|
|
3530
3530
|
growth: /* @__PURE__ */ new Set(["growth"]),
|
|
3531
3531
|
tip: /* @__PURE__ */ new Set()
|
|
@@ -3600,7 +3600,7 @@ var DEFAULT_PROMPTS = {
|
|
|
3600
3600
|
normal: "This is an efficiency nudge to compress early and keep context lean \u2014 not an overflow warning. A separate, stronger alert will appear if the context is actually full.\n\n{philosophy}",
|
|
3601
3601
|
emergency: "\u26A0\uFE0F Context limit reached \u2014 compress now. Prioritize consumed tool outputs.\n\n{philosophy}",
|
|
3602
3602
|
guidance: HOW_TO_COMPRESS_RULES,
|
|
3603
|
-
tier: "Tier {tier}: {count} tier-{prevTier} block(s) distillable ({tokens} tokens) \u2014
|
|
3603
|
+
tier: "Tier {tier}: {count} tier-{prevTier} block(s) distillable ({tokens} tokens) \u2014 distill them by compressing their checkpoint seq(s) [seqs {seqs}] as one range: compress({ content: [{ startSeq: {firstSeq}, endSeq: {lastSeq}, summary }] }).",
|
|
3604
3604
|
breakdown: "Context breakdown: {system}K system | {tool}K tool | {summaries}K summaries | {code}K code | {text}K text",
|
|
3605
3605
|
growth: "+{growth}K since last nudge",
|
|
3606
3606
|
tip: "\u{1F4A1} Compress all ranges in one call (pass multiple content entries: `content: [{...}, {...}]`)."
|
|
@@ -3749,7 +3749,7 @@ function replaceTierTrigger(text, nudge, session, prompts) {
|
|
|
3749
3749
|
const next = rest.match(/\n\nHOW TO COMPRESS/);
|
|
3750
3750
|
const end = next !== null ? start + 2 + next.index : text.length;
|
|
3751
3751
|
const targets = nudge.tierTargetBlocks;
|
|
3752
|
-
const summarySeqs = targets.map((block) => summarySeqOfKernelBlock(session, block.blockId)).filter((seq) => seq !== null);
|
|
3752
|
+
const summarySeqs = targets.map((block) => summarySeqOfKernelBlock(session, block.blockId)).filter((seq) => seq !== null).sort((a, b) => a - b);
|
|
3753
3753
|
const pending = nudge.tier === 2 ? nudge.breakdown?.pendingT2 : nudge.breakdown?.pendingT3;
|
|
3754
3754
|
const tokens = typeof pending === "number" ? pending : 0;
|
|
3755
3755
|
const tierValue = nudge.tier === null ? 2 : nudge.tier;
|
|
@@ -3758,7 +3758,9 @@ function replaceTierTrigger(text, nudge, session, prompts) {
|
|
|
3758
3758
|
count: targets.length,
|
|
3759
3759
|
prevTier: tierValue - 1,
|
|
3760
3760
|
tokens,
|
|
3761
|
-
seqs: summarySeqs.join(", ")
|
|
3761
|
+
seqs: summarySeqs.join(", "),
|
|
3762
|
+
firstSeq: summarySeqs[0] ?? "n/a",
|
|
3763
|
+
lastSeq: summarySeqs[summarySeqs.length - 1] ?? "n/a"
|
|
3762
3764
|
});
|
|
3763
3765
|
return text.slice(0, start) + "\n\n" + tierLine + text.slice(end);
|
|
3764
3766
|
}
|
|
@@ -3795,7 +3797,7 @@ function renderNudgeFromTemplates(nudge, emergency, session, prompts) {
|
|
|
3795
3797
|
if (prompts.nudge.guidance !== "") parts.push("", prompts.nudge.guidance);
|
|
3796
3798
|
if ((nudge.tier === 2 || nudge.tier === 3) && (nudge.tierTargetBlocks?.length ?? 0) > 0) {
|
|
3797
3799
|
const targets = nudge.tierTargetBlocks;
|
|
3798
|
-
const summarySeqs = targets.map((block) => summarySeqOfKernelBlock(session, block.blockId)).filter((seq) => seq !== null);
|
|
3800
|
+
const summarySeqs = targets.map((block) => summarySeqOfKernelBlock(session, block.blockId)).filter((seq) => seq !== null).sort((a, b) => a - b);
|
|
3799
3801
|
const pending = nudge.tier === 2 ? nudge.breakdown?.pendingT2 : nudge.breakdown?.pendingT3;
|
|
3800
3802
|
const tokens = typeof pending === "number" ? pending : 0;
|
|
3801
3803
|
const tierLine = renderTemplate(prompts.nudge.tier, {
|
|
@@ -3803,7 +3805,9 @@ function renderNudgeFromTemplates(nudge, emergency, session, prompts) {
|
|
|
3803
3805
|
count: targets.length,
|
|
3804
3806
|
prevTier: nudge.tier - 1,
|
|
3805
3807
|
tokens,
|
|
3806
|
-
seqs: summarySeqs.join(", ")
|
|
3808
|
+
seqs: summarySeqs.join(", "),
|
|
3809
|
+
firstSeq: summarySeqs[0] ?? "n/a",
|
|
3810
|
+
lastSeq: summarySeqs[summarySeqs.length - 1] ?? "n/a"
|
|
3807
3811
|
});
|
|
3808
3812
|
if (tierLine !== "") parts.push(tierLine);
|
|
3809
3813
|
const tierRules = nudge.tier === 2 ? TIER2_DISTILL_RULES : TIER3_CONDENSE_RULES;
|
|
@@ -3832,6 +3836,9 @@ function requireAgent(exec) {
|
|
|
3832
3836
|
}
|
|
3833
3837
|
return exec.agent;
|
|
3834
3838
|
}
|
|
3839
|
+
async function resolveEffectiveWindow(env, agent) {
|
|
3840
|
+
return env.windowFor === void 0 ? { limit: env.modelContextLimit, source: "explicit" } : await env.windowFor(agent);
|
|
3841
|
+
}
|
|
3835
3842
|
var compressParameters = {
|
|
3836
3843
|
// Tolerated wrapped-arguments form: some models emit
|
|
3837
3844
|
// `{ "arguments": "{\"content\": [...]}" }` (double-nested) or
|
|
@@ -3943,7 +3950,8 @@ async function handleCompress(env, args, exec) {
|
|
|
3943
3950
|
const coreMessages = allLogMessages(session);
|
|
3944
3951
|
const surfaceMessages = eventsToCoreMessages(surfaceEventsOf(session));
|
|
3945
3952
|
const tokenCount = resolveTokenCount(agent, surfaceMessages);
|
|
3946
|
-
const
|
|
3953
|
+
const window = await resolveEffectiveWindow(env, agent);
|
|
3954
|
+
const config = kernelConfigFor({ ...env, modelContextLimit: window.limit });
|
|
3947
3955
|
const turn = env.kernel.processTurn({ messages: coreMessages, state, config, tokenCount });
|
|
3948
3956
|
env.store.set(session, turn.state);
|
|
3949
3957
|
const byRaw = turn.state.messageRefs.byRaw;
|
|
@@ -4068,7 +4076,7 @@ async function handleCompress(env, args, exec) {
|
|
|
4068
4076
|
effectiveMessageIds: block.effectiveMessageIds
|
|
4069
4077
|
});
|
|
4070
4078
|
const adjusted = start !== range.startSeq || end !== range.endSeq;
|
|
4071
|
-
const tierLabel2 =
|
|
4079
|
+
const tierLabel2 = `, tier ${tier}`;
|
|
4072
4080
|
const note = range.recovered === true ? ` (seqs ${range.startSeq}..${range.endSeq} were already shadowed \u2014 compressed the live remainder ${start}..${end})` : adjusted ? ` (adjusted from ${range.startSeq}..${range.endSeq} to balanced edges)` : "";
|
|
4073
4081
|
lines.push(
|
|
4074
4082
|
` block ${compactionId.slice(0, 8)}: seqs ${start}..${end}, ${shadowed.length} messages shadowed${tierLabel2}${note}`
|
|
@@ -4227,7 +4235,8 @@ async function handleStatus(env, rawArgs, exec) {
|
|
|
4227
4235
|
const coreMessages = allLogMessages(session);
|
|
4228
4236
|
const surfaceMessages = eventsToCoreMessages(surface, toolNames);
|
|
4229
4237
|
const tokenCount = resolveTokenCount(agent, surfaceMessages);
|
|
4230
|
-
const
|
|
4238
|
+
const window = await resolveEffectiveWindow(env, agent);
|
|
4239
|
+
const config = kernelConfigFor({ ...env, modelContextLimit: window.limit });
|
|
4231
4240
|
const turn = env.kernel.processTurn({ messages: coreMessages, state, config, tokenCount });
|
|
4232
4241
|
const statusMessages = eventsToCoreMessages(
|
|
4233
4242
|
surface.filter((event) => !isCheckpointEvent(event)),
|
|
@@ -4240,6 +4249,10 @@ async function handleStatus(env, rawArgs, exec) {
|
|
|
4240
4249
|
if (nudge !== void 0) {
|
|
4241
4250
|
lines.push("", `Nudge: ${nudge.shouldInject ? "ACTIVE" : "idle"} \u2014 ${nudge.reason}`);
|
|
4242
4251
|
}
|
|
4252
|
+
const checkpointRows = blockRegistry(session).filter((entry) => entry.active && entry.summarySeq !== null).map((entry) => `${entry.kernelBlockId} \u2192 seq ${entry.summarySeq}`);
|
|
4253
|
+
if (checkpointRows.length > 0) {
|
|
4254
|
+
lines.push("", `Checkpoint seqs (active blocks \u2014 compress a checkpoint seq to distill it): ${checkpointRows.join(", ")}`);
|
|
4255
|
+
}
|
|
4243
4256
|
}
|
|
4244
4257
|
lines.push("", `Surface: ${surfaceSummary(session)}`);
|
|
4245
4258
|
if (args.scope === "uncompressed") {
|
|
@@ -4296,6 +4309,7 @@ function windowSourceLabel(window) {
|
|
|
4296
4309
|
if (window.source === "auto") {
|
|
4297
4310
|
return `auto-detected from ${window.provider ?? "?"}/${window.model ?? "?"}`;
|
|
4298
4311
|
}
|
|
4312
|
+
if (window.probeFailed === true) return "default (auto-detection failed \u2014 restart to re-probe)";
|
|
4299
4313
|
return "default (auto-detection unavailable)";
|
|
4300
4314
|
}
|
|
4301
4315
|
async function detectContextWindow(agent, provider, model) {
|
|
@@ -4319,7 +4333,7 @@ async function statusText(env, agent) {
|
|
|
4319
4333
|
const coreMessages = allLogMessages(session);
|
|
4320
4334
|
const surfaceMessages = eventsToCoreMessages(surfaceEventsOf(session));
|
|
4321
4335
|
const estimated = resolveTokenCount(agent, surfaceMessages);
|
|
4322
|
-
const window =
|
|
4336
|
+
const window = await resolveEffectiveWindow(env, agent);
|
|
4323
4337
|
const limit = window.limit;
|
|
4324
4338
|
const lines = [
|
|
4325
4339
|
`ACP status \u2014 session ${session.id}`,
|
|
@@ -4328,6 +4342,9 @@ async function statusText(env, agent) {
|
|
|
4328
4342
|
` estimated context: ${estimated} / ${limit} (${Math.round(estimated / limit * 100)}%)`,
|
|
4329
4343
|
` context window: ${limit} (${windowSourceLabel(window)})`
|
|
4330
4344
|
];
|
|
4345
|
+
if (window.probeFailed === true) {
|
|
4346
|
+
lines.push(` \u26A0 window auto-detection failed \u2014 using the ${limit} fallback (restart to re-probe, or set modelContextLimit explicitly)`);
|
|
4347
|
+
}
|
|
4331
4348
|
const state = structuredClone(env.store.stateFor(session));
|
|
4332
4349
|
const config = kernelConfigFor({ ...env, modelContextLimit: limit });
|
|
4333
4350
|
const turn = env.kernel.processTurn({ messages: coreMessages, state, config, tokenCount: estimated });
|
|
@@ -4561,7 +4578,14 @@ var AcpCompactionEngine = class extends CompactionEngine {
|
|
|
4561
4578
|
window = { limit: DEFAULT_CONTEXT_WINDOW, source: "default", provider, model };
|
|
4562
4579
|
} else {
|
|
4563
4580
|
const detected = await detectContextWindow(agent, provider, model);
|
|
4564
|
-
|
|
4581
|
+
if (detected === null) {
|
|
4582
|
+
this.ctx.logger.warn(
|
|
4583
|
+
`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)`
|
|
4584
|
+
);
|
|
4585
|
+
window = { limit: DEFAULT_CONTEXT_WINDOW, source: "default", provider, model, probeFailed: true };
|
|
4586
|
+
} else {
|
|
4587
|
+
window = { limit: detected, source: "auto", provider, model };
|
|
4588
|
+
}
|
|
4565
4589
|
}
|
|
4566
4590
|
this.windowCache.set(key, window);
|
|
4567
4591
|
return window;
|