adaptive-memory-multi-model-router 2.14.17 → 2.14.18
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/AGENT_COUNCIL_FINDINGS.md +142 -0
- package/LAUNCH_CHECKLIST.md +141 -0
- package/README.md.bak +836 -0
- package/articles/CHINESE_SUBMISSIONS_READY.md +322 -0
- package/articles/DEVTO_READY.md +255 -0
- package/articles/HN_POST_READY.md +137 -0
- package/articles/INDIEHACKERS_READY.md +120 -0
- package/articles/NEWSLETTER_SEND_NOW.md +259 -0
- package/articles/PRODUCTHUNT_READY.md +106 -0
- package/articles/REDDIT_SUBMISSION_READY.md +348 -0
- package/articles/TWEET_STORM_READY.md +165 -0
- package/council-votes/architecture-vote.md +121 -0
- package/council-votes/coverage-vote.md +93 -0
- package/dist/cost/costTracker.d.ts +109 -44
- package/dist/cost/costTracker.js +321 -98
- package/dist/cost/costTracker.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/routing/advancedRouter.d.ts +38 -43
- package/dist/routing/advancedRouter.js +394 -408
- package/dist/routing/advancedRouter.js.map +1 -1
- package/dist/routing/providers/providerConfig.d.ts +49 -0
- package/dist/routing/providers/providerConfig.js +883 -0
- package/dist/routing/routing/advancedRouter.d.ts +62 -0
- package/dist/routing/routing/advancedRouter.js +447 -0
- package/dist/routing/utils/tokenUtils.d.ts +52 -0
- package/dist/routing/utils/tokenUtils.js +129 -0
- package/dist/server/proxyServer.d.ts +1 -1
- package/package.json +1 -1
- package/research-log.md +49 -0
- package/src/cost/costTracker.ts +576 -0
- package/src/routing/advancedRouter.ts +536 -0
- package/test-council/AGENT_COUNCIL_ARCHITECTURE.md +349 -0
- package/tests/security/guardrailEngine.test.ts +700 -0
- package/research/PUBLISH_LOG.md +0 -3
|
@@ -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
|
-
*
|
|
2
|
+
* A3M Router - Budget Enforcer + Cost Tracker
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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?:
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
160
|
+
export {};
|