opencode-acp 1.18.4-pr.483.218 → 1.18.4-pr.486.219

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/dist/index.js CHANGED
@@ -921,6 +921,7 @@ var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
921
921
  "compress.images.minBytes",
922
922
  "compress.images.ttlDays",
923
923
  "compress.completionReserveTokens",
924
+ "compress.emergencyTruncation",
924
925
  "gc",
925
926
  "gc.algorithm",
926
927
  "gc.promotionThreshold",
@@ -1350,6 +1351,13 @@ function validateConfigTypes(config) {
1350
1351
  actual: typeof compress.completionReserveTokens
1351
1352
  });
1352
1353
  }
1354
+ if (compress.emergencyTruncation !== void 0 && typeof compress.emergencyTruncation !== "boolean") {
1355
+ errors.push({
1356
+ key: "compress.emergencyTruncation",
1357
+ expected: "boolean",
1358
+ actual: typeof compress.emergencyTruncation
1359
+ });
1360
+ }
1353
1361
  if (typeof compress.completionReserveTokens === "number" && compress.completionReserveTokens < 0) {
1354
1362
  errors.push({
1355
1363
  key: "compress.completionReserveTokens",
@@ -1422,6 +1430,7 @@ function validateConfigTypes(config) {
1422
1430
  const OVERRIDE_FIELD_TYPES = {
1423
1431
  showCompression: "boolean",
1424
1432
  summaryBuffer: "boolean",
1433
+ emergencyTruncation: "boolean",
1425
1434
  protectTags: "boolean",
1426
1435
  protectUserMessages: "boolean",
1427
1436
  lastSegmentSoftBlock: "boolean",
@@ -1809,6 +1818,7 @@ var defaultConfig = {
1809
1818
  permission: "allow",
1810
1819
  showCompression: true,
1811
1820
  summaryBuffer: true,
1821
+ emergencyTruncation: false,
1812
1822
  candidates: false,
1813
1823
  maxContextLimit: "80%",
1814
1824
  minContextLimit: "80%",
@@ -2017,7 +2027,8 @@ function mergeCompress(base, override) {
2017
2027
  minBytes: override.images?.minBytes ?? base.images?.minBytes ?? DEFAULT_COMPRESS_IMAGES.minBytes,
2018
2028
  ttlDays: override.images?.ttlDays ?? base.images?.ttlDays ?? DEFAULT_COMPRESS_IMAGES.ttlDays
2019
2029
  },
2020
- completionReserveTokens: override.completionReserveTokens ?? base.completionReserveTokens
2030
+ completionReserveTokens: override.completionReserveTokens ?? base.completionReserveTokens,
2031
+ emergencyTruncation: override.emergencyTruncation ?? base.emergencyTruncation
2021
2032
  };
2022
2033
  }
2023
2034
  function mergeCommands(base, override) {
@@ -2955,7 +2966,8 @@ function saveSessionState(sessionState, logger, sessionName) {
2955
2966
  modelContextLimit: sessionState.modelContextLimit,
2956
2967
  modelProviderID: sessionState.modelProviderID,
2957
2968
  modelID: sessionState.modelID,
2958
- imageArchive: sessionState.imageArchive
2969
+ imageArchive: sessionState.imageArchive,
2970
+ stickyTruncations: sessionState.stickyTruncations
2959
2971
  };
2960
2972
  const key = saveQueueKey(sessionState.sessionId, sessionState.storageDir);
2961
2973
  let queue = saveQueues.get(key);
@@ -5124,7 +5136,8 @@ function createSessionState() {
5124
5136
  qualityGateRetryPending: false,
5125
5137
  noContextLimitWarned: false,
5126
5138
  imageArchive: {},
5127
- imagePruneDone: false
5139
+ imagePruneDone: false,
5140
+ stickyTruncations: {}
5128
5141
  };
5129
5142
  }
5130
5143
  function resetSessionState(state) {
@@ -5170,6 +5183,7 @@ function resetSessionState(state) {
5170
5183
  state.noContextLimitWarned = false;
5171
5184
  state.imageArchive = {};
5172
5185
  state.imagePruneDone = false;
5186
+ state.stickyTruncations = {};
5173
5187
  }
5174
5188
  async function ensureSessionInitialized(client, state, sessionId, logger, messages, config, projectDir) {
5175
5189
  if (state.sessionId === sessionId) {
@@ -5263,6 +5277,14 @@ async function ensureSessionInitialized(client, state, sessionId, logger, messag
5263
5277
  }
5264
5278
  }
5265
5279
  }
5280
+ const persistedSticky = persisted.stickyTruncations;
5281
+ if (persistedSticky && typeof persistedSticky === "object") {
5282
+ for (const [callID, output] of Object.entries(persistedSticky)) {
5283
+ if (typeof output === "string") {
5284
+ state.stickyTruncations[callID] = output;
5285
+ }
5286
+ }
5287
+ }
5266
5288
  const persistedAny = persisted;
5267
5289
  if (persistedAny._persistedMessageIds) {
5268
5290
  state.messageIds = {
@@ -9953,66 +9975,6 @@ function dropCompressReasoning(messages, threshold) {
9953
9975
  return removed;
9954
9976
  }
9955
9977
 
9956
- // lib/messages/reasoning-canonicalize.ts
9957
- var CANONICAL_OPEN = "<thinking>\n";
9958
- var CANONICAL_CLOSE = "\n</thinking>";
9959
- function canonicalizeReasoningShape(messages) {
9960
- let normalized = 0;
9961
- for (const message of messages) {
9962
- if (!message || message.info.role !== "assistant") {
9963
- continue;
9964
- }
9965
- const parts = Array.isArray(message.parts) ? message.parts : [];
9966
- let allReasoning = "";
9967
- for (const part of parts) {
9968
- if (part.type === "reasoning") {
9969
- allReasoning += part.text;
9970
- }
9971
- }
9972
- if (allReasoning.length === 0) {
9973
- continue;
9974
- }
9975
- let allText = "";
9976
- for (const part of parts) {
9977
- if (part.type === "text") {
9978
- allText += part.text;
9979
- }
9980
- }
9981
- const merged = allText.length > 0 ? `${CANONICAL_OPEN}${allReasoning}${CANONICAL_CLOSE}
9982
- ${allText}` : `${CANONICAL_OPEN}${allReasoning}${CANONICAL_CLOSE}`;
9983
- const rebuilt = [];
9984
- let placed = false;
9985
- const placeMerged = (carrier) => {
9986
- if (placed) {
9987
- return;
9988
- }
9989
- placed = true;
9990
- const part = {
9991
- id: carrier.id,
9992
- sessionID: message.info.sessionID,
9993
- messageID: message.info.id,
9994
- type: "text",
9995
- text: merged
9996
- };
9997
- rebuilt.push(part);
9998
- };
9999
- for (const part of parts) {
10000
- if (part.type === "reasoning") {
10001
- placeMerged(part);
10002
- continue;
10003
- }
10004
- if (part.type === "text") {
10005
- placeMerged(part);
10006
- continue;
10007
- }
10008
- rebuilt.push(part);
10009
- }
10010
- message.parts = rebuilt;
10011
- normalized++;
10012
- }
10013
- return normalized;
10014
- }
10015
-
10016
9978
  // lib/messages/priority.ts
10017
9979
  function buildPriorityMap(_config, _state, _messages) {
10018
9980
  return /* @__PURE__ */ new Map();
@@ -11389,7 +11351,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
11389
11351
  import { join as join5 } from "path";
11390
11352
  import { existsSync as existsSync5 } from "fs";
11391
11353
  import { homedir as homedir3 } from "os";
11392
- var LOG_VERSION = true ? "1.18.4-pr.483.218" : "dev";
11354
+ var LOG_VERSION = true ? "1.18.4-pr.486.219" : "dev";
11393
11355
  var LEVEL_RANK = {
11394
11356
  debug: 10,
11395
11357
  info: 20,
@@ -12284,6 +12246,71 @@ function truncateLargeToolOutputs(state, config, logger, messages) {
12284
12246
  }
12285
12247
  }
12286
12248
 
12249
+ // lib/messages/sticky-truncation.ts
12250
+ function collectToolParts(messages) {
12251
+ const parts = [];
12252
+ for (const message of messages) {
12253
+ const messageParts = Array.isArray(message.parts) ? message.parts : [];
12254
+ for (const part of messageParts) {
12255
+ if (part?.type === "tool") {
12256
+ parts.push(part);
12257
+ }
12258
+ }
12259
+ }
12260
+ return parts;
12261
+ }
12262
+ function applyStickyTruncations(state, messages, logger) {
12263
+ const frozen = state.stickyTruncations;
12264
+ if (Object.keys(frozen).length === 0) return;
12265
+ let replayed = 0;
12266
+ const seen = /* @__PURE__ */ new Set();
12267
+ for (const part of collectToolParts(messages)) {
12268
+ const callID = typeof part.callID === "string" ? part.callID : void 0;
12269
+ if (!callID) continue;
12270
+ seen.add(callID);
12271
+ const recorded = frozen[callID];
12272
+ if (recorded === void 0) continue;
12273
+ if (typeof part.state?.output !== "string" || part.state.output === recorded) continue;
12274
+ part.state.output = recorded;
12275
+ replayed++;
12276
+ }
12277
+ for (const callID of Object.keys(frozen)) {
12278
+ if (!seen.has(callID)) delete frozen[callID];
12279
+ }
12280
+ if (replayed > 0) {
12281
+ logger.debug("Sticky truncation: replayed frozen tool outputs", {
12282
+ replayed,
12283
+ frozen: Object.keys(frozen).length
12284
+ });
12285
+ }
12286
+ }
12287
+ function snapshotToolOutputs(messages) {
12288
+ const snapshot = /* @__PURE__ */ new Map();
12289
+ for (const part of collectToolParts(messages)) {
12290
+ const callID = typeof part.callID === "string" ? part.callID : void 0;
12291
+ if (!callID) continue;
12292
+ if (typeof part.state?.output !== "string") continue;
12293
+ snapshot.set(callID, part.state.output);
12294
+ }
12295
+ return snapshot;
12296
+ }
12297
+ function recordStickyTruncations(state, messages, before, logger) {
12298
+ let recorded = 0;
12299
+ for (const part of collectToolParts(messages)) {
12300
+ const callID = typeof part.callID === "string" ? part.callID : void 0;
12301
+ if (!callID) continue;
12302
+ if (typeof part.state?.output !== "string") continue;
12303
+ const prior = before.get(callID);
12304
+ if (prior === void 0 || prior === part.state.output) continue;
12305
+ if (state.stickyTruncations[callID] === part.state.output) continue;
12306
+ state.stickyTruncations[callID] = part.state.output;
12307
+ recorded++;
12308
+ }
12309
+ if (recorded > 0) {
12310
+ logger.info("Sticky truncation: froze truncated tool outputs", { recorded });
12311
+ }
12312
+ }
12313
+
12287
12314
  // lib/messages/enforce-budget.ts
12288
12315
  var DEFAULT_COMPLETION_RESERVE_TOKENS = 32768;
12289
12316
  var TRUNCATION_MARKER2 = "[truncated for context space";
@@ -13588,12 +13615,6 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
13588
13615
  });
13589
13616
  }
13590
13617
  }
13591
- const canonicalizedReasoning = canonicalizeReasoningShape(output.messages);
13592
- if (canonicalizedReasoning > 0) {
13593
- logger.debug("reasoning-canonicalize: pinned historical thinking shape", {
13594
- messages: canonicalizedReasoning
13595
- });
13596
- }
13597
13618
  ensureBuiltinFiltersRegistered();
13598
13619
  const effectiveLimit = resolveEffectiveContextLimit(state, config);
13599
13620
  applyMessageFilters(output.messages, config.messageFilters, logger, {
@@ -13660,13 +13681,18 @@ ${text}`);
13660
13681
  prePruneTokens,
13661
13682
  candidateMessages
13662
13683
  );
13663
- truncateLargeToolOutputs(
13664
- state,
13665
- config,
13666
- logger,
13667
- output.messages.filter((message) => !isSyntheticMessage(message))
13668
- );
13669
- enforceContextBudget(state, config, logger, output.messages);
13684
+ if (config.compress?.emergencyTruncation === true) {
13685
+ applyStickyTruncations(state, output.messages, logger);
13686
+ const toolOutputsBefore = snapshotToolOutputs(output.messages);
13687
+ truncateLargeToolOutputs(
13688
+ state,
13689
+ config,
13690
+ logger,
13691
+ output.messages.filter((message) => !isSyntheticMessage(message))
13692
+ );
13693
+ enforceContextBudget(state, config, logger, output.messages);
13694
+ recordStickyTruncations(state, output.messages, toolOutputsBefore, logger);
13695
+ }
13670
13696
  injectMessageIds(state, config, output.messages, compressionPriorities);
13671
13697
  hideFailedCompressCalls(output.messages);
13672
13698
  stripStaleMetadata(output.messages);
@@ -14105,7 +14131,7 @@ var server = (async (ctx) => {
14105
14131
  }
14106
14132
  const logger = new Logger(config.debug, config.debug ? "debug" : config.logLevel);
14107
14133
  logger.info("ACP plugin initialized", {
14108
- version: true ? "1.18.4-pr.483.218" : "dev",
14134
+ version: true ? "1.18.4-pr.486.219" : "dev",
14109
14135
  workspace: ctx.directory,
14110
14136
  logLevel: logger.level,
14111
14137
  debug: config.debug,