@blockrun/clawrouter 0.8.9 → 0.8.11
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/dist/cli.js +25 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +39 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -908,12 +908,16 @@ function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPric
|
|
|
908
908
|
const tierConfig = tierConfigs[tier];
|
|
909
909
|
const model = tierConfig.primary;
|
|
910
910
|
const pricing = modelPricing.get(model);
|
|
911
|
-
const
|
|
912
|
-
const
|
|
911
|
+
const inputPrice = pricing?.inputPrice ?? 0;
|
|
912
|
+
const outputPrice = pricing?.outputPrice ?? 0;
|
|
913
|
+
const inputCost = estimatedInputTokens / 1e6 * inputPrice;
|
|
914
|
+
const outputCost = maxOutputTokens / 1e6 * outputPrice;
|
|
913
915
|
const costEstimate = inputCost + outputCost;
|
|
914
916
|
const opusPricing = modelPricing.get("anthropic/claude-opus-4");
|
|
915
|
-
const
|
|
916
|
-
const
|
|
917
|
+
const opusInputPrice = opusPricing?.inputPrice ?? 0;
|
|
918
|
+
const opusOutputPrice = opusPricing?.outputPrice ?? 0;
|
|
919
|
+
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
920
|
+
const baselineOutput = maxOutputTokens / 1e6 * opusOutputPrice;
|
|
917
921
|
const baselineCost = baselineInput + baselineOutput;
|
|
918
922
|
const savings = baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
919
923
|
return {
|
|
@@ -933,12 +937,16 @@ function getFallbackChain(tier, tierConfigs) {
|
|
|
933
937
|
}
|
|
934
938
|
function calculateModelCost(model, modelPricing, estimatedInputTokens, maxOutputTokens) {
|
|
935
939
|
const pricing = modelPricing.get(model);
|
|
936
|
-
const
|
|
937
|
-
const
|
|
940
|
+
const inputPrice = pricing?.inputPrice ?? 0;
|
|
941
|
+
const outputPrice = pricing?.outputPrice ?? 0;
|
|
942
|
+
const inputCost = estimatedInputTokens / 1e6 * inputPrice;
|
|
943
|
+
const outputCost = maxOutputTokens / 1e6 * outputPrice;
|
|
938
944
|
const costEstimate = inputCost + outputCost;
|
|
939
945
|
const opusPricing = modelPricing.get("anthropic/claude-opus-4");
|
|
940
|
-
const
|
|
941
|
-
const
|
|
946
|
+
const opusInputPrice = opusPricing?.inputPrice ?? 0;
|
|
947
|
+
const opusOutputPrice = opusPricing?.outputPrice ?? 0;
|
|
948
|
+
const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
|
|
949
|
+
const baselineOutput = maxOutputTokens / 1e6 * opusOutputPrice;
|
|
942
950
|
const baselineCost = baselineInput + baselineOutput;
|
|
943
951
|
const savings = baselineCost > 0 ? Math.max(0, (baselineCost - costEstimate) / baselineCost) : 0;
|
|
944
952
|
return { costEstimate, baselineCost, savings };
|
|
@@ -1821,6 +1829,12 @@ async function getStats(days = 7) {
|
|
|
1821
1829
|
}
|
|
1822
1830
|
const totalSavings = totalBaselineCost - totalCost;
|
|
1823
1831
|
const savingsPercentage = totalBaselineCost > 0 ? totalSavings / totalBaselineCost * 100 : 0;
|
|
1832
|
+
let entriesWithBaseline = 0;
|
|
1833
|
+
for (const day of dailyBreakdown) {
|
|
1834
|
+
if (day.totalBaselineCost !== day.totalCost) {
|
|
1835
|
+
entriesWithBaseline += day.totalRequests;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1824
1838
|
return {
|
|
1825
1839
|
period: days === 1 ? "today" : `last ${days} days`,
|
|
1826
1840
|
totalRequests,
|
|
@@ -1832,8 +1846,10 @@ async function getStats(days = 7) {
|
|
|
1832
1846
|
avgCostPerRequest: totalRequests > 0 ? totalCost / totalRequests : 0,
|
|
1833
1847
|
byTier: byTierWithPercentage,
|
|
1834
1848
|
byModel: byModelWithPercentage,
|
|
1835
|
-
dailyBreakdown: dailyBreakdown.reverse()
|
|
1849
|
+
dailyBreakdown: dailyBreakdown.reverse(),
|
|
1836
1850
|
// Oldest first for charts
|
|
1851
|
+
entriesWithBaseline
|
|
1852
|
+
// How many entries have valid baseline tracking
|
|
1837
1853
|
};
|
|
1838
1854
|
}
|
|
1839
1855
|
function formatStatsAscii(stats) {
|
|
@@ -1845,20 +1861,27 @@ function formatStatsAscii(stats) {
|
|
|
1845
1861
|
lines.push(`\u2551 Total Requests: ${stats.totalRequests.toString().padEnd(41)}\u2551`);
|
|
1846
1862
|
lines.push(`\u2551 Total Cost: $${stats.totalCost.toFixed(4).padEnd(43)}\u2551`);
|
|
1847
1863
|
lines.push(`\u2551 Baseline Cost (Opus): $${stats.totalBaselineCost.toFixed(4).padEnd(33)}\u2551`);
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1864
|
+
const savingsLine = `\u2551 \u{1F4B0} Total Saved: $${stats.totalSavings.toFixed(4)} (${stats.savingsPercentage.toFixed(1)}%)`;
|
|
1865
|
+
if (stats.entriesWithBaseline < stats.totalRequests && stats.entriesWithBaseline > 0) {
|
|
1866
|
+
lines.push(savingsLine.padEnd(61) + "\u2551");
|
|
1867
|
+
const note = `\u2551 (based on ${stats.entriesWithBaseline}/${stats.totalRequests} tracked requests)`;
|
|
1868
|
+
lines.push(note.padEnd(61) + "\u2551");
|
|
1869
|
+
} else {
|
|
1870
|
+
lines.push(savingsLine.padEnd(61) + "\u2551");
|
|
1871
|
+
}
|
|
1853
1872
|
lines.push(`\u2551 Avg Latency: ${stats.avgLatencyMs.toFixed(0)}ms`.padEnd(61) + "\u2551");
|
|
1854
1873
|
lines.push("\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563");
|
|
1855
1874
|
lines.push("\u2551 Routing by Tier: \u2551");
|
|
1856
|
-
const
|
|
1875
|
+
const knownTiers = ["SIMPLE", "MEDIUM", "COMPLEX", "REASONING"];
|
|
1876
|
+
const allTiers = Object.keys(stats.byTier);
|
|
1877
|
+
const otherTiers = allTiers.filter((t) => !knownTiers.includes(t));
|
|
1878
|
+
const tierOrder = [...knownTiers.filter((t) => stats.byTier[t]), ...otherTiers];
|
|
1857
1879
|
for (const tier of tierOrder) {
|
|
1858
1880
|
const data = stats.byTier[tier];
|
|
1859
1881
|
if (data) {
|
|
1860
1882
|
const bar = "\u2588".repeat(Math.min(20, Math.round(data.percentage / 5)));
|
|
1861
|
-
const
|
|
1883
|
+
const displayTier = tier === "UNKNOWN" ? "OTHER" : tier;
|
|
1884
|
+
const line = `\u2551 ${displayTier.padEnd(10)} ${bar.padEnd(20)} ${data.percentage.toFixed(1).padStart(5)}% (${data.count})`;
|
|
1862
1885
|
lines.push(line.padEnd(61) + "\u2551");
|
|
1863
1886
|
}
|
|
1864
1887
|
}
|