feat: add GLM Coding (China) provider and Usage by API Keys statistics

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Blade096
2026-02-11 15:44:08 +07:00
committed by decolua
co-authored by Cursor
parent bd23ab41ee
commit 1ae4e311b7
6 changed files with 835 additions and 199 deletions
+82 -4
View File
@@ -139,7 +139,7 @@ export async function getUsageDb() {
/**
* Save request usage
* @param {object} entry - Usage entry { provider, model, tokens: { prompt_tokens, completion_tokens, ... }, connectionId? }
* @param {object} entry - Usage entry { provider, model, tokens: { prompt_tokens, completion_tokens, ... }, connectionId?, apiKey? }
*/
export async function saveRequestUsage(entry) {
if (isCloud) return; // Skip saving in Workers
@@ -349,8 +349,8 @@ export async function getUsageStats() {
const db = await getUsageDb();
const history = db.data.history || [];
// Import localDb to get provider connection names
const { getProviderConnections } = await import("@/lib/localDb.js");
// Import localDb to get provider connection names and API keys
const { getProviderConnections, getApiKeys } = await import("@/lib/localDb.js");
// Fetch all provider connections to get account names
let allConnections = [];
@@ -367,14 +367,33 @@ export async function getUsageStats() {
connectionMap[conn.id] = conn.name || conn.email || conn.id;
}
// Fetch all API keys to get key names
let allApiKeys = [];
try {
allApiKeys = await getApiKeys();
} catch (error) {
console.warn("Could not fetch API keys for usage stats:", error.message);
}
// Create a map from API key to key info
const apiKeyMap = {};
for (const key of allApiKeys) {
apiKeyMap[key.key] = {
name: key.name,
id: key.id,
createdAt: key.createdAt
};
}
const stats = {
totalRequests: history.length,
totalPromptTokens: 0,
totalCompletionTokens: 0,
totalCost: 0, // NEW
totalCost: 0,
byProvider: {},
byModel: {},
byAccount: {},
byApiKey: {},
last10Minutes: [],
pending: pendingRequests,
activeRequests: []
@@ -507,6 +526,65 @@ export async function getUsageStats() {
stats.byAccount[accountKey].lastUsed = entry.timestamp;
}
}
// Handle requests with API key
if (entry.apiKey && typeof entry.apiKey === "string") {
const keyInfo = apiKeyMap[entry.apiKey];
const keyName = keyInfo?.name || entry.apiKey.slice(0, 8) + "...";
// Use full API key to avoid collisions (keys with same prefix)
const apiKeyKey = entry.apiKey;
// Group by API Key + Model + Provider combination to track different models used with the same key
const apiKeyModelKey = `${apiKeyKey}|${entry.model}|${entry.provider || 'unknown'}`;
if (!stats.byApiKey[apiKeyModelKey]) {
stats.byApiKey[apiKeyModelKey] = {
requests: 0,
promptTokens: 0,
completionTokens: 0,
cost: 0,
rawModel: entry.model,
provider: entry.provider,
apiKey: entry.apiKey,
keyName: keyName,
apiKeyKey: apiKeyKey,
lastUsed: entry.timestamp
};
}
const apiKeyEntry = stats.byApiKey[apiKeyModelKey];
apiKeyEntry.requests++;
apiKeyEntry.promptTokens += promptTokens;
apiKeyEntry.completionTokens += completionTokens;
apiKeyEntry.cost += entryCost;
if (new Date(entry.timestamp) > new Date(apiKeyEntry.lastUsed)) {
apiKeyEntry.lastUsed = entry.timestamp;
}
} else {
const apiKeyKey = "local-no-key";
const keyName = "Local (No API Key)";
if (!stats.byApiKey[apiKeyKey]) {
stats.byApiKey[apiKeyKey] = {
requests: 0,
promptTokens: 0,
completionTokens: 0,
cost: 0,
rawModel: entry.model,
provider: entry.provider,
apiKey: null,
keyName: keyName,
apiKeyKey: apiKeyKey,
lastUsed: entry.timestamp
};
}
const apiKeyEntry = stats.byApiKey[apiKeyKey];
apiKeyEntry.requests++;
apiKeyEntry.promptTokens += promptTokens;
apiKeyEntry.completionTokens += completionTokens;
apiKeyEntry.cost += entryCost;
if (new Date(entry.timestamp) > new Date(apiKeyEntry.lastUsed)) {
apiKeyEntry.lastUsed = entry.timestamp;
}
}
}
return stats;