adaptive-memory-multi-model-router 1.7.2 → 1.8.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.
package/dist/cli.js CHANGED
@@ -1,59 +1,199 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * TMLPD PI CLI
3
+ * A3M Router CLI - Adaptive Memory Multi-Model Router
4
+ *
5
+ * Usage:
6
+ * npx a3m-router route "Write a Python function"
7
+ * npx a3m-router status
8
+ * npx a3m-router memory add "text"
9
+ * npx a3m-router cost
4
10
  */
5
11
 
6
- const { createTMLPD } = require("./dist/index.js");
12
+ const { createA3MRouter, countTokens, estimateCost, MODEL_COSTS } = require("./index.js");
7
13
 
8
14
  const args = process.argv.slice(2);
9
15
  const command = args[0];
10
16
 
17
+ function formatRoute(result) {
18
+ console.log("\nšŸ”€ A3M Router — Route Result");
19
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
20
+ console.log(" Primary: " + result.primary_model);
21
+ if (result.fallback_models) {
22
+ console.log(" Fallbacks: " + result.fallback_models.join(", "));
23
+ }
24
+ if (result.estimated_cost) {
25
+ console.log(" Est. Cost: $" + result.estimated_cost.toFixed(6));
26
+ }
27
+ if (result.latency_tier) {
28
+ console.log(" Latency: " + result.latency_tier);
29
+ }
30
+ if (result.reason) {
31
+ console.log(" Reason: " + result.reason);
32
+ }
33
+ console.log("");
34
+ }
35
+
11
36
  async function main() {
37
+ const router = createA3MRouter({ memory: { maxSize: 1000 } });
38
+
12
39
  switch (command) {
13
- case "execute": {
14
- const tmlpd = createTMLPD();
15
- const prompt = args.slice(1).join(" ");
16
- const result = await tmlpd.execute(prompt);
17
- console.log(JSON.stringify(result, null, 2));
40
+ case "route": {
41
+ const query = args.slice(1).join(" ");
42
+ if (!query) {
43
+ console.error("Usage: npx a3m-router route \"your query here\"");
44
+ process.exit(1);
45
+ }
46
+ const result = router.route(query);
47
+ formatRoute(result);
18
48
  break;
19
49
  }
20
- case "parallel": {
21
- const tmlpd = createTMLPD();
22
- const models = args.slice(1).join(" ").split(",").map(m => m.trim());
23
- const prompt = "Compare these models";
24
- const result = await tmlpd.executeParallel(prompt, models);
25
- console.log(JSON.stringify(result, null, 2));
50
+
51
+ case "batch": {
52
+ const queries = args.slice(1);
53
+ if (queries.length === 0) {
54
+ console.error("Usage: npx a3m-router batch \"query1\" \"query2\" ...");
55
+ process.exit(1);
56
+ }
57
+ const results = router.routeBatch(queries);
58
+ console.log("\nšŸ”€ A3M Router — Batch Results");
59
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
60
+ results.forEach(function(r, i) {
61
+ console.log(" " + (i + 1) + ". \"" + queries[i].substring(0, 40) + "...\" → " + r.primary_model);
62
+ });
63
+ console.log("");
26
64
  break;
27
65
  }
28
- case "cost": {
29
- const tmlpd = createTMLPD();
30
- const summary = tmlpd.getCostSummary();
31
- console.log(JSON.stringify(summary, null, 2));
66
+
67
+ case "recommend": {
68
+ const task = args.slice(1).join(" ");
69
+ if (!task) {
70
+ console.error("Usage: npx a3m-router recommend \"coding\"");
71
+ process.exit(1);
72
+ }
73
+ const rec = router.recommend(task);
74
+ console.log("\nšŸŽÆ A3M Router — Recommendation");
75
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
76
+ console.log(JSON.stringify(rec, null, 2));
32
77
  break;
33
78
  }
79
+
34
80
  case "status": {
35
- const tmlpd = createTMLPD();
36
- const status = tmlpd.getProviderStatus();
37
- console.log(JSON.stringify(status, null, 2));
81
+ console.log("\nšŸ“Š A3M Router — Status");
82
+ console.log("━━━━━━━━━━━━━━━━━━━━━━");
83
+ console.log(" Version: 1.7.3");
84
+ console.log(" Exports: 66");
85
+ console.log(" Providers: 14");
86
+ console.log(" Integrations: 116");
87
+ console.log(" Keywords: 139");
88
+ console.log(" Subpaths: 11");
89
+ console.log(" Memory: āœ… MemoryTree + AutoFetch + ObsidianVault");
90
+ console.log(" Compression: āœ… Enhanced + ISON");
91
+ console.log(" Auth: āœ… OAuth 2.0 + PKCE");
92
+ console.log(" Cost: āœ… Tracking + Budgets");
93
+ console.log(" Cache: āœ… Prefix + Response");
94
+ console.log(" Routing: āœ… RouteLLM + Adaptive");
95
+ console.log(" Models known: " + Object.keys(MODEL_COSTS).length);
96
+ console.log("");
38
97
  break;
39
98
  }
40
- case "cache": {
41
- const tmlpd = createTMLPD();
42
- const stats = tmlpd.getCacheStats();
43
- console.log(JSON.stringify(stats, null, 2));
99
+
100
+ case "cost": {
101
+ const text = args.slice(1).join(" ") || "Hello world this is a test";
102
+ const tokens = countTokens(text);
103
+ var completionTokens = Math.ceil(tokens * 1.5);
104
+ var gpt4oCost = estimateCost(tokens, completionTokens, "gpt-4o");
105
+ var miniCost = estimateCost(tokens, completionTokens, "gpt-4o-mini");
106
+ var haikuCost = estimateCost(tokens, completionTokens, "claude-3-haiku");
107
+ var geminiCost = estimateCost(tokens, completionTokens, "gemini-2.0-flash");
108
+ console.log("\nšŸ’° A3M Router — Cost Estimate");
109
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
110
+ console.log(" Text: \"" + text.substring(0, 50) + "\"");
111
+ console.log(" Tokens: " + tokens);
112
+ console.log(" GPT-4o: $" + gpt4oCost.toFixed(6));
113
+ console.log(" GPT-4o-mini: $" + miniCost.toFixed(6));
114
+ console.log(" Claude Haiku: $" + haikuCost.toFixed(6));
115
+ console.log(" Gemini Flash: $" + geminiCost.toFixed(6));
116
+ if (gpt4oCost > 0) {
117
+ var savings = ((1 - miniCost / gpt4oCost) * 100).toFixed(1);
118
+ console.log(" Savings: " + savings + "% (mini vs GPT-4o)");
119
+ }
120
+ console.log("");
121
+ break;
122
+ }
123
+
124
+ case "models": {
125
+ console.log("\nšŸ“‹ A3M Router — Known Models");
126
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
127
+ var models = Object.entries(MODEL_COSTS);
128
+ models.forEach(function(entry) {
129
+ var name = entry[0];
130
+ var cost = entry[1];
131
+ console.log(" " + name.padEnd(25) + " in:$" + String(cost.input_per_1k).padEnd(6) + " out:$" + cost.output_per_1k);
132
+ });
133
+ console.log(" Total: " + models.length + " models");
134
+ console.log("");
44
135
  break;
45
136
  }
137
+
138
+ case "token": {
139
+ const text = args.slice(1).join(" ");
140
+ if (!text) {
141
+ console.error("Usage: npx a3m-router token \"your text here\"");
142
+ process.exit(1);
143
+ }
144
+ const tokens = countTokens(text);
145
+ console.log(" \"" + text + "\" → " + tokens + " tokens");
146
+ break;
147
+ }
148
+
149
+ case "memory": {
150
+ const subcmd = args[1];
151
+ if (subcmd === "add") {
152
+ const text = args.slice(2).join(" ");
153
+ router.memory.add(text, { metadata: { cli: true } });
154
+ console.log(" āœ… Added to memory: \"" + text.substring(0, 50) + "\"");
155
+ } else if (subcmd === "search") {
156
+ const query = args.slice(2).join(" ");
157
+ const results = router.memory.search(query);
158
+ console.log(" Found " + results.length + " results for \"" + query + "\"");
159
+ results.forEach(function(r, i) {
160
+ var content = r.content ? r.content.substring(0, 60) : JSON.stringify(r).substring(0, 60);
161
+ console.log(" " + (i + 1) + ". " + content);
162
+ });
163
+ } else {
164
+ const stats = router.memory.getStats();
165
+ console.log("\n🧠 A3M Router — Memory Stats");
166
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
167
+ console.log(JSON.stringify(stats, null, 2));
168
+ }
169
+ break;
170
+ }
171
+
46
172
  default:
47
- console.log(`TMLPD PI v1.0.0
48
-
49
- Usage:
50
- tmlpd-pi execute <prompt> Execute single prompt
51
- tmlpd-pi parallel <models> Execute in parallel
52
- tmlpd-pi cost Show cost summary
53
- tmlpd-pi status Show provider status
54
- tmlpd-pi cache Show cache stats
55
- `);
173
+ console.log("\nšŸ”€ A3M Router — Adaptive Memory Multi-Model Router");
174
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
175
+ console.log("");
176
+ console.log(" Commands:");
177
+ console.log(" route <query> Route query to best model");
178
+ console.log(" batch <q1> <q2>.. Route multiple queries");
179
+ console.log(" recommend <task> Get model recommendation");
180
+ console.log(" cost [text] Estimate token cost across models");
181
+ console.log(" models List known models + pricing");
182
+ console.log(" token <text> Count tokens");
183
+ console.log(" memory add <text> Add to memory tree");
184
+ console.log(" memory search <q> Search memory");
185
+ console.log(" memory Show memory stats");
186
+ console.log(" status Show router status");
187
+ console.log("");
188
+ console.log(" Examples:");
189
+ console.log(" npx a3m-router route \"Write a Python function to sort\"");
190
+ console.log(" npx a3m-router cost \"Hello world\"");
191
+ console.log(" npx a3m-router memory add \"Meeting notes from standup\"");
192
+ console.log("");
56
193
  }
57
194
  }
58
195
 
59
- main().catch(console.error);
196
+ main().catch(function(err) {
197
+ console.error("Error:", err.message);
198
+ process.exit(1);
199
+ });
@@ -236,5 +236,8 @@ class CostTracker {
236
236
  return [...this.history];
237
237
  }
238
238
  }
239
+ // Alias for convenience
240
+ CostTracker.prototype.getStatus = CostTracker.prototype.getSummary;
241
+
239
242
  exports.CostTracker = CostTracker;
240
243
  //# sourceMappingURL=costTracker.js.map
package/dist/index.js CHANGED
@@ -290,6 +290,10 @@ function createA3MRouter(config = {}) {
290
290
  const memoryTree = new memoryTree_1.MemoryTree(memory);
291
291
  const prefixCache = new (require("./cache/prefixCache").PrefixCache)(cache);
292
292
  const costTracker = new (require("./cost/costTracker").CostTracker)(cost);
293
+ // Alias getSummary as getStatus for convenience
294
+ if (typeof costTracker.getSummary === "function" && !costTracker.getStatus) {
295
+ costTracker.getStatus = costTracker.getSummary.bind(costTracker);
296
+ }
293
297
  const autoFetch = new autoFetch_1.AutoFetch(memory);
294
298
  const compression = new enhancedCompression_1.EnhancedCompression();
295
299
  const oauth = new oauth_1.OAuthManager();
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * Notion Integration - Pages, databases, and content management
4
+ */
5
+ class NotionIntegration {
6
+ constructor(apiKey, config = {}) {
7
+ this.apiKey = apiKey || process.env.NOTION_API_KEY;
8
+ this.baseUrl = 'https://api.notion.com/v1';
9
+ this.version = config.version || '2022-06-28';
10
+ }
11
+
12
+ async _request(endpoint, options = {}) {
13
+ const resp = await fetch(this.baseUrl + endpoint, {
14
+ method: options.method || 'GET',
15
+ headers: {
16
+ 'Authorization': 'Bearer ' + this.apiKey,
17
+ 'Notion-Version': this.version,
18
+ 'Content-Type': 'application/json',
19
+ },
20
+ body: options.body ? JSON.stringify(options.body) : undefined,
21
+ });
22
+ return resp.json();
23
+ }
24
+
25
+ // Pages
26
+ async createPage(parent, properties, children = []) {
27
+ return this._request('/pages', {
28
+ method: 'POST',
29
+ body: { parent, properties, children },
30
+ });
31
+ }
32
+
33
+ async getPage(pageId) {
34
+ return this._request('/pages/' + pageId);
35
+ }
36
+
37
+ async updatePage(pageId, properties) {
38
+ return this._request('/pages/' + pageId, {
39
+ method: 'PATCH',
40
+ body: { properties },
41
+ });
42
+ }
43
+
44
+ async deletePage(pageId) {
45
+ return this._request('/pages/' + pageId, {
46
+ method: 'PATCH',
47
+ body: { archived: true },
48
+ });
49
+ }
50
+
51
+ // Databases
52
+ async queryDatabase(databaseId, filter = {}, sorts = []) {
53
+ return this._request('/databases/' + databaseId + '/query', {
54
+ method: 'POST',
55
+ body: { filter, sorts },
56
+ });
57
+ }
58
+
59
+ async createDatabase(parent, title, properties) {
60
+ return this._request('/databases', {
61
+ method: 'POST',
62
+ body: { parent, title, properties },
63
+ });
64
+ }
65
+
66
+ async getDatabase(databaseId) {
67
+ return this._request('/databases/' + databaseId);
68
+ }
69
+
70
+ // Blocks
71
+ async getBlockChildren(blockId, pageSize = 100) {
72
+ return this._request('/blocks/' + blockId + '/children?page_size=' + pageSize);
73
+ }
74
+
75
+ async appendBlockChildren(blockId, children) {
76
+ return this._request('/blocks/' + blockId + '/children', {
77
+ method: 'PATCH',
78
+ body: { children },
79
+ });
80
+ }
81
+
82
+ // Search
83
+ async search(query, filter = {}) {
84
+ return this._request('/search', {
85
+ method: 'POST',
86
+ body: { query, filter },
87
+ });
88
+ }
89
+ }
90
+
91
+ module.exports = { NotionIntegration };
@@ -43,9 +43,11 @@ class MemoryTree {
43
43
  indexChunk(chunk) {
44
44
  const words = chunk.content.toLowerCase().split(/\s+/);
45
45
  for (const word of words) {
46
- if (word.length > 3) { // Skip short words
47
- if (!this.index.has(word)) this.index.set(word, new Set());
48
- this.index.get(word).add(chunk.id);
46
+ // Strip punctuation for better matching
47
+ const clean = word.replace(/[^a-z0-9-]/g, '');
48
+ if (clean.length > 3) { // Skip short words
49
+ if (!this.index.has(clean)) this.index.set(clean, new Set());
50
+ this.index.get(clean).add(chunk.id);
49
51
  }
50
52
  }
51
53
  }
@@ -73,8 +75,19 @@ class MemoryTree {
73
75
  let candidateIds = null;
74
76
 
75
77
  for (const word of words) {
76
- if (word.length <= 3) continue;
77
- const ids = this.index.get(word);
78
+ const clean = word.replace(/[^a-z0-9-]/g, '');
79
+ if (clean.length <= 3) continue;
80
+ // Try exact match first, then substring match
81
+ let ids = this.index.get(clean);
82
+ if (!ids) {
83
+ // Substring matching: find index keys containing this word
84
+ for (const [key, val] of this.index) {
85
+ if (key.includes(clean) || clean.includes(key)) {
86
+ ids = val;
87
+ break;
88
+ }
89
+ }
90
+ }
78
91
  if (ids) {
79
92
  if (!candidateIds) candidateIds = new Set(ids);
80
93
  else candidateIds = new Set([...candidateIds].filter(id => ids.has(id)));
@@ -108,12 +108,14 @@ const DEFAULT_PROVIDER_CONFIG = {
108
108
  maxTokens: 4096
109
109
  };
110
110
 
111
- module.exports = { ProviderRegistry };
111
+ const _routing = require("../routing/advancedRouter");
112
+ module.exports = {
113
+ ProviderRegistry,
114
+ routeQuery: _routing.routeQuery,
115
+ routeBatch: _routing.routeBatch,
116
+ recommendForTask: _routing.recommendForTask,
117
+ extractQueryFeatures: _routing.extractQueryFeatures,
118
+ MODEL_PROFILES: _routing.MODEL_PROFILES,
119
+ };
120
+
112
121
 
113
- // Re-export routing functions for convenience
114
- const advancedRouter = require("../routing/advancedRouter");
115
- Object.defineProperty(exports, "routeQuery", { enumerable: true, get: function () { return advancedRouter.routeQuery; } });
116
- Object.defineProperty(exports, "routeBatch", { enumerable: true, get: function () { return advancedRouter.routeBatch; } });
117
- Object.defineProperty(exports, "recommendForTask", { enumerable: true, get: function () { return advancedRouter.recommendForTask; } });
118
- Object.defineProperty(exports, "extractQueryFeatures", { enumerable: true, get: function () { return advancedRouter.extractQueryFeatures; } });
119
- Object.defineProperty(exports, "MODEL_PROFILES", { enumerable: true, get: function () { return advancedRouter.MODEL_PROFILES; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adaptive-memory-multi-model-router",
3
- "version": "1.7.2",
3
+ "version": "1.8.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.",