From 00c4e067bfcc19214bf9e1d7aaa38d3b869c3248 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 27 Apr 2026 21:53:02 +0800 Subject: [PATCH] fix: enforce brand matching for references --- .../agent-workflow/reference-search/route.ts | 74 ++++++++++++------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/app/api/agent-workflow/reference-search/route.ts b/app/api/agent-workflow/reference-search/route.ts index f119bfe4a..114ce5094 100644 --- a/app/api/agent-workflow/reference-search/route.ts +++ b/app/api/agent-workflow/reference-search/route.ts @@ -42,6 +42,9 @@ type ExternalTaskDetailCandidate = { brand?: string; productBrand?: string; brand_name?: string; + brand_name_cn?: string; + brandTitle?: string; + brand_title?: string; categoryName?: string; shopName?: string; sceneName?: string; @@ -64,6 +67,10 @@ type ExternalTaskDetailResponse = { brandName?: string | null; brand?: string | null; productBrand?: string | null; + brand_name?: string | null; + brand_name_cn?: string | null; + brandTitle?: string | null; + brand_title?: string | null; categoryName?: string | null; shopName?: string | null; candidateCount?: number; @@ -97,6 +104,29 @@ function normalizeUrlList(value: unknown) { ).slice(0, 64); } +function getExternalBrandName(value: { + brandName?: string | null; + brand?: string | null; + productBrand?: string | null; + brand_name?: string | null; + brand_name_cn?: string | null; + brandTitle?: string | null; + brand_title?: string | null; +}) { + return ( + String( + value.brandName || + value.brand || + value.productBrand || + value.brand_name || + value.brand_name_cn || + value.brandTitle || + value.brand_title || + "" + ).trim() || null + ); +} + function mapUpstreamErrorStatus(code: string) { if ( code === "SKU_NOT_FOUND" || @@ -117,21 +147,15 @@ function mapUpstreamErrorStatus(code: string) { function normalizeCandidate( value: ExternalTaskDetailCandidate, - index: number + index: number, + fallbackBrandName?: string | null ): AgentModeReferenceCandidate { const uploadedAt = String(value.uploadedAt || "").trim() || null; const taskNo = String(value.taskNo || "").trim() || null; const materialId = String(value.materialId || "").trim() || null; const sceneName = String(value.sceneName || "").trim() || null; const id = taskNo || materialId || `candidate-${index + 1}`; - const brandName = - String( - value.brandName || - value.brand || - value.productBrand || - value.brand_name || - "" - ).trim() || null; + const brandName = getExternalBrandName(value) || fallbackBrandName || null; return { id, @@ -224,13 +248,6 @@ function filterCandidatesByBrand( const normalizedRequestedBrand = normalizeComparableName(brandName); if (!normalizedRequestedBrand) return candidates; - const hasBrandMetadata = candidates.some((candidate) => - Boolean(normalizeComparableName(candidate.brandName)) - ); - if (!hasBrandMetadata) { - return candidates; - } - return candidates.filter((candidate) => isCandidateMatchedBrand(candidate, normalizedRequestedBrand) ); @@ -267,11 +284,17 @@ export async function GET(request: NextRequest) { const normalizedKeyword = parsed.keyword.trim().toUpperCase(); const queryType = parsed.queryType as AgentWorkflowMaterialQueryType; + const requestedBrandName = String(parsed.brandName || "").trim(); + const upstreamParams = new URLSearchParams({ + resourceType: "task-detail", + [queryType]: normalizedKeyword, + }); + if (requestedBrandName) { + upstreamParams.set("brandName", requestedBrandName); + } const upstreamUrl = `${normalizeBaseUrl( config.baseUrl - )}/standard-model-white-background?resourceType=task-detail&${queryType}=${encodeURIComponent( - normalizedKeyword - )}`; + )}/standard-model-white-background?${upstreamParams.toString()}`; const upstreamResponse = await fetch(upstreamUrl, { method: "GET", @@ -299,9 +322,11 @@ export async function GET(request: NextRequest) { ); } - const requestedBrandName = String(parsed.brandName || "").trim(); + const upstreamBrandName = getExternalBrandName(upstreamResult.data); const sortedCandidates = sortCandidatesByUploadedAtDesc( - (upstreamResult.data.candidates || []).map((item, index) => normalizeCandidate(item, index)) + (upstreamResult.data.candidates || []).map((item, index) => + normalizeCandidate(item, index, upstreamBrandName) + ) ); const normalizedCandidates = filterCandidatesByBrand(sortedCandidates, requestedBrandName) .filter((candidate) => getRenderableCandidateTargetUrls(candidate, parsed.target).length > 0); @@ -353,12 +378,7 @@ export async function GET(request: NextRequest) { matchedSku: String(upstreamResult.data.sku || "").trim() || null, brandName: selectedCandidate.brandName || - String( - upstreamResult.data.brandName || - upstreamResult.data.brand || - upstreamResult.data.productBrand || - "" - ).trim() || + upstreamBrandName || requestedBrandName || null, categoryName: selectedCandidate.categoryName || String(upstreamResult.data.categoryName || "").trim() || null,