opencode-acp 1.14.18-pr.307.19 → 1.14.19-pr.297.30
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 +12 -1
- package/README.zh-CN.md +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +145 -61
- package/dist/index.js.map +1 -1
- package/dist/lib/compress/decompress.d.ts.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.d.ts.map +1 -1
- package/dist/lib/compress/status.d.ts.map +1 -1
- package/dist/lib/hooks.d.ts +2 -0
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/logger.d.ts +2 -2
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/messages/filter/apply.d.ts.map +1 -1
- package/dist/lib/messages/inject/inject.d.ts.map +1 -1
- package/dist/lib/state/index.d.ts +1 -0
- package/dist/lib/state/index.d.ts.map +1 -1
- package/dist/lib/state/model-limits.d.ts +27 -0
- package/dist/lib/state/model-limits.d.ts.map +1 -0
- package/dist/lib/state/state.d.ts +9 -0
- package/dist/lib/state/state.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/dist/lib/ui/notification.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -284,7 +284,8 @@ Each level overrides the previous, so project settings take priority over global
|
|
|
284
284
|
// Automatically update npm-installed ACP when a newer npm latest is available.
|
|
285
285
|
// Version-locked plugin specs are not updated.
|
|
286
286
|
"autoUpdate": true,
|
|
287
|
-
// Enable
|
|
287
|
+
// Enable INFO/DEBUG logging + per-request snapshots to ~/.config/opencode/logs/acp/
|
|
288
|
+
// (WARN/ERROR are always logged to daily/<date>.log)
|
|
288
289
|
"debug": false,
|
|
289
290
|
// Notification display: "off", "minimal", or "detailed"
|
|
290
291
|
"pruneNotification": "off",
|
|
@@ -492,6 +493,16 @@ For the complete list with root cause analysis, see the [bug tracker](https://gi
|
|
|
492
493
|
|
|
493
494
|
## Changelog
|
|
494
495
|
|
|
496
|
+
### v1.14.19 — Fix release pipeline for real (npm 10 `--ignore-scripts` bug)
|
|
497
|
+
|
|
498
|
+
**Problem**: v1.14.18 (#306) was merged but still never published — `release.yml` failed at the exact same step. Root cause of the failed fix: the CI runner uses Node 22 (npm 10.9.x), and **npm 10 runs the `prepare` lifecycle hook during `npm pack` even when `--ignore-scripts` is passed**. v1.14.18's fix (`npm pack --ignore-scripts`) works on npm 11 but is a no-op on npm 10. When prepare runs, tsup writes `CLI Building entry: index.ts` to **stdout**, breaking `JSON.parse` in `verify-package.mjs` (`SyntaxError: Unexpected token`).
|
|
499
|
+
|
|
500
|
+
**Fix**: Redirect the `prepare` build's stdout to stderr: `"prepare": "npm run build 1>&2"` in `package.json`. Build output (informational) goes to stderr; stdout stays pure JSON regardless of npm version or whether `--ignore-scripts` works. Verified empirically with npm 10.9.9 locally: `npm pack --dry-run --json` now returns valid JSON (173 tarball entries) both with and without `--ignore-scripts`. The `--ignore-scripts` flag added in v1.14.18 is kept (harmless on npm 10, skips the redundant rebuild on npm 11). The `npm install github:...#branch` path still works — prepare still runs and still builds `dist/`.
|
|
501
|
+
|
|
502
|
+
Files: `package.json`. Tests: 976 pass; `check:package` green on npm 10.9.9 and npm 11.12.1.
|
|
503
|
+
|
|
504
|
+
**Install**: `opencode plugin opencode-acp@latest --global`
|
|
505
|
+
|
|
495
506
|
### v1.14.18 — Supersedes unpublished v1.14.17; fix release pipeline
|
|
496
507
|
|
|
497
508
|
**Problem**: v1.14.17 was merged (#305) but never published — `release.yml` failed at `npm run check:package` because the `prepare` hook added in #298 (`npm run build`) runs during `npm pack --json` inside `verify-package.mjs`, and tsup's `CLI Building entry: index.ts` stdout output breaks `JSON.parse` (`SyntaxError: Unexpected token 'C'`).
|
package/README.zh-CN.md
CHANGED
|
@@ -239,7 +239,8 @@ ACP 使用自己的配置文件,按以下顺序搜索:
|
|
|
239
239
|
// Automatically update npm-installed ACP when a newer npm latest is available.
|
|
240
240
|
// Version-locked plugin specs are not updated.
|
|
241
241
|
"autoUpdate": true,
|
|
242
|
-
// Enable
|
|
242
|
+
// Enable INFO/DEBUG logging + per-request snapshots to ~/.config/opencode/logs/acp/
|
|
243
|
+
// (WARN/ERROR are always logged to daily/<date>.log)
|
|
243
244
|
"debug": false,
|
|
244
245
|
// Notification display: "off", "minimal", or "detailed"
|
|
245
246
|
"pruneNotification": "detailed",
|
|
@@ -446,6 +447,16 @@ ACP 是 DCP 的直接替代品。迁移步骤:
|
|
|
446
447
|
|
|
447
448
|
## 更新日志
|
|
448
449
|
|
|
450
|
+
### v1.14.19 — 彻底修复发版流水线(npm 10 `--ignore-scripts` 失效)
|
|
451
|
+
|
|
452
|
+
**问题**:v1.14.18(#306)已合并但依然没有发布 —— `release.yml` 又在同一步骤失败。v1.14.18 修复失败的根本原因:CI 运行器是 Node 22(npm 10.9.x),而 **npm 10 在 `npm pack` 时即使传了 `--ignore-scripts` 也照样执行 `prepare` 生命周期钩子**。v1.14.18 的修复(`npm pack --ignore-scripts`)在 npm 11 上有效,在 npm 10 上是空操作。prepare 一旦执行,tsup 会把 `CLI Building entry: index.ts` 写到 **stdout**,破坏 `verify-package.mjs` 里的 `JSON.parse`(`SyntaxError: Unexpected token`)。
|
|
453
|
+
|
|
454
|
+
**修复**:把 `prepare` 构建的 stdout 重定向到 stderr:`package.json` 中改为 `"prepare": "npm run build 1>&2"`。构建输出(信息性)走 stderr,stdout 无论 npm 版本、无论 `--ignore-scripts` 是否生效都保持纯 JSON。已在本地用 npm 10.9.9 实证验证:`npm pack --dry-run --json` 现在返回合法 JSON(173 个 tarball 条目),带与不带 `--ignore-scripts` 均通过。v1.14.18 加的 `--ignore-scripts` 标志保留(npm 10 上无害,npm 11 上跳过多余重建)。`npm install github:...#branch` 路径不受影响 —— prepare 照常执行并构建 `dist/`。
|
|
455
|
+
|
|
456
|
+
文件:`package.json`。测试:976 通过;`check:package` 在 npm 10.9.9 和 npm 11.12.1 上均绿。
|
|
457
|
+
|
|
458
|
+
**安装**:`opencode plugin opencode-acp@latest --global`
|
|
459
|
+
|
|
449
460
|
### v1.14.18 — 取代未能发布的 v1.14.17;修复发版流水线
|
|
450
461
|
|
|
451
462
|
**问题**:v1.14.17 已合并(#305)但从未发布 —— \`release.yml\` 在 \`npm run check:package\` 一步失败:#298 新增的 \`prepare\` 钩子(\`npm run build\`)会在 \`verify-package.mjs\` 的 \`npm pack --json\` 期间运行,tsup 的 \`CLI Building entry: index.ts\` 输出污染 stdout,导致 \`JSON.parse\` 报错(\`SyntaxError: Unexpected token 'C'\`)。
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AA2BjD,QAAA,MAAM,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AA2BjD,QAAA,MAAM,MAAM,EAAE,MA6IK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -2949,6 +2949,51 @@ function applyPendingCompressionDurations(state) {
|
|
|
2949
2949
|
return updates;
|
|
2950
2950
|
}
|
|
2951
2951
|
|
|
2952
|
+
// lib/state/model-limits.ts
|
|
2953
|
+
function createModelLimitCatalog() {
|
|
2954
|
+
const modelLimits = /* @__PURE__ */ new Map();
|
|
2955
|
+
return {
|
|
2956
|
+
record(providerId, modelId, limit) {
|
|
2957
|
+
if (!providerId || !modelId || typeof limit !== "number" || limit <= 0) return;
|
|
2958
|
+
modelLimits.set(`${providerId}/${modelId}`, limit);
|
|
2959
|
+
},
|
|
2960
|
+
resolve(providerId, modelId) {
|
|
2961
|
+
if (!providerId || !modelId) return void 0;
|
|
2962
|
+
return modelLimits.get(`${providerId}/${modelId}`);
|
|
2963
|
+
},
|
|
2964
|
+
/**
|
|
2965
|
+
* Best-effort one-time seed from the host's provider catalog
|
|
2966
|
+
* (`client.config.providers()` → GET /config/providers). Never throws;
|
|
2967
|
+
* returns the number of model-limit entries recorded.
|
|
2968
|
+
*/
|
|
2969
|
+
async hydrateFromClient(client) {
|
|
2970
|
+
try {
|
|
2971
|
+
const config = client;
|
|
2972
|
+
const result = await config.config?.providers?.();
|
|
2973
|
+
const payload = result;
|
|
2974
|
+
const providers = payload?.data?.providers;
|
|
2975
|
+
if (!Array.isArray(providers)) return 0;
|
|
2976
|
+
let recorded = 0;
|
|
2977
|
+
for (const provider of providers) {
|
|
2978
|
+
const { id, models } = provider ?? {};
|
|
2979
|
+
if (typeof id !== "string" || !models) continue;
|
|
2980
|
+
for (const [modelId, model] of Object.entries(models)) {
|
|
2981
|
+
const limit = model?.limit;
|
|
2982
|
+
const context = limit?.context;
|
|
2983
|
+
if (typeof context === "number" && context > 0) {
|
|
2984
|
+
modelLimits.set(`${id}/${modelId}`, context);
|
|
2985
|
+
recorded++;
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
return recorded;
|
|
2990
|
+
} catch {
|
|
2991
|
+
return 0;
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
};
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2952
2997
|
// lib/compress/search.ts
|
|
2953
2998
|
import { tool } from "@opencode-ai/plugin";
|
|
2954
2999
|
async function fetchSessionMessages(client, sessionId) {
|
|
@@ -4140,6 +4185,26 @@ var SessionStateRegistry = class {
|
|
|
4140
4185
|
startsByCallId: /* @__PURE__ */ new Map(),
|
|
4141
4186
|
pendingByCallId: /* @__PURE__ */ new Map()
|
|
4142
4187
|
};
|
|
4188
|
+
// [FIX #312] Model-limit catalog (full rationale in ./model-limits.ts):
|
|
4189
|
+
// lets the messages hook reconcile state.modelContextLimit against the
|
|
4190
|
+
// model named on the request's user message instead of waiting one turn
|
|
4191
|
+
// for the system hook. Shared implementation — the test registry stub
|
|
4192
|
+
// composes the same factory.
|
|
4193
|
+
catalog = createModelLimitCatalog();
|
|
4194
|
+
recordModelLimit(providerId, modelId, limit) {
|
|
4195
|
+
this.catalog.record(providerId, modelId, limit);
|
|
4196
|
+
}
|
|
4197
|
+
resolveModelLimit(providerId, modelId) {
|
|
4198
|
+
return this.catalog.resolve(providerId, modelId);
|
|
4199
|
+
}
|
|
4200
|
+
/**
|
|
4201
|
+
* Best-effort one-time seed from the host's provider catalog
|
|
4202
|
+
* (`client.config.providers()` → GET /config/providers). Never throws;
|
|
4203
|
+
* returns the number of model-limit entries recorded.
|
|
4204
|
+
*/
|
|
4205
|
+
hydrateModelLimitsFromClient(client) {
|
|
4206
|
+
return this.catalog.hydrateFromClient(client);
|
|
4207
|
+
}
|
|
4143
4208
|
get(sessionId) {
|
|
4144
4209
|
return this.states.get(sessionId);
|
|
4145
4210
|
}
|
|
@@ -4688,8 +4753,8 @@ ${progressBar}`;
|
|
|
4688
4753
|
let toastMessage = message;
|
|
4689
4754
|
toastMessage = config.pruneNotification === "minimal" ? toastMessage : truncateToastBody(toastMessage);
|
|
4690
4755
|
if (config.debug) {
|
|
4691
|
-
|
|
4692
|
-
|
|
4756
|
+
logger.debug(`[ACP Debug] Compress notification:
|
|
4757
|
+
${message}`);
|
|
4693
4758
|
}
|
|
4694
4759
|
await client.tui.showToast({
|
|
4695
4760
|
body: {
|
|
@@ -5672,11 +5737,6 @@ exact values, errors). Then add "acknowledgeRisk": true to the compress tool cal
|
|
|
5672
5737
|
Without acknowledgeRisk: true, the compression will be rejected again.`;
|
|
5673
5738
|
return new Error(message);
|
|
5674
5739
|
}
|
|
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
5740
|
|
|
5681
5741
|
// lib/compress/pipeline.ts
|
|
5682
5742
|
function snapshotCompressionState(state) {
|
|
@@ -6150,13 +6210,13 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
6150
6210
|
}
|
|
6151
6211
|
const acknowledgeRisk = args.acknowledgeRisk === true;
|
|
6152
6212
|
const qualityGateRetryPendingBefore = ctx.state.qualityGateRetryPending;
|
|
6153
|
-
|
|
6154
|
-
|
|
6213
|
+
const bypassQuality = acknowledgeRisk && ctx.state.qualityGateRetryPending;
|
|
6214
|
+
const ignoredAcknowledgeRisk = acknowledgeRisk && !ctx.state.qualityGateRetryPending;
|
|
6215
|
+
if (ignoredAcknowledgeRisk) {
|
|
6216
|
+
ctx.logger.warn("compress: acknowledgeRisk ignored \u2014 no quality gate rejection pending");
|
|
6155
6217
|
}
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
} else {
|
|
6159
|
-
ctx.state.qualityGateRetryPending = false;
|
|
6218
|
+
ctx.state.qualityGateRetryPending = false;
|
|
6219
|
+
if (!bypassQuality) {
|
|
6160
6220
|
for (const plan of preparedPlans) {
|
|
6161
6221
|
const result = evaluatePreCommitQuality(
|
|
6162
6222
|
rawMessages,
|
|
@@ -6232,7 +6292,10 @@ function createCompressRangeTool(factoryCtx) {
|
|
|
6232
6292
|
const skippedNote = phantomSkipNotice !== null ? `
|
|
6233
6293
|
\u26A0\uFE0F ${phantomSkipNotice}
|
|
6234
6294
|
` : "";
|
|
6235
|
-
|
|
6295
|
+
const ackNote = ignoredAcknowledgeRisk ? `
|
|
6296
|
+
\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.
|
|
6297
|
+
` : "";
|
|
6298
|
+
return `Compressed ${totalCompressedMessages} messages into ${COMPRESSED_BLOCK_HEADER}.${skippedNote}${ackNote}
|
|
6236
6299
|
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
6300
|
\u{1F4A1} Tip: Use search_context('keyword') to find compressed content when you need it later.`;
|
|
6238
6301
|
}
|
|
@@ -7566,16 +7629,6 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
|
|
|
7566
7629
|
{ logger }
|
|
7567
7630
|
);
|
|
7568
7631
|
const hasRecommendations = recommendedRanges.length > 0;
|
|
7569
|
-
if (config.debug && contextRanges.compressible.length > 0) {
|
|
7570
|
-
const compressible = contextRanges.compressible;
|
|
7571
|
-
const fmt = (n) => n >= 1e3 ? `${(n / 1e3).toFixed(1)}K` : String(n);
|
|
7572
|
-
const lines = [
|
|
7573
|
-
`[ACP Debug] Recommendation filter:`,
|
|
7574
|
-
` Input: ${compressible.length} range(s), ${fmt(compressible.reduce((s, r) => s + r.tokens, 0))} tokens`,
|
|
7575
|
-
` Output: ${recommendedRanges.length} range(s) (last segment marked dangerous)`
|
|
7576
|
-
];
|
|
7577
|
-
logger.debug(lines.join("\n"));
|
|
7578
|
-
}
|
|
7579
7632
|
const allProtected = contextRanges.compressible.length === 0 && contextRanges.protected.length > 0;
|
|
7580
7633
|
const allInProtectedZone = protectedRefs.size > 0 && unprotectedCompressible.length === 0;
|
|
7581
7634
|
const nothingToCompress = allProtected || allInProtectedZone;
|
|
@@ -7671,6 +7724,16 @@ ${rules}`;
|
|
|
7671
7724
|
}
|
|
7672
7725
|
}
|
|
7673
7726
|
state.nudges.shouldInjectThisTurn = shouldInject;
|
|
7727
|
+
if (shouldInject && config.debug && contextRanges.compressible.length > 0) {
|
|
7728
|
+
const compressible = contextRanges.compressible;
|
|
7729
|
+
const fmt = (n) => n >= 1e3 ? `${(n / 1e3).toFixed(1)}K` : String(n);
|
|
7730
|
+
const lines = [
|
|
7731
|
+
`[ACP Debug] Recommendation filter:`,
|
|
7732
|
+
` Input: ${compressible.length} range(s), ${fmt(compressible.reduce((s, r) => s + r.tokens, 0))} tokens`,
|
|
7733
|
+
` Output: ${recommendedRanges.length} range(s) (last segment marked dangerous)`
|
|
7734
|
+
];
|
|
7735
|
+
logger.debug(lines.join("\n"));
|
|
7736
|
+
}
|
|
7674
7737
|
let tipsText = null;
|
|
7675
7738
|
if (shouldInject) {
|
|
7676
7739
|
if (suffixMessage && composition.total > 0) {
|
|
@@ -8125,10 +8188,6 @@ function resolveSingleBlockTarget(messagesState, blockIdArg) {
|
|
|
8125
8188
|
error: `Error: Block ${target.displayId} is nested inside active block ${activeAncestorBlockId}. Decompress block ${activeAncestorBlockId} first.`
|
|
8126
8189
|
};
|
|
8127
8190
|
}
|
|
8128
|
-
return {
|
|
8129
|
-
ok: false,
|
|
8130
|
-
error: `Error: Block ${target.displayId} is not active. It may have already been decompressed.`
|
|
8131
|
-
};
|
|
8132
8191
|
}
|
|
8133
8192
|
return { ok: true, targets: [target] };
|
|
8134
8193
|
}
|
|
@@ -8281,7 +8340,7 @@ function createDecompressTool(factoryCtx) {
|
|
|
8281
8340
|
const blockMessages = rawMessages.filter((m) => msgIdSet.has(extractMessageId(m)));
|
|
8282
8341
|
const lines2 = blockMessages.map(extractMessageText2);
|
|
8283
8342
|
const { writeFile: writeFile3 } = await import("fs/promises");
|
|
8284
|
-
const fileContent = lines2.length > 0 ? lines2.join("\n\n---\n\n") :
|
|
8343
|
+
const fileContent = lines2.length > 0 ? lines2.join("\n\n---\n\n") : targets[0]?.blocks[0]?.summary ?? "(no content available)";
|
|
8285
8344
|
await writeFile3(targetPath, fileContent, "utf-8");
|
|
8286
8345
|
const displayIds2 = targets.map((t) => `b${t.displayId}`).join(", ");
|
|
8287
8346
|
return `Block(s) ${displayIds2} content (${blockMessages.length} messages, ${fileContent.length} chars) written to ${targetPath}. Block(s) stay compressed \u2014 context unchanged. Use read tool to access specific parts.`;
|
|
@@ -8738,16 +8797,23 @@ function renderCompressedDrilldown(blocks, sort, limit, blocksById) {
|
|
|
8738
8797
|
lines.push(`Sorted by ${sort === "time" ? "time" : sort === "age" ? "age" : "size"}`);
|
|
8739
8798
|
lines.push("");
|
|
8740
8799
|
const shown = sorted.slice(0, limit);
|
|
8800
|
+
const activeCount = sorted.filter((b) => b.active).length;
|
|
8801
|
+
const inactiveCount = sorted.length - activeCount;
|
|
8802
|
+
if (inactiveCount > 0) {
|
|
8803
|
+
lines.push(`${activeCount} active, ${inactiveCount} inactive/consumed`);
|
|
8804
|
+
lines.push("");
|
|
8805
|
+
}
|
|
8741
8806
|
for (const b of shown) {
|
|
8742
8807
|
const survived = b.survivedCount ?? 0;
|
|
8743
8808
|
const gen = b.generation ?? "young";
|
|
8744
8809
|
const effCount = b.effectiveMessageIds?.length ?? 0;
|
|
8745
8810
|
const consumed = b.includedBlockIds && b.includedBlockIds.length > 0 ? ` nested=[${b.includedBlockIds.map((n) => `b${n}`).join(",")}]` : "";
|
|
8811
|
+
const status = b.active ? "" : " [inactive]";
|
|
8746
8812
|
const topic = b.topic || "(no topic)";
|
|
8747
8813
|
const tier = tierLabel(b);
|
|
8748
8814
|
const effTokens = getEffectiveCompressedTokens(b, blocksById);
|
|
8749
8815
|
lines.push(
|
|
8750
|
-
` b${b.blockId} (${tier}) ${formatTokens(effTokens)}\u2192${formatTokens(b.summaryTokens)} ${formatAge(b.createdAt)} ${formatIdRange(b)} age=${survived} ${gen} eff=${effCount}${consumed}`
|
|
8816
|
+
` b${b.blockId} (${tier}) ${formatTokens(effTokens)}\u2192${formatTokens(b.summaryTokens)} ${formatAge(b.createdAt)} ${formatIdRange(b)} age=${survived} ${gen} eff=${effCount}${consumed}${status}`
|
|
8751
8817
|
);
|
|
8752
8818
|
lines.push(` "${topic}"`);
|
|
8753
8819
|
}
|
|
@@ -8768,8 +8834,10 @@ function buildStatusReport(renderCtx, rawMessages, options) {
|
|
|
8768
8834
|
const sort = options?.sort ?? "size";
|
|
8769
8835
|
const limit = options?.limit ?? 30;
|
|
8770
8836
|
const msgState = renderCtx.state.prune.messages;
|
|
8771
|
-
const
|
|
8772
|
-
|
|
8837
|
+
const allBlocks = Array.from(msgState.blocksById.values()).sort(
|
|
8838
|
+
(a, b) => a.blockId - b.blockId
|
|
8839
|
+
);
|
|
8840
|
+
const activeBlocks = allBlocks.filter((b) => b.active);
|
|
8773
8841
|
const lines = [];
|
|
8774
8842
|
if (scope === "compressed") {
|
|
8775
8843
|
lines.push(...renderCompressedDrilldown(allBlocks, sort, limit, msgState.blocksById));
|
|
@@ -8791,7 +8859,7 @@ function buildStatusReport(renderCtx, rawMessages, options) {
|
|
|
8791
8859
|
visibleMsgs,
|
|
8792
8860
|
summaryTokens,
|
|
8793
8861
|
systemTokens,
|
|
8794
|
-
|
|
8862
|
+
activeBlocks,
|
|
8795
8863
|
false,
|
|
8796
8864
|
rawMessages,
|
|
8797
8865
|
renderCtx
|
|
@@ -8949,7 +9017,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
|
8949
9017
|
import { join as join3 } from "path";
|
|
8950
9018
|
import { existsSync as existsSync3 } from "fs";
|
|
8951
9019
|
import { homedir as homedir3 } from "os";
|
|
8952
|
-
var LOG_VERSION = true ? "1.14.
|
|
9020
|
+
var LOG_VERSION = true ? "1.14.19-pr.297.30" : "dev";
|
|
8953
9021
|
var Logger = class {
|
|
8954
9022
|
logDir;
|
|
8955
9023
|
enabled;
|
|
@@ -9004,7 +9072,7 @@ var Logger = class {
|
|
|
9004
9072
|
}
|
|
9005
9073
|
}
|
|
9006
9074
|
async write(level, component, message, data) {
|
|
9007
|
-
if (!this.enabled) return;
|
|
9075
|
+
if (!this.enabled && level !== "ERROR" && level !== "WARN") return;
|
|
9008
9076
|
try {
|
|
9009
9077
|
await this.ensureLogDir();
|
|
9010
9078
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -9031,12 +9099,10 @@ var Logger = class {
|
|
|
9031
9099
|
return this.write("DEBUG", component, message, data);
|
|
9032
9100
|
}
|
|
9033
9101
|
warn(message, data) {
|
|
9034
|
-
if (!this.enabled) return;
|
|
9035
9102
|
const component = this.getCallerFile(2);
|
|
9036
9103
|
return this.write("WARN", component, message, data);
|
|
9037
9104
|
}
|
|
9038
9105
|
error(message, data) {
|
|
9039
|
-
if (!this.enabled) return;
|
|
9040
9106
|
const component = this.getCallerFile(2);
|
|
9041
9107
|
return this.write("ERROR", component, message, data);
|
|
9042
9108
|
}
|
|
@@ -10047,6 +10113,7 @@ function applyMessageFilters(messages, config, logger, ctx) {
|
|
|
10047
10113
|
}
|
|
10048
10114
|
const result = { partsFiltered: 0, partsDropped: 0, partsModified: 0 };
|
|
10049
10115
|
const total = messages.length;
|
|
10116
|
+
const warnedFilters = /* @__PURE__ */ new Set();
|
|
10050
10117
|
const buildCtx = (text, role, i) => ({
|
|
10051
10118
|
text,
|
|
10052
10119
|
role,
|
|
@@ -10102,11 +10169,14 @@ function applyMessageFilters(messages, config, logger, ctx) {
|
|
|
10102
10169
|
try {
|
|
10103
10170
|
decision = filter.filter(filterCtx);
|
|
10104
10171
|
} catch (err) {
|
|
10105
|
-
|
|
10106
|
-
filter
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10172
|
+
if (!warnedFilters.has(filter.name)) {
|
|
10173
|
+
warnedFilters.add(filter.name);
|
|
10174
|
+
logger.warn("Message filter threw error", {
|
|
10175
|
+
filter: filter.name,
|
|
10176
|
+
error: err instanceof Error ? err.message : String(err),
|
|
10177
|
+
messageIndex: i
|
|
10178
|
+
});
|
|
10179
|
+
}
|
|
10110
10180
|
continue;
|
|
10111
10181
|
}
|
|
10112
10182
|
if (decision.action === "keep") continue;
|
|
@@ -10514,6 +10584,11 @@ function isInternalAgentRequest(messages) {
|
|
|
10514
10584
|
}
|
|
10515
10585
|
function createSystemPromptHandler(registry4, logger, config, prompts) {
|
|
10516
10586
|
return async (input, output) => {
|
|
10587
|
+
registry4.recordModelLimit(
|
|
10588
|
+
input.model?.providerID,
|
|
10589
|
+
input.model?.id,
|
|
10590
|
+
input.model?.limit?.context
|
|
10591
|
+
);
|
|
10517
10592
|
const state = input.sessionID ? registry4.get(input.sessionID) : void 0;
|
|
10518
10593
|
if (state && input.model?.limit?.context) {
|
|
10519
10594
|
state.modelContextLimit = input.model.limit.context;
|
|
@@ -10569,6 +10644,14 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
|
|
|
10569
10644
|
messages,
|
|
10570
10645
|
config
|
|
10571
10646
|
);
|
|
10647
|
+
const requestModel = lastUserMessage.info.model;
|
|
10648
|
+
const requestModelLimit = registry4.resolveModelLimit(
|
|
10649
|
+
requestModel?.providerID,
|
|
10650
|
+
requestModel?.modelID
|
|
10651
|
+
);
|
|
10652
|
+
if (requestModelLimit !== void 0) {
|
|
10653
|
+
state.modelContextLimit = requestModelLimit;
|
|
10654
|
+
}
|
|
10572
10655
|
await updatePerTurnState(state, logger, messages);
|
|
10573
10656
|
}
|
|
10574
10657
|
syncCompressPermissionState(state, config, hostPermissions, output.messages);
|
|
@@ -10614,23 +10697,6 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
|
|
|
10614
10697
|
config.debug ? (text) => {
|
|
10615
10698
|
logger.debug(`[ACP Debug] Nudge injected:
|
|
10616
10699
|
${text}`);
|
|
10617
|
-
if (state.sessionId && lastUserMessage) {
|
|
10618
|
-
const userInfo = lastUserMessage.info;
|
|
10619
|
-
sendIgnoredMessage(
|
|
10620
|
-
client,
|
|
10621
|
-
state.sessionId,
|
|
10622
|
-
`[ACP Debug Nudge]
|
|
10623
|
-
${text}`,
|
|
10624
|
-
{
|
|
10625
|
-
providerId: userInfo.model?.providerID,
|
|
10626
|
-
modelId: userInfo.model?.modelID,
|
|
10627
|
-
agent: userInfo.agent,
|
|
10628
|
-
variant: userInfo.variant
|
|
10629
|
-
},
|
|
10630
|
-
logger
|
|
10631
|
-
).catch(() => {
|
|
10632
|
-
});
|
|
10633
|
-
}
|
|
10634
10700
|
client.tui.showToast({
|
|
10635
10701
|
body: {
|
|
10636
10702
|
title: "ACP: Nudge Injected",
|
|
@@ -10684,10 +10750,9 @@ function createCommandExecuteHandler(client, registry4, logger, config, workingD
|
|
|
10684
10750
|
const sub = input.arguments?.trim().toLowerCase();
|
|
10685
10751
|
if (sub === "stats" || sub === "status") {
|
|
10686
10752
|
await handleStatsCommand(commandCtx);
|
|
10687
|
-
|
|
10753
|
+
return;
|
|
10688
10754
|
}
|
|
10689
10755
|
await handleContextCommand(commandCtx);
|
|
10690
|
-
throw new Error("__DCP_CONTEXT_HANDLED__");
|
|
10691
10756
|
}
|
|
10692
10757
|
};
|
|
10693
10758
|
}
|
|
@@ -10954,6 +11019,25 @@ var server = (async (ctx) => {
|
|
|
10954
11019
|
if (isSecureMode()) {
|
|
10955
11020
|
configureClientAuth(ctx.client);
|
|
10956
11021
|
}
|
|
11022
|
+
registry4.hydrateModelLimitsFromClient(ctx.client).then(
|
|
11023
|
+
(recorded) => {
|
|
11024
|
+
if (recorded > 0) {
|
|
11025
|
+
logger.info("Model limit catalog seeded from provider config", {
|
|
11026
|
+
models: recorded
|
|
11027
|
+
});
|
|
11028
|
+
} else {
|
|
11029
|
+
logger.warn(
|
|
11030
|
+
"Model limit catalog seeding recorded no entries \u2014 falling back to per-request refresh (system.transform)"
|
|
11031
|
+
);
|
|
11032
|
+
}
|
|
11033
|
+
},
|
|
11034
|
+
(error) => {
|
|
11035
|
+
logger.warn(
|
|
11036
|
+
"Model limit catalog seeding failed \u2014 falling back to per-request refresh (system.transform)",
|
|
11037
|
+
{ error: error instanceof Error ? error.message : String(error) }
|
|
11038
|
+
);
|
|
11039
|
+
}
|
|
11040
|
+
);
|
|
10957
11041
|
logger.info("DCP initialized");
|
|
10958
11042
|
startAutoUpdate(ctx, config.autoUpdate);
|
|
10959
11043
|
const compressToolContext = {
|