opencode-acp 1.14.0 → 1.14.2
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 +16 -0
- package/README.zh-CN.md +16 -0
- package/dist/index.js +87 -35
- package/dist/index.js.map +1 -1
- package/dist/lib/compress/message.d.ts.map +1 -1
- package/dist/lib/compress/pipeline.d.ts +9 -7
- package/dist/lib/compress/pipeline.d.ts.map +1 -1
- package/dist/lib/compress/protected-content.d.ts +2 -0
- package/dist/lib/compress/protected-content.d.ts.map +1 -1
- package/dist/lib/compress/range.d.ts.map +1 -1
- package/dist/lib/compress/status.d.ts.map +1 -1
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/messages/inject/inject.d.ts.map +1 -1
- package/dist/lib/messages/inject/utils.d.ts +7 -3
- package/dist/lib/messages/inject/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -528,6 +528,22 @@ For the complete list with root cause analysis, see the [bug tracker](https://gi
|
|
|
528
528
|
|
|
529
529
|
## Changelog
|
|
530
530
|
|
|
531
|
+
### v1.14.2 — Split Protected Ranges + Soften Last-User-Message (PR #210)
|
|
532
|
+
|
|
533
|
+
**Problem**: In autonomous agentic sessions (1 user message + many assistant/tool messages), `buildCompressibleRanges` created one giant compressible group because grouping only breaks on user messages — and tool results are `assistant` role in OpenCode. The giant group's endRef fell in the protected zone → `excludeProtectedRanges` removed the entire range → zero recommendations → nudge suppressed → model could never compress. Additionally, `preserveLastUserMessage` hard-rejected any compress call covering the last user message, blocking deliberate compressions of surrounding tool output.
|
|
534
|
+
|
|
535
|
+
**Fix**: (1) `buildCompressibleRanges` now accepts `protectedZoneRefs` and splits groups at the protected-zone boundary — the unprotected head survives as a recommended range while the protected tail is excluded. (2) `preserveLastUserMessage` moved from hard-reject (`checkProtectedRange` throw) to soft-filter (`filterLastUserMessage` excludes from compress plan, following Bug 39's `filterProtectedToolMessages` pattern). The last user message survives in visible context; surrounding tool output compresses normally. (3) Added `allInProtectedZone` condition to `nothingToCompress` to cover the case where all messages are in the protected zone. (4) Fixed stale error messages and added empty-plan guard in both range and message modes. Dual-agent reviewed (both APPROVE with minor fixes; all WARNINGs addressed in follow-up commit). 922 tests pass.
|
|
536
|
+
|
|
537
|
+
Files: `lib/messages/inject/{utils,inject}.ts`, `lib/compress/{pipeline,protected-content,range,message,status}.ts`. Tests: `tests/{preserve-recent,soft-block,protected-tool-exclusion}.test.ts`. No persisted-state schema changes. `preserveLastUserMessage` config semantics changed from hard-reject to soft-filter (intentional fix; `lastSegmentSoftBlock: false` disables all protection including the new soft filter).
|
|
538
|
+
|
|
539
|
+
### v1.14.1 — Log Version Info + Growth Baseline Fix (PRs #205, #207)
|
|
540
|
+
|
|
541
|
+
**Problem**: Two issues since v1.14.0. (1) **Unidentifiable logs** (PR #205): ACP daily logs and per-request context logs carried no version marker, so when users shared debug logs it was impossible to tell which ACP version produced them — making regression triage across versions guesswork. (2) **Growth-baseline feedback loop in short sessions** (PR #207): When the growth threshold was met (`nudgeAllowed`) but every compressible range was filtered out (`nothingToCompress`, e.g. all ranges inside the protected zone in a short session or subagent), the code reset `state.nudges.lastPerMessageNudgeTokens = currentTokens`. This ate the accumulated growth every cycle, so the baseline chased the current context and the model never saw a nudge even though context had grown well past the threshold.
|
|
542
|
+
|
|
543
|
+
**Fix**: (1) PR #205 — `lib/logger.ts` now appends `| v={version}` to every daily-log line and writes a one-shot `_version` file under each per-request context-log directory. The version is injected at build time via a new `tsup.config.ts` `define: { ACP_VERSION: JSON.stringify(pkg.version) }` (read from `package.json`), with a `declare const ACP_VERSION` ambient declaration in `logger.ts`. Falls back to `"dev"` when the define is absent (e.g. tsx-run tests). (2) PR #207 — Removed the `lastPerMessageNudgeTokens = currentTokens` reset in the `nothingToCompress` branch of `lib/messages/inject/inject.ts`; only `lastNudgeShownTokens` is cleared now. Growth now accumulates across `nothingToCompress` turns until there genuinely is something to compress, at which point the nudge fires. Coverage: 3 tautological baseline-reset tests (which never called `injectCompressNudges`, violating AGENTS.md §5.6) were removed; a real E2E growth scenario in `tests/inject.test.ts` verifies baseline preservation through `nothingToCompress` turns and nudge firing once content exits the protected zone. Dual-authored with Sisyphus (co-authored-by trailer).
|
|
544
|
+
|
|
545
|
+
Files: `lib/logger.ts`, `tsup.config.ts`, `lib/messages/inject/inject.ts`. Tests: `tests/inject.test.ts` (E2E growth scenario added, 3 tautological tests removed from `tests/baseline-reset.test.ts`). No persisted-state schema changes. No config changes.
|
|
546
|
+
|
|
531
547
|
### v1.14.0 — Three-Tier Compression + Preserve-Recent + Summary Visibility Fix (PRs #200, #201, #202)
|
|
532
548
|
|
|
533
549
|
**Problem**: Three critical issues for long-session stability. (1) **Summary accumulation** (PR #200): Summary blocks accumulated indefinitely (v1.13.5+ force-protection). At ~7.3K tokens/day growth rate, sessions hit the 100K summary ceiling in ~3 days. 92.5% of ancient blocks were shipped/historical work with zero actionable value. (2) **Active task loss** (PR #201): `lastSegmentSoftBlock` only protected the very last 1 message from compression. When the model compressed a range that included the current task context, the active work was lost — the recommendation list itself could point at messages that should have been protected. (3) **summaryBuffer over-counting** (PR #202): `getActiveSummaryTokenUsage()` counted ALL active blocks (e.g., 448 = 151K tokens), but only ~26 blocks had their compress calls in the visible context window. The inflated count caused false T2/T3 triggers and misleading `acp stats` output ("摘要 146%").
|
package/README.zh-CN.md
CHANGED
|
@@ -482,6 +482,22 @@ ACP 在首次启动时自动将配置从 `dcp.jsonc` 迁移到 `acp.jsonc`,将
|
|
|
482
482
|
|
|
483
483
|
## 更新日志
|
|
484
484
|
|
|
485
|
+
### v1.14.2 — 拆分保护区范围 + 软化最后用户消息保护(PR #210)
|
|
486
|
+
|
|
487
|
+
**问题**:在自主代理会话中(1 条用户消息 + 多条 assistant/tool 消息),`buildCompressibleRanges` 创建了一个巨型可压缩组,因为分组只在用户消息处断开 —— 而 OpenCode 中 tool 结果是 `assistant` 角色。巨型组的 endRef 落在保护区内 → `excludeProtectedRanges` 移除整个范围 → 零推荐 → nudge 被抑制 → 模型永远无法压缩。此外,`preserveLastUserMessage` 硬拒绝任何覆盖最后用户消息的压缩调用,阻塞了对周围 tool 输出的有意压缩。
|
|
488
|
+
|
|
489
|
+
**修复**:(1) `buildCompressibleRanges` 现在接受 `protectedZoneRefs` 参数,在保护区边界处拆分组 —— 非保护区头部保留为推荐范围,保护区尾部被排除。(2) `preserveLastUserMessage` 从硬拒绝(`checkProtectedRange` 抛错)改为软过滤(`filterLastUserMessage` 从压缩计划中排除,遵循 Bug 39 的 `filterProtectedToolMessages` 模式)。最后用户消息保留在可见上下文中;周围的 tool 输出正常压缩。(3) 在 `nothingToCompress` 中添加了 `allInProtectedZone` 条件,覆盖所有消息都在保护区内的情况。(4) 修复了过时的错误消息,在 range 和 message 模式中都添加了空计划守卫。双 agent 审查通过(均 APPROVE WITH MINOR FIXES;所有 WARNING 在后续 commit 中解决)。922 项测试通过。
|
|
490
|
+
|
|
491
|
+
文件:`lib/messages/inject/{utils,inject}.ts`、`lib/compress/{pipeline,protected-content,range,message,status}.ts`。测试:`tests/{preserve-recent,soft-block,protected-tool-exclusion}.test.ts`。无持久化状态 schema 变更。`preserveLastUserMessage` 配置语义从硬拒绝变为软过滤(有意的修复;`lastSegmentSoftBlock: false` 禁用所有保护包括新的软过滤)。
|
|
492
|
+
|
|
493
|
+
### v1.14.1 — 日志版本信息 + 增长基线修复(PR #205, #207)
|
|
494
|
+
|
|
495
|
+
**问题**:v1.14.0 之后的两个问题。(1) **日志无法识别版本**(PR #205):ACP daily 日志和每请求 context 日志没有任何版本标记,用户分享调试日志时无法判断是哪个 ACP 版本产生的 —— 跨版本回归排查只能靠猜。(2) **短会话中的增长基线反馈循环**(PR #207):当增长阈值已满足(`nudgeAllowed`)但所有可压缩范围都被过滤掉时(`nothingToCompress`,例如短会话或子代理中所有范围都在保护区内),旧代码会重置 `state.nudges.lastPerMessageNudgeTokens = currentTokens`。这会每轮吃掉累积增长,基线一路追逐当前上下文,即使上下文早已远超阈值,模型也永远等不到 nudge。
|
|
496
|
+
|
|
497
|
+
**修复**:(1) PR #205 —— `lib/logger.ts` 现在在每行 daily 日志末尾追加 `| v={version}`,并在每个每请求 context 日志目录下写一个一次性 `_version` 文件。版本通过新的 `tsup.config.ts` `define: { ACP_VERSION: JSON.stringify(pkg.version) }`(从 `package.json` 读取)在构建时注入,`logger.ts` 中有 `declare const ACP_VERSION` 环境声明。当 define 缺失时(例如 tsx 跑测试)回退为 `"dev"`。(2) PR #207 —— 移除了 `lib/messages/inject/inject.ts` 中 `nothingToCompress` 分支的 `lastPerMessageNudgeTokens = currentTokens` 重置;现在只清空 `lastNudgeShownTokens`。增长会在多个 `nothingToCompress` 轮次之间累积,直到确实有内容可压缩时 nudge 才触发。测试覆盖:删除了 3 个 taautological 的 baseline-reset 测试(这些测试从不调用 `injectCompressNudges`,违反 AGENTS.md §5.6);`tests/inject.test.ts` 中新增真实 E2E 增长场景,验证基线在 `nothingToCompress` 轮次间被保留、内容离开保护区后 nudge 触发。与 Sisyphus 合作完成(co-authored-by 署名)。
|
|
498
|
+
|
|
499
|
+
文件:`lib/logger.ts`、`tsup.config.ts`、`lib/messages/inject/inject.ts`。测试:`tests/inject.test.ts`(新增 E2E 增长场景,`tests/baseline-reset.test.ts` 删除 3 个 tautological 测试)。无持久化 state schema 变更,无配置变更。
|
|
500
|
+
|
|
485
501
|
### v1.14.0 — 三级压缩 + 保留近期消息 + 摘要可见性修复(PR #200, #201, #202)
|
|
486
502
|
|
|
487
503
|
**问题**:长会话稳定性三个关键问题。(1) **摘要累积**(PR #200):摘要块无限累积(v1.13.5+ 强制保护后),以每天约 7.3K token 增长,会话在约 3 天内触及 100K 摘要上限。92.5% 的旧块是已发布/历史工作,零可操作价值。(2) **活跃任务丢失**(PR #201):`lastSegmentSoftBlock` 仅保护最后 1 条消息不被压缩。当模型压缩包含当前任务上下文的范围时,活跃工作丢失——推荐列表本身可能指向应该被保护的消息。(3) **summaryBuffer 过度计数**(PR #202):`getActiveSummaryTokenUsage()` 计算了所有活跃块(如 448 块 = 151K token),但只有约 26 块的 compress 调用在可见上下文窗口中。虚高的计数导致错误的 T2/T3 触发和误导性的 `acp stats` 输出("摘要 146%")。
|
package/dist/index.js
CHANGED
|
@@ -3062,6 +3062,39 @@ function filterProtectedToolMessages(selection, searchContext, protectedTools, p
|
|
|
3062
3062
|
toolIds: filteredToolIds
|
|
3063
3063
|
};
|
|
3064
3064
|
}
|
|
3065
|
+
function filterLastUserMessage(selection, searchContext, state, compress) {
|
|
3066
|
+
if (compress.lastSegmentSoftBlock === false) return selection;
|
|
3067
|
+
if (!(compress.preserveLastUserMessage ?? true)) return selection;
|
|
3068
|
+
let lastUserMessageId = null;
|
|
3069
|
+
for (let i = searchContext.rawMessages.length - 1; i >= 0; i--) {
|
|
3070
|
+
const msg = searchContext.rawMessages[i];
|
|
3071
|
+
const id = msg?.info?.id;
|
|
3072
|
+
if (!id || typeof id !== "string") continue;
|
|
3073
|
+
if (isSyntheticMessage(msg)) continue;
|
|
3074
|
+
if (isIgnoredUserMessage(msg)) continue;
|
|
3075
|
+
if (state.prune.messages.byMessageId.has(id)) continue;
|
|
3076
|
+
if (msg.info.role === "user") {
|
|
3077
|
+
lastUserMessageId = id;
|
|
3078
|
+
break;
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
if (!lastUserMessageId || !selection.messageIds.includes(lastUserMessageId)) {
|
|
3082
|
+
return selection;
|
|
3083
|
+
}
|
|
3084
|
+
const filteredMessageIds = selection.messageIds.filter((id) => id !== lastUserMessageId);
|
|
3085
|
+
const filteredMessageTokenById = /* @__PURE__ */ new Map();
|
|
3086
|
+
for (const id of filteredMessageIds) {
|
|
3087
|
+
const tokens = selection.messageTokenById.get(id);
|
|
3088
|
+
if (tokens !== void 0) {
|
|
3089
|
+
filteredMessageTokenById.set(id, tokens);
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
return {
|
|
3093
|
+
...selection,
|
|
3094
|
+
messageIds: filteredMessageIds,
|
|
3095
|
+
messageTokenById: filteredMessageTokenById
|
|
3096
|
+
};
|
|
3097
|
+
}
|
|
3065
3098
|
|
|
3066
3099
|
// lib/compress/state.ts
|
|
3067
3100
|
var DEFAULT_PROMOTION_THRESHOLD = 5;
|
|
@@ -6399,7 +6432,6 @@ function checkPhantomBlock(state, plans) {
|
|
|
6399
6432
|
function computeProtectedRawIds(rawMessages, state, compress) {
|
|
6400
6433
|
const preserveN = compress.preserveRecentMessages ?? 20;
|
|
6401
6434
|
const preserveTokens = compress.preserveRecentTokens ?? 2e4;
|
|
6402
|
-
const preserveLastUser = compress.preserveLastUserMessage ?? true;
|
|
6403
6435
|
const result = /* @__PURE__ */ new Set();
|
|
6404
6436
|
const visible = [];
|
|
6405
6437
|
for (const msg of rawMessages) {
|
|
@@ -6430,14 +6462,6 @@ function computeProtectedRawIds(rawMessages, state, compress) {
|
|
|
6430
6462
|
tokenAccum += visible[i].tokens;
|
|
6431
6463
|
}
|
|
6432
6464
|
}
|
|
6433
|
-
if (preserveLastUser) {
|
|
6434
|
-
for (let i = visible.length - 1; i >= 0; i--) {
|
|
6435
|
-
if (visible[i].isUser) {
|
|
6436
|
-
result.add(visible[i].id);
|
|
6437
|
-
break;
|
|
6438
|
-
}
|
|
6439
|
-
}
|
|
6440
|
-
}
|
|
6441
6465
|
return result;
|
|
6442
6466
|
}
|
|
6443
6467
|
function checkProtectedRange(ctx, allPlanMessageIds, rawMessages, dangerous) {
|
|
@@ -6460,7 +6484,7 @@ function checkProtectedRange(ctx, allPlanMessageIds, rawMessages, dangerous) {
|
|
|
6460
6484
|
return new Error(
|
|
6461
6485
|
`This range includes ${coveredProtected.length} protected recent message(s) (${sample}), which are likely still needed for the current task step.
|
|
6462
6486
|
|
|
6463
|
-
Protected zone: last ${nMsgs} messages + last ${nToks >= 1e3 ? `${nToks / 1e3}K` : nToks} tokens
|
|
6487
|
+
Protected zone: last ${nMsgs} messages + last ${nToks >= 1e3 ? `${nToks / 1e3}K` : nToks} tokens.
|
|
6464
6488
|
If you are certain this content is genuinely consumed and must be compressed, re-issue the call with \`dangerous: true\`.
|
|
6465
6489
|
Otherwise, compress older ranges that do not include the tail of the conversation.`
|
|
6466
6490
|
);
|
|
@@ -6635,14 +6659,25 @@ function createCompressMessageTool(factoryCtx) {
|
|
|
6635
6659
|
ctx.state,
|
|
6636
6660
|
ctx.config
|
|
6637
6661
|
);
|
|
6638
|
-
|
|
6639
|
-
|
|
6662
|
+
const filteredPlans = plans.map((plan) => ({
|
|
6663
|
+
...plan,
|
|
6664
|
+
selection: filterLastUserMessage(
|
|
6665
|
+
plan.selection,
|
|
6666
|
+
searchContext,
|
|
6667
|
+
ctx.state,
|
|
6668
|
+
ctx.config.compress
|
|
6669
|
+
)
|
|
6670
|
+
})).filter((plan) => plan.selection.messageIds.length > 0);
|
|
6671
|
+
if (filteredPlans.length === 0) {
|
|
6672
|
+
throw new Error(
|
|
6673
|
+
skippedCount > 0 ? formatIssues(skippedIssues, skippedCount) : "All selected messages were filtered out (protected tool outputs and/or the last user message). They must remain in visible context."
|
|
6674
|
+
);
|
|
6640
6675
|
}
|
|
6641
6676
|
const minCompressRange = ctx.config.compress.minCompressRange;
|
|
6642
6677
|
if (minCompressRange > 0) {
|
|
6643
6678
|
let totalChars = 0;
|
|
6644
6679
|
const counted = /* @__PURE__ */ new Set();
|
|
6645
|
-
for (const plan of
|
|
6680
|
+
for (const plan of filteredPlans) {
|
|
6646
6681
|
for (const messageId of plan.selection.messageIds) {
|
|
6647
6682
|
if (counted.has(messageId)) continue;
|
|
6648
6683
|
counted.add(messageId);
|
|
@@ -6661,14 +6696,14 @@ function createCompressMessageTool(factoryCtx) {
|
|
|
6661
6696
|
const dangerous = args.dangerous === true;
|
|
6662
6697
|
const lastSegmentError = checkProtectedRange(
|
|
6663
6698
|
ctx,
|
|
6664
|
-
|
|
6699
|
+
filteredPlans.map((p) => p.selection.messageIds),
|
|
6665
6700
|
rawMessages,
|
|
6666
6701
|
dangerous
|
|
6667
6702
|
);
|
|
6668
6703
|
if (lastSegmentError) throw lastSegmentError;
|
|
6669
6704
|
const notifications = [];
|
|
6670
6705
|
const preparedPlans = [];
|
|
6671
|
-
for (const plan of
|
|
6706
|
+
for (const plan of filteredPlans) {
|
|
6672
6707
|
const summaryWithPromptInfo = appendProtectedPromptInfo(
|
|
6673
6708
|
plan.entry.summary,
|
|
6674
6709
|
plan.selection,
|
|
@@ -6778,7 +6813,7 @@ function createCompressMessageTool(factoryCtx) {
|
|
|
6778
6813
|
ctx.state.qualityGateRetryPending = qualityGateRetryPendingBefore;
|
|
6779
6814
|
throw error;
|
|
6780
6815
|
}
|
|
6781
|
-
return formatResult(
|
|
6816
|
+
return formatResult(filteredPlans.length, skippedIssues, skippedCount);
|
|
6782
6817
|
}
|
|
6783
6818
|
});
|
|
6784
6819
|
}
|
|
@@ -6852,10 +6887,18 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
6852
6887
|
ctx.config.compress.protectedTools,
|
|
6853
6888
|
ctx.config.protectedFilePatterns
|
|
6854
6889
|
)
|
|
6890
|
+
})).map((plan) => ({
|
|
6891
|
+
...plan,
|
|
6892
|
+
selection: filterLastUserMessage(
|
|
6893
|
+
plan.selection,
|
|
6894
|
+
searchContext,
|
|
6895
|
+
ctx.state,
|
|
6896
|
+
ctx.config.compress
|
|
6897
|
+
)
|
|
6855
6898
|
})).filter((plan) => plan.selection.messageIds.length > 0);
|
|
6856
6899
|
if (filteredPlans.length === 0) {
|
|
6857
6900
|
throw new Error(
|
|
6858
|
-
"All selected messages
|
|
6901
|
+
"All selected messages were filtered out (protected tool outputs and/or the last user message). They must remain in visible context."
|
|
6859
6902
|
);
|
|
6860
6903
|
}
|
|
6861
6904
|
const minCompressRange = ctx.config.compress.minCompressRange;
|
|
@@ -8122,7 +8165,7 @@ function refNum(ref) {
|
|
|
8122
8165
|
const n = parseInt(ref.slice(1), 10);
|
|
8123
8166
|
return Number.isNaN(n) ? -1 : n;
|
|
8124
8167
|
}
|
|
8125
|
-
function buildCompressibleRanges(messages, state, protectedTools = [], protectedFilePatterns = []) {
|
|
8168
|
+
function buildCompressibleRanges(messages, state, protectedTools = [], protectedFilePatterns = [], protectedZoneRefs) {
|
|
8126
8169
|
const msgInfo = [];
|
|
8127
8170
|
const protectedMsgInfo = [];
|
|
8128
8171
|
for (const msg of messages) {
|
|
@@ -8174,6 +8217,14 @@ function buildCompressibleRanges(messages, state, protectedTools = [], protected
|
|
|
8174
8217
|
let cur = null;
|
|
8175
8218
|
let prevRefNum = -2;
|
|
8176
8219
|
for (const info of msgInfo) {
|
|
8220
|
+
if (protectedZoneRefs?.has(info.ref)) {
|
|
8221
|
+
if (cur) {
|
|
8222
|
+
groups.push(cur);
|
|
8223
|
+
cur = null;
|
|
8224
|
+
}
|
|
8225
|
+
prevRefNum = info.refNum;
|
|
8226
|
+
continue;
|
|
8227
|
+
}
|
|
8177
8228
|
const hasGap = info.refNum > prevRefNum + 1;
|
|
8178
8229
|
if (cur && (info.isUser && cur.count >= 3 || hasGap)) {
|
|
8179
8230
|
groups.push(cur);
|
|
@@ -8380,7 +8431,6 @@ function computeProtectedRefs(messages, state, compress) {
|
|
|
8380
8431
|
if (compress.lastSegmentSoftBlock === false) return /* @__PURE__ */ new Set();
|
|
8381
8432
|
const preserveN = compress.preserveRecentMessages ?? 20;
|
|
8382
8433
|
const preserveTokens = compress.preserveRecentTokens ?? 2e4;
|
|
8383
|
-
const preserveLastUser = compress.preserveLastUserMessage ?? true;
|
|
8384
8434
|
const result = /* @__PURE__ */ new Set();
|
|
8385
8435
|
const visible = [];
|
|
8386
8436
|
for (const msg of messages) {
|
|
@@ -8411,14 +8461,6 @@ function computeProtectedRefs(messages, state, compress) {
|
|
|
8411
8461
|
tokenAccum += visible[i].tokens;
|
|
8412
8462
|
}
|
|
8413
8463
|
}
|
|
8414
|
-
if (preserveLastUser) {
|
|
8415
|
-
for (let i = visible.length - 1; i >= 0; i--) {
|
|
8416
|
-
if (visible[i].isUser) {
|
|
8417
|
-
result.add(visible[i].ref);
|
|
8418
|
-
break;
|
|
8419
|
-
}
|
|
8420
|
-
}
|
|
8421
|
-
}
|
|
8422
8464
|
return result;
|
|
8423
8465
|
}
|
|
8424
8466
|
function excludeProtectedRanges(ranges, protectedRefs) {
|
|
@@ -8600,13 +8642,14 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
|
|
|
8600
8642
|
config.compress.protectedTools,
|
|
8601
8643
|
config.protectedFilePatterns
|
|
8602
8644
|
);
|
|
8645
|
+
const protectedRefs = computeProtectedRefs(messages, state, config.compress);
|
|
8603
8646
|
const contextRanges = buildCompressibleRanges(
|
|
8604
8647
|
messages,
|
|
8605
8648
|
state,
|
|
8606
8649
|
config.compress.protectedTools,
|
|
8607
|
-
config.protectedFilePatterns
|
|
8650
|
+
config.protectedFilePatterns,
|
|
8651
|
+
protectedRefs
|
|
8608
8652
|
);
|
|
8609
|
-
const protectedRefs = computeProtectedRefs(messages, state, config.compress);
|
|
8610
8653
|
const unprotectedCompressible = excludeProtectedRanges(contextRanges.compressible, protectedRefs);
|
|
8611
8654
|
const recommendedRanges = filterRecommendedRanges(
|
|
8612
8655
|
unprotectedCompressible,
|
|
@@ -8635,10 +8678,10 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
|
|
|
8635
8678
|
}
|
|
8636
8679
|
const filterSuppressed = contextRanges.compressible.length > 0 && !hasRecommendations;
|
|
8637
8680
|
const allProtected = contextRanges.compressible.length === 0 && contextRanges.protected.length > 0;
|
|
8638
|
-
const
|
|
8681
|
+
const allInProtectedZone = protectedRefs.size > 0 && unprotectedCompressible.length === 0;
|
|
8682
|
+
const nothingToCompress = filterSuppressed || allProtected || allInProtectedZone;
|
|
8639
8683
|
let shouldInject = nudgeAllowed && (!nothingToCompress || emergencyOverride);
|
|
8640
|
-
if (nudgeAllowed && nothingToCompress && !emergencyOverride
|
|
8641
|
-
state.nudges.lastPerMessageNudgeTokens = currentTokens;
|
|
8684
|
+
if (nudgeAllowed && nothingToCompress && !emergencyOverride) {
|
|
8642
8685
|
state.nudges.lastNudgeShownTokens = void 0;
|
|
8643
8686
|
}
|
|
8644
8687
|
if (suffixMessage && !shouldInject) {
|
|
@@ -9635,11 +9678,13 @@ function renderOverview(visibleMessages, summaryTokens, blocks, fetchFailed, raw
|
|
|
9635
9678
|
const entry = pruneMap.get(msgId);
|
|
9636
9679
|
return !entry || entry.activeBlockIds.length === 0;
|
|
9637
9680
|
});
|
|
9681
|
+
const protectedRefs = ctx.config?.compress ? computeProtectedRefs(visibleRaw, ctx.state, ctx.config.compress) : /* @__PURE__ */ new Set();
|
|
9638
9682
|
const contextRanges = buildCompressibleRanges(
|
|
9639
9683
|
visibleRaw,
|
|
9640
9684
|
ctx.state,
|
|
9641
9685
|
ctx.config?.compress?.protectedTools ?? [],
|
|
9642
|
-
ctx.config?.protectedFilePatterns ?? []
|
|
9686
|
+
ctx.config?.protectedFilePatterns ?? [],
|
|
9687
|
+
protectedRefs
|
|
9643
9688
|
);
|
|
9644
9689
|
if (contextRanges.compressible.length > 0 || contextRanges.protected.length > 0) {
|
|
9645
9690
|
lines.push("");
|
|
@@ -9662,11 +9707,13 @@ function renderUncompressedRanges(rawMessages, ctx) {
|
|
|
9662
9707
|
const entry = pruneMap.get(msgId);
|
|
9663
9708
|
return !entry || entry.activeBlockIds.length === 0;
|
|
9664
9709
|
});
|
|
9710
|
+
const protectedRefs = ctx.config?.compress ? computeProtectedRefs(visibleMessages, ctx.state, ctx.config.compress) : /* @__PURE__ */ new Set();
|
|
9665
9711
|
const contextRanges = buildCompressibleRanges(
|
|
9666
9712
|
visibleMessages,
|
|
9667
9713
|
ctx.state,
|
|
9668
9714
|
ctx.config?.compress?.protectedTools ?? [],
|
|
9669
|
-
ctx.config?.protectedFilePatterns ?? []
|
|
9715
|
+
ctx.config?.protectedFilePatterns ?? [],
|
|
9716
|
+
protectedRefs
|
|
9670
9717
|
);
|
|
9671
9718
|
const compressible = contextRanges.compressible;
|
|
9672
9719
|
const totalTokens = compressible.reduce((s, r) => s + r.tokens, 0);
|
|
@@ -10023,6 +10070,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
|
10023
10070
|
import { join as join3 } from "path";
|
|
10024
10071
|
import { existsSync as existsSync3 } from "fs";
|
|
10025
10072
|
import { homedir as homedir3 } from "os";
|
|
10073
|
+
var LOG_VERSION = true ? "1.14.2" : "dev";
|
|
10026
10074
|
var Logger = class {
|
|
10027
10075
|
logDir;
|
|
10028
10076
|
enabled;
|
|
@@ -10082,7 +10130,7 @@ var Logger = class {
|
|
|
10082
10130
|
await this.ensureLogDir();
|
|
10083
10131
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
10084
10132
|
const dataStr = this.formatData(data);
|
|
10085
|
-
const logLine = `${timestamp} ${level.padEnd(5)} ${component}: ${message}${dataStr ? " | " + dataStr : ""}
|
|
10133
|
+
const logLine = `${timestamp} ${level.padEnd(5)} ${component}: ${message}${dataStr ? " | " + dataStr : ""} | v=${LOG_VERSION}
|
|
10086
10134
|
`;
|
|
10087
10135
|
const dailyLogDir = join3(this.logDir, "daily");
|
|
10088
10136
|
if (!existsSync3(dailyLogDir)) {
|
|
@@ -10211,6 +10259,10 @@ var Logger = class {
|
|
|
10211
10259
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10212
10260
|
const contextFile = join3(contextDir, `${timestamp}.json`);
|
|
10213
10261
|
await writeFile2(contextFile, JSON.stringify(minimized, null, 2));
|
|
10262
|
+
const versionFile = join3(contextDir, "_version");
|
|
10263
|
+
if (!existsSync3(versionFile)) {
|
|
10264
|
+
await writeFile2(versionFile, LOG_VERSION);
|
|
10265
|
+
}
|
|
10214
10266
|
} catch (error) {
|
|
10215
10267
|
}
|
|
10216
10268
|
}
|