added usage command

This commit is contained in:
redshift
2026-03-13 12:49:14 +00:00
parent 7e1bd78ffe
commit edf5b95bb5
2 changed files with 111 additions and 0 deletions
+68
View File
@@ -26,6 +26,19 @@ type RoutstrModel = {
context_length?: number;
};
type UsageEntry = {
id: string;
timestamp: number;
modelId: string;
baseUrl: string;
requestId: string;
cost: number;
satsCost: number;
promptTokens: number;
completionTokens: number;
totalTokens: number;
};
const cliVersion = "0.1.0";
async function initDaemon(): Promise<void> {
@@ -286,6 +299,61 @@ program
}
});
program
.command("usage")
.description("Show recent usage logs and total sats cost")
.option("-n, --limit <number>", "Number of recent usage entries", "10")
.action(async (options: { limit: string }) => {
await ensureDaemonRunning();
const requested = Number.parseInt(options.limit, 10);
const limit =
Number.isFinite(requested) && requested > 0 ? Math.min(requested, 1000) : 10;
const result = await callDaemon(`/usage?limit=${limit}`);
if (result.error) {
console.log(result.error);
process.exit(1);
}
const output = result.output as
| {
entries?: UsageEntry[];
totalEntries?: number;
totalSatsCost?: number;
recentSatsCost?: number;
limit?: number;
}
| undefined;
const entries = output?.entries || [];
const totalEntries = output?.totalEntries || 0;
const totalSatsCost = output?.totalSatsCost || 0;
const recentSatsCost = output?.recentSatsCost || 0;
console.log(`Usage entries: showing ${entries.length} of ${totalEntries}`);
console.log(`Total sats cost (all time): ${totalSatsCost.toFixed(3)} sats`);
console.log(`Sats cost (shown entries): ${recentSatsCost.toFixed(3)} sats`);
if (entries.length === 0) {
console.log("No usage entries yet.");
return;
}
console.log("");
entries.forEach((entry, index) => {
const time = new Date(entry.timestamp).toISOString();
const provider = entry.baseUrl || "unknown";
const reqId = entry.requestId || "unknown";
console.log(
`${index + 1}. ${time} | ${entry.modelId} | ${provider} | ${entry.satsCost.toFixed(3)} sats`,
);
console.log(
` tokens p/c/t: ${entry.promptTokens}/${entry.completionTokens}/${entry.totalTokens} | request: ${reqId}`,
);
});
});
// Stop
program
.command("stop")
+43
View File
@@ -816,6 +816,49 @@ async function main(): Promise<void> {
return;
}
if (req.method === "GET" && url.pathname === "/usage") {
try {
const requestedLimit = Number.parseInt(
url.searchParams.get("limit") || "10",
10,
);
const limit =
Number.isFinite(requestedLimit) && requestedLimit > 0
? Math.min(requestedLimit, 1000)
: 10;
const usageTracking =
((store.getState().usageTracking || []) as UsageTrackingEntry[]) ||
[];
const recent = usageTracking.slice(-limit).reverse();
const totalSatsCost = usageTracking.reduce(
(sum, entry) => sum + (entry.satsCost || 0),
0,
);
const recentSatsCost = recent.reduce(
(sum, entry) => sum + (entry.satsCost || 0),
0,
);
res.writeHead(200, { "Content-Type": "application/json" });
res.end(
JSON.stringify({
output: {
entries: recent,
totalEntries: usageTracking.length,
totalSatsCost,
recentSatsCost,
limit,
},
}),
);
} catch (error) {
res.writeHead(500, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: String(error) }));
}
return;
}
if (req.method !== "POST") {
res.writeHead(405, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Only POST is supported." }));