opencode-acp 1.14.16 → 1.14.17-pr.304.12
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 +10 -0
- package/README.zh-CN.md +10 -0
- package/dist/index.js +18 -23
- package/dist/index.js.map +1 -1
- package/dist/lib/compress/quality-gate/index.d.ts +1 -1
- package/dist/lib/compress/quality-gate/index.d.ts.map +1 -1
- package/dist/lib/compress/quality-gate/rejection.d.ts +0 -1
- package/dist/lib/compress/quality-gate/rejection.d.ts.map +1 -1
- package/dist/lib/compress/range-utils.d.ts +2 -0
- package/dist/lib/compress/range-utils.d.ts.map +1 -1
- package/dist/lib/compress/range.d.ts.map +1 -1
- package/dist/lib/compress/types.d.ts +1 -1
- package/dist/lib/compress/types.d.ts.map +1 -1
- package/dist/lib/prompts/compress-range.d.ts +1 -1
- package/dist/lib/prompts/compress-range.d.ts.map +1 -1
- package/dist/lib/prompts/extensions/tool.d.ts +1 -1
- package/dist/lib/prompts/extensions/tool.d.ts.map +1 -1
- package/dist/lib/state/types.d.ts +2 -1
- package/dist/lib/state/types.d.ts.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -492,6 +492,16 @@ For the complete list with root cause analysis, see the [bug tracker](https://gi
|
|
|
492
492
|
|
|
493
493
|
## Changelog
|
|
494
494
|
|
|
495
|
+
### v1.14.17 — Eliminate compress retry dead-ends (#301)
|
|
496
|
+
|
|
497
|
+
**Problem**: Two compress arguments hard-failed on first use and produced confusing error loops instead of actionable feedback. (1) The model learned "add `acknowledgeRisk: true` to retry" from quality-gate rejection templates, then carried the flag into *every* retry — including retries after non-quality errors (e.g. a missing topic), where no quality-gate rejection was pending, hitting `Parameter "acknowledgeRisk": true was provided, but no quality gate rejection is pending` (issue #301). (2) `content[0] needs a topic — provide content[0].topic or the top-level topic` hard-failed compress calls whose entries had no topic and no top-level fallback.
|
|
498
|
+
|
|
499
|
+
**Fix**: Both parameters are now tolerant. `acknowledgeRisk` without a pending rejection is a no-op — quality checks still run (the gate's protection is unchanged: bypass is only armed by a real quality-gate rejection), and a successful result carries an `⚠️ acknowledgeRisk was ignored: ...` note teaching correct usage. Topics are fully optional: an entry without its own topic falls back to the top-level topic, then to one derived from the summary's first line (markdown headings stripped, capped at 80 chars), so `search_context` always has something searchable.
|
|
500
|
+
|
|
501
|
+
Files: `lib/compress/range.ts`, `lib/compress/range-utils.ts` (new `deriveFallbackTopic`), `lib/compress/quality-gate/rejection.ts` (removed `buildPreemptiveAcknowledgeError`), `lib/compress/types.ts`, `lib/prompts/compress-range.ts`, `lib/prompts/extensions/tool.ts`, `lib/state/types.ts`. Tests: 976 pass.
|
|
502
|
+
|
|
503
|
+
**Install**: `opencode plugin opencode-acp@latest --global`
|
|
504
|
+
|
|
495
505
|
### v1.14.16 — Raise context limits to 80%
|
|
496
506
|
|
|
497
507
|
**Problem**: The compression thresholds were `maxContextLimit: 55%` / `minContextLimit: 45%`. The strong "over-limit" nudge fired as soon as context exceeded 55% of the model window. Combined with the fixed 50K growth threshold (v1.14.15), this still engaged compression relatively early, leaving usable context unused.
|
package/README.zh-CN.md
CHANGED
|
@@ -446,6 +446,16 @@ ACP 是 DCP 的直接替代品。迁移步骤:
|
|
|
446
446
|
|
|
447
447
|
## 更新日志
|
|
448
448
|
|
|
449
|
+
### v1.14.17 — 消除 compress 重试死循环(#301)
|
|
450
|
+
|
|
451
|
+
**问题**:两个 compress 参数在首次使用时硬报错,产生令人困惑的错误循环而非可执行的反馈。(1) 模型从质量门拒绝模板学到「重试要加 `acknowledgeRisk: true`」,于是把它带进了所有重试——包括非质量错误(如缺 topic)之后的重试,此时没有 pending 的质量门拒绝,撞上 `Parameter "acknowledgeRisk": true was provided, but no quality gate rejection is pending`(issue #301)。(2) `content[0] needs a topic — provide content[0].topic or the top-level topic` 在 entry 无 topic 且无顶层 fallback 时硬报错。
|
|
452
|
+
|
|
453
|
+
**修复**:两个参数均改为宽容处理。无 pending 拒绝时的 `acknowledgeRisk` 为 no-op——质量检查照常运行(质量门保护不变:bypass 只由真实的质量门拒绝解锁),成功结果附带 `⚠️ acknowledgeRisk was ignored: ...` 提示教模型正确用法。topic 完全可选:entry 无自有 topic 时依次回退到顶层 topic、再到从 summary 首行派生的 topic(去 markdown 标题符、截断 80 字符),保证 `search_context` 始终有可检索内容。
|
|
454
|
+
|
|
455
|
+
文件:`lib/compress/range.ts`、`lib/compress/range-utils.ts`(新增 `deriveFallbackTopic`)、`lib/compress/quality-gate/rejection.ts`(移除 `buildPreemptiveAcknowledgeError`)、`lib/compress/types.ts`、`lib/prompts/compress-range.ts`、`lib/prompts/extensions/tool.ts`、`lib/state/types.ts`。测试:976 通过。
|
|
456
|
+
|
|
457
|
+
**安装**:`opencode plugin opencode-acp@latest --global`
|
|
458
|
+
|
|
449
459
|
### v1.14.16 — 将上下文 limit 提升至 80%
|
|
450
460
|
|
|
451
461
|
**问题**:压缩阈值原为 `maxContextLimit: 55%` / `minContextLimit: 45%`。上下文一旦超过模型窗口的 55% 就会触发强「超限」nudge。配合 v1.14.15 固定的 50K 增长阈值,压缩仍较早介入,可用上下文未被充分利用。
|
package/dist/index.js
CHANGED
|
@@ -2075,7 +2075,7 @@ THE FORMAT OF COMPRESS
|
|
|
2075
2075
|
]
|
|
2076
2076
|
}
|
|
2077
2077
|
\`\`\`
|
|
2078
|
-
Each entry
|
|
2078
|
+
Each entry MAY have a topic. Missing topics fall back to the top-level topic, then to an automatic one derived from the summary.`;
|
|
2079
2079
|
|
|
2080
2080
|
// lib/state/persistence.ts
|
|
2081
2081
|
import * as fs from "fs/promises";
|
|
@@ -3756,8 +3756,11 @@ function filterProtectedRecentMessages(selection, searchContext, state, compress
|
|
|
3756
3756
|
|
|
3757
3757
|
// lib/compress/range-utils.ts
|
|
3758
3758
|
var BLOCK_PLACEHOLDER_REGEX = /\(b(\d+)\)|\{block_(\d+)\}/gi;
|
|
3759
|
+
function deriveFallbackTopic(summary) {
|
|
3760
|
+
const firstLine = summary.split("\n").map((line) => line.replace(/^#{1,6}\s*/, "").trim()).find((line) => line.length > 0) ?? "compressed range";
|
|
3761
|
+
return firstLine.length > 80 ? `${firstLine.slice(0, 77)}...` : firstLine;
|
|
3762
|
+
}
|
|
3759
3763
|
function validateArgs(args) {
|
|
3760
|
-
const hasTopLevelTopic = typeof args.topic === "string" && args.topic.trim().length > 0;
|
|
3761
3764
|
if (!Array.isArray(args.content) || args.content.length === 0) {
|
|
3762
3765
|
throw new Error("content is required and must be a non-empty array");
|
|
3763
3766
|
}
|
|
@@ -3773,18 +3776,12 @@ function validateArgs(args) {
|
|
|
3773
3776
|
if (typeof entry?.summary !== "string" || entry.summary.trim().length === 0) {
|
|
3774
3777
|
throw new Error(`${prefix}.summary is required and must be a non-empty string`);
|
|
3775
3778
|
}
|
|
3776
|
-
const hasEntryTopic = typeof entry?.topic === "string" && entry.topic.trim().length > 0;
|
|
3777
|
-
if (!hasEntryTopic && !hasTopLevelTopic) {
|
|
3778
|
-
throw new Error(
|
|
3779
|
-
`${prefix} needs a topic \u2014 provide ${prefix}.topic or the top-level topic`
|
|
3780
|
-
);
|
|
3781
|
-
}
|
|
3782
3779
|
}
|
|
3783
3780
|
}
|
|
3784
3781
|
function resolveRanges(args, searchContext, state, logger) {
|
|
3785
3782
|
return args.content.map((entry, index) => {
|
|
3786
3783
|
const normalizedEntry = {
|
|
3787
|
-
topic: typeof entry.topic === "string" && entry.topic.trim().length > 0 ? entry.topic.trim() : void 0,
|
|
3784
|
+
topic: typeof entry.topic === "string" && entry.topic.trim().length > 0 ? entry.topic.trim() : typeof args.topic === "string" && args.topic.trim().length > 0 ? void 0 : deriveFallbackTopic(entry.summary),
|
|
3788
3785
|
startId: entry.startId.trim(),
|
|
3789
3786
|
endId: entry.endId.trim(),
|
|
3790
3787
|
summary: entry.summary
|
|
@@ -5672,11 +5669,6 @@ exact values, errors). Then add "acknowledgeRisk": true to the compress tool cal
|
|
|
5672
5669
|
Without acknowledgeRisk: true, the compression will be rejected again.`;
|
|
5673
5670
|
return new Error(message);
|
|
5674
5671
|
}
|
|
5675
|
-
function buildPreemptiveAcknowledgeError() {
|
|
5676
|
-
return new Error(
|
|
5677
|
-
'Parameter "acknowledgeRisk": true was provided, but no quality gate rejection is pending. This parameter is only valid immediately after a compression was rejected by the quality gate. Remove it and try again.'
|
|
5678
|
-
);
|
|
5679
|
-
}
|
|
5680
5672
|
|
|
5681
5673
|
// lib/compress/pipeline.ts
|
|
5682
5674
|
function snapshotCompressionState(state) {
|
|
@@ -6150,13 +6142,13 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
6150
6142
|
}
|
|
6151
6143
|
const acknowledgeRisk = args.acknowledgeRisk === true;
|
|
6152
6144
|
const qualityGateRetryPendingBefore = ctx.state.qualityGateRetryPending;
|
|
6153
|
-
|
|
6154
|
-
|
|
6145
|
+
const bypassQuality = acknowledgeRisk && ctx.state.qualityGateRetryPending;
|
|
6146
|
+
const ignoredAcknowledgeRisk = acknowledgeRisk && !ctx.state.qualityGateRetryPending;
|
|
6147
|
+
if (ignoredAcknowledgeRisk) {
|
|
6148
|
+
ctx.logger.warn("compress: acknowledgeRisk ignored \u2014 no quality gate rejection pending");
|
|
6155
6149
|
}
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
} else {
|
|
6159
|
-
ctx.state.qualityGateRetryPending = false;
|
|
6150
|
+
ctx.state.qualityGateRetryPending = false;
|
|
6151
|
+
if (!bypassQuality) {
|
|
6160
6152
|
for (const plan of preparedPlans) {
|
|
6161
6153
|
const result = evaluatePreCommitQuality(
|
|
6162
6154
|
rawMessages,
|
|
@@ -6232,7 +6224,10 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
6232
6224
|
const skippedNote = phantomSkipNotice !== null ? `
|
|
6233
6225
|
\u26A0\uFE0F ${phantomSkipNotice}
|
|
6234
6226
|
` : "";
|
|
6235
|
-
|
|
6227
|
+
const ackNote = ignoredAcknowledgeRisk ? `
|
|
6228
|
+
\u26A0\uFE0F acknowledgeRisk was ignored: no quality gate rejection was pending, so quality checks ran normally. Only pass it when retrying immediately after a quality gate rejection.
|
|
6229
|
+
` : "";
|
|
6230
|
+
return `Compressed ${totalCompressedMessages} messages into ${COMPRESSED_BLOCK_HEADER}.${skippedNote}${ackNote}
|
|
6236
6231
|
IMPORTANT: This was an automatic context compression. You MUST continue your previous task exactly where you left off. Do NOT ask the user what to do next.
|
|
6237
6232
|
\u{1F4A1} Tip: Use search_context('keyword') to find compressed content when you need it later.`;
|
|
6238
6233
|
}
|
|
@@ -8949,7 +8944,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
|
8949
8944
|
import { join as join3 } from "path";
|
|
8950
8945
|
import { existsSync as existsSync3 } from "fs";
|
|
8951
8946
|
import { homedir as homedir3 } from "os";
|
|
8952
|
-
var LOG_VERSION = true ? "1.14.
|
|
8947
|
+
var LOG_VERSION = true ? "1.14.17-pr.304.12" : "dev";
|
|
8953
8948
|
var Logger = class {
|
|
8954
8949
|
logDir;
|
|
8955
8950
|
enabled;
|
|
@@ -9277,7 +9272,7 @@ Rules:
|
|
|
9277
9272
|
BATCHING
|
|
9278
9273
|
When multiple independent ranges are ready and their boundaries do not overlap, include all of them as separate entries in the \`content\` array of a single tool call. Each entry should have its own \`startId\`, \`endId\`, and \`summary\`.
|
|
9279
9274
|
|
|
9280
|
-
When the ranges cover unrelated topics, give each entry its own \`topic\` for better summary quality \u2014 do not force unrelated content under a single shared topic.
|
|
9275
|
+
When the ranges cover unrelated topics, give each entry its own \`topic\` for better summary quality \u2014 do not force unrelated content under a single shared topic. The top-level \`topic\` is an optional fallback; when no topic is provided at all, one is derived from the summary's first line automatically.
|
|
9281
9276
|
|
|
9282
9277
|
\`\`\`
|
|
9283
9278
|
compress({ content: [
|