adaptive-memory-multi-model-router 1.9.4 → 2.0.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/.github/ISSUE_TEMPLATE/bug_report.md +50 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +37 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +44 -0
- package/.github/workflows/npm-stats-validation.yml +152 -0
- package/.github/workflows/pages.yml +37 -0
- package/CHANGELOG.md +122 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +110 -0
- package/LAUNCH-PAIN-DRIVEN.md +339 -0
- package/LAUNCH.md +575 -0
- package/POPULARITY_BOOSTERS.md +285 -0
- package/README.md +231 -300
- package/SECURITY.md +69 -0
- package/articles/CONTENT_STRUCTURE.md +292 -0
- package/articles/DEVTO_COST_GUIDE.md +473 -0
- package/articles/DEVTO_FINAL.md +416 -0
- package/articles/DEVTO_MULTI_PROVIDER.md +542 -0
- package/articles/HN_10X_BETTER.md +430 -0
- package/articles/HN_CHINESE_STYLE.md +308 -0
- package/articles/HN_FINAL.md +199 -0
- package/articles/HN_POSTED_VERSION.md +56 -0
- package/articles/HN_RESEARCH.md +364 -0
- package/articles/PAIN-DRIVEN-devto-v2.md +308 -0
- package/articles/PAIN-DRIVEN-devto-v3.md +268 -0
- package/articles/PAIN-DRIVEN-devto.md +242 -0
- package/articles/PAIN-DRIVEN-hackernews-v2.md +138 -0
- package/articles/PAIN-DRIVEN-hackernews-v3.md +151 -0
- package/articles/PAIN-DRIVEN-hackernews.md +131 -0
- package/articles/PAIN-DRIVEN-reddit-v2.md +301 -0
- package/articles/PAIN-DRIVEN-reddit-v3.md +236 -0
- package/articles/PAIN-DRIVEN-reddit.md +218 -0
- package/articles/PAIN-DRIVEN-twitter-v2.md +110 -0
- package/articles/PAIN-DRIVEN-twitter-v3.md +121 -0
- package/articles/PAIN-DRIVEN-twitter.md +120 -0
- package/articles/PORTKEY_VS_A3M.md +147 -0
- package/articles/REDDIT_FINAL.md +232 -0
- package/articles/TWITTER_FINAL.md +167 -0
- package/articles/WHY_10X_BETTER.md +261 -0
- package/articles/WHY_CHINESE_STYLE_BETTER.md +323 -0
- package/articles/ai-discoverability-llm-routing.md +210 -0
- package/articles/devto-llm-routing.md +109 -0
- package/articles/hackernews-show-hn.md +65 -0
- package/articles/hashnode-llm-cost-optimization.md +125 -0
- package/articles/medium-building-llm-router.md +205 -0
- package/articles/reddit-ml.md +86 -0
- package/articles/twitter-thread-cost-savings.md +98 -0
- package/articles/youtube-tutorial-script.md +262 -0
- package/assets/banner.svg +109 -0
- package/assets/logo.svg +68 -0
- package/assets/social-preview.svg +64 -0
- package/demo/demo-script.md +53 -0
- package/dist/analytics/costAnalytics.d.ts +77 -0
- package/dist/analytics/costAnalytics.d.ts.map +1 -0
- package/dist/analytics/costAnalytics.js +219 -0
- package/dist/analytics/costAnalytics.js.map +1 -0
- package/dist/cache/semanticCache.d.ts +62 -0
- package/dist/cache/semanticCache.d.ts.map +1 -0
- package/dist/cache/semanticCache.js +176 -0
- package/dist/cache/semanticCache.js.map +1 -0
- package/dist/cli.js +35 -0
- package/dist/geo/generativeEngineOptimization.js +321 -0
- package/dist/geo/geoRouter.js +387 -0
- package/dist/index.d.ts +4 -723
- package/dist/index.js +11 -344
- package/dist/index.js.map +1 -1
- package/dist/integrations/langchainAdapter.d.ts +146 -0
- package/dist/integrations/langchainAdapter.d.ts.map +1 -0
- package/dist/integrations/langchainAdapter.js +731 -0
- package/dist/integrations/langchainAdapter.js.map +1 -0
- package/dist/integrations/oauth.d.ts +69 -0
- package/dist/integrations/oauth.d.ts.map +1 -0
- package/dist/integrations/oauth.js +225 -21
- package/dist/integrations/oauth.js.map +1 -0
- package/dist/memory/autoFetch.d.ts +39 -0
- package/dist/memory/autoFetch.d.ts.map +1 -0
- package/dist/memory/autoFetch.js +80 -88
- package/dist/memory/autoFetch.js.map +1 -0
- package/dist/memory/memoryTree.d.ts +76 -0
- package/dist/memory/memoryTree.d.ts.map +1 -0
- package/dist/memory/memoryTree.js +185 -130
- package/dist/memory/memoryTree.js.map +1 -0
- package/dist/memory/obsidianVault.d.ts +71 -0
- package/dist/memory/obsidianVault.d.ts.map +1 -0
- package/dist/memory/obsidianVault.js +207 -22
- package/dist/memory/obsidianVault.js.map +1 -0
- package/dist/providers/providerConfig.d.ts +49 -0
- package/dist/providers/providerConfig.d.ts.map +1 -0
- package/dist/providers/providerConfig.js +806 -401
- package/dist/providers/providerConfig.js.map +1 -0
- package/dist/security/guardrails.d.ts +76 -0
- package/dist/security/guardrails.d.ts.map +1 -0
- package/dist/security/guardrails.js +479 -0
- package/dist/security/guardrails.js.map +1 -0
- package/dist/security/inputValidation.js +351 -0
- package/dist/server/dashboard.d.ts +58 -0
- package/dist/server/dashboard.d.ts.map +1 -0
- package/dist/server/dashboard.js +553 -0
- package/dist/server/dashboard.js.map +1 -0
- package/dist/server/modelMapper.d.ts +43 -0
- package/dist/server/modelMapper.d.ts.map +1 -0
- package/dist/server/modelMapper.js +154 -0
- package/dist/server/modelMapper.js.map +1 -0
- package/dist/server/proxyServer.d.ts +41 -0
- package/dist/server/proxyServer.d.ts.map +1 -0
- package/dist/server/proxyServer.js +932 -0
- package/dist/server/proxyServer.js.map +1 -0
- package/dist/skills/__tests__/skill_manager.test.d.ts +2 -0
- package/dist/skills/__tests__/skill_manager.test.d.ts.map +1 -0
- package/dist/skills/__tests__/skill_manager.test.js +268 -0
- package/dist/skills/__tests__/skill_manager.test.js.map +1 -0
- package/docs/geo/GENERATIVE_ENGINE_OPTIMIZATION.md +232 -0
- package/docs-site/index.html +347 -0
- package/llms.txt +138 -0
- package/package.json +72 -7
- package/playground/README.md +51 -0
- package/playground/codesandbox.json +12 -0
- package/playground/index.js +39 -0
- package/scripts/update-npm-badges.js +158 -0
- package/src/analytics/costAnalytics.ts +304 -0
- package/src/cache/semanticCache.ts +221 -0
- package/src/index.ts +6 -0
- package/src/integrations/langchainAdapter.ts +955 -0
- package/src/providers/providerConfig.ts +923 -0
- package/src/security/guardrails.ts +585 -0
- package/src/server/dashboard.ts +610 -0
- package/src/server/modelMapper.ts +182 -0
- package/src/server/proxyServer.ts +1105 -0
- package/src/types/langchain.d.ts +83 -0
- package/tsconfig.build.json +20 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A3M Router - Semantic Cache
|
|
3
|
+
*
|
|
4
|
+
* Stores previous query->response pairs and returns cached responses
|
|
5
|
+
* for semantically similar queries using character n-gram Jaccard similarity.
|
|
6
|
+
*
|
|
7
|
+
* No external embedding API needed. Trigram overlap catches paraphrases like:
|
|
8
|
+
* "What is Python?" ≈ "Tell me about Python" ≈ "Explain Python"
|
|
9
|
+
* "Write a sort fn" ≈ "Create a sorting fn" ≈ "How to sort an array"
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// ============================================================
|
|
13
|
+
// Types
|
|
14
|
+
// ============================================================
|
|
15
|
+
|
|
16
|
+
export interface CachedResponse {
|
|
17
|
+
query: string;
|
|
18
|
+
response: string;
|
|
19
|
+
metadata?: any;
|
|
20
|
+
cachedAt: number;
|
|
21
|
+
hitCount: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SemanticCacheOptions {
|
|
25
|
+
maxSize?: number; // Max entries (default: 1000)
|
|
26
|
+
similarityThreshold?: number; // 0-1, min similarity for hit (default: 0.92)
|
|
27
|
+
ttl?: number; // TTL in ms (default: 3600000 = 1 hour)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface CacheEntry extends CachedResponse {
|
|
31
|
+
trigrams: Set<string>;
|
|
32
|
+
expiresAt: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SemanticCacheStats {
|
|
36
|
+
hits: number;
|
|
37
|
+
misses: number;
|
|
38
|
+
hitRate: number;
|
|
39
|
+
size: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ============================================================
|
|
43
|
+
// N-gram utilities
|
|
44
|
+
// ============================================================
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Normalize text: lowercase, collapse whitespace, strip punctuation edges.
|
|
48
|
+
*/
|
|
49
|
+
function normalize(text: string): string {
|
|
50
|
+
return text
|
|
51
|
+
.toLowerCase()
|
|
52
|
+
.replace(/\s+/g, " ")
|
|
53
|
+
.trim();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Extract character trigrams from text.
|
|
58
|
+
* Pads with spaces so short words still produce trigrams.
|
|
59
|
+
*/
|
|
60
|
+
function extractTrigrams(text: string): Set<string> {
|
|
61
|
+
const normalized = " " + normalize(text) + " ";
|
|
62
|
+
const trigrams = new Set<string>();
|
|
63
|
+
for (let i = 0; i <= normalized.length - 3; i++) {
|
|
64
|
+
trigrams.add(normalized.substring(i, i + 3));
|
|
65
|
+
}
|
|
66
|
+
return trigrams;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Compute Jaccard similarity between two sets.
|
|
71
|
+
* |A ∩ B| / |A ∪ B|
|
|
72
|
+
*/
|
|
73
|
+
function jaccard(a: Set<string>, b: Set<string>): number {
|
|
74
|
+
if (a.size === 0 && b.size === 0) return 1.0;
|
|
75
|
+
let intersection = 0;
|
|
76
|
+
for (const item of a) {
|
|
77
|
+
if (b.has(item)) intersection++;
|
|
78
|
+
}
|
|
79
|
+
const union = a.size + b.size - intersection;
|
|
80
|
+
return union === 0 ? 0 : intersection / union;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ============================================================
|
|
84
|
+
// Semantic Cache
|
|
85
|
+
// ============================================================
|
|
86
|
+
|
|
87
|
+
export class SemanticCache {
|
|
88
|
+
private entries: CacheEntry[] = [];
|
|
89
|
+
private maxSize: number;
|
|
90
|
+
private similarityThreshold: number;
|
|
91
|
+
private ttl: number;
|
|
92
|
+
private hits = 0;
|
|
93
|
+
private misses = 0;
|
|
94
|
+
|
|
95
|
+
constructor(options?: SemanticCacheOptions) {
|
|
96
|
+
this.maxSize = options?.maxSize ?? 1000;
|
|
97
|
+
this.similarityThreshold = options?.similarityThreshold ?? 0.92;
|
|
98
|
+
this.ttl = options?.ttl ?? 3600000; // 1 hour
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get cached response for a semantically similar query.
|
|
103
|
+
* Returns the best match above the similarity threshold, or null.
|
|
104
|
+
*/
|
|
105
|
+
async get(query: string): Promise<CachedResponse | null> {
|
|
106
|
+
const now = Date.now();
|
|
107
|
+
const queryTrigrams = extractTrigrams(query);
|
|
108
|
+
|
|
109
|
+
let bestEntry: CacheEntry | null = null;
|
|
110
|
+
let bestScore = 0;
|
|
111
|
+
|
|
112
|
+
for (const entry of this.entries) {
|
|
113
|
+
// Skip expired
|
|
114
|
+
if (now > entry.expiresAt) continue;
|
|
115
|
+
|
|
116
|
+
const score = jaccard(queryTrigrams, entry.trigrams);
|
|
117
|
+
if (score > bestScore) {
|
|
118
|
+
bestScore = score;
|
|
119
|
+
bestEntry = entry;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (bestEntry && bestScore >= this.similarityThreshold) {
|
|
124
|
+
this.hits++;
|
|
125
|
+
bestEntry.hitCount++;
|
|
126
|
+
return {
|
|
127
|
+
query: bestEntry.query,
|
|
128
|
+
response: bestEntry.response,
|
|
129
|
+
metadata: bestEntry.metadata,
|
|
130
|
+
cachedAt: bestEntry.cachedAt,
|
|
131
|
+
hitCount: bestEntry.hitCount,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
this.misses++;
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Store a query->response pair in the cache.
|
|
141
|
+
*/
|
|
142
|
+
async set(query: string, response: string, metadata?: any): Promise<void> {
|
|
143
|
+
const now = Date.now();
|
|
144
|
+
|
|
145
|
+
// Evict expired entries first
|
|
146
|
+
this.evictExpired();
|
|
147
|
+
|
|
148
|
+
// Evict oldest if at capacity
|
|
149
|
+
if (this.entries.length >= this.maxSize) {
|
|
150
|
+
this.evictOldest();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check if an exact-match entry already exists and update it
|
|
154
|
+
const normalized = normalize(query);
|
|
155
|
+
const existing = this.entries.find(
|
|
156
|
+
(e) => normalize(e.query) === normalized && now <= e.expiresAt
|
|
157
|
+
);
|
|
158
|
+
if (existing) {
|
|
159
|
+
existing.response = response;
|
|
160
|
+
existing.metadata = metadata;
|
|
161
|
+
existing.cachedAt = now;
|
|
162
|
+
existing.expiresAt = now + this.ttl;
|
|
163
|
+
existing.trigrams = extractTrigrams(query);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this.entries.push({
|
|
168
|
+
query,
|
|
169
|
+
response,
|
|
170
|
+
metadata,
|
|
171
|
+
cachedAt: now,
|
|
172
|
+
expiresAt: now + this.ttl,
|
|
173
|
+
hitCount: 0,
|
|
174
|
+
trigrams: extractTrigrams(query),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Clear all cache entries.
|
|
180
|
+
*/
|
|
181
|
+
clear(): void {
|
|
182
|
+
this.entries = [];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get cache statistics.
|
|
187
|
+
*/
|
|
188
|
+
getStats(): SemanticCacheStats {
|
|
189
|
+
const total = this.hits + this.misses;
|
|
190
|
+
return {
|
|
191
|
+
hits: this.hits,
|
|
192
|
+
misses: this.misses,
|
|
193
|
+
hitRate: total > 0 ? this.hits / total : 0,
|
|
194
|
+
size: this.entries.length,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Purge expired entries.
|
|
200
|
+
*/
|
|
201
|
+
private evictExpired(): void {
|
|
202
|
+
const now = Date.now();
|
|
203
|
+
this.entries = this.entries.filter((e) => now <= e.expiresAt);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Evict the oldest (by cachedAt) entry.
|
|
208
|
+
*/
|
|
209
|
+
private evictOldest(): void {
|
|
210
|
+
if (this.entries.length === 0) return;
|
|
211
|
+
let oldestIdx = 0;
|
|
212
|
+
let oldestTime = Infinity;
|
|
213
|
+
for (let i = 0; i < this.entries.length; i++) {
|
|
214
|
+
if (this.entries[i].cachedAt < oldestTime) {
|
|
215
|
+
oldestTime = this.entries[i].cachedAt;
|
|
216
|
+
oldestIdx = i;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
this.entries.splice(oldestIdx, 1);
|
|
220
|
+
}
|
|
221
|
+
}
|
package/src/index.ts
ADDED