@relayplane/proxy 1.5.22 → 1.5.24
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/README.md +25 -0
- package/dist/cli.js +0 -0
- package/dist/standalone-proxy.d.ts.map +1 -1
- package/dist/standalone-proxy.js +38 -11
- package/dist/standalone-proxy.js.map +1 -1
- package/package.json +1 -1
- package/dist/__tests__/model-suggestions.test.d.ts +0 -2
- package/dist/__tests__/model-suggestions.test.d.ts.map +0 -1
- package/dist/__tests__/model-suggestions.test.js +0 -67
- package/dist/__tests__/model-suggestions.test.js.map +0 -1
- package/dist/__tests__/routing-aliases.test.d.ts +0 -2
- package/dist/__tests__/routing-aliases.test.d.ts.map +0 -1
- package/dist/__tests__/routing-aliases.test.js +0 -81
- package/dist/__tests__/routing-aliases.test.js.map +0 -1
- package/dist/mesh-integration.d.ts +0 -95
- package/dist/mesh-integration.d.ts.map +0 -1
- package/dist/mesh-integration.js +0 -634
- package/dist/mesh-integration.js.map +0 -1
package/README.md
CHANGED
|
@@ -48,6 +48,31 @@ A minimal config file:
|
|
|
48
48
|
|
|
49
49
|
All configuration is optional — sensible defaults are applied for every field. The proxy merges your config with its defaults via deep merge, so you only need to specify what you want to change.
|
|
50
50
|
|
|
51
|
+
## Architecture (Current)
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Client (Claude Code / Aider / Cursor)
|
|
55
|
+
|
|
|
56
|
+
| OpenAI/Anthropic-compatible request
|
|
57
|
+
v
|
|
58
|
+
+-----------------------------------------------+
|
|
59
|
+
| RelayPlane Proxy (local) |
|
|
60
|
+
|-----------------------------------------------|
|
|
61
|
+
| 1) Parse request |
|
|
62
|
+
| 2) Infer task/complexity (pre-request) |
|
|
63
|
+
| 3) Select route/model |
|
|
64
|
+
| - explicit model / passthrough |
|
|
65
|
+
| - relayplane:auto/cost/fast/quality |
|
|
66
|
+
| - configured complexity/cascade rules |
|
|
67
|
+
| 4) Forward request to provider |
|
|
68
|
+
| 5) Return provider response |
|
|
69
|
+
| 6) (Optional) record telemetry metadata |
|
|
70
|
+
+-----------------------------------------------+
|
|
71
|
+
|
|
|
72
|
+
v
|
|
73
|
+
Provider APIs (Anthropic/OpenAI/Gemini/xAI/Moonshot/...)
|
|
74
|
+
```
|
|
75
|
+
|
|
51
76
|
## How It Works
|
|
52
77
|
|
|
53
78
|
RelayPlane is a local HTTP proxy. You point your agent at `localhost:4801` by setting `ANTHROPIC_BASE_URL` or `OPENAI_BASE_URL`. The proxy:
|
package/dist/cli.js
CHANGED
|
File without changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standalone-proxy.d.ts","sourceRoot":"","sources":["../src/standalone-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAKlC,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,kBAAkB,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAU5C,2DAA2D;AAC3D,eAAO,MAAM,mBAAmB,gBAAuB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CA6C9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAa/E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAQ/E,CAAC;AAiCF;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAWjD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMvD;AAkBD,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEjD,UAAU,WAAW;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;CAC9B;AAcD,UAAU,aAAa;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC;IAChD,cAAc,EAAE,MAAM,CAAC;CACxB;AAmBD,KAAK,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AA6EpD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,GAAG,KAAK,GAAG,MAAM,CAAC;CAChD;AAmZD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAe3D;AAuDD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,UAAU,CAiBrF;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,OAAO,CAIlG;
|
|
1
|
+
{"version":3,"file":"standalone-proxy.d.ts","sourceRoot":"","sources":["../src/standalone-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAKlC,OAAO,KAAK,EAAE,QAAQ,EAAY,MAAM,kBAAkB,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAU5C,2DAA2D;AAC3D,eAAO,MAAM,mBAAmB,gBAAuB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CA6C9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAa/E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGrD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAQ/E,CAAC;AAiCF;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAWjD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMvD;AAkBD,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAEjD,UAAU,WAAW;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;CAC9B;AAcD,UAAU,aAAa;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC;IAChD,cAAc,EAAE,MAAM,CAAC;CACxB;AAmBD,KAAK,UAAU,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AA6EpD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,GAAG,KAAK,GAAG,MAAM,CAAC;CAChD;AAmZD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAe3D;AAuDD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,UAAU,CAiBrF;AAED,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,OAAO,CAIlG;AAu9CD;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CA+sC/E"}
|
package/dist/standalone-proxy.js
CHANGED
|
@@ -1823,7 +1823,7 @@ table{width:100%;border-collapse:collapse;font-size:.85rem}
|
|
|
1823
1823
|
th{text-align:left;color:#64748b;font-weight:500;padding:8px 12px;border-bottom:1px solid #1e293b;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em}
|
|
1824
1824
|
td{padding:8px 12px;border-bottom:1px solid #111318}
|
|
1825
1825
|
.section{margin-bottom:32px}.section h2{font-size:1rem;font-weight:600;margin-bottom:12px;color:#94a3b8}
|
|
1826
|
-
.dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px}.dot.up{background:#34d399}.dot.down{background:#ef4444}
|
|
1826
|
+
.dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px}.dot.up{background:#34d399}.dot.warn{background:#fbbf24}.dot.down{background:#ef4444}
|
|
1827
1827
|
.badge{display:inline-block;padding:2px 8px;border-radius:6px;font-size:.75rem;font-weight:500}
|
|
1828
1828
|
.badge.ok{background:#052e1633;color:#34d399}.badge.err{background:#2d0a0a;color:#ef4444}
|
|
1829
1829
|
.badge.tt-code{background:#1e3a5f;color:#60a5fa}.badge.tt-analysis{background:#3b1f6e;color:#a78bfa}.badge.tt-summarization{background:#1a3a2a;color:#6ee7b7}.badge.tt-qa{background:#3a2f1e;color:#fbbf24}.badge.tt-general{background:#1e293b;color:#94a3b8}
|
|
@@ -1872,9 +1872,11 @@ async function load(){
|
|
|
1872
1872
|
$('runs').innerHTML=(runsR.runs||[]).map(r=>
|
|
1873
1873
|
'<tr><td>'+fmtTime(r.started_at)+'</td><td>'+r.model+'</td><td class="col-tt"><span class="badge '+ttCls(r.taskType)+'">'+(r.taskType||'general').replace(/_/g,' ')+'</span></td><td class="col-cx"><span class="badge '+cxCls(r.complexity)+'">'+(r.complexity||'simple')+'</span></td><td>'+(r.tokensIn||0)+'</td><td>'+(r.tokensOut||0)+'</td><td>$'+fmt(r.costUsd,4)+'</td><td>'+r.latencyMs+'ms</td><td><span class="badge '+(r.status==='success'?'ok':'err')+'">'+r.status+'</span></td></tr>'
|
|
1874
1874
|
).join('')||'<tr><td colspan=9 style="color:#64748b">No runs yet</td></tr>';
|
|
1875
|
-
$('providers').innerHTML=(provH.providers||[]).map(p=>
|
|
1876
|
-
|
|
1877
|
-
|
|
1875
|
+
$('providers').innerHTML=(provH.providers||[]).map(p=>{
|
|
1876
|
+
const dotClass = p.status==='healthy'?'up':(p.status==='degraded'?'warn':'down');
|
|
1877
|
+
const rate = p.successRate!==undefined?(' '+Math.round(p.successRate*100)+'%'):'';
|
|
1878
|
+
return '<div class="prov-item"><span class="dot '+dotClass+'"></span>'+p.provider+rate+'</div>';
|
|
1879
|
+
}).join('');
|
|
1878
1880
|
}catch(e){console.error(e)}
|
|
1879
1881
|
}
|
|
1880
1882
|
load();setInterval(load,5000);
|
|
@@ -2088,7 +2090,7 @@ async function startProxy(config = {}) {
|
|
|
2088
2090
|
const offset = parseInt(params.get('offset') || '0', 10);
|
|
2089
2091
|
const sorted = [...requestHistory].reverse();
|
|
2090
2092
|
const runs = sorted.slice(offset, offset + limit).map(r => {
|
|
2091
|
-
const origCost = (0, telemetry_js_1.estimateCost)(
|
|
2093
|
+
const origCost = (0, telemetry_js_1.estimateCost)('claude-opus-4-20250514', r.tokensIn, r.tokensOut);
|
|
2092
2094
|
const perRunSavings = Math.max(0, origCost - r.costUsd);
|
|
2093
2095
|
return {
|
|
2094
2096
|
id: r.id,
|
|
@@ -2117,15 +2119,15 @@ async function startProxy(config = {}) {
|
|
|
2117
2119
|
return;
|
|
2118
2120
|
}
|
|
2119
2121
|
if (req.method === 'GET' && telemetryPath === 'savings') {
|
|
2120
|
-
// Savings = cost
|
|
2121
|
-
//
|
|
2122
|
-
|
|
2122
|
+
// Savings = cost if everything ran on Opus - actual cost
|
|
2123
|
+
// Always compare against Opus as the baseline
|
|
2124
|
+
const OPUS_BASELINE = 'claude-opus-4-20250514';
|
|
2123
2125
|
let totalOriginalCost = 0;
|
|
2124
2126
|
let totalActualCost = 0;
|
|
2125
2127
|
let totalSavedAmount = 0;
|
|
2126
2128
|
const byDayMap = new Map();
|
|
2127
2129
|
for (const r of requestHistory) {
|
|
2128
|
-
const origCost = (0, telemetry_js_1.estimateCost)(
|
|
2130
|
+
const origCost = (0, telemetry_js_1.estimateCost)(OPUS_BASELINE, r.tokensIn, r.tokensOut);
|
|
2129
2131
|
const actualCost = r.costUsd;
|
|
2130
2132
|
const saved = Math.max(0, origCost - actualCost);
|
|
2131
2133
|
totalOriginalCost += origCost;
|
|
@@ -2161,14 +2163,39 @@ async function startProxy(config = {}) {
|
|
|
2161
2163
|
return;
|
|
2162
2164
|
}
|
|
2163
2165
|
if (req.method === 'GET' && telemetryPath === 'health') {
|
|
2166
|
+
// Calculate per-provider success rates from recent history (last 50 requests per provider)
|
|
2167
|
+
const providerStats = {};
|
|
2168
|
+
const recentHistory = requestHistory.slice(-200); // Look at last 200 requests
|
|
2169
|
+
for (const r of recentHistory) {
|
|
2170
|
+
const provider = r.provider || 'unknown';
|
|
2171
|
+
if (!providerStats[provider]) {
|
|
2172
|
+
providerStats[provider] = { success: 0, total: 0 };
|
|
2173
|
+
}
|
|
2174
|
+
providerStats[provider].total++;
|
|
2175
|
+
if (r.success) {
|
|
2176
|
+
providerStats[provider].success++;
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
// Debug: log provider stats
|
|
2180
|
+
console.log('[RelayPlane Health] Provider stats:', JSON.stringify(providerStats));
|
|
2164
2181
|
const providers = [];
|
|
2165
2182
|
for (const [name, ep] of Object.entries(exports.DEFAULT_ENDPOINTS)) {
|
|
2166
2183
|
const hasKey = !!process.env[ep.apiKeyEnv];
|
|
2184
|
+
const stats = providerStats[name.toLowerCase()];
|
|
2185
|
+
const successRate = stats && stats.total > 0 ? stats.success / stats.total : (hasKey ? 1 : 0);
|
|
2186
|
+
// Mark as unhealthy if success rate < 80% and has had requests
|
|
2187
|
+
let status = 'healthy';
|
|
2188
|
+
if (!hasKey) {
|
|
2189
|
+
status = 'down';
|
|
2190
|
+
}
|
|
2191
|
+
else if (stats && stats.total >= 5 && successRate < 0.8) {
|
|
2192
|
+
status = 'degraded';
|
|
2193
|
+
}
|
|
2167
2194
|
providers.push({
|
|
2168
2195
|
provider: name,
|
|
2169
|
-
status
|
|
2196
|
+
status,
|
|
2170
2197
|
latency: 0,
|
|
2171
|
-
successRate:
|
|
2198
|
+
successRate: Math.round(successRate * 100) / 100,
|
|
2172
2199
|
lastChecked: new Date().toISOString(),
|
|
2173
2200
|
});
|
|
2174
2201
|
}
|