313 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
| import { hg as requireUtils, hh as mapConnectionsByDestination, hi as getParentNodes, bz as emptyTokenUsageData, by as addTokenUsageData, hj as libExports, hk as splitTextBySearch, d as defineComponent, ca as useClipboard, a as useToast, x as computed, h as createElementBlock, g as openBlock, n as normalizeClass, F as Fragment, A as renderList, e as createBlock, f as createCommentVNode, l as unref, h7 as __unplugin_components_0, i as createVNode, aa as _sfc_main$1, c as useI18n, _ as _export_sfc } from "./index--OJ5nhDf.js";
 | |
| import { V as VueMarkdown, H as HighlightJS } from "./core-Br-UFy15.js";
 | |
| var utilsExports = requireUtils();
 | |
| function createNode(parent, nodeName, currentDepth, runIndex, r, children = []) {
 | |
|   return {
 | |
|     parent,
 | |
|     node: nodeName,
 | |
|     id: `${nodeName}:${runIndex}`,
 | |
|     depth: currentDepth,
 | |
|     startTime: r?.data?.metadata?.startTime ?? 0,
 | |
|     runIndex,
 | |
|     children,
 | |
|     consumedTokens: getConsumedTokens(r?.data)
 | |
|   };
 | |
| }
 | |
| function getTreeNodeData(nodeName, connectionsBySourceNode, aiData, runIndex) {
 | |
|   return getTreeNodeDataRec(void 0, nodeName, 0, connectionsBySourceNode, aiData, runIndex);
 | |
| }
 | |
| function getTreeNodeDataRec(parent, nodeName, currentDepth, connectionsBySourceNode, aiData, runIndex) {
 | |
|   const connectionsByDestinationNode = mapConnectionsByDestination(connectionsBySourceNode);
 | |
|   const nodeConnections = connectionsByDestinationNode[nodeName];
 | |
|   const resultData = aiData?.filter((data) => data.node === nodeName && runIndex === data.runIndex) ?? [];
 | |
|   if (!nodeConnections) {
 | |
|     return resultData.map((d) => createNode(parent, nodeName, currentDepth, d.runIndex, d));
 | |
|   }
 | |
|   const filteredAiData = aiData?.filter(({ data }) => {
 | |
|     if (!data?.source || data.source.every((source) => source === null)) {
 | |
|       return true;
 | |
|     }
 | |
|     return data.source.some(
 | |
|       (source) => source?.previousNode === nodeName && source.previousNodeRun === runIndex
 | |
|     );
 | |
|   });
 | |
|   const connectedSubNodes = getParentNodes(
 | |
|     connectionsByDestinationNode,
 | |
|     nodeName,
 | |
|     "ALL_NON_MAIN",
 | |
|     1
 | |
|   );
 | |
|   const treeNode = createNode(parent, nodeName, currentDepth, runIndex);
 | |
|   const children = (filteredAiData ?? []).flatMap(
 | |
|     (data) => connectedSubNodes.includes(data.node) ? getTreeNodeDataRec(
 | |
|       treeNode,
 | |
|       data.node,
 | |
|       currentDepth + 1,
 | |
|       connectionsBySourceNode,
 | |
|       aiData,
 | |
|       data.runIndex
 | |
|     ) : []
 | |
|   );
 | |
|   treeNode.children = children;
 | |
|   if (resultData.length) {
 | |
|     return resultData.map(
 | |
|       (r) => createNode(parent, nodeName, currentDepth, r.runIndex, r, children)
 | |
|     );
 | |
|   }
 | |
|   return [treeNode];
 | |
| }
 | |
| function createAiData(nodeName, connectionsBySourceNode, getWorkflowResultDataByNodeName) {
 | |
|   const connectionsByDestinationNode = mapConnectionsByDestination(connectionsBySourceNode);
 | |
|   return getParentNodes(connectionsByDestinationNode, nodeName, "ALL_NON_MAIN").flatMap(
 | |
|     (node) => (getWorkflowResultDataByNodeName(node) ?? []).map((task, index) => ({ node, task, index }))
 | |
|   ).sort((a, b) => {
 | |
|     if (a.task.executionIndex !== void 0 && b.task.executionIndex !== void 0) {
 | |
|       return a.task.executionIndex - b.task.executionIndex;
 | |
|     }
 | |
|     const aTime = a.task.startTime ?? 0;
 | |
|     const bTime = b.task.startTime ?? 0;
 | |
|     return aTime - bTime;
 | |
|   }).map(({ node, task, index }) => ({
 | |
|     data: getReferencedData(task, false)[0],
 | |
|     node,
 | |
|     runIndex: index
 | |
|   }));
 | |
| }
 | |
| function getReferencedData(taskData, withInput, withOutput) {
 | |
|   if (!taskData) {
 | |
|     return [];
 | |
|   }
 | |
|   const returnData = [];
 | |
|   function addFunction(data, inOut) {
 | |
|     if (!data) {
 | |
|       return;
 | |
|     }
 | |
|     Object.keys(data).map((type) => {
 | |
|       returnData.push({
 | |
|         data: data[type][0],
 | |
|         inOut,
 | |
|         type,
 | |
|         // Include source information in AI content to track which node triggered the execution
 | |
|         // This enables filtering in the UI to show only relevant executions
 | |
|         source: taskData.source,
 | |
|         metadata: {
 | |
|           executionTime: taskData.executionTime,
 | |
|           startTime: taskData.startTime,
 | |
|           subExecution: taskData.metadata?.subExecution
 | |
|         }
 | |
|       });
 | |
|     });
 | |
|   }
 | |
|   if (withInput) {
 | |
|     addFunction(taskData.inputOverride, "input");
 | |
|   }
 | |
|   {
 | |
|     addFunction(taskData.data, "output");
 | |
|   }
 | |
|   return returnData;
 | |
| }
 | |
| function getConsumedTokens(outputRun) {
 | |
|   if (!outputRun?.data) {
 | |
|     return emptyTokenUsageData;
 | |
|   }
 | |
|   const tokenUsage = outputRun.data.reduce(
 | |
|     (acc, curr) => {
 | |
|       const tokenUsageData = curr.json?.tokenUsage ?? curr.json?.tokenUsageEstimate;
 | |
|       if (!tokenUsageData) return acc;
 | |
|       return addTokenUsageData(acc, {
 | |
|         ...tokenUsageData,
 | |
|         isEstimate: !!curr.json.tokenUsageEstimate
 | |
|       });
 | |
|     },
 | |
|     emptyTokenUsageData
 | |
|   );
 | |
|   return tokenUsage;
 | |
| }
 | |
| function createHtmlFragmentWithSearchHighlight(text, search) {
 | |
|   const escaped = libExports.escapeHtml(text);
 | |
|   return search ? splitTextBySearch(escaped, search).map((part) => part.isMatched ? `<mark>${part.content}</mark>` : part.content).join("") : escaped;
 | |
| }
 | |
| function createSearchHighlightPlugin(search) {
 | |
|   return (md) => {
 | |
|     md.renderer.rules.text = (tokens, idx) => createHtmlFragmentWithSearchHighlight(tokens[idx].content, search);
 | |
|     md.renderer.rules.code_inline = (tokens, idx, _, __, slf) => `<code${slf.renderAttrs(tokens[idx])}>${createHtmlFragmentWithSearchHighlight(tokens[idx].content, search)}</code>`;
 | |
|     md.renderer.rules.code_block = (tokens, idx, _, __, slf) => `<pre${slf.renderAttrs(tokens[idx])}><code>${createHtmlFragmentWithSearchHighlight(tokens[idx].content, search)}</code></pre>
 | |
| `;
 | |
|     md.renderer.rules.fence = (tokens, idx, options, _, slf) => {
 | |
|       const token = tokens[idx];
 | |
|       const info = token.info ? utilsExports.unescapeAll(token.info).trim() : "";
 | |
|       let langName = "";
 | |
|       let langAttrs = "";
 | |
|       if (info) {
 | |
|         const arr = info.split(/(\s+)/g);
 | |
|         langName = arr[0];
 | |
|         langAttrs = arr.slice(2).join("");
 | |
|       }
 | |
|       const highlighted = options.highlight?.(token.content, langName, langAttrs) ?? createHtmlFragmentWithSearchHighlight(token.content, search);
 | |
|       if (highlighted.indexOf("<pre") === 0) {
 | |
|         return highlighted + "\n";
 | |
|       }
 | |
|       return `<pre><code${slf.renderAttrs(token)}>${highlighted}</code></pre>
 | |
| `;
 | |
|     };
 | |
|   };
 | |
| }
 | |
| const _hoisted_1 = ["data-content-type"];
 | |
| const _sfc_main = /* @__PURE__ */ defineComponent({
 | |
|   __name: "RunDataParsedAiContent",
 | |
|   props: {
 | |
|     content: {},
 | |
|     compact: { type: Boolean, default: false },
 | |
|     search: {},
 | |
|     renderType: {}
 | |
|   },
 | |
|   setup(__props) {
 | |
|     const i18n = useI18n();
 | |
|     const clipboard = useClipboard();
 | |
|     const { showMessage } = useToast();
 | |
|     const vueMarkdownPlugins = computed(() => [createSearchHighlightPlugin(__props.search)]);
 | |
|     function isJsonString(text) {
 | |
|       try {
 | |
|         JSON.parse(text);
 | |
|         return true;
 | |
|       } catch (e) {
 | |
|         return false;
 | |
|       }
 | |
|     }
 | |
|     const markdownOptions = {
 | |
|       highlight(str, lang) {
 | |
|         if (lang && HighlightJS.getLanguage(lang)) {
 | |
|           try {
 | |
|             return HighlightJS.highlight(str, { language: lang }).value;
 | |
|           } catch {
 | |
|           }
 | |
|         }
 | |
|         return void 0;
 | |
|       }
 | |
|     };
 | |
|     function isMarkdown(jsonMarkdown) {
 | |
|       if (typeof jsonMarkdown !== "string") return false;
 | |
|       const markdownPatterns = [
 | |
|         /^# .+/gm,
 | |
|         // headers
 | |
|         /\*{1,2}.+\*{1,2}/g,
 | |
|         // emphasis and strong
 | |
|         /\[.+\]\(.+\)/g,
 | |
|         // links
 | |
|         /```[\s\S]+```/g
 | |
|         // code blocks
 | |
|       ];
 | |
|       return markdownPatterns.some((pattern) => pattern.test(jsonMarkdown));
 | |
|     }
 | |
|     function formatToJsonMarkdown(data) {
 | |
|       return "```json\n" + data + "\n```";
 | |
|     }
 | |
|     function jsonToMarkdown(data) {
 | |
|       if (isMarkdown(data)) return data;
 | |
|       if (Array.isArray(data) && data.length && typeof data[0] !== "number") {
 | |
|         const markdownArray = data.map((item) => jsonToMarkdown(item));
 | |
|         return markdownArray.join("\n\n").trim();
 | |
|       }
 | |
|       if (typeof data === "string") {
 | |
|         if (isJsonString(data)) {
 | |
|           return formatToJsonMarkdown(data);
 | |
|         }
 | |
|         return data;
 | |
|       }
 | |
|       return formatToJsonMarkdown(JSON.stringify(data, null, 2));
 | |
|     }
 | |
|     function onCopyToClipboard(object) {
 | |
|       try {
 | |
|         void clipboard.copy(JSON.stringify(object, void 0, 2));
 | |
|         showMessage({
 | |
|           title: i18n.baseText("generic.copiedToClipboard"),
 | |
|           type: "success"
 | |
|         });
 | |
|       } catch {
 | |
|       }
 | |
|     }
 | |
|     return (_ctx, _cache) => {
 | |
|       const _component_TextWithHighlights = __unplugin_components_0;
 | |
|       return openBlock(), createElementBlock("div", {
 | |
|         class: normalizeClass([_ctx.$style.component, _ctx.compact ? _ctx.$style.compact : ""])
 | |
|       }, [
 | |
|         (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.content, ({ parsedContent, raw }, index) => {
 | |
|           return openBlock(), createElementBlock("div", {
 | |
|             key: index,
 | |
|             class: normalizeClass(_ctx.$style.contentText),
 | |
|             "data-content-type": parsedContent?.type
 | |
|           }, [
 | |
|             parsedContent && _ctx.renderType === "rendered" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
 | |
|               parsedContent.type === "json" ? (openBlock(), createBlock(unref(VueMarkdown), {
 | |
|                 key: 0,
 | |
|                 source: jsonToMarkdown(parsedContent.data),
 | |
|                 class: normalizeClass(_ctx.$style.markdown),
 | |
|                 options: markdownOptions,
 | |
|                 plugins: vueMarkdownPlugins.value
 | |
|               }, null, 8, ["source", "class", "plugins"])) : parsedContent.type === "markdown" ? (openBlock(), createBlock(unref(VueMarkdown), {
 | |
|                 key: 1,
 | |
|                 source: parsedContent.data,
 | |
|                 class: normalizeClass(_ctx.$style.markdown),
 | |
|                 options: markdownOptions,
 | |
|                 plugins: vueMarkdownPlugins.value
 | |
|               }, null, 8, ["source", "class", "plugins"])) : parsedContent.type === "text" ? (openBlock(), createBlock(_component_TextWithHighlights, {
 | |
|                 key: 2,
 | |
|                 class: normalizeClass(_ctx.$style.runText),
 | |
|                 content: String(parsedContent.data),
 | |
|                 search: _ctx.search
 | |
|               }, null, 8, ["class", "content", "search"])) : createCommentVNode("", true)
 | |
|             ], 64)) : (openBlock(), createElementBlock("div", {
 | |
|               key: 1,
 | |
|               class: normalizeClass(_ctx.$style.rawContent)
 | |
|             }, [
 | |
|               createVNode(unref(_sfc_main$1), {
 | |
|                 size: "small",
 | |
|                 class: normalizeClass(_ctx.$style.copyToClipboard),
 | |
|                 type: "secondary",
 | |
|                 title: unref(i18n).baseText("nodeErrorView.copyToClipboard"),
 | |
|                 icon: "files",
 | |
|                 onClick: ($event) => onCopyToClipboard(raw)
 | |
|               }, null, 8, ["class", "title", "onClick"]),
 | |
|               createVNode(unref(VueMarkdown), {
 | |
|                 source: jsonToMarkdown(raw),
 | |
|                 class: normalizeClass(_ctx.$style.markdown),
 | |
|                 plugins: vueMarkdownPlugins.value
 | |
|               }, null, 8, ["source", "class", "plugins"])
 | |
|             ], 2))
 | |
|           ], 10, _hoisted_1);
 | |
|         }), 128))
 | |
|       ], 2);
 | |
|     };
 | |
|   }
 | |
| });
 | |
| const runText = "_runText_1ucj0_123";
 | |
| const markdown = "_markdown_1ucj0_128";
 | |
| const compact = "_compact_1ucj0_151";
 | |
| const copyToClipboard = "_copyToClipboard_1ucj0_159";
 | |
| const rawContent = "_rawContent_1ucj0_169";
 | |
| const contentText = "_contentText_1ucj0_173";
 | |
| const style0 = {
 | |
|   runText,
 | |
|   markdown,
 | |
|   compact,
 | |
|   copyToClipboard,
 | |
|   rawContent,
 | |
|   contentText
 | |
| };
 | |
| const cssModules = {
 | |
|   "$style": style0
 | |
| };
 | |
| const RunDataAi = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]);
 | |
| const RunDataParsedAiContent = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
 | |
|   __proto__: null,
 | |
|   default: RunDataAi
 | |
| }, Symbol.toStringTag, { value: "Module" }));
 | |
| export {
 | |
|   RunDataAi as R,
 | |
|   getTreeNodeData as a,
 | |
|   getReferencedData as b,
 | |
|   createAiData as c,
 | |
|   RunDataParsedAiContent as d,
 | |
|   getConsumedTokens as g
 | |
| };
 |