From ac29da3bc3b3e49309e9d6537f0f3164687b1c1b Mon Sep 17 00:00:00 2001 From: mpstaton Date: Sat, 9 May 2026 21:44:13 -0500 Subject: [PATCH] fix(directory-templates): switch concept-profile to sonar-pro; surface unreplaced image markers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Concept-profile was using sonar-deep-research, which the article-generator's existing compatibility-warning has long flagged as "Images are unstable in deep research mode" — Perplexity returns an empty images array, so the [IMAGE N: …] markers the model emits never get swapped for embeds and the template's image-placeholder text leaks into the output. Two changes: 1. Concept-profile drops to sonar-pro to match vocabulary-profile. Both are encyclopedia-style entries that don't need the multi-step research loop; sonar-pro is also the model that reliably returns images. 2. Post-stream cleanup now counts [IMAGE N: …] markers before and after replacement. When markers remain unreplaced, log a console warning and show a Notice telling the user how many markers stayed and how many images Perplexity actually returned — so the failure mode is visible instead of silent. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/docs/templates/concept-profile.md | 2 +- src/services/directoryTemplateService.ts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/docs/templates/concept-profile.md b/src/docs/templates/concept-profile.md index 94f1abf..5a36a1c 100644 --- a/src/docs/templates/concept-profile.md +++ b/src/docs/templates/concept-profile.md @@ -13,7 +13,7 @@ # About this template ```cft provider: perplexity -model: sonar-deep-research +model: sonar-pro search-recency: year return-citations: true return-images: true diff --git a/src/services/directoryTemplateService.ts b/src/services/directoryTemplateService.ts index 0653d5d..b764f79 100644 --- a/src/services/directoryTemplateService.ts +++ b/src/services/directoryTemplateService.ts @@ -520,8 +520,25 @@ export async function applyTemplate( const trimmedStreamed = streamed.replace(/^\s+/, '').replace(/\s+$/, ''); let cleanedStreamed = wrapThinkBlocks(trimmedStreamed); if (wantsImages) { + const markerRe = /\[IMAGE\s+\d+:\s*[^\]]*?\]/gi; + const markersBefore = (cleanedStreamed.match(markerRe) ?? []).length; cleanedStreamed = processContentWithImages(cleanedStreamed, images); cleanedStreamed = stripUnreplacedImagePlaceholders(cleanedStreamed); + const markersAfter = (cleanedStreamed.match(markerRe) ?? []).length; + // Diagnostics: when the model emitted markers but Perplexity returned + // no images (common on sonar-deep-research), surface so the user knows + // why image embeds didn't appear. console keeps the detail; Notice is + // skipped in batch (quiet) mode. + if (markersBefore > 0 && markersAfter > 0) { + console.warn( + `[directoryTemplateService] ${markersAfter.toString()} of ${markersBefore.toString()} [IMAGE N: …] markers were not replaced. images.length=${images.length.toString()}, model=${modelName}.` + ); + if (!quiet) { + new Notice( + `${markersAfter.toString()} image markers left unreplaced — Perplexity returned ${images.length.toString()} image(s).` + ); + } + } } const sourcesFooter = buildSourcesFooter(sources); const finalContent = `${initialContent}${cleanedStreamed}\n${sourcesFooter}`;