@nxuss/lemma 0.5.2 → 0.5.3

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 (48) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  3. package/dist/cjs/cli/lemma-proxy.js +187 -98
  4. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  5. package/dist/cjs/config/index.d.ts.map +1 -1
  6. package/dist/cjs/config/index.js +2 -1
  7. package/dist/cjs/config/index.js.map +1 -1
  8. package/dist/cjs/errors/LemmaError.d.ts +52 -0
  9. package/dist/cjs/errors/LemmaError.d.ts.map +1 -0
  10. package/dist/cjs/errors/LemmaError.js +84 -0
  11. package/dist/cjs/errors/LemmaError.js.map +1 -0
  12. package/dist/cjs/index.d.ts.map +1 -1
  13. package/dist/cjs/index.js +24 -22
  14. package/dist/cjs/index.js.map +1 -1
  15. package/dist/cjs/subconscious/SemanticCache.d.ts +4 -4
  16. package/dist/cjs/subconscious/SemanticCache.d.ts.map +1 -1
  17. package/dist/cjs/subconscious/SemanticCache.js +14 -10
  18. package/dist/cjs/subconscious/SemanticCache.js.map +1 -1
  19. package/dist/cjs/types/index.d.ts +8 -8
  20. package/dist/cjs/types/index.d.ts.map +1 -1
  21. package/dist/cjs/utils/logger.d.ts +27 -6
  22. package/dist/cjs/utils/logger.d.ts.map +1 -1
  23. package/dist/cjs/utils/logger.js +96 -28
  24. package/dist/cjs/utils/logger.js.map +1 -1
  25. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  26. package/dist/esm/cli/lemma-proxy.js +187 -98
  27. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  28. package/dist/esm/config/index.d.ts.map +1 -1
  29. package/dist/esm/config/index.js +2 -1
  30. package/dist/esm/config/index.js.map +1 -1
  31. package/dist/esm/errors/LemmaError.d.ts +52 -0
  32. package/dist/esm/errors/LemmaError.d.ts.map +1 -0
  33. package/dist/esm/errors/LemmaError.js +75 -0
  34. package/dist/esm/errors/LemmaError.js.map +1 -0
  35. package/dist/esm/index.d.ts.map +1 -1
  36. package/dist/esm/index.js +24 -22
  37. package/dist/esm/index.js.map +1 -1
  38. package/dist/esm/subconscious/SemanticCache.d.ts +4 -4
  39. package/dist/esm/subconscious/SemanticCache.d.ts.map +1 -1
  40. package/dist/esm/subconscious/SemanticCache.js +14 -10
  41. package/dist/esm/subconscious/SemanticCache.js.map +1 -1
  42. package/dist/esm/types/index.d.ts +8 -8
  43. package/dist/esm/types/index.d.ts.map +1 -1
  44. package/dist/esm/utils/logger.d.ts +27 -6
  45. package/dist/esm/utils/logger.d.ts.map +1 -1
  46. package/dist/esm/utils/logger.js +93 -28
  47. package/dist/esm/utils/logger.js.map +1 -1
  48. package/package.json +27 -24
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # 🧠 Lemma v0.5.2
1
+ # 🧠 Lemma v0.5.3
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@nxuss/lemma.svg?color=orange&style=flat-square)](https://www.npmjs.com/package/@nxuss/lemma)
4
4
  [![License](https://img.shields.io/npm/l/@nxuss/lemma.svg?color=blue&style=flat-square)](https://github.com/Nxusbets/lemma/blob/main/LICENSE)
@@ -1 +1 @@
1
- {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AAoNA,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CA0I3D;AAED,wBAAgB,+BAA+B,IAAI,IAAI,CAyCtD;AAmsCD,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6KhL"}
1
+ {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AA8NA,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CA0I3D;AAED,wBAAgB,+BAA+B,IAAI,IAAI,CAyCtD;AAuxCD,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6KhL"}
@@ -32,7 +32,7 @@ function getVersion() {
32
32
  catch { }
33
33
  }
34
34
  }
35
- return '0.5.2';
35
+ return '0.5.3';
36
36
  }
37
37
  const VERSION = getVersion();
38
38
  const ComplexityRouter_1 = __importDefault(require("../proxy/ComplexityRouter"));
@@ -86,13 +86,20 @@ async function readJson(file, fallback) {
86
86
  catch { }
87
87
  return fallback;
88
88
  }
89
+ const writeQueues = new Map();
89
90
  async function writeJson(file, data) {
90
- try {
91
- const tempFile = file + '.tmp';
92
- await fs_1.default.promises.writeFile(tempFile, JSON.stringify(data, null, 2));
93
- await fs_1.default.promises.rename(tempFile, file);
94
- }
95
- catch { }
91
+ const chain = writeQueues.get(file) || Promise.resolve();
92
+ const writeOperation = async () => {
93
+ try {
94
+ const tempFile = `${file}.${crypto_1.default.randomUUID ? crypto_1.default.randomUUID() : Math.random().toString(36).substring(2, 15)}.tmp`;
95
+ await fs_1.default.promises.writeFile(tempFile, JSON.stringify(data, null, 2));
96
+ await fs_1.default.promises.rename(tempFile, file);
97
+ }
98
+ catch { }
99
+ };
100
+ const nextChain = chain.then(writeOperation).catch(() => { });
101
+ writeQueues.set(file, nextChain);
102
+ return nextChain;
96
103
  }
97
104
  function projectHash(name) {
98
105
  return crypto_1.default.createHash('sha1').update(name).digest('hex').slice(0, 12);
@@ -386,12 +393,21 @@ function startBackgroundClipboardWatcher() {
386
393
  }
387
394
  }
388
395
  // ── License helpers ────────────────────────────────────────────────────────────
396
+ let isProCached = null;
397
+ let lastLicenseCheck = 0;
398
+ const LICENSE_CACHE_TTL = 10000; // 10 seconds cache
389
399
  async function loadLicense() {
390
400
  return readJson(LICENSE_FILE, { isPro: false });
391
401
  }
392
402
  async function isPro() {
403
+ const now = Date.now();
404
+ if (isProCached !== null && (now - lastLicenseCheck) < LICENSE_CACHE_TTL) {
405
+ return isProCached;
406
+ }
393
407
  const l = await loadLicense();
394
- return !!(l && l.isPro);
408
+ isProCached = !!(l && l.isPro);
409
+ lastLicenseCheck = now;
410
+ return isProCached;
395
411
  }
396
412
  async function validateKeyRemote(key) {
397
413
  return new Promise((resolve, reject) => {
@@ -484,7 +500,15 @@ function cacheGet(provider, prompt) {
484
500
  return e;
485
501
  }
486
502
  function cacheSet(provider, prompt, data) {
487
- CACHE.set(cacheKey(provider, prompt), { input: prompt, data, createdAt: Date.now(), ttl: TTL_MS });
503
+ const MAX_CACHE_SIZE = 5000;
504
+ const k = cacheKey(provider, prompt);
505
+ if (!CACHE.has(k) && CACHE.size >= MAX_CACHE_SIZE) {
506
+ // Evict oldest cache entry (FIFO eviction)
507
+ const oldestKey = CACHE.keys().next().value;
508
+ if (oldestKey)
509
+ CACHE.delete(oldestKey);
510
+ }
511
+ CACHE.set(k, { input: prompt, data, createdAt: Date.now(), ttl: TTL_MS, provider });
488
512
  }
489
513
  // ── Semantic Search (Pro) ──────────────────────────────────────────────────────
490
514
  async function getEmbedding(text) {
@@ -529,7 +553,7 @@ async function semanticGet(provider, prompt) {
529
553
  distance = distances[0][i];
530
554
  }
531
555
  const similarity = Math.max(0, 1 - distance);
532
- const THRESHOLD = 0.7;
556
+ const THRESHOLD = 0.82; // raised from 0.7 to 0.82 to prevent false positives
533
557
  if (similarity >= THRESHOLD) {
534
558
  return {
535
559
  data: JSON.parse(metadata.response),
@@ -756,6 +780,16 @@ async function relayMissStream(res, body, provider, tier) {
756
780
  req.end();
757
781
  });
758
782
  }
783
+ class WriteQueue {
784
+ constructor() {
785
+ this.queue = Promise.resolve();
786
+ }
787
+ async enqueue(fn) {
788
+ this.queue = this.queue.then(fn).catch(() => { });
789
+ return this.queue;
790
+ }
791
+ }
792
+ const usageWriteQueue = new WriteQueue();
759
793
  // ── Proxy Server class ─────────────────────────────────────────────────────────
760
794
  class LemmaServer {
761
795
  constructor(port, projectName, openBrowser = true) {
@@ -885,24 +919,57 @@ class LemmaServer {
885
919
  res.status(500).json({ error: e.message });
886
920
  }
887
921
  });
888
- this.app.post('/api/cache/clear', (req, res) => {
889
- const count = CACHE.size;
890
- CACHE.clear();
891
- EVENT_LOG.length = 0; // Clear live event log
892
- SavingsLedger_1.savingsLedger.reset(); // Reset savings counters
893
- // Reset and persist statistics for the current project
894
- if (this.stats[this.projectName]) {
895
- this.stats[this.projectName] = {
896
- total: 0,
897
- hits: 0,
898
- misses: 0,
899
- totalLatency: 0,
900
- totalTokensSaved: 0,
901
- providers: {}
902
- };
903
- writeJson(STATS_FILE, this.stats).catch(() => { });
922
+ this.app.post('/api/cache/clear', async (req, res) => {
923
+ const { provider } = req.body || {};
924
+ let clearedCount = 0;
925
+ if (!provider) {
926
+ // Global clear
927
+ clearedCount = CACHE.size;
928
+ CACHE.clear();
929
+ EVENT_LOG.length = 0; // Clear live event log
930
+ SavingsLedger_1.savingsLedger.reset(); // Reset savings counters
931
+ // Reset and persist statistics for the current project
932
+ if (this.stats[this.projectName]) {
933
+ this.stats[this.projectName] = {
934
+ total: 0,
935
+ hits: 0,
936
+ misses: 0,
937
+ totalLatency: 0,
938
+ totalTokensSaved: 0,
939
+ providers: {}
940
+ };
941
+ writeJson(STATS_FILE, this.stats).catch(() => { });
942
+ }
943
+ // Clear Chroma DB collection
944
+ try {
945
+ await chroma.deleteCollection({ name: 'lemma-cache' }).catch(() => { });
946
+ }
947
+ catch (e) {
948
+ console.error(`[CacheClear] Failed to clear Chroma collection: ${e.message}`);
949
+ }
904
950
  }
905
- res.json({ success: true, clearedEntries: count });
951
+ else {
952
+ // Granular clear
953
+ for (const [k, e] of CACHE.entries()) {
954
+ if (e.provider === provider) {
955
+ CACHE.delete(k);
956
+ clearedCount++;
957
+ }
958
+ }
959
+ // Selective delete from Chroma DB collection using provider metadata filter
960
+ try {
961
+ const collection = await chroma.getOrCreateCollection({
962
+ name: 'lemma-cache',
963
+ embeddingFunction: dummyEmbeddingFunction,
964
+ metadata: { "hnsw:space": "cosine" }
965
+ });
966
+ await collection.delete({ where: { provider } });
967
+ }
968
+ catch (e) {
969
+ console.error(`[CacheClear] Failed to selectively delete provider ${provider} from Chroma: ${e.message}`);
970
+ }
971
+ }
972
+ res.json({ success: true, clearedEntries: clearedCount });
906
973
  });
907
974
  // Savings breakdown by source for the dashboard
908
975
  this.app.get('/api/savings-breakdown', (req, res) => {
@@ -946,89 +1013,36 @@ class LemmaServer {
946
1013
  logEvent({ type: 'privacy:mask', count: Object.keys(tokenMap).length, project: this.projectName });
947
1014
  }
948
1015
  const originalModel = req.body.model || 'gpt-4o';
949
- const routingDecision = complexityRouter.evaluate(prompt, originalModel);
950
- const model = routingDecision.model;
951
- if (req.body.model)
952
- req.body.model = model;
953
- // Record complexity routing savings when model is downgraded
954
- if (routingDecision.complexity === 'low' && model !== originalModel) {
955
- // Estimated token savings: cheap model costs ~5x less, so avg prompt of ~800 tokens saves ~640 tokens
956
- const estimatedPromptTokens = Math.floor(prompt.length / 4);
957
- const routingSavings = Math.floor(estimatedPromptTokens * 0.8); // conservative 80% cost reduction
958
- SavingsLedger_1.savingsLedger.recordTokens('complexityRouting', routingSavings);
959
- }
960
- // Apply the Agent Multiplexer to local-verify the prompt in parallel
961
- const enrichedPrompt = await agentMultiplexer.multiplexPrompt(prompt, model);
962
- // Resolve conversation session key and retrieve/create the fileHistory map
963
- let fileHistory;
964
- if (req.body.messages && req.body.messages.length > 0) {
965
- try {
966
- const firstMsg = req.body.messages[0];
967
- const content = typeof firstMsg.content === 'string' ? firstMsg.content : JSON.stringify(firstMsg.content);
968
- const sessionKey = crypto_1.default.createHash('sha1').update(content).digest('hex');
969
- if (!this.sessions.has(sessionKey)) {
970
- this.sessions.set(sessionKey, { fileHistory: new Map() });
971
- }
972
- fileHistory = this.sessions.get(sessionKey).fileHistory;
973
- }
974
- catch { }
975
- }
976
- // Compress long TS/JS codebase file blocks in the enriched prompt using the Context Squeezer AST Tree-Shaker!
977
- // The query context is the user's primary prompt to ensure we keep relevant methods!
978
- const squeezeResult = (0, ContextSqueezer_1.squeezePrompt)(enrichedPrompt, prompt, fileHistory);
979
- const squeezedPrompt = squeezeResult.squeezed;
980
- const compressionSavings = squeezeResult.originalSize - squeezeResult.squeezedSize;
981
- if (compressionSavings > 0) {
982
- SavingsLedger_1.savingsLedger.record('contextSqueeze', squeezeResult.originalSize, squeezeResult.squeezedSize);
983
- console.log(`⚡ [Squeezer] Compressed prompt from ${squeezeResult.originalSize} to ${squeezeResult.squeezedSize} chars (Saved ${(squeezeResult.compressionRatio * 100).toFixed(1)}% context tokens!)`);
984
- }
985
- if (provider === 'openai' || provider === 'anthropic') {
986
- if (req.body.messages && req.body.messages.length > 0) {
987
- injectSqueezedContent(req.body.messages[req.body.messages.length - 1], squeezedPrompt);
988
- // Apply conversational history pruning to save tokens on historical messages!
989
- const pruneResult = (0, ContextSqueezer_1.pruneHistoryMessages)(req.body.messages);
990
- req.body.messages = pruneResult.messages;
991
- historyTokensSaved = pruneResult.tokensSavedEstimate + Math.floor(compressionSavings / 4);
992
- if (pruneResult.tokensSavedEstimate > 0) {
993
- SavingsLedger_1.savingsLedger.recordTokens('historyPrune', pruneResult.tokensSavedEstimate);
994
- }
995
- }
996
- }
997
- else if (provider === 'gemini') {
998
- if (req.body.contents && req.body.contents.length > 0) {
999
- const lastContent = req.body.contents[req.body.contents.length - 1];
1000
- if (lastContent.parts && lastContent.parts.length > 0) {
1001
- lastContent.parts[lastContent.parts.length - 1].text = squeezedPrompt;
1002
- }
1003
- }
1004
- }
1016
+ // ── 1. Cache-First Hot Path ──
1017
+ // Perform exact cache check immediately (resolves in <1ms)
1005
1018
  const hit = cacheGet(provider, prompt);
1006
1019
  if (hit) {
1007
- const cacheTokensSaved = 2000 + historyTokensSaved;
1020
+ const cacheTokensSaved = 2000;
1008
1021
  SavingsLedger_1.savingsLedger.recordTokens('cache', cacheTokensSaved);
1009
1022
  await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, cacheTokensSaved);
1010
1023
  const unmaskedData = semanticScrubber.unmask(hit.data, tokenMap);
1011
1024
  if (isStream)
1012
- return simulateHitStream(res, unmaskedData, provider, model, tier, 1.0);
1025
+ return simulateHitStream(res, unmaskedData, provider, originalModel, tier, 1.0);
1013
1026
  res.setHeader('X-Lemma-Cache', 'HIT');
1014
1027
  res.setHeader('X-Lemma-Similarity', '1.000');
1015
1028
  res.setHeader('X-Lemma-Tier', tier);
1016
1029
  return res.json(unmaskedData);
1017
1030
  }
1031
+ // Perform semantic cache check (resolves in ~15ms)
1018
1032
  if (pro) {
1019
1033
  const semHit = await semanticGet(provider, prompt);
1020
1034
  if (semHit) {
1021
1035
  if (semHit.similarity >= 0.90) {
1022
- await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000 + historyTokensSaved);
1036
+ await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000);
1023
1037
  const unmaskedData = semanticScrubber.unmask(semHit.data, tokenMap);
1024
1038
  if (isStream)
1025
- return simulateHitStream(res, unmaskedData, provider, model, tier, semHit.similarity);
1039
+ return simulateHitStream(res, unmaskedData, provider, originalModel, tier, semHit.similarity);
1026
1040
  res.setHeader('X-Lemma-Cache', 'HIT');
1027
1041
  res.setHeader('X-Lemma-Similarity', semHit.similarity.toFixed(3));
1028
1042
  res.setHeader('X-Lemma-Tier', tier);
1029
1043
  return res.json(unmaskedData);
1030
1044
  }
1031
- else if (semHit.similarity >= 0.70) {
1045
+ else if (semHit.similarity >= 0.82) { // raised from 0.70 to 0.82 to prevent false positives
1032
1046
  console.log(`💡 [CARS] Near Cache Hit (Similarity: ${(semHit.similarity * 100).toFixed(1)}%). Synthesizing answer locally via Ollama...`);
1033
1047
  let cachedContent = '';
1034
1048
  if (provider === 'openai') {
@@ -1066,10 +1080,10 @@ Adjusted Answer:`;
1066
1080
  else if (provider === 'anthropic') {
1067
1081
  synthesizedData.content[0].text = adjustedText;
1068
1082
  }
1069
- await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000 + historyTokensSaved);
1083
+ await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000);
1070
1084
  const unmaskedData = semanticScrubber.unmask(synthesizedData, tokenMap);
1071
1085
  if (isStream) {
1072
- return simulateHitStream(res, unmaskedData, provider, model, tier, semHit.similarity);
1086
+ return simulateHitStream(res, unmaskedData, provider, originalModel, tier, semHit.similarity);
1073
1087
  }
1074
1088
  res.setHeader('X-Lemma-Cache', 'HIT-CARS');
1075
1089
  res.setHeader('X-Lemma-Similarity', semHit.similarity.toFixed(3));
@@ -1086,22 +1100,86 @@ Adjusted Answer:`;
1086
1100
  const cloudHit = await cloudSync.get(prompt);
1087
1101
  if (cloudHit) {
1088
1102
  cacheSet(provider, prompt, cloudHit.data);
1089
- await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000 + historyTokensSaved);
1103
+ await recordStat(this.stats, this.projectName, true, Date.now() - t0, provider, 2000);
1090
1104
  const unmaskedData = semanticScrubber.unmask(cloudHit.data, tokenMap);
1091
1105
  if (isStream)
1092
- return simulateHitStream(res, unmaskedData, provider, model, tier, cloudHit.similarity || 0.95);
1106
+ return simulateHitStream(res, unmaskedData, provider, originalModel, tier, cloudHit.similarity || 0.95);
1093
1107
  res.setHeader('X-Lemma-Cache', 'HIT');
1094
1108
  res.setHeader('X-Lemma-Similarity', (cloudHit.similarity || 0.95).toFixed(3));
1095
1109
  res.setHeader('X-Lemma-Tier', tier);
1096
1110
  return res.json(unmaskedData);
1097
1111
  }
1098
1112
  }
1113
+ // ── 2. Cache Miss Path ──
1114
+ const routingDecision = complexityRouter.evaluate(prompt, originalModel);
1115
+ const model = routingDecision.model;
1116
+ if (req.body.model)
1117
+ req.body.model = model;
1118
+ // Record complexity routing savings when model is downgraded
1119
+ if (routingDecision.complexity === 'low' && model !== originalModel) {
1120
+ const estimatedPromptTokens = Math.floor(prompt.length / 4);
1121
+ const routingSavings = Math.floor(estimatedPromptTokens * 0.8);
1122
+ SavingsLedger_1.savingsLedger.recordTokens('complexityRouting', routingSavings);
1123
+ }
1124
+ // Apply the Agent Multiplexer to local-verify the prompt in parallel
1125
+ const enrichedPrompt = await agentMultiplexer.multiplexPrompt(prompt, model);
1126
+ // Resolve conversation session key and retrieve/create the fileHistory map
1127
+ let fileHistory;
1128
+ if (req.body.messages && req.body.messages.length > 0) {
1129
+ try {
1130
+ const firstMsg = req.body.messages[0];
1131
+ const content = typeof firstMsg.content === 'string' ? firstMsg.content : JSON.stringify(firstMsg.content);
1132
+ const sessionKey = crypto_1.default.createHash('sha1').update(content).digest('hex');
1133
+ if (!this.sessions.has(sessionKey)) {
1134
+ // Enforce 500 active sessions cap to prevent memory leak (FIFO eviction)
1135
+ const MAX_SESSIONS = 500;
1136
+ if (this.sessions.size >= MAX_SESSIONS) {
1137
+ const oldestKey = this.sessions.keys().next().value;
1138
+ if (oldestKey)
1139
+ this.sessions.delete(oldestKey);
1140
+ }
1141
+ this.sessions.set(sessionKey, { fileHistory: new Map() });
1142
+ }
1143
+ fileHistory = this.sessions.get(sessionKey).fileHistory;
1144
+ }
1145
+ catch { }
1146
+ }
1147
+ // Compress long TS/JS codebase file blocks in the enriched prompt
1148
+ const squeezeResult = (0, ContextSqueezer_1.squeezePrompt)(enrichedPrompt, prompt, fileHistory);
1149
+ const squeezedPrompt = squeezeResult.squeezed;
1150
+ const compressionSavings = squeezeResult.originalSize - squeezeResult.squeezedSize;
1151
+ if (compressionSavings > 0) {
1152
+ SavingsLedger_1.savingsLedger.record('contextSqueeze', squeezeResult.originalSize, squeezeResult.squeezedSize);
1153
+ console.log(`⚡ [Squeezer] Compressed prompt from ${squeezeResult.originalSize} to ${squeezeResult.squeezedSize} chars (Saved ${(squeezeResult.compressionRatio * 100).toFixed(1)}% context tokens!)`);
1154
+ }
1155
+ if (provider === 'openai' || provider === 'anthropic') {
1156
+ if (req.body.messages && req.body.messages.length > 0) {
1157
+ injectSqueezedContent(req.body.messages[req.body.messages.length - 1], squeezedPrompt);
1158
+ // Apply conversational history pruning
1159
+ const pruneResult = (0, ContextSqueezer_1.pruneHistoryMessages)(req.body.messages);
1160
+ req.body.messages = pruneResult.messages;
1161
+ historyTokensSaved = pruneResult.tokensSavedEstimate + Math.floor(compressionSavings / 4);
1162
+ if (pruneResult.tokensSavedEstimate > 0) {
1163
+ SavingsLedger_1.savingsLedger.recordTokens('historyPrune', pruneResult.tokensSavedEstimate);
1164
+ }
1165
+ }
1166
+ }
1167
+ else if (provider === 'gemini') {
1168
+ if (req.body.contents && req.body.contents.length > 0) {
1169
+ const lastContent = req.body.contents[req.body.contents.length - 1];
1170
+ if (lastContent.parts && lastContent.parts.length > 0) {
1171
+ lastContent.parts[lastContent.parts.length - 1].text = squeezedPrompt;
1172
+ }
1173
+ }
1174
+ }
1099
1175
  if (isStream) {
1100
1176
  await recordStat(this.stats, this.projectName, false, Date.now() - t0, provider, historyTokensSaved);
1101
1177
  if (!pro) {
1102
- const u = await loadUsage();
1103
- u.count++;
1104
- await writeJson(USAGE_FILE, u);
1178
+ await usageWriteQueue.enqueue(async () => {
1179
+ const u = await loadUsage();
1180
+ u.count++;
1181
+ await writeJson(USAGE_FILE, u);
1182
+ });
1105
1183
  }
1106
1184
  return relayMissStream(res, req.body, provider, tier);
1107
1185
  }
@@ -1113,9 +1191,11 @@ Adjusted Answer:`;
1113
1191
  await cloudSync.set(prompt, data);
1114
1192
  }
1115
1193
  if (!pro) {
1116
- const u = await loadUsage();
1117
- u.count++;
1118
- await writeJson(USAGE_FILE, u);
1194
+ await usageWriteQueue.enqueue(async () => {
1195
+ const u = await loadUsage();
1196
+ u.count++;
1197
+ await writeJson(USAGE_FILE, u);
1198
+ });
1119
1199
  }
1120
1200
  await recordStat(this.stats, this.projectName, false, Date.now() - t0, provider, historyTokensSaved);
1121
1201
  return res.json(semanticScrubber.unmask(data, tokenMap));
@@ -1152,6 +1232,15 @@ Adjusted Answer:`;
1152
1232
  }
1153
1233
  async start() {
1154
1234
  this.stats = await loadStats();
1235
+ // Start active cache eviction sweep every hour
1236
+ setInterval(() => {
1237
+ const now = Date.now();
1238
+ for (const [k, e] of CACHE.entries()) {
1239
+ if (e.ttl > 0 && now - e.createdAt > e.ttl) {
1240
+ CACHE.delete(k);
1241
+ }
1242
+ }
1243
+ }, 3600000).unref();
1155
1244
  const server = http_1.default.createServer(this.app);
1156
1245
  server.on('error', (e) => {
1157
1246
  if (e.code === 'EADDRINUSE') {