mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
- Only consider API requests with valid token information - Skip messages with invalid/missing token data - Prevent counter from resetting on action approval messages - Ensure both tokensIn and tokensOut are valid numbers This makes the context token counter more stable and accurate by only updating on valid API responses with complete token data.
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
import { ClineMessage } from "./ExtensionMessage"
|
|
|
|
interface ApiMetrics {
|
|
totalTokensIn: number
|
|
totalTokensOut: number
|
|
totalCacheWrites?: number
|
|
totalCacheReads?: number
|
|
totalCost: number
|
|
contextTokens: number // Total tokens in conversation (last message's tokensIn + tokensOut)
|
|
}
|
|
|
|
/**
|
|
* Calculates API metrics from an array of ClineMessages.
|
|
*
|
|
* This function processes 'api_req_started' messages that have been combined with their
|
|
* corresponding 'api_req_finished' messages by the combineApiRequests function.
|
|
* It extracts and sums up the tokensIn, tokensOut, cacheWrites, cacheReads, and cost from these messages.
|
|
*
|
|
* @param messages - An array of ClineMessage objects to process.
|
|
* @returns An ApiMetrics object containing totalTokensIn, totalTokensOut, totalCacheWrites, totalCacheReads, and totalCost.
|
|
*
|
|
* @example
|
|
* const messages = [
|
|
* { type: "say", say: "api_req_started", text: '{"request":"GET /api/data","tokensIn":10,"tokensOut":20,"cost":0.005}', ts: 1000 }
|
|
* ];
|
|
* const { totalTokensIn, totalTokensOut, totalCost } = getApiMetrics(messages);
|
|
* // Result: { totalTokensIn: 10, totalTokensOut: 20, totalCost: 0.005 }
|
|
*/
|
|
export function getApiMetrics(messages: ClineMessage[]): ApiMetrics {
|
|
const result: ApiMetrics = {
|
|
totalTokensIn: 0,
|
|
totalTokensOut: 0,
|
|
totalCacheWrites: undefined,
|
|
totalCacheReads: undefined,
|
|
totalCost: 0,
|
|
contextTokens: 0,
|
|
}
|
|
|
|
// Find the last api_req_started message that has valid token information
|
|
const lastApiReq = [...messages].reverse().find((message) => {
|
|
if (message.type === "say" && message.say === "api_req_started" && message.text) {
|
|
try {
|
|
const parsedData = JSON.parse(message.text)
|
|
return typeof parsedData.tokensIn === "number" && typeof parsedData.tokensOut === "number"
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
return false
|
|
})
|
|
|
|
messages.forEach((message) => {
|
|
if (message.type === "say" && message.say === "api_req_started" && message.text) {
|
|
try {
|
|
const parsedData = JSON.parse(message.text)
|
|
const { tokensIn, tokensOut, cacheWrites, cacheReads, cost } = parsedData
|
|
|
|
if (typeof tokensIn === "number") {
|
|
result.totalTokensIn += tokensIn
|
|
}
|
|
if (typeof tokensOut === "number") {
|
|
result.totalTokensOut += tokensOut
|
|
}
|
|
if (typeof cacheWrites === "number") {
|
|
result.totalCacheWrites = (result.totalCacheWrites ?? 0) + cacheWrites
|
|
}
|
|
if (typeof cacheReads === "number") {
|
|
result.totalCacheReads = (result.totalCacheReads ?? 0) + cacheReads
|
|
}
|
|
if (typeof cost === "number") {
|
|
result.totalCost += cost
|
|
}
|
|
|
|
// If this is the last api request, use its tokens for context size
|
|
if (message === lastApiReq) {
|
|
// Only update context tokens if both input and output tokens are non-zero
|
|
if (tokensIn > 0 && tokensOut > 0) {
|
|
result.contextTokens = tokensIn + tokensOut
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Error parsing JSON:", error)
|
|
}
|
|
}
|
|
})
|
|
|
|
return result
|
|
}
|