Hello everyone,
I’m posting a solution to my own question, thanks to a brilliant idea from @dawni who answered me in Obsidian’s Discord channel.
The core problem, as I suspected, is that the Web Clipper’s template language cannot map filters (like markdown or callout) over a list of elements.
The workaround is to not treat it as a list at all. Instead, you grab all the elements in order, join them into a single string, and then use a clever, two-step replace() chain.
The Working Template
Here is the final template code that works perfectly for me. (Big thanks to dawni, who suggested the replace chain idea, which I adapted slightly).
JavaScript
{{selectorHtml:*:is(user-query, model-response message-content) | join:"" | replace:("<message-content":"★Gemini said<message-content" , "<user-query ":"★You said<user-query ") | markdown | blockquote | replace:("> \n> ★Gemini said":"\n> [!gemini]- Answer" , "> ★You said":"\n> [!user]- Query") }}
How This “Hack” Works
This one-liner is doing a lot, so here’s the breakdown:
selectorHtml:*:is(user-query, model-response message-content)This uses the:is()CSS selector to grab all user queries and model response content (I’m usingmessage-contentspecifically to ignore the model’s “thoughts” panel and other UI elements).| join:""This concatenates all the found HTML elements into one single, large HTML string.| replace:("...","...")(Part 1 - The “Pre-Hack”) This is the first key step. Before converting to Markdown, it injects unique text markers (★Gemini saidand★You said) directly into the HTML string, right before the content starts.| markdown | blockquoteThis converts the entire HTML string into Markdown and then wraps the whole thing in a blockquote. This is crucial because it prefixes every line with a>.| replace:("...","...")(Part 2 - The “Post-Hack”) This is the final step. It now searches for the markers, which (thanks to the previous filter) now look like> ★You said. It replaces these markers with the properly formatted newlines and callout headers (\n> [!user]- Query).
In my case, I use [!user] and [!gemini] callout types, which I defined via Callout Manager to have proper icons (lucide-user and lucide-stars, respectively), and I add the - that makes the callout collapsed by default, but you can adapt that to your taste.
This method completely bypasses the list-processing limitation. I hope this is helpful for anyone else facing a similar issue!