Skip to content

Commit a55f262

Browse files
committed
Fixed a bunch of coderabbit issues
1 parent b8067ca commit a55f262

File tree

7 files changed

+123
-111
lines changed

7 files changed

+123
-111
lines changed

apps/webapp/app/routes/admin.api.v1.llm-models.$modelId.ts

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,13 @@ export async function action({ request, params }: ActionFunctionArgs) {
8181
return json({ error: "Method not allowed" }, { status: 405 });
8282
}
8383

84-
const body = await request.json();
84+
let body: unknown;
85+
try {
86+
body = await request.json();
87+
} catch {
88+
return json({ error: "Invalid JSON body" }, { status: 400 });
89+
}
90+
8591
const parsed = UpdateModelSchema.safeParse(body);
8692

8793
if (!parsed.success) {
@@ -90,59 +96,56 @@ export async function action({ request, params }: ActionFunctionArgs) {
9096

9197
const { modelName, matchPattern, startDate, pricingTiers } = parsed.data;
9298

93-
// Validate regex if provided
99+
// Validate regex if provided — strip (?i) POSIX flag since our registry handles it
94100
if (matchPattern) {
95101
try {
96-
new RegExp(matchPattern);
102+
const testPattern = matchPattern.startsWith("(?i)") ? matchPattern.slice(4) : matchPattern;
103+
new RegExp(testPattern);
97104
} catch {
98105
return json({ error: "Invalid regex in matchPattern" }, { status: 400 });
99106
}
100107
}
101108

102-
// Update model fields
103-
const model = await prisma.llmModel.update({
104-
where: { id: modelId },
105-
data: {
106-
...(modelName !== undefined && { modelName }),
107-
...(matchPattern !== undefined && { matchPattern }),
108-
...(startDate !== undefined && { startDate: startDate ? new Date(startDate) : null }),
109-
},
110-
});
111-
112-
// If pricing tiers provided, replace them entirely
113-
if (pricingTiers) {
114-
// Delete existing tiers (cascades to prices)
115-
await prisma.llmPricingTier.deleteMany({ where: { modelId } });
116-
117-
// Create new tiers
118-
for (const tier of pricingTiers) {
119-
await prisma.llmPricingTier.create({
120-
data: {
121-
modelId,
122-
name: tier.name,
123-
isDefault: tier.isDefault,
124-
priority: tier.priority,
125-
conditions: tier.conditions,
126-
prices: {
127-
create: Object.entries(tier.prices).map(([usageType, price]) => ({
128-
modelId,
129-
usageType,
130-
price,
131-
})),
109+
// Update model + tiers atomically
110+
const updated = await prisma.$transaction(async (tx) => {
111+
await tx.llmModel.update({
112+
where: { id: modelId },
113+
data: {
114+
...(modelName !== undefined && { modelName }),
115+
...(matchPattern !== undefined && { matchPattern }),
116+
...(startDate !== undefined && { startDate: startDate ? new Date(startDate) : null }),
117+
},
118+
});
119+
120+
if (pricingTiers) {
121+
await tx.llmPricingTier.deleteMany({ where: { modelId } });
122+
123+
for (const tier of pricingTiers) {
124+
await tx.llmPricingTier.create({
125+
data: {
126+
modelId,
127+
name: tier.name,
128+
isDefault: tier.isDefault,
129+
priority: tier.priority,
130+
conditions: tier.conditions,
131+
prices: {
132+
create: Object.entries(tier.prices).map(([usageType, price]) => ({
133+
modelId,
134+
usageType,
135+
price,
136+
})),
137+
},
132138
},
133-
},
134-
});
139+
});
140+
}
135141
}
136-
}
137142

138-
const updated = await prisma.llmModel.findUnique({
139-
where: { id: modelId },
140-
include: {
141-
pricingTiers: {
142-
include: { prices: true },
143-
orderBy: { priority: "asc" },
143+
return tx.llmModel.findUnique({
144+
where: { id: modelId },
145+
include: {
146+
pricingTiers: { include: { prices: true }, orderBy: { priority: "asc" } },
144147
},
145-
},
148+
});
146149
});
147150

148151
return json({ model: updated });

apps/webapp/app/routes/admin.api.v1.llm-models.ts

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,13 @@ export async function action({ request }: ActionFunctionArgs) {
7575
return json({ error: "Method not allowed" }, { status: 405 });
7676
}
7777

78-
const body = await request.json();
78+
let body: unknown;
79+
try {
80+
body = await request.json();
81+
} catch {
82+
return json({ error: "Invalid JSON body" }, { status: 400 });
83+
}
84+
7985
const parsed = CreateModelSchema.safeParse(body);
8086

8187
if (!parsed.success) {
@@ -84,50 +90,51 @@ export async function action({ request }: ActionFunctionArgs) {
8490

8591
const { modelName, matchPattern, startDate, source, pricingTiers } = parsed.data;
8692

87-
// Validate regex pattern
93+
// Validate regex pattern — strip (?i) POSIX flag since our registry handles it
8894
try {
89-
new RegExp(matchPattern);
95+
const testPattern = matchPattern.startsWith("(?i)") ? matchPattern.slice(4) : matchPattern;
96+
new RegExp(testPattern);
9097
} catch {
9198
return json({ error: "Invalid regex in matchPattern" }, { status: 400 });
9299
}
93100

94-
// Create model first, then tiers with explicit model connection
95-
const model = await prisma.llmModel.create({
96-
data: {
97-
friendlyId: generateFriendlyId("llm_model"),
98-
modelName,
99-
matchPattern,
100-
startDate: startDate ? new Date(startDate) : null,
101-
source,
102-
},
103-
});
104-
105-
for (const tier of pricingTiers) {
106-
await prisma.llmPricingTier.create({
101+
// Create model + tiers atomically
102+
const created = await prisma.$transaction(async (tx) => {
103+
const model = await tx.llmModel.create({
107104
data: {
108-
modelId: model.id,
109-
name: tier.name,
110-
isDefault: tier.isDefault,
111-
priority: tier.priority,
112-
conditions: tier.conditions,
113-
prices: {
114-
create: Object.entries(tier.prices).map(([usageType, price]) => ({
115-
modelId: model.id,
116-
usageType,
117-
price,
118-
})),
119-
},
105+
friendlyId: generateFriendlyId("llm_model"),
106+
modelName,
107+
matchPattern,
108+
startDate: startDate ? new Date(startDate) : null,
109+
source,
120110
},
121111
});
122-
}
123112

124-
const created = await prisma.llmModel.findUnique({
125-
where: { id: model.id },
126-
include: {
127-
pricingTiers: {
128-
include: { prices: true },
113+
for (const tier of pricingTiers) {
114+
await tx.llmPricingTier.create({
115+
data: {
116+
modelId: model.id,
117+
name: tier.name,
118+
isDefault: tier.isDefault,
119+
priority: tier.priority,
120+
conditions: tier.conditions,
121+
prices: {
122+
create: Object.entries(tier.prices).map(([usageType, price]) => ({
123+
modelId: model.id,
124+
usageType,
125+
price,
126+
})),
127+
},
128+
},
129+
});
130+
}
131+
132+
return tx.llmModel.findUnique({
133+
where: { id: model.id },
134+
include: {
135+
pricingTiers: { include: { prices: true } },
129136
},
130-
},
137+
});
131138
});
132139

133140
return json({ model: created }, { status: 201 });

apps/webapp/app/routes/admin.llm-models.missing.$model.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
1616
const user = await prisma.user.findUnique({ where: { id: userId } });
1717
if (!user?.admin) return redirect("/");
1818

19-
// Model name is base64url-encoded in the URL param
19+
// Model name is URL-encoded in the URL param
2020
const modelName = decodeURIComponent(params.model ?? "");
2121
if (!modelName) throw new Response("Missing model param", { status: 400 });
2222

@@ -142,7 +142,7 @@ export default function AdminMissingModelDetailRoute() {
142142
</span>
143143
<div className="flex gap-4 mt-1 font-mono text-text-bright">
144144
<span>input: {providerCosts[0].estimatedInputPrice.toExponential(4)}</span>
145-
<span>output: {providerCosts[0].estimatedOutputPrice!.toExponential(4)}</span>
145+
<span>output: {providerCosts[0].estimatedOutputPrice ?? 0.toExponential(4)}</span>
146146
</div>
147147
<span className="text-text-dimmed mt-1 block">
148148
Cross-reference with the provider's pricing page before using these estimates.
@@ -457,7 +457,7 @@ The gateway/router is reporting costs for this model. Use these to cross-referen
457457
${providerCosts.map((c) => `- $${c.cost.toFixed(6)} for ${c.inputTokens.toLocaleString()} input + ${c.outputTokens.toLocaleString()} output tokens`).join("\n")}${providerCosts[0].estimatedInputPrice != null ? `
458458
- Estimated per-token rates (rough, assuming ~3x output/input ratio):
459459
- input: ${providerCosts[0].estimatedInputPrice.toExponential(4)} (${(providerCosts[0].estimatedInputPrice * 1_000_000).toFixed(4)} $/M)
460-
- output: ${providerCosts[0].estimatedOutputPrice!.toExponential(4)} (${(providerCosts[0].estimatedOutputPrice! * 1_000_000).toFixed(4)} $/M)
460+
- output: ${providerCosts[0].estimatedOutputPrice ?? 0.toExponential(4)} (${(providerCosts[0].estimatedOutputPrice ?? 0 * 1_000_000).toFixed(4)} $/M)
461461
- Verify these against the official pricing page before using.` : ""}` : ""}${sampleAttrs ? `
462462
463463
## Sample span attributes (first span)

apps/webapp/app/services/admin/missingLlmModels.server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ export async function getMissingLlmModels(opts: {
7070

7171
// Filter out models that now have pricing in the database (added after spans were inserted).
7272
// The registry's match() handles prefix stripping for gateway/openrouter models.
73-
return candidates.filter((c) => !llmPricingRegistry?.match(c.model));
73+
if (!llmPricingRegistry?.isLoaded) return candidates;
74+
return candidates.filter((c) => !llmPricingRegistry.match(c.model));
7475
}
7576

7677
export type MissingModelSample = {

internal-packages/llm-pricing/scripts/sync-model-prices.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ echo "Generating defaultPrices.ts..."
5050
node -e "
5151
const data = JSON.parse(require('fs').readFileSync('$JSON_TARGET', 'utf-8'));
5252
const stripped = data.map(e => ({
53-
modelName: e.modelName,
53+
modelName: e.modelName.trim(),
5454
matchPattern: e.matchPattern,
5555
startDate: e.createdAt,
5656
pricingTiers: e.pricingTiers.map(t => ({

internal-packages/llm-pricing/src/defaultPrices.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,7 @@ export const defaultModelPrices: DefaultModelDefinition[] = [
11091109
]
11101110
},
11111111
{
1112-
"modelName": " gpt-4-preview",
1112+
"modelName": "gpt-4-preview",
11131113
"matchPattern": "(?i)^(openai/)?(gpt-4-preview)$",
11141114
"startDate": "2024-04-23T10:37:17.092Z",
11151115
"pricingTiers": [

internal-packages/llm-pricing/src/seed.ts

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,37 @@ export async function seedLlmPricing(prisma: PrismaClient): Promise<{
2323
continue;
2424
}
2525

26-
// Create model first
27-
const model = await prisma.llmModel.create({
28-
data: {
29-
friendlyId: generateFriendlyId("llm_model"),
30-
modelName: modelDef.modelName,
31-
matchPattern: modelDef.matchPattern,
32-
startDate: modelDef.startDate ? new Date(modelDef.startDate) : null,
33-
source: "default",
34-
},
35-
});
36-
37-
// Create tiers and prices with explicit model connection
38-
for (const tier of modelDef.pricingTiers) {
39-
await prisma.llmPricingTier.create({
26+
// Create model + tiers atomically so partial models can't be left behind
27+
await prisma.$transaction(async (tx) => {
28+
const model = await tx.llmModel.create({
4029
data: {
41-
modelId: model.id,
42-
name: tier.name,
43-
isDefault: tier.isDefault,
44-
priority: tier.priority,
45-
conditions: tier.conditions,
46-
prices: {
47-
create: Object.entries(tier.prices).map(([usageType, price]) => ({
48-
modelId: model.id,
49-
usageType,
50-
price,
51-
})),
52-
},
30+
friendlyId: generateFriendlyId("llm_model"),
31+
modelName: modelDef.modelName.trim(),
32+
matchPattern: modelDef.matchPattern,
33+
startDate: modelDef.startDate ? new Date(modelDef.startDate) : null,
34+
source: "default",
5335
},
5436
});
55-
}
37+
38+
for (const tier of modelDef.pricingTiers) {
39+
await tx.llmPricingTier.create({
40+
data: {
41+
modelId: model.id,
42+
name: tier.name,
43+
isDefault: tier.isDefault,
44+
priority: tier.priority,
45+
conditions: tier.conditions,
46+
prices: {
47+
create: Object.entries(tier.prices).map(([usageType, price]) => ({
48+
modelId: model.id,
49+
usageType,
50+
price,
51+
})),
52+
},
53+
},
54+
});
55+
}
56+
});
5657

5758
modelsCreated++;
5859
}

0 commit comments

Comments
 (0)