From 910d26add380dedbfeec2fcc1370a13a61f0d1fb Mon Sep 17 00:00:00 2001 From: Jose Henrique Date: Fri, 3 Apr 2026 11:48:17 -0300 Subject: [PATCH] fixes! --- packages/backend/src/agents/retrieval.ts | 1 + packages/backend/src/pipelines/recommendation.ts | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/agents/retrieval.ts b/packages/backend/src/agents/retrieval.ts index bc6da7b..f292104 100644 --- a/packages/backend/src/agents/retrieval.ts +++ b/packages/backend/src/agents/retrieval.ts @@ -37,6 +37,7 @@ Rules: - Each "reason" should briefly explain why the ${mediaLabel} matches the preferences - Avoid duplicates - Include ${mediaLabelPlural} from different decades, countries${mediaType === 'tv_show' ? ', and networks' : ', and directors'} +- The "title" field must contain ONLY the exact title name — no years, descriptions, network names, episode counts, or parenthetical notes. ✗ Bad: "Breaking Bad (2008–2013, AMC)" ✓ Good: "Breaking Bad" - Aim for ${brainstormCount} candidates minimum${previousFullMatches.length > 0 ? '\n- Do NOT suggest titles already in the Previous Full Matches list — generate NEW candidates inspired by what made those successful' : ''}${hardRequirements ? '\n\nIMPORTANT: Strictly follow ALL requirements. Exclude any candidate that does not meet every stated requirement.' : ''}`, input: `Structured preferences: Liked ${mediaLabelPlural}: ${input.liked.join(', ') || '(none)'} diff --git a/packages/backend/src/pipelines/recommendation.ts b/packages/backend/src/pipelines/recommendation.ts index 2afded1..f67d227 100644 --- a/packages/backend/src/pipelines/recommendation.ts +++ b/packages/backend/src/pipelines/recommendation.ts @@ -121,12 +121,13 @@ async function runSubPipeline(ctx: SubPipelineCtx): Promise { runRanking(interpreterOutput, { candidates: bucket }, mediaType, useHardRequirements) ) ); + const dedupTitles = (titles: string[]) => [...new Map(titles.map((t) => [t.toLowerCase(), t])).values()]; const rankingOutput: RankingOutput = { - full_match: rankingBuckets.flatMap((r) => r.full_match), - definitely_like: rankingBuckets.flatMap((r) => r.definitely_like), - might_like: rankingBuckets.flatMap((r) => r.might_like), - questionable: rankingBuckets.flatMap((r) => r.questionable), - will_not_like: rankingBuckets.flatMap((r) => r.will_not_like), + full_match: dedupTitles(rankingBuckets.flatMap((r) => r.full_match)), + definitely_like: dedupTitles(rankingBuckets.flatMap((r) => r.definitely_like)), + might_like: dedupTitles(rankingBuckets.flatMap((r) => r.might_like)), + questionable: dedupTitles(rankingBuckets.flatMap((r) => r.questionable)), + will_not_like: dedupTitles(rankingBuckets.flatMap((r) => r.will_not_like)), }; log(recId, `${stagePrefix}Ranking: done (${Date.now() - t2}ms) — ${rankBucketCount} buckets`, { full_match: rankingOutput.full_match.length, @@ -163,7 +164,7 @@ async function runSubPipeline(ctx: SubPipelineCtx): Promise { runCurator(ranking, interpreterOutput, mediaType, useWebSearch) ) ); - const curatorOutput = curatorBucketOutputs.flat(); + const curatorOutput = curatorBucketOutputs.reduce((acc, bucket) => mergeCuratorOutputs(acc, bucket), [] as CuratorOutput[]); log(recId, `${stagePrefix}Curator: done (${Date.now() - t3}ms) — ${curatorOutput.length} items curated (${curatorBucketCount} buckets)`); sseWrite({ stage: p('curator'), status: 'done', data: curatorOutput });