@relayplane/proxy 0.1.4 → 0.1.5
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 +19 -0
- package/dist/cli.js +99 -7
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +99 -7
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,25 @@ Or run directly:
|
|
|
20
20
|
npx @relayplane/proxy
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
## CLI Commands
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Start the proxy server
|
|
27
|
+
npx @relayplane/proxy
|
|
28
|
+
|
|
29
|
+
# Start on custom port
|
|
30
|
+
npx @relayplane/proxy --port 8080
|
|
31
|
+
|
|
32
|
+
# View routing statistics
|
|
33
|
+
npx @relayplane/proxy stats
|
|
34
|
+
|
|
35
|
+
# View stats for last 30 days
|
|
36
|
+
npx @relayplane/proxy stats --days 30
|
|
37
|
+
|
|
38
|
+
# Show help
|
|
39
|
+
npx @relayplane/proxy --help
|
|
40
|
+
```
|
|
41
|
+
|
|
23
42
|
## Quick Start
|
|
24
43
|
|
|
25
44
|
### 1. Set your API keys
|
package/dist/cli.js
CHANGED
|
@@ -2615,18 +2615,28 @@ async function handleNonStreamingRequest(res, request, targetProvider, targetMod
|
|
|
2615
2615
|
}
|
|
2616
2616
|
|
|
2617
2617
|
// src/cli.ts
|
|
2618
|
+
var import_better_sqlite32 = __toESM(require("better-sqlite3"));
|
|
2618
2619
|
function printHelp() {
|
|
2619
2620
|
console.log(`
|
|
2620
2621
|
RelayPlane Proxy - Intelligent AI Model Routing
|
|
2621
2622
|
|
|
2622
2623
|
Usage:
|
|
2623
|
-
npx @relayplane/proxy [options]
|
|
2624
|
-
relayplane-proxy [options]
|
|
2624
|
+
npx @relayplane/proxy [command] [options]
|
|
2625
|
+
relayplane-proxy [command] [options]
|
|
2625
2626
|
|
|
2626
|
-
|
|
2627
|
+
Commands:
|
|
2628
|
+
(default) Start the proxy server
|
|
2629
|
+
stats Show routing statistics
|
|
2630
|
+
|
|
2631
|
+
Server Options:
|
|
2627
2632
|
--port <number> Port to listen on (default: 3001)
|
|
2628
2633
|
--host <string> Host to bind to (default: 127.0.0.1)
|
|
2629
2634
|
-v, --verbose Enable verbose logging
|
|
2635
|
+
|
|
2636
|
+
Stats Options:
|
|
2637
|
+
--days <number> Days of history to show (default: 7)
|
|
2638
|
+
|
|
2639
|
+
General:
|
|
2630
2640
|
-h, --help Show this help message
|
|
2631
2641
|
|
|
2632
2642
|
Environment Variables:
|
|
@@ -2636,26 +2646,108 @@ Environment Variables:
|
|
|
2636
2646
|
XAI_API_KEY xAI/Grok API key (optional)
|
|
2637
2647
|
MOONSHOT_API_KEY Moonshot API key (optional)
|
|
2638
2648
|
|
|
2639
|
-
|
|
2649
|
+
Examples:
|
|
2640
2650
|
# Start proxy on default port
|
|
2641
2651
|
npx @relayplane/proxy
|
|
2642
2652
|
|
|
2643
2653
|
# Start on custom port with verbose logging
|
|
2644
2654
|
npx @relayplane/proxy --port 8080 -v
|
|
2645
2655
|
|
|
2646
|
-
#
|
|
2647
|
-
|
|
2648
|
-
|
|
2656
|
+
# View routing stats for last 7 days
|
|
2657
|
+
npx @relayplane/proxy stats
|
|
2658
|
+
|
|
2659
|
+
# View stats for last 30 days
|
|
2660
|
+
npx @relayplane/proxy stats --days 30
|
|
2649
2661
|
|
|
2650
2662
|
Learn more: https://relayplane.com/integrations/openclaw
|
|
2651
2663
|
`);
|
|
2652
2664
|
}
|
|
2665
|
+
function showStats(days) {
|
|
2666
|
+
const dbPath = getDefaultDbPath();
|
|
2667
|
+
try {
|
|
2668
|
+
const db = new import_better_sqlite32.default(dbPath, { readonly: true });
|
|
2669
|
+
const cutoff = new Date(Date.now() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
2670
|
+
const runs = db.prepare(`
|
|
2671
|
+
SELECT
|
|
2672
|
+
model,
|
|
2673
|
+
task_type,
|
|
2674
|
+
COUNT(*) as count,
|
|
2675
|
+
SUM(tokens_in) as total_in,
|
|
2676
|
+
SUM(tokens_out) as total_out,
|
|
2677
|
+
AVG(duration_ms) as avg_duration,
|
|
2678
|
+
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successes
|
|
2679
|
+
FROM runs
|
|
2680
|
+
WHERE created_at >= ?
|
|
2681
|
+
GROUP BY model
|
|
2682
|
+
ORDER BY count DESC
|
|
2683
|
+
`).all(cutoff);
|
|
2684
|
+
const totalRuns = runs.reduce((sum, r) => sum + r.count, 0);
|
|
2685
|
+
const totalTokensIn = runs.reduce((sum, r) => sum + (r.total_in || 0), 0);
|
|
2686
|
+
const totalTokensOut = runs.reduce((sum, r) => sum + (r.total_out || 0), 0);
|
|
2687
|
+
console.log("");
|
|
2688
|
+
console.log(` \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E`);
|
|
2689
|
+
console.log(` \u2502 RelayPlane Routing Stats \u2502`);
|
|
2690
|
+
console.log(` \u2502 Last ${String(days).padStart(2)} days \u2502`);
|
|
2691
|
+
console.log(` \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F`);
|
|
2692
|
+
console.log("");
|
|
2693
|
+
if (totalRuns === 0) {
|
|
2694
|
+
console.log(" No routing data found for this period.");
|
|
2695
|
+
console.log(" Start using the proxy to collect stats!");
|
|
2696
|
+
console.log("");
|
|
2697
|
+
return;
|
|
2698
|
+
}
|
|
2699
|
+
console.log(" Summary:");
|
|
2700
|
+
console.log(` Total requests: ${totalRuns.toLocaleString()}`);
|
|
2701
|
+
console.log(` Total tokens in: ${totalTokensIn.toLocaleString()}`);
|
|
2702
|
+
console.log(` Total tokens out: ${totalTokensOut.toLocaleString()}`);
|
|
2703
|
+
console.log("");
|
|
2704
|
+
console.log(" By Model:");
|
|
2705
|
+
console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
2706
|
+
for (const row of runs) {
|
|
2707
|
+
const pct = (row.count / totalRuns * 100).toFixed(1);
|
|
2708
|
+
const successRate = row.count > 0 ? (row.successes / row.count * 100).toFixed(0) : "0";
|
|
2709
|
+
console.log(` ${row.model.padEnd(35)} ${String(row.count).padStart(6)} (${pct.padStart(5)}%) ${successRate}% ok`);
|
|
2710
|
+
}
|
|
2711
|
+
console.log("");
|
|
2712
|
+
const haikuRuns = runs.filter((r) => r.model.includes("haiku"));
|
|
2713
|
+
const haikuTokensIn = haikuRuns.reduce((sum, r) => sum + (r.total_in || 0), 0);
|
|
2714
|
+
const haikuTokensOut = haikuRuns.reduce((sum, r) => sum + (r.total_out || 0), 0);
|
|
2715
|
+
const opusCost = totalTokensIn * 15 / 1e6 + totalTokensOut * 75 / 1e6;
|
|
2716
|
+
const haikuCost = haikuTokensIn * 0.25 / 1e6 + haikuTokensOut * 1.25 / 1e6;
|
|
2717
|
+
const nonHaikuCost = (totalTokensIn - haikuTokensIn) * 3 / 1e6 + (totalTokensOut - haikuTokensOut) * 15 / 1e6;
|
|
2718
|
+
const actualCost = haikuCost + nonHaikuCost;
|
|
2719
|
+
const savings = opusCost - actualCost;
|
|
2720
|
+
if (savings > 0) {
|
|
2721
|
+
console.log(" Estimated Savings:");
|
|
2722
|
+
console.log(` If all Opus: $${opusCost.toFixed(2)}`);
|
|
2723
|
+
console.log(` With routing: $${actualCost.toFixed(2)}`);
|
|
2724
|
+
console.log(` Saved: $${savings.toFixed(2)} (${(savings / opusCost * 100).toFixed(0)}%)`);
|
|
2725
|
+
console.log("");
|
|
2726
|
+
}
|
|
2727
|
+
db.close();
|
|
2728
|
+
} catch (err) {
|
|
2729
|
+
console.error("Error reading stats:", err);
|
|
2730
|
+
console.log("");
|
|
2731
|
+
console.log(" No data found. The proxy stores data at:");
|
|
2732
|
+
console.log(` ${dbPath}`);
|
|
2733
|
+
console.log("");
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2653
2736
|
async function main() {
|
|
2654
2737
|
const args = process.argv.slice(2);
|
|
2655
2738
|
if (args.includes("-h") || args.includes("--help")) {
|
|
2656
2739
|
printHelp();
|
|
2657
2740
|
process.exit(0);
|
|
2658
2741
|
}
|
|
2742
|
+
if (args[0] === "stats") {
|
|
2743
|
+
let days = 7;
|
|
2744
|
+
const daysIdx = args.indexOf("--days");
|
|
2745
|
+
if (daysIdx !== -1 && args[daysIdx + 1]) {
|
|
2746
|
+
days = parseInt(args[daysIdx + 1], 10) || 7;
|
|
2747
|
+
}
|
|
2748
|
+
showStats(days);
|
|
2749
|
+
process.exit(0);
|
|
2750
|
+
}
|
|
2659
2751
|
let port = 3001;
|
|
2660
2752
|
let host = "127.0.0.1";
|
|
2661
2753
|
let verbose = false;
|