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.
- 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/benchmark-results.json +24 -24
- 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 +396 -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/dist/utils/costUtils.d.ts +57 -0
- package/dist/utils/costUtils.js +150 -0
- package/dist/utils/costUtils.js.map +1 -0
- package/dist/utils/sorting.d.ts +12 -0
- package/dist/utils/sorting.js +37 -0
- package/dist/utils/sorting.js.map +1 -0
- package/package.json +1 -1
- package/research/ensemble-voting.md +324 -0
- package/research/loss-functions.md +545 -0
- package/research-log.md +49 -0
- package/src/cost/costTracker.ts +576 -0
- package/src/routing/advancedRouter.ts +540 -0
- package/src/utils/costUtils.ts +157 -0
- package/src/utils/sorting.ts +42 -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,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quickselect algorithm for O(n) top-K selection
|
|
3
|
+
* Returns top k elements sorted descending by compare function
|
|
4
|
+
*
|
|
5
|
+
* Best case: O(n), Worst case: O(n log n), Average: O(n)
|
|
6
|
+
* vs Timsort O(n log n) for full sort + O(k log n) for top-k slice
|
|
7
|
+
*/
|
|
8
|
+
export function quickselectTopK<T>(
|
|
9
|
+
arr: T[],
|
|
10
|
+
k: number,
|
|
11
|
+
compare: (a: T) => number
|
|
12
|
+
): T[] {
|
|
13
|
+
if (arr.length <= k) {
|
|
14
|
+
return arr.slice().sort((a, b) => compare(b) - compare(a));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const pivotIndex = Math.floor(Math.random() * arr.length);
|
|
18
|
+
const pivotVal = compare(arr[pivotIndex]);
|
|
19
|
+
|
|
20
|
+
const left = arr.filter(a => compare(a) > pivotVal);
|
|
21
|
+
const right = arr.filter(a => compare(a) < pivotVal);
|
|
22
|
+
const middle = arr.filter(a => compare(a) === pivotVal);
|
|
23
|
+
|
|
24
|
+
if (left.length >= k) {
|
|
25
|
+
return quickselectTopK(left, k, compare);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const needed = k - left.length;
|
|
29
|
+
if (needed <= middle.length) {
|
|
30
|
+
return [...left, ...middle.slice(0, needed)];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return [...left, ...middle, ...quickselectTopK(right, k - left.length - middle.length, compare)];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Select top candidate using Quickselect
|
|
38
|
+
*/
|
|
39
|
+
export function selectTop<T>(arr: T[], compare: (a: T) => number): T | undefined {
|
|
40
|
+
const result = quickselectTopK(arr, 1, compare);
|
|
41
|
+
return result[0];
|
|
42
|
+
}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# Agent Council: Architecture Deepening Analysis
|
|
2
|
+
|
|
3
|
+
**Router:** adaptive-memory-multi-model-router (TMLPD)
|
|
4
|
+
**Date:** 2026-06-03
|
|
5
|
+
**Council Role:** Architecture Agent
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Executive Summary
|
|
10
|
+
|
|
11
|
+
The codebase has a **structural anomaly**: two critical modules are imported throughout the codebase but do not exist as TypeScript files. Beyond this, the architecture shows four high-value deepening candidates. The unique differentiator (ensemble parallel voting) is under-implemented relative to its strategic importance.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Anomaly: Missing TypeScript Modules
|
|
16
|
+
|
|
17
|
+
Two modules are exported and imported everywhere but have no corresponding `.ts` file:
|
|
18
|
+
|
|
19
|
+
| Missing File | Referenced In | Exported From |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `src/routing/advancedRouter.ts` | `src/index.ts`, `src/sdk.ts`, `src/server/modelMapper.ts` | `routeQuery`, `routeBatch`, `recommendForTask`, `extractQueryFeatures`, `MODEL_PROFILES`, `updateModelProfile`, `getProviderHealth` |
|
|
22
|
+
| `src/cost/costTracker.ts` | `src/index.ts`, `src/server/proxyServer.ts` | `CostTracker` class |
|
|
23
|
+
|
|
24
|
+
**Impact:** The main routing engine and cost recording system are entirely absent. The TypeScript routing layer is non-functional without these files. The Python `universal_router.py` partially fills this gap but has no TypeScript integration point.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Candidate 1: The Routing Engine Hole (P0)
|
|
29
|
+
|
|
30
|
+
### Files Affected
|
|
31
|
+
- **MISSING:** `src/routing/advancedRouter.ts`
|
|
32
|
+
- **AFFECTED:** `src/sdk.ts`, `src/server/modelMapper.ts`, `src/index.ts`
|
|
33
|
+
|
|
34
|
+
### Problem: Interface Without Implementation
|
|
35
|
+
|
|
36
|
+
The TypeScript surface area exports routing functions (`routeQuery`, `extractQueryFeatures`, `routeBatch`) but the file containing them does not exist. The `modelMapper.ts` imports from this non-existent file:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// modelMapper.ts line 5
|
|
40
|
+
import { routeQuery } from "../routing/advancedRouter"; // FILE DOES NOT EXIST
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The routing decision pipeline is split across three uncoordinated systems:
|
|
44
|
+
1. **TypeScript `modelMapper.ts`** (trivial: alias resolution only)
|
|
45
|
+
2. **TypeScript `proxyServer.ts`** (handles fallback chain manually)
|
|
46
|
+
3. **Python `universal_router.py`** (learned routing, but no TypeScript bridge)
|
|
47
|
+
|
|
48
|
+
### Solution: Implement `advancedRouter.ts`
|
|
49
|
+
|
|
50
|
+
Create `src/routing/advancedRouter.ts` as the single routing decision engine:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
src/routing/advancedRouter.ts
|
|
54
|
+
├── extractQueryFeatures() // Feature extraction (10+ signals)
|
|
55
|
+
├── MODEL_PROFILES // Static quality profiles per model
|
|
56
|
+
├── updateModelProfile() // Runtime profile updates
|
|
57
|
+
├── getProviderHealth() // Health status per provider
|
|
58
|
+
├── routeQuery() // Main routing decision
|
|
59
|
+
├── routeBatch() // Batch routing
|
|
60
|
+
└── recommendForTask() // Task-based recommendations
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This module should:
|
|
64
|
+
- Call `UniversalModelRouter` from Python via FFI/subprocess for learned routing
|
|
65
|
+
- Provide the TypeScript feature extraction layer (complexity, domain, code, math, multilingual signals)
|
|
66
|
+
- Manage the tier-based routing (free/cheap/mid/premium)
|
|
67
|
+
- Integrate with `ProviderHealthManager` for fallback chain ordering
|
|
68
|
+
|
|
69
|
+
### Benefits
|
|
70
|
+
- **Leverage:** Enables the full routing pipeline. Without this, the TypeScript SDK is non-functional.
|
|
71
|
+
- **Locality:** All routing logic in one place. Currently scattered across 3 files.
|
|
72
|
+
- **Testability:** Can unit-test feature extraction and routing decisions independently.
|
|
73
|
+
- **Seam quality:** Provides a clean interface for the Python learned router.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Candidate 2: Ensemble Voting is Shallow (P0 — Core Differentiator)
|
|
78
|
+
|
|
79
|
+
### Files Affected
|
|
80
|
+
- `src/ensemble.ts` (66 lines)
|
|
81
|
+
- `src/index.ts` (EnsembleOrchestrator)
|
|
82
|
+
|
|
83
|
+
### Problem: Shallow Module
|
|
84
|
+
|
|
85
|
+
The ARCHITECTURE.md claims the **ensemble parallel voting** is the unique differentiator — "Nobody does parallel multi-LLM execution with result merging." Yet the `EnsembleOrchestrator` class is 66 lines of naive code:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// ensemble.ts — current implementation
|
|
89
|
+
if (strategy === 'majority') {
|
|
90
|
+
const counts = {};
|
|
91
|
+
successful.forEach(r => counts[r.answer] = (counts[r.answer] || 0) + 1);
|
|
92
|
+
// ... naive string equality matching
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Problems:
|
|
97
|
+
1. **No parallel execution:** Uses `Promise.all` but treats results as independent strings
|
|
98
|
+
2. **No confidence weighting:** Doesn't use quality scores from provider responses
|
|
99
|
+
3. **No semantic similarity:** Uses exact string matching for voting — answers rarely match exactly
|
|
100
|
+
4. **No answer fusion:** Doesn't merge partial or complementary answers
|
|
101
|
+
5. **No model quality profiles:** Ignores the `MODEL_PROFILES` that should inform weighting
|
|
102
|
+
6. **Dead code:** `EnsembleOrchestrator` receives `router: A3MRouter` but the A3MRouter has no `.chat()` method — the ensemble can't actually call providers
|
|
103
|
+
|
|
104
|
+
### Solution: Deepen the Ensemble System
|
|
105
|
+
|
|
106
|
+
Split `ensemble.ts` into a proper subsystem:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
src/ensemble/
|
|
110
|
+
├── index.ts # EnsembleOrchestrator facade
|
|
111
|
+
├── parallelExecutor.ts # Promise.all parallel dispatch
|
|
112
|
+
├── semanticVoter.ts # Cosine-similarity-based answer voting
|
|
113
|
+
├── confidenceWeighter.ts # Model quality profile weighting
|
|
114
|
+
├── answerFusion.ts # Merge complementary partial answers
|
|
115
|
+
└── types.ts # EnsembleStrategy, EnsembleResult types
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Key improvements:
|
|
119
|
+
- **Semantic voting:** Embed provider answers and compute cosine similarity for fuzzy agreement
|
|
120
|
+
- **Confidence-weighted merging:** Use `MODEL_PROFILES` quality scores as vote weights
|
|
121
|
+
- **Partial answer fusion:** When no answer achieves consensus, merge the most complementary responses
|
|
122
|
+
- **Timeout-aware parallel:** Set per-provider timeouts and cancel slow providers
|
|
123
|
+
|
|
124
|
+
### Benefits
|
|
125
|
+
- **Leverage:** This IS the product's unique value. Currently it's marketing, not code.
|
|
126
|
+
- **Locality:** Ensemble logic isolated to its own subsystem.
|
|
127
|
+
- **Testability:** Each sub-component (voter, weighter, fusion) independently testable.
|
|
128
|
+
- **Strategic:** Reinforces the core competitive advantage.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Candidate 3: Cost Tracking System is Missing (P1)
|
|
133
|
+
|
|
134
|
+
### Files Affected
|
|
135
|
+
- **MISSING:** `src/cost/costTracker.ts`
|
|
136
|
+
- **AFFECTED:** `src/server/proxyServer.ts`, `src/index.ts`
|
|
137
|
+
|
|
138
|
+
### Problem: Incomplete Module
|
|
139
|
+
|
|
140
|
+
`proxyServer.ts` imports and instantiates `CostTracker`:
|
|
141
|
+
```typescript
|
|
142
|
+
import { CostTracker } from "../cost/costTracker"; // FILE DOES NOT EXIST
|
|
143
|
+
const costTracker = new CostTracker();
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The `CostAnalytics.ts` (304 lines) is fully implemented and rich. But the core `CostTracker` class it depends on is missing. This means cost recording at the proxy layer doesn't exist.
|
|
147
|
+
|
|
148
|
+
### Solution: Implement `costTracker.ts`
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// src/cost/costTracker.ts
|
|
152
|
+
export class CostTracker {
|
|
153
|
+
private records: Map<string, CostRecord[]>;
|
|
154
|
+
|
|
155
|
+
record(provider: string, model: string, inputTokens: number, outputTokens: number, latencyMs: number): void
|
|
156
|
+
getSummary(period?: 'hour' | 'day' | 'week' | 'month'): CostSummary
|
|
157
|
+
getByProvider(): Record<string, ProviderCostSummary>
|
|
158
|
+
getByModel(provider: string): Record<string, ModelCostSummary>
|
|
159
|
+
reset(): void
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
This should:
|
|
164
|
+
- Record every request with full metadata (provider, model, tokens, latency)
|
|
165
|
+
- Compute per-request cost using provider's `costPerK` rates
|
|
166
|
+
- Feed into `CostAnalytics` for aggregate reporting
|
|
167
|
+
- Provide the data layer that `costAnalytics.ts` operates on
|
|
168
|
+
|
|
169
|
+
### Benefits
|
|
170
|
+
- **Leverage:** Enables the cost tracking and savings reporting (key user value).
|
|
171
|
+
- **Locality:** Cost recording isolated to its own class.
|
|
172
|
+
- **Seam quality:** Clean interface between the proxy server and analytics.
|
|
173
|
+
- **Testability:** Can test cost calculations independently.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Candidate 4: Monolithic Provider Configuration (P1)
|
|
178
|
+
|
|
179
|
+
### Files Affected
|
|
180
|
+
- `src/providers/providerConfig.ts` (951 lines, single file)
|
|
181
|
+
|
|
182
|
+
### Problem: Shallow/Tightly-Coupled Monolith
|
|
183
|
+
|
|
184
|
+
All 40+ providers are defined in a single 951-line file with zero internal structure:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// All in one file:
|
|
188
|
+
export const DEFAULT_PROVIDERS: Record<string, ProviderDefinition> = {
|
|
189
|
+
ollama: { ... },
|
|
190
|
+
lmstudio: { ... },
|
|
191
|
+
groq: { ... },
|
|
192
|
+
// 40 more...
|
|
193
|
+
deepseek: { ... },
|
|
194
|
+
// ...all in one object
|
|
195
|
+
};
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Problems:
|
|
199
|
+
1. **Interface ≈ Implementation:** The file IS the data. Adding a provider requires editing the file.
|
|
200
|
+
2. **No lazy loading:** All providers initialized on import, even if API keys are missing.
|
|
201
|
+
3. **Testability:** Cannot test one provider's logic in isolation.
|
|
202
|
+
4. **Maintenance:** Hard to track provider-specific behavior (Chinese provider latency handling is scattered in `providerRetry.ts`).
|
|
203
|
+
5. **Coupling:** Provider definitions, config loading, runtime registration, and health checking all in one file.
|
|
204
|
+
|
|
205
|
+
### Solution: Provider Subsystem Deepening
|
|
206
|
+
|
|
207
|
+
Split into a provider subsystem:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
src/providers/
|
|
211
|
+
├── index.ts # Re-exports
|
|
212
|
+
├── types.ts # ProviderTier, ProviderFormat, ProviderType, ProviderDefinition
|
|
213
|
+
├── defaults/
|
|
214
|
+
│ ├── free.ts # Ollama, LM Studio, vLLM, Google, NVIDIA NIM
|
|
215
|
+
│ ├── cheap.ts # Groq, Cerebras, DeepInfra, Together, Fireworks...
|
|
216
|
+
│ ├── mid.ts # DeepSeek, Mistral, Perplexity, Cohere...
|
|
217
|
+
│ ├── premium.ts # OpenAI, Anthropic, xAI
|
|
218
|
+
│ └── enterprise.ts # Azure, Bedrock, Vertex
|
|
219
|
+
├── registry.ts # ProviderRegistry class (lazy loading, runtime registration)
|
|
220
|
+
├── loader.ts # Config file loading (JSON → ProviderDefinition[])
|
|
221
|
+
├── health.ts # ProviderHealth interface + checker
|
|
222
|
+
└── providerConfig.ts # Keep only the runtime API (registerProvider, getAvailableProviders)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Each tier file exports only its provider definitions:
|
|
226
|
+
```typescript
|
|
227
|
+
// src/providers/defaults/cheap.ts
|
|
228
|
+
export const CHEAP_PROVIDERS: ProviderDefinition[] = [
|
|
229
|
+
groqProvider(),
|
|
230
|
+
cerebrasProvider(),
|
|
231
|
+
// ...
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
function groqProvider(): ProviderDefinition {
|
|
235
|
+
return {
|
|
236
|
+
id: 'groq',
|
|
237
|
+
name: 'Groq',
|
|
238
|
+
baseUrl: 'https://api.groq.com/openai/v1/chat/completions',
|
|
239
|
+
// ...
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Benefits:
|
|
245
|
+
- **Leverage:** Lazy loading means only providers with valid API keys are initialized.
|
|
246
|
+
- **Locality:** Provider-specific behavior (timeout, retry config) co-located with the provider definition.
|
|
247
|
+
- **Testability:** Each provider factory function independently testable.
|
|
248
|
+
- **Seam quality:** Breaking the monolith creates clean seams between tiers.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Candidate 5: Proxy Server Monolith (P1)
|
|
253
|
+
|
|
254
|
+
### Files Affected
|
|
255
|
+
- `src/server/proxyServer.ts` (1105 lines, single file)
|
|
256
|
+
|
|
257
|
+
### Problem: God Object
|
|
258
|
+
|
|
259
|
+
The proxy server handles **6 distinct responsibilities** in one 1105-line file:
|
|
260
|
+
|
|
261
|
+
1. HTTP server setup + routing
|
|
262
|
+
2. OpenAI-compatible request parsing
|
|
263
|
+
3. Provider calls (OpenAI, Anthropic, Google, local)
|
|
264
|
+
4. Streaming SSE handling (5+ code paths)
|
|
265
|
+
5. Fallback chain logic
|
|
266
|
+
6. Request logging + health reporting
|
|
267
|
+
|
|
268
|
+
This makes it impossible to:
|
|
269
|
+
- Test streaming logic without a full HTTP server
|
|
270
|
+
- Swap the Anthropic API formatter independently
|
|
271
|
+
- Modify the fallback logic without touching provider call code
|
|
272
|
+
- Add a new API format (e.g., Cohere, AWS Bedrock) cleanly
|
|
273
|
+
|
|
274
|
+
### Solution: Deepen into Subsystem
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
src/server/
|
|
278
|
+
├── proxyServer.ts # Thin HTTP glue (~100 lines)
|
|
279
|
+
├── handlers/
|
|
280
|
+
│ ├── chatCompletions.ts # POST /v1/chat/completions
|
|
281
|
+
│ ├── completions.ts # POST /v1/completions
|
|
282
|
+
│ └── models.ts # GET /v1/models
|
|
283
|
+
├── providers/
|
|
284
|
+
│ ├── openaiCompat.ts # Standard OpenAI-compatible calls
|
|
285
|
+
│ ├── anthropic.ts # Anthropic Messages API
|
|
286
|
+
│ ├── google.ts # Google Gemini API
|
|
287
|
+
│ └── local.ts # Ollama, vLLM, LM Studio
|
|
288
|
+
├── streaming/
|
|
289
|
+
│ ├── sseNormalizer.ts # Normalize SSE streams to OpenAI format
|
|
290
|
+
│ └── streamManager.ts # Timeout, backpressure, chunk handling
|
|
291
|
+
├── fallback/
|
|
292
|
+
│ └── fallbackChain.ts # Provider fallback orchestration
|
|
293
|
+
└── healthReporter.ts # /health endpoint data assembly
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Benefits
|
|
297
|
+
- **Leverage:** Each provider format independently swappable.
|
|
298
|
+
- **Locality:** A bug in streaming logic doesn't touch provider calls.
|
|
299
|
+
- **Testability:** Each handler and provider formatter testable in isolation.
|
|
300
|
+
- **Extensibility:** Adding Cohere or Bedrock formats = new file, no existing file edited.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Summary Table
|
|
305
|
+
|
|
306
|
+
| Candidate | Files | Severity | Impact | Effort |
|
|
307
|
+
|---|---|---|---|---|
|
|
308
|
+
| 1. Routing Engine Hole | `advancedRouter.ts` (MISSING) | P0 | TypeScript SDK non-functional | Medium |
|
|
309
|
+
| 2. Ensemble Voting | `ensemble.ts` (66 lines) | P0 | Core differentiator under-built | High |
|
|
310
|
+
| 3. CostTracker Missing | `costTracker.ts` (MISSING) | P1 | Cost recording doesn't work | Medium |
|
|
311
|
+
| 4. Provider Monolith | `providerConfig.ts` (951 lines) | P1 | Hard to maintain, test | Medium |
|
|
312
|
+
| 5. Proxy Monolith | `proxyServer.ts` (1105 lines) | P1 | Untestable streaming logic | High |
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Top 3 Recommendations for Council Vote
|
|
317
|
+
|
|
318
|
+
### Recommendation 1: CRITICAL — Fix the Missing Routing Engine (Vote: P0)
|
|
319
|
+
**File to create:** `src/routing/advancedRouter.ts`
|
|
320
|
+
|
|
321
|
+
This unblocks the entire TypeScript routing pipeline. Without it, the SDK, proxy, and modelMapper all have dangling imports. Prioritize before any other work.
|
|
322
|
+
|
|
323
|
+
**Acceptance criteria:**
|
|
324
|
+
- `routeQuery()` returns a valid `RouterDecision` for any string input
|
|
325
|
+
- `extractQueryFeatures()` produces 10+ signal feature vector
|
|
326
|
+
- Integrates with `ProviderHealthManager` for health-aware fallback ordering
|
|
327
|
+
- Exports `MODEL_PROFILES` as the static quality baseline
|
|
328
|
+
|
|
329
|
+
### Recommendation 2: HIGH — Deepen Ensemble Voting (Vote: P0)
|
|
330
|
+
**File to modify:** `src/ensemble.ts` → `src/ensemble/`
|
|
331
|
+
|
|
332
|
+
Build the ensemble subsystem that is the claimed unique differentiator. Start with semantic voting (cosine similarity on embeddings) and confidence weighting. The current exact-string-match voting will never produce results in production.
|
|
333
|
+
|
|
334
|
+
**Acceptance criteria:**
|
|
335
|
+
- Ensemble dispatches to 3+ providers in parallel with per-provider timeouts
|
|
336
|
+
- Voting uses semantic similarity (embeddings) not exact string match
|
|
337
|
+
- Confidence-weighted merging uses `MODEL_PROFILES` quality scores
|
|
338
|
+
- "Uncertain" flag triggers fallback or partial answer fusion
|
|
339
|
+
|
|
340
|
+
### Recommendation 3: HIGH — Implement CostTracker (Vote: P1)
|
|
341
|
+
**File to create:** `src/cost/costTracker.ts`
|
|
342
|
+
|
|
343
|
+
The `CostAnalytics` (304 lines) is the most complete analytics module in the codebase. It needs the `CostTracker` data layer to function. This unblocks the savings reporting which is a key selling point.
|
|
344
|
+
|
|
345
|
+
**Acceptance criteria:**
|
|
346
|
+
- `CostTracker.record()` stores per-request data (provider, model, tokens, latency, cost)
|
|
347
|
+
- Integrates with proxy server to record every request
|
|
348
|
+
- Feeds `CostAnalytics` for aggregate reporting
|
|
349
|
+
- Supports reset and export
|