diff --git a/packages/@n8n/chat/package.json b/packages/@n8n/chat/package.json
index 6508081f45..6d27169d72 100644
--- a/packages/@n8n/chat/package.json
+++ b/packages/@n8n/chat/package.json
@@ -36,7 +36,7 @@
},
"dependencies": {
"@vueuse/core": "^10.11.0",
- "highlight.js": "^11.8.0",
+ "highlight.js": "catalog:frontend",
"markdown-it-link-attributes": "^4.0.1",
"uuid": "catalog:",
"vue": "catalog:frontend",
diff --git a/packages/editor-ui/package.json b/packages/editor-ui/package.json
index d46579c6d1..f80861f7d3 100644
--- a/packages/editor-ui/package.json
+++ b/packages/editor-ui/package.json
@@ -53,6 +53,7 @@
"fast-json-stable-stringify": "^2.1.0",
"file-saver": "^2.0.2",
"flatted": "^3.2.4",
+ "highlight.js": "catalog:frontend",
"humanize-duration": "^3.27.2",
"jsonpath": "^1.1.1",
"lodash-es": "^4.17.21",
diff --git a/packages/editor-ui/src/components/RunDataAi/AiRunContentBlock.vue b/packages/editor-ui/src/components/RunDataAi/AiRunContentBlock.vue
index a94bf38f8b..7a31030929 100644
--- a/packages/editor-ui/src/components/RunDataAi/AiRunContentBlock.vue
+++ b/packages/editor-ui/src/components/RunDataAi/AiRunContentBlock.vue
@@ -5,6 +5,7 @@ import { ref, onMounted } from 'vue';
import type { ParsedAiContent } from './useAiContentParsers';
import { useAiContentParsers } from './useAiContentParsers';
import VueMarkdown from 'vue-markdown-render';
+import hljs from 'highlight.js/lib/core';
import { useClipboard } from '@/composables/useClipboard';
import { useI18n } from '@/composables/useI18n';
import { useToast } from '@/composables/useToast';
@@ -38,6 +39,27 @@ function getInitialExpandedState() {
return !collapsedTypes[props.runData.inOut].includes(props.runData.type);
}
+function isJsonString(text: string) {
+ try {
+ JSON.parse(text);
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
+const markdownOptions = {
+ highlight(str: string, lang: string) {
+ if (lang && hljs.getLanguage(lang)) {
+ try {
+ return hljs.highlight(str, { language: lang }).value;
+ } catch {}
+ }
+
+ return ''; // use external default escaping
+ },
+};
+
function parseAiRunData(run: IAiDataContent) {
if (!run.data) {
return;
@@ -75,7 +97,13 @@ function jsonToMarkdown(data: JsonMarkdown): string {
}
if (typeof data === 'string') {
- return formatToJsonMarkdown(data);
+ // If data is a valid JSON string – format it as JSON markdown
+ if (isJsonString(data)) {
+ return formatToJsonMarkdown(data);
+ }
+
+ // Return original string otherwise
+ return data;
}
return formatToJsonMarkdown(JSON.stringify(data, null, 2));
@@ -145,10 +173,15 @@ onMounted(() => {
{ } pre { - background-color: var(--color-foreground-light); + background: var(--chat--message--pre--background); border-radius: var(--border-radius-base); line-height: var(--font-line-height-xloose); padding: var(--spacing-s); diff --git a/packages/editor-ui/src/components/RunDataAi/useAiContentParsers.ts b/packages/editor-ui/src/components/RunDataAi/useAiContentParsers.ts index 53275675d6..c7e204548e 100644 --- a/packages/editor-ui/src/components/RunDataAi/useAiContentParsers.ts +++ b/packages/editor-ui/src/components/RunDataAi/useAiContentParsers.ts @@ -47,10 +47,12 @@ const outputTypeParsers: { parsed: true, }; } + // Use the memory parser if the response is a memory-like(chat) object if (response.messages && Array.isArray(response.messages)) { return outputTypeParsers[NodeConnectionType.AiMemory](execData); } + if (response.generations) { const generations = response.generations as LmGeneration[]; @@ -220,8 +222,8 @@ export const useAiContentParsers = () => { } const contentJson = executionData.map((node) => { - const hasBinarData = !isObjectEmpty(node.binary); - return hasBinarData ? node.binary : node.json; + const hasBinaryData = !isObjectEmpty(node.binary); + return hasBinaryData ? node.binary : node.json; }); const parser = outputTypeParsers[endpointType as AllowedEndpointType]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8895ba097b..5aa9c26537 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,6 +58,9 @@ catalogs: '@vitest/coverage-v8': specifier: ^1.6.0 version: 1.6.0 + highlight.js: + specifier: ^11.8.0 + version: 11.9.0 vite: specifier: ^5.2.12 version: 5.2.12 @@ -255,7 +258,7 @@ importers: specifier: ^10.11.0 version: 10.11.0(vue@3.4.21(typescript@5.5.2)) highlight.js: - specifier: ^11.8.0 + specifier: catalog:frontend version: 11.9.0 markdown-it-link-attributes: specifier: ^4.0.1 @@ -1340,6 +1343,9 @@ importers: flatted: specifier: ^3.2.4 version: 3.2.7 + highlight.js: + specifier: catalog:frontend + version: 11.9.0 humanize-duration: specifier: ^3.27.2 version: 3.27.3 @@ -13139,8 +13145,8 @@ packages: vue-component-type-helpers@2.0.19: resolution: {integrity: sha512-cN3f1aTxxKo4lzNeQAkVopswuImUrb5Iurll9Gaw5cqpnbTAxtEMM1mgi6ou4X79OCyqYv1U1mzBHJkzmiK82w==} - vue-component-type-helpers@2.1.4: - resolution: {integrity: sha512-aVqB3KxwpM76cYRkpnezl1J62E/1omzHQfx1yuz7zcbxmzmP/PeSgI20NEmkdeGnjZPVzm0V9fB4ZyRu5BBj4A==} + vue-component-type-helpers@2.1.6: + resolution: {integrity: sha512-ng11B8B/ZADUMMOsRbqv0arc442q7lifSubD0v8oDXIFoMg/mXwAPUunrroIDkY+mcD0dHKccdaznSVp8EoX3w==} vue-demi@0.14.5: resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==} @@ -18571,7 +18577,7 @@ snapshots: ts-dedent: 2.2.0 type-fest: 2.19.0 vue: 3.4.21(typescript@5.5.2) - vue-component-type-helpers: 2.1.4 + vue-component-type-helpers: 2.1.6 transitivePeerDependencies: - encoding - prettier @@ -28055,7 +28061,7 @@ snapshots: vue-component-type-helpers@2.0.19: {} - vue-component-type-helpers@2.1.4: {} + vue-component-type-helpers@2.1.6: {} vue-demi@0.14.5(vue@3.4.21(typescript@5.5.2)): dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index e23937456c..aa76b0aa69 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -31,3 +31,4 @@ catalogs: vue: ^3.4.21 vue-tsc: ^2.0.19 vue-markdown-render: ^2.2.1 + highlight.js: ^11.8.0