opencode-acp 1.18.4-pr.480.215 → 1.18.4-pr.484.217

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
@@ -431,9 +431,15 @@ Each level overrides the previous, so project settings take priority over global
431
431
  // compression, so their thinking rides along every request as an
432
432
  // unreclaimable floor. Closed turns only; the active round is never
433
433
  // touched. Small thinkings under the threshold are kept.
434
+ // [#482] Pin the wire form of historical thinking: fold each assistant
435
+ // message's reasoning parts into one <thinking>-marked text part at
436
+ // request time, so serialized bytes stay deterministic across host
437
+ // metadata-table refreshes. On by default; set normalize:false for
438
+ // direct providers needing structured thinking replay.
434
439
  "reasoning": {
435
440
  "drop": true,
436
441
  "threshold": 2048,
442
+ "normalize": true
437
443
  },
438
444
  // [#478] Image archive: spill data-URL images to disk when they enter
439
445
  // the session so folded ranges keep re-readable pointers instead of
package/README.zh-CN.md CHANGED
@@ -376,9 +376,14 @@ ACP 使用自己的配置文件,按以下顺序搜索:
376
376
  // compress 调用被硬排除在压缩之外,其思考内容会随每次请求原样重发,
377
377
  // 形成无法回收的上下文底座。仅作用于已关闭的轮次,活跃轮永不触碰;
378
378
  // 低于阈值的小思考保留。
379
+ // [#482] 钉死历史思考的 wire 形态:请求时把每个 assistant 消息的
380
+ // reasoning 部分折叠为一个带 <thinking> 标记的 text 部分,使序列化字节
381
+ // 在宿主元数据表刷新后保持确定。默认开启;直连需要结构化 thinking
382
+ // 回放的 provider 设 normalize:false。
379
383
  "reasoning": {
380
384
  "drop": true,
381
385
  "threshold": 2048,
386
+ "normalize": true
382
387
  },
383
388
  // [#478] 图片归档:图片(data-URL)进入会话时即落盘,折叠后摘要里保留
384
389
  // 可重读的路径指针,而不是把像素悄悄丢掉。文件落在
package/dist/index.js CHANGED
@@ -916,6 +916,7 @@ var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
916
916
  "compress.reasoning",
917
917
  "compress.reasoning.drop",
918
918
  "compress.reasoning.threshold",
919
+ "compress.reasoning.normalize",
919
920
  "compress.images",
920
921
  "compress.images.enabled",
921
922
  "compress.images.minBytes",
@@ -1292,7 +1293,7 @@ function validateConfigTypes(config) {
1292
1293
  if (typeof compress.reasoning !== "object" || compress.reasoning === null || Array.isArray(compress.reasoning)) {
1293
1294
  errors.push({
1294
1295
  key: "compress.reasoning",
1295
- expected: "object { drop?: boolean; threshold?: integer (>= 0) }",
1296
+ expected: "object { drop?: boolean; threshold?: integer (>= 0); normalize?: boolean }",
1296
1297
  actual: JSON.stringify(compress.reasoning)
1297
1298
  });
1298
1299
  } else {
@@ -1310,6 +1311,13 @@ function validateConfigTypes(config) {
1310
1311
  actual: JSON.stringify(compress.reasoning.threshold)
1311
1312
  });
1312
1313
  }
1314
+ if (compress.reasoning.normalize !== void 0 && typeof compress.reasoning.normalize !== "boolean") {
1315
+ errors.push({
1316
+ key: "compress.reasoning.normalize",
1317
+ expected: "boolean",
1318
+ actual: typeof compress.reasoning.normalize
1319
+ });
1320
+ }
1313
1321
  }
1314
1322
  }
1315
1323
  if (compress.images !== void 0) {
@@ -1496,7 +1504,7 @@ function validateConfigTypes(config) {
1496
1504
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
1497
1505
  errors.push({
1498
1506
  key,
1499
- expected: "object { drop?: boolean; threshold?: integer (>= 0) }",
1507
+ expected: "object { drop?: boolean; threshold?: integer (>= 0); normalize?: boolean }",
1500
1508
  actual: JSON.stringify(value)
1501
1509
  });
1502
1510
  break;
@@ -1516,6 +1524,13 @@ function validateConfigTypes(config) {
1516
1524
  actual: JSON.stringify(reasoning.threshold)
1517
1525
  });
1518
1526
  }
1527
+ if (reasoning.normalize !== void 0 && typeof reasoning.normalize !== "boolean") {
1528
+ errors.push({
1529
+ key: `${key}.normalize`,
1530
+ expected: "boolean",
1531
+ actual: typeof reasoning.normalize
1532
+ });
1533
+ }
1519
1534
  break;
1520
1535
  }
1521
1536
  };
@@ -1976,6 +1991,7 @@ function mergeCompress(base, override) {
1976
1991
  if (!override) {
1977
1992
  return base;
1978
1993
  }
1994
+ const normalizeResolved = override.reasoning?.normalize ?? base.reasoning?.normalize;
1979
1995
  return {
1980
1996
  permission: override.permission ?? base.permission,
1981
1997
  showCompression: override.showCompression ?? base.showCompression,
@@ -2010,7 +2026,8 @@ function mergeCompress(base, override) {
2010
2026
  preserveLastUserMessage: override.preserveLastUserMessage ?? base.preserveLastUserMessage,
2011
2027
  reasoning: {
2012
2028
  drop: override.reasoning?.drop ?? base.reasoning?.drop ?? DEFAULT_COMPRESS_REASONING.drop,
2013
- threshold: override.reasoning?.threshold ?? base.reasoning?.threshold ?? DEFAULT_COMPRESS_REASONING.threshold
2029
+ threshold: override.reasoning?.threshold ?? base.reasoning?.threshold ?? DEFAULT_COMPRESS_REASONING.threshold,
2030
+ ...normalizeResolved !== void 0 ? { normalize: normalizeResolved } : {}
2014
2031
  },
2015
2032
  images: {
2016
2033
  enabled: override.images?.enabled ?? base.images?.enabled ?? DEFAULT_COMPRESS_IMAGES.enabled,
@@ -9884,6 +9901,8 @@ var injectMessageIds = (state, config, messages, compressionPriorities) => {
9884
9901
  };
9885
9902
 
9886
9903
  // lib/messages/reasoning-strip.ts
9904
+ var isReasoningWithText = (part) => part.type === "reasoning" && typeof part.text === "string";
9905
+ var isTextWithText = (part) => part.type === "text" && typeof part.text === "string";
9887
9906
  function stripStaleMetadata(messages) {
9888
9907
  const lastUserMessage = getLastUserMessage(messages);
9889
9908
  if (lastUserMessage?.info.role !== "user") {
@@ -9952,6 +9971,61 @@ function dropCompressReasoning(messages, threshold) {
9952
9971
  }
9953
9972
  return removed;
9954
9973
  }
9974
+ function normalizeThinkingForm(messages) {
9975
+ let normalized = 0;
9976
+ for (const message of messages) {
9977
+ if (!message || message.info.role !== "assistant") {
9978
+ continue;
9979
+ }
9980
+ const parts = Array.isArray(message.parts) ? message.parts : [];
9981
+ const reasoningParts = parts.filter(isReasoningWithText);
9982
+ if (reasoningParts.length === 0) {
9983
+ continue;
9984
+ }
9985
+ const R = reasoningParts.map((part) => part.text).join("");
9986
+ const textParts = parts.filter(isTextWithText);
9987
+ const T = textParts.map((part) => part.text).join("");
9988
+ const mergedText = `<thinking>
9989
+ ${R}
9990
+ </thinking>` + (T.length > 0 ? `
9991
+ ${T}` : "");
9992
+ const donor = textParts[0];
9993
+ const newParts = [];
9994
+ let inserted = false;
9995
+ for (const part of parts) {
9996
+ if (part.type === "reasoning" || part.type === "text") {
9997
+ if (!inserted) {
9998
+ if (donor) {
9999
+ newParts.push({ ...donor, text: mergedText });
10000
+ } else {
10001
+ newParts.push({
10002
+ id: `${message.info.id}-acp-think`,
10003
+ sessionID: message.info.sessionID,
10004
+ messageID: message.info.id,
10005
+ type: "text",
10006
+ text: mergedText
10007
+ });
10008
+ }
10009
+ inserted = true;
10010
+ }
10011
+ continue;
10012
+ }
10013
+ newParts.push(part);
10014
+ }
10015
+ if (!inserted) {
10016
+ newParts.unshift({
10017
+ id: `${message.info.id}-acp-think`,
10018
+ sessionID: message.info.sessionID,
10019
+ messageID: message.info.id,
10020
+ type: "text",
10021
+ text: mergedText
10022
+ });
10023
+ }
10024
+ message.parts = newParts;
10025
+ normalized++;
10026
+ }
10027
+ return normalized;
10028
+ }
9955
10029
 
9956
10030
  // lib/messages/priority.ts
9957
10031
  function buildPriorityMap(_config, _state, _messages) {
@@ -11329,7 +11403,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
11329
11403
  import { join as join5 } from "path";
11330
11404
  import { existsSync as existsSync5 } from "fs";
11331
11405
  import { homedir as homedir3 } from "os";
11332
- var LOG_VERSION = true ? "1.18.4-pr.480.215" : "dev";
11406
+ var LOG_VERSION = true ? "1.18.4-pr.484.217" : "dev";
11333
11407
  var LEVEL_RANK = {
11334
11408
  debug: 10,
11335
11409
  info: 20,
@@ -13528,6 +13602,14 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
13528
13602
  });
13529
13603
  }
13530
13604
  }
13605
+ if (reasoningConfig?.normalize !== false) {
13606
+ const normalizedThinking = normalizeThinkingForm(output.messages);
13607
+ if (normalizedThinking > 0) {
13608
+ logger.debug("compress.reasoning: pinned thinking wire form", {
13609
+ normalizedMessages: normalizedThinking
13610
+ });
13611
+ }
13612
+ }
13531
13613
  ensureBuiltinFiltersRegistered();
13532
13614
  const effectiveLimit = resolveEffectiveContextLimit(state, config);
13533
13615
  applyMessageFilters(output.messages, config.messageFilters, logger, {
@@ -14039,7 +14121,7 @@ var server = (async (ctx) => {
14039
14121
  }
14040
14122
  const logger = new Logger(config.debug, config.debug ? "debug" : config.logLevel);
14041
14123
  logger.info("ACP plugin initialized", {
14042
- version: true ? "1.18.4-pr.480.215" : "dev",
14124
+ version: true ? "1.18.4-pr.484.217" : "dev",
14043
14125
  workspace: ctx.directory,
14044
14126
  logLevel: logger.level,
14045
14127
  debug: config.debug,