refactor(ui): build transformed model rows without in-place mutation

Greptile flagged the per-second fields for extending the transformer's
mutate-in-a-loop pattern. Map each raw model to a new object instead so no
field is assigned onto a shared reference, and drop the now unused
prefer-const suppression for the file
This commit is contained in:
ryan-crabbe-berri 2026-09-17 16:24:55 -07:00
parent dfc74d3806
commit a282e3c78c
2 changed files with 60 additions and 80 deletions

View file

@ -656,11 +656,6 @@
"count": 1
}
},
"src/app/(dashboard)/models-and-endpoints/utils/modelDataTransformer.ts": {
"prefer-const": {
"count": 6
}
},
"src/app/(dashboard)/old-usage/_components/usage.tsx": {
"local/filename-pascal-case": {
"count": 1

View file

@ -11,82 +11,67 @@ export const perSecondCostTiers = (modelInfo: Record<string, unknown> | null | u
export const formatPerSecondCost = (cost: number): string =>
`$${cost.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 6 })}/s`;
/**
* Utility function to transform raw model data into the format expected by UI components
* This creates a new transformed data object without mutating the original
*/
interface RawLitellmParams {
model?: string;
custom_llm_provider?: string;
api_base?: string;
output_cost_per_second?: number;
[key: string]: unknown;
}
interface RawModelInfo {
input_cost_per_token?: number | null;
output_cost_per_token?: number | null;
output_cost_per_second?: number;
max_tokens?: number;
max_input_tokens?: number;
[key: string]: unknown;
}
interface RawModel {
litellm_params?: RawLitellmParams;
model_info?: RawModelInfo;
[key: string]: unknown;
}
const costPerMillionTokens = (costPerToken: number | null | undefined) =>
costPerToken == null ? costPerToken : (Number(costPerToken) * 1000000).toFixed(2);
const resolveProvider = (
litellmModelName: string | null | undefined,
customLlmProvider: string | null | undefined,
getProviderFromModel: (model: string) => string,
): string => {
if (!litellmModelName) return "-";
if (customLlmProvider) return customLlmProvider;
const splitModel = litellmModelName.split("/");
return splitModel.length === 1 ? getProviderFromModel(litellmModelName) : splitModel[0];
};
const transformModel = (rawModel: RawModel, getProviderFromModel: (model: string) => string) => {
const model: RawModel = JSON.parse(JSON.stringify(rawModel));
const litellmParams = model?.litellm_params;
const modelInfo = model?.model_info;
return {
...model,
provider: resolveProvider(litellmParams?.model, litellmParams?.custom_llm_provider, getProviderFromModel),
input_cost: modelInfo ? costPerMillionTokens(modelInfo.input_cost_per_token) : null,
output_cost: modelInfo ? costPerMillionTokens(modelInfo.output_cost_per_token) : null,
output_cost_per_second: litellmParams?.output_cost_per_second ?? modelInfo?.output_cost_per_second ?? null,
output_cost_per_second_tiers: perSecondCostTiers(modelInfo),
litellm_model_name: litellmParams?.model,
max_tokens: modelInfo ? modelInfo.max_tokens : "Undefined",
max_input_tokens: modelInfo ? modelInfo.max_input_tokens : "Undefined",
api_base: litellmParams?.api_base,
cleanedLitellmParams: Object.fromEntries(
Object.entries(litellmParams ?? {}).filter(([key]) => key !== "model" && key !== "api_base"),
),
};
};
export const transformModelData = (rawModelData: any, getProviderFromModel: (model: string) => string) => {
if (!rawModelData?.data) return { data: [] };
// Deep copy the data to avoid mutating the original
const transformedData = JSON.parse(JSON.stringify(rawModelData.data));
for (let i = 0; i < transformedData.length; i++) {
let curr_model = transformedData[i];
let litellm_model_name = curr_model?.litellm_params?.model;
let custom_llm_provider = curr_model?.litellm_params?.custom_llm_provider;
let model_info = curr_model?.model_info;
let provider = "";
let input_cost: any = null;
let output_cost: any = null;
let max_tokens = "Undefined";
let max_input_tokens = "Undefined";
let cleanedLitellmParams = {};
// Check if litellm_model_name is null or undefined
if (litellm_model_name) {
// Split litellm_model_name based on "/"
let splitModel = litellm_model_name.split("/");
// Get the first element in the split
let firstElement = splitModel[0];
// If there is only one element, default provider to openai
provider = custom_llm_provider;
if (!provider) {
provider = splitModel.length === 1 ? getProviderFromModel(litellm_model_name) : firstElement;
}
} else {
// litellm_model_name is null or undefined, default provider to openai
provider = "-";
}
if (model_info) {
input_cost = model_info?.input_cost_per_token;
output_cost = model_info?.output_cost_per_token;
max_tokens = model_info?.max_tokens;
max_input_tokens = model_info?.max_input_tokens;
}
if (curr_model?.litellm_params) {
cleanedLitellmParams = Object.fromEntries(
Object.entries(curr_model?.litellm_params).filter(([key]) => key !== "model" && key !== "api_base"),
);
}
transformedData[i].provider = provider;
transformedData[i].input_cost = input_cost;
transformedData[i].output_cost = output_cost;
transformedData[i].output_cost_per_second =
curr_model?.litellm_params?.output_cost_per_second ?? model_info?.output_cost_per_second ?? null;
transformedData[i].output_cost_per_second_tiers = perSecondCostTiers(model_info);
transformedData[i].litellm_model_name = litellm_model_name;
// Convert Cost in terms of Cost per 1M tokens
if (transformedData[i].input_cost != null) {
transformedData[i].input_cost = (Number(transformedData[i].input_cost) * 1000000).toFixed(2);
}
if (transformedData[i].output_cost != null) {
transformedData[i].output_cost = (Number(transformedData[i].output_cost) * 1000000).toFixed(2);
}
transformedData[i].max_tokens = max_tokens;
transformedData[i].max_input_tokens = max_input_tokens;
transformedData[i].api_base = curr_model?.litellm_params?.api_base;
transformedData[i].cleanedLitellmParams = cleanedLitellmParams;
}
return { data: transformedData };
return { data: rawModelData.data.map((rawModel: RawModel) => transformModel(rawModel, getProviderFromModel)) };
};