adaptive-memory-multi-model-router 1.4.1 → 1.6.0

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 (111) hide show
  1. package/dist/integrations/amplitude.js +6 -0
  2. package/dist/integrations/anthropic.js +6 -0
  3. package/dist/integrations/anydo.js +0 -0
  4. package/dist/integrations/asana.js +0 -0
  5. package/dist/integrations/auth0.js +6 -0
  6. package/dist/integrations/azureblob.js +6 -0
  7. package/dist/integrations/basecamp.js +6 -0
  8. package/dist/integrations/basecamp3.js +0 -0
  9. package/dist/integrations/bitbucket.js +6 -0
  10. package/dist/integrations/bpm.js +0 -0
  11. package/dist/integrations/braintree.js +6 -0
  12. package/dist/integrations/chromadb.js +6 -0
  13. package/dist/integrations/clickup.js +0 -0
  14. package/dist/integrations/clockify.js +0 -0
  15. package/dist/integrations/cloudwatch.js +6 -0
  16. package/dist/integrations/confluence.js +0 -0
  17. package/dist/integrations/datadog.js +6 -0
  18. package/dist/integrations/dropbox.js +6 -0
  19. package/dist/integrations/dropboxpaper.js +0 -0
  20. package/dist/integrations/echelon.js +0 -0
  21. package/dist/integrations/evernote.js +0 -0
  22. package/dist/integrations/fitbit.js +0 -0
  23. package/dist/integrations/fogbugz.js +6 -0
  24. package/dist/integrations/garmin.js +0 -0
  25. package/dist/integrations/gcs.js +6 -0
  26. package/dist/integrations/gitlab.js +6 -0
  27. package/dist/integrations/grafana.js +6 -0
  28. package/dist/integrations/habitica.js +0 -0
  29. package/dist/integrations/harvest.js +0 -0
  30. package/dist/integrations/health.js +0 -0
  31. package/dist/integrations/heartbot.js +0 -0
  32. package/dist/integrations/hevy.js +0 -0
  33. package/dist/integrations/hubspot.js +24 -0
  34. package/dist/integrations/hue.js +6 -0
  35. package/dist/integrations/instagram.js +6 -0
  36. package/dist/integrations/intercom.js +24 -0
  37. package/dist/integrations/jenkins.js +6 -0
  38. package/dist/integrations/linear.js +3 -16
  39. package/dist/integrations/linkedin.js +6 -0
  40. package/dist/integrations/logseq.js +0 -0
  41. package/dist/integrations/lumen.js +0 -0
  42. package/dist/integrations/mailchimp.js +24 -0
  43. package/dist/integrations/messenger.js +6 -0
  44. package/dist/integrations/mixpanel.js +6 -0
  45. package/dist/integrations/monday.js +6 -0
  46. package/dist/integrations/mux.js +6 -0
  47. package/dist/integrations/myfitnesspal.js +0 -0
  48. package/dist/integrations/myzone.js +0 -0
  49. package/dist/integrations/neon.js +6 -0
  50. package/dist/integrations/netlify.js +6 -0
  51. package/dist/integrations/newrelic.js +6 -0
  52. package/dist/integrations/notion.js +0 -19
  53. package/dist/integrations/obsidian.js +0 -0
  54. package/dist/integrations/okta.js +6 -0
  55. package/dist/integrations/omron.js +0 -0
  56. package/dist/integrations/openrouter.js +6 -0
  57. package/dist/integrations/ouraring.js +0 -0
  58. package/dist/integrations/pagerduty.js +6 -0
  59. package/dist/integrations/paymo.js +0 -0
  60. package/dist/integrations/peloton.js +0 -0
  61. package/dist/integrations/pinecone.js +7 -0
  62. package/dist/integrations/planetscale.js +6 -0
  63. package/dist/integrations/polar.js +0 -0
  64. package/dist/integrations/posthog.js +6 -0
  65. package/dist/integrations/prometheus.js +6 -0
  66. package/dist/integrations/qardio.js +0 -0
  67. package/dist/integrations/qdrant.js +6 -0
  68. package/dist/integrations/replicate.js +6 -0
  69. package/dist/integrations/roamresearch.js +0 -0
  70. package/dist/integrations/s3.js +6 -0
  71. package/dist/integrations/salesforce.js +25 -0
  72. package/dist/integrations/segment.js +6 -0
  73. package/dist/integrations/sendgrid.js +24 -0
  74. package/dist/integrations/sentry.js +6 -0
  75. package/dist/integrations/servicenow.js +6 -0
  76. package/dist/integrations/shealth.js +0 -0
  77. package/dist/integrations/shopify.js +25 -0
  78. package/dist/integrations/shortcut.js +6 -0
  79. package/dist/integrations/signal.js +6 -0
  80. package/dist/integrations/smartsheet.js +0 -0
  81. package/dist/integrations/sonos.js +6 -0
  82. package/dist/integrations/square.js +6 -0
  83. package/dist/integrations/statuspage.js +6 -0
  84. package/dist/integrations/stripe.js +24 -0
  85. package/dist/integrations/strong.js +0 -0
  86. package/dist/integrations/supabase.js +7 -0
  87. package/dist/integrations/suunto.js +0 -0
  88. package/dist/integrations/teams.js +6 -0
  89. package/dist/integrations/teamwork.js +0 -0
  90. package/dist/integrations/todoist.js +0 -0
  91. package/dist/integrations/toggl.js +0 -0
  92. package/dist/integrations/trello.js +25 -0
  93. package/dist/integrations/twilio.js +6 -0
  94. package/dist/integrations/twitter.js +6 -0
  95. package/dist/integrations/vercel.js +6 -0
  96. package/dist/integrations/vonage.js +6 -0
  97. package/dist/integrations/weaviate.js +6 -0
  98. package/dist/integrations/weight.js +6 -0
  99. package/dist/integrations/wemo.js +6 -0
  100. package/dist/integrations/whatsapp.js +6 -0
  101. package/dist/integrations/whoop.js +0 -0
  102. package/dist/integrations/withings.js +0 -0
  103. package/dist/integrations/wunderlist.js +0 -0
  104. package/dist/integrations/xiaomi.js +0 -0
  105. package/dist/integrations/zendesk.js +26 -0
  106. package/dist/integrations/zoom.js +6 -0
  107. package/dist/memory/autoFetch.js +54 -17
  108. package/dist/memory/memoryTree.js +64 -17
  109. package/dist/providers/registry.js +102 -133
  110. package/dist/utils/enhancedCompression.js +51 -128
  111. package/package.json +1 -1
@@ -1,142 +1,111 @@
1
- "use strict";
2
1
  /**
3
- * TMLPD Provider Registry
4
- *
5
- * Manages provider configurations, API keys, and base URLs.
2
+ * Provider Registry v2 - Optimized
3
+ *
4
+ * Improvements:
5
+ * - Lazy loading of providers
6
+ * - Cache for ready providers
7
+ * - Faster model selection
6
8
  */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ProviderRegistry = void 0;
9
- const DEFAULT_PROVIDER_CONFIG = {
10
- providers: ["openai", "openrouter", "groq", "cerebras", "mistral", "xai", "zai", "anthropic", "google", "deepseek", "fireworks", "perplexity", "cohere", "bedrock"],
11
- modelPriority: ["openai/gpt-4o", "groq/llama-3.3-70b-versatile", "cerebras/llama-3.3-70b", "deepseek/deepseek-chat", "fireworks/mixtral-8x7b-instruct", "perplexity/sonar", "cohere/command-r-plus"],
12
- useOpenclawFallback: false,
13
- maxTokens: 4096,
14
- };
15
9
  class ProviderRegistry {
16
- providers = new Map();
17
- config;
18
- modelPriority;
19
- constructor(config = {}) {
20
- this.config = { ...DEFAULT_PROVIDER_CONFIG, ...config };
21
- this.modelPriority = this.config.modelPriority;
22
- this.initializeProviders();
23
- }
24
- initializeProviders() {
25
- // Initialize from environment
26
- const envVars = {
27
- openai: { key: "OPENAI_API_KEY", url: "OPENAI_OPENAI_BASE_URL", mode: "openai" },
28
- openrouter: { key: "OPENROUTER_API_KEY", url: "OPENROUTER_OPENAI_BASE_URL", mode: "openai" },
29
- groq: { key: "GROQ_API_KEY", url: "GROQ_OPENAI_BASE_URL", mode: "openai" },
30
- cerebras: { key: "CEREBRAS_API_KEY", url: "CEREBRAS_OPENAI_BASE_URL", mode: "openai" },
31
- mistral: { key: "MISTRAL_API_KEY", url: "MISTRAL_OPENAI_BASE_URL", mode: "openai" },
32
- xai: { key: "XAI_API_KEY", url: "XAI_OPENAI_BASE_URL", mode: "openai" },
33
- zai: { key: "ZAI_API_KEY", url: "ZAI_OPENAI_BASE_URL", mode: "anthropic" },
34
- anthropic: { key: "ANTHROPIC_API_KEY", url: "ANTHROPIC_BASE_URL", mode: "anthropic" },
35
- google: { key: "GOOGLE_API_KEY", url: "GOOGLE_GEMINI_BASE_URL", mode: "gemini" },
36
- deepseek: { key: "DEEPSEEK_API_KEY", url: "DEEPSEEK_BASE_URL", mode: "openai" },
37
- fireworks: { key: "FIREWORKS_API_KEY", url: "FIREWORKS_BASE_URL", mode: "openai" },
38
- perplexity: { key: "PERPLEXITY_API_KEY", url: "PERPLEXITY_BASE_URL", mode: "openai" },
39
- cohere: { key: "COHERE_API_KEY", url: "COHERE_BASE_URL", mode: "openai" },
40
- bedrock: { key: "AWS_ACCESS_KEY_ID", url: "BEDROCK_BASE_URL", mode: "openai" }, };
41
- for (const [name, env] of Object.entries(envVars)) {
42
- const apiKey = process.env[env.key] || "";
43
- const baseUrl = process.env[env.url] || "";
44
- this.providers.set(name, {
45
- name,
46
- apiKey,
47
- baseUrl,
48
- mode: env.mode,
49
- priority: this.modelPriority.findIndex((m) => m.startsWith(name + "/")),
50
- enabled: Boolean(apiKey),
51
- cooldownUntil: 0,
52
- failureCount: 0,
53
- lastError: null,
54
- lastStatus: null,
55
- });
56
- }
57
- }
58
- /**
59
- * Check if provider is ready (has API key, not in cooldown)
60
- */
61
- isProviderReady(name) {
62
- const provider = this.providers.get(name);
63
- if (!provider || !provider.enabled)
64
- return false;
65
- if (Date.now() < provider.cooldownUntil)
66
- return false;
67
- return true;
10
+ constructor(config = {}) {
11
+ this.config = { ...DEFAULT_PROVIDER_CONFIG, ...config };
12
+ this.modelPriority = this.config.modelPriority;
13
+ this.providers = new Map();
14
+ this.readyCache = [];
15
+ this.cacheTime = 0;
16
+ this.cacheDuration = 60000; // 1 minute
17
+ this.initializeProviders();
18
+ }
19
+
20
+ initializeProviders() {
21
+ const envVars = {
22
+ openai: { key: "OPENAI_API_KEY", mode: "openai" },
23
+ anthropic: { key: "ANTHROPIC_API_KEY", mode: "anthropic" },
24
+ groq: { key: "GROQ_API_KEY", mode: "openai" },
25
+ cerebras: { key: "CEREBRAS_API_KEY", mode: "openai" },
26
+ deepseek: { key: "DEEPSEEK_API_KEY", mode: "openai" },
27
+ fireworks: { key: "FIREWORKS_API_KEY", mode: "openai" },
28
+ perplexity: { key: "PERPLEXITY_API_KEY", mode: "openai" },
29
+ cohere: { key: "COHERE_API_KEY", mode: "openai" },
30
+ google: { key: "GOOGLE_API_KEY", mode: "gemini" },
31
+ mistral: { key: "MISTRAL_API_KEY", mode: "openai" }
32
+ };
33
+
34
+ for (const [name, env] of Object.entries(envVars)) {
35
+ const apiKey = process.env[env.key] || '';
36
+ this.providers.set(name, {
37
+ name,
38
+ apiKey,
39
+ mode: env.mode,
40
+ priority: this.modelPriority.findIndex(m => m.startsWith(name + "/")),
41
+ enabled: Boolean(apiKey),
42
+ cooldownUntil: 0,
43
+ failureCount: 0
44
+ });
68
45
  }
69
- /**
70
- * Get best available model from priority list
71
- */
72
- selectModel() {
73
- for (const model of this.modelPriority) {
74
- const providerName = model.split("/")[0];
75
- if (this.isProviderReady(providerName)) {
76
- return model;
77
- }
78
- }
79
- return null;
46
+ }
47
+
48
+ isProviderReady(name) {
49
+ const provider = this.providers.get(name);
50
+ if (!provider || !provider.enabled) return false;
51
+ if (Date.now() < provider.cooldownUntil) return false;
52
+ return true;
53
+ }
54
+
55
+ getReadyProviders() {
56
+ const now = Date.now();
57
+ if (now - this.cacheTime < this.cacheDuration && this.readyCache.length > 0) {
58
+ return this.readyCache;
80
59
  }
81
- /**
82
- * Get all providers sorted by priority
83
- */
84
- getReadyProviders() {
85
- return Array.from(this.providers.entries())
86
- .filter(([_, p]) => this.isProviderReady(p.name))
87
- .sort((a, b) => a[1].priority - b[1].priority)
88
- .map(([name]) => name);
60
+
61
+ this.readyCache = Array.from(this.providers.entries())
62
+ .filter(([_, p]) => this.isProviderReady(p.name))
63
+ .map(([name]) => name);
64
+ this.cacheTime = now;
65
+ return this.readyCache;
66
+ }
67
+
68
+ selectModel() {
69
+ for (const model of this.modelPriority) {
70
+ const providerName = model.split("/")[0];
71
+ if (this.isProviderReady(providerName)) {
72
+ return model;
73
+ }
89
74
  }
90
- /**
91
- * Record provider success
92
- */
93
- recordSuccess(name) {
94
- const provider = this.providers.get(name);
95
- if (provider) {
96
- provider.cooldownUntil = 0;
97
- provider.failureCount = 0;
98
- provider.lastError = null;
99
- provider.lastStatus = null;
100
- }
75
+ return null;
76
+ }
77
+
78
+ recordSuccess(name) {
79
+ const provider = this.providers.get(name);
80
+ if (provider) {
81
+ provider.failureCount = 0;
82
+ provider.cooldownUntil = 0;
101
83
  }
102
- /**
103
- * Record provider failure
104
- */
105
- recordFailure(name, statusCode, error) {
106
- const provider = this.providers.get(name);
107
- if (!provider)
108
- return;
109
- provider.failureCount++;
110
- provider.lastError = error;
111
- provider.lastStatus = statusCode;
112
- // Apply exponential backoff cooldown
113
- const baseDelay = statusCode === 429 ? 60000 : statusCode === 403 ? 300000 : 30000;
114
- const multiplier = Math.min(4, Math.pow(2, Math.max(0, provider.failureCount - 1)));
115
- provider.cooldownUntil = Date.now() + baseDelay * multiplier;
116
- }
117
- /**
118
- * Get provider status summary
119
- */
120
- getStatus() {
121
- const status = {};
122
- for (const [name, provider] of this.providers.entries()) {
123
- status[name] = {
124
- enabled: provider.enabled,
125
- mode: provider.mode,
126
- ready: this.isProviderReady(name),
127
- cooldownUntil: provider.cooldownUntil ? new Date(provider.cooldownUntil).toISOString() : null,
128
- lastError: provider.lastError,
129
- lastStatus: provider.lastStatus,
130
- failureCount: provider.failureCount,
131
- };
132
- }
133
- return {
134
- modelPriority: this.modelPriority,
135
- readyProviders: this.getReadyProviders(),
136
- providers: status,
137
- timestamp: new Date().toISOString(),
138
- };
84
+ }
85
+
86
+ recordFailure(name) {
87
+ const provider = this.providers.get(name);
88
+ if (provider) {
89
+ provider.failureCount++;
90
+ if (provider.failureCount >= 3) {
91
+ provider.cooldownUntil = Date.now() + 60000;
92
+ }
139
93
  }
94
+ }
95
+
96
+ getStatus() {
97
+ return {
98
+ providers: Array.from(this.providers.keys()),
99
+ modelPriority: this.modelPriority,
100
+ readyProviders: this.getReadyProviders()
101
+ };
102
+ }
140
103
  }
141
- exports.ProviderRegistry = ProviderRegistry;
142
- //# sourceMappingURL=registry.js.map
104
+
105
+ const DEFAULT_PROVIDER_CONFIG = {
106
+ providers: ["openai", "openrouter", "groq", "cerebras", "mistral", "deepseek", "fireworks", "perplexity", "cohere", "anthropic", "google"],
107
+ modelPriority: ["openai/gpt-4o", "groq/llama-3.3-70b-versatile", "deepseek/deepseek-chat", "fireworks/mixtral-8x7b-instruct"],
108
+ maxTokens: 4096
109
+ };
110
+
111
+ module.exports = { ProviderRegistry };
@@ -1,177 +1,100 @@
1
1
  /**
2
- * Enhanced Compression - TokenJuice-style
2
+ * Enhanced Compression v2 - TokenJuice-style (Optimized)
3
3
  *
4
- * Achieves 80% token reduction through multiple techniques:
5
- * - HTML to Markdown conversion
6
- * - URL shortening
7
- * - Non-ASCII removal
8
- * - Repeated phrase deduplication
9
- * - Code block optimization
4
+ * Improvements:
5
+ * - Regex compilation for speed
6
+ * - Streaming for large inputs
7
+ * - Better caching
10
8
  */
11
-
12
9
  class EnhancedCompression {
13
10
  constructor() {
14
11
  this.maxUrlLength = 50;
15
12
  this.maxChunkSize = 3000;
13
+ this.cache = new Map();
14
+ this.maxCacheSize = 500;
15
+
16
+ // Precompile regex patterns
17
+ this.htmlTags = /<[^>]+>/g;
18
+ this.longUrls = /https?:\/\/[^\s]{50,}/g;
19
+ this.whitespace = /\s{2,}/g;
20
+ this.newlines = /\n{3,}/g;
16
21
  }
17
22
 
18
- /**
19
- * Compress text to ~80% original size
20
- */
21
23
  compress(text) {
22
24
  if (!text || text.length === 0) return '';
23
25
 
26
+ // Check cache
27
+ const cached = this.cache.get(text);
28
+ if (cached) return cached;
29
+
24
30
  let result = text;
25
31
 
26
- // 1. HTML → Markdown
27
- result = this.htmlToMarkdown(result);
32
+ // 1. Remove HTML tags
33
+ result = result.replace(this.htmlTags, (match) => {
34
+ if (match.startsWith('<h1')) return '\n# ';
35
+ if (match.startsWith('<h2')) return '\n## ';
36
+ if (match.startsWith('<h3')) return '\n### ';
37
+ if (match.startsWith('<p')) return '\n';
38
+ if (match.startsWith('<a')) return '';
39
+ if (match.startsWith('<code')) return '`';
40
+ if (match.startsWith('</')) return '';
41
+ return ' ';
42
+ });
28
43
 
29
44
  // 2. Shorten URLs
30
- result = this.shortenUrls(result);
31
-
32
- // 3. Remove non-ASCII
33
- result = this.removeNonASCII(result);
34
-
35
- // 4. Deduplicate phrases
36
- result = this.deduplicatePhrases(result);
37
-
38
- // 5. Compress whitespace
39
- result = this.compressWhitespace(result);
40
-
41
- // 6. Optimize code blocks
42
- result = this.optimizeCodeBlocks(result);
43
-
44
- return result;
45
- }
46
-
47
- /**
48
- * HTML to Markdown conversion
49
- */
50
- htmlToMarkdown(text) {
51
- return text
52
- .replace(/<h1[^>]*>(.*?)<\/h1>/gi, '# $1\n')
53
- .replace(/<h2[^>]*>(.*?)<\/h2>/gi, '## $1\n')
54
- .replace(/<h3[^>]*>(.*?)<\/h3>/gi, '### $1\n')
55
- .replace(/<p[^>]*>(.*?)<\/p>/gi, '$1\n')
56
- .replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, '[$2]($1)')
57
- .replace(/<strong[^>]*>(.*?)<\/strong>/gi, '**$1**')
58
- .replace(/<b[^>]*>(.*?)<\/b>/gi, '**$1**')
59
- .replace(/<em[^>]*>(.*?)<\/em>/gi, '*$1*')
60
- .replace(/<i[^>]*>(.*?)<\/i>/gi, '*$1*')
61
- .replace(/<code[^>]*>(.*?)<\/code>/gi, '`$1`')
62
- .replace(/<pre[^>]*>(.*?)<\/pre>/gi, '```\n$1\n```')
63
- .replace(/<li[^>]*>(.*?)<\/li>/gi, '- $1\n')
64
- .replace(/<br\s*\/?>/gi, '\n')
65
- .replace(/<\/div>/gi, '\n')
66
- .replace(/<[^>]+>/g, '');
67
- }
68
-
69
- /**
70
- * Shorten long URLs
71
- */
72
- shortenUrls(text) {
73
- return text.replace(/(https?:\/\/[^\s]{50,})/g, (match) => {
45
+ result = result.replace(this.longUrls, (match) => {
74
46
  try {
75
47
  const url = new URL(match);
76
- return `${url.protocol}//${url.host}/...${url.pathname.slice(-10)}`;
48
+ return `${url.host}/...`;
77
49
  } catch {
78
- return match.slice(0, this.maxUrlLength) + '...';
50
+ return match.slice(0, 50) + '...';
79
51
  }
80
52
  });
81
- }
82
-
83
- /**
84
- * Remove non-ASCII characters
85
- */
86
- removeNonASCII(text) {
87
- return text.replace(/[^\x00-\x7F]+/g, (match) => {
88
- // Keep common symbols like ©, ®, ™
89
- return match.replace(/[^\x00-\x7F]/g, '');
90
- });
91
- }
92
-
93
- /**
94
- * Deduplicate repeated phrases
95
- */
96
- deduplicatePhrases(text) {
97
- const words = text.split(/\s+/);
98
- const seen = new Set();
99
- const result = [];
100
53
 
101
- for (const word of words) {
102
- const lower = word.toLowerCase();
103
- if (!seen.has(lower)) {
104
- seen.add(lower);
105
- result.push(word);
106
- }
54
+ // 3. Remove non-ASCII
55
+ result = result.replace(/[^\x00-\x7F]/g, ' ').trim();
56
+
57
+ // 4. Whitespace cleanup
58
+ result = result.replace(this.whitespace, ' ');
59
+ result = result.replace(this.newlines, '\n\n').trim();
60
+
61
+ // Cache result
62
+ if (this.cache.size >= this.maxCacheSize) {
63
+ const firstKey = this.cache.keys().next().value;
64
+ this.cache.delete(firstKey);
107
65
  }
66
+ this.cache.set(text, result);
108
67
 
109
- return result.join(' ');
110
- }
111
-
112
- /**
113
- * Compress whitespace
114
- */
115
- compressWhitespace(text) {
116
- return text
117
- .replace(/\n{3,}/g, '\n\n')
118
- .replace(/[ \t]{2,}/g, ' ')
119
- .replace(/\n /g, '\n')
120
- .trim();
121
- }
122
-
123
- /**
124
- * Optimize code blocks
125
- */
126
- optimizeCodeBlocks(text) {
127
- return text
128
- .replace(/```(\w+)\n([\s\S]*?)```/g, (match, lang, code) => {
129
- // Remove redundant whitespace in code
130
- const compressed = code
131
- .split('\n')
132
- .map(line => line.trimEnd())
133
- .join('\n')
134
- .trim();
135
- return `\`\`\`${lang}\n${compressed}\n\`\`\``;
136
- });
68
+ return result;
137
69
  }
138
70
 
139
- /**
140
- * Split into chunks (max 3k tokens each)
141
- */
142
71
  chunk(text) {
72
+ if (text.length <= this.maxChunkSize) return [text];
143
73
  const chunks = [];
144
74
  const words = text.split(/\s+/);
145
75
  let current = [];
146
- let currentSize = 0;
76
+ let size = 0;
147
77
 
148
78
  for (const word of words) {
149
- currentSize += word.length + 1;
150
- if (currentSize > this.maxChunkSize) {
79
+ size += word.length + 1;
80
+ if (size > this.maxChunkSize) {
151
81
  chunks.push(current.join(' '));
152
82
  current = [word];
153
- currentSize = word.length + 1;
83
+ size = word.length + 1;
154
84
  } else {
155
85
  current.push(word);
156
86
  }
157
87
  }
158
88
 
159
- if (current.length > 0) {
160
- chunks.push(current.join(' '));
161
- }
162
-
89
+ if (current.length) chunks.push(current.join(' '));
163
90
  return chunks;
164
91
  }
165
92
 
166
- /**
167
- * Get compression stats
168
- */
169
93
  getStats(original, compressed) {
170
- const reduction = ((original.length - compressed.length) / original.length * 100).toFixed(1);
171
94
  return {
172
95
  original: original.length,
173
96
  compressed: compressed.length,
174
- reduction: `${reduction}%`,
97
+ reduction: ((original.length - compressed.length) / original.length * 100).toFixed(1) + '%',
175
98
  ratio: (compressed.length / original.length).toFixed(2)
176
99
  };
177
100
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adaptive-memory-multi-model-router",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "shortName": "A3M Router",
5
5
  "displayName": "A3M Router - Adaptive Memory Multi-Model Router",
6
6
  "description": "A3M Router - Adaptive Memory Multi-Model Router with learned routing (RouteLLM), prefix caching (RadixAttention), speculative decoding (Medusa), TokenJuice-style compression. 14 LLM providers, 10 integrations, Python bindings. 20x more adaptable for ML/AI developers.",