From c3f1e4e995695f3faa77191261aedd9f4e66cb65 Mon Sep 17 00:00:00 2001 From: iPLAYCAFE-dev Date: Tue, 30 Jun 2026 02:16:51 +0700 Subject: [PATCH] fix(sentiment): stripCodeFences before JSON.parse (closes #296) Mirror summary.service.ts:146 and merge-assessment.service.ts which already strip fences. Without it, any model that wraps json_object output in ```fences``` (e.g. claude-haiku-4.5, deepseek-chat via OpenRouter) breaks analyzeSentiment's bare JSON.parse. --- .../web/src/lib/server/domains/sentiment/sentiment.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/lib/server/domains/sentiment/sentiment.service.ts b/apps/web/src/lib/server/domains/sentiment/sentiment.service.ts index ecdb5c46c..79d6f3511 100644 --- a/apps/web/src/lib/server/domains/sentiment/sentiment.service.ts +++ b/apps/web/src/lib/server/domains/sentiment/sentiment.service.ts @@ -7,7 +7,7 @@ import { db, postSentiment, posts, eq, and, gte, lte, sql, count, isNull } from '@/lib/server/db' import { createId, type PostId } from '@quackback/ids' -import { getOpenAI } from '@/lib/server/domains/ai/config' +import { getOpenAI, stripCodeFences } from '@/lib/server/domains/ai/config' import { getChatModel } from '@/lib/server/domains/ai/models' import { withRetry } from '@/lib/server/domains/ai/retry' import { withUsageLogging } from '@/lib/server/domains/ai/usage-log' @@ -103,7 +103,7 @@ export async function analyzeSentiment( totalTokens: r.usage?.total_tokens ?? 0, }) ) - const parsed = JSON.parse(response.choices[0]?.message?.content || '{}') + const parsed = JSON.parse(stripCodeFences(response.choices[0]?.message?.content || '{}')) if (!isValidSentiment(parsed.sentiment) || typeof parsed.confidence !== 'number') { log.error({ model_response_keys: Object.keys(parsed) }, 'invalid sentiment model response')