opencode-acp 1.18.3-pr.475.210 → 1.18.3-pr.477.211

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
@@ -2908,7 +2908,8 @@ function saveSessionState(sessionState, logger, sessionName) {
2908
2908
  lastCompaction: sessionState.lastCompaction,
2909
2909
  modelContextLimit: sessionState.modelContextLimit,
2910
2910
  modelProviderID: sessionState.modelProviderID,
2911
- modelID: sessionState.modelID
2911
+ modelID: sessionState.modelID,
2912
+ usageSanity: sessionState.usageSanity
2912
2913
  };
2913
2914
  const key = saveQueueKey(sessionState.sessionId, sessionState.storageDir);
2914
2915
  let queue = saveQueues.get(key);
@@ -3763,18 +3764,32 @@ function adjustBoundariesForToolPairs(context, startIdx, endIdx) {
3763
3764
  return { startIndex: newStartIdx, endIndex: newEndIdx };
3764
3765
  }
3765
3766
  function buildBoundaryRecoveryHint(context, state) {
3766
- const visibleRefs = [];
3767
+ const visibleIndexes = [];
3767
3768
  for (const [messageRef, messageId] of state.messageIds.byRef) {
3768
- if (context.rawMessagesById.has(messageId)) {
3769
- visibleRefs.push(messageRef);
3770
- }
3769
+ if (!context.rawMessagesById.has(messageId)) continue;
3770
+ const idx = parseMessageRef(messageRef);
3771
+ if (idx !== null) visibleIndexes.push(idx);
3771
3772
  }
3773
+ visibleIndexes.sort((a, b) => a - b);
3774
+ const renderSpan = (start, end) => start === end ? formatMessageRef(start) : `${formatMessageRef(start)}\u2013${formatMessageRef(end)}`;
3772
3775
  const parts = [];
3773
- if (visibleRefs.length > 0) {
3774
- visibleRefs.sort();
3775
- const first = visibleRefs[0];
3776
- const last = visibleRefs[visibleRefs.length - 1];
3777
- parts.push(`Current visible: ${first}\u2013${last} (${visibleRefs.length} msgs).`);
3776
+ if (visibleIndexes.length > 0) {
3777
+ const spans = [];
3778
+ let spanStart = visibleIndexes[0];
3779
+ let spanPrev = visibleIndexes[0];
3780
+ for (let i = 1; i < visibleIndexes.length; i++) {
3781
+ const idx = visibleIndexes[i];
3782
+ if (idx !== spanPrev + 1) {
3783
+ spans.push(renderSpan(spanStart, spanPrev));
3784
+ spanStart = idx;
3785
+ }
3786
+ spanPrev = idx;
3787
+ }
3788
+ spans.push(renderSpan(spanStart, spanPrev));
3789
+ const MAX_SPANS = 8;
3790
+ const shown = spans.slice(0, MAX_SPANS);
3791
+ const overflow = spans.length - shown.length;
3792
+ parts.push(`Free ranges: ${shown.join(", ")}${overflow > 0 ? ` (+${overflow} more)` : ""}.`);
3778
3793
  }
3779
3794
  const blockCount = context.summaryByBlockId.size;
3780
3795
  if (blockCount > 0) {
@@ -3783,7 +3798,7 @@ function buildBoundaryRecoveryHint(context, state) {
3783
3798
  if (parts.length === 0) {
3784
3799
  return "";
3785
3800
  }
3786
- return `${parts.join(" ")} Call acp_status() to see which blocks consumed which IDs, then retry with valid IDs.`;
3801
+ return `${parts.join(" ")} Retry with IDs inside the free ranges.`;
3787
3802
  }
3788
3803
  function clampMessageRef(requested, context, state) {
3789
3804
  if (state.messageIds.byRef.has(requested.ref)) return null;
@@ -5232,6 +5247,14 @@ async function ensureSessionInitialized(client, state, sessionId, logger, messag
5232
5247
  state.modelProviderID = persisted.modelProviderID;
5233
5248
  state.modelID = persisted.modelID;
5234
5249
  }
5250
+ if (persisted.usageSanity) {
5251
+ const { reported, estimated } = persisted.usageSanity;
5252
+ if (Number.isFinite(reported) && Number.isFinite(estimated) && reported >= 0 && estimated >= 0) {
5253
+ state.usageSanity = { reported, estimated };
5254
+ } else {
5255
+ state.usageSanity = void 0;
5256
+ }
5257
+ }
5235
5258
  const applied = applyPendingCompressionDurations(state);
5236
5259
  if (applied > 0) {
5237
5260
  await saveSessionState(state, logger);
@@ -6784,6 +6807,49 @@ ${guidance}
6784
6807
  ${afterClose}`;
6785
6808
  }
6786
6809
 
6810
+ // lib/usage-sanity.ts
6811
+ var RELAY_INFLATION_RATIO = 1.5;
6812
+ var PAYLOAD_FLOOR_TOKENS = 5e3;
6813
+ function estimatePayloadTokens(messages) {
6814
+ let total = 0;
6815
+ for (const msg of messages) {
6816
+ if (isSyntheticMessage(msg)) continue;
6817
+ if (isIgnoredUserMessage(msg)) continue;
6818
+ total += estimateAllMessageTokensFast(msg);
6819
+ }
6820
+ return total;
6821
+ }
6822
+ function resolveCurrentUsage(state, messages, logger) {
6823
+ const reported = getCurrentTokenUsage(state, messages);
6824
+ if (reported === 0) {
6825
+ return { tokens: 0, source: "reported", inflationDetected: false };
6826
+ }
6827
+ const estimated = estimatePayloadTokens(messages) + (state.systemPromptTokens ?? 0);
6828
+ const prev = state.usageSanity;
6829
+ let inflationDetected = false;
6830
+ if (prev !== void 0 && prev.reported > 0 && prev.estimated >= PAYLOAD_FLOOR_TOKENS && estimated >= PAYLOAD_FLOOR_TOKENS) {
6831
+ const reportRatio = reported / prev.reported;
6832
+ const payloadRatio = estimated / prev.estimated;
6833
+ if (reportRatio > RELAY_INFLATION_RATIO && payloadRatio <= RELAY_INFLATION_RATIO) {
6834
+ inflationDetected = true;
6835
+ }
6836
+ }
6837
+ state.usageSanity = { reported, estimated };
6838
+ if (inflationDetected) {
6839
+ logger?.warn("Relay usage inflation detected \u2014 re-estimating context size", {
6840
+ session: state.sessionId,
6841
+ reported,
6842
+ previousReported: prev.reported,
6843
+ reportRatio: +(reported / prev.reported).toFixed(3),
6844
+ estimated,
6845
+ previousEstimated: prev.estimated,
6846
+ payloadRatio: +(estimated / prev.estimated).toFixed(3)
6847
+ });
6848
+ return { tokens: estimated, source: "reestimated", inflationDetected: true };
6849
+ }
6850
+ return { tokens: reported, source: "reported", inflationDetected: false };
6851
+ }
6852
+
6787
6853
  // lib/messages/utils.ts
6788
6854
  import { createHash as createHash2 } from "crypto";
6789
6855
  var SUMMARY_ID_HASH_LENGTH = 16;
@@ -7134,7 +7200,7 @@ function isContextOverLimits(config, state, providerId, modelId, messages) {
7134
7200
  );
7135
7201
  const maxContextLimit = resolvedMaxContextLimit === void 0 ? void 0 : resolvedMaxContextLimit + summaryTokenExtension;
7136
7202
  const minContextLimit = resolveContextTokenLimit(config, state, providerId, modelId, "min");
7137
- const currentTokens = getCurrentTokenUsage(state, messages);
7203
+ const currentTokens = resolveCurrentUsage(state, messages).tokens;
7138
7204
  let overMaxLimit = maxContextLimit === void 0 ? false : currentTokens > maxContextLimit;
7139
7205
  const overMinLimit = minContextLimit === void 0 ? false : currentTokens >= minContextLimit;
7140
7206
  if (overMaxLimit) {
@@ -9286,7 +9352,8 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
9286
9352
  const allInProtectedZone = protectedRefs.size > 0 && unprotectedCompressible.length === 0;
9287
9353
  const allBelowMin = contextRanges.compressible.length > 0 && recommendedRanges.length === 0;
9288
9354
  const noExecutableCandidates = candidatesEnabled && nudgeAllowed && candidateMessages !== void 0 && candidatePlan.candidates.length === 0;
9289
- const nothingToCompress = candidatesEnabled && candidateMessages !== void 0 ? noExecutableCandidates : allProtected || allInProtectedZone || allBelowMin;
9355
+ const noRangesAtAll = contextRanges.compressible.length === 0 && contextRanges.protected.length === 0;
9356
+ const nothingToCompress = (candidatesEnabled && candidateMessages !== void 0 ? noExecutableCandidates : allProtected || allInProtectedZone || allBelowMin) || noRangesAtAll;
9290
9357
  const emergencyNoTargets = emergencyOverride && nothingToCompress;
9291
9358
  const noticeCadenceMet = state.nudges.lastNudgeShownTokens === void 0 || growthSinceBaseline !== void 0 && growthSinceBaseline >= growthFloor;
9292
9359
  let shouldInjectNudge = nudgeAllowed && !nothingToCompress;
@@ -9491,7 +9558,7 @@ ${rules}`;
9491
9558
  } else if (nudgeAllowed && nothingToCompress) {
9492
9559
  logger.info("Nudge suppressed: nothing to compress", {
9493
9560
  session: state.sessionId,
9494
- reason: allProtected ? "all_protected" : allInProtectedZone ? "in_protected_zone" : allBelowMin ? "below_effective_floor" : "no_executable_candidates",
9561
+ reason: allProtected ? "all_protected" : allInProtectedZone ? "in_protected_zone" : allBelowMin ? "below_effective_floor" : noRangesAtAll ? "no_compressible_ranges" : "no_executable_candidates",
9495
9562
  currentTokens,
9496
9563
  usagePct,
9497
9564
  compressibleRanges: contextRanges.compressible.length
@@ -11109,7 +11176,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
11109
11176
  import { join as join4 } from "path";
11110
11177
  import { existsSync as existsSync4 } from "fs";
11111
11178
  import { homedir as homedir3 } from "os";
11112
- var LOG_VERSION = true ? "1.18.3-pr.475.210" : "dev";
11179
+ var LOG_VERSION = true ? "1.18.3-pr.477.211" : "dev";
11113
11180
  var LEVEL_RANK = {
11114
11181
  debug: 10,
11115
11182
  info: 20,
@@ -13330,7 +13397,7 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
13330
13397
  saveSessionState(state, logger).catch(() => {
13331
13398
  });
13332
13399
  }
13333
- const prePruneTokens = getCurrentTokenUsage(state, output.messages);
13400
+ const prePruneTokens = resolveCurrentUsage(state, output.messages, logger).tokens;
13334
13401
  const candidateMessages = config.compress.candidates === true ? output.messages.slice() : void 0;
13335
13402
  prune(state, logger, config, output.messages);
13336
13403
  hideConsumedCompressCalls(state, output.messages);
@@ -13379,7 +13446,7 @@ ${text}`);
13379
13446
  if (state.sessionId && smartPlanEnabled === true) {
13380
13447
  recordVisibleMessages(state.sessionId, output.messages);
13381
13448
  }
13382
- const postTokens = getCurrentTokenUsage(state, output.messages);
13449
+ const postTokens = resolveCurrentUsage(state, output.messages, logger).tokens;
13383
13450
  if (postTokens !== void 0 && effectiveLimit) {
13384
13451
  const budget = effectiveLimit.limit - (state.systemPromptTokens ?? 0) - OUTPUT_RESERVE_TOKENS;
13385
13452
  if (postTokens > budget) {
@@ -13805,7 +13872,7 @@ var server = (async (ctx) => {
13805
13872
  }
13806
13873
  const logger = new Logger(config.debug, config.debug ? "debug" : config.logLevel);
13807
13874
  logger.info("ACP plugin initialized", {
13808
- version: true ? "1.18.3-pr.475.210" : "dev",
13875
+ version: true ? "1.18.3-pr.477.211" : "dev",
13809
13876
  workspace: ctx.directory,
13810
13877
  logLevel: logger.level,
13811
13878
  debug: config.debug,