opencode-acp 1.16.0-pr.349.122 → 1.16.0-pr.360.124

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
@@ -890,7 +890,6 @@ var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
890
890
  "compress.modelMaxLimits",
891
891
  "compress.modelMinLimits",
892
892
  "compress.providers",
893
- "compress.contextLimitFallback",
894
893
  "compress.nudgeFrequency",
895
894
  "compress.minNudgeContextPercent",
896
895
  "compress.nudgeGrowthTokens",
@@ -1522,20 +1521,6 @@ function validateConfigTypes(config) {
1522
1521
  }
1523
1522
  };
1524
1523
  validateProviderOverrides(compress.providers);
1525
- if (compress.contextLimitFallback !== void 0 && typeof compress.contextLimitFallback !== "number") {
1526
- errors.push({
1527
- key: "compress.contextLimitFallback",
1528
- expected: "number",
1529
- actual: typeof compress.contextLimitFallback
1530
- });
1531
- }
1532
- if (typeof compress.contextLimitFallback === "number" && compress.contextLimitFallback < 0) {
1533
- errors.push({
1534
- key: "compress.contextLimitFallback",
1535
- expected: "non-negative number (0 disables the fallback)",
1536
- actual: `${compress.contextLimitFallback}`
1537
- });
1538
- }
1539
1524
  const validValues = ["ask", "allow", "deny"];
1540
1525
  if (compress.permission !== void 0 && !validValues.includes(compress.permission)) {
1541
1526
  errors.push({
@@ -1717,7 +1702,6 @@ var defaultConfig = {
1717
1702
  summaryBuffer: true,
1718
1703
  maxContextLimit: "80%",
1719
1704
  minContextLimit: "80%",
1720
- contextLimitFallback: 128e3,
1721
1705
  nudgeFrequency: 5,
1722
1706
  minNudgeContextPercent: 5,
1723
1707
  iterationNudgeThreshold: 15,
@@ -1888,7 +1872,6 @@ function mergeCompress(base, override) {
1888
1872
  modelMaxLimits: override.modelMaxLimits ?? base.modelMaxLimits,
1889
1873
  modelMinLimits: override.modelMinLimits ?? base.modelMinLimits,
1890
1874
  providers: mergeProviderOverrides(base.providers, override.providers),
1891
- contextLimitFallback: override.contextLimitFallback ?? base.contextLimitFallback,
1892
1875
  nudgeFrequency: override.nudgeFrequency ?? base.nudgeFrequency,
1893
1876
  minNudgeContextPercent: override.minNudgeContextPercent ?? base.minNudgeContextPercent,
1894
1877
  nudgeGrowthTokens: override.nudgeGrowthTokens,
@@ -2652,16 +2635,6 @@ function resetOnCompaction(state) {
2652
2635
  nextRef: 1
2653
2636
  };
2654
2637
  }
2655
- function resolveEffectiveContextLimit(state, config) {
2656
- if (typeof state.modelContextLimit === "number" && state.modelContextLimit > 0) {
2657
- return { limit: state.modelContextLimit, source: "model" };
2658
- }
2659
- const fallback = config.compress.contextLimitFallback;
2660
- if (typeof fallback === "number" && fallback > 0) {
2661
- return { limit: fallback, source: "fallback" };
2662
- }
2663
- return void 0;
2664
- }
2665
2638
 
2666
2639
  // lib/state/persistence.ts
2667
2640
  function getDefaultStorageDir() {
@@ -4533,24 +4506,6 @@ var SessionStateRegistry = class {
4533
4506
  hydrateModelLimitsFromClient(client) {
4534
4507
  return this.catalog.hydrateFromClient(client);
4535
4508
  }
4536
- // [FIX #346] The init-time seed (above) is fire-and-forget and races
4537
- // server readiness: in headless spawn+resume mode the provider-config
4538
- // call can fail before the server is up, leaving the catalog empty for
4539
- // the process's lifetime. During a request the server is guaranteed up
4540
- // (we are inside its pipeline), so on a catalog miss we retry hydration
4541
- // once per process before giving up (the fallback limit then applies).
4542
- // The in-flight promise (not a boolean) lets concurrent callers await the
4543
- // same hydration instead of skipping it.
4544
- lazyHydration;
4545
- async hydrateAndResolve(client, providerId, modelId) {
4546
- const existing = this.catalog.resolve(providerId, modelId);
4547
- if (existing !== void 0) {
4548
- return existing;
4549
- }
4550
- this.lazyHydration ??= this.catalog.hydrateFromClient(client);
4551
- await this.lazyHydration;
4552
- return this.catalog.resolve(providerId, modelId);
4553
- }
4554
4509
  get(sessionId) {
4555
4510
  return this.states.get(sessionId);
4556
4511
  }
@@ -6702,7 +6657,6 @@ function getModelInfo(messages) {
6702
6657
  };
6703
6658
  }
6704
6659
  function resolveContextTokenLimit(config, state, providerId, modelId, threshold) {
6705
- const effectiveLimit = resolveEffectiveContextLimit(state, config);
6706
6660
  const parseLimitValue = (limit) => {
6707
6661
  if (limit === void 0) {
6708
6662
  return void 0;
@@ -6710,7 +6664,7 @@ function resolveContextTokenLimit(config, state, providerId, modelId, threshold)
6710
6664
  if (typeof limit === "number") {
6711
6665
  return limit;
6712
6666
  }
6713
- if (!limit.endsWith("%") || effectiveLimit === void 0) {
6667
+ if (!limit.endsWith("%") || state.modelContextLimit === void 0) {
6714
6668
  return void 0;
6715
6669
  }
6716
6670
  const parsedPercent = parseFloat(limit.slice(0, -1));
@@ -6719,7 +6673,7 @@ function resolveContextTokenLimit(config, state, providerId, modelId, threshold)
6719
6673
  }
6720
6674
  const roundedPercent = Math.round(parsedPercent);
6721
6675
  const clampedPercent = Math.max(0, Math.min(100, roundedPercent));
6722
- return Math.round(clampedPercent / 100 * effectiveLimit.limit);
6676
+ return Math.round(clampedPercent / 100 * state.modelContextLimit);
6723
6677
  };
6724
6678
  if (threshold === "max") {
6725
6679
  const nestedLimit = resolveCompressOverrides(config, providerId, modelId).maxContextLimit;
@@ -6770,12 +6724,11 @@ function isContextOverLimits(config, state, providerId, modelId, messages) {
6770
6724
  if (!overMaxLimit) break;
6771
6725
  }
6772
6726
  }
6773
- const effectiveLimit = resolveEffectiveContextLimit(state, config);
6774
6727
  return {
6775
6728
  overMaxLimit,
6776
6729
  overMinLimit,
6777
6730
  currentTokens,
6778
- modelContextLimit: effectiveLimit?.limit
6731
+ modelContextLimit: state.modelContextLimit
6779
6732
  };
6780
6733
  }
6781
6734
  ensureBuiltinTriggerPolicyRegistered();
@@ -7081,13 +7034,10 @@ function buildCompressibleRanges(messages, state, protectedTools = [], protected
7081
7034
  if (!ref) continue;
7082
7035
  const rn = parseInt(ref.slice(1), 10);
7083
7036
  if ((protectedTools.length > 0 || protectedFilePatterns.length > 0) && messageContainsProtectedTool(msg, protectedTools, protectedFilePatterns)) {
7084
- let tokens2 = 0;
7037
+ const tokens2 = Math.round(countMessageCharacters(msg) / 4);
7085
7038
  const tools = /* @__PURE__ */ new Set();
7086
7039
  for (const part of msg.parts || []) {
7087
- if (part.type === "text" && typeof part.text === "string") {
7088
- tokens2 += Math.round(part.text.length / 4);
7089
- } else if (part.type !== "text" && part.type !== "reasoning") {
7090
- tokens2 += Math.round(JSON.stringify(part).length / 4);
7040
+ if (part.type !== "text" && part.type !== "reasoning") {
7091
7041
  const toolName = part?.tool;
7092
7042
  const callID = part?.callID;
7093
7043
  if (toolName && callID) {
@@ -7108,15 +7058,13 @@ function buildCompressibleRanges(messages, state, protectedTools = [], protected
7108
7058
  protectedMsgInfo.push({ ref, refNum: rn, tokens: tokens2, tools: [...tools] });
7109
7059
  continue;
7110
7060
  }
7111
- let tokens = 0;
7061
+ const tokens = Math.round(countMessageCharacters(msg) / 4);
7112
7062
  let isTool = false;
7113
7063
  let hasMeaningfulPart = false;
7114
7064
  for (const part of msg.parts || []) {
7115
7065
  if (part.type === "text" && typeof part.text === "string") {
7116
- tokens += Math.round(part.text.length / 4);
7117
7066
  if (part.text.trim().length > 0) hasMeaningfulPart = true;
7118
7067
  } else if (part.type !== "text" && part.type !== "reasoning") {
7119
- tokens += Math.round(JSON.stringify(part).length / 4);
7120
7068
  isTool = true;
7121
7069
  hasMeaningfulPart = true;
7122
7070
  }
@@ -8854,9 +8802,8 @@ function createDecompressTool(factoryCtx) {
8854
8802
  async execute(args, toolCtx) {
8855
8803
  const ctx = resolveToolContext(factoryCtx, toolCtx.sessionID);
8856
8804
  const { rawMessages } = await prepareDecompressSession(ctx, toolCtx);
8857
- const effectiveLimitBefore = resolveEffectiveContextLimit(ctx.state, ctx.config);
8858
- const contextUsageBefore = effectiveLimitBefore ? Math.round(
8859
- getCurrentTokenUsage(ctx.state, rawMessages) / effectiveLimitBefore.limit * 100
8805
+ const contextUsageBefore = ctx.state.modelContextLimit ? Math.round(
8806
+ getCurrentTokenUsage(ctx.state, rawMessages) / ctx.state.modelContextLimit * 100
8860
8807
  ) : void 0;
8861
8808
  const resolved = resolveTargets(args, ctx.state, rawMessages, ctx.logger);
8862
8809
  if (!resolved.ok) {
@@ -8920,9 +8867,8 @@ function createDecompressTool(factoryCtx) {
8920
8867
  0,
8921
8868
  ctx.state.stats.totalPruneTokens - restoredTokens
8922
8869
  );
8923
- const effectiveLimitAfter = resolveEffectiveContextLimit(ctx.state, ctx.config);
8924
- const contextUsageAfter = effectiveLimitAfter ? Math.round(
8925
- getCurrentTokenUsage(ctx.state, rawMessages) / effectiveLimitAfter.limit * 100
8870
+ const contextUsageAfter = ctx.state.modelContextLimit ? Math.round(
8871
+ getCurrentTokenUsage(ctx.state, rawMessages) / ctx.state.modelContextLimit * 100
8926
8872
  ) : void 0;
8927
8873
  await finalizeDecompressSession(ctx);
8928
8874
  const restoredContentPreview = buildRestoredContentPreview(
@@ -9579,7 +9525,7 @@ import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
9579
9525
  import { join as join4 } from "path";
9580
9526
  import { existsSync as existsSync4 } from "fs";
9581
9527
  import { homedir as homedir3 } from "os";
9582
- var LOG_VERSION = true ? "1.16.0-pr.349.122" : "dev";
9528
+ var LOG_VERSION = true ? "1.16.0-pr.360.124" : "dev";
9583
9529
  var LEVEL_RANK = {
9584
9530
  debug: 10,
9585
9531
  info: 20,
@@ -10403,8 +10349,6 @@ var MIN_OUTPUT_TOKENS = 1e3;
10403
10349
  var KEEP_PREFIX_CHARS = 2e3;
10404
10350
  var KEEP_SUFFIX_CHARS = 2e3;
10405
10351
  var PROTECT_RECENT_MESSAGES = 3;
10406
- var OUTPUT_RESERVE_TOKENS = 16384;
10407
- var overheadErrorLogged = /* @__PURE__ */ new Set();
10408
10352
  function parseGcThreshold(threshold, modelContextLimit) {
10409
10353
  if (typeof threshold === "number") return threshold;
10410
10354
  const str = threshold ?? "100%";
@@ -10413,26 +10357,10 @@ function parseGcThreshold(threshold, modelContextLimit) {
10413
10357
  return modelContextLimit;
10414
10358
  }
10415
10359
  function truncateLargeToolOutputs(state, config, logger, messages) {
10416
- const effective = resolveEffectiveContextLimit(state, config);
10417
- if (!effective) return;
10360
+ if (!state.modelContextLimit) return;
10418
10361
  const currentTokens = getCurrentTokenUsage(state, messages);
10419
10362
  if (currentTokens === 0) return;
10420
- const configuredThreshold = parseGcThreshold(config.gc?.majorGcThresholdPercent, effective.limit);
10421
- const overhead = (state.systemPromptTokens ?? 0) + OUTPUT_RESERVE_TOKENS;
10422
- const threshold = Math.min(configuredThreshold, effective.limit - overhead);
10423
- if (threshold <= 0) {
10424
- const sessionKey = state.sessionId ?? "unknown";
10425
- if (!overheadErrorLogged.has(sessionKey)) {
10426
- overheadErrorLogged.add(sessionKey);
10427
- logger.error("ACP: model context window too small to fit overhead", {
10428
- session: state.sessionId,
10429
- limit: effective.limit,
10430
- contextLimitSource: effective.source,
10431
- overhead
10432
- });
10433
- }
10434
- return;
10435
- }
10363
+ const threshold = parseGcThreshold(config.gc?.majorGcThresholdPercent, state.modelContextLimit);
10436
10364
  if (currentTokens < threshold) return;
10437
10365
  const protectedIndex = messages.length - PROTECT_RECENT_MESSAGES;
10438
10366
  const candidates = [];
@@ -10477,9 +10405,7 @@ function truncateLargeToolOutputs(state, config, logger, messages) {
10477
10405
  truncatedCount,
10478
10406
  estimatedSavedTokens: Math.round(savedTokens),
10479
10407
  currentTokens,
10480
- threshold,
10481
- contextLimit: effective.limit,
10482
- contextLimitSource: effective.source
10408
+ threshold
10483
10409
  });
10484
10410
  }
10485
10411
  }
@@ -11440,12 +11366,11 @@ function runBatchCleanup(state, config, logger, messages) {
11440
11366
  mergedCount: 0,
11441
11367
  savedTokens: 0
11442
11368
  };
11443
- const effective = resolveEffectiveContextLimit(state, config);
11444
- if (!effective) {
11369
+ if (!state.modelContextLimit || state.modelContextLimit <= 0) {
11445
11370
  return noop;
11446
11371
  }
11447
11372
  const currentTokens = getCurrentTokenUsage(state, messages);
11448
- if (currentTokens < effective.limit) {
11373
+ if (currentTokens < state.modelContextLimit) {
11449
11374
  return noop;
11450
11375
  }
11451
11376
  const maxMergedLength = config.gc.maxOldGenSummaryLength;
@@ -11462,8 +11387,7 @@ function runBatchCleanup(state, config, logger, messages) {
11462
11387
  mergedCount: result.mergedCount,
11463
11388
  savedTokens: result.savedTokens,
11464
11389
  currentTokens,
11465
- contextLimit: effective.limit,
11466
- contextLimitSource: effective.source
11390
+ contextLimit: state.modelContextLimit
11467
11391
  });
11468
11392
  return {
11469
11393
  tier: 3,
@@ -11497,6 +11421,11 @@ function createSystemPromptHandler(registry4, logger, config, prompts) {
11497
11421
  input.model?.limit?.context
11498
11422
  );
11499
11423
  const state = input.sessionID ? registry4.get(input.sessionID) : void 0;
11424
+ if (state && input.model?.limit?.context) {
11425
+ state.modelContextLimit = input.model.limit.context;
11426
+ state.modelProviderID = input.model?.providerID;
11427
+ state.modelID = input.model?.id;
11428
+ }
11500
11429
  if (!state || state.isSubAgent && !config.allowSubAgents) {
11501
11430
  return;
11502
11431
  }
@@ -11505,23 +11434,6 @@ function createSystemPromptHandler(registry4, logger, config, prompts) {
11505
11434
  logger.info("Skipping DCP system prompt injection for internal agent");
11506
11435
  return;
11507
11436
  }
11508
- if (input.model?.limit?.context) {
11509
- const limit = input.model.limit.context;
11510
- const providerID = input.model?.providerID;
11511
- const modelID = input.model?.id;
11512
- const changed = state.modelContextLimit !== limit || providerID !== void 0 && state.modelProviderID !== providerID || modelID !== void 0 && state.modelID !== modelID;
11513
- state.modelContextLimit = limit;
11514
- if (providerID !== void 0) {
11515
- state.modelProviderID = providerID;
11516
- }
11517
- if (modelID !== void 0) {
11518
- state.modelID = modelID;
11519
- }
11520
- if (changed) {
11521
- saveSessionState(state, logger).catch(() => {
11522
- });
11523
- }
11524
- }
11525
11437
  const effectivePermission = compressPermission(state, config);
11526
11438
  if (effectivePermission === "deny") {
11527
11439
  return;
@@ -11566,17 +11478,10 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
11566
11478
  config
11567
11479
  );
11568
11480
  const requestModel = lastUserMessage.info.model;
11569
- let requestModelLimit = registry4.resolveModelLimit(
11481
+ const requestModelLimit = registry4.resolveModelLimit(
11570
11482
  requestModel?.providerID,
11571
11483
  requestModel?.modelID
11572
11484
  );
11573
- if (requestModelLimit === void 0 && requestModel?.providerID && requestModel?.modelID) {
11574
- requestModelLimit = await registry4.hydrateAndResolve(
11575
- client,
11576
- requestModel.providerID,
11577
- requestModel.modelID
11578
- );
11579
- }
11580
11485
  const prevModelID = state.modelID;
11581
11486
  if (requestModelLimit !== void 0) {
11582
11487
  state.modelContextLimit = requestModelLimit;
@@ -11631,11 +11536,10 @@ function createChatMessageTransformHandler(client, registry4, logger, config, pr
11631
11536
  }
11632
11537
  }
11633
11538
  ensureBuiltinFiltersRegistered();
11634
- const effectiveLimit = resolveEffectiveContextLimit(state, config);
11635
11539
  applyMessageFilters(output.messages, config.messageFilters, logger, {
11636
11540
  sessionId: state.sessionId ?? "",
11637
11541
  isSubAgent: state.isSubAgent,
11638
- modelContextLimit: effectiveLimit?.limit
11542
+ modelContextLimit: state.modelContextLimit
11639
11543
  });
11640
11544
  cacheSystemPromptTokens(state, output.messages);
11641
11545
  assignMessageRefs(state, output.messages);
@@ -11686,31 +11590,14 @@ ${text}`);
11686
11590
  stripStaleMetadata(output.messages);
11687
11591
  dropEmptyMessages(output.messages);
11688
11592
  const postTokens = getCurrentTokenUsage(state, output.messages);
11689
- if (postTokens !== void 0 && effectiveLimit) {
11690
- const budget = effectiveLimit.limit - (state.systemPromptTokens ?? 0) - OUTPUT_RESERVE_TOKENS;
11691
- if (postTokens > budget) {
11692
- logger.error(
11693
- "ACP hard guard: context exceeds model budget after in-flight reduction",
11694
- {
11695
- session: state.sessionId,
11696
- postTokens,
11697
- budget,
11698
- contextLimit: effectiveLimit.limit,
11699
- contextLimitSource: effectiveLimit.source,
11700
- hint: "request will likely be rejected; run /compact or start a new session"
11701
- }
11702
- );
11703
- }
11704
- }
11705
11593
  logger.info("Chat transform complete", {
11706
11594
  session: state.sessionId,
11707
11595
  model: state.modelID,
11708
11596
  messages: output.messages.length,
11709
11597
  prePruneTokens,
11710
11598
  postTokens,
11711
- contextLimit: effectiveLimit?.limit,
11712
- contextLimitSource: effectiveLimit?.source,
11713
- usagePct: postTokens !== void 0 && effectiveLimit ? `${(postTokens / effectiveLimit.limit * 100).toFixed(1)}%` : void 0,
11599
+ contextLimit: state.modelContextLimit,
11600
+ usagePct: postTokens !== void 0 && state.modelContextLimit ? `${(postTokens / state.modelContextLimit * 100).toFixed(1)}%` : void 0,
11714
11601
  nudged: state.nudges.shouldInjectThisTurn
11715
11602
  });
11716
11603
  if (state.sessionId) {
@@ -12129,7 +12016,7 @@ var server = (async (ctx) => {
12129
12016
  }
12130
12017
  const logger = new Logger(config.debug, config.debug ? "debug" : config.logLevel);
12131
12018
  logger.info("ACP plugin initialized", {
12132
- version: true ? "1.16.0-pr.349.122" : "dev",
12019
+ version: true ? "1.16.0-pr.360.124" : "dev",
12133
12020
  workspace: ctx.directory,
12134
12021
  logLevel: logger.level,
12135
12022
  debug: config.debug,