fix: cart premlink fixed

This commit is contained in:
root 2026-05-11 23:06:18 +05:00
parent d1b657cba7
commit db9b09e09a
2 changed files with 90 additions and 7 deletions

View File

@ -43,7 +43,12 @@ describe("automatic storefront upsells", () => {
it("returns no upsell when the AI chooses null", () => {
const result = parseAiUpsellChoice(
JSON.stringify({ productId: null, reason: "No clearly complementary product." }),
JSON.stringify({
productId: null,
relationshipType: "uncertain",
confidence: 0,
reason: "No clearly complementary product.",
}),
[
{
title: "Candidate Product",
@ -61,9 +66,64 @@ describe("automatic storefront upsells", () => {
expect(result).toBeNull()
})
it("rejects AI choices marked as substitutes", () => {
const result = parseAiUpsellChoice(
JSON.stringify({
productId: "candidate-1",
relationshipType: "substitute",
confidence: 0.9,
reason: "This is an alternative, not an add-on.",
}),
[
{
title: "Candidate Product",
productType: "Same Category",
details: null,
product: {
productId: "candidate-1",
title: "Candidate Product",
variantId: "v-candidate",
},
},
],
)
expect(result).toBeNull()
})
it("accepts high-confidence complementary AI choices", () => {
const result = parseAiUpsellChoice(
JSON.stringify({
productId: "candidate-1",
relationshipType: "complementary_accessory",
confidence: 0.88,
reason: "This is used together with the base product.",
}),
[
{
title: "Candidate Product",
productType: "Accessory",
details: null,
product: {
productId: "candidate-1",
title: "Candidate Product",
variantId: "v-candidate",
},
},
],
)
expect(result?.productId).toBe("candidate-1")
})
it("only accepts AI choices that exist in the candidate list", () => {
const result = parseAiUpsellChoice(
JSON.stringify({ productId: "unknown-product", reason: "Not in the provided list." }),
JSON.stringify({
productId: "unknown-product",
relationshipType: "complementary_accessory",
confidence: 0.9,
reason: "Not in the provided list.",
}),
[
{
title: "Candidate Product",

View File

@ -21,6 +21,14 @@ type UpsellCatalogCandidate = {
details: string | null
}
const ACCEPTED_UPSELL_RELATIONSHIPS = new Set([
"complementary_accessory",
"care_item",
"consumable",
"bundle_addon",
"used_together",
])
function imageUrlFromImages(images: unknown): string | null {
const rows = typeof images === "string"
? (() => {
@ -104,9 +112,20 @@ export function parseAiUpsellChoice(
): StorefrontActionProduct | null {
if (!content) return null
try {
const parsed = JSON.parse(content) as { productId?: unknown }
const parsed = JSON.parse(content) as {
productId?: unknown
relationshipType?: unknown
confidence?: unknown
}
const productId = typeof parsed.productId === "string" ? parsed.productId.trim() : ""
if (!productId) return null
const relationshipType =
typeof parsed.relationshipType === "string"
? parsed.relationshipType.trim().toLowerCase()
: ""
if (!ACCEPTED_UPSELL_RELATIONSHIPS.has(relationshipType)) return null
const confidence = Number(parsed.confidence)
if (!Number.isFinite(confidence) || confidence < 0.75) return null
return candidates.find((candidate) => candidate.product.productId === productId)?.product ?? null
} catch {
return null
@ -122,10 +141,14 @@ async function selectAiUpsellCandidate(params: {
const system = [
"You select one ecommerce upsell item, or no item.",
"Use only the provided catalog candidates. Return JSON only: {\"productId\":\"...\"|null,\"reason\":\"...\"}.",
"A valid upsell must be clearly complementary to the base product: accessory, care item, consumable, add-on, matching bundle item, or item normally used together.",
"Do not choose substitutes or alternatives to the same requested product type, even if they share words, audience, color, brand, season, or price.",
"If the relationship is weak, generic, or uncertain, return productId null.",
"Use only the provided catalog candidates.",
"Return JSON only: {\"productId\":\"...\"|null,\"relationshipType\":\"complementary_accessory|care_item|consumable|bundle_addon|used_together|substitute|alternative|same_category|unrelated|uncertain\",\"confidence\":0-1,\"reason\":\"...\"}.",
"A valid upsell must be something the customer would reasonably buy in addition to the base product and use together with it.",
"Choose only these valid relationship types: complementary_accessory, care_item, consumable, bundle_addon, used_together.",
"Do not choose substitutes, alternatives, or same-category replacements, even if they share words, audience, color, brand, season, style, or price.",
"Invalid examples: sandals -> flip flops, slippers -> shoes, rain boots -> formal shoes, one backpack -> another backpack.",
"Valid examples: shoes -> socks, shoes -> laces, leather shoes -> polish, phone -> case, backpack -> lunch box.",
"If there is no clear add-on with confidence at least 0.75, return productId null with relationshipType uncertain.",
].join(" ")
const user = JSON.stringify({