@mastra/playground-ui 6.2.2-alpha.3 → 6.2.3-alpha.0

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.
Files changed (25) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/index.cjs.js +1297 -2068
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.es.js +1299 -2065
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/src/domains/agents/components/agent-metadata/agent-metadata-model-list.d.ts +17 -0
  7. package/dist/src/domains/agents/components/agent-metadata/agent-metadata.d.ts +4 -1
  8. package/dist/src/domains/agents/components/agent-table/types.d.ts +2 -1
  9. package/dist/src/domains/agents/components/provider-map-icon.d.ts +1 -0
  10. package/dist/src/domains/workflows/components/workflow-table/types.d.ts +0 -1
  11. package/dist/src/domains/workflows/components/workflow-table/workflow-table.d.ts +2 -3
  12. package/dist/src/domains/workflows/context/workflow-run-context.d.ts +0 -3
  13. package/dist/src/domains/workflows/index.d.ts +0 -2
  14. package/dist/src/domains/workflows/workflow/utils.d.ts +0 -10
  15. package/dist/src/hooks/use-workflows.d.ts +1 -45
  16. package/dist/src/services/stream-chunk-message.d.ts +9 -18
  17. package/dist/src/types.d.ts +7 -1
  18. package/package.json +6 -4
  19. package/dist/src/domains/workflows/context/legacy-workflow-nested-graph-context.d.ts +0 -13
  20. package/dist/src/domains/workflows/workflow/legacy-workflow-graph-inner.d.ts +0 -4
  21. package/dist/src/domains/workflows/workflow/legacy-workflow-graph.d.ts +0 -3
  22. package/dist/src/domains/workflows/workflow/legacy-workflow-nested-graph.d.ts +0 -5
  23. package/dist/src/domains/workflows/workflow/legacy-workflow-nested-node.d.ts +0 -11
  24. package/dist/src/domains/workflows/workflow/legacy-workflow-status.d.ts +0 -6
  25. package/dist/src/domains/workflows/workflow/legacy-workflow-trigger.d.ts +0 -4
package/dist/index.es.js CHANGED
@@ -3,7 +3,7 @@ import * as React from 'react';
3
3
  import React__default, { createContext, useContext, forwardRef, memo, useState, useEffect, useRef, useCallback, useMemo, Fragment as Fragment$1, isValidElement, useId, startTransition } from 'react';
4
4
  import { MastraClient } from '@mastra/client-js';
5
5
  import { useMessage, MessagePrimitive, ActionBarPrimitive, useAttachment, AttachmentPrimitive, useComposerRuntime, ComposerPrimitive, useComposer, ThreadPrimitive, CompositeAttachmentAdapter, SimpleImageAttachmentAdapter, SimpleTextAttachmentAdapter, WebSpeechSynthesisAdapter, useExternalStoreRuntime, AssistantRuntimeProvider } from '@assistant-ui/react';
6
- import { CheckIcon as CheckIcon$1, CopyIcon, Check, Copy, ChevronUpIcon, X, Share2, Braces, Loader2, Network, ChevronDown, PauseIcon, HourglassIcon, CircleDashed, Footprints, CircleCheck, CircleX, Workflow, AlertCircleIcon, AlertCircle, CalendarIcon, Brackets, PlusIcon, TrashIcon, Plus, ChevronDownIcon, Minus, Maximize, CirclePause, Circle, StopCircle, BrainIcon, AudioLinesIcon, StopCircleIcon, FileText, CircleXIcon, Link, CloudUpload, Mic, ArrowUp, Search, RefreshCcwIcon, ChevronRight, SortAsc, SortDesc, SaveIcon, RefreshCw, ExternalLink, InfoIcon as InfoIcon$1, TriangleAlertIcon, ChevronRightIcon, ArrowLeftIcon, ArrowRightIcon, XIcon, ChevronsRightIcon, ArrowUpIcon, ArrowDownIcon, AlignLeftIcon, AlignJustifyIcon, CircleAlertIcon, GaugeIcon, HashIcon, EditIcon, Users, Brain, NetworkIcon, SearchIcon, WorkflowIcon as WorkflowIcon$1, PackageIcon, GitBranchIcon, PackageOpenIcon, OctagonXIcon, AlertTriangleIcon, FrownIcon, ChevronUp, ChevronsLeftRight, TimerIcon, ChevronsLeftRightIcon, ChevronFirstIcon, ChevronLastIcon, ListTreeIcon, ArrowRightToLineIcon, CoinsIcon, EyeIcon, ChevronsLeftRightEllipsisIcon, PanelTopIcon, PanelLeftIcon } from 'lucide-react';
6
+ import { CheckIcon as CheckIcon$1, CopyIcon, Check, Copy, ChevronUpIcon, X, Share2, Braces, Loader2, Network, ChevronDown, PauseIcon, HourglassIcon, CircleDashed, Footprints, CircleCheck, CircleX, Minus, Plus, Maximize, Workflow, AlertCircleIcon, ChevronDownIcon, CirclePause, AlertCircle, CalendarIcon, Brackets, PlusIcon, TrashIcon, Circle, StopCircle, BrainIcon, AudioLinesIcon, StopCircleIcon, FileText, CircleXIcon, Link, CloudUpload, Mic, ArrowUp, Search, RefreshCcwIcon, ChevronRight, SortAsc, SortDesc, SaveIcon, RefreshCw, ExternalLink, InfoIcon as InfoIcon$1, TriangleAlertIcon, ChevronRightIcon, ArrowLeftIcon, ArrowRightIcon, XIcon, ChevronsRightIcon, ArrowUpIcon, ArrowDownIcon, AlignLeftIcon, AlignJustifyIcon, CircleAlertIcon, GaugeIcon, HashIcon, GripVertical, EditIcon, Users, Brain, NetworkIcon, SearchIcon, WorkflowIcon as WorkflowIcon$1, PackageIcon, GitBranchIcon, PackageOpenIcon, OctagonXIcon, AlertTriangleIcon, FrownIcon, ChevronUp, ChevronsLeftRight, TimerIcon, ChevronsLeftRightIcon, ChevronFirstIcon, ChevronLastIcon, ListTreeIcon, ArrowRightToLineIcon, CoinsIcon, EyeIcon, ChevronsLeftRightEllipsisIcon, PanelTopIcon, PanelLeftIcon } from 'lucide-react';
7
7
  import { Slot } from '@radix-ui/react-slot';
8
8
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
9
9
  import { TooltipProvider as TooltipProvider$1 } from '@radix-ui/react-tooltip';
@@ -19,27 +19,27 @@ import { draculaInit } from '@uiw/codemirror-theme-dracula';
19
19
  import CodeMirror, { EditorView } from '@uiw/react-codemirror';
20
20
  import { toast } from 'sonner';
21
21
  import * as DialogPrimitive from '@radix-ui/react-dialog';
22
- import { useDebouncedCallback } from 'use-debounce';
23
- import { create } from 'zustand';
24
- import { persist } from 'zustand/middleware';
25
- import { useQuery, useMutation, QueryClient, QueryClientProvider } from '@tanstack/react-query';
26
- import './index.css';export * from '@tanstack/react-query';
27
- import { MarkerType, Handle, Position, useNodesState, useEdgesState, ReactFlow, Controls, Background, BackgroundVariant, ReactFlowProvider, useViewport, useReactFlow, Panel } from '@xyflow/react';
22
+ import { MarkerType, Handle, Position, useViewport, useReactFlow, Panel, useNodesState, useEdgesState, ReactFlow, Background, BackgroundVariant, ReactFlowProvider } from '@xyflow/react';
28
23
  import '@xyflow/react/dist/style.css';
29
24
  import Dagre from '@dagrejs/dagre';
30
25
  import { Highlight, themes } from 'prism-react-renderer';
31
26
  import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
32
27
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
28
+ import { C as Colors, I as IconColors } from './colors-DrbbnW3f.js';
33
29
  import prettier from 'prettier';
34
30
  import prettierPluginBabel from 'prettier/plugins/babel';
35
31
  import prettierPluginEstree from 'prettier/plugins/estree';
36
- import { C as Colors, I as IconColors } from './colors-DrbbnW3f.js';
32
+ import * as SliderPrimitive from '@radix-ui/react-slider';
37
33
  import jsonSchemaToZod from 'json-schema-to-zod';
38
34
  import { parse } from 'superjson';
39
35
  import z$2, { z, ZodObject, ZodIntersection } from 'zod';
36
+ import { CodeBlock } from 'react-code-block';
37
+ import { create } from 'zustand';
38
+ import { persist } from 'zustand/middleware';
40
39
  import { AutoForm as AutoForm$1, buildZodFieldConfig } from '@autoform/react';
41
40
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
42
41
  import { format, isValid, formatDate, formatDistanceToNow } from 'date-fns';
42
+ import { useDebouncedCallback } from 'use-debounce';
43
43
  import { DayPicker } from 'react-day-picker';
44
44
  import * as PopoverPrimitive from '@radix-ui/react-popover';
45
45
  import * as SelectPrimitive from '@radix-ui/react-select';
@@ -47,19 +47,21 @@ import { v4 } from '@lukeed/uuid';
47
47
  import * as LabelPrimitive from '@radix-ui/react-label';
48
48
  import { ZodProvider, getFieldConfigInZodStack, getDefaultValueInZodStack } from '@autoform/zod/v4';
49
49
  import { z as z$1 } from 'zod/v3';
50
- import { CodeBlock } from 'react-code-block';
51
- import * as SliderPrimitive from '@radix-ui/react-slider';
52
50
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
51
+ import { useQuery, useMutation, QueryClient, QueryClientProvider } from '@tanstack/react-query';
52
+ import './index.css';export * from '@tanstack/react-query';
53
53
  import { useReactTable, getCoreRowModel, flexRender } from '@tanstack/react-table';
54
54
  import Markdown from 'react-markdown';
55
55
  import { useShallow } from 'zustand/shallow';
56
56
  import { RuntimeContext as RuntimeContext$1 } from '@mastra/core/di';
57
- import { flushSync } from 'react-dom';
57
+ import { useMastraChat } from '@mastra/react-hooks';
58
58
  import { AnimatePresence } from 'motion/react';
59
59
  import * as TabsPrimitive from '@radix-ui/react-tabs';
60
60
  import * as VisuallyHidden from '@radix-ui/react-visually-hidden';
61
61
  import { VisuallyHidden as VisuallyHidden$1 } from '@radix-ui/react-visually-hidden';
62
62
  import * as HoverCard from '@radix-ui/react-hover-card';
63
+ import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
64
+ import * as SwitchPrimitives from '@radix-ui/react-switch';
63
65
  import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
64
66
  import { RuntimeContext as RuntimeContext$2 } from '@mastra/core/runtime-context';
65
67
  import { format as format$1 } from 'date-fns/format';
@@ -4503,549 +4505,284 @@ const ToolBadge = ({ toolName, args, result, networkMetadata, toolOutput }) => {
4503
4505
  );
4504
4506
  };
4505
4507
 
4506
- function Skeleton({ className, ...props }) {
4507
- return /* @__PURE__ */ jsx("div", { className: cn("animate-pulse rounded-md bg-muted/50", className), ...props });
4508
- }
4509
-
4510
- const usePlaygroundStore = create()(
4511
- persist(
4512
- (set) => ({
4513
- runtimeContext: {},
4514
- setRuntimeContext: (runtimeContext) => set({ runtimeContext })
4515
- }),
4516
- {
4517
- name: "mastra-playground-store"
4508
+ function convertWorkflowRunStateToWatchResult(runState) {
4509
+ const runId = runState.runId;
4510
+ const steps = {};
4511
+ const context = runState.context || {};
4512
+ Object.entries(context).forEach(([stepId, stepResult]) => {
4513
+ if (stepId !== "input" && "status" in stepResult) {
4514
+ const result = stepResult;
4515
+ steps[stepId] = {
4516
+ status: result.status,
4517
+ output: "output" in result ? result.output : void 0,
4518
+ payload: "payload" in result ? result.payload : void 0,
4519
+ resumePayload: "resumePayload" in result ? result.resumePayload : void 0,
4520
+ error: "error" in result ? result.error : void 0,
4521
+ startedAt: "startedAt" in result ? result.startedAt : Date.now(),
4522
+ endedAt: "endedAt" in result ? result.endedAt : void 0,
4523
+ suspendedAt: "suspendedAt" in result ? result.suspendedAt : void 0,
4524
+ resumedAt: "resumedAt" in result ? result.resumedAt : void 0
4525
+ };
4518
4526
  }
4519
- )
4520
- );
4521
-
4522
- const useWorkflow = (workflowId) => {
4523
- const client = useMastraClient();
4524
- const { runtimeContext } = usePlaygroundStore();
4525
- return useQuery({
4526
- queryKey: ["workflow", workflowId],
4527
- queryFn: () => workflowId ? client.getWorkflow(workflowId).details(runtimeContext) : null,
4528
- enabled: Boolean(workflowId),
4529
- retry: false,
4530
- refetchOnWindowFocus: false,
4531
- throwOnError: false
4532
4527
  });
4533
- };
4534
- const useLegacyWorkflow = (workflowId) => {
4535
- const [legacyWorkflow, setLegacyWorkflow] = useState(null);
4536
- const [isLoading, setIsLoading] = useState(true);
4537
- const client = useMastraClient();
4538
- useEffect(() => {
4539
- const fetchWorkflow = async () => {
4540
- setIsLoading(true);
4541
- try {
4542
- if (!workflowId) {
4543
- setLegacyWorkflow(null);
4544
- setIsLoading(false);
4545
- return;
4546
- }
4547
- const { runtimeContext } = usePlaygroundStore.getState();
4548
- const res = await client.getLegacyWorkflow(workflowId).details(runtimeContext);
4549
- if (!res) {
4550
- setLegacyWorkflow(null);
4551
- console.error("Error fetching legacy workflow");
4552
- toast.error("Error fetching legacy workflow");
4553
- return;
4554
- }
4555
- const steps = res.steps;
4556
- const stepsWithWorkflow = await Promise.all(
4557
- Object.values(steps)?.map(async (step) => {
4558
- if (!step.workflowId) return step;
4559
- const wFlow = await client.getLegacyWorkflow(step.workflowId).details(runtimeContext);
4560
- if (!wFlow) return step;
4561
- return { ...step, stepGraph: wFlow.stepGraph, stepSubscriberGraph: wFlow.stepSubscriberGraph };
4562
- })
4563
- );
4564
- const _steps = stepsWithWorkflow.reduce((acc, b) => {
4565
- return { ...acc, [b.id]: b };
4566
- }, {});
4567
- setLegacyWorkflow({ ...res, steps: _steps });
4568
- } catch (error) {
4569
- setLegacyWorkflow(null);
4570
- console.error("Error fetching legacy workflow", error);
4571
- toast.error("Error fetching legacy workflow");
4572
- } finally {
4573
- setIsLoading(false);
4574
- }
4575
- };
4576
- fetchWorkflow();
4577
- }, [workflowId]);
4578
- return { legacyWorkflow, isLoading };
4579
- };
4580
- const useExecuteWorkflow = () => {
4581
- const client = useMastraClient();
4582
- const createLegacyWorkflowRun = async ({ workflowId, prevRunId }) => {
4583
- try {
4584
- const workflow = client.getLegacyWorkflow(workflowId);
4585
- const { runId: newRunId } = await workflow.createRun({ runId: prevRunId });
4586
- return { runId: newRunId };
4587
- } catch (error) {
4588
- console.error("Error creating workflow run:", error);
4589
- throw error;
4590
- }
4591
- };
4592
- const startLegacyWorkflowRun = async ({
4593
- workflowId,
4594
- runId,
4595
- input
4596
- }) => {
4597
- try {
4598
- const workflow = client.getLegacyWorkflow(workflowId);
4599
- await workflow.start({ runId, triggerData: input || {} });
4600
- } catch (error) {
4601
- console.error("Error starting workflow run:", error);
4602
- throw error;
4603
- }
4604
- };
4605
- return {
4606
- startLegacyWorkflowRun,
4607
- createLegacyWorkflowRun
4608
- };
4609
- };
4610
- const useWatchWorkflow = () => {
4611
- const [isWatchingLegacyWorkflow, setIsWatchingLegacyWorkflow] = useState(false);
4612
- const [legacyWatchResult, setLegacyWatchResult] = useState(null);
4613
- const client = useMastraClient();
4614
- const debouncedSetLegacyWorkflowWatchResult = useDebouncedCallback((record) => {
4615
- const formattedResults = Object.entries(record.results || {}).reduce(
4616
- (acc, [key, value]) => {
4617
- let output = value.status === "success" ? value.output : void 0;
4618
- if (output) {
4619
- output = Object.entries(output).reduce(
4620
- (_acc, [_key, _value]) => {
4621
- const val = _value;
4622
- _acc[_key] = val.type?.toLowerCase() === "buffer" ? { type: "Buffer", data: `[...buffered data]` } : val;
4623
- return _acc;
4624
- },
4625
- {}
4626
- );
4627
- }
4628
- acc[key] = { ...value, output };
4629
- return acc;
4630
- },
4631
- {}
4632
- );
4633
- const sanitizedRecord = {
4634
- ...record,
4635
- sanitizedOutput: record ? JSON.stringify({ ...record, results: formattedResults }, null, 2).slice(0, 5e4) : null
4636
- };
4637
- setLegacyWatchResult(sanitizedRecord);
4638
- }, 100);
4639
- const watchLegacyWorkflow = async ({ workflowId, runId }) => {
4640
- try {
4641
- setIsWatchingLegacyWorkflow(true);
4642
- const workflow = client.getLegacyWorkflow(workflowId);
4643
- await workflow.watch({ runId }, (record) => {
4644
- try {
4645
- debouncedSetLegacyWorkflowWatchResult(record);
4646
- } catch (err) {
4647
- console.error("Error processing workflow record:", err);
4648
- setLegacyWatchResult({
4649
- ...record
4650
- });
4651
- }
4652
- });
4653
- } catch (error) {
4654
- console.error("Error watching workflow:", error);
4655
- throw error;
4656
- } finally {
4657
- setIsWatchingLegacyWorkflow(false);
4658
- }
4659
- };
4660
- return {
4661
- watchLegacyWorkflow,
4662
- isWatchingLegacyWorkflow,
4663
- legacyWatchResult
4664
- };
4665
- };
4666
- const useResumeWorkflow = () => {
4667
- const [isResumingLegacyWorkflow, setIsResumingLegacyWorkflow] = useState(false);
4668
- const client = useMastraClient();
4669
- const resumeLegacyWorkflow = async ({
4670
- workflowId,
4671
- stepId,
4672
- runId,
4673
- context
4674
- }) => {
4675
- try {
4676
- setIsResumingLegacyWorkflow(true);
4677
- const response = await client.getLegacyWorkflow(workflowId).resume({ stepId, runId, context });
4678
- return response;
4679
- } catch (error) {
4680
- console.error("Error resuming workflow:", error);
4681
- throw error;
4682
- } finally {
4683
- setIsResumingLegacyWorkflow(false);
4684
- }
4685
- };
4528
+ const status = determineWorkflowStatus(steps);
4686
4529
  return {
4687
- resumeLegacyWorkflow,
4688
- isResumingLegacyWorkflow
4689
- };
4690
- };
4691
-
4692
- function extractConditions(group, type) {
4693
- let result = [];
4694
- if (!group) return result;
4695
- function recurse(group2, conj) {
4696
- if (typeof group2 === "string") {
4697
- result.push({ type, fnString: group2 });
4698
- } else {
4699
- const simpleCondition = Object.entries(group2).find(([key]) => key.includes("."));
4700
- if (simpleCondition) {
4701
- const [key, queryValue] = simpleCondition;
4702
- const [stepId, ...pathParts] = key.split(".");
4703
- const ref = {
4704
- step: {
4705
- id: stepId
4706
- },
4707
- path: pathParts.join(".")
4708
- };
4709
- result.push({
4710
- type,
4711
- ref,
4712
- query: { [queryValue === true || queryValue === false ? "is" : "eq"]: String(queryValue) },
4713
- conj
4714
- });
4715
- }
4716
- if ("ref" in group2) {
4717
- const { ref, query } = group2;
4718
- result.push({ type, ref, query, conj });
4719
- }
4720
- if ("and" in group2) {
4721
- for (const subGroup of group2.and) {
4722
- recurse({ ...subGroup }, "and");
4723
- }
4724
- }
4725
- if ("or" in group2) {
4726
- for (const subGroup of group2.or) {
4727
- recurse({ ...subGroup }, "or");
4728
- }
4729
- }
4730
- if ("not" in group2) {
4731
- recurse({ ...group2.not }, "not");
4530
+ type: "watch",
4531
+ payload: {
4532
+ workflowState: {
4533
+ status,
4534
+ steps,
4535
+ result: runState.value,
4536
+ payload: context.input,
4537
+ error: void 0
4732
4538
  }
4733
- }
4734
- }
4735
- recurse(group);
4736
- return result.reverse();
4737
- }
4738
- const getLayoutedElements = (nodes, edges) => {
4739
- const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
4740
- g.setGraph({ rankdir: "TB" });
4741
- edges.forEach((edge) => g.setEdge(edge.source, edge.target));
4742
- nodes.forEach(
4743
- (node) => g.setNode(node.id, {
4744
- ...node,
4745
- width: node.measured?.width ?? 274,
4746
- height: node.measured?.height ?? (node?.data?.isLarge ? 260 : 100)
4747
- })
4748
- );
4749
- Dagre.layout(g);
4750
- const fullWidth = g.graph()?.width ? g.graph().width / 2 : 0;
4751
- const fullHeight = g.graph()?.height ? g.graph().height / 2 : 0;
4752
- return {
4753
- nodes: nodes.map((node) => {
4754
- const position = g.node(node.id);
4755
- const positionX = position.x - (node.measured?.width ?? 274) / 2;
4756
- const positionY = position.y - (node.measured?.height ?? (node?.data?.isLarge ? 260 : 100)) / 2;
4757
- const x = positionX;
4758
- const y = positionY;
4759
- return { ...node, position: { x, y } };
4760
- }),
4761
- edges,
4762
- fullWidth,
4763
- fullHeight
4539
+ },
4540
+ eventTimestamp: new Date(runState.timestamp),
4541
+ runId
4764
4542
  };
4765
- };
4766
- const defaultEdgeOptions = {
4767
- animated: true,
4768
- markerEnd: {
4769
- type: MarkerType.ArrowClosed,
4770
- width: 20,
4771
- height: 20,
4772
- color: "#8e8e8e"
4543
+ }
4544
+ function determineWorkflowStatus(steps) {
4545
+ const stepStatuses = Object.values(steps).map((step) => step.status);
4546
+ if (stepStatuses.includes("failed")) {
4547
+ return "failed";
4773
4548
  }
4774
- };
4775
- const contructLegacyNodesAndEdges = ({
4776
- stepGraph,
4777
- stepSubscriberGraph,
4778
- steps: mainSteps = {}
4779
- }) => {
4780
- if (!stepGraph) {
4781
- return { nodes: [], edges: [] };
4549
+ if (stepStatuses.includes("suspended")) {
4550
+ return "suspended";
4782
4551
  }
4783
- const { initial, ...stepsList } = stepGraph;
4784
- if (!initial.length) {
4785
- return { nodes: [], edges: [] };
4552
+ if (stepStatuses.every((status) => status === "success")) {
4553
+ return "success";
4786
4554
  }
4787
- let nodes = [];
4788
- let edges = [];
4789
- let allSteps = [];
4790
- for (const [_index, _step] of initial.entries()) {
4791
- const step = _step.step;
4792
- const stepId = step.id;
4793
- const steps = [_step, ...stepsList?.[stepId] || []]?.reduce((acc, step2, i) => {
4794
- const { stepGraph: stepWflowGraph, stepSubscriberGraph: stepWflowSubscriberGraph } = mainSteps[step2.step.id] || {};
4795
- const hasGraph = !!stepWflowGraph;
4796
- const nodeId = nodes.some((node) => node.id === step2.step.id) ? `${step2.step.id}-${i}` : step2.step.id;
4797
- let newStep = {
4798
- ...step2.step,
4799
- label: step2.step.id,
4800
- originalId: step2.step.id,
4801
- type: hasGraph ? "nested-node" : "default-node",
4802
- id: nodeId,
4803
- stepGraph: stepWflowGraph,
4804
- stepSubscriberGraph: stepWflowSubscriberGraph
4805
- };
4806
- let conditionType = "when";
4807
- if (step2.config?.serializedWhen) {
4808
- conditionType = step2.step.id?.endsWith("_if") ? "if" : step2.step.id?.endsWith("_else") ? "else" : "when";
4809
- const conditions = extractConditions(step2.config.serializedWhen, conditionType);
4810
- const conditionStep = {
4811
- id: crypto.randomUUID(),
4812
- conditions,
4813
- type: "condition-node",
4814
- isLarge: (conditions?.length > 1 || conditions.some(({ fnString }) => !!fnString)) && conditionType !== "else"
4815
- };
4816
- acc.push(conditionStep);
4817
- }
4818
- if (conditionType === "if" || conditionType === "else") {
4819
- newStep = {
4820
- ...newStep,
4821
- label: conditionType === "if" ? "start if" : "start else"
4822
- };
4823
- }
4824
- newStep = {
4825
- ...newStep,
4826
- label: step2.config?.loopLabel || newStep.label
4827
- };
4828
- acc.push(newStep);
4829
- return acc;
4830
- }, []);
4831
- allSteps = [...allSteps, ...steps];
4832
- const newNodes = [...steps].map((step2, index) => {
4833
- const subscriberGraph = stepSubscriberGraph?.[step2.id];
4834
- return {
4835
- id: step2.id,
4836
- position: { x: _index * 300, y: index * 100 },
4837
- type: step2.type,
4838
- data: {
4839
- conditions: step2.conditions,
4840
- label: step2.label,
4841
- description: step2.description,
4842
- withoutTopHandle: subscriberGraph?.[step2.id] ? false : index === 0,
4843
- withoutBottomHandle: subscriberGraph ? false : index === steps.length - 1,
4844
- isLarge: step2.isLarge,
4845
- stepGraph: step2.stepGraph,
4846
- stepSubscriberGraph: step2.stepSubscriberGraph
4555
+ return "running";
4556
+ }
4557
+ const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
4558
+ if (chunk.type === "workflow-start") {
4559
+ return {
4560
+ ...prev,
4561
+ runId: chunk.runId,
4562
+ eventTimestamp: /* @__PURE__ */ new Date(),
4563
+ payload: {
4564
+ ...prev?.payload || {},
4565
+ workflowState: {
4566
+ ...prev?.payload?.workflowState,
4567
+ status: "running",
4568
+ steps: {}
4847
4569
  }
4848
- };
4849
- });
4850
- nodes = [...nodes, ...newNodes];
4851
- const edgeSteps = [...steps].slice(0, -1);
4852
- const newEdges = edgeSteps.map((step2, index) => ({
4853
- id: `e${step2.id}-${steps[index + 1].id}`,
4854
- source: step2.id,
4855
- target: steps[index + 1].id,
4856
- ...defaultEdgeOptions
4857
- }));
4858
- edges = [...edges, ...newEdges];
4859
- }
4860
- if (!stepSubscriberGraph || !Object.keys(stepSubscriberGraph).length) {
4861
- const { nodes: layoutedNodes2, edges: layoutedEdges2 } = getLayoutedElements(nodes, edges);
4862
- return { nodes: layoutedNodes2, edges: layoutedEdges2 };
4570
+ }
4571
+ };
4863
4572
  }
4864
- for (const [connectingStepId, stepInfoGraph] of Object.entries(stepSubscriberGraph)) {
4865
- const { initial: initial2, ...stepsList2 } = stepInfoGraph;
4866
- let untilOrWhileConditionId;
4867
- const loopResultSteps = [];
4868
- let finishedLoopStep;
4869
- let otherLoopStep;
4870
- if (initial2.length) {
4871
- for (const [_index, _step] of initial2.entries()) {
4872
- const step = _step.step;
4873
- const stepId = step.id;
4874
- const steps = [_step, ...stepsList2?.[stepId] || []]?.reduce((acc, step2, i) => {
4875
- const { stepGraph: stepWflowGraph, stepSubscriberGraph: stepWflowSubscriberGraph } = mainSteps[step2.step.id] || {};
4876
- const hasGraph = !!stepWflowGraph;
4877
- const nodeId = nodes.some((node) => node.id === step2.step.id) ? `${step2.step.id}-${i}` : step2.step.id;
4878
- let newStep = {
4879
- ...step2.step,
4880
- originalId: step2.step.id,
4881
- label: step2.step.id,
4882
- type: hasGraph ? "nested-node" : "default-node",
4883
- id: nodeId,
4884
- stepGraph: stepWflowGraph,
4885
- stepSubscriberGraph: stepWflowSubscriberGraph
4886
- };
4887
- let conditionType = "when";
4888
- const isFinishedLoop = step2.config?.loopLabel?.endsWith("loop finished");
4889
- if (step2.config?.serializedWhen && !isFinishedLoop) {
4890
- conditionType = step2.step.id?.endsWith("_if") ? "if" : step2.step.id?.endsWith("_else") ? "else" : step2.config?.loopType ?? "when";
4891
- const conditions = extractConditions(step2.config.serializedWhen, conditionType);
4892
- const conditionStep = {
4893
- id: crypto.randomUUID(),
4894
- conditions,
4895
- type: "condition-node",
4896
- isLarge: (conditions?.length > 1 || conditions.some(({ fnString }) => !!fnString)) && conditionType !== "else"
4897
- };
4898
- if (conditionType === "until" || conditionType === "while") {
4899
- untilOrWhileConditionId = conditionStep.id;
4573
+ if (chunk.type === "workflow-step-start") {
4574
+ const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
4575
+ return {
4576
+ ...prev,
4577
+ payload: {
4578
+ ...prev.payload,
4579
+ currentStep: {
4580
+ id: chunk.payload.id,
4581
+ ...chunk.payload
4582
+ },
4583
+ workflowState: {
4584
+ ...prev?.payload?.workflowState,
4585
+ steps: {
4586
+ ...prev?.payload?.workflowState?.steps,
4587
+ [chunk.payload.id]: {
4588
+ ...current || {},
4589
+ ...chunk.payload
4900
4590
  }
4901
- acc.push(conditionStep);
4902
- }
4903
- if (isFinishedLoop) {
4904
- const loopResultStep = {
4905
- id: crypto.randomUUID(),
4906
- type: "loop-result-node",
4907
- loopType: "finished",
4908
- loopResult: step2.config.loopType === "until" ? true : false
4909
- };
4910
- loopResultSteps.push(loopResultStep);
4911
- acc.push(loopResultStep);
4912
- }
4913
- if (!isFinishedLoop && step2.config?.loopType) {
4914
- const loopResultStep = {
4915
- id: crypto.randomUUID(),
4916
- type: "loop-result-node",
4917
- loopType: step2.config.loopType,
4918
- loopResult: step2.config.loopType === "until" ? false : true
4919
- };
4920
- loopResultSteps.push(loopResultStep);
4921
- acc.push(loopResultStep);
4922
4591
  }
4923
- if (conditionType === "if" || conditionType === "else") {
4924
- newStep = {
4925
- ...newStep,
4926
- label: conditionType === "if" ? "start if" : "start else"
4927
- };
4928
- }
4929
- if (step2.config.loopType) {
4930
- if (isFinishedLoop) {
4931
- finishedLoopStep = newStep;
4932
- } else {
4933
- otherLoopStep = newStep;
4592
+ }
4593
+ },
4594
+ eventTimestamp: /* @__PURE__ */ new Date()
4595
+ };
4596
+ }
4597
+ if (chunk.type === "workflow-step-suspended") {
4598
+ const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
4599
+ return {
4600
+ ...prev,
4601
+ payload: {
4602
+ ...prev?.payload,
4603
+ currentStep: {
4604
+ id: chunk.payload.id,
4605
+ ...prev?.payload?.currentStep,
4606
+ ...chunk.payload
4607
+ },
4608
+ workflowState: {
4609
+ ...prev?.payload?.workflowState,
4610
+ status: "suspended",
4611
+ steps: {
4612
+ ...prev?.payload?.workflowState?.steps,
4613
+ [chunk.payload.id]: {
4614
+ ...current || {},
4615
+ ...chunk.payload
4934
4616
  }
4935
4617
  }
4936
- newStep = {
4937
- ...newStep,
4938
- loopType: isFinishedLoop ? "finished" : step2.config.loopType,
4939
- label: step2.config?.loopLabel || newStep.label
4940
- };
4941
- acc.push(newStep);
4942
- return acc;
4943
- }, []);
4944
- let afterStep = [];
4945
- let afterStepStepList = connectingStepId?.includes("&&") ? connectingStepId.split("&&") : [];
4946
- if (connectingStepId?.includes("&&")) {
4947
- afterStep = [
4948
- {
4949
- id: connectingStepId,
4950
- label: connectingStepId,
4951
- type: "after-node",
4952
- steps: afterStepStepList
4953
- }
4954
- ];
4955
4618
  }
4956
- const newNodes = [...steps, ...afterStep].map((step2, index) => {
4957
- const subscriberGraph = stepSubscriberGraph?.[step2.id];
4958
- const withBottomHandle = step2.originalId === connectingStepId || subscriberGraph;
4959
- return {
4960
- id: step2.id,
4961
- position: { x: _index * 300 + 300, y: index * 100 + 100 },
4962
- type: step2.type,
4963
- data: {
4964
- conditions: step2.conditions,
4965
- label: step2.label,
4966
- description: step2.description,
4967
- result: step2.loopResult,
4968
- loopType: step2.loopType,
4969
- steps: step2.steps,
4970
- withoutBottomHandle: withBottomHandle ? false : index === steps.length - 1,
4971
- isLarge: step2.isLarge,
4972
- stepGraph: step2.stepGraph,
4973
- stepSubscriberGraph: step2.stepSubscriberGraph
4619
+ },
4620
+ eventTimestamp: /* @__PURE__ */ new Date()
4621
+ };
4622
+ }
4623
+ if (chunk.type === "workflow-step-waiting") {
4624
+ const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
4625
+ return {
4626
+ ...prev,
4627
+ payload: {
4628
+ ...prev?.payload,
4629
+ currentStep: {
4630
+ id: chunk.payload.id,
4631
+ ...prev?.payload?.currentStep || {},
4632
+ ...chunk.payload
4633
+ },
4634
+ workflowState: {
4635
+ ...prev?.payload?.workflowState,
4636
+ status: "waiting",
4637
+ steps: {
4638
+ ...prev?.payload?.workflowState?.steps,
4639
+ [chunk.payload.id]: {
4640
+ ...current,
4641
+ ...chunk.payload
4974
4642
  }
4975
- };
4976
- });
4977
- nodes = [...nodes, ...newNodes].map((node) => ({
4978
- ...node,
4979
- data: {
4980
- ...node.data,
4981
- withoutBottomHandle: afterStepStepList.includes(node.id) ? false : node.data.withoutBottomHandle
4982
- }
4983
- }));
4984
- const edgeSteps = [...steps].slice(0, -1);
4985
- const firstEdgeStep = steps[0];
4986
- const lastEdgeStep = steps[steps.length - 1];
4987
- const afterEdges = afterStepStepList?.map((step2) => ({
4988
- id: `e${step2}-${connectingStepId}`,
4989
- source: step2,
4990
- target: connectingStepId,
4991
- ...defaultEdgeOptions
4992
- }));
4993
- const finishedLoopResult = loopResultSteps?.find((step2) => step2.loopType === "finished");
4994
- const newEdges = edgeSteps.map((step2, index) => ({
4995
- id: `e${step2.id}-${steps[index + 1].id}`,
4996
- source: step2.id,
4997
- target: steps[index + 1].id,
4998
- remove: finishedLoopResult?.id === steps[index + 1].id,
4999
- //remove if target is a finished loop result
5000
- ...defaultEdgeOptions
5001
- }))?.filter((edge) => !edge.remove);
5002
- const connectingEdge = connectingStepId === firstEdgeStep.id ? [] : [
5003
- {
5004
- id: `e${connectingStepId}-${firstEdgeStep.id}`,
5005
- source: connectingStepId,
5006
- target: firstEdgeStep.id,
5007
- remove: finishedLoopResult?.id === firstEdgeStep.id,
5008
- ...defaultEdgeOptions
5009
4643
  }
5010
- ]?.filter((edge) => !edge.remove);
5011
- const lastEdge = lastEdgeStep.originalId === connectingStepId ? [
5012
- {
5013
- id: `e${lastEdgeStep.id}-${connectingStepId}`,
5014
- source: lastEdgeStep.id,
5015
- target: connectingStepId,
5016
- ...defaultEdgeOptions
4644
+ }
4645
+ },
4646
+ eventTimestamp: /* @__PURE__ */ new Date()
4647
+ };
4648
+ }
4649
+ if (chunk.type === "workflow-step-result") {
4650
+ const status = chunk.payload.status;
4651
+ const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
4652
+ const next = {
4653
+ ...prev,
4654
+ payload: {
4655
+ ...prev?.payload,
4656
+ currentStep: {
4657
+ id: chunk.payload.id,
4658
+ ...prev?.payload?.currentStep || {},
4659
+ ...chunk.payload
4660
+ },
4661
+ workflowState: {
4662
+ ...prev?.payload?.workflowState,
4663
+ status,
4664
+ steps: {
4665
+ ...prev?.payload?.workflowState?.steps,
4666
+ [chunk.payload.id]: {
4667
+ ...current,
4668
+ ...chunk.payload
4669
+ }
5017
4670
  }
5018
- ] : [];
5019
- edges = [...edges, ...afterEdges, ...connectingEdge, ...newEdges, ...lastEdge];
5020
- allSteps = [...allSteps, ...steps];
5021
- }
5022
- if (untilOrWhileConditionId && loopResultSteps.length && finishedLoopStep && otherLoopStep) {
5023
- const loopResultStepsEdges = loopResultSteps.map((step) => ({
5024
- id: `e${untilOrWhileConditionId}-${step.id}`,
5025
- source: untilOrWhileConditionId,
5026
- target: step.id,
5027
- ...defaultEdgeOptions
5028
- }));
5029
- const finishedLoopResult = loopResultSteps?.find((res) => res.loopType === "finished");
5030
- const otherLoopResult = loopResultSteps?.find((res) => res.loopType !== "finished");
5031
- const otherLoopEdge = {
5032
- id: `e${otherLoopResult?.id}-${otherLoopStep?.id}`,
5033
- source: otherLoopResult?.id,
5034
- target: otherLoopStep.id,
5035
- ...defaultEdgeOptions
5036
- };
5037
- const finishedLoopEdge = {
5038
- id: `e${finishedLoopResult?.id}-${finishedLoopStep?.id}`,
5039
- source: finishedLoopResult?.id,
5040
- target: finishedLoopStep.id,
5041
- ...defaultEdgeOptions
5042
- };
5043
- edges = [...edges, ...loopResultStepsEdges, otherLoopEdge, finishedLoopEdge];
5044
- }
4671
+ }
4672
+ },
4673
+ eventTimestamp: /* @__PURE__ */ new Date()
4674
+ };
4675
+ return next;
4676
+ }
4677
+ if (chunk.type === "workflow-canceled") {
4678
+ return {
4679
+ ...prev,
4680
+ payload: {
4681
+ ...prev?.payload,
4682
+ workflowState: {
4683
+ ...prev?.payload?.workflowState,
4684
+ status: "canceled"
4685
+ }
4686
+ },
4687
+ eventTimestamp: /* @__PURE__ */ new Date()
4688
+ };
4689
+ }
4690
+ if (chunk.type === "workflow-finish") {
4691
+ return {
4692
+ ...prev,
4693
+ payload: {
4694
+ ...prev?.payload,
4695
+ currentStep: void 0,
4696
+ workflowState: {
4697
+ ...prev?.payload?.workflowState,
4698
+ status: chunk.payload.workflowStatus
4699
+ }
4700
+ },
4701
+ eventTimestamp: /* @__PURE__ */ new Date()
4702
+ };
4703
+ }
4704
+ return prev;
4705
+ };
4706
+
4707
+ const WorkflowRunContext = createContext({});
4708
+ function WorkflowRunProvider({
4709
+ children,
4710
+ snapshot
4711
+ }) {
4712
+ const [result, setResult] = useState(
4713
+ () => snapshot ? convertWorkflowRunStateToWatchResult(snapshot) : null
4714
+ );
4715
+ const [payload, setPayload] = useState(null);
4716
+ const clearData = () => {
4717
+ setResult(null);
4718
+ setPayload(null);
4719
+ };
4720
+ useEffect(() => {
4721
+ if (snapshot?.runId) {
4722
+ setResult(convertWorkflowRunStateToWatchResult(snapshot));
4723
+ }
4724
+ }, [snapshot]);
4725
+ return /* @__PURE__ */ jsx(
4726
+ WorkflowRunContext.Provider,
4727
+ {
4728
+ value: {
4729
+ result,
4730
+ setResult,
4731
+ payload,
4732
+ setPayload,
4733
+ clearData,
4734
+ snapshot
4735
+ },
4736
+ children
5045
4737
  }
4738
+ );
4739
+ }
4740
+
4741
+ function Skeleton({ className, ...props }) {
4742
+ return /* @__PURE__ */ jsx("div", { className: cn("animate-pulse rounded-md bg-muted/50", className), ...props });
4743
+ }
4744
+
4745
+ const lodashTitleCase = (str) => {
4746
+ const camelCased = str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^(.)/, (char) => char.toLowerCase());
4747
+ return camelCased.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).trim();
4748
+ };
4749
+
4750
+ const getLayoutedElements = (nodes, edges) => {
4751
+ const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
4752
+ g.setGraph({ rankdir: "TB" });
4753
+ edges.forEach((edge) => g.setEdge(edge.source, edge.target));
4754
+ nodes.forEach(
4755
+ (node) => g.setNode(node.id, {
4756
+ ...node,
4757
+ width: node.measured?.width ?? 274,
4758
+ height: node.measured?.height ?? (node?.data?.isLarge ? 260 : 100)
4759
+ })
4760
+ );
4761
+ Dagre.layout(g);
4762
+ const fullWidth = g.graph()?.width ? g.graph().width / 2 : 0;
4763
+ const fullHeight = g.graph()?.height ? g.graph().height / 2 : 0;
4764
+ return {
4765
+ nodes: nodes.map((node) => {
4766
+ const position = g.node(node.id);
4767
+ const positionX = position.x - (node.measured?.width ?? 274) / 2;
4768
+ const positionY = position.y - (node.measured?.height ?? (node?.data?.isLarge ? 260 : 100)) / 2;
4769
+ const x = positionX;
4770
+ const y = positionY;
4771
+ return { ...node, position: { x, y } };
4772
+ }),
4773
+ edges,
4774
+ fullWidth,
4775
+ fullHeight
4776
+ };
4777
+ };
4778
+ const defaultEdgeOptions = {
4779
+ animated: true,
4780
+ markerEnd: {
4781
+ type: MarkerType.ArrowClosed,
4782
+ width: 20,
4783
+ height: 20,
4784
+ color: "#8e8e8e"
5046
4785
  }
5047
- const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges);
5048
- return { nodes: layoutedNodes, edges: layoutedEdges };
5049
4786
  };
5050
4787
  const getStepNodeAndEdge = ({
5051
4788
  stepFlow,
@@ -5483,257 +5220,20 @@ const ScrollBar = React.forwardRef(({ className, orientation = "vertical", ...pr
5483
5220
  ));
5484
5221
  ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
5485
5222
 
5486
- function convertWorkflowRunStateToWatchResult(runState) {
5487
- const runId = runState.runId;
5488
- const steps = {};
5489
- const context = runState.context || {};
5490
- Object.entries(context).forEach(([stepId, stepResult]) => {
5491
- if (stepId !== "input" && "status" in stepResult) {
5492
- const result = stepResult;
5493
- steps[stepId] = {
5494
- status: result.status,
5495
- output: "output" in result ? result.output : void 0,
5496
- payload: "payload" in result ? result.payload : void 0,
5497
- resumePayload: "resumePayload" in result ? result.resumePayload : void 0,
5498
- error: "error" in result ? result.error : void 0,
5499
- startedAt: "startedAt" in result ? result.startedAt : Date.now(),
5500
- endedAt: "endedAt" in result ? result.endedAt : void 0,
5501
- suspendedAt: "suspendedAt" in result ? result.suspendedAt : void 0,
5502
- resumedAt: "resumedAt" in result ? result.resumedAt : void 0
5503
- };
5504
- }
5505
- });
5506
- const status = determineWorkflowStatus(steps);
5507
- return {
5508
- type: "watch",
5509
- payload: {
5510
- workflowState: {
5511
- status,
5512
- steps,
5513
- result: runState.value,
5514
- payload: context.input,
5515
- error: void 0
5516
- }
5517
- },
5518
- eventTimestamp: new Date(runState.timestamp),
5519
- runId
5520
- };
5521
- }
5522
- function determineWorkflowStatus(steps) {
5523
- const stepStatuses = Object.values(steps).map((step) => step.status);
5524
- if (stepStatuses.includes("failed")) {
5525
- return "failed";
5526
- }
5527
- if (stepStatuses.includes("suspended")) {
5528
- return "suspended";
5529
- }
5530
- if (stepStatuses.every((status) => status === "success")) {
5531
- return "success";
5532
- }
5533
- return "running";
5534
- }
5535
- const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
5536
- if (chunk.type === "workflow-start") {
5537
- return {
5538
- ...prev,
5539
- runId: chunk.runId,
5540
- eventTimestamp: /* @__PURE__ */ new Date(),
5541
- payload: {
5542
- ...prev?.payload || {},
5543
- workflowState: {
5544
- ...prev?.payload?.workflowState,
5545
- status: "running",
5546
- steps: {}
5547
- }
5548
- }
5549
- };
5550
- }
5551
- if (chunk.type === "workflow-step-start") {
5552
- const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
5553
- return {
5554
- ...prev,
5555
- payload: {
5556
- ...prev.payload,
5557
- currentStep: {
5558
- id: chunk.payload.id,
5559
- ...chunk.payload
5560
- },
5561
- workflowState: {
5562
- ...prev?.payload?.workflowState,
5563
- steps: {
5564
- ...prev?.payload?.workflowState?.steps,
5565
- [chunk.payload.id]: {
5566
- ...current || {},
5567
- ...chunk.payload
5568
- }
5569
- }
5570
- }
5571
- },
5572
- eventTimestamp: /* @__PURE__ */ new Date()
5573
- };
5574
- }
5575
- if (chunk.type === "workflow-step-suspended") {
5576
- const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
5577
- return {
5578
- ...prev,
5579
- payload: {
5580
- ...prev?.payload,
5581
- currentStep: {
5582
- id: chunk.payload.id,
5583
- ...prev?.payload?.currentStep,
5584
- ...chunk.payload
5585
- },
5586
- workflowState: {
5587
- ...prev?.payload?.workflowState,
5588
- status: "suspended",
5589
- steps: {
5590
- ...prev?.payload?.workflowState?.steps,
5591
- [chunk.payload.id]: {
5592
- ...current || {},
5593
- ...chunk.payload
5594
- }
5595
- }
5596
- }
5597
- },
5598
- eventTimestamp: /* @__PURE__ */ new Date()
5599
- };
5600
- }
5601
- if (chunk.type === "workflow-step-waiting") {
5602
- const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
5603
- return {
5604
- ...prev,
5605
- payload: {
5606
- ...prev?.payload,
5607
- currentStep: {
5608
- id: chunk.payload.id,
5609
- ...prev?.payload?.currentStep || {},
5610
- ...chunk.payload
5611
- },
5612
- workflowState: {
5613
- ...prev?.payload?.workflowState,
5614
- status: "waiting",
5615
- steps: {
5616
- ...prev?.payload?.workflowState?.steps,
5617
- [chunk.payload.id]: {
5618
- ...current,
5619
- ...chunk.payload
5620
- }
5621
- }
5622
- }
5623
- },
5624
- eventTimestamp: /* @__PURE__ */ new Date()
5625
- };
5626
- }
5627
- if (chunk.type === "workflow-step-result") {
5628
- const status = chunk.payload.status;
5629
- const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
5630
- const next = {
5631
- ...prev,
5632
- payload: {
5633
- ...prev?.payload,
5634
- currentStep: {
5635
- id: chunk.payload.id,
5636
- ...prev?.payload?.currentStep || {},
5637
- ...chunk.payload
5638
- },
5639
- workflowState: {
5640
- ...prev?.payload?.workflowState,
5641
- status,
5642
- steps: {
5643
- ...prev?.payload?.workflowState?.steps,
5644
- [chunk.payload.id]: {
5645
- ...current,
5646
- ...chunk.payload
5647
- }
5648
- }
5649
- }
5650
- },
5651
- eventTimestamp: /* @__PURE__ */ new Date()
5652
- };
5653
- return next;
5654
- }
5655
- if (chunk.type === "workflow-canceled") {
5656
- return {
5657
- ...prev,
5658
- payload: {
5659
- ...prev?.payload,
5660
- workflowState: {
5661
- ...prev?.payload?.workflowState,
5662
- status: "canceled"
5663
- }
5664
- },
5665
- eventTimestamp: /* @__PURE__ */ new Date()
5666
- };
5667
- }
5668
- if (chunk.type === "workflow-finish") {
5669
- return {
5670
- ...prev,
5671
- payload: {
5672
- ...prev?.payload,
5673
- currentStep: void 0,
5674
- workflowState: {
5675
- ...prev?.payload?.workflowState,
5676
- status: chunk.payload.workflowStatus
5677
- }
5678
- },
5679
- eventTimestamp: /* @__PURE__ */ new Date()
5680
- };
5681
- }
5682
- return prev;
5683
- };
5684
-
5685
- const WorkflowRunContext = createContext({});
5686
- function WorkflowRunProvider({
5687
- children,
5688
- snapshot
5689
- }) {
5690
- const [legacyResult, setLegacyResult] = useState(null);
5691
- const [result, setResult] = useState(
5692
- () => snapshot ? convertWorkflowRunStateToWatchResult(snapshot) : null
5693
- );
5694
- const [payload, setPayload] = useState(null);
5695
- const clearData = () => {
5696
- setLegacyResult(null);
5697
- setResult(null);
5698
- setPayload(null);
5699
- };
5700
- useEffect(() => {
5701
- if (snapshot?.runId) {
5702
- setResult(convertWorkflowRunStateToWatchResult(snapshot));
5703
- }
5704
- }, [snapshot]);
5705
- return /* @__PURE__ */ jsx(
5706
- WorkflowRunContext.Provider,
5707
- {
5708
- value: {
5709
- legacyResult,
5710
- setLegacyResult,
5711
- result,
5712
- setResult,
5713
- payload,
5714
- setPayload,
5715
- clearData,
5716
- snapshot
5717
- },
5718
- children
5719
- }
5720
- );
5721
- }
5722
-
5723
- const useCurrentRun = () => {
5724
- const context = useContext(WorkflowRunContext);
5725
- const workflowCurrentSteps = context.result?.payload?.workflowState?.steps ?? {};
5726
- const steps = Object.entries(workflowCurrentSteps).reduce((acc, [key, value]) => {
5727
- return {
5728
- ...acc,
5729
- [key]: {
5730
- error: value.error,
5731
- startedAt: value.startedAt,
5732
- endedAt: value.endedAt,
5733
- status: value.status,
5734
- output: value.output,
5735
- input: value.payload,
5736
- resumeData: value.resumePayload
5223
+ const useCurrentRun = () => {
5224
+ const context = useContext(WorkflowRunContext);
5225
+ const workflowCurrentSteps = context.result?.payload?.workflowState?.steps ?? {};
5226
+ const steps = Object.entries(workflowCurrentSteps).reduce((acc, [key, value]) => {
5227
+ return {
5228
+ ...acc,
5229
+ [key]: {
5230
+ error: value.error,
5231
+ startedAt: value.startedAt,
5232
+ endedAt: value.endedAt,
5233
+ status: value.status,
5234
+ output: value.output,
5235
+ input: value.payload,
5236
+ resumeData: value.resumePayload
5737
5237
  }
5738
5238
  };
5739
5239
  }, {});
@@ -6288,74 +5788,161 @@ function Spinner({ color = "#fff", className }) {
6288
5788
  );
6289
5789
  }
6290
5790
 
6291
- function LegacyWorkflowNestedGraph({
6292
- stepGraph,
6293
- stepSubscriberGraph,
6294
- open
6295
- }) {
6296
- const { nodes: initialNodes, edges: initialEdges } = contructLegacyNodesAndEdges({
6297
- stepGraph,
6298
- stepSubscriberGraph
6299
- });
6300
- const [isMounted, setIsMounted] = useState(false);
6301
- const [nodes, _, onNodesChange] = useNodesState(initialNodes);
6302
- const [edges] = useEdgesState(initialEdges);
6303
- const nodeTypes = {
6304
- "default-node": WorkflowDefaultNode,
6305
- "condition-node": WorkflowConditionNode,
6306
- "after-node": WorkflowAfterNode,
6307
- "loop-result-node": WorkflowLoopResultNode
6308
- };
6309
- useEffect(() => {
6310
- if (open) {
6311
- setTimeout(() => {
6312
- setIsMounted(true);
6313
- }, 500);
6314
- }
6315
- }, [open]);
6316
- return /* @__PURE__ */ jsx("div", { className: "w-full h-full relative", children: isMounted ? /* @__PURE__ */ jsxs(
6317
- ReactFlow,
6318
- {
6319
- nodes,
6320
- edges,
6321
- fitView: true,
6322
- fitViewOptions: { maxZoom: 0.85 },
6323
- nodeTypes,
6324
- onNodesChange,
6325
- children: [
6326
- /* @__PURE__ */ jsx(Controls, {}),
6327
- /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Lines, gap: 12, size: 0.5 })
6328
- ]
6329
- }
6330
- ) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, {}) }) });
6331
- }
6332
-
6333
- const LegacyWorkflowNestedGraphContext = createContext(
6334
- {}
6335
- );
6336
- function LegacyWorkflowNestedGraphProvider({ children }) {
6337
- const [stepGraph, setStepGraph] = useState(null);
6338
- const [stepSubscriberGraph, setStepSubscriberGraph] = useState(null);
6339
- const [openDialog, setOpenDialog] = useState(false);
6340
- const [label, setLabel] = useState("");
6341
- const closeNestedGraph = () => {
6342
- setOpenDialog(false);
6343
- setStepGraph(null);
6344
- setStepSubscriberGraph(null);
6345
- setLabel("");
6346
- };
6347
- const showNestedGraph = ({
6348
- label: label2,
6349
- stepGraph: stepGraph2,
6350
- stepSubscriberGraph: stepSubscriberGraph2
6351
- }) => {
6352
- setLabel(label2);
6353
- setStepGraph(stepGraph2);
6354
- setStepSubscriberGraph(stepSubscriberGraph2);
6355
- setOpenDialog(true);
5791
+ const Slider = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(
5792
+ SliderPrimitive.Root,
5793
+ {
5794
+ ref,
5795
+ className: cn("relative flex w-full touch-none select-none items-center", className),
5796
+ ...props,
5797
+ children: [
5798
+ /* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full bg-primary/50" }) }),
5799
+ /* @__PURE__ */ jsx(SliderPrimitive.Thumb, { className: "block h-4 w-4 rounded-full border border-primary/50 bg-white shadow transition-colors disabled:pointer-events-none disabled:opacity-50" })
5800
+ ]
5801
+ }
5802
+ ));
5803
+ Slider.displayName = SliderPrimitive.Root.displayName;
5804
+
5805
+ const ZoomSlider = forwardRef(({ className, ...props }) => {
5806
+ const { zoom } = useViewport();
5807
+ const { zoomTo, zoomIn, zoomOut, fitView } = useReactFlow();
5808
+ return /* @__PURE__ */ jsxs(Panel, { className: cn("flex gap-1 rounded-md bg-primary-foreground p-1 text-foreground", className), ...props, children: [
5809
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomOut({ duration: 300 }), children: /* @__PURE__ */ jsx(Minus, { className: "h-4 w-4" }) }),
5810
+ /* @__PURE__ */ jsx(
5811
+ Slider,
5812
+ {
5813
+ className: "w-[140px]",
5814
+ value: [zoom],
5815
+ min: 0.01,
5816
+ max: 1,
5817
+ step: 0.01,
5818
+ onValueChange: (values) => {
5819
+ zoomTo(values[0]);
5820
+ }
5821
+ }
5822
+ ),
5823
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomIn({ duration: 300 }), children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }) }),
5824
+ /* @__PURE__ */ jsxs(Button$2, { className: "min-w-20 tabular-nums", variant: "ghost", onClick: () => zoomTo(1, { duration: 300 }), children: [
5825
+ (100 * zoom).toFixed(0),
5826
+ "%"
5827
+ ] }),
5828
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => fitView({ duration: 300, maxZoom: 1 }), children: /* @__PURE__ */ jsx(Maximize, { className: "h-4 w-4" }) })
5829
+ ] });
5830
+ });
5831
+ ZoomSlider.displayName = "ZoomSlider";
5832
+
5833
+ function WorkflowNestedGraph({
5834
+ stepGraph,
5835
+ open,
5836
+ workflowName,
5837
+ onShowTrace,
5838
+ onSendEvent
5839
+ }) {
5840
+ const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
5841
+ stepGraph
5842
+ });
5843
+ const [isMounted, setIsMounted] = useState(false);
5844
+ const [nodes, _, onNodesChange] = useNodesState(initialNodes);
5845
+ const [edges] = useEdgesState(initialEdges);
5846
+ const { steps } = useCurrentRun();
5847
+ const nodeTypes = {
5848
+ "default-node": (props) => /* @__PURE__ */ jsx(
5849
+ WorkflowDefaultNode,
5850
+ {
5851
+ parentWorkflowName: workflowName,
5852
+ onShowTrace,
5853
+ onSendEvent,
5854
+ ...props
5855
+ }
5856
+ ),
5857
+ "condition-node": WorkflowConditionNode,
5858
+ "after-node": WorkflowAfterNode,
5859
+ "loop-result-node": WorkflowLoopResultNode,
5860
+ "nested-node": (props) => /* @__PURE__ */ jsx(
5861
+ WorkflowNestedNode,
5862
+ {
5863
+ parentWorkflowName: workflowName,
5864
+ onShowTrace,
5865
+ onSendEvent,
5866
+ ...props
5867
+ }
5868
+ )
5869
+ };
5870
+ useEffect(() => {
5871
+ if (open) {
5872
+ setTimeout(() => {
5873
+ setIsMounted(true);
5874
+ }, 500);
5875
+ }
5876
+ }, [open]);
5877
+ return /* @__PURE__ */ jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxs(
5878
+ ReactFlow,
5879
+ {
5880
+ nodes,
5881
+ edges: edges.map((e) => ({
5882
+ ...e,
5883
+ style: {
5884
+ ...e.style,
5885
+ stroke: steps[`${workflowName}.${e.data?.previousStepId}`]?.status === "success" && steps[`${workflowName}.${e.data?.nextStepId}`] ? "#22c55e" : e.data?.conditionNode && !steps[`${workflowName}.${e.data?.previousStepId}`] && Boolean(steps[`${workflowName}.${e.data?.nextStepId}`]?.status) ? "#22c55e" : void 0
5886
+ }
5887
+ })),
5888
+ fitView: true,
5889
+ fitViewOptions: {
5890
+ maxZoom: 1
5891
+ },
5892
+ minZoom: 0.01,
5893
+ maxZoom: 1,
5894
+ nodeTypes,
5895
+ onNodesChange,
5896
+ children: [
5897
+ /* @__PURE__ */ jsx(ZoomSlider, { position: "bottom-left" }),
5898
+ /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Lines, gap: 12, size: 0.5 })
5899
+ ]
5900
+ }
5901
+ ) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, {}) }) });
5902
+ }
5903
+
5904
+ const WorkflowNestedGraphContext = createContext(
5905
+ {}
5906
+ );
5907
+ function WorkflowNestedGraphProvider({
5908
+ children,
5909
+ onShowTrace,
5910
+ onSendEvent
5911
+ }) {
5912
+ const [stepGraph, setStepGraph] = useState(null);
5913
+ const [parentStepGraphList, setParentStepGraphList] = useState([]);
5914
+ const [openDialog, setOpenDialog] = useState(false);
5915
+ const [label, setLabel] = useState("");
5916
+ const [fullStep, setFullStep] = useState("");
5917
+ const closeNestedGraph = () => {
5918
+ if (parentStepGraphList.length) {
5919
+ const lastStepGraph = parentStepGraphList[parentStepGraphList.length - 1];
5920
+ setStepGraph(lastStepGraph.stepGraph);
5921
+ setLabel(lastStepGraph.label);
5922
+ setFullStep(lastStepGraph.fullStep);
5923
+ setParentStepGraphList(parentStepGraphList.slice(0, -1));
5924
+ } else {
5925
+ setOpenDialog(false);
5926
+ setStepGraph(null);
5927
+ setLabel("");
5928
+ setFullStep("");
5929
+ }
5930
+ };
5931
+ const showNestedGraph = ({
5932
+ label: newLabel,
5933
+ stepGraph: newStepGraph,
5934
+ fullStep: newFullStep
5935
+ }) => {
5936
+ if (stepGraph) {
5937
+ setParentStepGraphList([...parentStepGraphList, { stepGraph, label, fullStep }]);
5938
+ }
5939
+ setLabel(newLabel);
5940
+ setFullStep(newFullStep);
5941
+ setStepGraph(newStepGraph);
5942
+ setOpenDialog(true);
6356
5943
  };
6357
5944
  return /* @__PURE__ */ jsxs(
6358
- LegacyWorkflowNestedGraphContext.Provider,
5945
+ WorkflowNestedGraphContext.Provider,
6359
5946
  {
6360
5947
  value: {
6361
5948
  showNestedGraph,
@@ -6363,8 +5950,8 @@ function LegacyWorkflowNestedGraphProvider({ children }) {
6363
5950
  },
6364
5951
  children: [
6365
5952
  children,
6366
- /* @__PURE__ */ jsx(Dialog, { open: openDialog, onOpenChange: closeNestedGraph, children: /* @__PURE__ */ jsx(DialogPortal, { children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-[40rem] h-[40rem] bg-[#121212] p-[0.5rem]", children: [
6367
- /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-1.5 absolute top-2.5 left-2.5", children: [
5953
+ /* @__PURE__ */ jsx(Dialog, { open: openDialog, onOpenChange: closeNestedGraph, children: /* @__PURE__ */ jsx(DialogPortal, { children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-[45rem] h-[45rem] max-w-[unset] bg-[#121212] p-[0.5rem]", children: [
5954
+ /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-1.5 absolute top-3 left-3 z-50", children: [
6368
5955
  /* @__PURE__ */ jsx(Workflow, { className: "text-current w-4 h-4" }),
6369
5956
  /* @__PURE__ */ jsxs(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: [
6370
5957
  label,
@@ -6372,77 +5959,131 @@ function LegacyWorkflowNestedGraphProvider({ children }) {
6372
5959
  ] })
6373
5960
  ] }),
6374
5961
  /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(
6375
- LegacyWorkflowNestedGraph,
5962
+ WorkflowNestedGraph,
6376
5963
  {
6377
5964
  stepGraph,
6378
5965
  open: openDialog,
6379
- stepSubscriberGraph
5966
+ workflowName: fullStep,
5967
+ onShowTrace,
5968
+ onSendEvent
6380
5969
  }
6381
5970
  ) })
6382
- ] }) }) })
5971
+ ] }) }) }, `${label}-${fullStep}`)
6383
5972
  ]
6384
5973
  }
6385
5974
  );
6386
5975
  }
6387
5976
 
6388
- function LegacyWorkflowNestedNode({ data }) {
6389
- const { label, withoutTopHandle, withoutBottomHandle, stepGraph, stepSubscriberGraph } = data;
6390
- const { showNestedGraph } = useContext(LegacyWorkflowNestedGraphContext);
6391
- return /* @__PURE__ */ jsxs("div", { className: cn("bg-[rgba(29,29,29,0.5)] rounded-md h-full overflow-scroll w-[274px]"), children: [
5977
+ function WorkflowNestedNode({
5978
+ data,
5979
+ parentWorkflowName,
5980
+ onShowTrace,
5981
+ onSendEvent
5982
+ }) {
5983
+ const { steps, runId } = useCurrentRun();
5984
+ const { showNestedGraph } = useContext(WorkflowNestedGraphContext);
5985
+ const { label, description, withoutTopHandle, withoutBottomHandle, stepGraph, mapConfig, event } = data;
5986
+ const fullLabel = parentWorkflowName ? `${parentWorkflowName}.${label}` : label;
5987
+ const step = steps[fullLabel];
5988
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6392
5989
  !withoutTopHandle && /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Top, style: { visibility: "hidden" } }),
6393
- /* @__PURE__ */ jsx("div", { className: "p-2 cursor-pointer", onClick: () => showNestedGraph({ label, stepGraph, stepSubscriberGraph }), children: /* @__PURE__ */ jsxs("div", { className: "text-sm bg-mastra-bg-9 flex items-center gap-1.5 rounded-sm p-2 cursor-pointer", children: [
6394
- /* @__PURE__ */ jsx(Workflow, { className: "text-current w-4 h-4" }),
6395
- /* @__PURE__ */ jsx(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: label })
6396
- ] }) }),
5990
+ /* @__PURE__ */ jsxs(
5991
+ "div",
5992
+ {
5993
+ className: cn(
5994
+ "bg-surface3 rounded-lg w-[274px] border-sm border-border1 pt-2",
5995
+ step?.status === "success" && "bg-accent1Darker",
5996
+ step?.status === "failed" && "bg-accent2Darker",
5997
+ step?.status === "suspended" && "bg-accent3Darker",
5998
+ step?.status === "waiting" && "bg-accent5Darker",
5999
+ step?.status === "running" && "bg-accent6Darker"
6000
+ ),
6001
+ children: [
6002
+ /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2 px-3", !description && "pb-2"), children: [
6003
+ /* @__PURE__ */ jsxs(Icon, { children: [
6004
+ step?.status === "failed" && /* @__PURE__ */ jsx(CrossIcon, { className: "text-accent2" }),
6005
+ step?.status === "success" && /* @__PURE__ */ jsx(CheckIcon, { className: "text-accent1" }),
6006
+ step?.status === "suspended" && /* @__PURE__ */ jsx(PauseIcon, { className: "text-accent3" }),
6007
+ step?.status === "waiting" && /* @__PURE__ */ jsx(HourglassIcon, { className: "text-accent5" }),
6008
+ step?.status === "running" && /* @__PURE__ */ jsx(Loader2, { className: "text-accent6 animate-spin" }),
6009
+ !step && /* @__PURE__ */ jsx(CircleDashed, { className: "text-icon2" })
6010
+ ] }),
6011
+ /* @__PURE__ */ jsxs(Txt, { variant: "ui-lg", className: "text-icon6 font-medium inline-flex items-center gap-1 justify-between w-full", children: [
6012
+ label,
6013
+ " ",
6014
+ step?.startedAt && /* @__PURE__ */ jsx(Clock, { startedAt: step.startedAt, endedAt: step.endedAt })
6015
+ ] })
6016
+ ] }),
6017
+ description && /* @__PURE__ */ jsx(Txt, { variant: "ui-sm", className: "text-icon3 px-3 pb-2", children: description }),
6018
+ /* @__PURE__ */ jsx(
6019
+ WorkflowStepActionBar,
6020
+ {
6021
+ stepName: label,
6022
+ input: step?.input,
6023
+ resumeData: step?.resumeData,
6024
+ output: step?.output,
6025
+ error: step?.error,
6026
+ mapConfig,
6027
+ onShowTrace: runId && onShowTrace ? () => onShowTrace?.({ runId, stepName: fullLabel }) : void 0,
6028
+ onShowNestedGraph: () => showNestedGraph({ label, fullStep: fullLabel, stepGraph }),
6029
+ onSendEvent,
6030
+ event: step?.status === "waiting" ? event : void 0,
6031
+ runId,
6032
+ status: step?.status
6033
+ }
6034
+ )
6035
+ ]
6036
+ }
6037
+ ),
6397
6038
  !withoutBottomHandle && /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Bottom, style: { visibility: "hidden" } })
6398
6039
  ] });
6399
6040
  }
6400
6041
 
6401
- function LegacyWorkflowGraphInner({ workflow }) {
6402
- const { nodes: initialNodes, edges: initialEdges } = contructLegacyNodesAndEdges({
6403
- stepGraph: workflow.serializedStepGraph || workflow.stepGraph,
6404
- stepSubscriberGraph: workflow.serializedStepSubscriberGraph || workflow.stepSubscriberGraph,
6405
- steps: workflow.steps
6406
- });
6042
+ function WorkflowGraphInner({ workflow, onShowTrace, onSendEvent }) {
6043
+ const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges(workflow);
6407
6044
  const [nodes, _, onNodesChange] = useNodesState(initialNodes);
6408
6045
  const [edges] = useEdgesState(initialEdges);
6046
+ const { steps, runId } = useCurrentRun();
6409
6047
  const nodeTypes = {
6410
- "default-node": WorkflowDefaultNode,
6048
+ "default-node": (props) => /* @__PURE__ */ jsx(WorkflowDefaultNode, { onShowTrace, onSendEvent, ...props }),
6411
6049
  "condition-node": WorkflowConditionNode,
6412
6050
  "after-node": WorkflowAfterNode,
6413
6051
  "loop-result-node": WorkflowLoopResultNode,
6414
- "nested-node": LegacyWorkflowNestedNode
6052
+ "nested-node": (props) => /* @__PURE__ */ jsx(WorkflowNestedNode, { onShowTrace, onSendEvent, ...props })
6415
6053
  };
6416
- return /* @__PURE__ */ jsx("div", { className: "w-full h-full", children: /* @__PURE__ */ jsxs(
6054
+ return /* @__PURE__ */ jsx("div", { className: "w-full h-full bg-surface1", children: /* @__PURE__ */ jsxs(
6417
6055
  ReactFlow,
6418
6056
  {
6419
6057
  nodes,
6420
- edges,
6058
+ edges: edges.map((e) => ({
6059
+ ...e,
6060
+ style: {
6061
+ ...e.style,
6062
+ stroke: steps[e.data?.previousStepId]?.status === "success" && steps[e.data?.nextStepId] ? "#22c55e" : e.data?.conditionNode && !steps[e.data?.previousStepId] && Boolean(steps[e.data?.nextStepId]?.status) ? "#22c55e" : void 0
6063
+ }
6064
+ })),
6421
6065
  nodeTypes,
6422
6066
  onNodesChange,
6423
6067
  fitView: true,
6424
6068
  fitViewOptions: {
6425
- maxZoom: 0.85
6069
+ maxZoom: 1
6426
6070
  },
6071
+ minZoom: 0.01,
6072
+ maxZoom: 1,
6427
6073
  children: [
6428
- /* @__PURE__ */ jsx(Controls, {}),
6074
+ /* @__PURE__ */ jsx(ZoomSlider, { position: "bottom-left" }),
6429
6075
  /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Dots, gap: 12, size: 0.5 })
6430
6076
  ]
6431
6077
  }
6432
6078
  ) });
6433
6079
  }
6434
6080
 
6435
- const lodashTitleCase = (str) => {
6436
- const camelCased = str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^(.)/, (char) => char.toLowerCase());
6437
- return camelCased.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).trim();
6438
- };
6439
-
6440
- function LegacyWorkflowGraph({ workflowId }) {
6441
- const { legacyWorkflow, isLoading } = useLegacyWorkflow(workflowId);
6081
+ function WorkflowGraph({ workflowId, onShowTrace, workflow, isLoading, onSendEvent }) {
6082
+ const { snapshot } = useContext(WorkflowRunContext);
6442
6083
  if (isLoading) {
6443
- return /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[600px]" }) });
6084
+ return /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-full" }) });
6444
6085
  }
6445
- if (!legacyWorkflow) {
6086
+ if (!workflow) {
6446
6087
  return /* @__PURE__ */ jsx("div", { className: "grid h-full place-items-center", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
6447
6088
  /* @__PURE__ */ jsx(AlertCircleIcon, {}),
6448
6089
  /* @__PURE__ */ jsxs("div", { children: [
@@ -6452,13 +6093,99 @@ function LegacyWorkflowGraph({ workflowId }) {
6452
6093
  ] })
6453
6094
  ] }) });
6454
6095
  }
6455
- return /* @__PURE__ */ jsx(LegacyWorkflowNestedGraphProvider, { children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(LegacyWorkflowGraphInner, { workflow: legacyWorkflow }) }) });
6456
- }
6457
-
6458
- const Form = React__default.forwardRef(({ children, ...props }, ref) => {
6459
- return /* @__PURE__ */ jsx("form", { ref, className: "space-y-4", ...props, children });
6460
- });
6461
-
6096
+ return /* @__PURE__ */ jsx(
6097
+ WorkflowNestedGraphProvider,
6098
+ {
6099
+ onShowTrace,
6100
+ onSendEvent,
6101
+ children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(
6102
+ WorkflowGraphInner,
6103
+ {
6104
+ workflow: snapshot?.serializedStepGraph ? { stepGraph: snapshot?.serializedStepGraph } : workflow,
6105
+ onShowTrace,
6106
+ onSendEvent
6107
+ }
6108
+ ) })
6109
+ },
6110
+ snapshot?.runId ?? workflowId
6111
+ );
6112
+ }
6113
+
6114
+ function resolveSerializedZodOutput(obj) {
6115
+ return Function("z", `"use strict";return (${obj});`)(z);
6116
+ }
6117
+
6118
+ function CodeBlockDemo({
6119
+ code = "",
6120
+ language = "ts",
6121
+ filename,
6122
+ className
6123
+ }) {
6124
+ return /* @__PURE__ */ jsxs(CodeBlock, { code, language, theme: themes.oneDark, children: [
6125
+ 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,
6126
+ /* @__PURE__ */ jsx(
6127
+ CodeBlock.Code,
6128
+ {
6129
+ className: cn("bg-transparent h-full p-6 rounded-xl whitespace-pre-wrap", filename ? "pt-10" : "", className),
6130
+ children: /* @__PURE__ */ jsx("div", { className: "table-row", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
6131
+ /* @__PURE__ */ jsx(CodeBlock.LineNumber, { className: "table-cell pr-4 text-sm text-right select-none text-gray-500/50" }),
6132
+ /* @__PURE__ */ jsx(CodeBlock.LineContent, { className: "flex", children: /* @__PURE__ */ jsx(CodeBlock.Token, { className: "font-mono text-sm mastra-token" }) })
6133
+ ] }) })
6134
+ }
6135
+ )
6136
+ ] });
6137
+ }
6138
+
6139
+ const usePlaygroundStore = create()(
6140
+ persist(
6141
+ (set) => ({
6142
+ runtimeContext: {},
6143
+ setRuntimeContext: (runtimeContext) => set({ runtimeContext })
6144
+ }),
6145
+ {
6146
+ name: "mastra-playground-store"
6147
+ }
6148
+ )
6149
+ );
6150
+
6151
+ const WorkflowCard = ({ header, children, footer }) => {
6152
+ const [expanded, setExpanded] = useState(false);
6153
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface4", children: [
6154
+ /* @__PURE__ */ jsxs("button", { className: "py-1 px-2 flex items-center gap-3 justify-between w-full", onClick: () => setExpanded((s) => !s), children: [
6155
+ /* @__PURE__ */ jsx("div", { className: "w-full", children: header }),
6156
+ /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("text-icon3 transition-transform -rotate-90", expanded && "rotate-0") }) })
6157
+ ] }),
6158
+ children && expanded && /* @__PURE__ */ jsx("div", { className: "border-t-sm border-border1", children }),
6159
+ footer && /* @__PURE__ */ jsx("div", { className: "py-1 px-2 border-t-sm border-border1", children: footer })
6160
+ ] });
6161
+ };
6162
+
6163
+ const WorkflowStatus = ({ stepId, status, result }) => {
6164
+ return /* @__PURE__ */ jsx(
6165
+ WorkflowCard,
6166
+ {
6167
+ header: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
6168
+ /* @__PURE__ */ jsxs(Icon, { children: [
6169
+ status === "success" && /* @__PURE__ */ jsx(CheckIcon, { className: "text-accent1" }),
6170
+ status === "failed" && /* @__PURE__ */ jsx(CrossIcon, { className: "text-accent2" }),
6171
+ status === "suspended" && /* @__PURE__ */ jsx(CirclePause, { className: "text-accent3" }),
6172
+ status === "waiting" && /* @__PURE__ */ jsx(HourglassIcon, { className: "text-accent5" }),
6173
+ status === "running" && /* @__PURE__ */ jsx(Loader2, { className: "text-accent6 animate-spin" })
6174
+ ] }),
6175
+ /* @__PURE__ */ jsx(Txt, { as: "span", variant: "ui-lg", className: "text-icon6 font-medium", children: stepId.charAt(0).toUpperCase() + stepId.slice(1) })
6176
+ ] }),
6177
+ children: /* @__PURE__ */ jsxs("div", { className: "rounded-md bg-surface4 p-1 font-mono relative", children: [
6178
+ /* @__PURE__ */ jsx(CopyButton, { content: JSON.stringify(result, null, 2), className: "absolute top-2 right-2 z-10" }),
6179
+ /* @__PURE__ */ jsx(SyntaxHighlighter$1, { data: result })
6180
+ ] })
6181
+ }
6182
+ );
6183
+ };
6184
+
6185
+ const Form = React__default.forwardRef(({ children, ...props }, ref) => {
6186
+ return /* @__PURE__ */ jsx("form", { ref, className: "space-y-4", ...props, children });
6187
+ });
6188
+
6462
6189
  const DISABLED_LABELS = ["boolean", "object", "array"];
6463
6190
  const FieldWrapper = ({ label, children, id, field, error }) => {
6464
6191
  const isDisabled = DISABLED_LABELS.includes(field.type);
@@ -7269,610 +6996,30 @@ function DynamicForm({
7269
6996
  if (isNotZodObject) {
7270
6997
  return z$2.object({
7271
6998
  "​": schema2
7272
- });
7273
- }
7274
- return schema2;
7275
- };
7276
- const schemaProvider = new CustomZodProvider(normalizedSchema(schema));
7277
- const formProps = {
7278
- schema: schemaProvider,
7279
- onSubmit: async (values) => {
7280
- await onSubmit?.(isNotZodObject ? values["​"] || {} : values);
7281
- },
7282
- defaultValues: isNotZodObject ? defaultValues ? { "​": defaultValues } : void 0 : defaultValues,
7283
- formProps: {
7284
- className
7285
- },
7286
- uiComponents: {
7287
- SubmitButton: ({ children }) => onSubmit ? /* @__PURE__ */ jsx(Button$1, { variant: "light", className: "w-full", size: "lg", disabled: isSubmitLoading, children: isSubmitLoading ? /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" }) }) : submitButtonLabel || children }) : null
7288
- },
7289
- formComponents: {
7290
- Label: ({ value }) => /* @__PURE__ */ jsx(Label, { className: "text-sm font-normal", children: value })
7291
- },
7292
- withSubmit: true
7293
- };
7294
- return /* @__PURE__ */ jsx(AutoForm, { ...formProps, readOnly });
7295
- }
7296
-
7297
- function resolveSerializedZodOutput(obj) {
7298
- return Function("z", `"use strict";return (${obj});`)(z);
7299
- }
7300
-
7301
- function CodeBlockDemo({
7302
- code = "",
7303
- language = "ts",
7304
- filename,
7305
- className
7306
- }) {
7307
- return /* @__PURE__ */ jsxs(CodeBlock, { code, language, theme: themes.oneDark, children: [
7308
- 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,
7309
- /* @__PURE__ */ jsx(
7310
- CodeBlock.Code,
7311
- {
7312
- className: cn("bg-transparent h-full p-6 rounded-xl whitespace-pre-wrap", filename ? "pt-10" : "", className),
7313
- children: /* @__PURE__ */ jsx("div", { className: "table-row", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
7314
- /* @__PURE__ */ jsx(CodeBlock.LineNumber, { className: "table-cell pr-4 text-sm text-right select-none text-gray-500/50" }),
7315
- /* @__PURE__ */ jsx(CodeBlock.LineContent, { className: "flex", children: /* @__PURE__ */ jsx(CodeBlock.Token, { className: "font-mono text-sm mastra-token" }) })
7316
- ] }) })
7317
- }
7318
- )
7319
- ] });
7320
- }
7321
-
7322
- const WorkflowCard = ({ header, children, footer }) => {
7323
- const [expanded, setExpanded] = useState(false);
7324
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface4", children: [
7325
- /* @__PURE__ */ jsxs("button", { className: "py-1 px-2 flex items-center gap-3 justify-between w-full", onClick: () => setExpanded((s) => !s), children: [
7326
- /* @__PURE__ */ jsx("div", { className: "w-full", children: header }),
7327
- /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("text-icon3 transition-transform -rotate-90", expanded && "rotate-0") }) })
7328
- ] }),
7329
- children && expanded && /* @__PURE__ */ jsx("div", { className: "border-t-sm border-border1", children }),
7330
- footer && /* @__PURE__ */ jsx("div", { className: "py-1 px-2 border-t-sm border-border1", children: footer })
7331
- ] });
7332
- };
7333
-
7334
- const LegacyWorkflowStatus = ({ stepId, pathStatus, path }) => {
7335
- const status = pathStatus === "completed" ? "Completed" : stepId === path ? pathStatus.charAt(0).toUpperCase() + pathStatus.slice(1) : pathStatus === "executing" ? "Executing" : "Completed";
7336
- return /* @__PURE__ */ jsx(
7337
- WorkflowCard,
7338
- {
7339
- header: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
7340
- /* @__PURE__ */ jsxs(Icon, { children: [
7341
- status === "Completed" && /* @__PURE__ */ jsx(CheckIcon, { className: "text-accent1" }),
7342
- status === "Failed" && /* @__PURE__ */ jsx(CrossIcon, { className: "text-accent2" }),
7343
- status === "Executing" && /* @__PURE__ */ jsx(Loader2, { className: "text-icon3 animate-spin" })
7344
- ] }),
7345
- /* @__PURE__ */ jsx(Txt, { as: "span", variant: "ui-lg", className: "text-icon6 font-medium", children: path })
7346
- ] })
7347
- }
7348
- );
7349
- };
7350
-
7351
- const WorkflowResult = ({ jsonResult, sanitizedJsonResult }) => {
7352
- const { handleCopy } = useCopyToClipboard({ text: jsonResult });
7353
- const [expanded, setExpanded] = useState(false);
7354
- return /* @__PURE__ */ jsx(
7355
- WorkflowCard,
7356
- {
7357
- header: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 justify-between w-full", children: [
7358
- /* @__PURE__ */ jsxs(Txt, { variant: "ui-lg", className: "text-icon6 flex items-center gap-3 font-medium", children: [
7359
- /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(DeploymentIcon, {}) }),
7360
- "Workflow Execution (JSON)"
7361
- ] }),
7362
- /* @__PURE__ */ jsxs(Tooltip, { children: [
7363
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
7364
- "button",
7365
- {
7366
- className: "p-2 rounded-lg hover:bg-surface5 transition-colors duration-150 ease-in-out text-icon3 hover:text-icon6",
7367
- onClick: () => handleCopy(),
7368
- children: /* @__PURE__ */ jsx(Icon, { size: "sm", children: /* @__PURE__ */ jsx(CopyIcon, {}) })
7369
- }
7370
- ) }),
7371
- /* @__PURE__ */ jsx(TooltipContent, { children: "Copy result" })
7372
- ] })
7373
- ] }),
7374
- footer: /* @__PURE__ */ jsx(
7375
- "button",
7376
- {
7377
- className: "w-full h-full text-center text-icon2 hover:text-icon6 text-ui-md",
7378
- onClick: () => setExpanded((s) => !s),
7379
- children: expanded ? "collapse" : "expand"
7380
- }
7381
- ),
7382
- children: expanded ? /* @__PURE__ */ jsx(CodeBlockDemo, { className: "w-full overflow-x-auto", code: sanitizedJsonResult || jsonResult, language: "json" }) : null
7383
- }
7384
- );
7385
- };
7386
-
7387
- function LegacyWorkflowTrigger({
7388
- workflowId,
7389
- setRunId
7390
- }) {
7391
- const { legacyResult: result, setLegacyResult: setResult, payload, setPayload } = useContext(WorkflowRunContext);
7392
- const { isLoading, legacyWorkflow: workflow } = useLegacyWorkflow(workflowId);
7393
- const { createLegacyWorkflowRun: createWorkflowRun, startLegacyWorkflowRun: startWorkflowRun } = useExecuteWorkflow();
7394
- const {
7395
- watchLegacyWorkflow: watchWorkflow,
7396
- legacyWatchResult: watchResult,
7397
- isWatchingLegacyWorkflow: isWatchingWorkflow
7398
- } = useWatchWorkflow();
7399
- const { resumeLegacyWorkflow: resumeWorkflow, isResumingLegacyWorkflow: isResumingWorkflow } = useResumeWorkflow();
7400
- const [suspendedSteps, setSuspendedSteps] = useState([]);
7401
- const [isRunning, setIsRunning] = useState(false);
7402
- const triggerSchema = workflow?.triggerSchema;
7403
- const handleExecuteWorkflow = async (data) => {
7404
- try {
7405
- if (!workflow) return;
7406
- setIsRunning(true);
7407
- setResult(null);
7408
- const { runId } = await createWorkflowRun({ workflowId });
7409
- setRunId?.(runId);
7410
- watchWorkflow({ workflowId, runId });
7411
- startWorkflowRun({ workflowId, runId, input: data });
7412
- } catch (err) {
7413
- setIsRunning(false);
7414
- toast.error("Error executing workflow");
7415
- }
7416
- };
7417
- const handleResumeWorkflow = async (step) => {
7418
- if (!workflow) return;
7419
- const { stepId, runId: prevRunId, context } = step;
7420
- const { runId } = await createWorkflowRun({ workflowId, prevRunId });
7421
- watchWorkflow({ workflowId, runId });
7422
- await resumeWorkflow({
7423
- stepId,
7424
- runId,
7425
- context,
7426
- workflowId
7427
- });
7428
- };
7429
- const watchResultToUse = result ?? watchResult;
7430
- const workflowActivePaths = watchResultToUse?.activePaths ?? {};
7431
- useEffect(() => {
7432
- setIsRunning(isWatchingWorkflow);
7433
- }, [isWatchingWorkflow]);
7434
- useEffect(() => {
7435
- if (!watchResultToUse?.activePaths || !result?.runId) return;
7436
- const suspended = Object.entries(watchResultToUse.activePaths).filter(([_, { status }]) => status === "suspended").map(([stepId, { suspendPayload }]) => ({
7437
- stepId,
7438
- runId: result.runId,
7439
- suspendPayload
7440
- }));
7441
- setSuspendedSteps(suspended);
7442
- }, [watchResultToUse, result]);
7443
- useEffect(() => {
7444
- if (watchResult) {
7445
- setResult(watchResult);
7446
- }
7447
- }, [watchResult]);
7448
- if (isLoading) {
7449
- return /* @__PURE__ */ jsx(ScrollArea, { className: "h-[calc(100vh-126px)] pt-2 px-4 pb-4 text-xs", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
7450
- /* @__PURE__ */ jsx(Skeleton, { className: "h-10" }),
7451
- /* @__PURE__ */ jsx(Skeleton, { className: "h-10" })
7452
- ] }) });
7453
- }
7454
- if (!workflow) return null;
7455
- const isSuspendedSteps = suspendedSteps.length > 0;
7456
- const zodInputSchema = triggerSchema ? resolveSerializedZodOutput(jsonSchemaToZod(parse(triggerSchema))) : null;
7457
- const { sanitizedOutput, ...restResult } = result ?? {};
7458
- const hasWorkflowActivePaths = Object.values(workflowActivePaths).length > 0;
7459
- return /* @__PURE__ */ jsx("div", { className: "h-full px-5 pt-3 pb-12", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
7460
- isResumingWorkflow && /* @__PURE__ */ jsxs("div", { className: "py-2 px-5 flex items-center gap-2 bg-surface5 -mx-5 -mt-5 border-b-sm border-border1", children: [
7461
- /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(Loader2, { className: "animate-spin text-icon6" }) }),
7462
- /* @__PURE__ */ jsx(Txt, { children: "Resuming workflow" })
7463
- ] }),
7464
- !isSuspendedSteps && /* @__PURE__ */ jsx(Fragment, { children: zodInputSchema ? /* @__PURE__ */ jsx(
7465
- DynamicForm,
7466
- {
7467
- schema: zodInputSchema,
7468
- defaultValues: payload,
7469
- isSubmitLoading: isWatchingWorkflow,
7470
- submitButtonLabel: "Run",
7471
- onSubmit: (data) => {
7472
- setPayload(data);
7473
- handleExecuteWorkflow(data);
7474
- }
7475
- }
7476
- ) : /* @__PURE__ */ jsx(
7477
- Button$1,
7478
- {
7479
- className: "w-full",
7480
- variant: "light",
7481
- disabled: isRunning,
7482
- onClick: () => handleExecuteWorkflow(null),
7483
- children: isRunning ? /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" }) }) : "Trigger"
7484
- }
7485
- ) }),
7486
- isSuspendedSteps && suspendedSteps?.map((step) => {
7487
- const stepDefinition = workflow.steps[step.stepId];
7488
- const stepSchema = stepDefinition?.inputSchema ? resolveSerializedZodOutput(jsonSchemaToZod(parse(stepDefinition.inputSchema))) : z.record(z.string(), z.any());
7489
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col px-4", children: [
7490
- /* @__PURE__ */ jsx(Text, { variant: "secondary", className: "text-mastra-el-3", size: "xs", children: step.stepId }),
7491
- step.suspendPayload && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
7492
- CodeBlockDemo,
7493
- {
7494
- className: "w-full overflow-x-auto p-2",
7495
- code: JSON.stringify(step.suspendPayload, null, 2),
7496
- language: "json"
7497
- }
7498
- ) }),
7499
- /* @__PURE__ */ jsx(
7500
- DynamicForm,
7501
- {
7502
- schema: stepSchema,
7503
- isSubmitLoading: isResumingWorkflow,
7504
- submitButtonLabel: "Resume",
7505
- onSubmit: (data) => {
7506
- handleResumeWorkflow({
7507
- stepId: step.stepId,
7508
- runId: step.runId,
7509
- suspendPayload: step.suspendPayload,
7510
- context: data
7511
- });
7512
- }
7513
- }
7514
- )
7515
- ] });
7516
- }),
7517
- hasWorkflowActivePaths && /* @__PURE__ */ jsxs(Fragment, { children: [
7518
- /* @__PURE__ */ jsx("hr", { className: "border-border1 border-sm my-5" }),
7519
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: Object.entries(workflowActivePaths)?.map(([stepId, { status: pathStatus, stepPath }]) => {
7520
- return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: stepPath?.map((path, idx) => {
7521
- return /* @__PURE__ */ jsx(LegacyWorkflowStatus, { stepId, pathStatus, path }, idx);
7522
- }) }, stepId);
7523
- }) })
7524
- ] }),
7525
- result && /* @__PURE__ */ jsxs(Fragment, { children: [
7526
- /* @__PURE__ */ jsx("hr", { className: "border-border1 border-sm my-5" }),
7527
- /* @__PURE__ */ jsx(WorkflowResult, { sanitizedJsonResult: sanitizedOutput, jsonResult: JSON.stringify(restResult, null, 2) })
7528
- ] })
7529
- ] }) });
7530
- }
7531
-
7532
- const Slider = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(
7533
- SliderPrimitive.Root,
7534
- {
7535
- ref,
7536
- className: cn("relative flex w-full touch-none select-none items-center", className),
7537
- ...props,
7538
- children: [
7539
- /* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full bg-primary/50" }) }),
7540
- /* @__PURE__ */ jsx(SliderPrimitive.Thumb, { className: "block h-4 w-4 rounded-full border border-primary/50 bg-white shadow transition-colors disabled:pointer-events-none disabled:opacity-50" })
7541
- ]
7542
- }
7543
- ));
7544
- Slider.displayName = SliderPrimitive.Root.displayName;
7545
-
7546
- const ZoomSlider = forwardRef(({ className, ...props }) => {
7547
- const { zoom } = useViewport();
7548
- const { zoomTo, zoomIn, zoomOut, fitView } = useReactFlow();
7549
- return /* @__PURE__ */ jsxs(Panel, { className: cn("flex gap-1 rounded-md bg-primary-foreground p-1 text-foreground", className), ...props, children: [
7550
- /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomOut({ duration: 300 }), children: /* @__PURE__ */ jsx(Minus, { className: "h-4 w-4" }) }),
7551
- /* @__PURE__ */ jsx(
7552
- Slider,
7553
- {
7554
- className: "w-[140px]",
7555
- value: [zoom],
7556
- min: 0.01,
7557
- max: 1,
7558
- step: 0.01,
7559
- onValueChange: (values) => {
7560
- zoomTo(values[0]);
7561
- }
7562
- }
7563
- ),
7564
- /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomIn({ duration: 300 }), children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }) }),
7565
- /* @__PURE__ */ jsxs(Button$2, { className: "min-w-20 tabular-nums", variant: "ghost", onClick: () => zoomTo(1, { duration: 300 }), children: [
7566
- (100 * zoom).toFixed(0),
7567
- "%"
7568
- ] }),
7569
- /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => fitView({ duration: 300, maxZoom: 1 }), children: /* @__PURE__ */ jsx(Maximize, { className: "h-4 w-4" }) })
7570
- ] });
7571
- });
7572
- ZoomSlider.displayName = "ZoomSlider";
7573
-
7574
- function WorkflowNestedGraph({
7575
- stepGraph,
7576
- open,
7577
- workflowName,
7578
- onShowTrace,
7579
- onSendEvent
7580
- }) {
7581
- const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
7582
- stepGraph
7583
- });
7584
- const [isMounted, setIsMounted] = useState(false);
7585
- const [nodes, _, onNodesChange] = useNodesState(initialNodes);
7586
- const [edges] = useEdgesState(initialEdges);
7587
- const { steps } = useCurrentRun();
7588
- const nodeTypes = {
7589
- "default-node": (props) => /* @__PURE__ */ jsx(
7590
- WorkflowDefaultNode,
7591
- {
7592
- parentWorkflowName: workflowName,
7593
- onShowTrace,
7594
- onSendEvent,
7595
- ...props
7596
- }
7597
- ),
7598
- "condition-node": WorkflowConditionNode,
7599
- "after-node": WorkflowAfterNode,
7600
- "loop-result-node": WorkflowLoopResultNode,
7601
- "nested-node": (props) => /* @__PURE__ */ jsx(
7602
- WorkflowNestedNode,
7603
- {
7604
- parentWorkflowName: workflowName,
7605
- onShowTrace,
7606
- onSendEvent,
7607
- ...props
7608
- }
7609
- )
7610
- };
7611
- useEffect(() => {
7612
- if (open) {
7613
- setTimeout(() => {
7614
- setIsMounted(true);
7615
- }, 500);
7616
- }
7617
- }, [open]);
7618
- return /* @__PURE__ */ jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxs(
7619
- ReactFlow,
7620
- {
7621
- nodes,
7622
- edges: edges.map((e) => ({
7623
- ...e,
7624
- style: {
7625
- ...e.style,
7626
- stroke: steps[`${workflowName}.${e.data?.previousStepId}`]?.status === "success" && steps[`${workflowName}.${e.data?.nextStepId}`] ? "#22c55e" : e.data?.conditionNode && !steps[`${workflowName}.${e.data?.previousStepId}`] && Boolean(steps[`${workflowName}.${e.data?.nextStepId}`]?.status) ? "#22c55e" : void 0
7627
- }
7628
- })),
7629
- fitView: true,
7630
- fitViewOptions: {
7631
- maxZoom: 1
7632
- },
7633
- minZoom: 0.01,
7634
- maxZoom: 1,
7635
- nodeTypes,
7636
- onNodesChange,
7637
- children: [
7638
- /* @__PURE__ */ jsx(ZoomSlider, { position: "bottom-left" }),
7639
- /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Lines, gap: 12, size: 0.5 })
7640
- ]
7641
- }
7642
- ) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, {}) }) });
7643
- }
7644
-
7645
- const WorkflowNestedGraphContext = createContext(
7646
- {}
7647
- );
7648
- function WorkflowNestedGraphProvider({
7649
- children,
7650
- onShowTrace,
7651
- onSendEvent
7652
- }) {
7653
- const [stepGraph, setStepGraph] = useState(null);
7654
- const [parentStepGraphList, setParentStepGraphList] = useState([]);
7655
- const [openDialog, setOpenDialog] = useState(false);
7656
- const [label, setLabel] = useState("");
7657
- const [fullStep, setFullStep] = useState("");
7658
- const closeNestedGraph = () => {
7659
- if (parentStepGraphList.length) {
7660
- const lastStepGraph = parentStepGraphList[parentStepGraphList.length - 1];
7661
- setStepGraph(lastStepGraph.stepGraph);
7662
- setLabel(lastStepGraph.label);
7663
- setFullStep(lastStepGraph.fullStep);
7664
- setParentStepGraphList(parentStepGraphList.slice(0, -1));
7665
- } else {
7666
- setOpenDialog(false);
7667
- setStepGraph(null);
7668
- setLabel("");
7669
- setFullStep("");
7670
- }
7671
- };
7672
- const showNestedGraph = ({
7673
- label: newLabel,
7674
- stepGraph: newStepGraph,
7675
- fullStep: newFullStep
7676
- }) => {
7677
- if (stepGraph) {
7678
- setParentStepGraphList([...parentStepGraphList, { stepGraph, label, fullStep }]);
7679
- }
7680
- setLabel(newLabel);
7681
- setFullStep(newFullStep);
7682
- setStepGraph(newStepGraph);
7683
- setOpenDialog(true);
7684
- };
7685
- return /* @__PURE__ */ jsxs(
7686
- WorkflowNestedGraphContext.Provider,
7687
- {
7688
- value: {
7689
- showNestedGraph,
7690
- closeNestedGraph
7691
- },
7692
- children: [
7693
- children,
7694
- /* @__PURE__ */ jsx(Dialog, { open: openDialog, onOpenChange: closeNestedGraph, children: /* @__PURE__ */ jsx(DialogPortal, { children: /* @__PURE__ */ jsxs(DialogContent, { className: "w-[45rem] h-[45rem] max-w-[unset] bg-[#121212] p-[0.5rem]", children: [
7695
- /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-1.5 absolute top-3 left-3 z-50", children: [
7696
- /* @__PURE__ */ jsx(Workflow, { className: "text-current w-4 h-4" }),
7697
- /* @__PURE__ */ jsxs(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: [
7698
- label,
7699
- " workflow"
7700
- ] })
7701
- ] }),
7702
- /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(
7703
- WorkflowNestedGraph,
7704
- {
7705
- stepGraph,
7706
- open: openDialog,
7707
- workflowName: fullStep,
7708
- onShowTrace,
7709
- onSendEvent
7710
- }
7711
- ) })
7712
- ] }) }) }, `${label}-${fullStep}`)
7713
- ]
7714
- }
7715
- );
7716
- }
7717
-
7718
- function WorkflowNestedNode({
7719
- data,
7720
- parentWorkflowName,
7721
- onShowTrace,
7722
- onSendEvent
7723
- }) {
7724
- const { steps, runId } = useCurrentRun();
7725
- const { showNestedGraph } = useContext(WorkflowNestedGraphContext);
7726
- const { label, description, withoutTopHandle, withoutBottomHandle, stepGraph, mapConfig, event } = data;
7727
- const fullLabel = parentWorkflowName ? `${parentWorkflowName}.${label}` : label;
7728
- const step = steps[fullLabel];
7729
- return /* @__PURE__ */ jsxs(Fragment, { children: [
7730
- !withoutTopHandle && /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Top, style: { visibility: "hidden" } }),
7731
- /* @__PURE__ */ jsxs(
7732
- "div",
7733
- {
7734
- className: cn(
7735
- "bg-surface3 rounded-lg w-[274px] border-sm border-border1 pt-2",
7736
- step?.status === "success" && "bg-accent1Darker",
7737
- step?.status === "failed" && "bg-accent2Darker",
7738
- step?.status === "suspended" && "bg-accent3Darker",
7739
- step?.status === "waiting" && "bg-accent5Darker",
7740
- step?.status === "running" && "bg-accent6Darker"
7741
- ),
7742
- children: [
7743
- /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2 px-3", !description && "pb-2"), children: [
7744
- /* @__PURE__ */ jsxs(Icon, { children: [
7745
- step?.status === "failed" && /* @__PURE__ */ jsx(CrossIcon, { className: "text-accent2" }),
7746
- step?.status === "success" && /* @__PURE__ */ jsx(CheckIcon, { className: "text-accent1" }),
7747
- step?.status === "suspended" && /* @__PURE__ */ jsx(PauseIcon, { className: "text-accent3" }),
7748
- step?.status === "waiting" && /* @__PURE__ */ jsx(HourglassIcon, { className: "text-accent5" }),
7749
- step?.status === "running" && /* @__PURE__ */ jsx(Loader2, { className: "text-accent6 animate-spin" }),
7750
- !step && /* @__PURE__ */ jsx(CircleDashed, { className: "text-icon2" })
7751
- ] }),
7752
- /* @__PURE__ */ jsxs(Txt, { variant: "ui-lg", className: "text-icon6 font-medium inline-flex items-center gap-1 justify-between w-full", children: [
7753
- label,
7754
- " ",
7755
- step?.startedAt && /* @__PURE__ */ jsx(Clock, { startedAt: step.startedAt, endedAt: step.endedAt })
7756
- ] })
7757
- ] }),
7758
- description && /* @__PURE__ */ jsx(Txt, { variant: "ui-sm", className: "text-icon3 px-3 pb-2", children: description }),
7759
- /* @__PURE__ */ jsx(
7760
- WorkflowStepActionBar,
7761
- {
7762
- stepName: label,
7763
- input: step?.input,
7764
- resumeData: step?.resumeData,
7765
- output: step?.output,
7766
- error: step?.error,
7767
- mapConfig,
7768
- onShowTrace: runId && onShowTrace ? () => onShowTrace?.({ runId, stepName: fullLabel }) : void 0,
7769
- onShowNestedGraph: () => showNestedGraph({ label, fullStep: fullLabel, stepGraph }),
7770
- onSendEvent,
7771
- event: step?.status === "waiting" ? event : void 0,
7772
- runId,
7773
- status: step?.status
7774
- }
7775
- )
7776
- ]
7777
- }
7778
- ),
7779
- !withoutBottomHandle && /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Bottom, style: { visibility: "hidden" } })
7780
- ] });
7781
- }
7782
-
7783
- function WorkflowGraphInner({ workflow, onShowTrace, onSendEvent }) {
7784
- const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges(workflow);
7785
- const [nodes, _, onNodesChange] = useNodesState(initialNodes);
7786
- const [edges] = useEdgesState(initialEdges);
7787
- const { steps, runId } = useCurrentRun();
7788
- const nodeTypes = {
7789
- "default-node": (props) => /* @__PURE__ */ jsx(WorkflowDefaultNode, { onShowTrace, onSendEvent, ...props }),
7790
- "condition-node": WorkflowConditionNode,
7791
- "after-node": WorkflowAfterNode,
7792
- "loop-result-node": WorkflowLoopResultNode,
7793
- "nested-node": (props) => /* @__PURE__ */ jsx(WorkflowNestedNode, { onShowTrace, onSendEvent, ...props })
7794
- };
7795
- return /* @__PURE__ */ jsx("div", { className: "w-full h-full bg-surface1", children: /* @__PURE__ */ jsxs(
7796
- ReactFlow,
7797
- {
7798
- nodes,
7799
- edges: edges.map((e) => ({
7800
- ...e,
7801
- style: {
7802
- ...e.style,
7803
- stroke: steps[e.data?.previousStepId]?.status === "success" && steps[e.data?.nextStepId] ? "#22c55e" : e.data?.conditionNode && !steps[e.data?.previousStepId] && Boolean(steps[e.data?.nextStepId]?.status) ? "#22c55e" : void 0
7804
- }
7805
- })),
7806
- nodeTypes,
7807
- onNodesChange,
7808
- fitView: true,
7809
- fitViewOptions: {
7810
- maxZoom: 1
7811
- },
7812
- minZoom: 0.01,
7813
- maxZoom: 1,
7814
- children: [
7815
- /* @__PURE__ */ jsx(ZoomSlider, { position: "bottom-left" }),
7816
- /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Dots, gap: 12, size: 0.5 })
7817
- ]
7818
- }
7819
- ) });
7820
- }
7821
-
7822
- function WorkflowGraph({ workflowId, onShowTrace, workflow, isLoading, onSendEvent }) {
7823
- const { snapshot } = useContext(WorkflowRunContext);
7824
- if (isLoading) {
7825
- return /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-full" }) });
7826
- }
7827
- if (!workflow) {
7828
- return /* @__PURE__ */ jsx("div", { className: "grid h-full place-items-center", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
7829
- /* @__PURE__ */ jsx(AlertCircleIcon, {}),
7830
- /* @__PURE__ */ jsxs("div", { children: [
7831
- "We couldn't find ",
7832
- lodashTitleCase(workflowId),
7833
- " workflow."
7834
- ] })
7835
- ] }) });
7836
- }
7837
- return /* @__PURE__ */ jsx(
7838
- WorkflowNestedGraphProvider,
7839
- {
7840
- onShowTrace,
7841
- onSendEvent,
7842
- children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(
7843
- WorkflowGraphInner,
7844
- {
7845
- workflow: snapshot?.serializedStepGraph ? { stepGraph: snapshot?.serializedStepGraph } : workflow,
7846
- onShowTrace,
7847
- onSendEvent
7848
- }
7849
- ) })
7850
- },
7851
- snapshot?.runId ?? workflowId
7852
- );
7853
- }
7854
-
7855
- const WorkflowStatus = ({ stepId, status, result }) => {
7856
- return /* @__PURE__ */ jsx(
7857
- WorkflowCard,
7858
- {
7859
- header: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
7860
- /* @__PURE__ */ jsxs(Icon, { children: [
7861
- status === "success" && /* @__PURE__ */ jsx(CheckIcon, { className: "text-accent1" }),
7862
- status === "failed" && /* @__PURE__ */ jsx(CrossIcon, { className: "text-accent2" }),
7863
- status === "suspended" && /* @__PURE__ */ jsx(CirclePause, { className: "text-accent3" }),
7864
- status === "waiting" && /* @__PURE__ */ jsx(HourglassIcon, { className: "text-accent5" }),
7865
- status === "running" && /* @__PURE__ */ jsx(Loader2, { className: "text-accent6 animate-spin" })
7866
- ] }),
7867
- /* @__PURE__ */ jsx(Txt, { as: "span", variant: "ui-lg", className: "text-icon6 font-medium", children: stepId.charAt(0).toUpperCase() + stepId.slice(1) })
7868
- ] }),
7869
- children: /* @__PURE__ */ jsxs("div", { className: "rounded-md bg-surface4 p-1 font-mono relative", children: [
7870
- /* @__PURE__ */ jsx(CopyButton, { content: JSON.stringify(result, null, 2), className: "absolute top-2 right-2 z-10" }),
7871
- /* @__PURE__ */ jsx(SyntaxHighlighter$1, { data: result })
7872
- ] })
6999
+ });
7873
7000
  }
7874
- );
7875
- };
7001
+ return schema2;
7002
+ };
7003
+ const schemaProvider = new CustomZodProvider(normalizedSchema(schema));
7004
+ const formProps = {
7005
+ schema: schemaProvider,
7006
+ onSubmit: async (values) => {
7007
+ await onSubmit?.(isNotZodObject ? values["​"] || {} : values);
7008
+ },
7009
+ defaultValues: isNotZodObject ? defaultValues ? { "​": defaultValues } : void 0 : defaultValues,
7010
+ formProps: {
7011
+ className
7012
+ },
7013
+ uiComponents: {
7014
+ SubmitButton: ({ children }) => onSubmit ? /* @__PURE__ */ jsx(Button$1, { variant: "light", className: "w-full", size: "lg", disabled: isSubmitLoading, children: isSubmitLoading ? /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(Loader2, { className: "animate-spin" }) }) : submitButtonLabel || children }) : null
7015
+ },
7016
+ formComponents: {
7017
+ Label: ({ value }) => /* @__PURE__ */ jsx(Label, { className: "text-sm font-normal", children: value })
7018
+ },
7019
+ withSubmit: true
7020
+ };
7021
+ return /* @__PURE__ */ jsx(AutoForm, { ...formProps, readOnly });
7022
+ }
7876
7023
 
7877
7024
  const RadioGroup = React.forwardRef(({ className, ...props }, ref) => {
7878
7025
  return /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { className: cn("grid gap-2", className), ...props, ref });
@@ -8520,18 +7667,15 @@ const columns$3 = [
8520
7667
  id: "stepsCount",
8521
7668
  header: "Steps",
8522
7669
  size: 300,
8523
- cell: ({ row }) => /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex justify-end items-center gap-2", children: [
8524
- /* @__PURE__ */ jsxs(Badge$1, { icon: /* @__PURE__ */ jsx(Footprints, {}), className: "!h-button-md", children: [
8525
- row.original.stepsCount,
8526
- " step",
8527
- row.original.stepsCount > 1 ? "s" : ""
8528
- ] }),
8529
- row.original.isLegacy ? /* @__PURE__ */ jsx(Badge$1, { className: "!text-foreground/80 !h-button-md", children: "Legacy" }) : null
8530
- ] }) })
7670
+ cell: ({ row }) => /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx("div", { className: "flex justify-end items-center gap-2", children: /* @__PURE__ */ jsxs(Badge$1, { icon: /* @__PURE__ */ jsx(Footprints, {}), className: "!h-button-md", children: [
7671
+ row.original.stepsCount,
7672
+ " step",
7673
+ row.original.stepsCount > 1 ? "s" : ""
7674
+ ] }) }) })
8531
7675
  }
8532
7676
  ];
8533
7677
 
8534
- function WorkflowTable({ workflows, legacyWorkflows, isLoading }) {
7678
+ function WorkflowTable({ workflows, isLoading }) {
8535
7679
  const { navigate, paths } = useLinkComponent();
8536
7680
  const workflowData = useMemo(() => {
8537
7681
  const _workflowsData = Object.keys(workflows ?? {}).map((key) => {
@@ -8540,22 +7684,11 @@ function WorkflowTable({ workflows, legacyWorkflows, isLoading }) {
8540
7684
  id: key,
8541
7685
  name: workflow?.name || "N/A",
8542
7686
  stepsCount: Object.keys(workflow?.steps ?? {})?.length,
8543
- isLegacy: false,
8544
- link: paths.workflowLink(key)
8545
- };
8546
- });
8547
- const legacyWorkflowsData = Object.keys(legacyWorkflows ?? {}).map((key) => {
8548
- const workflow = legacyWorkflows?.[key];
8549
- return {
8550
- id: key,
8551
- name: workflow?.name || "N/A",
8552
- stepsCount: Object.keys(workflow?.steps ?? {})?.length,
8553
- isLegacy: true,
8554
7687
  link: paths.workflowLink(key)
8555
7688
  };
8556
7689
  });
8557
- return [..._workflowsData, ...legacyWorkflowsData];
8558
- }, [workflows, legacyWorkflows]);
7690
+ return _workflowsData;
7691
+ }, [workflows]);
8559
7692
  const table = useReactTable({
8560
7693
  data: workflowData,
8561
7694
  columns: columns$3,
@@ -8651,6 +7784,19 @@ const useWorkflowStream = (workflowFullState) => {
8651
7784
  }, [workflowFullState]);
8652
7785
  };
8653
7786
 
7787
+ const useWorkflow = (workflowId) => {
7788
+ const client = useMastraClient();
7789
+ const { runtimeContext } = usePlaygroundStore();
7790
+ return useQuery({
7791
+ queryKey: ["workflow", workflowId],
7792
+ queryFn: () => workflowId ? client.getWorkflow(workflowId).details(runtimeContext) : null,
7793
+ enabled: Boolean(workflowId),
7794
+ retry: false,
7795
+ refetchOnWindowFocus: false,
7796
+ throwOnError: false
7797
+ });
7798
+ };
7799
+
8654
7800
  const LoadingBadge = () => {
8655
7801
  return /* @__PURE__ */ jsx(
8656
7802
  BadgeWrapper,
@@ -9845,212 +8991,185 @@ const handleNetworkMessageFromMemory = (content) => {
9845
8991
  return { role: "assistant", content: [{ type: "text", text: "Unknown response" }] };
9846
8992
  };
9847
8993
 
9848
- const handleStreamChunk = async ({
9849
- chunk,
9850
- setMessages,
9851
- refreshWorkingMemory,
9852
- _sideEffects
9853
- }) => {
9854
- function updater() {
9855
- setMessages((currentConversation) => {
9856
- const message = {
8994
+ const handleStreamChunk = ({ chunk, conversation }) => {
8995
+ switch (chunk.type) {
8996
+ default:
8997
+ return [...conversation];
8998
+ case "text-start": {
8999
+ const newMessage = {
9857
9000
  role: "assistant",
9858
- content: [{ type: "text", text: _sideEffects.content }]
9001
+ content: [{ type: "text", text: "" }]
9859
9002
  };
9860
- if (!_sideEffects.assistantMessageAdded) {
9861
- _sideEffects.assistantMessageAdded = true;
9862
- if (_sideEffects.assistantToolCallAddedForUpdater) {
9863
- _sideEffects.assistantToolCallAddedForUpdater = false;
9864
- }
9865
- return [...currentConversation, message];
9866
- }
9867
- if (_sideEffects.assistantToolCallAddedForUpdater) {
9868
- _sideEffects.assistantToolCallAddedForUpdater = false;
9869
- return [...currentConversation, message];
9870
- }
9871
- return [...currentConversation.slice(0, -1), message];
9872
- });
9873
- }
9874
- switch (chunk.type) {
9003
+ return [...conversation, newMessage];
9004
+ }
9875
9005
  case "text-delta": {
9876
- if (_sideEffects.assistantToolCallAddedForContent) {
9877
- _sideEffects.assistantToolCallAddedForContent = false;
9878
- _sideEffects.content = chunk.payload.text;
9879
- } else {
9880
- _sideEffects.content += chunk.payload.text;
9006
+ const lastMessage = conversation[conversation.length - 1];
9007
+ if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9008
+ const updatedContent = lastMessage.content.map((part) => {
9009
+ if (typeof part === "object" && part.type === "text") {
9010
+ return {
9011
+ ...part,
9012
+ text: part.text + chunk.payload.text
9013
+ };
9014
+ }
9015
+ return part;
9016
+ });
9017
+ const updatedMessage = {
9018
+ ...lastMessage,
9019
+ content: updatedContent
9020
+ };
9021
+ return [...conversation.slice(0, -1), updatedMessage];
9881
9022
  }
9882
- updater();
9883
- break;
9023
+ return [...conversation];
9884
9024
  }
9885
9025
  case "tool-output": {
9886
9026
  if (chunk.payload.output?.type.startsWith("workflow-")) {
9887
- handleWorkflowChunk({ workflowChunk: chunk.payload.output, setMessages, entityName: chunk.payload.toolName });
9888
- } else {
9889
- setMessages((currentConversation) => {
9890
- const lastMessage = currentConversation[currentConversation.length - 1];
9891
- if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9892
- const updatedContent = lastMessage.content.map((part) => {
9893
- if (typeof part === "object" && part.type === "tool-call" && part.toolCallId === chunk.payload.toolCallId) {
9894
- const existingToolOutput = part.args?.__mastraMetadata?.toolOutput || [];
9895
- return {
9896
- ...part,
9897
- args: {
9898
- ...part.args,
9899
- __mastraMetadata: {
9900
- ...part.args?.__mastraMetadata,
9901
- toolOutput: [...existingToolOutput, chunk?.payload?.output]
9902
- }
9903
- }
9904
- };
9027
+ return handleWorkflowChunk({
9028
+ workflowChunk: chunk.payload.output,
9029
+ conversation,
9030
+ entityName: chunk.payload.toolName
9031
+ });
9032
+ }
9033
+ const lastMessage = conversation[conversation.length - 1];
9034
+ if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9035
+ const updatedContent = lastMessage.content.map((part) => {
9036
+ if (typeof part === "object" && part.type === "tool-call" && part.toolCallId === chunk.payload.toolCallId) {
9037
+ const existingToolOutput = part.args?.__mastraMetadata?.toolOutput || [];
9038
+ return {
9039
+ ...part,
9040
+ args: {
9041
+ ...part.args,
9042
+ __mastraMetadata: {
9043
+ ...part.args?.__mastraMetadata,
9044
+ toolOutput: [...existingToolOutput, chunk?.payload?.output]
9045
+ }
9905
9046
  }
9906
- return part;
9907
- });
9908
- const updatedMessage = {
9909
- ...lastMessage,
9910
- content: updatedContent
9911
9047
  };
9912
- return [...currentConversation.slice(0, -1), updatedMessage];
9913
9048
  }
9914
- return currentConversation;
9049
+ return part;
9915
9050
  });
9051
+ const updatedMessage = {
9052
+ ...lastMessage,
9053
+ content: updatedContent
9054
+ };
9055
+ return [...conversation.slice(0, -1), updatedMessage];
9916
9056
  }
9917
- break;
9057
+ return [...conversation];
9918
9058
  }
9919
9059
  case "tool-call": {
9920
- setMessages((currentConversation) => {
9921
- const lastMessage = currentConversation[currentConversation.length - 1];
9922
- if (lastMessage && lastMessage.role === "assistant") {
9923
- const updatedMessage = {
9924
- ...lastMessage,
9925
- content: Array.isArray(lastMessage.content) ? [
9926
- ...lastMessage.content,
9927
- {
9928
- type: "tool-call",
9929
- toolCallId: chunk.payload.toolCallId,
9930
- toolName: chunk.payload.toolName,
9931
- args: {
9932
- ...chunk.payload.args,
9933
- __mastraMetadata: {
9934
- ...chunk.payload.args?.__mastraMetadata,
9935
- isStreaming: true
9936
- }
9937
- }
9938
- }
9939
- ] : [
9940
- ...typeof lastMessage.content === "string" ? [{ type: "text", text: lastMessage.content }] : [],
9941
- {
9942
- type: "tool-call",
9943
- toolCallId: chunk.payload.toolCallId,
9944
- toolName: chunk.payload.toolName,
9945
- args: {
9946
- ...chunk.payload.args,
9947
- __mastraMetadata: {
9948
- ...chunk.payload.args?.__mastraMetadata,
9949
- isStreaming: true
9950
- }
9060
+ const lastMessage = conversation[conversation.length - 1];
9061
+ if (lastMessage && lastMessage.role === "assistant") {
9062
+ const updatedMessage = {
9063
+ ...lastMessage,
9064
+ content: Array.isArray(lastMessage.content) ? [
9065
+ ...lastMessage.content,
9066
+ {
9067
+ type: "tool-call",
9068
+ toolCallId: chunk.payload.toolCallId,
9069
+ toolName: chunk.payload.toolName,
9070
+ args: {
9071
+ ...chunk.payload.args,
9072
+ __mastraMetadata: {
9073
+ ...chunk.payload.args?.__mastraMetadata,
9074
+ isStreaming: true
9951
9075
  }
9952
9076
  }
9953
- ]
9954
- };
9955
- _sideEffects.assistantToolCallAddedForUpdater = true;
9956
- _sideEffects.assistantToolCallAddedForContent = true;
9957
- return [...currentConversation.slice(0, -1), updatedMessage];
9958
- }
9959
- const newMessage = {
9960
- role: "assistant",
9961
- content: [
9962
- { type: "text", text: _sideEffects.content },
9077
+ }
9078
+ ] : [
9079
+ ...typeof lastMessage.content === "string" ? [{ type: "text", text: lastMessage.content }] : [],
9963
9080
  {
9964
9081
  type: "tool-call",
9965
9082
  toolCallId: chunk.payload.toolCallId,
9966
9083
  toolName: chunk.payload.toolName,
9967
9084
  args: {
9968
9085
  ...chunk.payload.args,
9969
- __mastraMetadata: { ...chunk.payload.args?.__mastraMetadata, isStreaming: true }
9086
+ __mastraMetadata: {
9087
+ ...chunk.payload.args?.__mastraMetadata,
9088
+ isStreaming: true
9089
+ }
9970
9090
  }
9971
9091
  }
9972
9092
  ]
9973
9093
  };
9974
- _sideEffects.assistantToolCallAddedForUpdater = true;
9975
- _sideEffects.assistantToolCallAddedForContent = true;
9976
- return [...currentConversation, newMessage];
9977
- });
9978
- _sideEffects.toolCallIdToName.current[chunk.payload.toolCallId] = chunk.payload.toolName;
9979
- break;
9094
+ return [...conversation.slice(0, -1), updatedMessage];
9095
+ }
9096
+ const newMessage = {
9097
+ role: "assistant",
9098
+ content: [
9099
+ {
9100
+ type: "tool-call",
9101
+ toolCallId: chunk.payload.toolCallId,
9102
+ toolName: chunk.payload.toolName,
9103
+ args: {
9104
+ ...chunk.payload.args,
9105
+ __mastraMetadata: {
9106
+ ...chunk.payload.args?.__mastraMetadata,
9107
+ isStreaming: true
9108
+ }
9109
+ }
9110
+ }
9111
+ ]
9112
+ };
9113
+ return [...conversation, newMessage];
9980
9114
  }
9981
9115
  case "tool-result": {
9982
- setMessages((currentConversation) => {
9983
- const lastMessage = currentConversation[currentConversation.length - 1];
9984
- if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9985
- const updatedContent = lastMessage.content.map((part) => {
9986
- if (typeof part === "object" && part.type === "tool-call" && part.toolCallId === chunk.payload.toolCallId) {
9987
- return {
9988
- ...part,
9989
- result: chunk.payload.result
9990
- };
9991
- }
9992
- return part;
9993
- });
9994
- const updatedMessage = {
9995
- ...lastMessage,
9996
- content: updatedContent
9997
- };
9998
- return [...currentConversation.slice(0, -1), updatedMessage];
9999
- }
10000
- return currentConversation;
10001
- });
10002
- try {
10003
- const toolName = _sideEffects.toolCallIdToName.current[chunk.payload.toolCallId];
10004
- if (toolName === "updateWorkingMemory" && chunk.payload.result?.success) {
10005
- await refreshWorkingMemory?.();
10006
- }
10007
- } finally {
10008
- delete _sideEffects.toolCallIdToName.current[chunk.payload.toolCallId];
9116
+ const lastMessage = conversation[conversation.length - 1];
9117
+ if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9118
+ const updatedContent = lastMessage.content.map((part) => {
9119
+ if (typeof part === "object" && part.type === "tool-call" && part.toolCallId === chunk.payload.toolCallId) {
9120
+ return {
9121
+ ...part,
9122
+ result: chunk.payload.result
9123
+ };
9124
+ }
9125
+ return part;
9126
+ });
9127
+ const updatedMessage = {
9128
+ ...lastMessage,
9129
+ content: updatedContent
9130
+ };
9131
+ return [...conversation.slice(0, -1), updatedMessage];
10009
9132
  }
10010
- break;
9133
+ return [...conversation];
10011
9134
  }
10012
9135
  case "error": {
10013
9136
  if (typeof chunk.payload.error === "string") {
10014
9137
  throw new Error(chunk.payload.error);
10015
9138
  }
10016
- break;
9139
+ return [...conversation];
10017
9140
  }
10018
9141
  case "finish": {
10019
- handleFinishReason$1(chunk.payload.finishReason);
10020
- break;
9142
+ handleFinishReason$1(chunk.payload.stepResult.reason);
9143
+ return [...conversation];
10021
9144
  }
10022
9145
  case "reasoning-delta": {
10023
- setMessages((currentConversation) => {
10024
- const lastMessage = currentConversation[currentConversation.length - 1];
10025
- if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
10026
- const updatedContent = lastMessage.content.map((part) => {
10027
- if (typeof part === "object" && part.type === "reasoning") {
10028
- return {
10029
- ...part,
10030
- text: part.text + chunk.payload.text
10031
- };
10032
- }
10033
- return part;
10034
- });
10035
- const updatedMessage = {
10036
- ...lastMessage,
10037
- content: updatedContent
10038
- };
10039
- return [...currentConversation.slice(0, -1), updatedMessage];
10040
- }
10041
- const newMessage = {
10042
- role: "assistant",
10043
- content: [
10044
- {
10045
- type: "reasoning",
10046
- text: chunk.payload.text
10047
- },
10048
- { type: "text", text: _sideEffects.content }
10049
- ]
9146
+ const lastMessage = conversation[conversation.length - 1];
9147
+ if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9148
+ const updatedContent = lastMessage.content.map((part) => {
9149
+ if (typeof part === "object" && part.type === "reasoning") {
9150
+ return {
9151
+ ...part,
9152
+ text: part.text + chunk.payload.text
9153
+ };
9154
+ }
9155
+ return part;
9156
+ });
9157
+ const updatedMessage = {
9158
+ ...lastMessage,
9159
+ content: updatedContent
10050
9160
  };
10051
- return [...currentConversation, newMessage];
10052
- });
10053
- break;
9161
+ return [...conversation.slice(0, -1), updatedMessage];
9162
+ }
9163
+ const newMessage = {
9164
+ role: "assistant",
9165
+ content: [
9166
+ {
9167
+ type: "reasoning",
9168
+ text: chunk.payload.text
9169
+ }
9170
+ ]
9171
+ };
9172
+ return [...conversation, newMessage];
10054
9173
  }
10055
9174
  }
10056
9175
  };
@@ -10060,15 +9179,179 @@ const handleFinishReason$1 = (finishReason) => {
10060
9179
  throw new Error("Stream finished with reason tool-calls, try increasing maxSteps");
10061
9180
  }
10062
9181
  };
10063
- const handleWorkflowChunk = ({ workflowChunk, setMessages, entityName }) => {
10064
- flushSync(() => {
10065
- setMessages((currentConversation) => {
10066
- const lastMessage = currentConversation[currentConversation.length - 1];
9182
+ const handleWorkflowChunk = ({
9183
+ workflowChunk,
9184
+ conversation,
9185
+ entityName
9186
+ }) => {
9187
+ const lastMessage = conversation[conversation.length - 1];
9188
+ const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
9189
+ const newMessage = {
9190
+ ...lastMessage,
9191
+ content: contentArray.map((part) => {
9192
+ if (part.type === "tool-call") {
9193
+ return {
9194
+ ...part,
9195
+ toolName: part?.entityName || entityName,
9196
+ args: {
9197
+ ...part.args,
9198
+ __mastraMetadata: {
9199
+ ...part.args?.__mastraMetadata,
9200
+ workflowFullState: mapWorkflowStreamChunkToWatchResult(
9201
+ part.args?.__mastraMetadata?.workflowFullState || {},
9202
+ workflowChunk
9203
+ ),
9204
+ isStreaming: true
9205
+ }
9206
+ }
9207
+ };
9208
+ }
9209
+ return part;
9210
+ })
9211
+ };
9212
+ return [...conversation.slice(0, -1), newMessage];
9213
+ };
9214
+ const handleAgentChunk = ({
9215
+ agentChunk,
9216
+ conversation,
9217
+ entityName
9218
+ }) => {
9219
+ switch (agentChunk.type) {
9220
+ case "tool-result": {
9221
+ const lastMessage = conversation[conversation.length - 1];
9222
+ const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
9223
+ const newMessage = {
9224
+ ...lastMessage,
9225
+ content: contentArray.map((part) => {
9226
+ if (part.type === "tool-call") {
9227
+ const messages = part.args?.__mastraMetadata?.messages || [];
9228
+ const next = {
9229
+ ...part,
9230
+ toolName: part?.entityName || entityName,
9231
+ args: {
9232
+ ...part.args,
9233
+ __mastraMetadata: {
9234
+ ...part.args?.__mastraMetadata,
9235
+ isStreaming: true,
9236
+ messages: [
9237
+ ...messages.slice(0, -1),
9238
+ {
9239
+ ...messages[messages.length - 1],
9240
+ type: "tool",
9241
+ toolName: agentChunk.payload.toolName,
9242
+ args: agentChunk.payload.args,
9243
+ toolOutput: agentChunk.payload.result
9244
+ }
9245
+ ]
9246
+ }
9247
+ }
9248
+ };
9249
+ return next;
9250
+ }
9251
+ return part;
9252
+ })
9253
+ };
9254
+ return [...conversation.slice(0, -1), newMessage];
9255
+ }
9256
+ case "tool-call": {
9257
+ const lastMessage = conversation[conversation.length - 1];
9258
+ const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
9259
+ const newMessage = {
9260
+ ...lastMessage,
9261
+ content: contentArray.map((part) => {
9262
+ if (part.type === "tool-call") {
9263
+ const messages = part.args?.__mastraMetadata?.messages || [];
9264
+ const next = {
9265
+ ...part,
9266
+ toolName: part?.entityName || entityName,
9267
+ args: {
9268
+ ...part.args,
9269
+ __mastraMetadata: {
9270
+ ...part.args?.__mastraMetadata,
9271
+ isStreaming: true,
9272
+ messages: [
9273
+ ...messages,
9274
+ {
9275
+ type: "tool",
9276
+ toolCallId: agentChunk.payload.toolCallId,
9277
+ toolName: agentChunk.payload.toolName,
9278
+ args: {
9279
+ ...agentChunk.payload.args,
9280
+ __mastraMetadata: {
9281
+ ...agentChunk.payload.args?.__mastraMetadata,
9282
+ isStreaming: true
9283
+ }
9284
+ }
9285
+ }
9286
+ ]
9287
+ }
9288
+ }
9289
+ };
9290
+ return next;
9291
+ }
9292
+ return part;
9293
+ })
9294
+ };
9295
+ return [...conversation.slice(0, -1), newMessage];
9296
+ }
9297
+ case "text-delta": {
9298
+ const lastMessage = conversation[conversation.length - 1];
9299
+ const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
9300
+ const newMessage = {
9301
+ ...lastMessage,
9302
+ content: contentArray.map((part) => {
9303
+ if (part.type === "tool-call") {
9304
+ const messages = part.args?.__mastraMetadata?.messages || [];
9305
+ const lastMastraMessage = messages[messages.length - 1];
9306
+ const nextMessages = lastMastraMessage?.type === "text" ? [
9307
+ ...messages.slice(0, -1),
9308
+ { type: "text", content: (lastMastraMessage?.content || "") + agentChunk.payload.text }
9309
+ ] : [...messages, { type: "text", content: agentChunk.payload.text }];
9310
+ return {
9311
+ ...part,
9312
+ toolName: part?.entityName || entityName,
9313
+ args: {
9314
+ ...part.args,
9315
+ __mastraMetadata: {
9316
+ ...part.args?.__mastraMetadata,
9317
+ isStreaming: true,
9318
+ messages: nextMessages
9319
+ }
9320
+ }
9321
+ };
9322
+ }
9323
+ return part;
9324
+ })
9325
+ };
9326
+ return [...conversation.slice(0, -1), newMessage];
9327
+ }
9328
+ case "tool-output": {
9329
+ if (!agentChunk.payload.output.type.startsWith("workflow-")) return [...conversation];
9330
+ const lastMessage = conversation[conversation.length - 1];
10067
9331
  const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
10068
9332
  const newMessage = {
10069
9333
  ...lastMessage,
10070
9334
  content: contentArray.map((part) => {
10071
9335
  if (part.type === "tool-call") {
9336
+ const messages = part.args?.__mastraMetadata?.messages || [];
9337
+ const lastMastraMessage = messages[messages.length - 1];
9338
+ const nextMessages = lastMastraMessage?.type === "tool" ? [
9339
+ ...messages.slice(0, -1),
9340
+ {
9341
+ ...lastMastraMessage,
9342
+ args: {
9343
+ ...agentChunk.payload.args,
9344
+ __mastraMetadata: {
9345
+ ...agentChunk.payload.args?.__mastraMetadata,
9346
+ workflowFullState: mapWorkflowStreamChunkToWatchResult(
9347
+ lastMastraMessage.args?.__mastraMetadata?.workflowFullState || {},
9348
+ agentChunk.payload.output
9349
+ ),
9350
+ isStreaming: true
9351
+ }
9352
+ }
9353
+ }
9354
+ ] : messages;
10072
9355
  return {
10073
9356
  ...part,
10074
9357
  toolName: part?.entityName || entityName,
@@ -10076,11 +9359,8 @@ const handleWorkflowChunk = ({ workflowChunk, setMessages, entityName }) => {
10076
9359
  ...part.args,
10077
9360
  __mastraMetadata: {
10078
9361
  ...part.args?.__mastraMetadata,
10079
- workflowFullState: mapWorkflowStreamChunkToWatchResult(
10080
- part.args?.__mastraMetadata?.workflowFullState || {},
10081
- workflowChunk
10082
- ),
10083
- isStreaming: true
9362
+ isStreaming: true,
9363
+ messages: nextMessages
10084
9364
  }
10085
9365
  }
10086
9366
  };
@@ -10088,216 +9368,42 @@ const handleWorkflowChunk = ({ workflowChunk, setMessages, entityName }) => {
10088
9368
  return part;
10089
9369
  })
10090
9370
  };
10091
- return [...currentConversation.slice(0, -1), newMessage];
10092
- });
10093
- });
10094
- };
10095
- const handleAgentChunk = ({ agentChunk, setMessages, entityName }) => {
10096
- switch (agentChunk.type) {
10097
- case "tool-result": {
10098
- setMessages((currentConversation) => {
10099
- const lastMessage = currentConversation[currentConversation.length - 1];
10100
- const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
10101
- const newMessage = {
10102
- ...lastMessage,
10103
- content: contentArray.map((part) => {
10104
- if (part.type === "tool-call") {
10105
- const messages = part.args?.__mastraMetadata?.messages || [];
10106
- const next = {
10107
- ...part,
10108
- toolName: part?.entityName || entityName,
10109
- args: {
10110
- ...part.args,
10111
- __mastraMetadata: {
10112
- ...part.args?.__mastraMetadata,
10113
- isStreaming: true,
10114
- messages: [
10115
- ...messages.slice(0, -1),
10116
- {
10117
- ...messages[messages.length - 1],
10118
- type: "tool",
10119
- toolName: agentChunk.payload.toolName,
10120
- args: agentChunk.payload.args,
10121
- toolOutput: agentChunk.payload.result
10122
- }
10123
- ]
10124
- }
10125
- }
10126
- };
10127
- return next;
10128
- }
10129
- return part;
10130
- })
10131
- };
10132
- return [...currentConversation.slice(0, -1), newMessage];
10133
- });
10134
- break;
10135
- }
10136
- case "tool-call": {
10137
- setMessages((currentConversation) => {
10138
- const lastMessage = currentConversation[currentConversation.length - 1];
10139
- const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
10140
- const newMessage = {
10141
- ...lastMessage,
10142
- content: contentArray.map((part) => {
10143
- if (part.type === "tool-call") {
10144
- const messages = part.args?.__mastraMetadata?.messages || [];
10145
- const next = {
10146
- ...part,
10147
- toolName: part?.entityName || entityName,
10148
- args: {
10149
- ...part.args,
10150
- __mastraMetadata: {
10151
- ...part.args?.__mastraMetadata,
10152
- isStreaming: true,
10153
- messages: [
10154
- ...messages,
10155
- {
10156
- type: "tool",
10157
- toolCallId: agentChunk.payload.toolCallId,
10158
- toolName: agentChunk.payload.toolName,
10159
- args: {
10160
- ...agentChunk.payload.args,
10161
- __mastraMetadata: {
10162
- ...agentChunk.payload.args?.__mastraMetadata,
10163
- isStreaming: true
10164
- }
10165
- }
10166
- }
10167
- ]
10168
- }
10169
- }
10170
- };
10171
- return next;
10172
- }
10173
- return part;
10174
- })
10175
- };
10176
- return [...currentConversation.slice(0, -1), newMessage];
10177
- });
10178
- break;
10179
- }
10180
- case "text-delta": {
10181
- setMessages((currentConversation) => {
10182
- const lastMessage = currentConversation[currentConversation.length - 1];
10183
- const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
10184
- const newMessage = {
10185
- ...lastMessage,
10186
- content: contentArray.map((part) => {
10187
- if (part.type === "tool-call") {
10188
- const messages = part.args?.__mastraMetadata?.messages || [];
10189
- const lastMastraMessage = messages[messages.length - 1];
10190
- const nextMessages = lastMastraMessage?.type === "text" ? [
10191
- ...messages.slice(0, -1),
10192
- { type: "text", content: (lastMastraMessage?.content || "") + agentChunk.payload.text }
10193
- ] : [...messages, { type: "text", content: agentChunk.payload.text }];
10194
- return {
10195
- ...part,
10196
- toolName: part?.entityName || entityName,
10197
- args: {
10198
- ...part.args,
10199
- __mastraMetadata: {
10200
- ...part.args?.__mastraMetadata,
10201
- isStreaming: true,
10202
- messages: nextMessages
10203
- }
10204
- }
10205
- };
10206
- }
10207
- return part;
10208
- })
10209
- };
10210
- return [...currentConversation.slice(0, -1), newMessage];
10211
- });
10212
- break;
10213
- }
10214
- case "tool-output": {
10215
- flushSync(() => {
10216
- setMessages((currentConversation) => {
10217
- if (!agentChunk.payload.output.type.startsWith("workflow-")) return currentConversation;
10218
- const lastMessage = currentConversation[currentConversation.length - 1];
10219
- const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
10220
- const newMessage = {
10221
- ...lastMessage,
10222
- content: contentArray.map((part) => {
10223
- if (part.type === "tool-call") {
10224
- const messages = part.args?.__mastraMetadata?.messages || [];
10225
- const lastMastraMessage = messages[messages.length - 1];
10226
- const nextMessages = lastMastraMessage?.type === "tool" ? [
10227
- ...messages.slice(0, -1),
10228
- {
10229
- ...lastMastraMessage,
10230
- args: {
10231
- ...agentChunk.payload.args,
10232
- __mastraMetadata: {
10233
- ...agentChunk.payload.args?.__mastraMetadata,
10234
- workflowFullState: mapWorkflowStreamChunkToWatchResult(
10235
- lastMastraMessage.args?.__mastraMetadata?.workflowFullState || {},
10236
- agentChunk.payload.output
10237
- ),
10238
- isStreaming: true
10239
- }
10240
- }
10241
- }
10242
- ] : messages;
10243
- return {
10244
- ...part,
10245
- toolName: part?.entityName || entityName,
10246
- args: {
10247
- ...part.args,
10248
- __mastraMetadata: {
10249
- ...part.args?.__mastraMetadata,
10250
- isStreaming: true,
10251
- messages: nextMessages
10252
- }
10253
- }
10254
- };
10255
- }
10256
- return part;
10257
- })
10258
- };
10259
- return [...currentConversation.slice(0, -1), newMessage];
10260
- });
10261
- });
10262
- break;
9371
+ return [...conversation.slice(0, -1), newMessage];
10263
9372
  }
9373
+ default:
9374
+ case "agent-execution-end":
9375
+ return [...conversation];
10264
9376
  }
10265
9377
  };
10266
9378
  const createRootToolAssistantMessage = ({
10267
9379
  chunk,
10268
9380
  entityName,
10269
- setMessages,
9381
+ conversation,
10270
9382
  runId,
10271
- _sideEffects,
10272
9383
  from,
10273
9384
  networkMetadata
10274
9385
  }) => {
10275
- setMessages((currentConversation) => {
10276
- if (!entityName || !runId) return currentConversation;
10277
- const newMessage = {
10278
- role: "assistant",
10279
- content: [
10280
- { type: "text", text: _sideEffects.content },
10281
- {
10282
- type: "tool-call",
10283
- toolCallId: runId,
10284
- toolName: entityName,
10285
- args: {
10286
- ...chunk?.payload?.args,
10287
- __mastraMetadata: {
10288
- from,
10289
- networkMetadata,
10290
- ...chunk.payload.args?.__mastraMetadata,
10291
- isStreaming: true
10292
- }
9386
+ if (!entityName || !runId) return [...conversation];
9387
+ const newMessage = {
9388
+ role: "assistant",
9389
+ content: [
9390
+ {
9391
+ type: "tool-call",
9392
+ toolCallId: runId,
9393
+ toolName: entityName,
9394
+ args: {
9395
+ ...chunk?.payload?.args,
9396
+ __mastraMetadata: {
9397
+ from,
9398
+ networkMetadata,
9399
+ ...chunk.payload.args?.__mastraMetadata,
9400
+ isStreaming: true
10293
9401
  }
10294
9402
  }
10295
- ]
10296
- };
10297
- _sideEffects.assistantToolCallAddedForUpdater = true;
10298
- _sideEffects.assistantToolCallAddedForContent = true;
10299
- return [...currentConversation, newMessage];
10300
- });
9403
+ }
9404
+ ]
9405
+ };
9406
+ return [...conversation, newMessage];
10301
9407
  };
10302
9408
 
10303
9409
  const convertMessage$1 = (message) => {
@@ -10346,6 +9452,60 @@ const convertToAIAttachments = async (attachments) => {
10346
9452
  });
10347
9453
  return Promise.all(promises);
10348
9454
  };
9455
+ const initializeMessageState = (initialMessages) => {
9456
+ const convertedMessages = initialMessages?.map((message) => {
9457
+ let content;
9458
+ try {
9459
+ content = JSON.parse(message.content);
9460
+ if (content.isNetwork) {
9461
+ return handleNetworkMessageFromMemory(content);
9462
+ }
9463
+ } catch (e) {
9464
+ }
9465
+ const attachmentsAsContentParts = (message.experimental_attachments || []).map((image) => ({
9466
+ type: image.contentType.startsWith(`image/`) ? "image" : image.contentType.startsWith(`audio/`) ? "audio" : "file",
9467
+ mimeType: image.contentType,
9468
+ image: image.url
9469
+ }));
9470
+ const formattedParts = (message.parts || []).map((part) => {
9471
+ if (part.type === "reasoning") {
9472
+ return {
9473
+ type: "reasoning",
9474
+ text: part.reasoning || part?.details?.filter((detail) => detail.type === "text")?.map((detail) => detail.text).join(" ")
9475
+ };
9476
+ }
9477
+ if (part.type === "tool-invocation") {
9478
+ if (part.toolInvocation.state === "result") {
9479
+ return {
9480
+ type: "tool-call",
9481
+ toolCallId: part.toolInvocation.toolCallId,
9482
+ toolName: part.toolInvocation.toolName,
9483
+ args: part.toolInvocation.args,
9484
+ result: part.toolInvocation.result
9485
+ };
9486
+ }
9487
+ }
9488
+ if (part.type === "file") {
9489
+ return {
9490
+ type: "file",
9491
+ mimeType: part.mimeType,
9492
+ data: part.data
9493
+ };
9494
+ }
9495
+ if (part.type === "text") {
9496
+ return {
9497
+ type: "text",
9498
+ text: part.text
9499
+ };
9500
+ }
9501
+ }).filter(Boolean);
9502
+ return {
9503
+ ...message,
9504
+ content: [...formattedParts, ...attachmentsAsContentParts]
9505
+ };
9506
+ }).filter(Boolean);
9507
+ return convertedMessages;
9508
+ };
10349
9509
  function MastraRuntimeProvider({
10350
9510
  children,
10351
9511
  agentId,
@@ -10358,8 +9518,17 @@ function MastraRuntimeProvider({
10358
9518
  modelVersion
10359
9519
  }) {
10360
9520
  const [isRunning, setIsRunning] = useState(false);
10361
- const [messages, setMessages] = useState([]);
10362
- const [currentThreadId, setCurrentThreadId] = useState(threadId);
9521
+ const {
9522
+ messages,
9523
+ setMessages,
9524
+ streamVNext,
9525
+ network,
9526
+ cancelRun,
9527
+ isRunning: isRunningStreamVNext
9528
+ } = useMastraChat({
9529
+ agentId,
9530
+ initializeMessages: () => memory ? initializeMessageState(initialMessages || []) : []
9531
+ });
10363
9532
  const { refetch: refreshWorkingMemory } = useWorkingMemory();
10364
9533
  const abortControllerRef = useRef(null);
10365
9534
  const {
@@ -10382,76 +9551,23 @@ function MastraRuntimeProvider({
10382
9551
  Object.entries(runtimeContext ?? {}).forEach(([key, value]) => {
10383
9552
  runtimeContextInstance.set(key, value);
10384
9553
  });
10385
- useEffect(() => {
10386
- const hasNewInitialMessages = initialMessages && initialMessages?.length > messages?.length;
10387
- if (messages.length === 0 || currentThreadId !== threadId || hasNewInitialMessages && currentThreadId === threadId) {
10388
- if (initialMessages && threadId && memory) {
10389
- const convertedMessages = initialMessages?.map((message) => {
10390
- let content;
10391
- try {
10392
- content = JSON.parse(message.content);
10393
- if (content.isNetwork) {
10394
- return handleNetworkMessageFromMemory(content);
10395
- }
10396
- } catch (e) {
10397
- }
10398
- const attachmentsAsContentParts = (message.experimental_attachments || []).map((image) => ({
10399
- type: image.contentType.startsWith(`image/`) ? "image" : image.contentType.startsWith(`audio/`) ? "audio" : "file",
10400
- mimeType: image.contentType,
10401
- image: image.url
10402
- }));
10403
- const formattedParts = (message.parts || []).map((part) => {
10404
- if (part.type === "reasoning") {
10405
- return {
10406
- type: "reasoning",
10407
- text: part.reasoning || part?.details?.filter((detail) => detail.type === "text")?.map((detail) => detail.text).join(" ")
10408
- };
10409
- }
10410
- if (part.type === "tool-invocation") {
10411
- if (part.toolInvocation.state === "result") {
10412
- return {
10413
- type: "tool-call",
10414
- toolCallId: part.toolInvocation.toolCallId,
10415
- toolName: part.toolInvocation.toolName,
10416
- args: part.toolInvocation.args,
10417
- result: part.toolInvocation.result
10418
- };
10419
- }
10420
- }
10421
- if (part.type === "file") {
10422
- return {
10423
- type: "file",
10424
- mimeType: part.mimeType,
10425
- data: part.data
10426
- };
10427
- }
10428
- if (part.type === "text") {
10429
- return {
10430
- type: "text",
10431
- text: part.text
10432
- };
10433
- }
10434
- }).filter(Boolean);
10435
- return {
10436
- ...message,
10437
- content: [...formattedParts, ...attachmentsAsContentParts]
10438
- };
10439
- }).filter(Boolean);
10440
- setMessages(convertedMessages);
10441
- setCurrentThreadId(threadId);
10442
- }
10443
- }
10444
- }, [initialMessages, threadId, memory]);
9554
+ const modelSettingsArgs = {
9555
+ frequencyPenalty,
9556
+ presencePenalty,
9557
+ maxRetries,
9558
+ temperature,
9559
+ topK,
9560
+ topP,
9561
+ maxTokens,
9562
+ instructions,
9563
+ providerOptions
9564
+ };
10445
9565
  const baseClient = useMastraClient();
10446
9566
  const onNew = async (message) => {
10447
9567
  if (message.content[0]?.type !== "text") throw new Error("Only text messages are supported");
10448
9568
  const attachments = await convertToAIAttachments(message.attachments);
10449
9569
  const input = message.content[0].text;
10450
- setMessages((currentConversation) => [
10451
- ...currentConversation,
10452
- { role: "user", content: input, attachments: message.attachments }
10453
- ]);
10454
- setIsRunning(true);
9570
+ setMessages((s) => [...s, { role: "user", content: input, attachments: message.attachments }]);
10455
9571
  const controller = new AbortController();
10456
9572
  abortControllerRef.current = controller;
10457
9573
  const clientWithAbort = new MastraClient({
@@ -10461,7 +9577,7 @@ function MastraRuntimeProvider({
10461
9577
  const agent = clientWithAbort.getAgent(agentId);
10462
9578
  try {
10463
9579
  let handleGenerateResponse = function(generatedResponse) {
10464
- if (generatedResponse.response && "messages" in generatedResponse.response) {
9580
+ if (generatedResponse.response && "messages" in generatedResponse.response && generatedResponse.response.messages) {
10465
9581
  const latestMessage = generatedResponse.response.messages.reduce(
10466
9582
  (acc, message2) => {
10467
9583
  const _content = Array.isArray(acc.content) ? acc.content : [];
@@ -10542,86 +9658,72 @@ function MastraRuntimeProvider({
10542
9658
  };
10543
9659
  if (modelVersion === "v2") {
10544
9660
  if (chatWithNetwork) {
10545
- const response = await agent.network({
10546
- messages: [
9661
+ let currentEntityId;
9662
+ await network({
9663
+ coreUserMessages: [
10547
9664
  {
10548
9665
  role: "user",
10549
9666
  content: input
10550
- }
9667
+ },
9668
+ ...attachments
10551
9669
  ],
10552
- maxSteps,
10553
- modelSettings: {
10554
- frequencyPenalty,
10555
- presencePenalty,
10556
- maxRetries,
10557
- maxOutputTokens: maxTokens,
10558
- temperature,
10559
- topK,
10560
- topP
10561
- },
10562
- runId: agentId,
10563
9670
  runtimeContext: runtimeContextInstance,
10564
- ...memory ? { thread: threadId, resourceId: agentId } : {}
10565
- });
10566
- const _sideEffects = {
10567
- assistantMessageAdded: false,
10568
- assistantToolCallAddedForUpdater: false,
10569
- assistantToolCallAddedForContent: false,
10570
- content: "",
10571
- toolCallIdToName
10572
- };
10573
- let currentEntityId;
10574
- await response.processDataStream({
10575
- onChunk: async (chunk) => {
9671
+ threadId,
9672
+ modelSettings: modelSettingsArgs,
9673
+ signal: controller.signal,
9674
+ onNetworkChunk: (chunk, conversation) => {
10576
9675
  if (chunk.type.startsWith("agent-execution-event-")) {
10577
9676
  const agentChunk = chunk.payload;
10578
- if (!currentEntityId) return;
10579
- await handleAgentChunk({ agentChunk, setMessages, entityName: currentEntityId });
9677
+ if (!currentEntityId) return conversation;
9678
+ return handleAgentChunk({ agentChunk, conversation, entityName: currentEntityId });
10580
9679
  } else if (chunk.type === "tool-execution-start") {
10581
- await handleStreamChunk({
9680
+ const { args: argsData } = chunk.payload;
9681
+ const nestedArgs = argsData.args || {};
9682
+ const mastraMetadata = argsData.__mastraMetadata || {};
9683
+ const selectionReason = argsData.selectionReason || "";
9684
+ return handleStreamChunk({
10582
9685
  chunk: {
10583
9686
  ...chunk,
10584
9687
  type: "tool-call",
10585
9688
  payload: {
10586
- ...chunk?.payload,
10587
- toolCallId: chunk?.payload?.args?.toolCallId,
10588
- toolName: chunk?.payload?.args?.toolName,
9689
+ ...chunk.payload,
9690
+ toolCallId: argsData.toolCallId || "unknown",
9691
+ toolName: argsData.toolName || "unknown",
10589
9692
  args: {
10590
- ...chunk?.payload?.args?.args,
9693
+ ...nestedArgs,
10591
9694
  __mastraMetadata: {
10592
- ...chunk?.payload?.args?.__mastraMetadata,
9695
+ ...mastraMetadata,
10593
9696
  networkMetadata: {
10594
- selectionReason: chunk?.payload?.args?.selectionReason || "",
10595
- input: chunk?.payload?.args?.args
9697
+ selectionReason,
9698
+ input: nestedArgs
10596
9699
  }
10597
9700
  }
10598
9701
  }
10599
9702
  }
10600
9703
  },
10601
- setMessages,
10602
- refreshWorkingMemory,
10603
- _sideEffects
9704
+ conversation
10604
9705
  });
10605
9706
  } else if (chunk.type === "tool-execution-end") {
10606
- await handleStreamChunk({
9707
+ const next = handleStreamChunk({
10607
9708
  chunk: { ...chunk, type: "tool-result" },
10608
- setMessages,
10609
- refreshWorkingMemory,
10610
- _sideEffects
9709
+ conversation
10611
9710
  });
9711
+ if (chunk.payload?.toolName === "updateWorkingMemory" && typeof chunk.payload.result === "object" && "success" in chunk.payload.result && chunk.payload.result?.success) {
9712
+ refreshWorkingMemory?.();
9713
+ }
9714
+ return next;
10612
9715
  } else if (chunk.type.startsWith("workflow-execution-event-")) {
10613
9716
  const workflowChunk = chunk.payload;
10614
- if (!currentEntityId) return;
10615
- await handleWorkflowChunk({ workflowChunk, setMessages, entityName: currentEntityId });
9717
+ if (!currentEntityId) return conversation;
9718
+ return handleWorkflowChunk({ workflowChunk, conversation, entityName: currentEntityId });
10616
9719
  } else if (chunk.type === "workflow-execution-start" || chunk.type === "agent-execution-start") {
10617
9720
  currentEntityId = chunk.payload?.args?.resourceId;
10618
9721
  const runId = chunk.payload.runId;
10619
- if (!currentEntityId || !runId) return;
10620
- createRootToolAssistantMessage({
9722
+ if (!currentEntityId || !runId) return conversation;
9723
+ return createRootToolAssistantMessage({
10621
9724
  entityName: currentEntityId,
10622
- setMessages,
9725
+ conversation,
10623
9726
  runId,
10624
- _sideEffects,
10625
9727
  chunk,
10626
9728
  from: chunk.type === "agent-execution-start" ? "AGENT" : "WORKFLOW",
10627
9729
  networkMetadata: {
@@ -10629,21 +9731,19 @@ function MastraRuntimeProvider({
10629
9731
  input: chunk?.payload?.args?.prompt
10630
9732
  }
10631
9733
  });
10632
- _sideEffects.toolCallIdToName.current[runId] = currentEntityId;
10633
9734
  } else if (chunk.type === "network-execution-event-step-finish") {
10634
- setMessages((currentConversation) => {
10635
- return [
10636
- ...currentConversation,
10637
- { role: "assistant", content: [{ type: "text", text: chunk?.payload?.result || "" }] }
10638
- ];
10639
- });
9735
+ return [
9736
+ ...conversation,
9737
+ { role: "assistant", content: [{ type: "text", text: chunk?.payload?.result || "" }] }
9738
+ ];
10640
9739
  } else {
10641
- await handleStreamChunk({ chunk, setMessages, refreshWorkingMemory, _sideEffects });
9740
+ return handleStreamChunk({ chunk, conversation });
10642
9741
  }
10643
9742
  }
10644
9743
  });
10645
9744
  } else {
10646
9745
  if (chatWithGenerateVNext) {
9746
+ setIsRunning(true);
10647
9747
  const response = await agent.generateVNext({
10648
9748
  messages: [
10649
9749
  {
@@ -10671,50 +9771,32 @@ function MastraRuntimeProvider({
10671
9771
  setIsRunning(false);
10672
9772
  return;
10673
9773
  } else {
10674
- const response = await agent.streamVNext({
10675
- messages: [
9774
+ await streamVNext({
9775
+ coreUserMessages: [
10676
9776
  {
10677
9777
  role: "user",
10678
9778
  content: input
10679
9779
  },
10680
9780
  ...attachments
10681
9781
  ],
10682
- runId: agentId,
10683
- modelSettings: {
10684
- frequencyPenalty,
10685
- presencePenalty,
10686
- maxRetries,
10687
- maxOutputTokens: maxTokens,
10688
- temperature,
10689
- topK,
10690
- topP
10691
- },
10692
- instructions,
10693
9782
  runtimeContext: runtimeContextInstance,
10694
- ...memory ? { threadId, resourceId: agentId } : {},
10695
- providerOptions
10696
- });
10697
- if (!response.body) {
10698
- throw new Error("No response body");
10699
- }
10700
- const _sideEffects = {
10701
- assistantMessageAdded: false,
10702
- assistantToolCallAddedForUpdater: false,
10703
- assistantToolCallAddedForContent: false,
10704
- content: "",
10705
- toolCallIdToName
10706
- };
10707
- await response.processDataStream({
10708
- onChunk: async (chunk) => {
10709
- await handleStreamChunk({ chunk, setMessages, refreshWorkingMemory, _sideEffects });
10710
- }
9783
+ threadId,
9784
+ modelSettings: modelSettingsArgs,
9785
+ onChunk: (chunk, conversation) => {
9786
+ const next = handleStreamChunk({ chunk, conversation });
9787
+ if (chunk.type === "tool-result" && chunk.payload?.toolName === "updateWorkingMemory" && typeof chunk.payload.result === "object" && "success" in chunk.payload.result && chunk.payload.result?.success) {
9788
+ refreshWorkingMemory?.();
9789
+ }
9790
+ return next;
9791
+ },
9792
+ signal: controller.signal
10711
9793
  });
10712
- setIsRunning(false);
10713
9794
  return;
10714
9795
  }
10715
9796
  }
10716
9797
  } else {
10717
9798
  if (chatWithGenerate) {
9799
+ setIsRunning(true);
10718
9800
  const generateResponse = await agent.generate({
10719
9801
  messages: [
10720
9802
  {
@@ -10829,6 +9911,7 @@ function MastraRuntimeProvider({
10829
9911
  return [...currentConversation.slice(0, -1), message2];
10830
9912
  });
10831
9913
  };
9914
+ setIsRunning(true);
10832
9915
  const response = await agent.stream({
10833
9916
  messages: [
10834
9917
  {
@@ -11008,11 +10091,12 @@ function MastraRuntimeProvider({
11008
10091
  abortControllerRef.current.abort();
11009
10092
  abortControllerRef.current = null;
11010
10093
  setIsRunning(false);
10094
+ cancelRun?.();
11011
10095
  }
11012
10096
  };
11013
10097
  const { adapters, isReady } = useAdapters(agentId);
11014
10098
  const runtime = useExternalStoreRuntime({
11015
- isRunning,
10099
+ isRunning: isRunning || isRunningStreamVNext,
11016
10100
  messages,
11017
10101
  convertMessage: convertMessage$1,
11018
10102
  onNew,
@@ -12233,6 +11317,7 @@ const MistralIcon = (props) => /* @__PURE__ */ jsxs(
12233
11317
 
12234
11318
  const providerMapToIcon = {
12235
11319
  "openai.chat": /* @__PURE__ */ jsx(OpenaiChatIcon, {}),
11320
+ "openai.responses": /* @__PURE__ */ jsx(OpenaiChatIcon, {}),
12236
11321
  "anthropic.chat": /* @__PURE__ */ jsx(AnthropicChatIcon, {}),
12237
11322
  "anthropic.messages": /* @__PURE__ */ jsx(AnthropicMessagesIcon, {}),
12238
11323
  AZURE: /* @__PURE__ */ jsx(AzureIcon, {}),
@@ -12264,17 +11349,34 @@ const columns$2 = [
12264
11349
  {
12265
11350
  header: "Model",
12266
11351
  accessorKey: "model",
12267
- size: 160,
11352
+ size: 300,
12268
11353
  cell: ({ row }) => {
12269
- return /* @__PURE__ */ jsx(Cell, { children: /* @__PURE__ */ jsx(
12270
- Badge$1,
12271
- {
12272
- variant: "default",
12273
- icon: providerMapToIcon[row.original.provider] || /* @__PURE__ */ jsx(OpenAIIcon, {}),
12274
- className: "truncate",
12275
- children: row.original.modelId || "N/A"
12276
- }
12277
- ) });
11354
+ return /* @__PURE__ */ jsxs(Cell, { children: [
11355
+ /* @__PURE__ */ jsx(
11356
+ Badge$1,
11357
+ {
11358
+ variant: "default",
11359
+ icon: providerMapToIcon[row.original.provider] || /* @__PURE__ */ jsx(OpenAIIcon, {}),
11360
+ className: "truncate",
11361
+ children: row.original.modelId || "N/A"
11362
+ }
11363
+ ),
11364
+ row.original.modelList && row.original.modelList.length > 1 ? /* @__PURE__ */ jsxs(Tooltip, { children: [
11365
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Badge$1, { variant: "info", className: "ml-2", children: [
11366
+ "+ ",
11367
+ row.original.modelList.length - 1,
11368
+ " more"
11369
+ ] }) }),
11370
+ /* @__PURE__ */ jsx(TooltipContent, { className: "bg-surface5 flex flex-col gap-2", children: row.original.modelList.slice(1).map((mdl) => /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
11371
+ Badge$1,
11372
+ {
11373
+ variant: "default",
11374
+ icon: providerMapToIcon[mdl.model.provider],
11375
+ children: mdl.model.modelId
11376
+ }
11377
+ ) }, mdl.id)) })
11378
+ ] }) : null
11379
+ ] });
12278
11380
  }
12279
11381
  },
12280
11382
  {
@@ -12307,7 +11409,8 @@ function AgentsTable({ agents, isLoading }) {
12307
11409
  repoUrl: void 0,
12308
11410
  tools: agent.tools,
12309
11411
  modelId: agent.modelId,
12310
- link: paths.agentLink(key)
11412
+ link: paths.agentLink(key),
11413
+ modelList: agent.modelList
12311
11414
  };
12312
11415
  }),
12313
11416
  [agents]
@@ -12323,10 +11426,10 @@ function AgentsTable({ agents, isLoading }) {
12323
11426
  if (rows.length === 0) {
12324
11427
  return /* @__PURE__ */ jsx(EmptyAgentsTable, {});
12325
11428
  }
12326
- return /* @__PURE__ */ jsx(ScrollableContainer, { children: /* @__PURE__ */ jsxs(Table$1, { children: [
11429
+ return /* @__PURE__ */ jsx(ScrollableContainer, { children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Table$1, { children: [
12327
11430
  /* @__PURE__ */ jsx(Thead, { className: "sticky top-0", children: ths.headers.map((header) => /* @__PURE__ */ jsx(Th, { style: { width: header.index === 0 ? "auto" : header.column.getSize() }, children: flexRender(header.column.columnDef.header, header.getContext()) }, header.id)) }),
12328
11431
  /* @__PURE__ */ jsx(Tbody, { children: rows.map((row) => /* @__PURE__ */ jsx(Row, { onClick: () => navigate(row.original.link), children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(React__default.Fragment, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id)) }, row.id)) })
12329
- ] }) });
11432
+ ] }) }) });
12330
11433
  }
12331
11434
  const AgentsTableSkeleton = () => /* @__PURE__ */ jsxs(Table$1, { children: [
12332
11435
  /* @__PURE__ */ jsxs(Thead, { children: [
@@ -14454,6 +13557,126 @@ const AgentMetadataModelSwitcher = ({
14454
13557
  ] });
14455
13558
  };
14456
13559
 
13560
+ const Switch = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
13561
+ SwitchPrimitives.Root,
13562
+ {
13563
+ className: cn(
13564
+ "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-mastra-bg-7 data-[state=unchecked]:bg-input",
13565
+ className
13566
+ ),
13567
+ ...props,
13568
+ ref,
13569
+ children: /* @__PURE__ */ jsx(
13570
+ SwitchPrimitives.Thumb,
13571
+ {
13572
+ className: cn(
13573
+ "pointer-events-none block h-4 w-4 rounded-full bg-white shadow-lg transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
13574
+ )
13575
+ }
13576
+ )
13577
+ }
13578
+ ));
13579
+ Switch.displayName = SwitchPrimitives.Root.displayName;
13580
+
13581
+ const AgentMetadataModelList = ({
13582
+ modelList,
13583
+ modelProviders,
13584
+ updateModelInModelList,
13585
+ reorderModelList
13586
+ }) => {
13587
+ const [modelConfigs, setModelConfigs] = useState(() => modelList);
13588
+ const handleDragEnd = (result) => {
13589
+ if (!result.destination) {
13590
+ return;
13591
+ }
13592
+ const items = Array.from(modelConfigs);
13593
+ const [reorderedItem] = items.splice(result.source.index, 1);
13594
+ items.splice(result.destination.index, 0, reorderedItem);
13595
+ setModelConfigs(items);
13596
+ reorderModelList({ reorderedModelIds: items.map((item) => item.id) });
13597
+ };
13598
+ const updateModel = (params) => {
13599
+ setModelConfigs(
13600
+ (prev) => prev.map(
13601
+ (modelConfig) => modelConfig.id === params.modelConfigId ? {
13602
+ ...modelConfig,
13603
+ enabled: params.enabled ?? modelConfig.enabled,
13604
+ maxRetries: params.maxRetries ?? modelConfig.maxRetries,
13605
+ model: {
13606
+ modelId: params.model?.modelId ?? modelConfig.model.modelId,
13607
+ provider: params.model?.provider ?? modelConfig.model.provider,
13608
+ modelVersion: modelConfig.model.modelVersion
13609
+ }
13610
+ } : modelConfig
13611
+ )
13612
+ );
13613
+ return updateModelInModelList(params);
13614
+ };
13615
+ return /* @__PURE__ */ jsx(DragDropContext, { onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx(Droppable, { droppableId: "model-list", children: (provided) => /* @__PURE__ */ jsxs("div", { ...provided.droppableProps, ref: provided.innerRef, className: "flex flex-col gap-2", children: [
13616
+ modelConfigs.map((modelConfig, index) => /* @__PURE__ */ jsx(Draggable, { draggableId: modelConfig.id, index, children: (provided2) => /* @__PURE__ */ jsx(
13617
+ "div",
13618
+ {
13619
+ ref: provided2.innerRef,
13620
+ ...provided2.draggableProps,
13621
+ ...provided2.dragHandleProps,
13622
+ style: provided2.draggableProps.style,
13623
+ children: /* @__PURE__ */ jsx(
13624
+ AgentMetadataModelListItem,
13625
+ {
13626
+ modelConfig,
13627
+ modelProviders,
13628
+ updateModelInModelList: updateModel
13629
+ }
13630
+ )
13631
+ }
13632
+ ) }, modelConfig.id)),
13633
+ provided.placeholder
13634
+ ] }) }) });
13635
+ };
13636
+ const AgentMetadataModelListItem = ({
13637
+ modelConfig,
13638
+ modelProviders,
13639
+ updateModelInModelList
13640
+ }) => {
13641
+ const [isEditingModel, setIsEditingModel] = useState(false);
13642
+ const [enabled, setEnabled] = useState(() => modelConfig.enabled);
13643
+ const providerIcon = providerMapToIcon[modelConfig.model.provider || "openai.chat"];
13644
+ return isEditingModel ? /* @__PURE__ */ jsx(
13645
+ AgentMetadataModelSwitcher,
13646
+ {
13647
+ defaultProvider: modelConfig.model.provider,
13648
+ defaultModel: modelConfig.model.modelId,
13649
+ updateModel: (params) => updateModelInModelList({ modelConfigId: modelConfig.id, model: params }),
13650
+ closeEditor: () => setIsEditingModel(false),
13651
+ modelProviders
13652
+ }
13653
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2 rounded-lg bg-background hover:bg-muted/50 transition-colors", children: [
13654
+ /* @__PURE__ */ jsx("div", { className: "text-icon3 cursor-grab active:cursor-grabbing", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(GripVertical, {}) }) }),
13655
+ /* @__PURE__ */ jsx(Badge$1, { icon: providerIcon, className: "font-medium", children: modelConfig.model.modelId || "N/A" }),
13656
+ /* @__PURE__ */ jsx(
13657
+ Switch,
13658
+ {
13659
+ checked: enabled,
13660
+ onCheckedChange: (checked) => {
13661
+ setEnabled(checked);
13662
+ updateModelInModelList({ modelConfigId: modelConfig.id, enabled: checked });
13663
+ }
13664
+ }
13665
+ ),
13666
+ /* @__PURE__ */ jsx(
13667
+ "button",
13668
+ {
13669
+ onClick: () => setIsEditingModel(true),
13670
+ className: "text-icon3 hover:text-icon6",
13671
+ title: "Edit model",
13672
+ type: "button",
13673
+ "aria-label": "Edit model",
13674
+ children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(EditIcon, {}) })
13675
+ }
13676
+ )
13677
+ ] });
13678
+ };
13679
+
14457
13680
  const AgentMetadataNetworkList = ({ agents }) => {
14458
13681
  const { Link, paths } = useLinkComponent();
14459
13682
  if (agents.length === 0) {
@@ -14467,7 +13690,9 @@ const AgentMetadata = ({
14467
13690
  promptSlot,
14468
13691
  hasMemoryEnabled,
14469
13692
  updateModel,
14470
- modelProviders
13693
+ modelProviders,
13694
+ updateModelInModelList,
13695
+ reorderModelList
14471
13696
  }) => {
14472
13697
  const [isEditingModel, setIsEditingModel] = useState(false);
14473
13698
  const providerIcon = providerMapToIcon[agent.provider || "openai.chat"];
@@ -14478,7 +13703,15 @@ const AgentMetadata = ({
14478
13703
  const agentWorkflows = agent.workflows ?? {};
14479
13704
  const workflows = Object.keys(agentWorkflows).map((key) => ({ id: key, ...agentWorkflows[key] }));
14480
13705
  return /* @__PURE__ */ jsxs(AgentMetadataWrapper, { children: [
14481
- /* @__PURE__ */ jsx(AgentMetadataSection, { title: "Model", children: isEditingModel ? /* @__PURE__ */ jsx(
13706
+ agent.modelList ? /* @__PURE__ */ jsx(AgentMetadataSection, { title: "Models", children: /* @__PURE__ */ jsx(
13707
+ AgentMetadataModelList,
13708
+ {
13709
+ modelList: agent.modelList,
13710
+ modelProviders,
13711
+ updateModelInModelList,
13712
+ reorderModelList
13713
+ }
13714
+ ) }) : /* @__PURE__ */ jsx(AgentMetadataSection, { title: "Model", children: isEditingModel ? /* @__PURE__ */ jsx(
14482
13715
  AgentMetadataModelSwitcher,
14483
13716
  {
14484
13717
  defaultProvider: agent.provider,
@@ -15981,10 +15214,11 @@ const ToolListInner = ({ toolsWithAgents }) => {
15981
15214
  const ToolEntity = ({ tool }) => {
15982
15215
  const linkRef = useRef(null);
15983
15216
  const { Link, paths } = useLinkComponent();
15217
+ const toolLink = tool.agents.length > 0 ? paths.agentToolLink(tool.agents[0].id, tool.id) : paths.toolLink(tool.id);
15984
15218
  return /* @__PURE__ */ jsxs(Entity, { onClick: () => linkRef.current?.click(), children: [
15985
15219
  /* @__PURE__ */ jsx(EntityIcon, { children: /* @__PURE__ */ jsx(ToolsIcon, { className: "group-hover/entity:text-[#ECB047]" }) }),
15986
15220
  /* @__PURE__ */ jsxs(EntityContent, { children: [
15987
- /* @__PURE__ */ jsx(EntityName, { children: /* @__PURE__ */ jsx(Link, { ref: linkRef, href: paths.toolLink(tool.id), children: tool.id }) }),
15221
+ /* @__PURE__ */ jsx(EntityName, { children: /* @__PURE__ */ jsx(Link, { ref: linkRef, href: toolLink, children: tool.id }) }),
15988
15222
  /* @__PURE__ */ jsx(EntityDescription, { children: tool.description }),
15989
15223
  /* @__PURE__ */ jsx("div", { className: "inline-flex flex-wrap gap-2 pt-4", children: tool.agents.map((agent) => {
15990
15224
  return /* @__PURE__ */ jsx(
@@ -19177,5 +18411,5 @@ const parseError = (error) => {
19177
18411
  }
19178
18412
  };
19179
18413
 
19180
- export { AgentChat, AgentCoinIcon, AgentEntityHeader, AgentEvals, AgentIcon, AgentMetadata, AgentMetadataList, AgentMetadataListEmpty, AgentMetadataListItem, AgentMetadataNetworkList, AgentMetadataPrompt, AgentMetadataScorerList, AgentMetadataSection, AgentMetadataToolList, AgentMetadataWorkflowList, AgentMetadataWrapper, AgentNetworkCoinIcon, AgentSettings, AgentSettingsContext, AgentSettingsProvider, AgentsTable, AgentsTableSkeleton, AiIcon, AlertDialog, ApiIcon, Badge$1 as Badge, BranchIcon, Breadcrumb, Button$1 as Button, Cell, ChatThreads, CheckIcon, ChevronIcon, Collapsible, CollapsibleContent, CollapsibleTrigger, CommitIcon, CrossIcon, Crumb, DarkLogo, DateTimeCell, DateTimePicker, DateTimePickerContent, DbIcon, DebugIcon, DefaultTrigger, DeploymentIcon, DividerIcon, DocsIcon, DynamicForm, EmptyAgentsTable, EmptyScorersTable, EmptyState, EmptyWorkflowsTable, Entity, EntityContent, EntityDescription, EntityHeader, EntityIcon, EntityMainHeader, EntityName, Entry, EntryCell, EntryList, EntryListItem, EntryListPageHeader, EntryListStatusCell, EntryListTextCell, EntryListToolbar, EnvIcon, EvaluatorCoinIcon, FiltersIcon, FolderIcon, FormActions, GithubCoinIcon, GithubIcon, GoogleIcon, Header, HeaderAction, HeaderGroup, HeaderTitle, HomeIcon, Icon, InfoIcon, InputField, JudgeIcon, Kbd, KeyValueList, LatencyIcon, LegacyWorkflowGraph, LegacyWorkflowTrigger, LinkComponentProvider, LogsIcon, MainContentContent, MainContentLayout, MastraClientProvider, MastraResizablePanel, McpCoinIcon, McpServerIcon, MemoryIcon, MemorySearch, NetworkContext, NetworkProvider, NetworkTable, NetworkTableEmpty, NetworkTableSkeleton, OpenAIIcon, PageHeader, PlaygroundQueryClient, PlaygroundTabs, PromptIcon, RadioGroup, RadioGroupField, RadioGroupItem, RepoIcon, Row, RuntimeContext, RuntimeContextWrapper, ScoreDialog, ScoreIcon, ScorersTable, ScorersTableSkeleton, ScoresTools, SearchField, Searchbar, SelectField, SettingsIcon, SideDialog, SideDialogCodeSection, SideDialogContent, SideDialogFooter, SideDialogFooterGroup, SideDialogHeader, SideDialogHeading, SideDialogKeyValueList, SideDialogSection, SideDialogTop, SlashIcon, SliderField, Tab, TabContent, TabList, Table$1 as Table, Tbody, TemplateFailure, TemplateForm, TemplateInfo, TemplateInstallation, TemplateSuccess, TemplatesList, TemplatesTools, TextAndIcon, TextareaField, Th, Thead, ThreadDeleteButton, ThreadInputProvider, ThreadItem, ThreadLink, ThreadList, Threads, ToolCoinIcon, ToolList, ToolListEmpty, ToolListSkeleton, ToolsIcon, TraceDialog, TraceIcon, TraceTimeline, TraceTimelineLegend, TraceTimelineSpan, TracesTools, TracesView, TracesViewSkeleton, TsIcon, Txt, TxtCell, UnitCell, VNextNetworkChat, VariablesIcon, WorkflowCoinIcon, WorkflowGraph, WorkflowIcon, WorkflowRunContext, WorkflowRunProvider, WorkflowRuns, WorkflowTable, WorkflowTableSkeleton, WorkflowTrigger, WorkingMemoryContext, WorkingMemoryProvider, allowedAiSpanAttributes, cleanString, convertWorkflowRunStateToWatchResult, formatDuration, formatHierarchicalSpans, formatOtelTimestamp, formatOtelTimestamp2, getColumnTemplate, getShortId, getSpanTypeUi, mapWorkflowStreamChunkToWatchResult, parseError, providerMapToIcon, spanTypePrefixes, transformKey, useAgentSettings, useCurrentRun, useExecuteWorkflow, useInView, useLegacyWorkflow, useLinkComponent, useMastraClient, usePlaygroundStore, usePolling, useResumeWorkflow, useScorer, useScorers, useScoresByEntityId, useScoresByScorerId, useSpeechRecognition, useThreadInput, useWatchWorkflow, useWorkflow, useWorkflowRuns, useWorkingMemory };
18414
+ export { AgentChat, AgentCoinIcon, AgentEntityHeader, AgentEvals, AgentIcon, AgentMetadata, AgentMetadataList, AgentMetadataListEmpty, AgentMetadataListItem, AgentMetadataNetworkList, AgentMetadataPrompt, AgentMetadataScorerList, AgentMetadataSection, AgentMetadataToolList, AgentMetadataWorkflowList, AgentMetadataWrapper, AgentNetworkCoinIcon, AgentSettings, AgentSettingsContext, AgentSettingsProvider, AgentsTable, AgentsTableSkeleton, AiIcon, AlertDialog, ApiIcon, Badge$1 as Badge, BranchIcon, Breadcrumb, Button$1 as Button, Cell, ChatThreads, CheckIcon, ChevronIcon, Collapsible, CollapsibleContent, CollapsibleTrigger, CommitIcon, CrossIcon, Crumb, DarkLogo, DateTimeCell, DateTimePicker, DateTimePickerContent, DbIcon, DebugIcon, DefaultTrigger, DeploymentIcon, DividerIcon, DocsIcon, DynamicForm, EmptyAgentsTable, EmptyScorersTable, EmptyState, EmptyWorkflowsTable, Entity, EntityContent, EntityDescription, EntityHeader, EntityIcon, EntityMainHeader, EntityName, Entry, EntryCell, EntryList, EntryListItem, EntryListPageHeader, EntryListStatusCell, EntryListTextCell, EntryListToolbar, EnvIcon, EvaluatorCoinIcon, FiltersIcon, FolderIcon, FormActions, GithubCoinIcon, GithubIcon, GoogleIcon, Header, HeaderAction, HeaderGroup, HeaderTitle, HomeIcon, Icon, InfoIcon, InputField, JudgeIcon, Kbd, KeyValueList, LatencyIcon, LinkComponentProvider, LogsIcon, MainContentContent, MainContentLayout, MastraClientProvider, MastraResizablePanel, McpCoinIcon, McpServerIcon, MemoryIcon, MemorySearch, NetworkContext, NetworkProvider, NetworkTable, NetworkTableEmpty, NetworkTableSkeleton, OpenAIIcon, PageHeader, PlaygroundQueryClient, PlaygroundTabs, PromptIcon, RadioGroup, RadioGroupField, RadioGroupItem, RepoIcon, Row, RuntimeContext, RuntimeContextWrapper, ScoreDialog, ScoreIcon, ScorersTable, ScorersTableSkeleton, ScoresTools, SearchField, Searchbar, SelectField, SettingsIcon, SideDialog, SideDialogCodeSection, SideDialogContent, SideDialogFooter, SideDialogFooterGroup, SideDialogHeader, SideDialogHeading, SideDialogKeyValueList, SideDialogSection, SideDialogTop, SlashIcon, SliderField, Tab, TabContent, TabList, Table$1 as Table, Tbody, TemplateFailure, TemplateForm, TemplateInfo, TemplateInstallation, TemplateSuccess, TemplatesList, TemplatesTools, TextAndIcon, TextareaField, Th, Thead, ThreadDeleteButton, ThreadInputProvider, ThreadItem, ThreadLink, ThreadList, Threads, ToolCoinIcon, ToolList, ToolListEmpty, ToolListSkeleton, ToolsIcon, TraceDialog, TraceIcon, TraceTimeline, TraceTimelineLegend, TraceTimelineSpan, TracesTools, TracesView, TracesViewSkeleton, TsIcon, Txt, TxtCell, UnitCell, VNextNetworkChat, VariablesIcon, WorkflowCoinIcon, WorkflowGraph, WorkflowIcon, WorkflowRunContext, WorkflowRunProvider, WorkflowRuns, WorkflowTable, WorkflowTableSkeleton, WorkflowTrigger, WorkingMemoryContext, WorkingMemoryProvider, allowedAiSpanAttributes, cleanString, convertWorkflowRunStateToWatchResult, formatDuration, formatHierarchicalSpans, formatOtelTimestamp, formatOtelTimestamp2, getColumnTemplate, getShortId, getSpanTypeUi, mapWorkflowStreamChunkToWatchResult, parseError, providerMapToIcon, spanTypePrefixes, transformKey, useAgentSettings, useCurrentRun, useInView, useLinkComponent, useMastraClient, usePlaygroundStore, usePolling, useScorer, useScorers, useScoresByEntityId, useScoresByScorerId, useSpeechRecognition, useThreadInput, useWorkflow, useWorkflowRuns, useWorkingMemory };
19181
18415
  //# sourceMappingURL=index.es.js.map