adaptive-memory-multi-model-router 2.14.17 → 2.14.19

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 (45) hide show
  1. package/AGENT_COUNCIL_FINDINGS.md +142 -0
  2. package/LAUNCH_CHECKLIST.md +141 -0
  3. package/README.md.bak +836 -0
  4. package/articles/CHINESE_SUBMISSIONS_READY.md +322 -0
  5. package/articles/DEVTO_READY.md +255 -0
  6. package/articles/HN_POST_READY.md +137 -0
  7. package/articles/INDIEHACKERS_READY.md +120 -0
  8. package/articles/NEWSLETTER_SEND_NOW.md +259 -0
  9. package/articles/PRODUCTHUNT_READY.md +106 -0
  10. package/articles/REDDIT_SUBMISSION_READY.md +348 -0
  11. package/articles/TWEET_STORM_READY.md +165 -0
  12. package/benchmark-results.json +24 -24
  13. package/council-votes/architecture-vote.md +121 -0
  14. package/council-votes/coverage-vote.md +93 -0
  15. package/dist/cost/costTracker.d.ts +109 -44
  16. package/dist/cost/costTracker.js +321 -98
  17. package/dist/cost/costTracker.js.map +1 -1
  18. package/dist/index.d.ts +6 -4
  19. package/dist/routing/advancedRouter.d.ts +38 -43
  20. package/dist/routing/advancedRouter.js +396 -408
  21. package/dist/routing/advancedRouter.js.map +1 -1
  22. package/dist/routing/providers/providerConfig.d.ts +49 -0
  23. package/dist/routing/providers/providerConfig.js +883 -0
  24. package/dist/routing/routing/advancedRouter.d.ts +62 -0
  25. package/dist/routing/routing/advancedRouter.js +447 -0
  26. package/dist/routing/utils/tokenUtils.d.ts +52 -0
  27. package/dist/routing/utils/tokenUtils.js +129 -0
  28. package/dist/server/proxyServer.d.ts +1 -1
  29. package/dist/utils/costUtils.d.ts +57 -0
  30. package/dist/utils/costUtils.js +150 -0
  31. package/dist/utils/costUtils.js.map +1 -0
  32. package/dist/utils/sorting.d.ts +12 -0
  33. package/dist/utils/sorting.js +37 -0
  34. package/dist/utils/sorting.js.map +1 -0
  35. package/package.json +1 -1
  36. package/research/ensemble-voting.md +324 -0
  37. package/research/loss-functions.md +545 -0
  38. package/research-log.md +49 -0
  39. package/src/cost/costTracker.ts +576 -0
  40. package/src/routing/advancedRouter.ts +540 -0
  41. package/src/utils/costUtils.ts +157 -0
  42. package/src/utils/sorting.ts +42 -0
  43. package/test-council/AGENT_COUNCIL_ARCHITECTURE.md +349 -0
  44. package/tests/security/guardrailEngine.test.ts +700 -0
  45. package/research/PUBLISH_LOG.md +0 -3
@@ -0,0 +1,121 @@
1
+ # Architecture Vote
2
+
3
+ **Project:** A3M Router Architecture Analysis
4
+ **Date:** 2026-06-03
5
+ **Agents:** 3 (Architecture, Performance, Test Coverage)
6
+ **Goal:** Identify top 3 improvements via council vote
7
+
8
+ ---
9
+
10
+ ## Architecture Vote
11
+
12
+ ### Finding 1: BROKEN MAIN ENTRY POINT (Critical)
13
+
14
+ **Files:**
15
+ - `src/index.ts` (lines 63, 112)
16
+ - `src/routing/advancedRouter.ts` (MISSING)
17
+ - `src/cost/costTracker.ts` (MISSING)
18
+
19
+ **Problem:** The main public API (`index.ts`) exports from modules that do not exist:
20
+ ```typescript
21
+ // Line 63 - MODULE NOT FOUND
22
+ export { CostTracker } from './cost/costTracker';
23
+
24
+ // Lines 110-112 - MODULE NOT FOUND
25
+ import { CostTracker } from './cost/costTracker';
26
+ ```
27
+
28
+ The `routing/advancedRouter.ts` is imported but never created - only `universal_router.py` (Python) exists.
29
+
30
+ **Solution:**
31
+ 1. Create `src/routing/advancedRouter.ts` as TypeScript wrapper around Python router, OR
32
+ 2. Consolidate routing into existing TypeScript modules (`crossModelValidation.ts`, `providerRetry.ts`)
33
+ 3. Replace missing `CostTracker` with existing `costAnalytics.ts` (already has full functionality)
34
+
35
+ **Deletion test:** FIXING SCATTERS complexity - deleting the broken exports would make the module load but lose public API surface. Must fix the imports properly.
36
+
37
+ ---
38
+
39
+ ### Finding 2: ROUTING LOGIC DUALITY (Python/TypeScript Boundary Leak)
40
+
41
+ **Files:**
42
+ - `src/routing/universal_router.py` (Python - learned routing, model profiles, online learning)
43
+ - `src/routing/providerRetry.ts` (TypeScript - thin wrapper)
44
+ - `src/ensemble.ts` (TypeScript - parallel execution, but assumes router works)
45
+ - `src/index.ts` (broken export chain)
46
+
47
+ **Problem:** The routing engine is split across two languages with no clear seam:
48
+ - `UniversalModelRouter` (Python) has all the ML logic: learned profiles, quality prediction, online learning
49
+ - TypeScript has fragments: `crossModelValidation.ts` (validator), `providerRetry.ts` (retry), `providerHealth.ts` (health)
50
+ - `ensemble.ts` calls `router.chat()` but router is undefined in TypeScript
51
+
52
+ The boundary leaks: `ensemble.ts` needs a router but can't access the Python `UniversalModelRouter` from TypeScript.
53
+
54
+ **Solution:**
55
+ 1. Implement routing logic in TypeScript for tight integration with ensemble
56
+ 2. Keep `universal_router.py` as optional optimization, not required
57
+ 3. Create `src/routing/index.ts` that exports unified routing interface
58
+
59
+ **Deletion test:** CONCENTRATES complexity - currently routing logic is scattered across 4+ files in 2 languages. Consolidation would reduce cognitive load.
60
+
61
+ ---
62
+
63
+ ### Finding 3: MEMORY SYSTEM FRAGMENTATION (6 implementations, no clear hierarchy)
64
+
65
+ **Files:**
66
+ - `src/memory/memoryTree.ts` (TypeScript, main)
67
+ - `src/memory/semantic_memory.py` (Python, ChromaDB optional)
68
+ - `src/memory/agentic_memory.py` (Python)
69
+ - `src/memory/working_memory.py` (Python)
70
+ - `src/memory/simple_memory.py` (Python)
71
+ - `src/memory/obsidianVault.ts` (TypeScript, export only)
72
+
73
+ **Problem:** 6 memory implementations with unclear purpose:
74
+ - No abstract base class or interface
75
+ - `MemoryTree.ts` has 3KB chunking, but Python memories have different semantics
76
+ - `semantic_memory.py` mentions "Memoria framework (arXiv:2512.12686)" but not integrated
77
+ - No clear path for when to use which memory
78
+
79
+ **Solution:**
80
+ 1. Create abstract `MemoryStore` interface in TypeScript
81
+ 2. Implement as `LocalMemoryStore` (current MemoryTree) and `SemanticMemoryStore` (current semantic_memory.py)
82
+ 3. Drop `agentic_memory.py`, `working_memory.py`, `simple_memory.py` if unused or consolidate
83
+
84
+ **Deletion test:** CONCENTRATES complexity - consolidating 6 memory implementations into 2 clear abstractions reduces the surface area significantly.
85
+
86
+ ---
87
+
88
+ ### Finding 4: PROVIDER CONFIG TIGHT COUPLING (47+ providers baked in)
89
+
90
+ **Files:**
91
+ - `src/providers/providerConfig.ts` (1000+ lines of hardcoded provider definitions)
92
+
93
+ **Problem:** 47+ providers are baked into a single 1000+ line file with no abstraction:
94
+ - Adding/removing providers requires modifying core code
95
+ - Provider-specific logic (format: openai/anthropic/google) is duplicated per-provider
96
+ - No plugin architecture for third-party providers
97
+
98
+ **Solution:**
99
+ 1. Create `ProviderAdapter` interface for API format handling (OpenAI, Anthropic, Google)
100
+ 2. Move provider definitions to `providers/` as individual files
101
+ 3. Implement registry pattern with hot-reload from config files
102
+
103
+ **Deletion test:** CONCENTRATES complexity - but splitting 1000 lines into 47 files creates new complexity. Better to create adapters and keep definitions data-driven.
104
+
105
+ ---
106
+
107
+ ## Vote: Priority Ranking
108
+
109
+ **I vote for Finding #1 (Broken Main Entry Point) as highest priority.**
110
+
111
+ **Rationale:** This is the only finding that currently BREAKS the build. The other findings are architectural debt, but Finding 1 prevents the public API from loading at all. No amount of internal refactoring matters if `import { A3MRouter } from 'adaptive-memory-multi-model-router'` fails.
112
+
113
+ **Implementation order:**
114
+ 1. **P0:** Fix broken imports in `src/index.ts`
115
+ 2. **P1:** Unify routing across Python/TypeScript boundary
116
+ 3. **P2:** Consolidate memory system into 2 clear implementations
117
+ 4. **P3:** Extract provider adapters from hardcoded config
118
+
119
+ ---
120
+
121
+ *Submitted by: Architecture Agent*
@@ -0,0 +1,93 @@
1
+ ## Test Coverage Vote
2
+
3
+ ### Finding 1: GuardrailEngine Has Zero Tests (CRITICAL)
4
+ - **Files:** `src/security/guardrails.ts` (500+ lines)
5
+ - **Problem:** Critical security module has NO tests despite handling:
6
+ - Prompt injection detection (DAN, jailbreak, ignore instructions)
7
+ - PII redaction (emails, phones, SSN, credit cards, API keys)
8
+ - Content filtering (violence, hate, self-harm)
9
+ - Output validation and hallucination detection
10
+ - **Solution:** Add comprehensive tests for:
11
+ - Each prompt injection pattern detection
12
+ - PII redaction for all types
13
+ - Content filter thresholds
14
+ - GuardrailEngine.checkInput() and checkOutput() full paths
15
+ - Custom guardrail registration
16
+ - Blocklist management
17
+ - **Tests gained:** ~25 tests covering security-critical paths
18
+
19
+ ### Finding 2: EnsembleOrchestrator Has Zero Tests (CORE P0)
20
+ - **Files:** `src/ensemble.ts`, `tests/routing/ensembleVoting.test.ts` (partial)
21
+ - **Problem:** Core P0 feature (parallel multi-LLM execution with result merging) has only partial tests in `tests/routing/`. The `EnsembleOrchestrator` class is NOT tested, and these critical paths are missing:
22
+ - Actual provider calls (mocked in ensembleVoting.test.ts)
23
+ - Majority voting strategy
24
+ - Weighted voting strategy
25
+ - Conservative strategy with uncertainty detection
26
+ - All-providers-fail error handling
27
+ - **Solution:** Add integration tests for EnsembleOrchestrator with:
28
+ - Mock providers returning different answers
29
+ - Strategy-specific voting logic
30
+ - Confidence scoring accuracy
31
+ - Reasoning generation
32
+ - **Tests gained:** ~15 tests for the unique differentiator
33
+
34
+ ### Finding 3: CostAnalytics Has Zero Tests (BUSINESS-CRITICAL)
35
+ - **Files:** `src/analytics/costAnalytics.ts`
36
+ - **Problem:** Cost tracking and savings calculation has no tests:
37
+ - No verification of savings calculation against known baselines
38
+ - No tests for BASELINE_COSTS accuracy
39
+ - No export format tests (JSON/CSV)
40
+ - No period filtering (hour/day/week/month)
41
+ - No auto-rotation when maxRecords exceeded
42
+ - **Solution:** Add tests for:
43
+ - Savings calculation accuracy (compare against known costs)
44
+ - Period filtering correctness
45
+ - Export format validation
46
+ - Provider/query type breakdown accuracy
47
+ - **Tests gained:** ~12 tests for cost accuracy
48
+
49
+ ### Finding 4: SDK Class (A3MRouter) Has Only Structure Tests
50
+ - **Files:** `src/sdk.ts`, `test-council/1-structure-tests.test.ts`
51
+ - **Problem:** SDK wrapper has basic type-checking but no behavioral tests:
52
+ - No tests for route() behavior
53
+ - No tests for analyze() feature extraction
54
+ - No tests for tier classification thresholds
55
+ - No tests for recommend() method
56
+ - **Solution:** Add behavioral tests verifying:
57
+ - Route decisions match expected patterns
58
+ - Feature extraction accuracy
59
+ - Tier classification boundaries (free/cheap/mid/premium)
60
+ - Batch routing consistency
61
+ - **Tests gained:** ~10 tests
62
+
63
+ ### Finding 5: Observability Middleware Not Tested
64
+ - **Files:** `src/observability/middleware.ts`
65
+ - **Problem:** Middleware components not tested:
66
+ - observabilityMiddleware not tested
67
+ - budgetAlertMiddleware not tested
68
+ - Integration with Express/Fastify not tested
69
+ - **Solution:** Add middleware tests verifying:
70
+ - Request/response interception
71
+ - Header injection
72
+ - Budget alert triggers
73
+ - Error propagation
74
+ - **Tests gained:** ~8 tests
75
+
76
+ ---
77
+
78
+ ## Vote
79
+
80
+ **I vote for Finding #1 (GuardrailEngine) as highest priority.**
81
+
82
+ ### Rationale:
83
+ 1. **Security-critical code without tests = production risk** - Prompt injection and PII handling bugs can leak sensitive data or bypass safety
84
+ 2. **Measurable impact** - Every user query goes through guardrails before routing
85
+ 3. **Clear scope** - 500+ lines with well-defined functions that are easy to test
86
+ 4. **Existing patterns** - The providerRetry.test.ts shows how to structure similar complex tests
87
+
88
+ ### Implementation estimate:
89
+ - **GuardrailEngine:** ~3 hours for comprehensive tests
90
+ - **EnsembleOrchestrator:** ~2 hours
91
+ - **CostAnalytics:** ~1.5 hours
92
+ - **SDK:** ~1 hour
93
+ - **Middleware:** ~1 hour
@@ -1,22 +1,109 @@
1
1
  /**
2
- * TMLPD Cost Tracker
2
+ * A3M Router - Budget Enforcer + Cost Tracker
3
3
  *
4
- * Tracks real-time spending across all providers.
5
- * Supports per-model budgets, spending alerts, and cost analysis.
4
+ * Hard budget enforcement for API key spend management:
5
+ * - Track spend per API key with monthly reset
6
+ * - Check budget before each request
7
+ * - Emit alerts at configurable thresholds (50%, 80%, 100%)
8
+ * - Support hard cap (reject requests) or soft cap (warn only)
9
+ * - In-memory storage (Redis backup can be added later)
10
+ *
11
+ * Plus legacy CostTracker for backward compatibility.
6
12
  */
13
+ import { EventEmitter } from 'events';
7
14
  export interface BudgetConfig {
8
- daily_limit?: number;
9
- monthly_limit?: number;
10
- per_model_limits?: Record<string, number>;
15
+ apiKey: string;
16
+ monthlyLimit: number;
17
+ alertThresholds?: number[];
18
+ hardCap?: boolean;
19
+ }
20
+ export interface SpendRecord {
21
+ apiKey: string;
22
+ spent: number;
23
+ budget: number;
24
+ remaining: number;
25
+ resetDate: Date;
26
+ alertEmitted: number[] | Set<number>;
27
+ }
28
+ export interface BudgetCheckResult {
29
+ allowed: boolean;
30
+ reason?: string;
31
+ remaining: number;
32
+ }
33
+ export declare class BudgetEnforcer extends EventEmitter {
34
+ budgets: Map<string, BudgetConfig>;
35
+ spend: Map<string, SpendRecord>;
36
+ static DEFAULT_THRESHOLDS: number[];
37
+ constructor();
38
+ /**
39
+ * Set budget for an API key
40
+ */
41
+ setBudget(apiKey: string, monthlyLimit: number, options?: {
42
+ alertThresholds?: number[];
43
+ hardCap?: boolean;
44
+ }): void;
45
+ /**
46
+ * Get current budget config for an API key
47
+ */
48
+ getBudgetConfig(apiKey: string): BudgetConfig | undefined;
49
+ /**
50
+ * Remove budget config (stops tracking)
51
+ */
52
+ removeBudget(apiKey: string): void;
53
+ /**
54
+ * Check if a request is allowed within budget
55
+ */
56
+ checkBudget(apiKey: string, additionalCost: number): BudgetCheckResult;
57
+ /**
58
+ * Record spend for an API key
59
+ */
60
+ recordSpend(apiKey: string, cost: number): void;
61
+ /**
62
+ * Get current spend record for an API key
63
+ */
64
+ getSpend(apiKey: string): SpendRecord | undefined;
65
+ /**
66
+ * Get all spend records
67
+ */
68
+ getAllSpend(): SpendRecord[];
69
+ /**
70
+ * Reset budget for an API key (manual reset)
71
+ */
72
+ resetBudget(apiKey: string): void;
73
+ /**
74
+ * Reset all budgets
75
+ */
76
+ resetAll(): void;
77
+ /**
78
+ * Update monthly limit for an API key
79
+ */
80
+ updateLimit(apiKey: string, monthlyLimit: number): void;
81
+ /**
82
+ * Check if reset is needed and perform it
83
+ */
84
+ checkAndReset(apiKey: string): void;
85
+ /**
86
+ * Check if monthly reset is due
87
+ */
88
+ isResetDue(resetDate: Date): boolean;
89
+ /**
90
+ * Get next monthly reset date
91
+ */
92
+ getNextResetDate(): Date;
93
+ /**
94
+ * Get days until next reset
95
+ */
96
+ getDaysUntilReset(apiKey: string): number | undefined;
11
97
  }
12
- export interface CostAlert {
13
- type: "daily" | "monthly" | "model" | "budget";
14
- threshold: number;
15
- current: number;
16
- provider?: string;
17
- model?: string;
98
+ export declare function createBudgetEnforcer(): BudgetEnforcer;
99
+ export declare class BudgetExceededError extends Error {
100
+ apiKey: string;
101
+ spent: number;
102
+ budget: number;
103
+ remaining: number;
104
+ constructor(apiKey: string, spent: number, budget: number);
18
105
  }
19
- export interface CostSnapshot {
106
+ interface CostSnapshot {
20
107
  provider: string;
21
108
  model: string;
22
109
  input_tokens: number;
@@ -26,7 +113,7 @@ export interface CostSnapshot {
26
113
  total_cost: number;
27
114
  timestamp: number;
28
115
  }
29
- export interface CostSummary {
116
+ interface CostSummary {
30
117
  total_cost: number;
31
118
  by_provider: Record<string, number>;
32
119
  by_model: Record<string, number>;
@@ -46,50 +133,28 @@ export declare class CostTracker {
46
133
  private alerts_callback;
47
134
  private daily_reset;
48
135
  private monthly_reset;
49
- constructor(budgets?: BudgetConfig);
50
- /**
51
- * Calculate cost for a model based on tokens
52
- */
136
+ constructor(budgets?: {
137
+ daily_limit?: number;
138
+ monthly_limit?: number;
139
+ per_model_limits?: Record<string, number>;
140
+ });
53
141
  calculateCost(model: string, input_tokens: number, output_tokens: number): {
54
142
  input: number;
55
143
  output: number;
56
144
  total: number;
57
145
  };
58
- /**
59
- * Record a request's cost
60
- */
61
146
  record(provider: string, model: string, input_tokens: number, output_tokens: number): CostSnapshot;
62
- /**
63
- * Check budgets and trigger alerts
64
- */
65
147
  private checkBudgets;
66
- /**
67
- * Emit an alert via callback
68
- */
69
148
  private emitAlert;
70
- /**
71
- * Register alert callback
72
- */
73
- onAlert(callback: (alert: CostAlert) => void): void;
74
- /**
75
- * Get comprehensive cost summary
76
- */
149
+ onAlert(callback: (alert: any) => void): void;
77
150
  getSummary(): CostSummary;
78
- /**
79
- * Get remaining budget
80
- */
81
151
  getRemainingBudget(): {
82
152
  daily: number | null;
83
153
  monthly: number | null;
84
154
  per_model: Record<string, number>;
85
155
  };
86
- /**
87
- * Reset cost history
88
- */
89
156
  reset(): void;
90
- /**
91
- * Export cost data for analysis
92
- */
93
157
  export(): CostSnapshot[];
158
+ getStatus(): CostSummary;
94
159
  }
95
- //# sourceMappingURL=costTracker.d.ts.map
160
+ export {};