feat: Enhance LLM robustness with improved error handling and model resolution
This commit is contained in:
43
src/llm.ts
43
src/llm.ts
@@ -111,7 +111,17 @@ export async function analyzeProducts(
|
|||||||
}
|
}
|
||||||
return fallback;
|
return fallback;
|
||||||
}
|
}
|
||||||
throw err;
|
|
||||||
|
const errorReason = formatErrorReason(err);
|
||||||
|
console.warn(
|
||||||
|
`LLM request failed for ${products.length} product(s): ${errorReason}`,
|
||||||
|
);
|
||||||
|
return products.map((product) => ({
|
||||||
|
asin: product.record.asin,
|
||||||
|
verdict: "SKIP" as const,
|
||||||
|
confidence: 0,
|
||||||
|
reasoning: `LLM analysis failed: ${errorReason}`,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,6 +205,10 @@ async function requestClaudeContent(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const model = resolveAnthropicModel(
|
||||||
|
config.anthropicModel ?? "claude-sonnet-4-6",
|
||||||
|
);
|
||||||
|
|
||||||
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -203,7 +217,7 @@ async function requestClaudeContent(
|
|||||||
"anthropic-version": "2023-06-01",
|
"anthropic-version": "2023-06-01",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
model: config.anthropicModel,
|
model,
|
||||||
system: systemPrompt,
|
system: systemPrompt,
|
||||||
messages: [
|
messages: [
|
||||||
{ role: "user", content: JSON.stringify(productSummaries, null, 2) },
|
{ role: "user", content: JSON.stringify(productSummaries, null, 2) },
|
||||||
@@ -230,6 +244,31 @@ async function requestClaudeContent(
|
|||||||
.join("\n");
|
.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveAnthropicModel(rawModel: string): string {
|
||||||
|
const normalized = rawModel.trim().toLowerCase();
|
||||||
|
const aliases: Record<string, string> = {
|
||||||
|
"claude-4-6-sonnet": "claude-sonnet-4-6",
|
||||||
|
"claude-4-6-haiku": "claude-haiku-4-5",
|
||||||
|
"claude-4-7-opus": "claude-opus-4-7",
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapped = aliases[normalized];
|
||||||
|
if (mapped && mapped !== rawModel) {
|
||||||
|
console.warn(
|
||||||
|
`ANTHROPIC_MODEL '${rawModel}' is not an official API ID. Using '${mapped}' instead.`,
|
||||||
|
);
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatErrorReason(err: unknown): string {
|
||||||
|
const message = String(err).replace(/\s+/g, " ").trim();
|
||||||
|
if (!message) return "Unknown LLM error";
|
||||||
|
return message.length > 140 ? `${message.slice(0, 137)}...` : message;
|
||||||
|
}
|
||||||
|
|
||||||
async function readErrorBody(response: Response): Promise<string> {
|
async function readErrorBody(response: Response): Promise<string> {
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
if (!text.trim()) return "No response body";
|
if (!text.trim()) return "No response body";
|
||||||
|
|||||||
Reference in New Issue
Block a user