mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-20 11:12:31 +02:00
Dont count usage when the response was not successful
This commit is contained in:
@@ -17,7 +17,7 @@ export type AiUsage = {
|
|||||||
estimated: boolean;
|
estimated: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function emptyUsage(): AiUsage {
|
export function emptyUsage(): AiUsage {
|
||||||
return {
|
return {
|
||||||
promptTokens: 0,
|
promptTokens: 0,
|
||||||
cacheReadTokens: 0,
|
cacheReadTokens: 0,
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ import {
|
|||||||
needsStreamUsageInjection,
|
needsStreamUsageInjection,
|
||||||
withStreamUsageOption,
|
withStreamUsageOption,
|
||||||
extractResponseModel,
|
extractResponseModel,
|
||||||
|
emptyUsage,
|
||||||
type AiUsage
|
type AiUsage
|
||||||
} from "@server/lib/aiUsageExtraction";
|
} from "@server/lib/aiUsageExtraction";
|
||||||
import { streamAiGatewayResponse } from "@server/routers/aiGateway/streamAiGatewayResponse";
|
import { streamAiGatewayResponse } from "@server/routers/aiGateway/streamAiGatewayResponse";
|
||||||
@@ -713,19 +714,35 @@ export function recordAiGatewayCompletion(args: {
|
|||||||
budgets
|
budgets
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
let usage: AiUsage | null = extractUsage(
|
// A non-2xx status means the upstream provider rejected the request
|
||||||
capability,
|
// (bad auth, invalid request, rate limit, 5xx, etc.) before ever running
|
||||||
responseText,
|
// the model - no tokens were actually billed, so don't estimate usage
|
||||||
isStream,
|
// off the error body text or price/charge it. We still record a
|
||||||
headers
|
// zeroed-out row below (rather than skipping it) so request-count
|
||||||
);
|
// dashboards built on aiUsageRecords keep counting every attempt.
|
||||||
if (!usage || isUsageEmpty(usage)) {
|
const upstreamSucceeded = statusCode >= 200 && statusCode < 300;
|
||||||
usage = estimateUsage(JSON.stringify(requestBody ?? ""), responseText);
|
|
||||||
}
|
|
||||||
|
|
||||||
const model = extractResponseModel(responseText) ?? requestedModel;
|
let usage: AiUsage;
|
||||||
const pricing = getModelPricing(provider.type as AiProviderType, model);
|
let model: string | undefined;
|
||||||
const cost = calculateAiCost(pricing, usage);
|
let pricing: ReturnType<typeof getModelPricing> = null;
|
||||||
|
let cost: ReturnType<typeof calculateAiCost> = null;
|
||||||
|
|
||||||
|
if (upstreamSucceeded) {
|
||||||
|
usage = extractUsage(capability, responseText, isStream, headers) ?? emptyUsage();
|
||||||
|
if (isUsageEmpty(usage)) {
|
||||||
|
usage = estimateUsage(
|
||||||
|
JSON.stringify(requestBody ?? ""),
|
||||||
|
responseText
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
model = extractResponseModel(responseText) ?? requestedModel;
|
||||||
|
pricing = getModelPricing(provider.type as AiProviderType, model);
|
||||||
|
cost = calculateAiCost(pricing, usage);
|
||||||
|
} else {
|
||||||
|
usage = emptyUsage();
|
||||||
|
model = requestedModel;
|
||||||
|
}
|
||||||
|
|
||||||
// Shared by the usage record and the session log so the two can be
|
// Shared by the usage record and the session log so the two can be
|
||||||
// joined later to show token/cost usage alongside the transcript -
|
// joined later to show token/cost usage alongside the transcript -
|
||||||
@@ -738,6 +755,7 @@ export function recordAiGatewayCompletion(args: {
|
|||||||
providerId: provider.providerId,
|
providerId: provider.providerId,
|
||||||
providerType: provider.type,
|
providerType: provider.type,
|
||||||
model,
|
model,
|
||||||
|
statusCode,
|
||||||
estimated: usage.estimated,
|
estimated: usage.estimated,
|
||||||
promptTokens: usage.promptTokens,
|
promptTokens: usage.promptTokens,
|
||||||
cacheReadTokens: usage.cacheReadTokens,
|
cacheReadTokens: usage.cacheReadTokens,
|
||||||
|
|||||||
Reference in New Issue
Block a user