@mastra/playground-ui 2.0.1-alpha.1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1,24 +1,21 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { MessagePrimitive, ActionBarPrimitive, BranchPickerPrimitive, ThreadPrimitive, ComposerPrimitive, useExternalStoreRuntime, AssistantRuntimeProvider } from '@assistant-ui/react';
3
+ import { CheckIcon, CopyIcon, ChevronLeftIcon, ChevronRightIcon, ArrowUp, Copy, Search, RefreshCcwIcon, ChevronRight, SortAsc, SortDesc, Braces, Clock1, ChevronDown, XIcon, Footprints, CircleCheck, CircleX, AlertCircleIcon, X, Plus, CalendarIcon, Check, Loader2 } from 'lucide-react';
2
4
  import * as React from 'react';
3
- import React__default, { useState, useRef, useCallback, useEffect, useLayoutEffect, Suspense, useMemo, forwardRef, memo, createContext, useContext, Fragment as Fragment$1 } from 'react';
4
- import { useSWRConfig } from 'swr';
5
- import { MastraClient } from '@mastra/client-js';
6
- import { Check, Copy, X, FileIcon, Paperclip, Square, ArrowUp, Dot, ArrowDown, CheckIcon, CopyIcon, ChevronLeftIcon, ChevronRightIcon, Search, RefreshCcwIcon, ChevronRight, SortAsc, SortDesc, Braces, Clock1, ChevronDown, XIcon, Footprints, AlertCircleIcon, Plus, CalendarIcon, Loader2 } from 'lucide-react';
5
+ import React__default, { forwardRef, memo, useState, useEffect, createContext, useContext, useRef, useMemo, useCallback, Fragment as Fragment$1 } from 'react';
7
6
  import { Slot } from '@radix-ui/react-slot';
8
- import { omit } from 'remeda';
9
- import { motion, AnimatePresence } from 'motion/react';
10
- import Markdown from 'react-markdown';
11
- import remarkGfm from 'remark-gfm';
12
- import { MessagePrimitive, ActionBarPrimitive, BranchPickerPrimitive, ThreadPrimitive, ComposerPrimitive, useExternalStoreRuntime, AssistantRuntimeProvider } from '@assistant-ui/react';
13
7
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
14
8
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
15
9
  import { unstable_memoizeMarkdownComponents, useIsMarkdownCodeBlock, MarkdownTextPrimitive } from '@assistant-ui/react-markdown';
16
10
  import '@assistant-ui/react-markdown/styles/dot.css';
11
+ import remarkGfm from 'remark-gfm';
17
12
  import { makePrismAsyncSyntaxHighlighter } from '@assistant-ui/react-syntax-highlighter';
18
13
  import { coldarkDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
14
+ import { MastraClient } from '@mastra/client-js';
19
15
  import { format, formatDistanceToNow, isValid } from 'date-fns';
20
16
  import * as TabsPrimitive from '@radix-ui/react-tabs';
21
17
  import { toast } from 'sonner';
18
+ import { AnimatePresence } from 'motion/react';
22
19
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
23
20
  import { jsonLanguage } from '@codemirror/lang-json';
24
21
  import { tags } from '@lezer/highlight';
@@ -44,7 +41,7 @@ import { DayPicker } from 'react-day-picker';
44
41
  import * as SelectPrimitive from '@radix-ui/react-select';
45
42
  import * as LabelPrimitive from '@radix-ui/react-label';
46
43
  import { v4 } from '@lukeed/uuid';
47
- import { CodeBlock as CodeBlock$1 } from 'react-code-block';
44
+ import { CodeBlock } from 'react-code-block';
48
45
 
49
46
  import './index.css';function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
50
47
 
@@ -2837,877 +2834,6 @@ const Button = React.forwardRef(
2837
2834
  );
2838
2835
  Button.displayName = "Button";
2839
2836
 
2840
- function useCopyToClipboard$2({ text, copyMessage = "Copied to clipboard!" }) {
2841
- const [isCopied, setIsCopied] = useState(false);
2842
- const [error, setError] = useState("");
2843
- const timeoutRef = useRef(null);
2844
- const handleCopy = useCallback(() => {
2845
- navigator.clipboard.writeText(text).then(() => {
2846
- setIsCopied(true);
2847
- if (timeoutRef.current) {
2848
- clearTimeout(timeoutRef.current);
2849
- timeoutRef.current = null;
2850
- }
2851
- timeoutRef.current = setTimeout(() => {
2852
- setIsCopied(false);
2853
- }, 2e3);
2854
- }).catch(() => {
2855
- setError("Failed to copy to clipboard.");
2856
- });
2857
- }, [text, copyMessage]);
2858
- return { isCopied, handleCopy, error };
2859
- }
2860
-
2861
- function CopyButton$1({ content, copyMessage, classname }) {
2862
- const { isCopied, handleCopy } = useCopyToClipboard$2({
2863
- text: content,
2864
- copyMessage
2865
- });
2866
- return /* @__PURE__ */ jsxs("button", { className: cn("relative h-6 w-6", classname), "aria-label": "Copy to clipboard", onClick: handleCopy, children: [
2867
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(Check, { className: cn("h-4 w-4 transition-transform ease-in-out", isCopied ? "scale-100" : "scale-0") }) }),
2868
- /* @__PURE__ */ jsx(Copy, { className: cn("h-4 w-4 transition-transform ease-in-out", isCopied ? "scale-0" : "scale-100") })
2869
- ] });
2870
- }
2871
-
2872
- const ACTIVATION_THRESHOLD = 50;
2873
- function useAutoScroll(dependencies) {
2874
- const containerRef = useRef(null);
2875
- const previousScrollTop = useRef(null);
2876
- const [shouldAutoScroll, setShouldAutoScroll] = useState(true);
2877
- const scrollToBottom = () => {
2878
- if (containerRef.current) {
2879
- containerRef.current.scrollTop = containerRef.current.scrollHeight;
2880
- }
2881
- };
2882
- const handleScroll = () => {
2883
- if (containerRef.current) {
2884
- const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
2885
- const isScrollingUp = previousScrollTop.current ? scrollTop < previousScrollTop.current : false;
2886
- if (isScrollingUp) {
2887
- setShouldAutoScroll(false);
2888
- } else {
2889
- const isScrolledToBottom = Math.abs(scrollHeight - scrollTop - clientHeight) < ACTIVATION_THRESHOLD;
2890
- setShouldAutoScroll(isScrolledToBottom);
2891
- }
2892
- previousScrollTop.current = scrollTop;
2893
- }
2894
- };
2895
- const handleTouchStart = () => {
2896
- setShouldAutoScroll(false);
2897
- };
2898
- useEffect(() => {
2899
- if (containerRef.current) {
2900
- previousScrollTop.current = containerRef.current.scrollTop;
2901
- }
2902
- }, []);
2903
- useEffect(() => {
2904
- if (shouldAutoScroll) {
2905
- scrollToBottom();
2906
- }
2907
- }, dependencies);
2908
- return {
2909
- containerRef,
2910
- scrollToBottom,
2911
- handleScroll,
2912
- shouldAutoScroll,
2913
- handleTouchStart
2914
- };
2915
- }
2916
-
2917
- const FilePreview = React__default.forwardRef((props, ref) => {
2918
- if (props.file.type.startsWith("image/")) {
2919
- return /* @__PURE__ */ jsx(ImageFilePreview, { ...props, ref });
2920
- }
2921
- if (props.file.type.startsWith("text/") || props.file.name.endsWith(".txt") || props.file.name.endsWith(".md")) {
2922
- return /* @__PURE__ */ jsx(TextFilePreview, { ...props, ref });
2923
- }
2924
- return /* @__PURE__ */ jsx(GenericFilePreview, { ...props, ref });
2925
- });
2926
- FilePreview.displayName = "FilePreview";
2927
- const ImageFilePreview = React__default.forwardRef(({ file, onRemove }, ref) => {
2928
- return /* @__PURE__ */ jsxs(
2929
- motion.div,
2930
- {
2931
- ref,
2932
- className: "relative flex max-w-[200px] rounded-md border p-1.5 pr-2 text-xs",
2933
- layout: true,
2934
- initial: { opacity: 0, y: "100%" },
2935
- animate: { opacity: 1, y: 0 },
2936
- exit: { opacity: 0, y: "100%" },
2937
- children: [
2938
- /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center space-x-2", children: [
2939
- /* @__PURE__ */ jsx(
2940
- "img",
2941
- {
2942
- alt: `Attachment ${file.name}`,
2943
- className: "bg-muted grid h-10 w-10 shrink-0 place-items-center rounded-sm border object-cover",
2944
- src: URL.createObjectURL(file)
2945
- }
2946
- ),
2947
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-full truncate", children: file.name })
2948
- ] }),
2949
- onRemove ? /* @__PURE__ */ jsx(
2950
- "button",
2951
- {
2952
- className: "bg-background absolute -right-2 -top-2 flex h-4 w-4 items-center justify-center rounded-full border",
2953
- type: "button",
2954
- onClick: onRemove,
2955
- "aria-label": "Remove attachment",
2956
- children: /* @__PURE__ */ jsx(X, { className: "h-2.5 w-2.5" })
2957
- }
2958
- ) : null
2959
- ]
2960
- }
2961
- );
2962
- });
2963
- ImageFilePreview.displayName = "ImageFilePreview";
2964
- const TextFilePreview = React__default.forwardRef(({ file, onRemove }, ref) => {
2965
- const [preview, setPreview] = React__default.useState("");
2966
- useEffect(() => {
2967
- const reader = new FileReader();
2968
- reader.onload = (e) => {
2969
- const text = e.target?.result;
2970
- setPreview(text.slice(0, 50) + (text.length > 50 ? "..." : ""));
2971
- };
2972
- reader.readAsText(file);
2973
- }, [file]);
2974
- return /* @__PURE__ */ jsxs(
2975
- motion.div,
2976
- {
2977
- ref,
2978
- className: "relative flex max-w-[200px] rounded-md border p-1.5 pr-2 text-xs",
2979
- layout: true,
2980
- initial: { opacity: 0, y: "100%" },
2981
- animate: { opacity: 1, y: 0 },
2982
- exit: { opacity: 0, y: "100%" },
2983
- children: [
2984
- /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center space-x-2", children: [
2985
- /* @__PURE__ */ jsx("div", { className: "bg-muted grid h-10 w-10 shrink-0 place-items-center rounded-sm border p-0.5", children: /* @__PURE__ */ jsx("div", { className: "text-muted-foreground h-full w-full overflow-hidden text-[6px] leading-none", children: preview || "Loading..." }) }),
2986
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-full truncate", children: file.name })
2987
- ] }),
2988
- onRemove ? /* @__PURE__ */ jsx(
2989
- "button",
2990
- {
2991
- className: "bg-background absolute -right-2 -top-2 flex h-4 w-4 items-center justify-center rounded-full border",
2992
- type: "button",
2993
- onClick: onRemove,
2994
- "aria-label": "Remove attachment",
2995
- children: /* @__PURE__ */ jsx(X, { className: "h-2.5 w-2.5" })
2996
- }
2997
- ) : null
2998
- ]
2999
- }
3000
- );
3001
- });
3002
- TextFilePreview.displayName = "TextFilePreview";
3003
- const GenericFilePreview = React__default.forwardRef(({ file, onRemove }, ref) => {
3004
- return /* @__PURE__ */ jsxs(
3005
- motion.div,
3006
- {
3007
- ref,
3008
- className: "relative flex max-w-[200px] rounded-md border p-1.5 pr-2 text-xs",
3009
- layout: true,
3010
- initial: { opacity: 0, y: "100%" },
3011
- animate: { opacity: 1, y: 0 },
3012
- exit: { opacity: 0, y: "100%" },
3013
- children: [
3014
- /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center space-x-2", children: [
3015
- /* @__PURE__ */ jsx("div", { className: "bg-muted grid h-10 w-10 shrink-0 place-items-center rounded-sm border", children: /* @__PURE__ */ jsx(FileIcon, { className: "text-foreground h-6 w-6" }) }),
3016
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground w-full truncate", children: file.name })
3017
- ] }),
3018
- onRemove ? /* @__PURE__ */ jsx(
3019
- "button",
3020
- {
3021
- className: "bg-background absolute -right-2 -top-2 flex h-4 w-4 items-center justify-center rounded-full border",
3022
- type: "button",
3023
- onClick: onRemove,
3024
- "aria-label": "Remove attachment",
3025
- children: /* @__PURE__ */ jsx(X, { className: "h-2.5 w-2.5" })
3026
- }
3027
- ) : null
3028
- ]
3029
- }
3030
- );
3031
- });
3032
- GenericFilePreview.displayName = "GenericFilePreview";
3033
-
3034
- function useAutosizeTextArea({
3035
- ref,
3036
- maxHeight = Number.MAX_SAFE_INTEGER,
3037
- borderWidth = 0,
3038
- dependencies
3039
- }) {
3040
- const originalHeight = useRef(null);
3041
- useLayoutEffect(() => {
3042
- if (!ref.current) return;
3043
- const currentRef = ref.current;
3044
- const borderAdjustment = borderWidth * 2;
3045
- if (originalHeight.current === null) {
3046
- originalHeight.current = currentRef.scrollHeight - borderAdjustment;
3047
- }
3048
- currentRef.style.removeProperty("height");
3049
- const scrollHeight = currentRef.scrollHeight;
3050
- const clampedToMax = Math.min(scrollHeight, maxHeight);
3051
- const clampedToMin = Math.max(clampedToMax, originalHeight.current);
3052
- currentRef.style.height = `${clampedToMin + borderAdjustment}px`;
3053
- }, [maxHeight, ref, ...dependencies]);
3054
- }
3055
-
3056
- function MessageInput({
3057
- placeholder = "Ask AI...",
3058
- className,
3059
- onKeyDown: onKeyDownProp,
3060
- submitOnEnter = true,
3061
- stop,
3062
- isGenerating,
3063
- ...props
3064
- }) {
3065
- const [isDragging, setIsDragging] = useState(false);
3066
- const addFiles = (files) => {
3067
- if (props.allowAttachments) {
3068
- props.setFiles((currentFiles) => {
3069
- if (currentFiles === null) {
3070
- return files;
3071
- }
3072
- if (files === null) {
3073
- return currentFiles;
3074
- }
3075
- return [...currentFiles, ...files];
3076
- });
3077
- }
3078
- };
3079
- const onDragOver = (event) => {
3080
- if (props.allowAttachments !== true) return;
3081
- event.preventDefault();
3082
- setIsDragging(true);
3083
- };
3084
- const onDragLeave = (event) => {
3085
- if (props.allowAttachments !== true) return;
3086
- event.preventDefault();
3087
- setIsDragging(false);
3088
- };
3089
- const onDrop = (event) => {
3090
- setIsDragging(false);
3091
- if (props.allowAttachments !== true) return;
3092
- event.preventDefault();
3093
- const dataTransfer = event.dataTransfer;
3094
- if (dataTransfer.files.length) {
3095
- addFiles(Array.from(dataTransfer.files));
3096
- }
3097
- };
3098
- const onPaste = (event) => {
3099
- const items = event.clipboardData?.items;
3100
- if (!items) return;
3101
- const files = Array.from(items).map((item) => item.getAsFile()).filter((file) => file !== null);
3102
- if (props.allowAttachments && files.length > 0) {
3103
- addFiles(files);
3104
- }
3105
- };
3106
- const onKeyDown = (event) => {
3107
- if (submitOnEnter && event.key === "Enter" && !event.shiftKey) {
3108
- event.preventDefault();
3109
- event.currentTarget.form?.requestSubmit();
3110
- }
3111
- onKeyDownProp?.(event);
3112
- };
3113
- const textAreaRef = useRef(null);
3114
- const showFileList = props.allowAttachments && props.files && props.files.length > 0;
3115
- useAutosizeTextArea({
3116
- ref: textAreaRef,
3117
- maxHeight: 240,
3118
- borderWidth: 1,
3119
- dependencies: [props.value, showFileList]
3120
- });
3121
- return /* @__PURE__ */ jsxs("div", { className: "relative mx-auto flex w-full", onDragOver, onDragLeave, onDrop, children: [
3122
- /* @__PURE__ */ jsx(
3123
- "textarea",
3124
- {
3125
- "aria-label": "Write your prompt here",
3126
- placeholder,
3127
- ref: textAreaRef,
3128
- onPaste,
3129
- onKeyDown,
3130
- className: cn(
3131
- "ring-offset-background placeholder:text-muted-foreground focus-visible:border-primary h-[98px] w-full grow resize-none rounded-2xl border-[0.5px] border-[#424242] bg-[#141414] p-3 pr-24 text-sm shadow-[0px_2px_8.1px_0px_rgba(0,0,0,0.20);] transition-[border] focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
3132
- showFileList && "pb-16",
3133
- className
3134
- ),
3135
- ...props.allowAttachments ? omit(props, ["allowAttachments", "files", "setFiles"]) : omit(props, ["allowAttachments"])
3136
- }
3137
- ),
3138
- props.allowAttachments && /* @__PURE__ */ jsx("div", { className: "absolute inset-x-3 bottom-0 overflow-x-scroll py-3", children: /* @__PURE__ */ jsx("div", { className: "flex space-x-3", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "popLayout", children: props.files?.map((file) => {
3139
- return /* @__PURE__ */ jsx(
3140
- FilePreview,
3141
- {
3142
- file,
3143
- onRemove: () => {
3144
- props.setFiles((files) => {
3145
- if (!files) return null;
3146
- const filtered = Array.from(files).filter((f) => f !== file);
3147
- if (filtered.length === 0) return null;
3148
- return filtered;
3149
- });
3150
- }
3151
- },
3152
- file.name + String(file.lastModified)
3153
- );
3154
- }) }) }) }),
3155
- /* @__PURE__ */ jsxs("div", { className: "absolute bottom-3 right-3 flex gap-2", children: [
3156
- props.allowAttachments && /* @__PURE__ */ jsx(
3157
- Button,
3158
- {
3159
- type: "button",
3160
- size: "icon",
3161
- variant: "outline",
3162
- className: "h-8 w-8",
3163
- "aria-label": "Attach a file",
3164
- onClick: async () => {
3165
- const files = await showFileUploadDialog();
3166
- addFiles(files);
3167
- },
3168
- children: /* @__PURE__ */ jsx(Paperclip, { className: "h-4 w-4" })
3169
- }
3170
- ),
3171
- isGenerating && stop ? /* @__PURE__ */ jsx(Button, { type: "button", size: "icon", className: "h-8 w-8", "aria-label": "Stop generating", onClick: stop, children: /* @__PURE__ */ jsx(Square, { className: "h-3 w-3 animate-pulse", fill: "currentColor" }) }) : /* @__PURE__ */ jsx(
3172
- Button,
3173
- {
3174
- type: "submit",
3175
- variant: "secondary",
3176
- size: "icon",
3177
- className: "mt-0 h-8 w-8 rounded-full transition-opacity",
3178
- "aria-label": "Send message",
3179
- disabled: props.value === "" || isGenerating,
3180
- children: /* @__PURE__ */ jsx(ArrowUp, { className: "h-6 w-6" })
3181
- }
3182
- )
3183
- ] }),
3184
- props.allowAttachments && /* @__PURE__ */ jsx(FileUploadOverlay, { isDragging })
3185
- ] });
3186
- }
3187
- MessageInput.displayName = "MessageInput";
3188
- function FileUploadOverlay({ isDragging }) {
3189
- return /* @__PURE__ */ jsx(AnimatePresence, { children: isDragging && /* @__PURE__ */ jsxs(
3190
- motion.div,
3191
- {
3192
- className: "border-border bg-background text-muted-foreground pointer-events-none absolute inset-0 flex items-center justify-center space-x-2 rounded-xl border border-dashed text-sm",
3193
- initial: { opacity: 0 },
3194
- animate: { opacity: 1 },
3195
- exit: { opacity: 0 },
3196
- transition: { duration: 0.2 },
3197
- "aria-hidden": true,
3198
- children: [
3199
- /* @__PURE__ */ jsx(Paperclip, { className: "h-4 w-4" }),
3200
- /* @__PURE__ */ jsx("span", { children: "Drop your files here to attach them." })
3201
- ]
3202
- }
3203
- ) });
3204
- }
3205
- function showFileUploadDialog() {
3206
- const input = document.createElement("input");
3207
- input.type = "file";
3208
- input.multiple = true;
3209
- input.accept = "*/*";
3210
- input.click();
3211
- return new Promise((resolve) => {
3212
- input.onchange = (e) => {
3213
- const files = e.currentTarget.files;
3214
- if (files) {
3215
- resolve(Array.from(files));
3216
- return;
3217
- }
3218
- resolve(null);
3219
- };
3220
- });
3221
- }
3222
-
3223
- async function highlight(code, language) {
3224
- const { codeToTokens, bundledLanguages } = await import('shiki');
3225
- if (!(language in bundledLanguages)) return null;
3226
- const { tokens } = await codeToTokens(code, {
3227
- lang: language,
3228
- defaultColor: false,
3229
- themes: {
3230
- light: "github-light",
3231
- dark: "github-dark"
3232
- }
3233
- });
3234
- return tokens;
3235
- }
3236
-
3237
- function MarkdownRenderer({ children }) {
3238
- const processedText = children?.replace(/\\n/g, "\n");
3239
- return /* @__PURE__ */ jsx(Markdown, { remarkPlugins: [remarkGfm], components: COMPONENTS, className: "space-y-3", children: processedText });
3240
- }
3241
- const HighlightedPre = React__default.memo(({ children, language, ...props }) => {
3242
- const [tokens, setTokens] = useState([]);
3243
- useEffect(() => {
3244
- highlight(children, language).then((tokens2) => {
3245
- if (tokens2) setTokens(tokens2);
3246
- });
3247
- }, [children, language]);
3248
- if (!tokens.length) {
3249
- return /* @__PURE__ */ jsx("pre", { ...props, children });
3250
- }
3251
- return /* @__PURE__ */ jsx("pre", { ...props, children: /* @__PURE__ */ jsx("code", { children: tokens.map((line, lineIndex) => /* @__PURE__ */ jsxs(Fragment, { children: [
3252
- /* @__PURE__ */ jsx("span", { children: line.map((token, tokenIndex) => {
3253
- const style = typeof token.htmlStyle === "string" ? void 0 : token.htmlStyle;
3254
- return /* @__PURE__ */ jsx(
3255
- "span",
3256
- {
3257
- className: "text-shiki-light bg-shiki-light-bg dark:text-shiki-dark dark:bg-shiki-dark-bg",
3258
- style,
3259
- children: token.content
3260
- },
3261
- tokenIndex
3262
- );
3263
- }) }, lineIndex),
3264
- lineIndex !== tokens.length - 1 && "\n"
3265
- ] })) }) });
3266
- });
3267
- HighlightedPre.displayName = "HighlightedCode";
3268
- const CodeBlock = ({ children, className, language, ...restProps }) => {
3269
- const code = typeof children === "string" ? children : childrenTakeAllStringContents(children);
3270
- const preClass = cn(
3271
- "overflow-x-scroll rounded-md border bg-background/50 p-4 font-mono text-sm [scrollbar-width:none]",
3272
- className
3273
- );
3274
- return /* @__PURE__ */ jsxs("div", { className: "group/code relative mb-4", children: [
3275
- /* @__PURE__ */ jsx(
3276
- Suspense,
3277
- {
3278
- fallback: /* @__PURE__ */ jsx("pre", { className: preClass, ...restProps, children }),
3279
- children: /* @__PURE__ */ jsx(HighlightedPre, { language, className: preClass, children: code })
3280
- }
3281
- ),
3282
- /* @__PURE__ */ jsx("div", { className: "invisible absolute right-2 top-2 flex space-x-1 rounded-lg p-1 opacity-0 transition-all duration-200 group-hover/code:visible group-hover/code:opacity-100", children: /* @__PURE__ */ jsx(CopyButton$1, { content: code, copyMessage: "Copied code to clipboard" }) })
3283
- ] });
3284
- };
3285
- function childrenTakeAllStringContents(element) {
3286
- if (typeof element === "string") {
3287
- return element;
3288
- }
3289
- if (element && typeof element === "object" && "props" in element) {
3290
- const el = element;
3291
- const children = el.props.children;
3292
- if (Array.isArray(children)) {
3293
- return children.map((child) => childrenTakeAllStringContents(child)).join("");
3294
- } else {
3295
- return childrenTakeAllStringContents(children);
3296
- }
3297
- }
3298
- return "";
3299
- }
3300
- const COMPONENTS = {
3301
- h1: withClass("h1", "text-2xl font-semibold"),
3302
- h2: withClass("h2", "font-semibold text-xl"),
3303
- h3: withClass("h3", "font-semibold text-lg"),
3304
- h4: withClass("h4", "font-semibold text-base"),
3305
- h5: withClass("h5", "font-medium"),
3306
- strong: withClass("strong", "font-semibold"),
3307
- a: withClass("a", "text-primary underline underline-offset-2"),
3308
- blockquote: withClass("blockquote", "border-l-2 border-primary pl-4"),
3309
- code: ({ children, className, ...rest }) => {
3310
- const match = /language-(\w+)/.exec(className || "");
3311
- return match ? /* @__PURE__ */ jsx(CodeBlock, { className, language: match[1], ...rest, children }) : /* @__PURE__ */ jsx(
3312
- "code",
3313
- {
3314
- className: cn(
3315
- "[:not(pre)>&]:bg-background/50 font-mono [:not(pre)>&]:rounded-md [:not(pre)>&]:px-1 [:not(pre)>&]:py-0.5"
3316
- ),
3317
- ...rest,
3318
- children
3319
- }
3320
- );
3321
- },
3322
- pre: ({ children }) => children,
3323
- ol: withClass("ol", "list-decimal space-y-2 pl-6"),
3324
- ul: withClass("ul", "list-disc space-y-2 pl-6"),
3325
- li: withClass("li", "my-1.5"),
3326
- table: withClass("table", "w-full border-collapse overflow-y-auto rounded-md border border-foreground/20"),
3327
- th: withClass(
3328
- "th",
3329
- "border border-foreground/20 px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right"
3330
- ),
3331
- td: withClass(
3332
- "td",
3333
- "border border-foreground/20 px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right"
3334
- ),
3335
- tr: withClass("tr", "m-0 border-t p-0 even:bg-muted"),
3336
- p: withClass("p", "whitespace-pre-wrap leading-relaxed"),
3337
- hr: withClass("hr", "border-foreground/20")
3338
- };
3339
- function withClass(Tag, classes) {
3340
- const Component = ({ node, ...props }) => /* @__PURE__ */ jsx(Tag, { className: classes, ...props });
3341
- Component.displayName = Tag;
3342
- return Component;
3343
- }
3344
-
3345
- const chatBubbleVariants = cva("group/message relative break-words rounded-xl px-3 py-2 text-sm sm:max-w-[70%]", {
3346
- variants: {
3347
- isUser: {
3348
- true: "bg-primary text-primary-foreground",
3349
- false: "bg-muted text-foreground"
3350
- },
3351
- isError: {
3352
- true: "bg-red-100 dark:bg-red-900/20",
3353
- false: ""
3354
- },
3355
- animation: {
3356
- none: "",
3357
- slide: "duration-300 animate-in fade-in-0",
3358
- scale: "duration-300 animate-in fade-in-0 zoom-in-75",
3359
- fade: "duration-500 animate-in fade-in-0"
3360
- }
3361
- },
3362
- compoundVariants: [
3363
- {
3364
- isUser: true,
3365
- animation: "slide",
3366
- class: "slide-in-from-right"
3367
- },
3368
- {
3369
- isUser: false,
3370
- animation: "slide",
3371
- class: "slide-in-from-left"
3372
- },
3373
- {
3374
- isUser: true,
3375
- animation: "scale",
3376
- class: "origin-bottom-right"
3377
- },
3378
- {
3379
- isUser: false,
3380
- animation: "scale",
3381
- class: "origin-bottom-left"
3382
- }
3383
- ]
3384
- });
3385
- const ChatMessage = ({
3386
- role,
3387
- content,
3388
- createdAt,
3389
- showTimeStamp = false,
3390
- animation = "scale",
3391
- actions,
3392
- className,
3393
- experimental_attachments,
3394
- isError = false
3395
- }) => {
3396
- const isUser = role === "user";
3397
- const files = useMemo(() => {
3398
- return experimental_attachments?.map((attachment) => {
3399
- const dataArray = dataUrlToUint8Array(attachment.url);
3400
- const file = new File([dataArray], attachment.name ?? "Unknown");
3401
- return file;
3402
- });
3403
- }, [experimental_attachments]);
3404
- const formattedTime = createdAt?.toLocaleTimeString("en-US", {
3405
- hour: "2-digit",
3406
- minute: "2-digit"
3407
- });
3408
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", isUser ? "items-end" : "items-start"), children: [
3409
- files ? /* @__PURE__ */ jsx("div", { className: "mb-1 flex flex-wrap gap-2", children: files.map((file, index) => {
3410
- return /* @__PURE__ */ jsx(FilePreview, { file }, index);
3411
- }) }) : null,
3412
- /* @__PURE__ */ jsxs("div", { className: cn(chatBubbleVariants({ isUser, isError, animation: "none" }), className), children: [
3413
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(MarkdownRenderer, { children: content }) }),
3414
- role === "assistant" && actions ? /* @__PURE__ */ jsx("div", { className: "bg-background text-foreground absolute -bottom-4 right-2 flex space-x-1 rounded-lg border p-1 opacity-0 transition-opacity group-hover/message:opacity-100", children: actions }) : null
3415
- ] }),
3416
- showTimeStamp && createdAt ? /* @__PURE__ */ jsx(
3417
- "time",
3418
- {
3419
- dateTime: createdAt.toISOString(),
3420
- className: cn(
3421
- "mt-1 block px-1 text-xs opacity-50",
3422
- animation !== "none" && "animate-in fade-in-0 duration-500"
3423
- ),
3424
- children: formattedTime
3425
- }
3426
- ) : null
3427
- ] });
3428
- };
3429
- function dataUrlToUint8Array(data) {
3430
- const base64 = data.split(",")[1];
3431
- const buf = Buffer.from(base64 ?? "", "base64");
3432
- return new Uint8Array(buf);
3433
- }
3434
-
3435
- function TypingIndicator() {
3436
- return /* @__PURE__ */ jsx("div", { className: "justify-left flex space-x-1", children: /* @__PURE__ */ jsx("div", { className: "bg-muted flex items-center gap-1 rounded-lg px-2 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex -space-x-2.5", children: [
3437
- /* @__PURE__ */ jsx(Dot, { className: "animate-typing-dot-bounce h-5 w-5" }),
3438
- /* @__PURE__ */ jsx(Dot, { className: "animate-typing-dot-bounce h-5 w-5 delay-200" }),
3439
- /* @__PURE__ */ jsx(Dot, { className: "animate-typing-dot-bounce h-5 w-5 delay-500" })
3440
- ] }) }) });
3441
- }
3442
-
3443
- function MessageList({ messages, showTimeStamps = true, isTyping = false, messageOptions }) {
3444
- return /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-3xl space-y-4 px-3 pt-3", children: [
3445
- messages.map((message, index) => {
3446
- const additionalOptions = typeof messageOptions === "function" ? messageOptions(message) : messageOptions;
3447
- if (message.role === "assistant" && !message.content.trim()) {
3448
- return null;
3449
- }
3450
- return /* @__PURE__ */ jsx(ChatMessage, { showTimeStamp: showTimeStamps, ...message, ...additionalOptions }, index);
3451
- }),
3452
- isTyping && /* @__PURE__ */ jsx(TypingIndicator, {})
3453
- ] });
3454
- }
3455
-
3456
- function PromptSuggestions({ append, suggestions, memoryIsPresent }) {
3457
- return /* @__PURE__ */ jsx("div", { className: "flex gap-6 text-sm", children: suggestions.map((suggestion) => /* @__PURE__ */ jsx(
3458
- "button",
3459
- {
3460
- type: "button",
3461
- onClick: () => append({ role: "user", content: suggestion }),
3462
- className: "h-max rounded-[0.4rem] bg-[#141414] p-4 py-[0.6rem]",
3463
- children: /* @__PURE__ */ jsx(
3464
- "span",
3465
- {
3466
- className: cn("text-[#939393] transition-colors hover:text-white", memoryIsPresent ? "text-xs" : "text-sm"),
3467
- children: suggestion
3468
- }
3469
- )
3470
- },
3471
- suggestion
3472
- )) });
3473
- }
3474
-
3475
- function ChatMessages({
3476
- messages,
3477
- children
3478
- }) {
3479
- const { scrollToBottom, shouldAutoScroll } = useAutoScroll([messages]);
3480
- return /* @__PURE__ */ jsxs("div", { className: "h-full overflow-y-scroll pb-4", children: [
3481
- children,
3482
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-end justify-end [grid-column:1/1] [grid-row:1/1]", children: !shouldAutoScroll && /* @__PURE__ */ jsx("div", { className: "sticky bottom-0 left-0 flex w-full justify-end", children: /* @__PURE__ */ jsx(
3483
- Button,
3484
- {
3485
- onClick: scrollToBottom,
3486
- className: "animate-in fade-in-0 slide-in-from-bottom-1 h-8 w-8 rounded-full ease-in-out",
3487
- size: "icon",
3488
- variant: "ghost",
3489
- children: /* @__PURE__ */ jsx(ArrowDown, { className: "h-4 w-4" })
3490
- }
3491
- ) }) })
3492
- ] });
3493
- }
3494
- const ChatContainer = forwardRef(
3495
- ({ className, ...props }, ref) => {
3496
- return /* @__PURE__ */ jsx("div", { ref, className: cn("w-full", className), ...props });
3497
- }
3498
- );
3499
- ChatContainer.displayName = "ChatContainer";
3500
- const ChatForm = forwardRef(
3501
- ({ children, handleSubmit, isPending, className }, ref) => {
3502
- const [files, setFiles] = useState(null);
3503
- const onSubmit = (event) => {
3504
- if (isPending) {
3505
- event.preventDefault();
3506
- return;
3507
- }
3508
- if (!files) {
3509
- handleSubmit(event);
3510
- return;
3511
- }
3512
- const fileList = createFileList(files);
3513
- handleSubmit(event, { experimental_attachments: fileList });
3514
- setFiles(null);
3515
- };
3516
- return /* @__PURE__ */ jsx("form", { ref, onSubmit, className, children: children({ files, setFiles }) });
3517
- }
3518
- );
3519
- ChatForm.displayName = "ChatForm";
3520
- function createFileList(files) {
3521
- const dataTransfer = new DataTransfer();
3522
- for (const file of Array.from(files)) {
3523
- dataTransfer.items.add(file);
3524
- }
3525
- return dataTransfer.files;
3526
- }
3527
-
3528
- function Chat({ agentId, initialMessages = [], agentName, threadId, memory, buildUrl }) {
3529
- const [messages, setMessages] = useState(initialMessages);
3530
- const [input, setInput] = useState("");
3531
- const [isLoading, setIsLoading] = useState(false);
3532
- const { mutate } = useSWRConfig();
3533
- const { containerRef, handleScroll, handleTouchStart } = useAutoScroll([messages]);
3534
- useEffect(() => {
3535
- setMessages(initialMessages);
3536
- }, [initialMessages]);
3537
- const handleInputChange = useCallback((e) => {
3538
- setInput(e.target.value);
3539
- }, []);
3540
- const handleSubmit = useCallback(
3541
- async (event) => {
3542
- event?.preventDefault?.();
3543
- if (!input.trim() || isLoading) return;
3544
- const userMessage = input;
3545
- setInput("");
3546
- setIsLoading(true);
3547
- const newUserMessage = {
3548
- id: Date.now().toString(),
3549
- role: "user",
3550
- content: userMessage
3551
- };
3552
- const newAssistantMessage = {
3553
- id: (Date.now() + 1).toString(),
3554
- role: "assistant",
3555
- content: ""
3556
- };
3557
- setMessages((prev) => [...prev, newUserMessage, newAssistantMessage]);
3558
- const newThreadId = threadId ? threadId : crypto.randomUUID();
3559
- try {
3560
- const client = new MastraClient({
3561
- baseUrl: buildUrl || ""
3562
- });
3563
- const response = await client.getAgent(agentId).stream({
3564
- messages: [userMessage],
3565
- threadId: newThreadId,
3566
- resourceId: agentId
3567
- });
3568
- if (!response.body) return;
3569
- if (response.status !== 200) {
3570
- const error = await response.json();
3571
- setMessages((prev) => [
3572
- ...prev.slice(0, -1),
3573
- {
3574
- ...prev[prev.length - 1],
3575
- content: error.error,
3576
- isError: true
3577
- }
3578
- ]);
3579
- return;
3580
- }
3581
- await mutate(`${buildUrl}/api/memory/threads?resourceid=${agentId}`);
3582
- const reader = response.body.getReader();
3583
- const decoder = new TextDecoder();
3584
- let buffer = "";
3585
- let assistantMessage = "";
3586
- while (true) {
3587
- const { done, value } = await reader.read();
3588
- if (done) {
3589
- break;
3590
- }
3591
- const chunk = decoder.decode(value);
3592
- buffer += chunk;
3593
- if (buffer?.toLocaleLowerCase()?.includes("an error occurred")) {
3594
- setMessages((prev) => [
3595
- ...prev.slice(0, -1),
3596
- {
3597
- ...prev[prev.length - 1],
3598
- content: "An error occurred while processing your request.",
3599
- isError: true
3600
- }
3601
- ]);
3602
- return;
3603
- }
3604
- const matches = buffer.matchAll(/0:"([^"]*)"/g);
3605
- for (const match of matches) {
3606
- const content = match[1];
3607
- assistantMessage += content;
3608
- setMessages((prev) => [...prev.slice(0, -1), { ...prev[prev.length - 1], content: assistantMessage }]);
3609
- }
3610
- buffer = "";
3611
- }
3612
- } catch (error) {
3613
- console.error("Error:", error);
3614
- setMessages((prev) => [
3615
- ...prev.slice(0, -1),
3616
- {
3617
- ...prev[prev.length - 1],
3618
- content: "An error occurred while processing your request.",
3619
- isError: true
3620
- }
3621
- ]);
3622
- } finally {
3623
- setIsLoading(false);
3624
- }
3625
- },
3626
- [input, isLoading, buildUrl, agentId, threadId, mutate]
3627
- );
3628
- const lastMessage = messages.at(-1);
3629
- const isEmpty = messages.length === 0;
3630
- const isTyping = isLoading && lastMessage?.role === "assistant" && !lastMessage?.content.trim();
3631
- const append = useCallback(
3632
- (message) => {
3633
- setInput(message.content);
3634
- handleSubmit();
3635
- },
3636
- [handleSubmit]
3637
- );
3638
- const suggestions = ["What capabilities do you have?", "How can you help me?", "Tell me about yourself"];
3639
- return /* @__PURE__ */ jsxs(ChatContainer, { className: "relative flex h-full w-full flex-col overflow-y-clip pb-9", children: [
3640
- /* @__PURE__ */ jsx(
3641
- "div",
3642
- {
3643
- ref: containerRef,
3644
- onScroll: handleScroll,
3645
- onTouchStart: handleTouchStart,
3646
- className: "h-full overflow-y-clip bg-transparent pb-[calc(98px+2rem)]",
3647
- children: /* @__PURE__ */ jsx(ChatMessages, { messages, children: /* @__PURE__ */ jsx(MessageList, { messages, isTyping }) })
3648
- }
3649
- ),
3650
- /* @__PURE__ */ jsxs("div", { className: "absolute bottom-8 left-1/2 flex w-full max-w-3xl -translate-x-1/2 flex-col gap-2 bg-[#0f0f0f] pb-3", children: [
3651
- isEmpty ? /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-2xl", children: /* @__PURE__ */ jsx(
3652
- PromptSuggestions,
3653
- {
3654
- memoryIsPresent: memory,
3655
- label: `Chat with ${agentName}`,
3656
- append,
3657
- suggestions
3658
- }
3659
- ) }) : null,
3660
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ChatForm, { isPending: isLoading || isTyping, handleSubmit, children: ({ files, setFiles }) => /* @__PURE__ */ jsx(
3661
- MessageInput,
3662
- {
3663
- value: input,
3664
- onChange: handleInputChange,
3665
- files,
3666
- setFiles,
3667
- isGenerating: isLoading,
3668
- placeholder: `Enter your message...`
3669
- }
3670
- ) }) }),
3671
- !memory && /* @__PURE__ */ jsxs("div", { className: "text-mastra-el-5 flex items-center gap-1 text-sm", children: [
3672
- /* @__PURE__ */ jsxs(
3673
- "svg",
3674
- {
3675
- xmlns: "http://www.w3.org/2000/svg",
3676
- width: "14",
3677
- height: "14",
3678
- viewBox: "0 0 24 24",
3679
- fill: "none",
3680
- stroke: "currentColor",
3681
- strokeWidth: "2",
3682
- strokeLinecap: "round",
3683
- strokeLinejoin: "round",
3684
- className: "text-purple-400",
3685
- children: [
3686
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
3687
- /* @__PURE__ */ jsx("path", { d: "M12 16v-4" }),
3688
- /* @__PURE__ */ jsx("path", { d: "M12 8h.01" })
3689
- ]
3690
- }
3691
- ),
3692
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-gray-300/60", children: [
3693
- "Agent will not remember previous messages. To enable memory for agent see",
3694
- " ",
3695
- /* @__PURE__ */ jsx(
3696
- "a",
3697
- {
3698
- href: "https://mastra.ai/docs/agents/01-agent-memory",
3699
- target: "_blank",
3700
- rel: "noopener",
3701
- className: "text-gray-300/60 underline hover:text-gray-100",
3702
- children: "docs."
3703
- }
3704
- )
3705
- ] })
3706
- ] })
3707
- ] })
3708
- ] });
3709
- }
3710
-
3711
2837
  const TooltipProvider = TooltipPrimitive.Provider;
3712
2838
  const Tooltip = TooltipPrimitive.Root;
3713
2839
  const TooltipTrigger = TooltipPrimitive.Trigger;
@@ -4378,7 +3504,7 @@ function MastraRuntimeProvider({
4378
3504
  refreshThreadList?.();
4379
3505
  }
4380
3506
  } catch (error) {
4381
- console.error("Error occured in MastraRuntimeProvider", error);
3507
+ console.error("Error occurred in MastraRuntimeProvider", error);
4382
3508
  setIsRunning(false);
4383
3509
  }
4384
3510
  };
@@ -4523,7 +3649,7 @@ const Table = React.forwardRef(
4523
3649
  );
4524
3650
  Table.displayName = "Table";
4525
3651
  const TableHeader = React.forwardRef(
4526
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props })
3652
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b-[0.5px]", className), ...props })
4527
3653
  );
4528
3654
  TableHeader.displayName = "TableHeader";
4529
3655
  const TableBody = React.forwardRef(
@@ -4842,29 +3968,112 @@ function EvalTable({ evals, isCIMode = false }) {
4842
3968
  evals: [evaluation]
4843
3969
  });
4844
3970
  }
4845
- return groups2;
4846
- }, []);
4847
- if (searchTerm) {
4848
- groups = groups.filter(
4849
- (group) => group.metricName.toLowerCase().includes(searchTerm.toLowerCase()) || group.evals.some(
4850
- (metric) => metric.input?.toLowerCase().includes(searchTerm.toLowerCase()) || metric.output?.toLowerCase().includes(searchTerm.toLowerCase()) || metric.instructions?.toLowerCase().includes(searchTerm.toLowerCase())
4851
- )
4852
- );
4853
- }
4854
- groups.sort((a, b) => {
4855
- const direction = sortConfig.direction === "asc" ? 1 : -1;
4856
- switch (sortConfig.field) {
4857
- case "metricName":
4858
- return direction * a.metricName.localeCompare(b.metricName);
4859
- case "averageScore":
4860
- return direction * (a.averageScore - b.averageScore);
4861
- default:
4862
- return 0;
3971
+ return groups2;
3972
+ }, []);
3973
+ if (searchTerm) {
3974
+ groups = groups.filter(
3975
+ (group) => group.metricName.toLowerCase().includes(searchTerm.toLowerCase()) || group.evals.some(
3976
+ (metric) => metric.input?.toLowerCase().includes(searchTerm.toLowerCase()) || metric.output?.toLowerCase().includes(searchTerm.toLowerCase()) || metric.instructions?.toLowerCase().includes(searchTerm.toLowerCase())
3977
+ )
3978
+ );
3979
+ }
3980
+ groups.sort((a, b) => {
3981
+ const direction = sortConfig.direction === "asc" ? 1 : -1;
3982
+ switch (sortConfig.field) {
3983
+ case "metricName":
3984
+ return direction * a.metricName.localeCompare(b.metricName);
3985
+ case "averageScore":
3986
+ return direction * (a.averageScore - b.averageScore);
3987
+ default:
3988
+ return 0;
3989
+ }
3990
+ });
3991
+ return groups;
3992
+ }
3993
+ }
3994
+
3995
+ const useResizeColumn = ({
3996
+ defaultWidth,
3997
+ minimumWidth,
3998
+ maximumWidth,
3999
+ setCurrentWidth
4000
+ }) => {
4001
+ const [isDragging, setIsDragging] = useState(false);
4002
+ const [sidebarWidth, setSidebarWidth] = useState(defaultWidth);
4003
+ const containerRef = useRef(null);
4004
+ const dragStartXRef = useRef(0);
4005
+ const initialWidthRef = useRef(0);
4006
+ const handleMouseDown = (e) => {
4007
+ e.preventDefault();
4008
+ setIsDragging(true);
4009
+ dragStartXRef.current = e.clientX;
4010
+ initialWidthRef.current = sidebarWidth;
4011
+ };
4012
+ useEffect(() => {
4013
+ setSidebarWidth(defaultWidth);
4014
+ setCurrentWidth?.(defaultWidth);
4015
+ }, [defaultWidth]);
4016
+ useEffect(() => {
4017
+ const handleMouseMove = (e) => {
4018
+ if (!isDragging || !containerRef.current) return;
4019
+ const containerWidth = containerRef.current.offsetWidth;
4020
+ const deltaX = dragStartXRef.current - e.clientX;
4021
+ const deltaPercentage = deltaX / containerWidth * 100;
4022
+ const newWidth = Math.min(Math.max(initialWidthRef.current + deltaPercentage, minimumWidth), maximumWidth);
4023
+ setSidebarWidth(newWidth);
4024
+ setCurrentWidth?.(newWidth);
4025
+ };
4026
+ const handleMouseUp = () => {
4027
+ setIsDragging(false);
4028
+ };
4029
+ if (isDragging) {
4030
+ window.addEventListener("mousemove", handleMouseMove);
4031
+ window.addEventListener("mouseup", handleMouseUp);
4032
+ }
4033
+ return () => {
4034
+ window.removeEventListener("mousemove", handleMouseMove);
4035
+ window.removeEventListener("mouseup", handleMouseUp);
4036
+ };
4037
+ }, [isDragging]);
4038
+ return { sidebarWidth, isDragging, handleMouseDown, containerRef };
4039
+ };
4040
+
4041
+ const MastraResizablePanel = ({
4042
+ children,
4043
+ defaultWidth,
4044
+ minimumWidth,
4045
+ maximumWidth,
4046
+ className,
4047
+ disabled = false,
4048
+ setCurrentWidth,
4049
+ dividerPosition = "left"
4050
+ }) => {
4051
+ const { sidebarWidth, isDragging, handleMouseDown, containerRef } = useResizeColumn({
4052
+ defaultWidth: disabled ? 100 : defaultWidth,
4053
+ minimumWidth,
4054
+ maximumWidth,
4055
+ setCurrentWidth
4056
+ });
4057
+ return /* @__PURE__ */ jsxs("div", { className: cn("w-full h-full relative", className), ref: containerRef, style: { width: `${sidebarWidth}%` }, children: [
4058
+ !disabled && dividerPosition === "left" ? /* @__PURE__ */ jsx(
4059
+ "div",
4060
+ {
4061
+ className: `w-1 bg-mastra-bg-1 bg-[#121212] h-full cursor-col-resize hover:w-1.5 hover:bg-mastra-border-2 hover:bg-[#424242] active:bg-mastra-border-3 active:bg-[#3e3e3e] transition-colors absolute inset-y-0 -left-1 -right-1 z-10
4062
+ ${isDragging ? "bg-mastra-border-2 bg-[#424242] w-1.5 cursor- col-resize" : ""}`,
4063
+ onMouseDown: handleMouseDown
4064
+ }
4065
+ ) : null,
4066
+ children,
4067
+ !disabled && dividerPosition === "right" ? /* @__PURE__ */ jsx(
4068
+ "div",
4069
+ {
4070
+ className: `w-1 bg-mastra-bg-1 bg-[#121212] h-full cursor-col-resize hover:w-1.5 hover:bg-mastra-border-2 hover:bg-[#424242] active:bg-mastra-border-3 active:bg-[#3e3e3e] transition-colors absolute inset-y-0 -left-1 -right-1 z-10
4071
+ ${isDragging ? "bg-mastra-border-2 bg-[#424242] w-1.5 cursor- col-resize" : ""}`,
4072
+ onMouseDown: handleMouseDown
4863
4073
  }
4864
- });
4865
- return groups;
4866
- }
4867
- }
4074
+ ) : null
4075
+ ] });
4076
+ };
4868
4077
 
4869
4078
  const ScrollArea = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(ScrollAreaPrimitive.Root, { ref, className: cn("relative overflow-hidden", className), ...props, children: [
4870
4079
  /* @__PURE__ */ jsx(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
@@ -5044,11 +4253,18 @@ const allowedAiSpanAttributes = [
5044
4253
  ];
5045
4254
 
5046
4255
  function Traces({ traces }) {
5047
- const { setTraces, trace: currentTrace } = useContext(TraceContext);
5048
- const currentTraceParentSpan = currentTrace?.find((span) => span.parentSpanId === void 0) || currentTrace?.[0];
4256
+ const { trace: currentTrace } = useContext(TraceContext);
4257
+ const [prevTracesId, setPrevTracesId] = useState(/* @__PURE__ */ new Set());
5049
4258
  useEffect(() => {
5050
- setTraces(traces);
4259
+ if (!prevTracesId.size && traces) {
4260
+ setPrevTracesId(new Set(traces.map((trace) => trace.traceId)));
4261
+ }
5051
4262
  }, [traces]);
4263
+ const isNew = (traceId) => {
4264
+ if (!prevTracesId.size) return false;
4265
+ return !prevTracesId.has(traceId);
4266
+ };
4267
+ const currentTraceParentSpan = currentTrace?.find((span) => span.parentSpanId === void 0) || currentTrace?.[0];
5052
4268
  return /* @__PURE__ */ jsx("div", { className: "h-full w-[calc(100%_-_400px)]", children: /* @__PURE__ */ jsx(ScrollArea, { className: "h-full", children: /* @__PURE__ */ jsxs(Table, { children: [
5053
4269
  /* @__PURE__ */ jsx(TableHeader, { className: "sticky top-0 z-10 bg-[#0F0F0F]", style: { outline: "1px solid 0_0%_20.4%" }, children: /* @__PURE__ */ jsxs(TableRow, { className: "border-gray-6 border-b-[0.1px] text-[0.8125rem]", children: [
5054
4270
  /* @__PURE__ */ jsx(TableHead, { className: "text-mastra-el-3 h-10", children: "Trace" }),
@@ -5062,9 +4278,13 @@ function Traces({ traces }) {
5062
4278
  /* @__PURE__ */ jsx(TableBody, { className: "border-b border-gray-6", children: !traces.length ? /* @__PURE__ */ jsx(TableRow, { className: "border-b-gray-6 border-b-[0.1px] text-[0.8125rem]", children: /* @__PURE__ */ jsx(TableCell, { colSpan: 4, className: "h-24 text-center", children: "No traces found" }) }) : traces.map((trace, index) => /* @__PURE__ */ jsxs(
5063
4279
  TableRow,
5064
4280
  {
5065
- className: cn("border-b-gray-6 border-b-[0.1px] text-[0.8125rem]", {
5066
- "bg-muted/50": currentTraceParentSpan?.traceId === trace.traceId
5067
- }),
4281
+ className: cn(
4282
+ "border-b-gray-6 border-b-[0.1px] text-[0.8125rem]",
4283
+ isNew(trace.traceId) ? "animate-fade-in" : "not-new",
4284
+ {
4285
+ "bg-muted/50": currentTraceParentSpan?.traceId === trace.traceId
4286
+ }
4287
+ ),
5068
4288
  children: [
5069
4289
  /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(
5070
4290
  TraceButton,
@@ -5459,7 +4679,8 @@ function usePolling({
5459
4679
  enabled = false,
5460
4680
  onSuccess,
5461
4681
  onError,
5462
- shouldContinue = () => true
4682
+ shouldContinue = () => true,
4683
+ restartPolling = false
5463
4684
  }) {
5464
4685
  const [isPolling, setIsPolling] = useState(enabled);
5465
4686
  const [error, setError] = useState(null);
@@ -5468,6 +4689,7 @@ function usePolling({
5468
4689
  const [firstCallLoading, setFirstCallLoading] = useState(false);
5469
4690
  const timeoutRef = useRef(null);
5470
4691
  const mountedRef = useRef(true);
4692
+ const [restart, setRestart] = useState(restartPolling);
5471
4693
  const cleanup = useCallback(() => {
5472
4694
  console.log("cleanup");
5473
4695
  if (timeoutRef.current) {
@@ -5486,17 +4708,15 @@ function usePolling({
5486
4708
  setError(null);
5487
4709
  }, []);
5488
4710
  const executePoll = useCallback(
5489
- async (fistCall = false) => {
4711
+ async (refetch2 = true) => {
5490
4712
  if (!mountedRef.current) return;
5491
4713
  setIsLoading(true);
5492
- setFirstCallLoading(fistCall);
5493
4714
  try {
5494
4715
  const result = await fetchFn();
5495
4716
  setData(result);
5496
4717
  setError(null);
5497
4718
  onSuccess?.(result);
5498
- setFirstCallLoading(false);
5499
- if (shouldContinue(result)) {
4719
+ if (shouldContinue(result) && refetch2) {
5500
4720
  timeoutRef.current = setTimeout(executePoll, interval);
5501
4721
  } else {
5502
4722
  stopPolling();
@@ -5515,6 +4735,18 @@ function usePolling({
5515
4735
  },
5516
4736
  [fetchFn, interval, onSuccess, onError, shouldContinue, stopPolling]
5517
4737
  );
4738
+ const refetch = useCallback(
4739
+ (withPolling = false) => {
4740
+ console.log("refetch", { withPolling });
4741
+ if (withPolling) {
4742
+ setIsPolling(true);
4743
+ } else {
4744
+ executePoll(false);
4745
+ }
4746
+ setError(null);
4747
+ },
4748
+ [executePoll]
4749
+ );
5518
4750
  useEffect(() => {
5519
4751
  mountedRef.current = true;
5520
4752
  if (enabled && isPolling) {
@@ -5526,6 +4758,16 @@ function usePolling({
5526
4758
  cleanup();
5527
4759
  };
5528
4760
  }, [enabled, isPolling, executePoll, cleanup]);
4761
+ useEffect(() => {
4762
+ setRestart(restartPolling);
4763
+ }, [restartPolling]);
4764
+ useEffect(() => {
4765
+ if (restart && !isPolling) {
4766
+ setIsPolling(true);
4767
+ executePoll();
4768
+ setRestart(false);
4769
+ }
4770
+ }, [restart]);
5529
4771
  return {
5530
4772
  isPolling,
5531
4773
  isLoading,
@@ -5533,15 +4775,19 @@ function usePolling({
5533
4775
  data,
5534
4776
  startPolling,
5535
4777
  stopPolling,
5536
- firstCallLoading
4778
+ firstCallLoading,
4779
+ refetch
5537
4780
  };
5538
4781
  }
5539
4782
 
5540
4783
  const useTraces = (componentName, baseUrl, isWorkflow = false) => {
5541
- const [traces, setTraces] = useState(null);
5542
- const client = new MastraClient({
5543
- baseUrl: baseUrl || ""
5544
- });
4784
+ const [traces, setTraces] = useState([]);
4785
+ const client = useMemo(
4786
+ () => new MastraClient({
4787
+ baseUrl: baseUrl || ""
4788
+ }),
4789
+ [baseUrl]
4790
+ );
5545
4791
  const fetchFn = useCallback(async () => {
5546
4792
  try {
5547
4793
  const res = await client.getTelemetry({
@@ -5557,7 +4803,7 @@ const useTraces = (componentName, baseUrl, isWorkflow = false) => {
5557
4803
  } catch (error2) {
5558
4804
  throw error2;
5559
4805
  }
5560
- }, [componentName]);
4806
+ }, [client, componentName, isWorkflow]);
5561
4807
  const onSuccess = useCallback((newTraces) => {
5562
4808
  if (newTraces.length > 0) {
5563
4809
  setTraces(() => newTraces);
@@ -5566,8 +4812,8 @@ const useTraces = (componentName, baseUrl, isWorkflow = false) => {
5566
4812
  const onError = useCallback((error2) => {
5567
4813
  toast.error(error2.message);
5568
4814
  }, []);
5569
- const shouldContinue = useCallback(() => {
5570
- return true;
4815
+ const shouldContinue = useCallback((result) => {
4816
+ return result.length > 0;
5571
4817
  }, []);
5572
4818
  const { firstCallLoading, error } = usePolling({
5573
4819
  fetchFn,
@@ -5580,89 +4826,6 @@ const useTraces = (componentName, baseUrl, isWorkflow = false) => {
5580
4826
  return { traces, firstCallLoading, error };
5581
4827
  };
5582
4828
 
5583
- const useResizeColumn = ({
5584
- defaultWidth,
5585
- minimumWidth,
5586
- maximumWidth,
5587
- setCurrentWidth
5588
- }) => {
5589
- const [isDragging, setIsDragging] = useState(false);
5590
- const [sidebarWidth, setSidebarWidth] = useState(defaultWidth);
5591
- const containerRef = useRef(null);
5592
- const dragStartXRef = useRef(0);
5593
- const initialWidthRef = useRef(0);
5594
- const handleMouseDown = (e) => {
5595
- e.preventDefault();
5596
- setIsDragging(true);
5597
- dragStartXRef.current = e.clientX;
5598
- initialWidthRef.current = sidebarWidth;
5599
- };
5600
- useEffect(() => {
5601
- setSidebarWidth(defaultWidth);
5602
- setCurrentWidth?.(defaultWidth);
5603
- }, [defaultWidth]);
5604
- useEffect(() => {
5605
- const handleMouseMove = (e) => {
5606
- if (!isDragging || !containerRef.current) return;
5607
- const containerWidth = containerRef.current.offsetWidth;
5608
- const deltaX = dragStartXRef.current - e.clientX;
5609
- const deltaPercentage = deltaX / containerWidth * 100;
5610
- const newWidth = Math.min(Math.max(initialWidthRef.current + deltaPercentage, minimumWidth), maximumWidth);
5611
- setSidebarWidth(newWidth);
5612
- setCurrentWidth?.(newWidth);
5613
- };
5614
- const handleMouseUp = () => {
5615
- setIsDragging(false);
5616
- };
5617
- if (isDragging) {
5618
- window.addEventListener("mousemove", handleMouseMove);
5619
- window.addEventListener("mouseup", handleMouseUp);
5620
- }
5621
- return () => {
5622
- window.removeEventListener("mousemove", handleMouseMove);
5623
- window.removeEventListener("mouseup", handleMouseUp);
5624
- };
5625
- }, [isDragging]);
5626
- return { sidebarWidth, isDragging, handleMouseDown, containerRef };
5627
- };
5628
-
5629
- const MastraResizablePanel = ({
5630
- children,
5631
- defaultWidth,
5632
- minimumWidth,
5633
- maximumWidth,
5634
- className,
5635
- disabled = false,
5636
- setCurrentWidth,
5637
- dividerPosition = "left"
5638
- }) => {
5639
- const { sidebarWidth, isDragging, handleMouseDown, containerRef } = useResizeColumn({
5640
- defaultWidth: disabled ? 100 : defaultWidth,
5641
- minimumWidth,
5642
- maximumWidth,
5643
- setCurrentWidth
5644
- });
5645
- return /* @__PURE__ */ jsxs("div", { className: cn("w-full h-full relative", className), ref: containerRef, style: { width: `${sidebarWidth}%` }, children: [
5646
- !disabled && dividerPosition === "left" ? /* @__PURE__ */ jsx(
5647
- "div",
5648
- {
5649
- className: `w-1 bg-mastra-bg-1 bg-[#121212] h-full cursor-col-resize hover:w-1.5 hover:bg-mastra-border-2 hover:bg-[#424242] active:bg-mastra-border-3 active:bg-[#3e3e3e] transition-colors absolute inset-y-0 -left-1 -right-1 z-10
5650
- ${isDragging ? "bg-mastra-border-2 bg-[#424242] w-1.5 cursor- col-resize" : ""}`,
5651
- onMouseDown: handleMouseDown
5652
- }
5653
- ) : null,
5654
- children,
5655
- !disabled && dividerPosition === "right" ? /* @__PURE__ */ jsx(
5656
- "div",
5657
- {
5658
- className: `w-1 bg-mastra-bg-1 bg-[#121212] h-full cursor-col-resize hover:w-1.5 hover:bg-mastra-border-2 hover:bg-[#424242] active:bg-mastra-border-3 active:bg-[#3e3e3e] transition-colors absolute inset-y-0 -left-1 -right-1 z-10
5659
- ${isDragging ? "bg-mastra-border-2 bg-[#424242] w-1.5 cursor- col-resize" : ""}`,
5660
- onMouseDown: handleMouseDown
5661
- }
5662
- ) : null
5663
- ] });
5664
- };
5665
-
5666
4829
  function AgentTraces({
5667
4830
  agentName,
5668
4831
  baseUrl,
@@ -5813,7 +4976,8 @@ const DataTable = ({
5813
4976
  emptyStateHeight,
5814
4977
  getRowId,
5815
4978
  selectedRowId,
5816
- isLoading
4979
+ isLoading,
4980
+ emptyText
5817
4981
  }) => {
5818
4982
  const [sorting, setSorting] = useState([]);
5819
4983
  const [{ pageIndex, pageSize }, setPagination] = useState({
@@ -5888,7 +5052,10 @@ const DataTable = ({
5888
5052
  },
5889
5053
  cell.id
5890
5054
  ))
5891
- ] }, row.id)) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: columns.length, className: cn("h-24 text-center", emptyStateHeight), children: "No results." }) }) })
5055
+ ] }, row.id)) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsxs(TableCell, { colSpan: columns.length, className: cn("h-24 text-center", emptyStateHeight), children: [
5056
+ "No ",
5057
+ emptyText || "results"
5058
+ ] }) }) })
5892
5059
  ] }) }),
5893
5060
  pagination && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-between px-2", children: [
5894
5061
  /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground text-sm", children: [
@@ -5918,6 +5085,7 @@ const AgentsTable = ({
5918
5085
  return /* @__PURE__ */ jsx(
5919
5086
  DataTable,
5920
5087
  {
5088
+ emptyText: "Agents",
5921
5089
  title,
5922
5090
  isLoading,
5923
5091
  withoutBorder: true,
@@ -5925,7 +5093,7 @@ const AgentsTable = ({
5925
5093
  icon: /* @__PURE__ */ jsx(AgentIcon, { className: "h-4 w-4" }),
5926
5094
  columns,
5927
5095
  data: agentsList,
5928
- className: "border-t-0' border-[0.5px] border-x-0"
5096
+ className: "!border-t-0 border-[0.5px] border-x-0"
5929
5097
  }
5930
5098
  );
5931
5099
  };
@@ -6082,16 +5250,26 @@ const useExecuteWorkflow = (baseUrl) => {
6082
5250
  setIsExecutingWorkflow(false);
6083
5251
  }
6084
5252
  };
6085
- const createWorkflowRun = async ({ workflowId, input }) => {
5253
+ const createWorkflowRun = async ({ workflowId, prevRunId }) => {
6086
5254
  try {
6087
- const response = await client.getWorkflow(workflowId).startRun(input || {});
6088
- return response;
5255
+ const workflow = client.getWorkflow(workflowId);
5256
+ const { runId: newRunId } = await workflow.createRun({ runId: prevRunId });
5257
+ return { runId: newRunId };
6089
5258
  } catch (error) {
6090
5259
  console.error("Error creating workflow run:", error);
6091
5260
  throw error;
6092
5261
  }
6093
5262
  };
6094
- return { executeWorkflow, createWorkflowRun, isExecutingWorkflow };
5263
+ const startWorkflowRun = async ({ workflowId, runId, input }) => {
5264
+ try {
5265
+ const workflow = client.getWorkflow(workflowId);
5266
+ await workflow.start({ runId, triggerData: input || {} });
5267
+ } catch (error) {
5268
+ console.error("Error starting workflow run:", error);
5269
+ throw error;
5270
+ }
5271
+ };
5272
+ return { executeWorkflow, startWorkflowRun, createWorkflowRun, isExecutingWorkflow };
6095
5273
  };
6096
5274
  const useWatchWorkflow = (baseUrl) => {
6097
5275
  const [isWatchingWorkflow, setIsWatchingWorkflow] = useState(false);
@@ -6102,13 +5280,10 @@ const useWatchWorkflow = (baseUrl) => {
6102
5280
  const client = new MastraClient({
6103
5281
  baseUrl
6104
5282
  });
6105
- const watchSubscription = client.getWorkflow(workflowId).watch({ runId });
6106
- if (!watchSubscription) {
6107
- throw new Error("Error watching workflow");
6108
- }
6109
- for await (const record of watchSubscription) {
5283
+ const workflow = client.getWorkflow(workflowId);
5284
+ workflow.watch({ runId }, (record) => {
6110
5285
  setWatchResult(record);
6111
- }
5286
+ });
6112
5287
  } catch (error) {
6113
5288
  console.error("Error watching workflow:", error);
6114
5289
  throw error;
@@ -6181,6 +5356,9 @@ function extractConditions(group, type) {
6181
5356
  recurse({ ...subGroup }, "or");
6182
5357
  }
6183
5358
  }
5359
+ if ("not" in group2) {
5360
+ recurse({ ...group2.not }, "not");
5361
+ }
6184
5362
  }
6185
5363
  }
6186
5364
  recurse(group);
@@ -6230,19 +5408,21 @@ const contructNodesAndEdges = ({
6230
5408
  }
6231
5409
  let nodes = [];
6232
5410
  let edges = [];
5411
+ let allSteps = [];
6233
5412
  for (const [_index, _step] of initial.entries()) {
6234
5413
  const step = _step.step;
6235
5414
  const stepId = step.id;
6236
5415
  const steps = [_step, ...stepsList?.[stepId] || []]?.reduce((acc, step2, i) => {
6237
- const newStep = {
5416
+ let newStep = {
6238
5417
  ...step2.step,
6239
5418
  label: step2.step.id,
5419
+ originalId: step2.step.id,
6240
5420
  type: "default-node",
6241
5421
  id: nodes.some((node) => node.id === step2.step.id) ? `${step2.step.id}-${i}` : step2.step.id
6242
5422
  };
6243
5423
  let conditionType = "when";
6244
5424
  if (step2.config?.serializedWhen) {
6245
- conditionType = step2.step.id === "__start_if" ? "if" : step2.step.id === "__start_else" ? "else" : "when";
5425
+ conditionType = step2.step.id?.endsWith("_if") ? "if" : step2.step.id?.endsWith("_else") ? "else" : "when";
6246
5426
  const conditions = extractConditions(step2.config.serializedWhen, conditionType);
6247
5427
  const conditionStep = {
6248
5428
  id: crypto.randomUUID(),
@@ -6252,11 +5432,20 @@ const contructNodesAndEdges = ({
6252
5432
  };
6253
5433
  acc.push(conditionStep);
6254
5434
  }
6255
- if (conditionType === "when") {
6256
- acc.push(newStep);
5435
+ if (conditionType === "if" || conditionType === "else") {
5436
+ newStep = {
5437
+ ...newStep,
5438
+ label: conditionType === "if" ? "start if" : "start else"
5439
+ };
6257
5440
  }
5441
+ newStep = {
5442
+ ...newStep,
5443
+ label: step2.config?.loopLabel || newStep.label
5444
+ };
5445
+ acc.push(newStep);
6258
5446
  return acc;
6259
5447
  }, []);
5448
+ allSteps = [...allSteps, ...steps];
6260
5449
  const newNodes = [...steps].map((step2, index) => {
6261
5450
  const subscriberGraph = stepSubscriberGraph?.[step2.id];
6262
5451
  return {
@@ -6289,21 +5478,26 @@ const contructNodesAndEdges = ({
6289
5478
  }
6290
5479
  for (const [connectingStepId, stepInfoGraph] of Object.entries(stepSubscriberGraph)) {
6291
5480
  const { initial: initial2, ...stepsList2 } = stepInfoGraph;
5481
+ let untilOrWhileConditionId;
5482
+ const loopResultSteps = [];
5483
+ let finishedLoopStep;
5484
+ let otherLoopStep;
6292
5485
  if (initial2.length) {
6293
5486
  for (const [_index, _step] of initial2.entries()) {
6294
5487
  const step = _step.step;
6295
5488
  const stepId = step.id;
6296
- const originalSteps = [_step, ...stepsList2?.[stepId] || []]?.map((step2) => step2.step);
6297
5489
  const steps = [_step, ...stepsList2?.[stepId] || []]?.reduce((acc, step2, i) => {
6298
- const newStep = {
5490
+ let newStep = {
6299
5491
  ...step2.step,
5492
+ originalId: step2.step.id,
6300
5493
  label: step2.step.id,
6301
5494
  type: "default-node",
6302
5495
  id: nodes.some((node) => node.id === step2.step.id) ? `${step2.step.id}-${i}` : step2.step.id
6303
5496
  };
6304
5497
  let conditionType = "when";
6305
- if (step2.config?.serializedWhen) {
6306
- conditionType = step2.step.id === "__start_if" ? "if" : step2.step.id === "__start_else" ? "else" : "when";
5498
+ const isFinishedLoop = step2.config?.loopLabel?.endsWith("loop finished");
5499
+ if (step2.config?.serializedWhen && !isFinishedLoop) {
5500
+ conditionType = step2.step.id?.endsWith("_if") ? "if" : step2.step.id?.endsWith("_else") ? "else" : step2.config?.loopType ?? "when";
6307
5501
  const conditions = extractConditions(step2.config.serializedWhen, conditionType);
6308
5502
  const conditionStep = {
6309
5503
  id: crypto.randomUUID(),
@@ -6311,15 +5505,67 @@ const contructNodesAndEdges = ({
6311
5505
  type: "condition-node",
6312
5506
  isLarge: (conditions?.length > 1 || conditions.some(({ fnString }) => !!fnString)) && conditionType !== "else"
6313
5507
  };
5508
+ if (conditionType === "until" || conditionType === "while") {
5509
+ untilOrWhileConditionId = conditionStep.id;
5510
+ }
6314
5511
  acc.push(conditionStep);
6315
5512
  }
6316
- if (conditionType === "when") {
6317
- acc.push(newStep);
5513
+ if (isFinishedLoop) {
5514
+ const loopResultStep = {
5515
+ id: crypto.randomUUID(),
5516
+ type: "loop-result-node",
5517
+ loopType: "finished",
5518
+ loopResult: step2.config.loopType === "until" ? true : false
5519
+ };
5520
+ loopResultSteps.push(loopResultStep);
5521
+ acc.push(loopResultStep);
5522
+ }
5523
+ if (!isFinishedLoop && step2.config?.loopType) {
5524
+ const loopResultStep = {
5525
+ id: crypto.randomUUID(),
5526
+ type: "loop-result-node",
5527
+ loopType: step2.config.loopType,
5528
+ loopResult: step2.config.loopType === "until" ? false : true
5529
+ };
5530
+ loopResultSteps.push(loopResultStep);
5531
+ acc.push(loopResultStep);
5532
+ }
5533
+ if (conditionType === "if" || conditionType === "else") {
5534
+ newStep = {
5535
+ ...newStep,
5536
+ label: conditionType === "if" ? "start if" : "start else"
5537
+ };
6318
5538
  }
5539
+ if (step2.config.loopType) {
5540
+ if (isFinishedLoop) {
5541
+ finishedLoopStep = newStep;
5542
+ } else {
5543
+ otherLoopStep = newStep;
5544
+ }
5545
+ }
5546
+ newStep = {
5547
+ ...newStep,
5548
+ loopType: isFinishedLoop ? "finished" : step2.config.loopType,
5549
+ label: step2.config?.loopLabel || newStep.label
5550
+ };
5551
+ acc.push(newStep);
6319
5552
  return acc;
6320
5553
  }, []);
6321
- const newNodes = [...steps].map((step2, index) => {
5554
+ let afterStep = [];
5555
+ let afterStepStepList = connectingStepId?.includes("&&") ? connectingStepId.split("&&") : [];
5556
+ if (connectingStepId?.includes("&&")) {
5557
+ afterStep = [
5558
+ {
5559
+ id: connectingStepId,
5560
+ label: connectingStepId,
5561
+ type: "after-node",
5562
+ steps: afterStepStepList
5563
+ }
5564
+ ];
5565
+ }
5566
+ const newNodes = [...steps, ...afterStep].map((step2, index) => {
6322
5567
  const subscriberGraph = stepSubscriberGraph?.[step2.id];
5568
+ const withBottomHandle = step2.originalId === connectingStepId || subscriberGraph;
6323
5569
  return {
6324
5570
  id: step2.id,
6325
5571
  position: { x: _index * 300 + 300, y: index * 100 + 100 },
@@ -6328,19 +5574,37 @@ const contructNodesAndEdges = ({
6328
5574
  conditions: step2.conditions,
6329
5575
  label: step2.label,
6330
5576
  description: step2.description,
6331
- withoutBottomHandle: originalSteps.some(({ id }) => id === step2.label && id !== step2.id) || subscriberGraph ? false : index === steps.length - 1,
5577
+ result: step2.loopResult,
5578
+ loopType: step2.loopType,
5579
+ steps: step2.steps,
5580
+ withoutBottomHandle: withBottomHandle ? false : index === steps.length - 1,
6332
5581
  isLarge: step2.isLarge
6333
5582
  }
6334
5583
  };
6335
5584
  });
6336
- nodes = [...nodes, ...newNodes];
5585
+ nodes = [...nodes, ...newNodes].map((node) => ({
5586
+ ...node,
5587
+ data: {
5588
+ ...node.data,
5589
+ withoutBottomHandle: afterStepStepList.includes(node.id) ? false : node.data.withoutBottomHandle
5590
+ }
5591
+ }));
6337
5592
  const edgeSteps = [...steps].slice(0, -1);
5593
+ const afterEdges = afterStepStepList.map((step2) => ({
5594
+ id: `e${step2}-${connectingStepId}`,
5595
+ source: step2,
5596
+ target: connectingStepId,
5597
+ ...defaultEdgeOptions
5598
+ }));
5599
+ const finishedLoopResult = loopResultSteps?.find((step2) => step2.loopType === "finished");
6338
5600
  const newEdges = edgeSteps.map((step2, index) => ({
6339
5601
  id: `e${step2.id}-${steps[index + 1].id}`,
6340
5602
  source: step2.id,
6341
5603
  target: steps[index + 1].id,
5604
+ remove: finishedLoopResult?.id === steps[index + 1].id,
5605
+ //remove if target is a finished loop result
6342
5606
  ...defaultEdgeOptions
6343
- }));
5607
+ }))?.filter((edge) => !edge.remove);
6344
5608
  const firstEdgeStep = steps[0];
6345
5609
  const lastEdgeStep = steps[steps.length - 1];
6346
5610
  const connectingEdge = connectingStepId === firstEdgeStep.id ? [] : [
@@ -6348,10 +5612,11 @@ const contructNodesAndEdges = ({
6348
5612
  id: `e${connectingStepId}-${firstEdgeStep.id}`,
6349
5613
  source: connectingStepId,
6350
5614
  target: firstEdgeStep.id,
5615
+ remove: finishedLoopResult?.id === firstEdgeStep.id,
6351
5616
  ...defaultEdgeOptions
6352
5617
  }
6353
- ];
6354
- const lastEdge = originalSteps.some(({ id }) => id === lastEdgeStep.label && id !== lastEdgeStep.id) ? [
5618
+ ]?.filter((edge) => !edge.remove);
5619
+ const lastEdge = lastEdgeStep.originalId === connectingStepId ? [
6355
5620
  {
6356
5621
  id: `e${lastEdgeStep.id}-${connectingStepId}`,
6357
5622
  source: lastEdgeStep.id,
@@ -6359,7 +5624,31 @@ const contructNodesAndEdges = ({
6359
5624
  ...defaultEdgeOptions
6360
5625
  }
6361
5626
  ] : [];
6362
- edges = [...edges, ...connectingEdge, ...newEdges, ...lastEdge];
5627
+ edges = [...edges, ...afterEdges, ...connectingEdge, ...newEdges, ...lastEdge];
5628
+ allSteps = [...allSteps, ...steps];
5629
+ }
5630
+ if (untilOrWhileConditionId && loopResultSteps.length && finishedLoopStep && otherLoopStep) {
5631
+ const loopResultStepsEdges = loopResultSteps.map((step) => ({
5632
+ id: `e${untilOrWhileConditionId}-${step.id}`,
5633
+ source: untilOrWhileConditionId,
5634
+ target: step.id,
5635
+ ...defaultEdgeOptions
5636
+ }));
5637
+ const finishedLoopResult = loopResultSteps?.find((res) => res.loopType === "finished");
5638
+ const otherLoopResult = loopResultSteps?.find((res) => res.loopType !== "finished");
5639
+ const otherLoopEdge = {
5640
+ id: `e${otherLoopResult?.id}-${otherLoopStep?.id}`,
5641
+ source: otherLoopResult?.id,
5642
+ target: otherLoopStep.id,
5643
+ ...defaultEdgeOptions
5644
+ };
5645
+ const finishedLoopEdge = {
5646
+ id: `e${finishedLoopResult?.id}-${finishedLoopStep?.id}`,
5647
+ source: finishedLoopResult?.id,
5648
+ target: finishedLoopStep.id,
5649
+ ...defaultEdgeOptions
5650
+ };
5651
+ edges = [...edges, ...loopResultStepsEdges, otherLoopEdge, finishedLoopEdge];
6363
5652
  }
6364
5653
  }
6365
5654
  }
@@ -6427,7 +5716,7 @@ function WorkflowConditionNode({ data }) {
6427
5716
  size: "xs",
6428
5717
  weight: "medium",
6429
5718
  className: "text-mastra-el-3 bg-mastra-bg-11 my-auto block rounded-[0.125rem] px-2 py-1 text-[10px] w-fit",
6430
- children: type.toUpperCase()
5719
+ children: type?.toUpperCase()
6431
5720
  }
6432
5721
  ),
6433
5722
  isCollapsible && /* @__PURE__ */ jsx(
@@ -6488,14 +5777,72 @@ function WorkflowDefaultNode({ data }) {
6488
5777
  ] });
6489
5778
  }
6490
5779
 
5780
+ function WorkflowAfterNode({ data }) {
5781
+ const { steps } = data;
5782
+ const [open, setOpen] = useState(true);
5783
+ return /* @__PURE__ */ jsxs(
5784
+ Collapsible,
5785
+ {
5786
+ open,
5787
+ onOpenChange: setOpen,
5788
+ className: cn("bg-mastra-bg-3 rounded-md w-[274px] flex flex-col p-2 gap-2"),
5789
+ children: [
5790
+ /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Top, style: { visibility: "hidden" } }),
5791
+ /* @__PURE__ */ jsxs(CollapsibleTrigger, { className: "flex items-center justify-between w-full", children: [
5792
+ /* @__PURE__ */ jsx(
5793
+ Text,
5794
+ {
5795
+ size: "xs",
5796
+ weight: "medium",
5797
+ className: "text-mastra-el-3 bg-mastra-bg-11 my-auto block rounded-[0.125rem] px-2 py-1 text-[10px] w-fit",
5798
+ children: "AFTER"
5799
+ }
5800
+ ),
5801
+ /* @__PURE__ */ jsx(
5802
+ ChevronDown,
5803
+ {
5804
+ className: cn("w-4 h-4 transition-transform", {
5805
+ "transform rotate-180": open
5806
+ })
5807
+ }
5808
+ )
5809
+ ] }),
5810
+ /* @__PURE__ */ jsx(CollapsibleContent, { className: "flex flex-col gap-2", children: steps.map((step) => /* @__PURE__ */ jsxs("div", { className: "text-sm bg-mastra-bg-9 flex items-center gap-[6px] rounded-sm p-2", children: [
5811
+ /* @__PURE__ */ jsx(Footprints, { className: "text-current w-4 h-4" }),
5812
+ /* @__PURE__ */ jsx(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: step })
5813
+ ] }, step)) }),
5814
+ /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Bottom, style: { visibility: "hidden" } })
5815
+ ]
5816
+ }
5817
+ );
5818
+ }
5819
+
5820
+ function WorkflowLoopResultNode({ data }) {
5821
+ const { result } = data;
5822
+ return /* @__PURE__ */ jsxs("div", { className: cn("bg-mastra-bg-8 rounded-md w-[274px]"), children: [
5823
+ /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Top, style: { visibility: "hidden" } }),
5824
+ /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs("div", { className: "text-sm bg-mastra-bg-9 flex items-center gap-[6px] rounded-sm p-2", children: [
5825
+ result ? /* @__PURE__ */ jsx(CircleCheck, { className: "text-current w-4 h-4" }) : /* @__PURE__ */ jsx(CircleX, { className: "text-current w-4 h-4" }),
5826
+ /* @__PURE__ */ jsx(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: String(result) })
5827
+ ] }) }),
5828
+ /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Bottom, style: { visibility: "hidden" } })
5829
+ ] });
5830
+ }
5831
+
6491
5832
  function WorkflowGraphInner({ workflow }) {
6492
- const { nodes: initialNodes, edges: initialEdges } = contructNodesAndEdges(workflow);
5833
+ const { nodes: initialNodes, edges: initialEdges } = contructNodesAndEdges({
5834
+ stepGraph: workflow.serializedStepGraph,
5835
+ stepSubscriberGraph: workflow.serializedStepSubscriberGraph
5836
+ });
6493
5837
  const [nodes, _, onNodesChange] = useNodesState(initialNodes);
6494
5838
  const [edges] = useEdgesState(initialEdges);
6495
5839
  const nodeTypes = {
6496
5840
  "default-node": WorkflowDefaultNode,
6497
- "condition-node": WorkflowConditionNode
5841
+ "condition-node": WorkflowConditionNode,
5842
+ "after-node": WorkflowAfterNode,
5843
+ "loop-result-node": WorkflowLoopResultNode
6498
5844
  };
5845
+ console.log("nodes===>", nodes);
6499
5846
  return /* @__PURE__ */ jsx("div", { className: "w-full h-full", children: /* @__PURE__ */ jsxs(
6500
5847
  ReactFlow,
6501
5848
  {
@@ -6574,6 +5921,7 @@ const WorkflowsTable = ({
6574
5921
  return /* @__PURE__ */ jsx(
6575
5922
  DataTable,
6576
5923
  {
5924
+ emptyText: "Workflows",
6577
5925
  title,
6578
5926
  withoutBorder: true,
6579
5927
  withoutRadius: true,
@@ -7836,15 +7184,15 @@ function CodeBlockDemo({
7836
7184
  filename,
7837
7185
  className
7838
7186
  }) {
7839
- return /* @__PURE__ */ jsxs(CodeBlock$1, { code, language, theme: themes.oneDark, children: [
7187
+ return /* @__PURE__ */ jsxs(CodeBlock, { code, language, theme: themes.oneDark, children: [
7840
7188
  filename ? /* @__PURE__ */ jsx("div", { className: "absolute w-full px-6 py-2 pl-4 text-sm rounded bg-mastra-bg-2 text-mastra-el-6/50", children: filename }) : null,
7841
7189
  /* @__PURE__ */ jsx(
7842
- CodeBlock$1.Code,
7190
+ CodeBlock.Code,
7843
7191
  {
7844
7192
  className: cn("bg-transparent h-full p-6 rounded-xl whitespace-pre-wrap", filename ? "pt-10" : "", className),
7845
7193
  children: /* @__PURE__ */ jsx("div", { className: "table-row", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
7846
- /* @__PURE__ */ jsx(CodeBlock$1.LineNumber, { className: "table-cell pr-4 text-sm text-right select-none text-gray-500/50" }),
7847
- /* @__PURE__ */ jsx(CodeBlock$1.LineContent, { className: "flex", children: /* @__PURE__ */ jsx(CodeBlock$1.Token, { className: "font-mono text-sm mastra-token" }) })
7194
+ /* @__PURE__ */ jsx(CodeBlock.LineNumber, { className: "table-cell pr-4 text-sm text-right select-none text-gray-500/50" }),
7195
+ /* @__PURE__ */ jsx(CodeBlock.LineContent, { className: "flex", children: /* @__PURE__ */ jsx(CodeBlock.Token, { className: "font-mono text-sm mastra-token" }) })
7848
7196
  ] }) })
7849
7197
  }
7850
7198
  )
@@ -7923,7 +7271,7 @@ function WorkflowTrigger({
7923
7271
  }) {
7924
7272
  const { result, setResult, payload, setPayload } = useContext(WorkflowRunContext);
7925
7273
  const { isLoading, workflow } = useWorkflow(workflowId, baseUrl);
7926
- const { createWorkflowRun } = useExecuteWorkflow(baseUrl);
7274
+ const { createWorkflowRun, startWorkflowRun } = useExecuteWorkflow(baseUrl);
7927
7275
  const { watchWorkflow, watchResult, isWatchingWorkflow } = useWatchWorkflow(baseUrl);
7928
7276
  const { resumeWorkflow, isResumingWorkflow } = useResumeWorkflow(baseUrl);
7929
7277
  const [suspendedSteps, setSuspendedSteps] = useState([]);
@@ -7934,9 +7282,10 @@ function WorkflowTrigger({
7934
7282
  if (!workflow) return;
7935
7283
  setIsRunning(true);
7936
7284
  setResult(null);
7937
- const { runId } = await createWorkflowRun({ workflowId, input: data });
7285
+ const { runId } = await createWorkflowRun({ workflowId });
7938
7286
  setRunId?.(runId);
7939
7287
  watchWorkflow({ workflowId, runId });
7288
+ startWorkflowRun({ workflowId, runId, input: data });
7940
7289
  } catch (err) {
7941
7290
  setIsRunning(false);
7942
7291
  toast.error("Error executing workflow");
@@ -7944,14 +7293,15 @@ function WorkflowTrigger({
7944
7293
  };
7945
7294
  const handleResumeWorkflow = async (step) => {
7946
7295
  if (!workflow) return;
7947
- const { stepId, runId, context } = step;
7948
- resumeWorkflow({
7296
+ const { stepId, runId: prevRunId, context } = step;
7297
+ const { runId } = await createWorkflowRun({ workflowId, prevRunId });
7298
+ watchWorkflow({ workflowId, runId });
7299
+ await resumeWorkflow({
7949
7300
  stepId,
7950
7301
  runId,
7951
7302
  context,
7952
7303
  workflowId
7953
7304
  });
7954
- watchWorkflow({ workflowId, runId });
7955
7305
  };
7956
7306
  const watchResultToUse = result ?? watchResult;
7957
7307
  const workflowActivePaths = watchResultToUse?.activePaths ?? [];
@@ -7962,7 +7312,8 @@ function WorkflowTrigger({
7962
7312
  if (!watchResultToUse?.activePaths || !result?.runId) return;
7963
7313
  const suspended = watchResultToUse.activePaths.filter((path) => watchResultToUse.context?.steps?.[path.stepId]?.status === "suspended").map((path) => ({
7964
7314
  stepId: path.stepId,
7965
- runId: result.runId
7315
+ runId: result.runId,
7316
+ suspendPayload: watchResultToUse.context?.steps?.[path.stepId]?.suspendPayload
7966
7317
  }));
7967
7318
  setSuspendedSteps(suspended);
7968
7319
  }, [watchResultToUse, result]);
@@ -7980,13 +7331,13 @@ function WorkflowTrigger({
7980
7331
  if (!workflow) return null;
7981
7332
  if (!triggerSchema) {
7982
7333
  return /* @__PURE__ */ jsx(ScrollArea, { className: "h-[calc(100vh-126px)] pt-2 px-4 pb-4 text-xs w-full", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
7983
- /* @__PURE__ */ jsx("div", { className: "space-y-4 px-4", children: /* @__PURE__ */ jsx(Button, { className: "w-full", disabled: isRunning, onClick: () => handleExecuteWorkflow(null), children: isRunning ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : "Trigger" }) }),
7334
+ /* @__PURE__ */ jsx("div", { className: "px-4 space-y-4", children: /* @__PURE__ */ jsx(Button, { className: "w-full", disabled: isRunning, onClick: () => handleExecuteWorkflow(null), children: isRunning ? /* @__PURE__ */ jsx(Loader2, { className: "w-4 h-4 animate-spin" }) : "Trigger" }) }),
7984
7335
  /* @__PURE__ */ jsxs("div", { children: [
7985
- /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "text-mastra-el-3 px-4", size: "xs", children: "Output" }),
7336
+ /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "px-4 text-mastra-el-3", size: "xs", children: "Output" }),
7986
7337
  /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ jsx(
7987
7338
  CopyButton,
7988
7339
  {
7989
- classname: "absolute z-40 top-4 right-4 w-8 h-8 p-0 opacity-0 group-hover:opacity-100 transition-opacity duration-150 ease-in-out",
7340
+ classname: "absolute z-40 w-8 h-8 p-0 transition-opacity duration-150 ease-in-out opacity-0 top-4 right-4 group-hover:opacity-100",
7990
7341
  content: JSON.stringify(result ?? {}, null, 2)
7991
7342
  }
7992
7343
  ) }),
@@ -8002,30 +7353,13 @@ function WorkflowTrigger({
8002
7353
  ] }) });
8003
7354
  }
8004
7355
  const zodInputSchema = resolveSerializedZodOutput(jsonSchemaToZod(parse(triggerSchema)));
7356
+ const isSuspendedSteps = suspendedSteps.length > 0;
8005
7357
  return /* @__PURE__ */ jsx(ScrollArea, { className: "h-[calc(100vh-126px)] pt-2 px-4 pb-4 text-xs w-full", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8006
- /* @__PURE__ */ jsxs("div", { children: [
8007
- suspendedSteps.length > 0 ? suspendedSteps?.map((step) => /* @__PURE__ */ jsxs("div", { className: "px-4", children: [
8008
- /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "text-mastra-el-3", size: "xs", children: step.stepId }),
8009
- /* @__PURE__ */ jsx(
8010
- DynamicForm,
8011
- {
8012
- schema: z$1.record(z$1.string(), z$1.any()),
8013
- isSubmitLoading: isResumingWorkflow,
8014
- submitButtonLabel: "Resume",
8015
- onSubmit: (data) => {
8016
- handleResumeWorkflow({
8017
- stepId: step.stepId,
8018
- runId: step.runId,
8019
- context: data
8020
- });
8021
- }
8022
- }
8023
- )
8024
- ] })) : /* @__PURE__ */ jsx(Fragment, {}),
7358
+ !isSuspendedSteps && /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
8025
7359
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between w-full", children: [
8026
- /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "text-mastra-el-3 px-4", size: "xs", children: "Input" }),
7360
+ /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "px-4 text-mastra-el-3", size: "xs", children: "Input" }),
8027
7361
  isResumingWorkflow ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
8028
- /* @__PURE__ */ jsx(Loader2, { className: "animate-spin w-3 h-3 text-mastra-el-accent" }),
7362
+ /* @__PURE__ */ jsx(Loader2, { className: "w-3 h-3 animate-spin text-mastra-el-accent" }),
8029
7363
  " Resuming workflow"
8030
7364
  ] }) : /* @__PURE__ */ jsx(Fragment, {})
8031
7365
  ] }),
@@ -8034,7 +7368,7 @@ function WorkflowTrigger({
8034
7368
  {
8035
7369
  schema: zodInputSchema,
8036
7370
  defaultValues: payload,
8037
- isSubmitLoading: isRunning,
7371
+ isSubmitLoading: isWatchingWorkflow,
8038
7372
  onSubmit: (data) => {
8039
7373
  setPayload(data);
8040
7374
  handleExecuteWorkflow(data);
@@ -8042,12 +7376,12 @@ function WorkflowTrigger({
8042
7376
  }
8043
7377
  )
8044
7378
  ] }),
8045
- workflowActivePaths.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
8046
- /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "text-mastra-el-3 px-4", size: "xs", children: "Status" }),
7379
+ workflowActivePaths.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
7380
+ /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "px-4 text-mastra-el-3", size: "xs", children: "Status" }),
8047
7381
  /* @__PURE__ */ jsx("div", { className: "px-4", children: workflowActivePaths?.map((activePath, idx) => {
8048
- return /* @__PURE__ */ jsx("div", { className: "flex flex-col mt-2 border overflow-hidden", children: activePath?.stepPath?.map((sp, idx2) => {
7382
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col mt-2 overflow-hidden border", children: activePath?.stepPath?.map((sp, idx2) => {
8049
7383
  const status = activePath?.status === "completed" ? "Completed" : sp === activePath?.stepId ? activePath?.status.charAt(0).toUpperCase() + activePath?.status.slice(1) : "Completed";
8050
- const statusIcon = status === "Completed" ? /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-green-500 rounded-full" }) : /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-yellow-500 animate-pulse rounded-full" });
7384
+ const statusIcon = status === "Completed" ? /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-green-500 rounded-full" }) : /* @__PURE__ */ jsx("div", { className: "w-2 h-2 bg-yellow-500 rounded-full animate-pulse" });
8051
7385
  return /* @__PURE__ */ jsxs(
8052
7386
  "div",
8053
7387
  {
@@ -8069,12 +7403,39 @@ function WorkflowTrigger({
8069
7403
  }) }, idx);
8070
7404
  }) })
8071
7405
  ] }),
8072
- result && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
8073
- /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "text-mastra-el-3 px-4", size: "xs", children: "Output" }),
7406
+ isSuspendedSteps && suspendedSteps?.map((step) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col px-4", children: [
7407
+ /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "text-mastra-el-3", size: "xs", children: step.stepId }),
7408
+ step.suspendPayload && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
7409
+ CodeBlockDemo,
7410
+ {
7411
+ className: "w-[300px] overflow-x-auto",
7412
+ code: JSON.stringify(step.suspendPayload, null, 2),
7413
+ language: "json"
7414
+ }
7415
+ ) }),
7416
+ /* @__PURE__ */ jsx(
7417
+ DynamicForm,
7418
+ {
7419
+ schema: z$1.record(z$1.string(), z$1.any()),
7420
+ isSubmitLoading: isResumingWorkflow,
7421
+ submitButtonLabel: "Resume",
7422
+ onSubmit: (data) => {
7423
+ handleResumeWorkflow({
7424
+ stepId: step.stepId,
7425
+ runId: step.runId,
7426
+ suspendPayload: step.suspendPayload,
7427
+ context: data
7428
+ });
7429
+ }
7430
+ }
7431
+ )
7432
+ ] })),
7433
+ result && /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
7434
+ /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "px-4 text-mastra-el-3", size: "xs", children: "Output" }),
8074
7435
  /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: /* @__PURE__ */ jsx(
8075
7436
  CopyButton,
8076
7437
  {
8077
- classname: "absolute z-40 top-4 right-4 w-8 h-8 p-0 opacity-0 group-hover:opacity-100 transition-opacity duration-150 ease-in-out",
7438
+ classname: "absolute z-40 w-8 h-8 p-0 transition-opacity duration-150 ease-in-out opacity-0 top-4 right-4 group-hover:opacity-100",
8078
7439
  content: JSON.stringify(result, null, 2)
8079
7440
  }
8080
7441
  ) }),
@@ -8090,5 +7451,5 @@ function WorkflowTrigger({
8090
7451
  ] }) });
8091
7452
  }
8092
7453
 
8093
- export { AgentChat, AgentEvals, AgentTraces, AgentsTable, Chat, MastraResizablePanel, WorkflowGraph, WorkflowRunContext, WorkflowRunProvider, WorkflowTraces, WorkflowTrigger, WorkflowsTable };
7454
+ export { AgentChat, AgentEvals, AgentTraces, AgentsTable, MastraResizablePanel, WorkflowGraph, WorkflowRunContext, WorkflowRunProvider, WorkflowTraces, WorkflowTrigger, WorkflowsTable };
8094
7455
  //# sourceMappingURL=index.es.js.map