diff --git a/src/components/graph/widgets/TextPreviewWidget.vue b/src/components/graph/widgets/TextPreviewWidget.vue
index 33ab748748..68c2c09550 100644
--- a/src/components/graph/widgets/TextPreviewWidget.vue
+++ b/src/components/graph/widgets/TextPreviewWidget.vue
@@ -27,7 +27,33 @@ const props = defineProps<{
const executionStore = useExecutionStore()
const isParentNodeExecuting = ref(true)
-const formattedText = computed(() => nl2br(linkifyHtml(modelValue.value)))
+const formattedText = computed(() => {
+ const src = modelValue.value
+ // Turn [[label|url]] into placeholders to avoid interfering with linkifyHtml
+ const tokens: { label: string; url: string }[] = []
+ const holed = src.replace(
+ /\[\[([^|\]]+)\|([^\]]+)\]\]/g,
+ (_m, label, url) => {
+ tokens.push({ label: String(label), url: String(url) })
+ return `__LNK${tokens.length - 1}__`
+ }
+ )
+
+ // Keep current behavior (auto-link bare URLs + \n ->
)
+ let html = nl2br(linkifyHtml(holed))
+
+ // Restore placeholders as ... (minimal escaping + http default)
+ html = html.replace(/__LNK(\d+)__/g, (_m, i) => {
+ const { label, url } = tokens[+i]
+ const safeHref = url.replace(/"/g, '"')
+ const safeLabel = label.replace(//g, '>')
+ return /^https?:\/\//i.test(url)
+ ? `${safeLabel}`
+ : safeLabel
+ })
+
+ return html
+})
let parentNodeId: NodeId | null = null
onMounted(() => {