opencode-acp 1.12.5 → 1.12.6

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 CHANGED
@@ -422,6 +422,14 @@ For the complete list with root cause analysis, see the [bug tracker](https://gi
422
422
 
423
423
  ## Changelog
424
424
 
425
+ ### v1.12.6 — Stale contextLimitAnchors Fix (PR #143)
426
+
427
+ **Problem**: `contextLimitAnchors` were populated when `overMaxLimit=true` but only cleared on a compress tool call in the current turn (`currentTurnHasCompress`). If context dropped below `maxLimit` via another mechanism (OpenCode compaction, external message deletion), the anchors stayed stale → `applyAnchoredNudges` kept injecting the "⚠️ Context limit reached" template at low context levels (as low as 10% usage).
428
+
429
+ **Fix**: Added `else` branch in `lib/messages/inject/inject.ts` that clears `contextLimitAnchors` whenever `!overMaxLimit`, establishing symmetry with the existing turn/iteration anchor cleanup at `!overMinLimit`. 3 regression tests (state-level clear, integration with prompt markers, sub-minLimit clear path). Dual-agent reviewed (Oracle + independent reviewer, both APPROVE).
430
+
431
+ Files: `lib/messages/inject/inject.ts`. Tests: `tests/inject.test.ts`. 691 tests pass.
432
+
425
433
  ### v1.12.5 — Bug 20 Suppression Fix + Growth Floor Gate Correction (PRs #139, #140)
426
434
 
427
435
  **Problem**: Two bugs in the nudge suppression logic introduced after v1.12.4. (1) `isContextOverLimits` Bug 20 suppression checked `(part as any).type === "tool-invocation" && (part as any).toolInvocation?.toolName === "compress"` — a message-part format that does not exist in the SDK (all 18+ other tool-type checks in the codebase use `part.type === "tool" && part.tool === "compress"`). The suppression never matched, so `overMaxLimit` was never set to `false` after a compress call → the max-limit alert fired every turn → over-compression feedback loop. (2) The growth floor gate (PR #134) made `growthFloor` the sole gate for `nudgeAllowed`, dropping the `decision.shouldNudge` requirement — meaning nudges could fire on negative growth as long as the growth floor condition was met.
package/README.zh-CN.md CHANGED
@@ -395,6 +395,14 @@ ACP 在首次启动时自动将配置从 `dcp.jsonc` 迁移到 `acp.jsonc`,将
395
395
 
396
396
  ## 更新日志
397
397
 
398
+ ### v1.12.6 — Stale contextLimitAnchors 修复(PR #143)
399
+
400
+ **问题**:`contextLimitAnchors` 仅在 `overMaxLimit=true` 时添加,但只在当前 turn 有 compress 调用时 (`currentTurnHasCompress`) 才清除。如果上下文通过其他机制(OpenCode compaction、外部消息删除)降到 `maxLimit` 以下,anchors 保持 stale → `applyAnchoredNudges` 持续注入 "⚠️ Context limit reached" 模板,即使实际上下文很低(低至 10%)。
401
+
402
+ **修复**:在 `lib/messages/inject/inject.ts` 添加 `else` 分支,当 `!overMaxLimit` 时清除 `contextLimitAnchors`,与已有的 `!overMinLimit` 清除 turn/iteration anchors 逻辑对称。3 个回归测试(state 级、prompt marker 集成、sub-minLimit 清除)。双 agent review(Oracle + 独立 reviewer,均 APPROVE)。
403
+
404
+ 文件:`lib/messages/inject/inject.ts`。测试:`tests/inject.test.ts`。691 测试通过。
405
+
398
406
  ### v1.12.5 — Bug 20 抑制修复 + 增长下限门控修正(PR #139, #140)
399
407
 
400
408
  **问题**:v1.12.4 后引入的两个 nudge 抑制逻辑 bug。(1)`isContextOverLimits` 的 Bug 20 抑制检查 `(part as any).type === "tool-invocation" && (part as any).toolInvocation?.toolName === "compress"` —— 这个消息部件格式在 SDK 中根本不存在(代码库中其他 18+ 处工具类型检查全部使用 `part.type === "tool" && part.tool === "compress"`)。抑制逻辑永不匹配,所以压缩后 `overMaxLimit` 从不置 false → max-limit 告警每轮触发 → 过度压缩正反馈循环。(2)增长下限门控(PR #134)使 `growthFloor` 成为 `nudgeAllowed` 的唯一 gate,丢弃了 `decision.shouldNudge` 要求 —— 意味着即使增长为负,只要满足增长下限条件 nudge 就会触发。
package/dist/index.js CHANGED
@@ -7160,35 +7160,41 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
7160
7160
  anchorsChanged = true;
7161
7161
  }
7162
7162
  }
7163
- } else if (overMinLimit) {
7164
- const isLastMessageUser = lastMessage?.message.info.role === "user";
7165
- if (isLastMessageUser && lastAssistantMessage) {
7166
- const previousSize = state.nudges.turnNudgeAnchors.size;
7167
- state.nudges.turnNudgeAnchors.add(lastMessage.message.info.id);
7168
- state.nudges.turnNudgeAnchors.add(lastAssistantMessage.info.id);
7169
- if (state.nudges.turnNudgeAnchors.size !== previousSize) {
7170
- anchorsChanged = true;
7171
- }
7163
+ } else {
7164
+ if (state.nudges.contextLimitAnchors.size > 0) {
7165
+ state.nudges.contextLimitAnchors.clear();
7166
+ anchorsChanged = true;
7172
7167
  }
7173
- const lastUserMessage = getLastUserMessage(messages);
7174
- if (lastUserMessage && lastMessage) {
7175
- const lastUserMessageIndex = messages.findIndex(
7176
- (message) => message.info.id === lastUserMessage.info.id
7177
- );
7178
- if (lastUserMessageIndex >= 0) {
7179
- const messagesSinceUser = countMessagesAfterIndex(messages, lastUserMessageIndex);
7180
- const iterationThreshold = getIterationNudgeThreshold(config);
7181
- if (lastMessage.index > lastUserMessageIndex && messagesSinceUser >= iterationThreshold) {
7182
- const interval = getNudgeFrequency(config);
7183
- const added = addAnchor(
7184
- state.nudges.iterationNudgeAnchors,
7185
- lastMessage.message.info.id,
7186
- lastMessage.index,
7187
- messages,
7188
- interval
7189
- );
7190
- if (added) {
7191
- anchorsChanged = true;
7168
+ if (overMinLimit) {
7169
+ const isLastMessageUser = lastMessage?.message.info.role === "user";
7170
+ if (isLastMessageUser && lastAssistantMessage) {
7171
+ const previousSize = state.nudges.turnNudgeAnchors.size;
7172
+ state.nudges.turnNudgeAnchors.add(lastMessage.message.info.id);
7173
+ state.nudges.turnNudgeAnchors.add(lastAssistantMessage.info.id);
7174
+ if (state.nudges.turnNudgeAnchors.size !== previousSize) {
7175
+ anchorsChanged = true;
7176
+ }
7177
+ }
7178
+ const lastUserMessage = getLastUserMessage(messages);
7179
+ if (lastUserMessage && lastMessage) {
7180
+ const lastUserMessageIndex = messages.findIndex(
7181
+ (message) => message.info.id === lastUserMessage.info.id
7182
+ );
7183
+ if (lastUserMessageIndex >= 0) {
7184
+ const messagesSinceUser = countMessagesAfterIndex(messages, lastUserMessageIndex);
7185
+ const iterationThreshold = getIterationNudgeThreshold(config);
7186
+ if (lastMessage.index > lastUserMessageIndex && messagesSinceUser >= iterationThreshold) {
7187
+ const interval = getNudgeFrequency(config);
7188
+ const added = addAnchor(
7189
+ state.nudges.iterationNudgeAnchors,
7190
+ lastMessage.message.info.id,
7191
+ lastMessage.index,
7192
+ messages,
7193
+ interval
7194
+ );
7195
+ if (added) {
7196
+ anchorsChanged = true;
7197
+ }
7192
7198
  }
7193
7199
  }
7194
7200
  }