@mastra/playground-ui 6.2.2 → 6.2.3-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/index.cjs.js +1370 -2120
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.es.js +1275 -2019
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/src/components/assistant-ui/messages/assistant-message.d.ts +2 -1
  7. package/dist/src/components/assistant-ui/thread.d.ts +2 -1
  8. package/dist/src/components/ui/button.d.ts +1 -1
  9. package/dist/src/components/ui/command.d.ts +2 -2
  10. package/dist/src/components/ui/resizable.d.ts +1 -1
  11. package/dist/src/domains/agents/components/agent-chat.d.ts +1 -1
  12. package/dist/src/domains/agents/components/agent-metadata/agent-metadata-model-list.d.ts +17 -0
  13. package/dist/src/domains/agents/components/agent-metadata/agent-metadata.d.ts +4 -1
  14. package/dist/src/domains/agents/components/agent-table/types.d.ts +2 -1
  15. package/dist/src/domains/agents/components/provider-map-icon.d.ts +1 -0
  16. package/dist/src/domains/workflows/components/workflow-table/types.d.ts +0 -1
  17. package/dist/src/domains/workflows/components/workflow-table/workflow-table.d.ts +2 -3
  18. package/dist/src/domains/workflows/context/workflow-run-context.d.ts +0 -3
  19. package/dist/src/domains/workflows/index.d.ts +0 -2
  20. package/dist/src/domains/workflows/workflow/utils.d.ts +0 -10
  21. package/dist/src/hooks/use-workflows.d.ts +1 -45
  22. package/dist/src/index.d.ts +1 -1
  23. package/dist/src/services/stream-chunk-message.d.ts +9 -18
  24. package/dist/src/types.d.ts +9 -1
  25. package/package.json +9 -7
  26. package/dist/src/contexts/mastra-client-context.d.ts +0 -8
  27. package/dist/src/domains/workflows/context/legacy-workflow-nested-graph-context.d.ts +0 -13
  28. package/dist/src/domains/workflows/workflow/legacy-workflow-graph-inner.d.ts +0 -4
  29. package/dist/src/domains/workflows/workflow/legacy-workflow-graph.d.ts +0 -3
  30. package/dist/src/domains/workflows/workflow/legacy-workflow-nested-graph.d.ts +0 -5
  31. package/dist/src/domains/workflows/workflow/legacy-workflow-nested-node.d.ts +0 -11
  32. package/dist/src/domains/workflows/workflow/legacy-workflow-status.d.ts +0 -6
  33. package/dist/src/domains/workflows/workflow/legacy-workflow-trigger.d.ts +0 -4
package/dist/index.es.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import * as React from 'react';
3
- import React__default, { createContext, useContext, forwardRef, memo, useState, useEffect, useRef, useCallback, useMemo, Fragment as Fragment$1, isValidElement, useId, startTransition } from 'react';
4
- import { MastraClient } from '@mastra/client-js';
5
2
  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';
3
+ 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';
4
+ import * as React from 'react';
5
+ import React__default, { forwardRef, memo, useState, useEffect, useRef, useCallback, useMemo, createContext, useContext, Fragment as Fragment$1, isValidElement, useId, startTransition } from 'react';
7
6
  import { Slot } from '@radix-ui/react-slot';
8
7
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
9
8
  import { TooltipProvider as TooltipProvider$1 } from '@radix-ui/react-tooltip';
@@ -19,27 +18,27 @@ import { draculaInit } from '@uiw/codemirror-theme-dracula';
19
18
  import CodeMirror, { EditorView } from '@uiw/react-codemirror';
20
19
  import { toast } from 'sonner';
21
20
  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';
21
+ import { MarkerType, Handle, Position, useViewport, useReactFlow, Panel, useNodesState, useEdgesState, ReactFlow, Background, BackgroundVariant, ReactFlowProvider } from '@xyflow/react';
28
22
  import '@xyflow/react/dist/style.css';
29
23
  import Dagre from '@dagrejs/dagre';
30
24
  import { Highlight, themes } from 'prism-react-renderer';
31
25
  import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
32
26
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
27
+ import { C as Colors, I as IconColors } from './colors-DrbbnW3f.js';
33
28
  import prettier from 'prettier';
34
29
  import prettierPluginBabel from 'prettier/plugins/babel';
35
30
  import prettierPluginEstree from 'prettier/plugins/estree';
36
- import { C as Colors, I as IconColors } from './colors-DrbbnW3f.js';
31
+ import * as SliderPrimitive from '@radix-ui/react-slider';
37
32
  import jsonSchemaToZod from 'json-schema-to-zod';
38
33
  import { parse } from 'superjson';
39
34
  import z$2, { z, ZodObject, ZodIntersection } from 'zod';
35
+ import { CodeBlock } from 'react-code-block';
36
+ import { create } from 'zustand';
37
+ import { persist } from 'zustand/middleware';
40
38
  import { AutoForm as AutoForm$1, buildZodFieldConfig } from '@autoform/react';
41
39
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
42
40
  import { format, isValid, formatDate, formatDistanceToNow } from 'date-fns';
41
+ import { useDebouncedCallback } from 'use-debounce';
43
42
  import { DayPicker } from 'react-day-picker';
44
43
  import * as PopoverPrimitive from '@radix-ui/react-popover';
45
44
  import * as SelectPrimitive from '@radix-ui/react-select';
@@ -47,49 +46,27 @@ import { v4 } from '@lukeed/uuid';
47
46
  import * as LabelPrimitive from '@radix-ui/react-label';
48
47
  import { ZodProvider, getFieldConfigInZodStack, getDefaultValueInZodStack } from '@autoform/zod/v4';
49
48
  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
49
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
50
+ import { useMastraClient, useChat } from '@mastra/react';
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 { MastraClient } from '@mastra/client-js';
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';
66
68
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
67
69
 
68
- const createMastraClient = (baseUrl, mastraClientHeaders = {}) => {
69
- return new MastraClient({
70
- baseUrl: baseUrl || "",
71
- // only add the header if the baseUrl is not provided i.e it's a local dev environment
72
- headers: !baseUrl ? { ...mastraClientHeaders, "x-mastra-dev-playground": "true" } : mastraClientHeaders
73
- });
74
- };
75
-
76
- const MastraClientContext = createContext(void 0);
77
- const MastraClientProvider = ({
78
- children,
79
- baseUrl,
80
- headers
81
- }) => {
82
- const client = createMastraClient(baseUrl, headers);
83
- return /* @__PURE__ */ jsx(MastraClientContext.Provider, { value: { client }, children });
84
- };
85
- const useMastraClient = () => {
86
- const context = useContext(MastraClientContext);
87
- if (context === void 0) {
88
- throw new Error("useMastraClient must be used within a MastraClientProvider");
89
- }
90
- return context.client;
91
- };
92
-
93
70
  function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
94
71
 
95
72
  const falsyToString = (value)=>typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
@@ -4503,239 +4480,249 @@ const ToolBadge = ({ toolName, args, result, networkMetadata, toolOutput }) => {
4503
4480
  );
4504
4481
  };
4505
4482
 
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"
4483
+ function convertWorkflowRunStateToWatchResult(runState) {
4484
+ const runId = runState.runId;
4485
+ const steps = {};
4486
+ const context = runState.context || {};
4487
+ Object.entries(context).forEach(([stepId, stepResult]) => {
4488
+ if (stepId !== "input" && "status" in stepResult) {
4489
+ const result = stepResult;
4490
+ steps[stepId] = {
4491
+ status: result.status,
4492
+ output: "output" in result ? result.output : void 0,
4493
+ payload: "payload" in result ? result.payload : void 0,
4494
+ resumePayload: "resumePayload" in result ? result.resumePayload : void 0,
4495
+ error: "error" in result ? result.error : void 0,
4496
+ startedAt: "startedAt" in result ? result.startedAt : Date.now(),
4497
+ endedAt: "endedAt" in result ? result.endedAt : void 0,
4498
+ suspendedAt: "suspendedAt" in result ? result.suspendedAt : void 0,
4499
+ resumedAt: "resumedAt" in result ? result.resumedAt : void 0
4500
+ };
4518
4501
  }
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
4502
  });
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;
4503
+ const status = determineWorkflowStatus(steps);
4504
+ return {
4505
+ type: "watch",
4506
+ payload: {
4507
+ workflowState: {
4508
+ status,
4509
+ steps,
4510
+ result: runState.value,
4511
+ payload: context.input,
4512
+ error: void 0
4513
+ }
4514
+ },
4515
+ eventTimestamp: new Date(runState.timestamp),
4516
+ runId
4517
+ };
4518
+ }
4519
+ function determineWorkflowStatus(steps) {
4520
+ const stepStatuses = Object.values(steps).map((step) => step.status);
4521
+ if (stepStatuses.includes("failed")) {
4522
+ return "failed";
4523
+ }
4524
+ if (stepStatuses.includes("suspended")) {
4525
+ return "suspended";
4526
+ }
4527
+ if (stepStatuses.every((status) => status === "success")) {
4528
+ return "success";
4529
+ }
4530
+ return "running";
4531
+ }
4532
+ const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
4533
+ if (chunk.type === "workflow-start") {
4534
+ return {
4535
+ ...prev,
4536
+ runId: chunk.runId,
4537
+ eventTimestamp: /* @__PURE__ */ new Date(),
4538
+ payload: {
4539
+ ...prev?.payload || {},
4540
+ workflowState: {
4541
+ ...prev?.payload?.workflowState,
4542
+ status: "running",
4543
+ steps: {}
4554
4544
  }
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
4545
  }
4575
4546
  };
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
- );
4547
+ }
4548
+ if (chunk.type === "workflow-step-start") {
4549
+ const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
4550
+ return {
4551
+ ...prev,
4552
+ payload: {
4553
+ ...prev.payload,
4554
+ currentStep: {
4555
+ id: chunk.payload.id,
4556
+ ...chunk.payload
4557
+ },
4558
+ workflowState: {
4559
+ ...prev?.payload?.workflowState,
4560
+ steps: {
4561
+ ...prev?.payload?.workflowState?.steps,
4562
+ [chunk.payload.id]: {
4563
+ ...current || {},
4564
+ ...chunk.payload
4565
+ }
4566
+ }
4627
4567
  }
4628
- acc[key] = { ...value, output };
4629
- return acc;
4630
4568
  },
4631
- {}
4632
- );
4633
- const sanitizedRecord = {
4634
- ...record,
4635
- sanitizedOutput: record ? JSON.stringify({ ...record, results: formattedResults }, null, 2).slice(0, 5e4) : null
4569
+ eventTimestamp: /* @__PURE__ */ new Date()
4636
4570
  };
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
- };
4686
- 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");
4571
+ }
4572
+ if (chunk.type === "workflow-step-suspended") {
4573
+ const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
4574
+ return {
4575
+ ...prev,
4576
+ payload: {
4577
+ ...prev?.payload,
4578
+ currentStep: {
4579
+ id: chunk.payload.id,
4580
+ ...prev?.payload?.currentStep,
4581
+ ...chunk.payload
4582
+ },
4583
+ workflowState: {
4584
+ ...prev?.payload?.workflowState,
4585
+ status: "suspended",
4586
+ steps: {
4587
+ ...prev?.payload?.workflowState?.steps,
4588
+ [chunk.payload.id]: {
4589
+ ...current || {},
4590
+ ...chunk.payload
4591
+ }
4592
+ }
4723
4593
  }
4724
- }
4725
- if ("or" in group2) {
4726
- for (const subGroup of group2.or) {
4727
- recurse({ ...subGroup }, "or");
4594
+ },
4595
+ eventTimestamp: /* @__PURE__ */ new Date()
4596
+ };
4597
+ }
4598
+ if (chunk.type === "workflow-step-waiting") {
4599
+ const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
4600
+ return {
4601
+ ...prev,
4602
+ payload: {
4603
+ ...prev?.payload,
4604
+ currentStep: {
4605
+ id: chunk.payload.id,
4606
+ ...prev?.payload?.currentStep || {},
4607
+ ...chunk.payload
4608
+ },
4609
+ workflowState: {
4610
+ ...prev?.payload?.workflowState,
4611
+ status: "waiting",
4612
+ steps: {
4613
+ ...prev?.payload?.workflowState?.steps,
4614
+ [chunk.payload.id]: {
4615
+ ...current,
4616
+ ...chunk.payload
4617
+ }
4618
+ }
4728
4619
  }
4729
- }
4730
- if ("not" in group2) {
4731
- recurse({ ...group2.not }, "not");
4732
- }
4733
- }
4620
+ },
4621
+ eventTimestamp: /* @__PURE__ */ new Date()
4622
+ };
4734
4623
  }
4735
- recurse(group);
4736
- return result.reverse();
4737
- }
4738
- const getLayoutedElements = (nodes, edges) => {
4624
+ if (chunk.type === "workflow-step-result") {
4625
+ const status = chunk.payload.status;
4626
+ const current = prev?.payload?.workflowState?.steps?.[chunk.payload.id] || {};
4627
+ const next = {
4628
+ ...prev,
4629
+ payload: {
4630
+ ...prev?.payload,
4631
+ currentStep: {
4632
+ id: chunk.payload.id,
4633
+ ...prev?.payload?.currentStep || {},
4634
+ ...chunk.payload
4635
+ },
4636
+ workflowState: {
4637
+ ...prev?.payload?.workflowState,
4638
+ status,
4639
+ steps: {
4640
+ ...prev?.payload?.workflowState?.steps,
4641
+ [chunk.payload.id]: {
4642
+ ...current,
4643
+ ...chunk.payload
4644
+ }
4645
+ }
4646
+ }
4647
+ },
4648
+ eventTimestamp: /* @__PURE__ */ new Date()
4649
+ };
4650
+ return next;
4651
+ }
4652
+ if (chunk.type === "workflow-canceled") {
4653
+ return {
4654
+ ...prev,
4655
+ payload: {
4656
+ ...prev?.payload,
4657
+ workflowState: {
4658
+ ...prev?.payload?.workflowState,
4659
+ status: "canceled"
4660
+ }
4661
+ },
4662
+ eventTimestamp: /* @__PURE__ */ new Date()
4663
+ };
4664
+ }
4665
+ if (chunk.type === "workflow-finish") {
4666
+ return {
4667
+ ...prev,
4668
+ payload: {
4669
+ ...prev?.payload,
4670
+ currentStep: void 0,
4671
+ workflowState: {
4672
+ ...prev?.payload?.workflowState,
4673
+ status: chunk.payload.workflowStatus
4674
+ }
4675
+ },
4676
+ eventTimestamp: /* @__PURE__ */ new Date()
4677
+ };
4678
+ }
4679
+ return prev;
4680
+ };
4681
+
4682
+ const WorkflowRunContext = createContext({});
4683
+ function WorkflowRunProvider({
4684
+ children,
4685
+ snapshot
4686
+ }) {
4687
+ const [result, setResult] = useState(
4688
+ () => snapshot ? convertWorkflowRunStateToWatchResult(snapshot) : null
4689
+ );
4690
+ const [payload, setPayload] = useState(null);
4691
+ const clearData = () => {
4692
+ setResult(null);
4693
+ setPayload(null);
4694
+ };
4695
+ useEffect(() => {
4696
+ if (snapshot?.runId) {
4697
+ setResult(convertWorkflowRunStateToWatchResult(snapshot));
4698
+ }
4699
+ }, [snapshot]);
4700
+ return /* @__PURE__ */ jsx(
4701
+ WorkflowRunContext.Provider,
4702
+ {
4703
+ value: {
4704
+ result,
4705
+ setResult,
4706
+ payload,
4707
+ setPayload,
4708
+ clearData,
4709
+ snapshot
4710
+ },
4711
+ children
4712
+ }
4713
+ );
4714
+ }
4715
+
4716
+ function Skeleton({ className, ...props }) {
4717
+ return /* @__PURE__ */ jsx("div", { className: cn("animate-pulse rounded-md bg-muted/50", className), ...props });
4718
+ }
4719
+
4720
+ const lodashTitleCase = (str) => {
4721
+ const camelCased = str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "").replace(/^(.)/, (char) => char.toLowerCase());
4722
+ return camelCased.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).trim();
4723
+ };
4724
+
4725
+ const getLayoutedElements = (nodes, edges) => {
4739
4726
  const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
4740
4727
  g.setGraph({ rankdir: "TB" });
4741
4728
  edges.forEach((edge) => g.setEdge(edge.source, edge.target));
@@ -4772,281 +4759,6 @@ const defaultEdgeOptions = {
4772
4759
  color: "#8e8e8e"
4773
4760
  }
4774
4761
  };
4775
- const contructLegacyNodesAndEdges = ({
4776
- stepGraph,
4777
- stepSubscriberGraph,
4778
- steps: mainSteps = {}
4779
- }) => {
4780
- if (!stepGraph) {
4781
- return { nodes: [], edges: [] };
4782
- }
4783
- const { initial, ...stepsList } = stepGraph;
4784
- if (!initial.length) {
4785
- return { nodes: [], edges: [] };
4786
- }
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
4847
- }
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 };
4863
- }
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;
4900
- }
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
- }
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;
4934
- }
4935
- }
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
- }
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
4974
- }
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
- }
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
5017
- }
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
- }
5045
- }
5046
- }
5047
- const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges);
5048
- return { nodes: layoutedNodes, edges: layoutedEdges };
5049
- };
5050
4762
  const getStepNodeAndEdge = ({
5051
4763
  stepFlow,
5052
4764
  xIndex,
@@ -5483,257 +5195,20 @@ const ScrollBar = React.forwardRef(({ className, orientation = "vertical", ...pr
5483
5195
  ));
5484
5196
  ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
5485
5197
 
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") {
5198
+ const useCurrentRun = () => {
5199
+ const context = useContext(WorkflowRunContext);
5200
+ const workflowCurrentSteps = context.result?.payload?.workflowState?.steps ?? {};
5201
+ const steps = Object.entries(workflowCurrentSteps).reduce((acc, [key, value]) => {
5537
5202
  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
5203
+ ...acc,
5204
+ [key]: {
5205
+ error: value.error,
5206
+ startedAt: value.startedAt,
5207
+ endedAt: value.endedAt,
5208
+ status: value.status,
5209
+ output: value.output,
5210
+ input: value.payload,
5211
+ resumeData: value.resumePayload
5737
5212
  }
5738
5213
  };
5739
5214
  }, {});
@@ -6288,23 +5763,84 @@ function Spinner({ color = "#fff", className }) {
6288
5763
  );
6289
5764
  }
6290
5765
 
6291
- function LegacyWorkflowNestedGraph({
5766
+ const Slider = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs(
5767
+ SliderPrimitive.Root,
5768
+ {
5769
+ ref,
5770
+ className: cn("relative flex w-full touch-none select-none items-center", className),
5771
+ ...props,
5772
+ children: [
5773
+ /* @__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" }) }),
5774
+ /* @__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" })
5775
+ ]
5776
+ }
5777
+ ));
5778
+ Slider.displayName = SliderPrimitive.Root.displayName;
5779
+
5780
+ const ZoomSlider = forwardRef(({ className, ...props }) => {
5781
+ const { zoom } = useViewport();
5782
+ const { zoomTo, zoomIn, zoomOut, fitView } = useReactFlow();
5783
+ return /* @__PURE__ */ jsxs(Panel, { className: cn("flex gap-1 rounded-md bg-primary-foreground p-1 text-foreground", className), ...props, children: [
5784
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomOut({ duration: 300 }), children: /* @__PURE__ */ jsx(Minus, { className: "h-4 w-4" }) }),
5785
+ /* @__PURE__ */ jsx(
5786
+ Slider,
5787
+ {
5788
+ className: "w-[140px]",
5789
+ value: [zoom],
5790
+ min: 0.01,
5791
+ max: 1,
5792
+ step: 0.01,
5793
+ onValueChange: (values) => {
5794
+ zoomTo(values[0]);
5795
+ }
5796
+ }
5797
+ ),
5798
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => zoomIn({ duration: 300 }), children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }) }),
5799
+ /* @__PURE__ */ jsxs(Button$2, { className: "min-w-20 tabular-nums", variant: "ghost", onClick: () => zoomTo(1, { duration: 300 }), children: [
5800
+ (100 * zoom).toFixed(0),
5801
+ "%"
5802
+ ] }),
5803
+ /* @__PURE__ */ jsx(Button$2, { variant: "ghost", size: "icon", onClick: () => fitView({ duration: 300, maxZoom: 1 }), children: /* @__PURE__ */ jsx(Maximize, { className: "h-4 w-4" }) })
5804
+ ] });
5805
+ });
5806
+ ZoomSlider.displayName = "ZoomSlider";
5807
+
5808
+ function WorkflowNestedGraph({
6292
5809
  stepGraph,
6293
- stepSubscriberGraph,
6294
- open
5810
+ open,
5811
+ workflowName,
5812
+ onShowTrace,
5813
+ onSendEvent
6295
5814
  }) {
6296
- const { nodes: initialNodes, edges: initialEdges } = contructLegacyNodesAndEdges({
6297
- stepGraph,
6298
- stepSubscriberGraph
5815
+ const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges({
5816
+ stepGraph
6299
5817
  });
6300
5818
  const [isMounted, setIsMounted] = useState(false);
6301
5819
  const [nodes, _, onNodesChange] = useNodesState(initialNodes);
6302
5820
  const [edges] = useEdgesState(initialEdges);
5821
+ const { steps } = useCurrentRun();
6303
5822
  const nodeTypes = {
6304
- "default-node": WorkflowDefaultNode,
5823
+ "default-node": (props) => /* @__PURE__ */ jsx(
5824
+ WorkflowDefaultNode,
5825
+ {
5826
+ parentWorkflowName: workflowName,
5827
+ onShowTrace,
5828
+ onSendEvent,
5829
+ ...props
5830
+ }
5831
+ ),
6305
5832
  "condition-node": WorkflowConditionNode,
6306
5833
  "after-node": WorkflowAfterNode,
6307
- "loop-result-node": WorkflowLoopResultNode
5834
+ "loop-result-node": WorkflowLoopResultNode,
5835
+ "nested-node": (props) => /* @__PURE__ */ jsx(
5836
+ WorkflowNestedNode,
5837
+ {
5838
+ parentWorkflowName: workflowName,
5839
+ onShowTrace,
5840
+ onSendEvent,
5841
+ ...props
5842
+ }
5843
+ )
6308
5844
  };
6309
5845
  useEffect(() => {
6310
5846
  if (open) {
@@ -6313,49 +5849,75 @@ function LegacyWorkflowNestedGraph({
6313
5849
  }, 500);
6314
5850
  }
6315
5851
  }, [open]);
6316
- return /* @__PURE__ */ jsx("div", { className: "w-full h-full relative", children: isMounted ? /* @__PURE__ */ jsxs(
5852
+ return /* @__PURE__ */ jsx("div", { className: "w-full h-full relative bg-surface1", children: isMounted ? /* @__PURE__ */ jsxs(
6317
5853
  ReactFlow,
6318
5854
  {
6319
5855
  nodes,
6320
- edges,
5856
+ edges: edges.map((e) => ({
5857
+ ...e,
5858
+ style: {
5859
+ ...e.style,
5860
+ 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
5861
+ }
5862
+ })),
6321
5863
  fitView: true,
6322
- fitViewOptions: { maxZoom: 0.85 },
6323
- nodeTypes,
6324
- onNodesChange,
6325
- children: [
6326
- /* @__PURE__ */ jsx(Controls, {}),
5864
+ fitViewOptions: {
5865
+ maxZoom: 1
5866
+ },
5867
+ minZoom: 0.01,
5868
+ maxZoom: 1,
5869
+ nodeTypes,
5870
+ onNodesChange,
5871
+ children: [
5872
+ /* @__PURE__ */ jsx(ZoomSlider, { position: "bottom-left" }),
6327
5873
  /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Lines, gap: 12, size: 0.5 })
6328
5874
  ]
6329
5875
  }
6330
5876
  ) : /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx(Spinner, {}) }) });
6331
5877
  }
6332
5878
 
6333
- const LegacyWorkflowNestedGraphContext = createContext(
5879
+ const WorkflowNestedGraphContext = createContext(
6334
5880
  {}
6335
5881
  );
6336
- function LegacyWorkflowNestedGraphProvider({ children }) {
5882
+ function WorkflowNestedGraphProvider({
5883
+ children,
5884
+ onShowTrace,
5885
+ onSendEvent
5886
+ }) {
6337
5887
  const [stepGraph, setStepGraph] = useState(null);
6338
- const [stepSubscriberGraph, setStepSubscriberGraph] = useState(null);
5888
+ const [parentStepGraphList, setParentStepGraphList] = useState([]);
6339
5889
  const [openDialog, setOpenDialog] = useState(false);
6340
5890
  const [label, setLabel] = useState("");
5891
+ const [fullStep, setFullStep] = useState("");
6341
5892
  const closeNestedGraph = () => {
6342
- setOpenDialog(false);
6343
- setStepGraph(null);
6344
- setStepSubscriberGraph(null);
6345
- setLabel("");
5893
+ if (parentStepGraphList.length) {
5894
+ const lastStepGraph = parentStepGraphList[parentStepGraphList.length - 1];
5895
+ setStepGraph(lastStepGraph.stepGraph);
5896
+ setLabel(lastStepGraph.label);
5897
+ setFullStep(lastStepGraph.fullStep);
5898
+ setParentStepGraphList(parentStepGraphList.slice(0, -1));
5899
+ } else {
5900
+ setOpenDialog(false);
5901
+ setStepGraph(null);
5902
+ setLabel("");
5903
+ setFullStep("");
5904
+ }
6346
5905
  };
6347
5906
  const showNestedGraph = ({
6348
- label: label2,
6349
- stepGraph: stepGraph2,
6350
- stepSubscriberGraph: stepSubscriberGraph2
5907
+ label: newLabel,
5908
+ stepGraph: newStepGraph,
5909
+ fullStep: newFullStep
6351
5910
  }) => {
6352
- setLabel(label2);
6353
- setStepGraph(stepGraph2);
6354
- setStepSubscriberGraph(stepSubscriberGraph2);
5911
+ if (stepGraph) {
5912
+ setParentStepGraphList([...parentStepGraphList, { stepGraph, label, fullStep }]);
5913
+ }
5914
+ setLabel(newLabel);
5915
+ setFullStep(newFullStep);
5916
+ setStepGraph(newStepGraph);
6355
5917
  setOpenDialog(true);
6356
5918
  };
6357
5919
  return /* @__PURE__ */ jsxs(
6358
- LegacyWorkflowNestedGraphContext.Provider,
5920
+ WorkflowNestedGraphContext.Provider,
6359
5921
  {
6360
5922
  value: {
6361
5923
  showNestedGraph,
@@ -6363,8 +5925,8 @@ function LegacyWorkflowNestedGraphProvider({ children }) {
6363
5925
  },
6364
5926
  children: [
6365
5927
  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: [
5928
+ /* @__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: [
5929
+ /* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-1.5 absolute top-3 left-3 z-50", children: [
6368
5930
  /* @__PURE__ */ jsx(Workflow, { className: "text-current w-4 h-4" }),
6369
5931
  /* @__PURE__ */ jsxs(Text, { size: "xs", weight: "medium", className: "text-mastra-el-6 capitalize", children: [
6370
5932
  label,
@@ -6372,77 +5934,131 @@ function LegacyWorkflowNestedGraphProvider({ children }) {
6372
5934
  ] })
6373
5935
  ] }),
6374
5936
  /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(
6375
- LegacyWorkflowNestedGraph,
5937
+ WorkflowNestedGraph,
6376
5938
  {
6377
5939
  stepGraph,
6378
5940
  open: openDialog,
6379
- stepSubscriberGraph
5941
+ workflowName: fullStep,
5942
+ onShowTrace,
5943
+ onSendEvent
6380
5944
  }
6381
5945
  ) })
6382
- ] }) }) })
5946
+ ] }) }) }, `${label}-${fullStep}`)
6383
5947
  ]
6384
5948
  }
6385
5949
  );
6386
5950
  }
6387
5951
 
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: [
5952
+ function WorkflowNestedNode({
5953
+ data,
5954
+ parentWorkflowName,
5955
+ onShowTrace,
5956
+ onSendEvent
5957
+ }) {
5958
+ const { steps, runId } = useCurrentRun();
5959
+ const { showNestedGraph } = useContext(WorkflowNestedGraphContext);
5960
+ const { label, description, withoutTopHandle, withoutBottomHandle, stepGraph, mapConfig, event } = data;
5961
+ const fullLabel = parentWorkflowName ? `${parentWorkflowName}.${label}` : label;
5962
+ const step = steps[fullLabel];
5963
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6392
5964
  !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
- ] }) }),
5965
+ /* @__PURE__ */ jsxs(
5966
+ "div",
5967
+ {
5968
+ className: cn(
5969
+ "bg-surface3 rounded-lg w-[274px] border-sm border-border1 pt-2",
5970
+ step?.status === "success" && "bg-accent1Darker",
5971
+ step?.status === "failed" && "bg-accent2Darker",
5972
+ step?.status === "suspended" && "bg-accent3Darker",
5973
+ step?.status === "waiting" && "bg-accent5Darker",
5974
+ step?.status === "running" && "bg-accent6Darker"
5975
+ ),
5976
+ children: [
5977
+ /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2 px-3", !description && "pb-2"), children: [
5978
+ /* @__PURE__ */ jsxs(Icon, { children: [
5979
+ step?.status === "failed" && /* @__PURE__ */ jsx(CrossIcon, { className: "text-accent2" }),
5980
+ step?.status === "success" && /* @__PURE__ */ jsx(CheckIcon, { className: "text-accent1" }),
5981
+ step?.status === "suspended" && /* @__PURE__ */ jsx(PauseIcon, { className: "text-accent3" }),
5982
+ step?.status === "waiting" && /* @__PURE__ */ jsx(HourglassIcon, { className: "text-accent5" }),
5983
+ step?.status === "running" && /* @__PURE__ */ jsx(Loader2, { className: "text-accent6 animate-spin" }),
5984
+ !step && /* @__PURE__ */ jsx(CircleDashed, { className: "text-icon2" })
5985
+ ] }),
5986
+ /* @__PURE__ */ jsxs(Txt, { variant: "ui-lg", className: "text-icon6 font-medium inline-flex items-center gap-1 justify-between w-full", children: [
5987
+ label,
5988
+ " ",
5989
+ step?.startedAt && /* @__PURE__ */ jsx(Clock, { startedAt: step.startedAt, endedAt: step.endedAt })
5990
+ ] })
5991
+ ] }),
5992
+ description && /* @__PURE__ */ jsx(Txt, { variant: "ui-sm", className: "text-icon3 px-3 pb-2", children: description }),
5993
+ /* @__PURE__ */ jsx(
5994
+ WorkflowStepActionBar,
5995
+ {
5996
+ stepName: label,
5997
+ input: step?.input,
5998
+ resumeData: step?.resumeData,
5999
+ output: step?.output,
6000
+ error: step?.error,
6001
+ mapConfig,
6002
+ onShowTrace: runId && onShowTrace ? () => onShowTrace?.({ runId, stepName: fullLabel }) : void 0,
6003
+ onShowNestedGraph: () => showNestedGraph({ label, fullStep: fullLabel, stepGraph }),
6004
+ onSendEvent,
6005
+ event: step?.status === "waiting" ? event : void 0,
6006
+ runId,
6007
+ status: step?.status
6008
+ }
6009
+ )
6010
+ ]
6011
+ }
6012
+ ),
6397
6013
  !withoutBottomHandle && /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Bottom, style: { visibility: "hidden" } })
6398
6014
  ] });
6399
6015
  }
6400
6016
 
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
- });
6017
+ function WorkflowGraphInner({ workflow, onShowTrace, onSendEvent }) {
6018
+ const { nodes: initialNodes, edges: initialEdges } = constructNodesAndEdges(workflow);
6407
6019
  const [nodes, _, onNodesChange] = useNodesState(initialNodes);
6408
6020
  const [edges] = useEdgesState(initialEdges);
6021
+ const { steps, runId } = useCurrentRun();
6409
6022
  const nodeTypes = {
6410
- "default-node": WorkflowDefaultNode,
6023
+ "default-node": (props) => /* @__PURE__ */ jsx(WorkflowDefaultNode, { onShowTrace, onSendEvent, ...props }),
6411
6024
  "condition-node": WorkflowConditionNode,
6412
6025
  "after-node": WorkflowAfterNode,
6413
6026
  "loop-result-node": WorkflowLoopResultNode,
6414
- "nested-node": LegacyWorkflowNestedNode
6027
+ "nested-node": (props) => /* @__PURE__ */ jsx(WorkflowNestedNode, { onShowTrace, onSendEvent, ...props })
6415
6028
  };
6416
- return /* @__PURE__ */ jsx("div", { className: "w-full h-full", children: /* @__PURE__ */ jsxs(
6029
+ return /* @__PURE__ */ jsx("div", { className: "w-full h-full bg-surface1", children: /* @__PURE__ */ jsxs(
6417
6030
  ReactFlow,
6418
6031
  {
6419
6032
  nodes,
6420
- edges,
6033
+ edges: edges.map((e) => ({
6034
+ ...e,
6035
+ style: {
6036
+ ...e.style,
6037
+ 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
6038
+ }
6039
+ })),
6421
6040
  nodeTypes,
6422
6041
  onNodesChange,
6423
6042
  fitView: true,
6424
6043
  fitViewOptions: {
6425
- maxZoom: 0.85
6044
+ maxZoom: 1
6426
6045
  },
6046
+ minZoom: 0.01,
6047
+ maxZoom: 1,
6427
6048
  children: [
6428
- /* @__PURE__ */ jsx(Controls, {}),
6049
+ /* @__PURE__ */ jsx(ZoomSlider, { position: "bottom-left" }),
6429
6050
  /* @__PURE__ */ jsx(Background, { variant: BackgroundVariant.Dots, gap: 12, size: 0.5 })
6430
6051
  ]
6431
6052
  }
6432
6053
  ) });
6433
6054
  }
6434
6055
 
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);
6056
+ function WorkflowGraph({ workflowId, onShowTrace, workflow, isLoading, onSendEvent }) {
6057
+ const { snapshot } = useContext(WorkflowRunContext);
6442
6058
  if (isLoading) {
6443
- return /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-[600px]" }) });
6059
+ return /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-full" }) });
6444
6060
  }
6445
- if (!legacyWorkflow) {
6061
+ if (!workflow) {
6446
6062
  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
6063
  /* @__PURE__ */ jsx(AlertCircleIcon, {}),
6448
6064
  /* @__PURE__ */ jsxs("div", { children: [
@@ -6452,9 +6068,95 @@ function LegacyWorkflowGraph({ workflowId }) {
6452
6068
  ] })
6453
6069
  ] }) });
6454
6070
  }
6455
- return /* @__PURE__ */ jsx(LegacyWorkflowNestedGraphProvider, { children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(LegacyWorkflowGraphInner, { workflow: legacyWorkflow }) }) });
6071
+ return /* @__PURE__ */ jsx(
6072
+ WorkflowNestedGraphProvider,
6073
+ {
6074
+ onShowTrace,
6075
+ onSendEvent,
6076
+ children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(
6077
+ WorkflowGraphInner,
6078
+ {
6079
+ workflow: snapshot?.serializedStepGraph ? { stepGraph: snapshot?.serializedStepGraph } : workflow,
6080
+ onShowTrace,
6081
+ onSendEvent
6082
+ }
6083
+ ) })
6084
+ },
6085
+ snapshot?.runId ?? workflowId
6086
+ );
6087
+ }
6088
+
6089
+ function resolveSerializedZodOutput(obj) {
6090
+ return Function("z", `"use strict";return (${obj});`)(z);
6091
+ }
6092
+
6093
+ function CodeBlockDemo({
6094
+ code = "",
6095
+ language = "ts",
6096
+ filename,
6097
+ className
6098
+ }) {
6099
+ return /* @__PURE__ */ jsxs(CodeBlock, { code, language, theme: themes.oneDark, children: [
6100
+ 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,
6101
+ /* @__PURE__ */ jsx(
6102
+ CodeBlock.Code,
6103
+ {
6104
+ className: cn("bg-transparent h-full p-6 rounded-xl whitespace-pre-wrap", filename ? "pt-10" : "", className),
6105
+ children: /* @__PURE__ */ jsx("div", { className: "table-row", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
6106
+ /* @__PURE__ */ jsx(CodeBlock.LineNumber, { className: "table-cell pr-4 text-sm text-right select-none text-gray-500/50" }),
6107
+ /* @__PURE__ */ jsx(CodeBlock.LineContent, { className: "flex", children: /* @__PURE__ */ jsx(CodeBlock.Token, { className: "font-mono text-sm mastra-token" }) })
6108
+ ] }) })
6109
+ }
6110
+ )
6111
+ ] });
6456
6112
  }
6457
6113
 
6114
+ const usePlaygroundStore = create()(
6115
+ persist(
6116
+ (set) => ({
6117
+ runtimeContext: {},
6118
+ setRuntimeContext: (runtimeContext) => set({ runtimeContext })
6119
+ }),
6120
+ {
6121
+ name: "mastra-playground-store"
6122
+ }
6123
+ )
6124
+ );
6125
+
6126
+ const WorkflowCard = ({ header, children, footer }) => {
6127
+ const [expanded, setExpanded] = useState(false);
6128
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border-sm border-border1 bg-surface4", children: [
6129
+ /* @__PURE__ */ jsxs("button", { className: "py-1 px-2 flex items-center gap-3 justify-between w-full", onClick: () => setExpanded((s) => !s), children: [
6130
+ /* @__PURE__ */ jsx("div", { className: "w-full", children: header }),
6131
+ /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: cn("text-icon3 transition-transform -rotate-90", expanded && "rotate-0") }) })
6132
+ ] }),
6133
+ children && expanded && /* @__PURE__ */ jsx("div", { className: "border-t-sm border-border1", children }),
6134
+ footer && /* @__PURE__ */ jsx("div", { className: "py-1 px-2 border-t-sm border-border1", children: footer })
6135
+ ] });
6136
+ };
6137
+
6138
+ const WorkflowStatus = ({ stepId, status, result }) => {
6139
+ return /* @__PURE__ */ jsx(
6140
+ WorkflowCard,
6141
+ {
6142
+ header: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
6143
+ /* @__PURE__ */ jsxs(Icon, { children: [
6144
+ status === "success" && /* @__PURE__ */ jsx(CheckIcon, { className: "text-accent1" }),
6145
+ status === "failed" && /* @__PURE__ */ jsx(CrossIcon, { className: "text-accent2" }),
6146
+ status === "suspended" && /* @__PURE__ */ jsx(CirclePause, { className: "text-accent3" }),
6147
+ status === "waiting" && /* @__PURE__ */ jsx(HourglassIcon, { className: "text-accent5" }),
6148
+ status === "running" && /* @__PURE__ */ jsx(Loader2, { className: "text-accent6 animate-spin" })
6149
+ ] }),
6150
+ /* @__PURE__ */ jsx(Txt, { as: "span", variant: "ui-lg", className: "text-icon6 font-medium", children: stepId.charAt(0).toUpperCase() + stepId.slice(1) })
6151
+ ] }),
6152
+ children: /* @__PURE__ */ jsxs("div", { className: "rounded-md bg-surface4 p-1 font-mono relative", children: [
6153
+ /* @__PURE__ */ jsx(CopyButton, { content: JSON.stringify(result, null, 2), className: "absolute top-2 right-2 z-10" }),
6154
+ /* @__PURE__ */ jsx(SyntaxHighlighter$1, { data: result })
6155
+ ] })
6156
+ }
6157
+ );
6158
+ };
6159
+
6458
6160
  const Form = React__default.forwardRef(({ children, ...props }, ref) => {
6459
6161
  return /* @__PURE__ */ jsx("form", { ref, className: "space-y-4", ...props, children });
6460
6162
  });
@@ -7288,591 +6990,11 @@ function DynamicForm({
7288
6990
  },
7289
6991
  formComponents: {
7290
6992
  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
- ] })
7873
- }
7874
- );
7875
- };
6993
+ },
6994
+ withSubmit: true
6995
+ };
6996
+ return /* @__PURE__ */ jsx(AutoForm, { ...formProps, readOnly });
6997
+ }
7876
6998
 
7877
6999
  const RadioGroup = React.forwardRef(({ className, ...props }, ref) => {
7878
7000
  return /* @__PURE__ */ jsx(RadioGroupPrimitive.Root, { className: cn("grid gap-2", className), ...props, ref });
@@ -8520,18 +7642,15 @@ const columns$3 = [
8520
7642
  id: "stepsCount",
8521
7643
  header: "Steps",
8522
7644
  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
- ] }) })
7645
+ 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: [
7646
+ row.original.stepsCount,
7647
+ " step",
7648
+ row.original.stepsCount > 1 ? "s" : ""
7649
+ ] }) }) })
8531
7650
  }
8532
7651
  ];
8533
7652
 
8534
- function WorkflowTable({ workflows, legacyWorkflows, isLoading }) {
7653
+ function WorkflowTable({ workflows, isLoading }) {
8535
7654
  const { navigate, paths } = useLinkComponent();
8536
7655
  const workflowData = useMemo(() => {
8537
7656
  const _workflowsData = Object.keys(workflows ?? {}).map((key) => {
@@ -8540,22 +7659,11 @@ function WorkflowTable({ workflows, legacyWorkflows, isLoading }) {
8540
7659
  id: key,
8541
7660
  name: workflow?.name || "N/A",
8542
7661
  stepsCount: Object.keys(workflow?.steps ?? {})?.length,
8543
- isLegacy: false,
8544
7662
  link: paths.workflowLink(key)
8545
7663
  };
8546
7664
  });
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
- link: paths.workflowLink(key)
8555
- };
8556
- });
8557
- return [..._workflowsData, ...legacyWorkflowsData];
8558
- }, [workflows, legacyWorkflows]);
7665
+ return _workflowsData;
7666
+ }, [workflows]);
8559
7667
  const table = useReactTable({
8560
7668
  data: workflowData,
8561
7669
  columns: columns$3,
@@ -8651,6 +7759,19 @@ const useWorkflowStream = (workflowFullState) => {
8651
7759
  }, [workflowFullState]);
8652
7760
  };
8653
7761
 
7762
+ const useWorkflow = (workflowId) => {
7763
+ const client = useMastraClient();
7764
+ const { runtimeContext } = usePlaygroundStore();
7765
+ return useQuery({
7766
+ queryKey: ["workflow", workflowId],
7767
+ queryFn: () => workflowId ? client.getWorkflow(workflowId).details(runtimeContext) : null,
7768
+ enabled: Boolean(workflowId),
7769
+ retry: false,
7770
+ refetchOnWindowFocus: false,
7771
+ throwOnError: false
7772
+ });
7773
+ };
7774
+
8654
7775
  const LoadingBadge = () => {
8655
7776
  return /* @__PURE__ */ jsx(
8656
7777
  BadgeWrapper,
@@ -8756,10 +7877,12 @@ const Reasoning = ({ text }) => {
8756
7877
  ] });
8757
7878
  };
8758
7879
 
8759
- const AssistantMessage = ({ ToolFallback: ToolFallbackCustom }) => {
7880
+ const AssistantMessage = ({ ToolFallback: ToolFallbackCustom, hasModelList }) => {
8760
7881
  const data = useMessage();
8761
7882
  const messageId = data.id;
8762
7883
  const isToolCallAndOrReasoning = data.content.every(({ type }) => type === "tool-call" || type === "reasoning");
7884
+ const modelMetadata = data.metadata?.custom?.modelMetadata;
7885
+ const showModelUsed = hasModelList && modelMetadata;
8763
7886
  return /* @__PURE__ */ jsxs(MessagePrimitive.Root, { className: "max-w-full", "data-message-id": messageId, children: [
8764
7887
  /* @__PURE__ */ jsx("div", { className: "text-icon6 text-ui-lg leading-ui-lg", children: /* @__PURE__ */ jsx(
8765
7888
  MessagePrimitive.Parts,
@@ -8771,7 +7894,17 @@ const AssistantMessage = ({ ToolFallback: ToolFallbackCustom }) => {
8771
7894
  }
8772
7895
  }
8773
7896
  ) }),
8774
- !isToolCallAndOrReasoning && /* @__PURE__ */ jsx("div", { className: "h-6 pt-1", children: /* @__PURE__ */ jsx(AssistantActionBar$1, {}) })
7897
+ !isToolCallAndOrReasoning && /* @__PURE__ */ jsxs("div", { className: cn("h-6 pt-1 flex gap-2 items-center", { "pb-1": showModelUsed }), children: [
7898
+ showModelUsed && /* @__PURE__ */ jsxs(Fragment, { children: [
7899
+ /* @__PURE__ */ jsx(BrainIcon, { className: "size-4" }),
7900
+ /* @__PURE__ */ jsxs("span", { className: "text-ui-sm leading-ui-sm text-icon6", children: [
7901
+ modelMetadata.modelProvider,
7902
+ "/",
7903
+ modelMetadata.modelId
7904
+ ] })
7905
+ ] }),
7906
+ /* @__PURE__ */ jsx(AssistantActionBar$1, {})
7907
+ ] })
8775
7908
  ] });
8776
7909
  };
8777
7910
  const AssistantActionBar$1 = () => {
@@ -9357,11 +8490,11 @@ const useThreadInput = () => {
9357
8490
  return useContext(ThreadInputContext);
9358
8491
  };
9359
8492
 
9360
- const Thread = ({ ToolFallback, agentName, agentId, hasMemory }) => {
8493
+ const Thread = ({ ToolFallback, agentName, agentId, hasMemory, hasModelList }) => {
9361
8494
  const areaRef = useRef(null);
9362
8495
  useAutoscroll(areaRef, { enabled: true });
9363
8496
  const WrappedAssistantMessage = (props) => {
9364
- return /* @__PURE__ */ jsx(AssistantMessage, { ...props, ToolFallback });
8497
+ return /* @__PURE__ */ jsx(AssistantMessage, { ...props, ToolFallback, hasModelList });
9365
8498
  };
9366
8499
  return /* @__PURE__ */ jsxs(ThreadWrapper$1, { children: [
9367
8500
  /* @__PURE__ */ jsxs(ThreadPrimitive.Viewport, { ref: areaRef, autoScroll: false, className: "overflow-y-scroll scroll-smooth h-full", children: [
@@ -9744,14 +8877,14 @@ const useAdapters = (agentId) => {
9744
8877
  };
9745
8878
 
9746
8879
  const handleNetworkMessageFromMemory = (content) => {
9747
- if (content.resourceType === "workflow") {
8880
+ if (content.primitiveType === "workflow") {
9748
8881
  return {
9749
8882
  role: "assistant",
9750
8883
  content: [
9751
8884
  {
9752
8885
  type: "tool-call",
9753
8886
  toolCallId: content.finalResult.runId,
9754
- toolName: content.resourceId,
8887
+ toolName: content.primitiveId,
9755
8888
  result: { runId: content.finalResult.runId },
9756
8889
  args: {
9757
8890
  __mastraMetadata: {
@@ -9766,7 +8899,7 @@ const handleNetworkMessageFromMemory = (content) => {
9766
8899
  ]
9767
8900
  };
9768
8901
  }
9769
- if (content.resourceType === "agent") {
8902
+ if (content.primitiveType === "agent") {
9770
8903
  const badgeMessages = [];
9771
8904
  let toolCalls = {};
9772
8905
  const messages = content.finalResult.messages.slice(1);
@@ -9804,7 +8937,7 @@ const handleNetworkMessageFromMemory = (content) => {
9804
8937
  {
9805
8938
  type: "tool-call",
9806
8939
  toolCallId: content.finalResult.runId,
9807
- toolName: content.resourceId,
8940
+ toolName: content.primitiveId,
9808
8941
  result: { runId: content.finalResult.runId },
9809
8942
  args: {
9810
8943
  __mastraMetadata: {
@@ -9820,14 +8953,14 @@ const handleNetworkMessageFromMemory = (content) => {
9820
8953
  ]
9821
8954
  };
9822
8955
  }
9823
- if (content.resourceType === "tool") {
8956
+ if (content.primitiveType === "tool") {
9824
8957
  return {
9825
8958
  role: "assistant",
9826
8959
  content: [
9827
8960
  {
9828
8961
  type: "tool-call",
9829
8962
  toolCallId: content.finalResult.toolCallId,
9830
- toolName: content.resourceId,
8963
+ toolName: content.primitiveId,
9831
8964
  result: content.finalResult.result,
9832
8965
  args: {
9833
8966
  ...content?.input,
@@ -9845,213 +8978,211 @@ const handleNetworkMessageFromMemory = (content) => {
9845
8978
  return { role: "assistant", content: [{ type: "text", text: "Unknown response" }] };
9846
8979
  };
9847
8980
 
9848
- const handleStreamChunk = async ({
9849
- chunk,
9850
- setMessages,
9851
- refreshWorkingMemory,
9852
- _sideEffects
9853
- }) => {
9854
- function updater() {
9855
- setMessages((currentConversation) => {
9856
- const message = {
8981
+ const handleStreamChunk = ({ chunk, conversation }) => {
8982
+ switch (chunk.type) {
8983
+ case "start": {
8984
+ const newMessage = {
9857
8985
  role: "assistant",
9858
- content: [{ type: "text", text: _sideEffects.content }]
8986
+ content: []
9859
8987
  };
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) {
8988
+ return [...conversation, newMessage];
8989
+ }
8990
+ case "text-start":
9875
8991
  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;
8992
+ const lastMessage = conversation[conversation.length - 1];
8993
+ if (!lastMessage) return conversation;
8994
+ if (lastMessage.role === "assistant" && typeof lastMessage.content !== `string` && (!lastMessage.content || lastMessage.content.length === 0 || lastMessage.content[lastMessage.content.length - 1]?.type !== `text`)) {
8995
+ return [
8996
+ ...conversation.slice(0, -1),
8997
+ {
8998
+ ...lastMessage,
8999
+ content: [...lastMessage.content || [], { type: "text", text: "" }]
9000
+ }
9001
+ ];
9002
+ }
9003
+ if (chunk.type === `text-start`) return conversation;
9004
+ if (typeof lastMessage.content === `string`) {
9005
+ return [
9006
+ ...conversation.slice(0, -1),
9007
+ {
9008
+ ...lastMessage,
9009
+ content: lastMessage.content + chunk.payload.text
9010
+ }
9011
+ ];
9881
9012
  }
9882
- updater();
9883
- break;
9013
+ const lastPart = lastMessage.content?.[lastMessage.content.length - 1];
9014
+ if (!lastPart || lastPart.type !== `text`) return conversation;
9015
+ return [
9016
+ ...conversation.slice(0, -1),
9017
+ {
9018
+ ...lastMessage,
9019
+ content: [...lastMessage.content.slice(0, -1), { ...lastPart, text: lastPart.text + chunk.payload.text }]
9020
+ }
9021
+ ];
9884
9022
  }
9885
9023
  case "tool-output": {
9886
9024
  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
- };
9025
+ return handleWorkflowChunk({
9026
+ workflowChunk: chunk.payload.output,
9027
+ conversation,
9028
+ entityName: chunk.payload.toolName
9029
+ });
9030
+ }
9031
+ const lastMessage = conversation[conversation.length - 1];
9032
+ if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9033
+ const updatedContent = lastMessage.content.map((part) => {
9034
+ if (typeof part === "object" && part.type === "tool-call" && part.toolCallId === chunk.payload.toolCallId) {
9035
+ const existingToolOutput = part.args?.__mastraMetadata?.toolOutput || [];
9036
+ return {
9037
+ ...part,
9038
+ args: {
9039
+ ...part.args,
9040
+ __mastraMetadata: {
9041
+ ...part.args?.__mastraMetadata,
9042
+ toolOutput: [...existingToolOutput, chunk?.payload?.output]
9043
+ }
9905
9044
  }
9906
- return part;
9907
- });
9908
- const updatedMessage = {
9909
- ...lastMessage,
9910
- content: updatedContent
9911
9045
  };
9912
- return [...currentConversation.slice(0, -1), updatedMessage];
9913
9046
  }
9914
- return currentConversation;
9047
+ return part;
9915
9048
  });
9049
+ const updatedMessage = {
9050
+ ...lastMessage,
9051
+ content: updatedContent
9052
+ };
9053
+ return [...conversation.slice(0, -1), updatedMessage];
9916
9054
  }
9917
- break;
9055
+ return [...conversation];
9918
9056
  }
9919
9057
  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
- }
9058
+ const lastMessage = conversation[conversation.length - 1];
9059
+ if (lastMessage && lastMessage.role === "assistant") {
9060
+ const updatedMessage = {
9061
+ ...lastMessage,
9062
+ content: Array.isArray(lastMessage.content) ? [
9063
+ ...lastMessage.content,
9064
+ {
9065
+ type: "tool-call",
9066
+ toolCallId: chunk.payload.toolCallId,
9067
+ toolName: chunk.payload.toolName,
9068
+ args: {
9069
+ ...chunk.payload.args,
9070
+ __mastraMetadata: {
9071
+ ...chunk.payload.args?.__mastraMetadata,
9072
+ isStreaming: true
9951
9073
  }
9952
9074
  }
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 },
9075
+ }
9076
+ ] : [
9077
+ ...typeof lastMessage.content === "string" ? [{ type: "text", text: lastMessage.content }] : [],
9963
9078
  {
9964
9079
  type: "tool-call",
9965
9080
  toolCallId: chunk.payload.toolCallId,
9966
9081
  toolName: chunk.payload.toolName,
9967
9082
  args: {
9968
9083
  ...chunk.payload.args,
9969
- __mastraMetadata: { ...chunk.payload.args?.__mastraMetadata, isStreaming: true }
9084
+ __mastraMetadata: {
9085
+ ...chunk.payload.args?.__mastraMetadata,
9086
+ isStreaming: true
9087
+ }
9970
9088
  }
9971
9089
  }
9972
9090
  ]
9973
9091
  };
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;
9092
+ return [...conversation.slice(0, -1), updatedMessage];
9093
+ }
9094
+ const newMessage = {
9095
+ role: "assistant",
9096
+ content: [
9097
+ {
9098
+ type: "tool-call",
9099
+ toolCallId: chunk.payload.toolCallId,
9100
+ toolName: chunk.payload.toolName,
9101
+ args: {
9102
+ ...chunk.payload.args,
9103
+ __mastraMetadata: {
9104
+ ...chunk.payload.args?.__mastraMetadata,
9105
+ isStreaming: true
9106
+ }
9107
+ }
9108
+ }
9109
+ ]
9110
+ };
9111
+ return [...conversation, newMessage];
9980
9112
  }
9981
9113
  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];
9114
+ const lastMessage = conversation[conversation.length - 1];
9115
+ if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9116
+ const updatedContent = lastMessage.content.map((part) => {
9117
+ if (typeof part === "object" && part.type === "tool-call" && part.toolCallId === chunk.payload.toolCallId) {
9118
+ return {
9119
+ ...part,
9120
+ result: chunk.payload.result
9121
+ };
9122
+ }
9123
+ return part;
9124
+ });
9125
+ const updatedMessage = {
9126
+ ...lastMessage,
9127
+ content: updatedContent
9128
+ };
9129
+ return [...conversation.slice(0, -1), updatedMessage];
10009
9130
  }
10010
- break;
9131
+ return [...conversation];
10011
9132
  }
10012
9133
  case "error": {
10013
9134
  if (typeof chunk.payload.error === "string") {
10014
9135
  throw new Error(chunk.payload.error);
10015
9136
  }
10016
- break;
9137
+ return [...conversation];
10017
9138
  }
10018
9139
  case "finish": {
10019
- handleFinishReason$1(chunk.payload.finishReason);
10020
- break;
9140
+ const lastMessage = conversation[conversation.length - 1];
9141
+ handleFinishReason$1(chunk.payload.stepResult.reason);
9142
+ if (lastMessage && lastMessage.role === "assistant") {
9143
+ const updatedMessage = {
9144
+ ...lastMessage,
9145
+ metadata: {
9146
+ custom: {
9147
+ modelMetadata: chunk.payload.metadata.modelMetadata
9148
+ }
9149
+ }
9150
+ };
9151
+ return [...conversation.slice(0, -1), updatedMessage];
9152
+ }
9153
+ return [...conversation];
10021
9154
  }
10022
9155
  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
- ]
9156
+ const lastMessage = conversation[conversation.length - 1];
9157
+ if (lastMessage && lastMessage.role === "assistant" && Array.isArray(lastMessage.content)) {
9158
+ const updatedContent = lastMessage.content.map((part) => {
9159
+ if (typeof part === "object" && part.type === "reasoning") {
9160
+ return {
9161
+ ...part,
9162
+ text: part.text + chunk.payload.text
9163
+ };
9164
+ }
9165
+ return part;
9166
+ });
9167
+ const updatedMessage = {
9168
+ ...lastMessage,
9169
+ content: updatedContent
10050
9170
  };
10051
- return [...currentConversation, newMessage];
10052
- });
10053
- break;
9171
+ return [...conversation.slice(0, -1), updatedMessage];
9172
+ }
9173
+ const newMessage = {
9174
+ role: "assistant",
9175
+ content: [
9176
+ {
9177
+ type: "reasoning",
9178
+ text: chunk.payload.text
9179
+ }
9180
+ ]
9181
+ };
9182
+ return [...conversation, newMessage];
10054
9183
  }
9184
+ default:
9185
+ return [...conversation];
10055
9186
  }
10056
9187
  };
10057
9188
  const handleFinishReason$1 = (finishReason) => {
@@ -10060,15 +9191,179 @@ const handleFinishReason$1 = (finishReason) => {
10060
9191
  throw new Error("Stream finished with reason tool-calls, try increasing maxSteps");
10061
9192
  }
10062
9193
  };
10063
- const handleWorkflowChunk = ({ workflowChunk, setMessages, entityName }) => {
10064
- flushSync(() => {
10065
- setMessages((currentConversation) => {
10066
- const lastMessage = currentConversation[currentConversation.length - 1];
9194
+ const handleWorkflowChunk = ({
9195
+ workflowChunk,
9196
+ conversation,
9197
+ entityName
9198
+ }) => {
9199
+ const lastMessage = conversation[conversation.length - 1];
9200
+ const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
9201
+ const newMessage = {
9202
+ ...lastMessage,
9203
+ content: contentArray.map((part) => {
9204
+ if (part.type === "tool-call") {
9205
+ return {
9206
+ ...part,
9207
+ toolName: part?.entityName || entityName,
9208
+ args: {
9209
+ ...part.args,
9210
+ __mastraMetadata: {
9211
+ ...part.args?.__mastraMetadata,
9212
+ workflowFullState: mapWorkflowStreamChunkToWatchResult(
9213
+ part.args?.__mastraMetadata?.workflowFullState || {},
9214
+ workflowChunk
9215
+ ),
9216
+ isStreaming: true
9217
+ }
9218
+ }
9219
+ };
9220
+ }
9221
+ return part;
9222
+ })
9223
+ };
9224
+ return [...conversation.slice(0, -1), newMessage];
9225
+ };
9226
+ const handleAgentChunk = ({
9227
+ agentChunk,
9228
+ conversation,
9229
+ entityName
9230
+ }) => {
9231
+ switch (agentChunk.type) {
9232
+ case "tool-result": {
9233
+ const lastMessage = conversation[conversation.length - 1];
9234
+ const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
9235
+ const newMessage = {
9236
+ ...lastMessage,
9237
+ content: contentArray.map((part) => {
9238
+ if (part.type === "tool-call") {
9239
+ const messages = part.args?.__mastraMetadata?.messages || [];
9240
+ const next = {
9241
+ ...part,
9242
+ toolName: part?.entityName || entityName,
9243
+ args: {
9244
+ ...part.args,
9245
+ __mastraMetadata: {
9246
+ ...part.args?.__mastraMetadata,
9247
+ isStreaming: true,
9248
+ messages: [
9249
+ ...messages.slice(0, -1),
9250
+ {
9251
+ ...messages[messages.length - 1],
9252
+ type: "tool",
9253
+ toolName: agentChunk.payload.toolName,
9254
+ args: agentChunk.payload.args,
9255
+ toolOutput: agentChunk.payload.result
9256
+ }
9257
+ ]
9258
+ }
9259
+ }
9260
+ };
9261
+ return next;
9262
+ }
9263
+ return part;
9264
+ })
9265
+ };
9266
+ return [...conversation.slice(0, -1), newMessage];
9267
+ }
9268
+ case "tool-call": {
9269
+ const lastMessage = conversation[conversation.length - 1];
9270
+ const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
9271
+ const newMessage = {
9272
+ ...lastMessage,
9273
+ content: contentArray.map((part) => {
9274
+ if (part.type === "tool-call") {
9275
+ const messages = part.args?.__mastraMetadata?.messages || [];
9276
+ const next = {
9277
+ ...part,
9278
+ toolName: part?.entityName || entityName,
9279
+ args: {
9280
+ ...part.args,
9281
+ __mastraMetadata: {
9282
+ ...part.args?.__mastraMetadata,
9283
+ isStreaming: true,
9284
+ messages: [
9285
+ ...messages,
9286
+ {
9287
+ type: "tool",
9288
+ toolCallId: agentChunk.payload.toolCallId,
9289
+ toolName: agentChunk.payload.toolName,
9290
+ args: {
9291
+ ...agentChunk.payload.args,
9292
+ __mastraMetadata: {
9293
+ ...agentChunk.payload.args?.__mastraMetadata,
9294
+ isStreaming: true
9295
+ }
9296
+ }
9297
+ }
9298
+ ]
9299
+ }
9300
+ }
9301
+ };
9302
+ return next;
9303
+ }
9304
+ return part;
9305
+ })
9306
+ };
9307
+ return [...conversation.slice(0, -1), newMessage];
9308
+ }
9309
+ case "text-delta": {
9310
+ const lastMessage = conversation[conversation.length - 1];
9311
+ const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
9312
+ const newMessage = {
9313
+ ...lastMessage,
9314
+ content: contentArray.map((part) => {
9315
+ if (part.type === "tool-call") {
9316
+ const messages = part.args?.__mastraMetadata?.messages || [];
9317
+ const lastMastraMessage = messages[messages.length - 1];
9318
+ const nextMessages = lastMastraMessage?.type === "text" ? [
9319
+ ...messages.slice(0, -1),
9320
+ { type: "text", content: (lastMastraMessage?.content || "") + agentChunk.payload.text }
9321
+ ] : [...messages, { type: "text", content: agentChunk.payload.text }];
9322
+ return {
9323
+ ...part,
9324
+ toolName: part?.entityName || entityName,
9325
+ args: {
9326
+ ...part.args,
9327
+ __mastraMetadata: {
9328
+ ...part.args?.__mastraMetadata,
9329
+ isStreaming: true,
9330
+ messages: nextMessages
9331
+ }
9332
+ }
9333
+ };
9334
+ }
9335
+ return part;
9336
+ })
9337
+ };
9338
+ return [...conversation.slice(0, -1), newMessage];
9339
+ }
9340
+ case "tool-output": {
9341
+ if (!agentChunk.payload.output.type.startsWith("workflow-")) return [...conversation];
9342
+ const lastMessage = conversation[conversation.length - 1];
10067
9343
  const contentArray = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
10068
9344
  const newMessage = {
10069
9345
  ...lastMessage,
10070
9346
  content: contentArray.map((part) => {
10071
9347
  if (part.type === "tool-call") {
9348
+ const messages = part.args?.__mastraMetadata?.messages || [];
9349
+ const lastMastraMessage = messages[messages.length - 1];
9350
+ const nextMessages = lastMastraMessage?.type === "tool" ? [
9351
+ ...messages.slice(0, -1),
9352
+ {
9353
+ ...lastMastraMessage,
9354
+ args: {
9355
+ ...agentChunk.payload.args,
9356
+ __mastraMetadata: {
9357
+ ...agentChunk.payload.args?.__mastraMetadata,
9358
+ workflowFullState: mapWorkflowStreamChunkToWatchResult(
9359
+ lastMastraMessage.args?.__mastraMetadata?.workflowFullState || {},
9360
+ agentChunk.payload.output
9361
+ ),
9362
+ isStreaming: true
9363
+ }
9364
+ }
9365
+ }
9366
+ ] : messages;
10072
9367
  return {
10073
9368
  ...part,
10074
9369
  toolName: part?.entityName || entityName,
@@ -10076,11 +9371,8 @@ const handleWorkflowChunk = ({ workflowChunk, setMessages, entityName }) => {
10076
9371
  ...part.args,
10077
9372
  __mastraMetadata: {
10078
9373
  ...part.args?.__mastraMetadata,
10079
- workflowFullState: mapWorkflowStreamChunkToWatchResult(
10080
- part.args?.__mastraMetadata?.workflowFullState || {},
10081
- workflowChunk
10082
- ),
10083
- isStreaming: true
9374
+ isStreaming: true,
9375
+ messages: nextMessages
10084
9376
  }
10085
9377
  }
10086
9378
  };
@@ -10088,216 +9380,42 @@ const handleWorkflowChunk = ({ workflowChunk, setMessages, entityName }) => {
10088
9380
  return part;
10089
9381
  })
10090
9382
  };
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;
9383
+ return [...conversation.slice(0, -1), newMessage];
10263
9384
  }
9385
+ default:
9386
+ case "agent-execution-end":
9387
+ return [...conversation];
10264
9388
  }
10265
9389
  };
10266
9390
  const createRootToolAssistantMessage = ({
10267
9391
  chunk,
10268
9392
  entityName,
10269
- setMessages,
9393
+ conversation,
10270
9394
  runId,
10271
- _sideEffects,
10272
9395
  from,
10273
9396
  networkMetadata
10274
9397
  }) => {
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
- }
9398
+ if (!entityName || !runId) return [...conversation];
9399
+ const newMessage = {
9400
+ role: "assistant",
9401
+ content: [
9402
+ {
9403
+ type: "tool-call",
9404
+ toolCallId: runId,
9405
+ toolName: entityName,
9406
+ args: {
9407
+ ...chunk?.payload?.args,
9408
+ __mastraMetadata: {
9409
+ from,
9410
+ networkMetadata,
9411
+ ...chunk.payload.args?.__mastraMetadata,
9412
+ isStreaming: true
10293
9413
  }
10294
9414
  }
10295
- ]
10296
- };
10297
- _sideEffects.assistantToolCallAddedForUpdater = true;
10298
- _sideEffects.assistantToolCallAddedForContent = true;
10299
- return [...currentConversation, newMessage];
10300
- });
9415
+ }
9416
+ ]
9417
+ };
9418
+ return [...conversation, newMessage];
10301
9419
  };
10302
9420
 
10303
9421
  const convertMessage$1 = (message) => {
@@ -10346,6 +9464,60 @@ const convertToAIAttachments = async (attachments) => {
10346
9464
  });
10347
9465
  return Promise.all(promises);
10348
9466
  };
9467
+ const initializeMessageState = (initialMessages) => {
9468
+ const convertedMessages = initialMessages?.map((message) => {
9469
+ let content;
9470
+ try {
9471
+ content = JSON.parse(message.content);
9472
+ if (content.isNetwork) {
9473
+ return handleNetworkMessageFromMemory(content);
9474
+ }
9475
+ } catch (e) {
9476
+ }
9477
+ const attachmentsAsContentParts = (message.experimental_attachments || []).map((image) => ({
9478
+ type: image.contentType.startsWith(`image/`) ? "image" : image.contentType.startsWith(`audio/`) ? "audio" : "file",
9479
+ mimeType: image.contentType,
9480
+ image: image.url
9481
+ }));
9482
+ const formattedParts = (message.parts || []).map((part) => {
9483
+ if (part.type === "reasoning") {
9484
+ return {
9485
+ type: "reasoning",
9486
+ text: part.reasoning || part?.details?.filter((detail) => detail.type === "text")?.map((detail) => detail.text).join(" ")
9487
+ };
9488
+ }
9489
+ if (part.type === "tool-invocation") {
9490
+ if (part.toolInvocation.state === "result") {
9491
+ return {
9492
+ type: "tool-call",
9493
+ toolCallId: part.toolInvocation.toolCallId,
9494
+ toolName: part.toolInvocation.toolName,
9495
+ args: part.toolInvocation.args,
9496
+ result: part.toolInvocation.result
9497
+ };
9498
+ }
9499
+ }
9500
+ if (part.type === "file") {
9501
+ return {
9502
+ type: "file",
9503
+ mimeType: part.mimeType,
9504
+ data: part.data
9505
+ };
9506
+ }
9507
+ if (part.type === "text") {
9508
+ return {
9509
+ type: "text",
9510
+ text: part.text
9511
+ };
9512
+ }
9513
+ }).filter(Boolean);
9514
+ return {
9515
+ ...message,
9516
+ content: [...formattedParts, ...attachmentsAsContentParts]
9517
+ };
9518
+ }).filter(Boolean);
9519
+ return convertedMessages;
9520
+ };
10349
9521
  function MastraRuntimeProvider({
10350
9522
  children,
10351
9523
  agentId,
@@ -10358,8 +9530,17 @@ function MastraRuntimeProvider({
10358
9530
  modelVersion
10359
9531
  }) {
10360
9532
  const [isRunning, setIsRunning] = useState(false);
10361
- const [messages, setMessages] = useState([]);
10362
- const [currentThreadId, setCurrentThreadId] = useState(threadId);
9533
+ const {
9534
+ messages,
9535
+ setMessages,
9536
+ streamVNext,
9537
+ network,
9538
+ cancelRun,
9539
+ isRunning: isRunningStreamVNext
9540
+ } = useChat({
9541
+ agentId,
9542
+ initializeMessages: () => memory ? initializeMessageState(initialMessages || []) : []
9543
+ });
10363
9544
  const { refetch: refreshWorkingMemory } = useWorkingMemory();
10364
9545
  const abortControllerRef = useRef(null);
10365
9546
  const {
@@ -10382,76 +9563,23 @@ function MastraRuntimeProvider({
10382
9563
  Object.entries(runtimeContext ?? {}).forEach(([key, value]) => {
10383
9564
  runtimeContextInstance.set(key, value);
10384
9565
  });
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]);
9566
+ const modelSettingsArgs = {
9567
+ frequencyPenalty,
9568
+ presencePenalty,
9569
+ maxRetries,
9570
+ temperature,
9571
+ topK,
9572
+ topP,
9573
+ maxTokens,
9574
+ instructions,
9575
+ providerOptions
9576
+ };
10445
9577
  const baseClient = useMastraClient();
10446
9578
  const onNew = async (message) => {
10447
9579
  if (message.content[0]?.type !== "text") throw new Error("Only text messages are supported");
10448
9580
  const attachments = await convertToAIAttachments(message.attachments);
10449
9581
  const input = message.content[0].text;
10450
- setMessages((currentConversation) => [
10451
- ...currentConversation,
10452
- { role: "user", content: input, attachments: message.attachments }
10453
- ]);
10454
- setIsRunning(true);
9582
+ setMessages((s) => [...s, { role: "user", content: input, attachments: message.attachments }]);
10455
9583
  const controller = new AbortController();
10456
9584
  abortControllerRef.current = controller;
10457
9585
  const clientWithAbort = new MastraClient({
@@ -10461,7 +9589,7 @@ function MastraRuntimeProvider({
10461
9589
  const agent = clientWithAbort.getAgent(agentId);
10462
9590
  try {
10463
9591
  let handleGenerateResponse = function(generatedResponse) {
10464
- if (generatedResponse.response && "messages" in generatedResponse.response) {
9592
+ if (generatedResponse.response && "messages" in generatedResponse.response && generatedResponse.response.messages) {
10465
9593
  const latestMessage = generatedResponse.response.messages.reduce(
10466
9594
  (acc, message2) => {
10467
9595
  const _content = Array.isArray(acc.content) ? acc.content : [];
@@ -10534,7 +9662,17 @@ function MastraRuntimeProvider({
10534
9662
  },
10535
9663
  { role: "assistant", content: [] }
10536
9664
  );
10537
- setMessages((currentConversation) => [...currentConversation, latestMessage]);
9665
+ setMessages((currentConversation) => [
9666
+ ...currentConversation,
9667
+ {
9668
+ ...latestMessage,
9669
+ metadata: {
9670
+ custom: {
9671
+ modelMetadata: generatedResponse.response.modelMetadata
9672
+ }
9673
+ }
9674
+ }
9675
+ ]);
10538
9676
  if (generatedResponse.finishReason) {
10539
9677
  handleFinishReason(generatedResponse.finishReason);
10540
9678
  }
@@ -10542,86 +9680,72 @@ function MastraRuntimeProvider({
10542
9680
  };
10543
9681
  if (modelVersion === "v2") {
10544
9682
  if (chatWithNetwork) {
10545
- const response = await agent.network({
10546
- messages: [
9683
+ let currentEntityId;
9684
+ await network({
9685
+ coreUserMessages: [
10547
9686
  {
10548
9687
  role: "user",
10549
9688
  content: input
10550
- }
9689
+ },
9690
+ ...attachments
10551
9691
  ],
10552
- maxSteps,
10553
- modelSettings: {
10554
- frequencyPenalty,
10555
- presencePenalty,
10556
- maxRetries,
10557
- maxOutputTokens: maxTokens,
10558
- temperature,
10559
- topK,
10560
- topP
10561
- },
10562
- runId: agentId,
10563
9692
  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) => {
9693
+ threadId,
9694
+ modelSettings: modelSettingsArgs,
9695
+ signal: controller.signal,
9696
+ onNetworkChunk: (chunk, conversation) => {
10576
9697
  if (chunk.type.startsWith("agent-execution-event-")) {
10577
9698
  const agentChunk = chunk.payload;
10578
- if (!currentEntityId) return;
10579
- await handleAgentChunk({ agentChunk, setMessages, entityName: currentEntityId });
9699
+ if (!currentEntityId) return conversation;
9700
+ return handleAgentChunk({ agentChunk, conversation, entityName: currentEntityId });
10580
9701
  } else if (chunk.type === "tool-execution-start") {
10581
- await handleStreamChunk({
9702
+ const { args: argsData } = chunk.payload;
9703
+ const nestedArgs = argsData.args || {};
9704
+ const mastraMetadata = argsData.__mastraMetadata || {};
9705
+ const selectionReason = argsData.selectionReason || "";
9706
+ return handleStreamChunk({
10582
9707
  chunk: {
10583
9708
  ...chunk,
10584
9709
  type: "tool-call",
10585
9710
  payload: {
10586
- ...chunk?.payload,
10587
- toolCallId: chunk?.payload?.args?.toolCallId,
10588
- toolName: chunk?.payload?.args?.toolName,
9711
+ ...chunk.payload,
9712
+ toolCallId: argsData.toolCallId || "unknown",
9713
+ toolName: argsData.toolName || "unknown",
10589
9714
  args: {
10590
- ...chunk?.payload?.args?.args,
9715
+ ...nestedArgs,
10591
9716
  __mastraMetadata: {
10592
- ...chunk?.payload?.args?.__mastraMetadata,
9717
+ ...mastraMetadata,
10593
9718
  networkMetadata: {
10594
- selectionReason: chunk?.payload?.args?.selectionReason || "",
10595
- input: chunk?.payload?.args?.args
9719
+ selectionReason,
9720
+ input: nestedArgs
10596
9721
  }
10597
9722
  }
10598
9723
  }
10599
9724
  }
10600
9725
  },
10601
- setMessages,
10602
- refreshWorkingMemory,
10603
- _sideEffects
9726
+ conversation
10604
9727
  });
10605
9728
  } else if (chunk.type === "tool-execution-end") {
10606
- await handleStreamChunk({
9729
+ const next = handleStreamChunk({
10607
9730
  chunk: { ...chunk, type: "tool-result" },
10608
- setMessages,
10609
- refreshWorkingMemory,
10610
- _sideEffects
9731
+ conversation
10611
9732
  });
9733
+ if (chunk.payload?.toolName === "updateWorkingMemory" && typeof chunk.payload.result === "object" && "success" in chunk.payload.result && chunk.payload.result?.success) {
9734
+ refreshWorkingMemory?.();
9735
+ }
9736
+ return next;
10612
9737
  } else if (chunk.type.startsWith("workflow-execution-event-")) {
10613
9738
  const workflowChunk = chunk.payload;
10614
- if (!currentEntityId) return;
10615
- await handleWorkflowChunk({ workflowChunk, setMessages, entityName: currentEntityId });
9739
+ if (!currentEntityId) return conversation;
9740
+ return handleWorkflowChunk({ workflowChunk, conversation, entityName: currentEntityId });
10616
9741
  } else if (chunk.type === "workflow-execution-start" || chunk.type === "agent-execution-start") {
10617
- currentEntityId = chunk.payload?.args?.resourceId;
9742
+ currentEntityId = chunk.payload?.args?.primitiveId;
10618
9743
  const runId = chunk.payload.runId;
10619
- if (!currentEntityId || !runId) return;
10620
- createRootToolAssistantMessage({
9744
+ if (!currentEntityId || !runId) return conversation;
9745
+ return createRootToolAssistantMessage({
10621
9746
  entityName: currentEntityId,
10622
- setMessages,
9747
+ conversation,
10623
9748
  runId,
10624
- _sideEffects,
10625
9749
  chunk,
10626
9750
  from: chunk.type === "agent-execution-start" ? "AGENT" : "WORKFLOW",
10627
9751
  networkMetadata: {
@@ -10629,21 +9753,19 @@ function MastraRuntimeProvider({
10629
9753
  input: chunk?.payload?.args?.prompt
10630
9754
  }
10631
9755
  });
10632
- _sideEffects.toolCallIdToName.current[runId] = currentEntityId;
10633
9756
  } 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
- });
9757
+ return [
9758
+ ...conversation,
9759
+ { role: "assistant", content: [{ type: "text", text: chunk?.payload?.result || "" }] }
9760
+ ];
10640
9761
  } else {
10641
- await handleStreamChunk({ chunk, setMessages, refreshWorkingMemory, _sideEffects });
9762
+ return handleStreamChunk({ chunk, conversation });
10642
9763
  }
10643
9764
  }
10644
9765
  });
10645
9766
  } else {
10646
9767
  if (chatWithGenerateVNext) {
9768
+ setIsRunning(true);
10647
9769
  const response = await agent.generateVNext({
10648
9770
  messages: [
10649
9771
  {
@@ -10671,50 +9793,32 @@ function MastraRuntimeProvider({
10671
9793
  setIsRunning(false);
10672
9794
  return;
10673
9795
  } else {
10674
- const response = await agent.streamVNext({
10675
- messages: [
9796
+ await streamVNext({
9797
+ coreUserMessages: [
10676
9798
  {
10677
9799
  role: "user",
10678
9800
  content: input
10679
9801
  },
10680
9802
  ...attachments
10681
9803
  ],
10682
- runId: agentId,
10683
- modelSettings: {
10684
- frequencyPenalty,
10685
- presencePenalty,
10686
- maxRetries,
10687
- maxOutputTokens: maxTokens,
10688
- temperature,
10689
- topK,
10690
- topP
10691
- },
10692
- instructions,
10693
9804
  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
- }
9805
+ threadId,
9806
+ modelSettings: modelSettingsArgs,
9807
+ onChunk: (chunk, conversation) => {
9808
+ const next = handleStreamChunk({ chunk, conversation });
9809
+ if (chunk.type === "tool-result" && chunk.payload?.toolName === "updateWorkingMemory" && typeof chunk.payload.result === "object" && "success" in chunk.payload.result && chunk.payload.result?.success) {
9810
+ refreshWorkingMemory?.();
9811
+ }
9812
+ return next;
9813
+ },
9814
+ signal: controller.signal
10711
9815
  });
10712
- setIsRunning(false);
10713
9816
  return;
10714
9817
  }
10715
9818
  }
10716
9819
  } else {
10717
9820
  if (chatWithGenerate) {
9821
+ setIsRunning(true);
10718
9822
  const generateResponse = await agent.generate({
10719
9823
  messages: [
10720
9824
  {
@@ -10829,6 +9933,7 @@ function MastraRuntimeProvider({
10829
9933
  return [...currentConversation.slice(0, -1), message2];
10830
9934
  });
10831
9935
  };
9936
+ setIsRunning(true);
10832
9937
  const response = await agent.stream({
10833
9938
  messages: [
10834
9939
  {
@@ -11008,11 +10113,12 @@ function MastraRuntimeProvider({
11008
10113
  abortControllerRef.current.abort();
11009
10114
  abortControllerRef.current = null;
11010
10115
  setIsRunning(false);
10116
+ cancelRun?.();
11011
10117
  }
11012
10118
  };
11013
10119
  const { adapters, isReady } = useAdapters(agentId);
11014
10120
  const runtime = useExternalStoreRuntime({
11015
- isRunning,
10121
+ isRunning: isRunning || isRunningStreamVNext,
11016
10122
  messages,
11017
10123
  convertMessage: convertMessage$1,
11018
10124
  onNew,
@@ -11094,7 +10200,8 @@ const AgentChat = ({
11094
10200
  initialMessages,
11095
10201
  memory,
11096
10202
  refreshThreadList,
11097
- modelVersion
10203
+ modelVersion,
10204
+ modelList
11098
10205
  }) => {
11099
10206
  const { settings } = useAgentSettings();
11100
10207
  const { runtimeContext } = usePlaygroundStore();
@@ -11110,7 +10217,7 @@ const AgentChat = ({
11110
10217
  refreshThreadList,
11111
10218
  settings,
11112
10219
  runtimeContext,
11113
- children: /* @__PURE__ */ jsx(Thread, { agentName: agentName ?? "", hasMemory: memory, agentId })
10220
+ children: /* @__PURE__ */ jsx(Thread, { agentName: agentName ?? "", hasMemory: memory, agentId, hasModelList: Boolean(modelList) })
11114
10221
  }
11115
10222
  );
11116
10223
  };
@@ -12233,6 +11340,7 @@ const MistralIcon = (props) => /* @__PURE__ */ jsxs(
12233
11340
 
12234
11341
  const providerMapToIcon = {
12235
11342
  "openai.chat": /* @__PURE__ */ jsx(OpenaiChatIcon, {}),
11343
+ "openai.responses": /* @__PURE__ */ jsx(OpenaiChatIcon, {}),
12236
11344
  "anthropic.chat": /* @__PURE__ */ jsx(AnthropicChatIcon, {}),
12237
11345
  "anthropic.messages": /* @__PURE__ */ jsx(AnthropicMessagesIcon, {}),
12238
11346
  AZURE: /* @__PURE__ */ jsx(AzureIcon, {}),
@@ -12264,17 +11372,34 @@ const columns$2 = [
12264
11372
  {
12265
11373
  header: "Model",
12266
11374
  accessorKey: "model",
12267
- size: 160,
11375
+ size: 300,
12268
11376
  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
- ) });
11377
+ return /* @__PURE__ */ jsxs(Cell, { children: [
11378
+ /* @__PURE__ */ jsx(
11379
+ Badge$1,
11380
+ {
11381
+ variant: "default",
11382
+ icon: providerMapToIcon[row.original.provider] || /* @__PURE__ */ jsx(OpenAIIcon, {}),
11383
+ className: "truncate",
11384
+ children: row.original.modelId || "N/A"
11385
+ }
11386
+ ),
11387
+ row.original.modelList && row.original.modelList.length > 1 ? /* @__PURE__ */ jsxs(Tooltip, { children: [
11388
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Badge$1, { variant: "info", className: "ml-2", children: [
11389
+ "+ ",
11390
+ row.original.modelList.length - 1,
11391
+ " more"
11392
+ ] }) }),
11393
+ /* @__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(
11394
+ Badge$1,
11395
+ {
11396
+ variant: "default",
11397
+ icon: providerMapToIcon[mdl.model.provider],
11398
+ children: mdl.model.modelId
11399
+ }
11400
+ ) }, mdl.id)) })
11401
+ ] }) : null
11402
+ ] });
12278
11403
  }
12279
11404
  },
12280
11405
  {
@@ -12307,7 +11432,8 @@ function AgentsTable({ agents, isLoading }) {
12307
11432
  repoUrl: void 0,
12308
11433
  tools: agent.tools,
12309
11434
  modelId: agent.modelId,
12310
- link: paths.agentLink(key)
11435
+ link: paths.agentLink(key),
11436
+ modelList: agent.modelList
12311
11437
  };
12312
11438
  }),
12313
11439
  [agents]
@@ -12323,10 +11449,10 @@ function AgentsTable({ agents, isLoading }) {
12323
11449
  if (rows.length === 0) {
12324
11450
  return /* @__PURE__ */ jsx(EmptyAgentsTable, {});
12325
11451
  }
12326
- return /* @__PURE__ */ jsx(ScrollableContainer, { children: /* @__PURE__ */ jsxs(Table$1, { children: [
11452
+ return /* @__PURE__ */ jsx(ScrollableContainer, { children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Table$1, { children: [
12327
11453
  /* @__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
11454
  /* @__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
- ] }) });
11455
+ ] }) }) });
12330
11456
  }
12331
11457
  const AgentsTableSkeleton = () => /* @__PURE__ */ jsxs(Table$1, { children: [
12332
11458
  /* @__PURE__ */ jsxs(Thead, { children: [
@@ -14454,6 +13580,126 @@ const AgentMetadataModelSwitcher = ({
14454
13580
  ] });
14455
13581
  };
14456
13582
 
13583
+ const Switch = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
13584
+ SwitchPrimitives.Root,
13585
+ {
13586
+ className: cn(
13587
+ "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",
13588
+ className
13589
+ ),
13590
+ ...props,
13591
+ ref,
13592
+ children: /* @__PURE__ */ jsx(
13593
+ SwitchPrimitives.Thumb,
13594
+ {
13595
+ className: cn(
13596
+ "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"
13597
+ )
13598
+ }
13599
+ )
13600
+ }
13601
+ ));
13602
+ Switch.displayName = SwitchPrimitives.Root.displayName;
13603
+
13604
+ const AgentMetadataModelList = ({
13605
+ modelList,
13606
+ modelProviders,
13607
+ updateModelInModelList,
13608
+ reorderModelList
13609
+ }) => {
13610
+ const [modelConfigs, setModelConfigs] = useState(() => modelList);
13611
+ const handleDragEnd = (result) => {
13612
+ if (!result.destination) {
13613
+ return;
13614
+ }
13615
+ const items = Array.from(modelConfigs);
13616
+ const [reorderedItem] = items.splice(result.source.index, 1);
13617
+ items.splice(result.destination.index, 0, reorderedItem);
13618
+ setModelConfigs(items);
13619
+ reorderModelList({ reorderedModelIds: items.map((item) => item.id) });
13620
+ };
13621
+ const updateModel = (params) => {
13622
+ setModelConfigs(
13623
+ (prev) => prev.map(
13624
+ (modelConfig) => modelConfig.id === params.modelConfigId ? {
13625
+ ...modelConfig,
13626
+ enabled: params.enabled ?? modelConfig.enabled,
13627
+ maxRetries: params.maxRetries ?? modelConfig.maxRetries,
13628
+ model: {
13629
+ modelId: params.model?.modelId ?? modelConfig.model.modelId,
13630
+ provider: params.model?.provider ?? modelConfig.model.provider,
13631
+ modelVersion: modelConfig.model.modelVersion
13632
+ }
13633
+ } : modelConfig
13634
+ )
13635
+ );
13636
+ return updateModelInModelList(params);
13637
+ };
13638
+ 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: [
13639
+ modelConfigs.map((modelConfig, index) => /* @__PURE__ */ jsx(Draggable, { draggableId: modelConfig.id, index, children: (provided2) => /* @__PURE__ */ jsx(
13640
+ "div",
13641
+ {
13642
+ ref: provided2.innerRef,
13643
+ ...provided2.draggableProps,
13644
+ ...provided2.dragHandleProps,
13645
+ style: provided2.draggableProps.style,
13646
+ children: /* @__PURE__ */ jsx(
13647
+ AgentMetadataModelListItem,
13648
+ {
13649
+ modelConfig,
13650
+ modelProviders,
13651
+ updateModelInModelList: updateModel
13652
+ }
13653
+ )
13654
+ }
13655
+ ) }, modelConfig.id)),
13656
+ provided.placeholder
13657
+ ] }) }) });
13658
+ };
13659
+ const AgentMetadataModelListItem = ({
13660
+ modelConfig,
13661
+ modelProviders,
13662
+ updateModelInModelList
13663
+ }) => {
13664
+ const [isEditingModel, setIsEditingModel] = useState(false);
13665
+ const [enabled, setEnabled] = useState(() => modelConfig.enabled);
13666
+ const providerIcon = providerMapToIcon[modelConfig.model.provider || "openai.chat"];
13667
+ return isEditingModel ? /* @__PURE__ */ jsx(
13668
+ AgentMetadataModelSwitcher,
13669
+ {
13670
+ defaultProvider: modelConfig.model.provider,
13671
+ defaultModel: modelConfig.model.modelId,
13672
+ updateModel: (params) => updateModelInModelList({ modelConfigId: modelConfig.id, model: params }),
13673
+ closeEditor: () => setIsEditingModel(false),
13674
+ modelProviders
13675
+ }
13676
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2 rounded-lg bg-background hover:bg-muted/50 transition-colors", children: [
13677
+ /* @__PURE__ */ jsx("div", { className: "text-icon3 cursor-grab active:cursor-grabbing", children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(GripVertical, {}) }) }),
13678
+ /* @__PURE__ */ jsx(Badge$1, { icon: providerIcon, className: "font-medium", children: modelConfig.model.modelId || "N/A" }),
13679
+ /* @__PURE__ */ jsx(
13680
+ Switch,
13681
+ {
13682
+ checked: enabled,
13683
+ onCheckedChange: (checked) => {
13684
+ setEnabled(checked);
13685
+ updateModelInModelList({ modelConfigId: modelConfig.id, enabled: checked });
13686
+ }
13687
+ }
13688
+ ),
13689
+ /* @__PURE__ */ jsx(
13690
+ "button",
13691
+ {
13692
+ onClick: () => setIsEditingModel(true),
13693
+ className: "text-icon3 hover:text-icon6",
13694
+ title: "Edit model",
13695
+ type: "button",
13696
+ "aria-label": "Edit model",
13697
+ children: /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(EditIcon, {}) })
13698
+ }
13699
+ )
13700
+ ] });
13701
+ };
13702
+
14457
13703
  const AgentMetadataNetworkList = ({ agents }) => {
14458
13704
  const { Link, paths } = useLinkComponent();
14459
13705
  if (agents.length === 0) {
@@ -14467,7 +13713,9 @@ const AgentMetadata = ({
14467
13713
  promptSlot,
14468
13714
  hasMemoryEnabled,
14469
13715
  updateModel,
14470
- modelProviders
13716
+ modelProviders,
13717
+ updateModelInModelList,
13718
+ reorderModelList
14471
13719
  }) => {
14472
13720
  const [isEditingModel, setIsEditingModel] = useState(false);
14473
13721
  const providerIcon = providerMapToIcon[agent.provider || "openai.chat"];
@@ -14478,7 +13726,15 @@ const AgentMetadata = ({
14478
13726
  const agentWorkflows = agent.workflows ?? {};
14479
13727
  const workflows = Object.keys(agentWorkflows).map((key) => ({ id: key, ...agentWorkflows[key] }));
14480
13728
  return /* @__PURE__ */ jsxs(AgentMetadataWrapper, { children: [
14481
- /* @__PURE__ */ jsx(AgentMetadataSection, { title: "Model", children: isEditingModel ? /* @__PURE__ */ jsx(
13729
+ agent.modelList ? /* @__PURE__ */ jsx(AgentMetadataSection, { title: "Models", children: /* @__PURE__ */ jsx(
13730
+ AgentMetadataModelList,
13731
+ {
13732
+ modelList: agent.modelList,
13733
+ modelProviders,
13734
+ updateModelInModelList,
13735
+ reorderModelList
13736
+ }
13737
+ ) }) : /* @__PURE__ */ jsx(AgentMetadataSection, { title: "Model", children: isEditingModel ? /* @__PURE__ */ jsx(
14482
13738
  AgentMetadataModelSwitcher,
14483
13739
  {
14484
13740
  defaultProvider: agent.provider,
@@ -14568,7 +13824,7 @@ const AgentMetadataScorerList = ({ entityId, entityType }) => {
14568
13824
  const scorerList = Object.keys(scorers).filter((scorerKey) => {
14569
13825
  const scorer = scorers[scorerKey];
14570
13826
  if (entityType === "AGENT") {
14571
- return scorer.agentNames.includes(entityId);
13827
+ return scorer.agentNames?.includes?.(entityId);
14572
13828
  }
14573
13829
  return scorer.workflowIds.includes(entityId);
14574
13830
  }).map((scorerKey) => ({ ...scorers[scorerKey], id: scorerKey }));
@@ -19178,5 +18434,5 @@ const parseError = (error) => {
19178
18434
  }
19179
18435
  };
19180
18436
 
19181
- 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 };
18437
+ 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, 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, ToolFallback, 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, usePlaygroundStore, usePolling, useScorer, useScorers, useScoresByEntityId, useScoresByScorerId, useSpeechRecognition, useThreadInput, useWorkflow, useWorkflowRuns, useWorkingMemory };
19182
18438
  //# sourceMappingURL=index.es.js.map