opencode-acp 1.12.10 → 1.13.2

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.
Files changed (32) hide show
  1. package/NOTICE +29 -0
  2. package/README.md +123 -37
  3. package/README.zh-CN.md +100 -20
  4. package/dist/index.js +917 -54
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/compress/pipeline.d.ts.map +1 -1
  7. package/dist/lib/compress/quality-gate/algorithms/index.d.ts +3 -0
  8. package/dist/lib/compress/quality-gate/algorithms/index.d.ts.map +1 -0
  9. package/dist/lib/compress/quality-gate/evaluate.d.ts +8 -0
  10. package/dist/lib/compress/quality-gate/evaluate.d.ts.map +1 -0
  11. package/dist/lib/compress/quality-gate/index.d.ts +5 -0
  12. package/dist/lib/compress/quality-gate/index.d.ts.map +1 -0
  13. package/dist/lib/compress/quality-gate/registry.d.ts +6 -0
  14. package/dist/lib/compress/quality-gate/registry.d.ts.map +1 -0
  15. package/dist/lib/compress/quality-gate/types.d.ts +51 -0
  16. package/dist/lib/compress/quality-gate/types.d.ts.map +1 -0
  17. package/dist/lib/config-validation.d.ts.map +1 -1
  18. package/dist/lib/config.d.ts +9 -0
  19. package/dist/lib/config.d.ts.map +1 -1
  20. package/dist/lib/messages/inject/policy/index.d.ts +5 -0
  21. package/dist/lib/messages/inject/policy/index.d.ts.map +1 -0
  22. package/dist/lib/messages/inject/policy/registry.d.ts +8 -0
  23. package/dist/lib/messages/inject/policy/registry.d.ts.map +1 -0
  24. package/dist/lib/messages/inject/policy/types.d.ts +2 -0
  25. package/dist/lib/messages/inject/policy/types.d.ts.map +1 -0
  26. package/dist/lib/messages/inject/utils.d.ts +0 -9
  27. package/dist/lib/messages/inject/utils.d.ts.map +1 -1
  28. package/dist/lib/messages/utils.d.ts.map +1 -1
  29. package/dist/lib/ui/notification.d.ts.map +1 -1
  30. package/package.json +5 -2
  31. package/dist/lib/prompts/compression-rules.d.ts +0 -20
  32. package/dist/lib/prompts/compression-rules.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -926,7 +926,11 @@ var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
926
926
  "strategies.purgeErrors",
927
927
  "strategies.purgeErrors.enabled",
928
928
  "strategies.purgeErrors.turns",
929
- "strategies.purgeErrors.protectedTools"
929
+ "strategies.purgeErrors.protectedTools",
930
+ "qualityGate",
931
+ "qualityGate.enabled",
932
+ "qualityGate.algorithm",
933
+ "qualityGate.algorithms"
930
934
  ]);
931
935
  function getConfigKeyPaths(obj, prefix = "") {
932
936
  const keys = [];
@@ -1553,8 +1557,11 @@ var defaultConfig = {
1553
1557
  enabled: true,
1554
1558
  autoUpdate: true,
1555
1559
  debug: false,
1556
- pruneNotification: "detailed",
1557
- pruneNotificationType: "chat",
1560
+ pruneNotification: "off",
1561
+ // [FIX #20] Default to toast — chat-mode notifications inject an empty
1562
+ // user message that freezes the session on providers that reject empty
1563
+ // messages (zhipuai-lb code 1214). See lib/ui/notification.ts.
1564
+ pruneNotificationType: "toast",
1558
1565
  commands: {
1559
1566
  enabled: true,
1560
1567
  protectedTools: [...DEFAULT_PROTECTED_TOOLS]
@@ -1586,7 +1593,7 @@ var defaultConfig = {
1586
1593
  protectedTools: [...COMPRESS_DEFAULT_PROTECTED_TOOLS],
1587
1594
  protectTags: false,
1588
1595
  protectUserMessages: false,
1589
- maxSummaryLengthHard: 1e4,
1596
+ maxSummaryLengthHard: 2e4,
1590
1597
  minCompressRange: 5e3,
1591
1598
  minNudgeGrowthRatio: 0.45,
1592
1599
  minNudgeGrowthFloor: 5e3,
@@ -1618,6 +1625,18 @@ var defaultConfig = {
1618
1625
  highThreshold: "75%",
1619
1626
  forceThreshold: "90%"
1620
1627
  }
1628
+ },
1629
+ qualityGate: {
1630
+ enabled: false,
1631
+ algorithm: "rouge-recall-v1",
1632
+ algorithms: {
1633
+ "rouge-recall-v1": {
1634
+ layer1MinChars: 200,
1635
+ layer1MinRetentionPct: 1,
1636
+ layer2MaxRougeF1: 0.05,
1637
+ layer2MaxTop20Recall: 0.2
1638
+ }
1639
+ }
1621
1640
  }
1622
1641
  };
1623
1642
  var GLOBAL_CONFIG_DIR = process.env.XDG_CONFIG_HOME ? join(process.env.XDG_CONFIG_HOME, "opencode") : join(homedir(), ".config", "opencode");
@@ -1815,6 +1834,11 @@ function deepCloneConfig(config) {
1815
1834
  gc: {
1816
1835
  ...config.gc,
1817
1836
  batchCleanup: { ...config.gc.batchCleanup }
1837
+ },
1838
+ qualityGate: {
1839
+ enabled: config.qualityGate.enabled,
1840
+ algorithm: config.qualityGate.algorithm,
1841
+ algorithms: { ...config.qualityGate.algorithms }
1818
1842
  }
1819
1843
  };
1820
1844
  }
@@ -1828,6 +1852,14 @@ function mergeGC(base, override) {
1828
1852
  batchCleanup: { ...base.batchCleanup, ...override.batchCleanup ?? {} }
1829
1853
  };
1830
1854
  }
1855
+ function mergeQualityGate(base, override) {
1856
+ if (!override) return base;
1857
+ return {
1858
+ enabled: override.enabled ?? base.enabled,
1859
+ algorithm: override.algorithm ?? base.algorithm,
1860
+ algorithms: { ...base.algorithms, ...override.algorithms ?? {} }
1861
+ };
1862
+ }
1831
1863
  function mergeLayer(config, data) {
1832
1864
  return {
1833
1865
  enabled: data.enabled ?? config.enabled,
@@ -1847,7 +1879,8 @@ function mergeLayer(config, data) {
1847
1879
  ],
1848
1880
  compress: mergeCompress(config.compress, data.compress),
1849
1881
  gc: mergeGC(config.gc, data.gc),
1850
- strategies: mergeStrategies(config.strategies, data.strategies)
1882
+ strategies: mergeStrategies(config.strategies, data.strategies),
1883
+ qualityGate: mergeQualityGate(config.qualityGate, data.qualityGate)
1851
1884
  };
1852
1885
  }
1853
1886
  function scheduleParseWarning(ctx, title, message) {
@@ -3287,6 +3320,8 @@ var SoftIssue = class extends Error {
3287
3320
  this.kind = kind;
3288
3321
  this.messageId = messageId;
3289
3322
  }
3323
+ kind;
3324
+ messageId;
3290
3325
  };
3291
3326
  function validateArgs(args) {
3292
3327
  if (typeof args.topic !== "string" || args.topic.trim().length === 0) {
@@ -5043,10 +5078,25 @@ function formatContextTransition(tokensBefore, tokensAfter) {
5043
5078
  return `Context ${beforeStr} \u2192 ${afterStr}`;
5044
5079
  }
5045
5080
  async function sendCompressNotification(client, logger, config, state, sessionId, entries, batchTopic, sessionMessageIds, params, contextTokensBefore) {
5046
- if (config.pruneNotification === "off") {
5081
+ if (entries.length === 0) {
5047
5082
  return false;
5048
5083
  }
5049
- if (entries.length === 0) {
5084
+ const logBlockIds = entries.map((e) => e.blockId);
5085
+ const logTopics = entries.map((e) => state.prune.messages.blocksById.get(e.blockId)?.topic ?? "?");
5086
+ const logCompressedTokens = entries.reduce((sum, e) => {
5087
+ const block = state.prune.messages.blocksById.get(e.blockId);
5088
+ return sum + (block?.compressedTokens ?? 0);
5089
+ }, 0);
5090
+ const logSummaryTokens = entries.reduce((sum, e) => sum + e.summaryTokens, 0);
5091
+ logger.info("Compression completed", {
5092
+ sessionId,
5093
+ blockIds: logBlockIds,
5094
+ topics: logTopics,
5095
+ compressedTokens: logCompressedTokens,
5096
+ summaryTokens: logSummaryTokens,
5097
+ contextTokensBefore
5098
+ });
5099
+ if (config.pruneNotification === "off") {
5050
5100
  return false;
5051
5101
  }
5052
5102
  let message;
@@ -5145,20 +5195,22 @@ ${progressBar}`;
5145
5195
  \u2192 Compression (~${summaryTokensStr}): ${displaySummary}`;
5146
5196
  }
5147
5197
  }
5148
- if (config.pruneNotificationType === "toast") {
5149
- let toastMessage = message;
5150
- toastMessage = config.pruneNotification === "minimal" ? toastMessage : truncateToastBody(toastMessage);
5151
- await client.tui.showToast({
5152
- body: {
5153
- title: "ACP: Compress Notification",
5154
- message: toastMessage,
5155
- variant: "info",
5156
- duration: 5e3
5157
- }
5158
- });
5159
- return true;
5198
+ if (config.pruneNotificationType === "chat") {
5199
+ logger.warn(
5200
+ "compress.pruneNotificationType 'chat' is no longer supported (it injects an empty user message that causes provider 400 errors); falling back to toast. Set pruneNotificationType to 'toast' (or pruneNotification to 'off') to silence this warning.",
5201
+ { sessionId }
5202
+ );
5160
5203
  }
5161
- await sendIgnoredMessage(client, sessionId, message, params, logger);
5204
+ let toastMessage = message;
5205
+ toastMessage = config.pruneNotification === "minimal" ? toastMessage : truncateToastBody(toastMessage);
5206
+ await client.tui.showToast({
5207
+ body: {
5208
+ title: "ACP: Compress Notification",
5209
+ message: toastMessage,
5210
+ variant: "info",
5211
+ duration: 5e3
5212
+ }
5213
+ });
5162
5214
  return true;
5163
5215
  }
5164
5216
  async function sendIgnoredMessage(client, sessionID, text, params, logger) {
@@ -5192,6 +5244,737 @@ async function sendIgnoredMessage(client, sessionID, text, params, logger) {
5192
5244
  }
5193
5245
  }
5194
5246
 
5247
+ // lib/compress/quality-gate/registry.ts
5248
+ var registry = /* @__PURE__ */ new Map();
5249
+ function registerQualityGate(gate) {
5250
+ if (registry.has(gate.name)) {
5251
+ const existing = registry.get(gate.name);
5252
+ if (existing !== gate && existing.version !== gate.version) {
5253
+ throw new Error(
5254
+ `Quality gate "${gate.name}" already registered with version ${existing.version} (attempted ${gate.version})`
5255
+ );
5256
+ }
5257
+ }
5258
+ registry.set(gate.name, gate);
5259
+ }
5260
+ function getQualityGate(name) {
5261
+ return registry.get(name);
5262
+ }
5263
+
5264
+ // node_modules/context-compress-algorithms/dist/chunk-E6LYOQFY.js
5265
+ var ENGLISH_WORD_RE = /[a-z][a-z0-9_]+/g;
5266
+ var CJK_RE = /[\u4e00-\u9fff]/g;
5267
+ var FILE_PATH_RE = /(?:[a-zA-Z0-9_-]+\/){1,}[a-zA-Z0-9_-]+\.[a-zA-Z]{1,5}/g;
5268
+ var STOPWORDS = /* @__PURE__ */ new Set([
5269
+ "the",
5270
+ "that",
5271
+ "this",
5272
+ "these",
5273
+ "those",
5274
+ "there",
5275
+ "their",
5276
+ "them",
5277
+ "then",
5278
+ "than",
5279
+ "thats",
5280
+ "with",
5281
+ "will",
5282
+ "would",
5283
+ "could",
5284
+ "should",
5285
+ "from",
5286
+ "have",
5287
+ "has",
5288
+ "had",
5289
+ "having",
5290
+ "were",
5291
+ "what",
5292
+ "which",
5293
+ "when",
5294
+ "where",
5295
+ "while",
5296
+ "your",
5297
+ "yours",
5298
+ "theirs",
5299
+ "ours",
5300
+ "mine",
5301
+ "hers",
5302
+ "whose",
5303
+ "they",
5304
+ "them",
5305
+ "those",
5306
+ "these",
5307
+ "this",
5308
+ "that",
5309
+ "such",
5310
+ "some",
5311
+ "same",
5312
+ "other",
5313
+ "another",
5314
+ "each",
5315
+ "into",
5316
+ "onto",
5317
+ "upon",
5318
+ "over",
5319
+ "under",
5320
+ "between",
5321
+ "through",
5322
+ "during",
5323
+ "before",
5324
+ "after",
5325
+ "above",
5326
+ "below",
5327
+ "among",
5328
+ "across",
5329
+ "along",
5330
+ "around",
5331
+ "about",
5332
+ "because",
5333
+ "since",
5334
+ "unless",
5335
+ "although",
5336
+ "though",
5337
+ "whereas",
5338
+ "whether",
5339
+ "either",
5340
+ "neither",
5341
+ "both",
5342
+ "also",
5343
+ "only",
5344
+ "just",
5345
+ "very",
5346
+ "more",
5347
+ "most",
5348
+ "much",
5349
+ "many",
5350
+ "less",
5351
+ "least",
5352
+ "several",
5353
+ "enough",
5354
+ "make",
5355
+ "made",
5356
+ "makes",
5357
+ "making",
5358
+ "take",
5359
+ "took",
5360
+ "taken",
5361
+ "takes",
5362
+ "taking",
5363
+ "get",
5364
+ "got",
5365
+ "getting",
5366
+ "gets",
5367
+ "give",
5368
+ "gave",
5369
+ "given",
5370
+ "gives",
5371
+ "giving",
5372
+ "come",
5373
+ "came",
5374
+ "comes",
5375
+ "coming",
5376
+ "were",
5377
+ "been",
5378
+ "being",
5379
+ "have",
5380
+ "make",
5381
+ "want",
5382
+ "need",
5383
+ "using",
5384
+ "true",
5385
+ "false",
5386
+ "null",
5387
+ "undefined",
5388
+ "void",
5389
+ "return",
5390
+ "returns",
5391
+ "returning",
5392
+ "function",
5393
+ "const",
5394
+ "class",
5395
+ "interface",
5396
+ "type",
5397
+ "typeof",
5398
+ "instanceof",
5399
+ "import",
5400
+ "export",
5401
+ "require",
5402
+ "module",
5403
+ "default",
5404
+ "async",
5405
+ "await",
5406
+ "static",
5407
+ "public",
5408
+ "private",
5409
+ "protected",
5410
+ "readonly",
5411
+ "partial",
5412
+ "abstract",
5413
+ "virtual",
5414
+ "override",
5415
+ "final",
5416
+ "super",
5417
+ "value",
5418
+ "values",
5419
+ "param",
5420
+ "params",
5421
+ "name",
5422
+ "names",
5423
+ "test",
5424
+ "tests",
5425
+ "testing",
5426
+ "tested",
5427
+ "expect",
5428
+ "expected",
5429
+ "actual",
5430
+ "actuals",
5431
+ "result",
5432
+ "results",
5433
+ "output",
5434
+ "outputs",
5435
+ "input",
5436
+ "inputs",
5437
+ "data",
5438
+ "record",
5439
+ "records",
5440
+ "item",
5441
+ "items",
5442
+ "like",
5443
+ "want",
5444
+ "need",
5445
+ "used",
5446
+ "uses",
5447
+ "said",
5448
+ "say",
5449
+ "says",
5450
+ "went",
5451
+ "goes",
5452
+ "here",
5453
+ "there",
5454
+ "where",
5455
+ "when",
5456
+ "what",
5457
+ "who",
5458
+ "how",
5459
+ "why",
5460
+ "which",
5461
+ "whose",
5462
+ "whom",
5463
+ "yourself",
5464
+ "myself",
5465
+ "itself",
5466
+ "themselves",
5467
+ "ourselves",
5468
+ "himself",
5469
+ "herself",
5470
+ "yeah",
5471
+ "okay",
5472
+ "ok",
5473
+ "yes",
5474
+ "no",
5475
+ "not",
5476
+ "nor",
5477
+ "or",
5478
+ "and",
5479
+ "but",
5480
+ "if",
5481
+ "then",
5482
+ "else",
5483
+ "elif",
5484
+ "when",
5485
+ "while",
5486
+ "for",
5487
+ "to",
5488
+ "of",
5489
+ "in",
5490
+ "on",
5491
+ "at",
5492
+ "by",
5493
+ "with",
5494
+ "from",
5495
+ "into",
5496
+ "onto",
5497
+ "\u7684",
5498
+ "\u662F",
5499
+ "\u4E86",
5500
+ "\u5728",
5501
+ "\u548C",
5502
+ "\u4E0E",
5503
+ "\u6216",
5504
+ "\u4E5F",
5505
+ "\u90FD",
5506
+ "\u5C31",
5507
+ "\u8FD8",
5508
+ "\u53C8",
5509
+ "\u624D",
5510
+ "\u518D",
5511
+ "\u5DF2",
5512
+ "\u5C06",
5513
+ "\u4F1A",
5514
+ "\u80FD",
5515
+ "\u53EF",
5516
+ "\u53EF\u4EE5",
5517
+ "\u8981",
5518
+ "\u60F3",
5519
+ "\u9700\u8981",
5520
+ "\u5E94\u8BE5",
5521
+ "\u5FC5\u987B",
5522
+ "\u6CA1",
5523
+ "\u6CA1\u6709",
5524
+ "\u4E0D",
5525
+ "\u975E",
5526
+ "\u65E0",
5527
+ "\u83AB",
5528
+ "\u6211",
5529
+ "\u4F60",
5530
+ "\u4ED6",
5531
+ "\u5979",
5532
+ "\u5B83",
5533
+ "\u6211\u4EEC",
5534
+ "\u4F60\u4EEC",
5535
+ "\u4ED6\u4EEC",
5536
+ "\u5979\u4EEC",
5537
+ "\u5B83\u4EEC",
5538
+ "\u54B1",
5539
+ "\u54B1\u4EEC",
5540
+ "\u81EA\u5DF1",
5541
+ "\u8FD9",
5542
+ "\u90A3",
5543
+ "\u8FD9\u4E2A",
5544
+ "\u90A3\u4E2A",
5545
+ "\u8FD9\u4E9B",
5546
+ "\u90A3\u4E9B",
5547
+ "\u8FD9\u6837",
5548
+ "\u90A3\u6837",
5549
+ "\u8FD9\u91CC",
5550
+ "\u90A3\u91CC",
5551
+ "\u8FD9\u4E48",
5552
+ "\u90A3\u4E48",
5553
+ "\u4EC0\u4E48",
5554
+ "\u600E\u4E48",
5555
+ "\u4E3A\u4EC0\u4E48",
5556
+ "\u54EA",
5557
+ "\u54EA\u4E2A",
5558
+ "\u54EA\u4E9B",
5559
+ "\u54EA\u91CC",
5560
+ "\u600E\u6837",
5561
+ "\u591A\u5C11",
5562
+ "\u51E0",
5563
+ "\u591A",
5564
+ "\u5C11",
5565
+ "\u4E8E",
5566
+ "\u4ECE",
5567
+ "\u5411",
5568
+ "\u5F80",
5569
+ "\u5230",
5570
+ "\u81F3",
5571
+ "\u4E3A",
5572
+ "\u5BF9\u4E8E",
5573
+ "\u5173\u4E8E",
5574
+ "\u81F3\u4E8E",
5575
+ "\u7531\u4E8E",
5576
+ "\u56E0\u4E3A",
5577
+ "\u6240\u4EE5",
5578
+ "\u4F46\u662F",
5579
+ "\u4F46",
5580
+ "\u4E0D\u8FC7",
5581
+ "\u7136\u800C",
5582
+ "\u53EF\u662F",
5583
+ "\u53EA\u662F",
5584
+ "\u53EA\u6709",
5585
+ "\u9664\u4E86",
5586
+ "\u9664\u975E",
5587
+ "\u65E0\u8BBA",
5588
+ "\u4E0D\u7BA1",
5589
+ "\u5C3D\u7BA1",
5590
+ "\u867D\u7136",
5591
+ "\u867D\u8BF4",
5592
+ "\u5373\u4F7F",
5593
+ "\u5373\u4FBF",
5594
+ "\u54EA\u6015",
5595
+ "\u4E00\u65E6",
5596
+ "\u5982\u679C",
5597
+ "\u8981\u662F",
5598
+ "\u5047\u5982",
5599
+ "\u5047\u4F7F",
5600
+ "\u5018\u82E5",
5601
+ "\u4E4B",
5602
+ "\u5176",
5603
+ "\u5176\u4E2D",
5604
+ "\u5176\u4ED6",
5605
+ "\u5176\u5B83",
5606
+ "\u5176\u4F59",
5607
+ "\u53E6\u4E00",
5608
+ "\u53E6\u5916",
5609
+ "\u6B64\u5916",
5610
+ "\u5E76\u4E14",
5611
+ "\u5E76",
5612
+ "\u4E14",
5613
+ "\u7740",
5614
+ "\u8FC7",
5615
+ "\u5427",
5616
+ "\u5417",
5617
+ "\u5462",
5618
+ "\u554A",
5619
+ "\u54E6",
5620
+ "\u55EF",
5621
+ "\u5440",
5622
+ "\u54C7",
5623
+ "\u54C8",
5624
+ "\u561B",
5625
+ "\u54AF",
5626
+ "\u54DF"
5627
+ ]);
5628
+ var ZH_STOPWORD_BIGRAMS = /* @__PURE__ */ new Set([
5629
+ "\u6211\u4EEC",
5630
+ "\u4F60\u4EEC",
5631
+ "\u4ED6\u4EEC",
5632
+ "\u5979\u4EEC",
5633
+ "\u5B83\u4EEC",
5634
+ "\u54B1\u4EEC",
5635
+ "\u8FD9\u4E2A",
5636
+ "\u90A3\u4E2A",
5637
+ "\u8FD9\u4E9B",
5638
+ "\u90A3\u4E9B",
5639
+ "\u4EC0\u4E48",
5640
+ "\u600E\u4E48",
5641
+ "\u4E3A\u4EC0\u4E48",
5642
+ "\u5982\u4F55",
5643
+ "\u53EF\u4EE5",
5644
+ "\u5E94\u8BE5",
5645
+ "\u4F46\u662F",
5646
+ "\u56E0\u4E3A",
5647
+ "\u6240\u4EE5",
5648
+ "\u5982\u679C",
5649
+ "\u867D\u7136",
5650
+ "\u5373\u4F7F",
5651
+ "\u5C3D\u7BA1",
5652
+ "\u4E3A\u4E86",
5653
+ "\u7531\u4E8E",
5654
+ "\u4E0D\u4F46",
5655
+ "\u800C\u4E14",
5656
+ "\u5E76\u4E14",
5657
+ "\u6216\u8005",
5658
+ "\u8FD8\u662F",
5659
+ "\u4EE5\u53CA",
5660
+ "\u4EE5\u4E3A",
5661
+ "\u4E8E\u662F",
5662
+ "\u7136\u800C",
5663
+ "\u5176\u5B9E",
5664
+ "\u5C31\u662F",
5665
+ "\u53EA\u662F",
5666
+ "\u53EA\u6709",
5667
+ "\u9664\u4E86",
5668
+ "\u9664\u975E",
5669
+ "\u8FD9\u6837",
5670
+ "\u90A3\u6837",
5671
+ "\u8FD9\u4E48",
5672
+ "\u90A3\u4E48",
5673
+ "\u8FD9\u4E9B",
5674
+ "\u90A3\u4E9B",
5675
+ "\u8FD9\u91CC",
5676
+ "\u90A3\u91CC",
5677
+ "\u73B0\u5728",
5678
+ "\u4EE5\u540E",
5679
+ "\u4EE5\u524D",
5680
+ "\u4E4B\u540E",
5681
+ "\u4E4B\u524D",
5682
+ "\u7136\u540E",
5683
+ "\u5F53\u7136",
5684
+ "\u53EF\u80FD",
5685
+ "\u4E00\u4E9B",
5686
+ "\u8BB8\u591A",
5687
+ "\u975E\u5E38",
5688
+ "\u5341\u5206",
5689
+ "\u6BD4\u8F83",
5690
+ "\u66F4\u52A0",
5691
+ "\u6700\u4E3A",
5692
+ "\u4E5F\u662F",
5693
+ "\u8FD8\u662F",
5694
+ "\u5C31\u662F",
5695
+ "\u4E0D\u8FC7",
5696
+ "\u4E0D\u8981",
5697
+ "\u4E0D\u80FD",
5698
+ "\u4E0D\u4F1A",
5699
+ "\u6CA1\u6709",
5700
+ "\u4E0D\u662F",
5701
+ "\u4E0D\u7528",
5702
+ "\u4E0D\u5FC5",
5703
+ "\u4E00\u76F4",
5704
+ "\u5DF2\u7ECF",
5705
+ "\u6B63\u5728",
5706
+ "\u9A6C\u4E0A"
5707
+ ]);
5708
+ var DEFAULT_OPTS = {
5709
+ english: true,
5710
+ zhUnigrams: true,
5711
+ zhBigrams: true
5712
+ };
5713
+ function tokenize(text, opts = {}) {
5714
+ if (!text || typeof text !== "string") return [];
5715
+ const options = { ...DEFAULT_OPTS, ...opts };
5716
+ const tokens = [];
5717
+ const lower = text.toLowerCase();
5718
+ if (options.english) {
5719
+ const matches = lower.match(ENGLISH_WORD_RE);
5720
+ if (matches) {
5721
+ for (const w of matches) {
5722
+ if (w.length >= 4 && !STOPWORDS.has(w) && !/^\d+$/.test(w)) {
5723
+ tokens.push(w);
5724
+ }
5725
+ }
5726
+ }
5727
+ }
5728
+ if (options.zhUnigrams || options.zhBigrams) {
5729
+ const cjkChars = text.match(CJK_RE);
5730
+ if (cjkChars && cjkChars.length > 0) {
5731
+ const cjkStr = cjkChars.join("");
5732
+ if (options.zhUnigrams) {
5733
+ for (const c of cjkStr) {
5734
+ if (!STOPWORDS.has(c)) tokens.push(c);
5735
+ }
5736
+ }
5737
+ if (options.zhBigrams) {
5738
+ for (let i = 0; i < cjkStr.length - 1; i++) {
5739
+ const bg = cjkStr.slice(i, i + 2);
5740
+ if (!ZH_STOPWORD_BIGRAMS.has(bg) && !STOPWORDS.has(bg[0]) && !STOPWORDS.has(bg[1])) {
5741
+ tokens.push(bg);
5742
+ }
5743
+ }
5744
+ }
5745
+ }
5746
+ }
5747
+ return tokens;
5748
+ }
5749
+ function termFrequency(tokens) {
5750
+ const tf = /* @__PURE__ */ new Map();
5751
+ for (const t of tokens) {
5752
+ tf.set(t, (tf.get(t) ?? 0) + 1);
5753
+ }
5754
+ return tf;
5755
+ }
5756
+ function topKByTf(tokens, k) {
5757
+ if (tokens.length === 0 || k <= 0) return [];
5758
+ const tf = termFrequency(tokens);
5759
+ const sorted = [...tf.entries()].sort((a, b) => {
5760
+ if (b[1] !== a[1]) return b[1] - a[1];
5761
+ return a[0].localeCompare(b[0]);
5762
+ });
5763
+ return sorted.slice(0, k).map((e) => e[0]);
5764
+ }
5765
+ function extractFilePaths(text) {
5766
+ if (!text) return /* @__PURE__ */ new Set();
5767
+ const paths = /* @__PURE__ */ new Set();
5768
+ const matches = text.match(FILE_PATH_RE);
5769
+ if (matches) {
5770
+ for (const m of matches) paths.add(m);
5771
+ }
5772
+ return paths;
5773
+ }
5774
+ function rouge1Recall(summaryTokens, originalTokens) {
5775
+ if (originalTokens.length === 0) return 0;
5776
+ const summarySet = new Set(summaryTokens);
5777
+ const originalSet = new Set(originalTokens);
5778
+ let hit = 0;
5779
+ for (const t of originalSet) if (summarySet.has(t)) hit++;
5780
+ return hit / originalSet.size;
5781
+ }
5782
+ function rouge1Precision(summaryTokens, originalTokens) {
5783
+ if (summaryTokens.length === 0) return 0;
5784
+ const summarySet = new Set(summaryTokens);
5785
+ const originalSet = new Set(originalTokens);
5786
+ let hit = 0;
5787
+ for (const t of summarySet) if (originalSet.has(t)) hit++;
5788
+ return hit / summarySet.size;
5789
+ }
5790
+ function rouge1F1(summaryTokens, originalTokens) {
5791
+ const r = rouge1Recall(summaryTokens, originalTokens);
5792
+ const p = rouge1Precision(summaryTokens, originalTokens);
5793
+ if (r + p === 0) return 0;
5794
+ return 2 * r * p / (r + p);
5795
+ }
5796
+ function topKRecall(summaryTokens, originalTokens, k) {
5797
+ if (originalTokens.length === 0 || k <= 0) return 0;
5798
+ const top = topKByTf(originalTokens, k);
5799
+ if (top.length === 0) return 0;
5800
+ const summarySet = new Set(summaryTokens);
5801
+ let hit = 0;
5802
+ for (const t of top) if (summarySet.has(t)) hit++;
5803
+ return hit / top.length;
5804
+ }
5805
+ var DEFAULT_ROUGE_RECALL_V1_CONFIG = {
5806
+ layer1MinChars: 200,
5807
+ layer1MinRetentionPct: 1,
5808
+ layer2MaxRougeF1: 0.05,
5809
+ layer2MaxTop20Recall: 0.2
5810
+ };
5811
+ var TOP_K = 20;
5812
+ var ORIGINAL_TOKEN_ESTIMATE_CHARS_PER_TOKEN = 4;
5813
+ function resolveConfig(input) {
5814
+ if (!input || typeof input !== "object") return DEFAULT_ROUGE_RECALL_V1_CONFIG;
5815
+ const c = input;
5816
+ return {
5817
+ layer1MinChars: typeof c.layer1MinChars === "number" && c.layer1MinChars > 0 ? c.layer1MinChars : DEFAULT_ROUGE_RECALL_V1_CONFIG.layer1MinChars,
5818
+ layer1MinRetentionPct: typeof c.layer1MinRetentionPct === "number" && c.layer1MinRetentionPct >= 0 ? c.layer1MinRetentionPct : DEFAULT_ROUGE_RECALL_V1_CONFIG.layer1MinRetentionPct,
5819
+ layer2MaxRougeF1: typeof c.layer2MaxRougeF1 === "number" && c.layer2MaxRougeF1 >= 0 ? c.layer2MaxRougeF1 : DEFAULT_ROUGE_RECALL_V1_CONFIG.layer2MaxRougeF1,
5820
+ layer2MaxTop20Recall: typeof c.layer2MaxTop20Recall === "number" && c.layer2MaxTop20Recall >= 0 ? c.layer2MaxTop20Recall : DEFAULT_ROUGE_RECALL_V1_CONFIG.layer2MaxTop20Recall
5821
+ };
5822
+ }
5823
+ var rougeRecallV1 = {
5824
+ name: "rouge-recall-v1",
5825
+ version: "1.0.0",
5826
+ description: "Two-layer gate: length floor (L1) then ROUGE-1 F1 AND top-20 keyword recall (L2)",
5827
+ evaluate(ctx, rawConfig) {
5828
+ const cfg = resolveConfig(rawConfig);
5829
+ const summaryLen = ctx.summary.length;
5830
+ const originalChars = ctx.originalText.length;
5831
+ const retentionPct = ctx.block.compressedTokens > 0 ? summaryLen / (ctx.block.compressedTokens * ORIGINAL_TOKEN_ESTIMATE_CHARS_PER_TOKEN) * 100 : 0;
5832
+ const baseMetrics = [
5833
+ { name: "summaryLen", value: summaryLen },
5834
+ { name: "retentionPct", value: +retentionPct.toFixed(2), format: "percent" },
5835
+ { name: "originalTokens", value: ctx.block.compressedTokens }
5836
+ ];
5837
+ if (summaryLen < cfg.layer1MinChars || originalChars > 0 && retentionPct < cfg.layer1MinRetentionPct) {
5838
+ return {
5839
+ passed: false,
5840
+ layer: "L1-length",
5841
+ reason: `Summary too short: ${summaryLen} chars, ${retentionPct.toFixed(2)}% retention (threshold: ${cfg.layer1MinChars} chars OR ${cfg.layer1MinRetentionPct}% retention)`,
5842
+ metrics: baseMetrics
5843
+ };
5844
+ }
5845
+ if (ctx.originalText.length === 0) {
5846
+ return { passed: true, metrics: baseMetrics };
5847
+ }
5848
+ const summaryTokens = tokenize(ctx.summary);
5849
+ const originalTokens = tokenize(ctx.originalText);
5850
+ const rougeF1 = rouge1F1(summaryTokens, originalTokens);
5851
+ const rougeRecall = rouge1Recall(summaryTokens, originalTokens);
5852
+ const top20 = topKRecall(summaryTokens, originalTokens, TOP_K);
5853
+ const summaryPaths = extractFilePaths(ctx.summary);
5854
+ const originalPaths = extractFilePaths(ctx.originalText);
5855
+ const pathCoverage = originalPaths.size >= 5 ? [...summaryPaths].filter((p) => originalPaths.has(p)).length / originalPaths.size : -1;
5856
+ const contentMetrics = [
5857
+ ...baseMetrics,
5858
+ { name: "rougeF1", value: +rougeF1.toFixed(4), format: "ratio" },
5859
+ { name: "rougeRecall", value: +rougeRecall.toFixed(4), format: "ratio" },
5860
+ { name: "top20Recall", value: +top20.toFixed(4), format: "ratio" },
5861
+ { name: "nOriginalPaths", value: originalPaths.size },
5862
+ { name: "nSummaryPaths", value: summaryPaths.size }
5863
+ ];
5864
+ if (pathCoverage >= 0) {
5865
+ contentMetrics.push({ name: "pathCoverage", value: +pathCoverage.toFixed(3), format: "ratio" });
5866
+ }
5867
+ if (rougeF1 < cfg.layer2MaxRougeF1 && top20 < cfg.layer2MaxTop20Recall) {
5868
+ return {
5869
+ passed: false,
5870
+ layer: "L2-recall",
5871
+ reason: `Content coverage too low: rougeF1=${rougeF1.toFixed(3)}, top20Recall=${top20.toFixed(3)} (threshold: rougeF1<${cfg.layer2MaxRougeF1} AND top20<${cfg.layer2MaxTop20Recall})`,
5872
+ metrics: contentMetrics
5873
+ };
5874
+ }
5875
+ return { passed: true, metrics: contentMetrics };
5876
+ }
5877
+ };
5878
+
5879
+ // lib/compress/quality-gate/algorithms/index.ts
5880
+ function ensureBuiltinGatesRegistered() {
5881
+ registerQualityGate(rougeRecallV1);
5882
+ }
5883
+
5884
+ // lib/compress/quality-gate/evaluate.ts
5885
+ var CHARS_PER_TOKEN_ESTIMATE = 4;
5886
+ var TOOL_OUTPUT_MAX_CHARS = 1500;
5887
+ var TOOL_INPUT_MAX_CHARS = 500;
5888
+ function extractMessageText(parts) {
5889
+ if (!parts || !Array.isArray(parts)) return "";
5890
+ let text = "";
5891
+ for (const part of parts) {
5892
+ if (!part || typeof part !== "object") continue;
5893
+ if (part.type === "text") {
5894
+ text += part.text + "\n";
5895
+ } else if (part.type === "tool") {
5896
+ const state = part.state;
5897
+ const input = state.status === "completed" && typeof state.input === "object" ? JSON.stringify(state.input).slice(0, TOOL_INPUT_MAX_CHARS) : "";
5898
+ const output = state.status === "completed" && typeof state.output === "string" ? state.output.slice(0, TOOL_OUTPUT_MAX_CHARS) : state.status === "completed" && typeof state.output === "object" ? JSON.stringify(state.output).slice(0, TOOL_OUTPUT_MAX_CHARS) : "";
5899
+ text += `[tool:${part.tool}] ${input}
5900
+ ${output}
5901
+ `;
5902
+ }
5903
+ }
5904
+ return text;
5905
+ }
5906
+ function buildContext(block, rawMessages) {
5907
+ const directIds = block.directMessageIds;
5908
+ if (!directIds || directIds.length === 0) return null;
5909
+ const idToMsg = /* @__PURE__ */ new Map();
5910
+ for (const m of rawMessages) {
5911
+ const id = m?.info?.id;
5912
+ if (typeof id === "string") idToMsg.set(id, m);
5913
+ }
5914
+ const chunks = [];
5915
+ for (const id of directIds) {
5916
+ const m = idToMsg.get(id);
5917
+ if (!m) continue;
5918
+ chunks.push(extractMessageText(m.parts));
5919
+ }
5920
+ if (chunks.length === 0) return null;
5921
+ const originalText = chunks.join("\n");
5922
+ return {
5923
+ block,
5924
+ summary: block.summary ?? "",
5925
+ originalChunks: chunks,
5926
+ originalText,
5927
+ originalTokens: Math.ceil(originalText.length / CHARS_PER_TOKEN_ESTIMATE)
5928
+ };
5929
+ }
5930
+ function evaluateBlockQuality(state, rawMessages, entry, config, logger) {
5931
+ const qg = config.qualityGate;
5932
+ if (!qg || qg.enabled !== true) return null;
5933
+ ensureBuiltinGatesRegistered();
5934
+ const algoName = qg.algorithm;
5935
+ if (!algoName) {
5936
+ logger.warn("Quality gate enabled but no algorithm specified", {});
5937
+ return null;
5938
+ }
5939
+ const gate = getQualityGate(algoName);
5940
+ if (!gate) {
5941
+ logger.warn("Quality gate algorithm not found in registry", { algorithm: algoName });
5942
+ return null;
5943
+ }
5944
+ const block = state.prune.messages.blocksById.get(entry.blockId);
5945
+ if (!block) {
5946
+ logger.warn("Quality gate: block not found", { blockId: entry.blockId });
5947
+ return null;
5948
+ }
5949
+ const ctx = buildContext(block, rawMessages);
5950
+ if (!ctx) return null;
5951
+ const algoConfig = (qg.algorithms && qg.algorithms[algoName]) ?? {};
5952
+ try {
5953
+ return gate.evaluate(ctx, algoConfig);
5954
+ } catch (err) {
5955
+ logger.warn("Quality gate threw \u2014 treating as pass", {
5956
+ gate: gate.name,
5957
+ blockId: entry.blockId,
5958
+ error: err instanceof Error ? err.message : String(err)
5959
+ });
5960
+ return { passed: true, metrics: [] };
5961
+ }
5962
+ }
5963
+ function evaluateBatchQuality(state, rawMessages, entries, config, logger) {
5964
+ const failures = [];
5965
+ for (const entry of entries) {
5966
+ const result = evaluateBlockQuality(state, rawMessages, entry, config, logger);
5967
+ if (result && !result.passed) {
5968
+ failures.push({ blockId: entry.blockId, result });
5969
+ }
5970
+ }
5971
+ return {
5972
+ total: entries.length,
5973
+ passed: entries.length - failures.length,
5974
+ failures
5975
+ };
5976
+ }
5977
+
5195
5978
  // lib/compress/pipeline.ts
5196
5979
  function snapshotCompressionState(state) {
5197
5980
  return {
@@ -5240,6 +6023,27 @@ async function finalizeSession(ctx, toolCtx, rawMessages, entries, batchTopic) {
5240
6023
  ctx.state.manualMode = ctx.state.manualMode ? "active" : false;
5241
6024
  applyPendingCompressionDurations(ctx.state);
5242
6025
  await saveSessionState(ctx.state, ctx.logger);
6026
+ if (entries.length > 0) {
6027
+ const qualityReport = evaluateBatchQuality(
6028
+ ctx.state,
6029
+ rawMessages,
6030
+ entries,
6031
+ ctx.config,
6032
+ ctx.logger
6033
+ );
6034
+ for (const failure of qualityReport.failures) {
6035
+ const metrics = Object.fromEntries(
6036
+ failure.result.metrics.map((m) => [m.name, m.value])
6037
+ );
6038
+ ctx.logger.warn("Compression quality gate FAILED", {
6039
+ blockId: failure.blockId,
6040
+ algorithm: ctx.config.qualityGate.algorithm,
6041
+ layer: failure.result.layer,
6042
+ reason: failure.result.reason,
6043
+ ...metrics
6044
+ });
6045
+ }
6046
+ }
5243
6047
  const params = getCurrentParams(ctx.state, rawMessages, ctx.logger);
5244
6048
  const sessionMessageIds = rawMessages.filter((msg) => !isIgnoredUserMessage(msg)).map((msg) => msg.info.id);
5245
6049
  const contextTokensBefore = getCurrentTokenUsage(ctx.state, rawMessages);
@@ -5880,15 +6684,29 @@ var filterCompressedRanges = (state, messages) => {
5880
6684
  if (state.prune.messages.byMessageId.size === 0) {
5881
6685
  return;
5882
6686
  }
6687
+ const survive = messages.map((msg) => {
6688
+ const pruneEntry = state.prune.messages.byMessageId.get(msg.info.id);
6689
+ if (!pruneEntry || pruneEntry.activeBlockIds.length === 0) {
6690
+ return true;
6691
+ }
6692
+ return false;
6693
+ });
6694
+ const anyUserSurvives = messages.some(
6695
+ (msg, i) => survive[i] && msg.info.role === "user"
6696
+ );
6697
+ if (!anyUserSurvives) {
6698
+ for (let i = messages.length - 1; i >= 0; i--) {
6699
+ if (messages[i].info.role === "user" && !survive[i]) {
6700
+ survive[i] = true;
6701
+ break;
6702
+ }
6703
+ }
6704
+ }
5883
6705
  const result = [];
5884
6706
  for (let i = 0; i < messages.length; i++) {
5885
- const msg = messages[i];
5886
- const msgId = msg.info.id;
5887
- const pruneEntry = state.prune.messages.byMessageId.get(msgId);
5888
- if (pruneEntry && pruneEntry.activeBlockIds.length > 0) {
5889
- continue;
6707
+ if (survive[i]) {
6708
+ result.push(messages[i]);
5890
6709
  }
5891
- result.push(msg);
5892
6710
  }
5893
6711
  messages.length = 0;
5894
6712
  messages.push(...result);
@@ -6220,7 +7038,7 @@ var dropEmptyMessages = (messages) => {
6220
7038
  for (let i = messages.length - 1; i >= 0; i--) {
6221
7039
  const parts = Array.isArray(messages[i].parts) ? messages[i].parts : [];
6222
7040
  const isEmpty = parts.every(
6223
- (part) => part.type === "text" && (typeof part.text !== "string" || part.text.trim().length === 0)
7041
+ (part) => part.type === "text" && (typeof part.text !== "string" || part.text.trim().length === 0 || part.ignored === true)
6224
7042
  );
6225
7043
  if (isEmpty) {
6226
7044
  messages.splice(i, 1);
@@ -6388,6 +7206,62 @@ function listPriorityRefsBeforeIndex(messages, priorities, anchorIndex, priority
6388
7206
  return refs;
6389
7207
  }
6390
7208
 
7209
+ // node_modules/context-compress-algorithms/dist/chunk-UX2UW5FY.js
7210
+ var NUDGE_GROWTH_FLOOR = 6e3;
7211
+ var NUDGE_GROWTH_CAP = 5e4;
7212
+ var NUDGE_GROWTH_RATIO = 0.05;
7213
+ function computeShouldNudge(params) {
7214
+ const { currentTokens, overMinLimit, overMaxLimit } = params;
7215
+ if (currentTokens === void 0) {
7216
+ return { shouldNudge: false, tipsVariant: null };
7217
+ }
7218
+ if (params.lastNudgeTokens === void 0) {
7219
+ return { shouldNudge: false, tipsVariant: null };
7220
+ }
7221
+ const growthSinceLastNudge = currentTokens - params.lastNudgeTokens;
7222
+ const shouldNudge = growthSinceLastNudge >= params.nudgeGrowthTokens || overMaxLimit;
7223
+ if (!shouldNudge) {
7224
+ return { shouldNudge: false, tipsVariant: null };
7225
+ }
7226
+ const tipsVariant = overMaxLimit ? "maxLimit" : overMinLimit ? "minLimit" : "normal";
7227
+ return { shouldNudge: true, tipsVariant };
7228
+ }
7229
+ function resolveAdaptiveNudgeGrowth(modelContextLimit) {
7230
+ if (!modelContextLimit || modelContextLimit <= 0) return NUDGE_GROWTH_FLOOR;
7231
+ return Math.min(
7232
+ NUDGE_GROWTH_CAP,
7233
+ Math.max(NUDGE_GROWTH_FLOOR, Math.round(modelContextLimit * NUDGE_GROWTH_RATIO))
7234
+ );
7235
+ }
7236
+ var defaultTriggerPolicy = {
7237
+ name: "context-compress-algorithms-trigger",
7238
+ version: "1.0.0",
7239
+ description: "Growth-only cadence: nudge when context growth since last nudge exceeds adaptive threshold, or when over max limit.",
7240
+ computeShouldNudge,
7241
+ resolveAdaptiveNudgeGrowth
7242
+ };
7243
+
7244
+ // lib/messages/inject/policy/registry.ts
7245
+ var registry2 = /* @__PURE__ */ new Map();
7246
+ var defaultPolicy = null;
7247
+ function registerTriggerPolicy2(policy) {
7248
+ if (!policy.name) {
7249
+ throw new Error("TriggerPolicy must have a name");
7250
+ }
7251
+ registry2.set(policy.name, policy);
7252
+ if (!defaultPolicy) {
7253
+ defaultPolicy = policy;
7254
+ }
7255
+ }
7256
+ function getDefaultTriggerPolicy() {
7257
+ return defaultPolicy;
7258
+ }
7259
+
7260
+ // lib/messages/inject/policy/index.ts
7261
+ function ensureBuiltinTriggerPolicyRegistered() {
7262
+ registerTriggerPolicy2(defaultTriggerPolicy);
7263
+ }
7264
+
6391
7265
  // lib/messages/inject/utils.ts
6392
7266
  var MESSAGE_MODE_NUDGE_PRIORITY = "high";
6393
7267
  function getNudgeFrequency(config) {
@@ -6500,31 +7374,20 @@ function isContextOverLimits(config, state, providerId, modelId, messages) {
6500
7374
  modelContextLimit: state.modelContextLimit
6501
7375
  };
6502
7376
  }
6503
- function computeShouldNudge(params) {
6504
- const { currentTokens, overMinLimit, overMaxLimit } = params;
6505
- if (currentTokens === void 0) {
6506
- return { shouldNudge: false, tipsVariant: null };
6507
- }
6508
- if (params.lastNudgeTokens === void 0) {
7377
+ ensureBuiltinTriggerPolicyRegistered();
7378
+ function computeShouldNudge2(params) {
7379
+ const policy = getDefaultTriggerPolicy();
7380
+ if (!policy) {
6509
7381
  return { shouldNudge: false, tipsVariant: null };
6510
7382
  }
6511
- const growthSinceLastNudge = currentTokens - params.lastNudgeTokens;
6512
- const shouldNudge = growthSinceLastNudge >= params.nudgeGrowthTokens || overMaxLimit;
6513
- if (!shouldNudge) {
6514
- return { shouldNudge: false, tipsVariant: null };
6515
- }
6516
- const tipsVariant = overMaxLimit ? "maxLimit" : overMinLimit ? "minLimit" : "normal";
6517
- return { shouldNudge: true, tipsVariant };
7383
+ return policy.computeShouldNudge(params);
6518
7384
  }
6519
- var NUDGE_GROWTH_FLOOR = 6e3;
6520
- var NUDGE_GROWTH_CAP = 5e4;
6521
- var NUDGE_GROWTH_RATIO = 0.05;
6522
- function resolveAdaptiveNudgeGrowth(modelContextLimit) {
6523
- if (!modelContextLimit || modelContextLimit <= 0) return NUDGE_GROWTH_FLOOR;
6524
- return Math.min(
6525
- NUDGE_GROWTH_CAP,
6526
- Math.max(NUDGE_GROWTH_FLOOR, Math.round(modelContextLimit * NUDGE_GROWTH_RATIO))
6527
- );
7385
+ function resolveAdaptiveNudgeGrowth2(modelContextLimit) {
7386
+ const policy = getDefaultTriggerPolicy();
7387
+ if (!policy) {
7388
+ return 6e3;
7389
+ }
7390
+ return policy.resolveAdaptiveNudgeGrowth(modelContextLimit);
6528
7391
  }
6529
7392
  function addAnchor(anchorMessageIds, anchorMessageId, anchorMessageIndex, messages, interval) {
6530
7393
  if (anchorMessageIndex < 0) {
@@ -7100,7 +7963,7 @@ ${lines2.join("\n")}`;
7100
7963
  ${lines.join("\n")}`;
7101
7964
  }
7102
7965
 
7103
- // lib/prompts/compression-rules.ts
7966
+ // node_modules/context-compress-algorithms/dist/chunk-ZRHPFN6B.js
7104
7967
  var COMPRESS_PHILOSOPHY = `Compression Philosophy:
7105
7968
  - All compression serves the primary task, but be frugal.
7106
7969
  - Context capacity is precious. Save context by compressing consumed outputs, not by avoiding tools.
@@ -7276,7 +8139,7 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
7276
8139
  }
7277
8140
  }
7278
8141
  const suffixMessage = createSuffixMessage(messages);
7279
- const nudgeGrowthTokens = config.compress?.nudgeGrowthTokens ?? resolveAdaptiveNudgeGrowth(modelContextLimit);
8142
+ const nudgeGrowthTokens = config.compress?.nudgeGrowthTokens ?? resolveAdaptiveNudgeGrowth2(modelContextLimit);
7280
8143
  const growthFloor = Math.max(
7281
8144
  config.compress?.minNudgeGrowthFloor ?? 5e3,
7282
8145
  (config.compress?.minNudgeGrowthRatio ?? 0.45) * nudgeGrowthTokens
@@ -7291,7 +8154,7 @@ var injectCompressNudges = (state, config, logger, messages, prompts, compressio
7291
8154
  const hasPendingNudge = state.nudges.lastNudgeShownTokens !== void 0;
7292
8155
  const effectiveThreshold = hasPendingNudge ? Math.floor(nudgeGrowthTokens / 2) : nudgeGrowthTokens;
7293
8156
  const growthReference = state.nudges.lastNudgeShownTokens ?? state.nudges.lastPerMessageNudgeTokens;
7294
- const decision = computeShouldNudge({
8157
+ const decision = computeShouldNudge2({
7295
8158
  currentTokens,
7296
8159
  modelContextLimit,
7297
8160
  overMinLimit,
@@ -8025,7 +8888,7 @@ function buildSchema3() {
8025
8888
  function extractMessageId(m) {
8026
8889
  return m.id ?? m.messageId ?? "";
8027
8890
  }
8028
- function extractMessageText(m) {
8891
+ function extractMessageText2(m) {
8029
8892
  const msg = m;
8030
8893
  const role = msg.role || msg.type || "unknown";
8031
8894
  const content = typeof msg.content === "string" ? msg.content : typeof msg.text === "string" ? msg.text : JSON.stringify(msg.content || msg.text || "");
@@ -8078,7 +8941,7 @@ function createDecompressTool(ctx) {
8078
8941
  }
8079
8942
  }
8080
8943
  const blockMessages = rawMessages.filter((m) => msgIdSet.has(extractMessageId(m)));
8081
- const lines2 = blockMessages.map(extractMessageText);
8944
+ const lines2 = blockMessages.map(extractMessageText2);
8082
8945
  const { writeFile: writeFile3 } = await import("fs/promises");
8083
8946
  const fileContent = lines2.length > 0 ? lines2.join("\n\n---\n\n") : activeBlocks[0]?.summary ?? "(no content available)";
8084
8947
  await writeFile3(targetPath, fileContent, "utf-8");