@mastra/playground-ui 6.6.2 → 6.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -4397,6 +4397,9 @@ const BadgeWrapper = ({
4397
4397
  "data-testid": dataTestId
4398
4398
  }) => {
4399
4399
  const [isCollapsed, setIsCollapsed] = useState(initialCollapsed);
4400
+ useEffect(() => {
4401
+ setIsCollapsed(initialCollapsed);
4402
+ }, [initialCollapsed]);
4400
4403
  return /* @__PURE__ */ jsxs("div", { className: "mb-4", "data-testid": dataTestId, children: [
4401
4404
  /* @__PURE__ */ jsxs("div", { className: "flex flex-row gap-2 items-center justify-between", children: [
4402
4405
  /* @__PURE__ */ jsxs(
@@ -4513,17 +4516,114 @@ const NetworkChoiceMetadataDialogTrigger = ({
4513
4516
  ] });
4514
4517
  };
4515
4518
 
4516
- const ToolBadge = ({ toolName, args, result, metadata, toolOutput }) => {
4519
+ const sizeClasses = {
4520
+ md: "h-button-md gap-md",
4521
+ lg: "h-button-lg gap-lg"
4522
+ };
4523
+ const variantClasses$1 = {
4524
+ default: "bg-surface2 hover:bg-surface4 text-icon3 hover:text-icon6 disabled:opacity-50",
4525
+ light: "bg-surface3 hover:bg-surface5 text-icon6 disabled:opacity-50"
4526
+ };
4527
+ const Button$1 = ({ className, as, size = "md", variant = "default", ...props }) => {
4528
+ const Component = as || "button";
4529
+ return /* @__PURE__ */ jsx(
4530
+ Component,
4531
+ {
4532
+ className: clsx(
4533
+ "bg-surface2 border-sm border-border1 px-lg text-ui-md inline-flex items-center justify-center rounded-md border",
4534
+ variantClasses$1[variant],
4535
+ sizeClasses[size],
4536
+ className,
4537
+ {
4538
+ "cursor-not-allowed": props.disabled
4539
+ }
4540
+ ),
4541
+ ...props
4542
+ }
4543
+ );
4544
+ };
4545
+
4546
+ const ToolCallContext = createContext(void 0);
4547
+ function ToolCallProvider({
4548
+ children,
4549
+ approveToolcall,
4550
+ declineToolcall,
4551
+ isRunning,
4552
+ toolCallApprovals
4553
+ }) {
4554
+ return /* @__PURE__ */ jsx(ToolCallContext.Provider, { value: { approveToolcall, declineToolcall, isRunning, toolCallApprovals }, children });
4555
+ }
4556
+ function useToolCall() {
4557
+ const context = useContext(ToolCallContext);
4558
+ if (!context) {
4559
+ throw new Error("useToolCall must be used within a ToolCallProvider");
4560
+ }
4561
+ return context;
4562
+ }
4563
+
4564
+ const ToolApprovalButtons = ({ toolCalled, toolCallId, toolApprovalMetadata }) => {
4565
+ const { approveToolcall, declineToolcall, isRunning, toolCallApprovals } = useToolCall();
4566
+ const handleApprove = () => {
4567
+ approveToolcall(toolCallId);
4568
+ };
4569
+ const handleDecline = () => {
4570
+ declineToolcall(toolCallId);
4571
+ };
4572
+ const toolCallApprovalStatus = toolCallApprovals?.[toolCallId]?.status;
4573
+ if (toolApprovalMetadata && !toolCalled) {
4574
+ return /* @__PURE__ */ jsxs("div", { children: [
4575
+ /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Approval required" }),
4576
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
4577
+ /* @__PURE__ */ jsxs(
4578
+ Button$1,
4579
+ {
4580
+ onClick: handleApprove,
4581
+ disabled: isRunning || !!toolCallApprovalStatus,
4582
+ className: toolCallApprovalStatus === "approved" ? "!text-accent1" : "",
4583
+ children: [
4584
+ /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(Check, {}) }),
4585
+ "Approve"
4586
+ ]
4587
+ }
4588
+ ),
4589
+ /* @__PURE__ */ jsxs(
4590
+ Button$1,
4591
+ {
4592
+ onClick: handleDecline,
4593
+ disabled: isRunning || !!toolCallApprovalStatus,
4594
+ className: toolCallApprovalStatus === "declined" ? "!text-accent2" : "",
4595
+ children: [
4596
+ /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(X, {}) }),
4597
+ "Decline"
4598
+ ]
4599
+ }
4600
+ )
4601
+ ] })
4602
+ ] });
4603
+ }
4604
+ return null;
4605
+ };
4606
+
4607
+ const ToolBadge = ({
4608
+ toolName,
4609
+ args,
4610
+ result,
4611
+ metadata,
4612
+ toolOutput,
4613
+ toolCallId,
4614
+ toolApprovalMetadata
4615
+ }) => {
4517
4616
  let argSlot = null;
4518
4617
  try {
4519
4618
  const { __mastraMetadata: _, ...formattedArgs } = typeof args === "object" ? args : JSON.parse(args);
4520
4619
  argSlot = /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: formattedArgs, "data-testid": "tool-args" });
4521
4620
  } catch {
4522
- argSlot = /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap", children: args });
4621
+ argSlot = /* @__PURE__ */ jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: args });
4523
4622
  }
4524
- let resultSlot = typeof result === "string" ? /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap bg-surface4 p-4 rounded-md", children: result }) : /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: result, "data-testid": "tool-result" });
4623
+ let resultSlot = typeof result === "string" ? /* @__PURE__ */ jsx("pre", { className: "whitespace-pre bg-surface4 p-4 rounded-md overflow-x-auto", children: result }) : /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: result, "data-testid": "tool-result" });
4525
4624
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
4526
4625
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
4626
+ const toolCalled = result || toolOutput.length > 0;
4527
4627
  return /* @__PURE__ */ jsx(
4528
4628
  BadgeWrapper,
4529
4629
  {
@@ -4537,19 +4637,28 @@ const ToolBadge = ({ toolName, args, result, metadata, toolOutput }) => {
4537
4637
  input: agentNetworkInput
4538
4638
  }
4539
4639
  ),
4640
+ initialCollapsed: !!!toolApprovalMetadata,
4540
4641
  children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
4541
4642
  /* @__PURE__ */ jsxs("div", { children: [
4542
4643
  /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Tool arguments" }),
4543
4644
  argSlot
4544
4645
  ] }),
4545
- resultSlot !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
4646
+ resultSlot !== void 0 && result && /* @__PURE__ */ jsxs("div", { children: [
4546
4647
  /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Tool result" }),
4547
4648
  resultSlot
4548
4649
  ] }),
4549
4650
  toolOutput.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
4550
4651
  /* @__PURE__ */ jsx("p", { className: "font-medium pb-2", children: "Tool output" }),
4551
4652
  /* @__PURE__ */ jsx("div", { className: "h-40 overflow-y-auto", children: /* @__PURE__ */ jsx(SyntaxHighlighter$2, { data: toolOutput, "data-testid": "tool-output" }) })
4552
- ] })
4653
+ ] }),
4654
+ /* @__PURE__ */ jsx(
4655
+ ToolApprovalButtons,
4656
+ {
4657
+ toolCalled,
4658
+ toolCallId,
4659
+ toolApprovalMetadata
4660
+ }
4661
+ )
4553
4662
  ] })
4554
4663
  }
4555
4664
  );
@@ -5136,33 +5245,6 @@ const useCurrentRun = () => {
5136
5245
  return { steps, runId: context.runId };
5137
5246
  };
5138
5247
 
5139
- const sizeClasses = {
5140
- md: "h-button-md gap-md",
5141
- lg: "h-button-lg gap-lg"
5142
- };
5143
- const variantClasses$1 = {
5144
- default: "bg-surface2 hover:bg-surface4 text-icon3 hover:text-icon6",
5145
- light: "bg-surface3 hover:bg-surface5 text-icon6"
5146
- };
5147
- const Button$1 = ({ className, as, size = "md", variant = "default", ...props }) => {
5148
- const Component = as || "button";
5149
- return /* @__PURE__ */ jsx(
5150
- Component,
5151
- {
5152
- className: clsx(
5153
- "bg-surface2 border-sm border-border1 px-lg text-ui-md inline-flex items-center justify-center rounded-md border",
5154
- variantClasses$1[variant],
5155
- sizeClasses[size],
5156
- className,
5157
- {
5158
- "cursor-not-allowed": props.disabled
5159
- }
5160
- ),
5161
- ...props
5162
- }
5163
- );
5164
- };
5165
-
5166
5248
  const useCodemirrorTheme$1 = () => {
5167
5249
  return useMemo(
5168
5250
  () => draculaInit({
@@ -8129,7 +8211,15 @@ const useWorkflow = (workflowId) => {
8129
8211
  });
8130
8212
  };
8131
8213
 
8132
- const WorkflowBadge = ({ runId, workflowId, isStreaming, metadata }) => {
8214
+ const WorkflowBadge = ({
8215
+ result,
8216
+ workflowId,
8217
+ isStreaming,
8218
+ metadata,
8219
+ toolCallId,
8220
+ toolApprovalMetadata
8221
+ }) => {
8222
+ const { runId, status } = result || {};
8133
8223
  const { data: workflow, isLoading: isWorkflowLoading } = useWorkflow(workflowId);
8134
8224
  const { data: runs, isLoading: isRunsLoading } = useWorkflowRuns(workflowId, {
8135
8225
  enabled: Boolean(runId) && !isStreaming
@@ -8156,7 +8246,8 @@ const WorkflowBadge = ({ runId, workflowId, isStreaming, metadata }) => {
8156
8246
  ),
8157
8247
  children: [
8158
8248
  !isStreaming && !isLoading && /* @__PURE__ */ jsx(WorkflowRunProvider, { snapshot, children: /* @__PURE__ */ jsx(WorkflowBadgeExtended, { workflowId, workflow, runId }) }),
8159
- isStreaming && /* @__PURE__ */ jsx(WorkflowBadgeExtended, { workflowId, workflow, runId })
8249
+ isStreaming && /* @__PURE__ */ jsx(WorkflowBadgeExtended, { workflowId, workflow, runId }),
8250
+ /* @__PURE__ */ jsx(ToolApprovalButtons, { toolCalled: !!status, toolCallId, toolApprovalMetadata })
8160
8251
  ]
8161
8252
  }
8162
8253
  );
@@ -8179,10 +8270,10 @@ const useWorkflowStream = (workflowFullState) => {
8179
8270
  }, [workflowFullState]);
8180
8271
  };
8181
8272
 
8182
- const AgentBadge = ({ agentId, messages = [], metadata }) => {
8273
+ const AgentBadge = ({ agentId, messages = [], metadata, toolCallId, toolApprovalMetadata }) => {
8183
8274
  const selectionReason = metadata?.mode === "network" ? metadata.selectionReason : void 0;
8184
8275
  const agentNetworkInput = metadata?.mode === "network" ? metadata.agentInput : void 0;
8185
- return /* @__PURE__ */ jsx(
8276
+ return /* @__PURE__ */ jsxs(
8186
8277
  BadgeWrapper,
8187
8278
  {
8188
8279
  "data-testid": "agent-badge",
@@ -8196,29 +8287,39 @@ const AgentBadge = ({ agentId, messages = [], metadata }) => {
8196
8287
  input: agentNetworkInput
8197
8288
  }
8198
8289
  ),
8199
- children: messages.map((message, index) => {
8200
- if (message.type === "text") {
8201
- return /* @__PURE__ */ jsx(Markdown, { children: message.content }, index);
8202
- }
8203
- const result = typeof message.toolOutput === "string" ? JSON.parse(message.toolOutput) : message.toolOutput;
8204
- return /* @__PURE__ */ jsx(React__default.Fragment, { children: /* @__PURE__ */ jsx(
8205
- ToolFallback,
8206
- {
8207
- toolName: message.toolName,
8208
- argsText: typeof message.args === "string" ? message.args : JSON.stringify(message.args),
8209
- result,
8210
- args: message.args,
8211
- status: { type: "complete" },
8212
- type: "tool-call",
8213
- toolCallId: message.toolCallId,
8214
- addResult: () => {
8215
- },
8216
- metadata: {
8217
- mode: "stream"
8290
+ children: [
8291
+ messages.map((message, index) => {
8292
+ if (message.type === "text") {
8293
+ return /* @__PURE__ */ jsx(Markdown, { children: message.content }, index);
8294
+ }
8295
+ const result = typeof message.toolOutput === "string" ? JSON.parse(message.toolOutput) : message.toolOutput;
8296
+ return /* @__PURE__ */ jsx(React__default.Fragment, { children: /* @__PURE__ */ jsx(
8297
+ ToolFallback,
8298
+ {
8299
+ toolName: message.toolName,
8300
+ argsText: typeof message.args === "string" ? message.args : JSON.stringify(message.args),
8301
+ result,
8302
+ args: message.args,
8303
+ status: { type: "complete" },
8304
+ type: "tool-call",
8305
+ toolCallId: message.toolCallId,
8306
+ addResult: () => {
8307
+ },
8308
+ metadata: {
8309
+ mode: "stream"
8310
+ }
8218
8311
  }
8312
+ ) }, index);
8313
+ }),
8314
+ /* @__PURE__ */ jsx(
8315
+ ToolApprovalButtons,
8316
+ {
8317
+ toolCalled: messages?.length > 0,
8318
+ toolCallId,
8319
+ toolApprovalMetadata
8219
8320
  }
8220
- ) }, index);
8221
- })
8321
+ )
8322
+ ]
8222
8323
  }
8223
8324
  );
8224
8325
  };
@@ -8240,27 +8341,53 @@ const useAgentMessages = ({
8240
8341
  });
8241
8342
  };
8242
8343
 
8243
- const AgentBadgeWrapper = ({ agentId, result, metadata }) => {
8344
+ const AgentBadgeWrapper = ({
8345
+ agentId,
8346
+ result,
8347
+ metadata,
8348
+ toolCallId,
8349
+ toolApprovalMetadata
8350
+ }) => {
8244
8351
  const { data: memoryMessages } = useAgentMessages({
8245
8352
  threadId: result?.subAgentThreadId ?? "",
8246
8353
  agentId,
8247
8354
  memory: true
8248
8355
  });
8249
8356
  const childMessages = result?.childMessages ?? resolveToChildMessages(memoryMessages?.uiMessages ?? []);
8250
- return /* @__PURE__ */ jsx(AgentBadge, { agentId, messages: childMessages, metadata });
8357
+ return /* @__PURE__ */ jsx(
8358
+ AgentBadge,
8359
+ {
8360
+ agentId,
8361
+ messages: childMessages,
8362
+ metadata,
8363
+ toolCallId,
8364
+ toolApprovalMetadata
8365
+ }
8366
+ );
8251
8367
  };
8252
8368
 
8253
8369
  const ToolFallback = ({ toolName, result, args, ...props }) => {
8254
8370
  return /* @__PURE__ */ jsx(WorkflowRunProvider, { children: /* @__PURE__ */ jsx(ToolFallbackInner, { toolName, result, args, ...props }) });
8255
8371
  };
8256
- const ToolFallbackInner = ({ toolName, result, args, metadata, ...props }) => {
8372
+ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...props }) => {
8257
8373
  const isAgent = metadata?.mode === "network" && metadata.from === "AGENT" || toolName.startsWith("agent-");
8258
8374
  const isWorkflow = metadata?.mode === "network" && metadata.from === "WORKFLOW" || toolName.startsWith("workflow-");
8259
8375
  const agentToolName = toolName.startsWith("agent-") ? toolName.substring("agent-".length) : toolName;
8260
8376
  const workflowToolName = toolName.startsWith("workflow-") ? toolName.substring("workflow-".length) : toolName;
8377
+ const requireApprovalMetadata = metadata?.mode === "stream" && metadata?.requireApprovalMetadata;
8378
+ const toolApprovalMetadata = requireApprovalMetadata ? requireApprovalMetadata?.[toolCallId] : void 0;
8261
8379
  useWorkflowStream(result);
8262
8380
  if (isAgent) {
8263
- return /* @__PURE__ */ jsx(AgentBadgeWrapper, { agentId: agentToolName, result, metadata });
8381
+ return /* @__PURE__ */ jsx(
8382
+ AgentBadgeWrapper,
8383
+ {
8384
+ agentId: agentToolName,
8385
+ result,
8386
+ metadata,
8387
+ toolCallId,
8388
+ toolApprovalMetadata
8389
+ }
8390
+ );
8264
8391
  }
8265
8392
  if (isWorkflow) {
8266
8393
  const isStreaming = metadata?.mode === "stream" || metadata?.mode === "network";
@@ -8269,8 +8396,10 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, ...props }) => {
8269
8396
  {
8270
8397
  workflowId: workflowToolName,
8271
8398
  isStreaming,
8272
- runId: result?.runId,
8273
- metadata
8399
+ result,
8400
+ metadata,
8401
+ toolCallId,
8402
+ toolApprovalMetadata
8274
8403
  }
8275
8404
  );
8276
8405
  }
@@ -8281,7 +8410,9 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, ...props }) => {
8281
8410
  args,
8282
8411
  result,
8283
8412
  toolOutput: result?.toolOutput || [],
8284
- metadata
8413
+ metadata,
8414
+ toolCallId,
8415
+ toolApprovalMetadata
8285
8416
  }
8286
8417
  );
8287
8418
  };
@@ -9949,7 +10080,10 @@ function MastraRuntimeProvider({
9949
10080
  sendMessage,
9950
10081
  cancelRun,
9951
10082
  isRunning: isRunningStream,
9952
- setMessages
10083
+ setMessages,
10084
+ approveToolCall,
10085
+ declineToolCall,
10086
+ toolCallApprovals
9953
10087
  } = useChat({
9954
10088
  agentId,
9955
10089
  initializeMessages: () => initialMessages || []
@@ -9969,7 +10103,8 @@ function MastraRuntimeProvider({
9969
10103
  chatWithGenerateLegacy,
9970
10104
  chatWithGenerate,
9971
10105
  chatWithNetwork,
9972
- providerOptions
10106
+ providerOptions,
10107
+ requireToolApproval
9973
10108
  } = settings?.modelSettings ?? {};
9974
10109
  const toolCallIdToName = useRef({});
9975
10110
  const runtimeContextInstance = new RuntimeContext$2();
@@ -9986,7 +10121,8 @@ function MastraRuntimeProvider({
9986
10121
  maxTokens,
9987
10122
  instructions,
9988
10123
  providerOptions,
9989
- maxSteps
10124
+ maxSteps,
10125
+ requireToolApproval
9990
10126
  };
9991
10127
  const baseClient = useMastraClient();
9992
10128
  const isVNext = modelVersion === "v2";
@@ -10374,10 +10510,23 @@ function MastraRuntimeProvider({
10374
10510
  convertMessage: (x) => x,
10375
10511
  onNew,
10376
10512
  onCancel,
10377
- adapters: isReady ? adapters : void 0
10513
+ adapters: isReady ? adapters : void 0,
10514
+ extras: {
10515
+ approveToolCall,
10516
+ declineToolCall
10517
+ }
10378
10518
  });
10379
10519
  if (!isReady) return null;
10380
- return /* @__PURE__ */ jsx(AssistantRuntimeProvider, { runtime, children });
10520
+ return /* @__PURE__ */ jsx(AssistantRuntimeProvider, { runtime, children: /* @__PURE__ */ jsx(
10521
+ ToolCallProvider,
10522
+ {
10523
+ approveToolcall: approveToolCall,
10524
+ declineToolcall: declineToolCall,
10525
+ isRunning: isRunningStream,
10526
+ toolCallApprovals,
10527
+ children
10528
+ }
10529
+ ) });
10381
10530
  }
10382
10531
 
10383
10532
  const defaultSettings = {
@@ -11198,6 +11347,16 @@ const AgentSettings = ({ modelVersion, hasMemory = false, hasSubAgents = false }
11198
11347
  ]
11199
11348
  }
11200
11349
  ) }),
11350
+ /* @__PURE__ */ jsx(Entry, { label: "Require Tool Approval", children: /* @__PURE__ */ jsx(
11351
+ Checkbox,
11352
+ {
11353
+ checked: settings?.modelSettings?.requireToolApproval,
11354
+ onCheckedChange: (value) => setSettings({
11355
+ ...settings,
11356
+ modelSettings: { ...settings?.modelSettings, requireToolApproval: value }
11357
+ })
11358
+ }
11359
+ ) }),
11201
11360
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-8", children: [
11202
11361
  /* @__PURE__ */ jsx(Entry, { label: "Temperature", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-row justify-between items-center gap-2", children: [
11203
11362
  /* @__PURE__ */ jsx(
@@ -16558,7 +16717,7 @@ function TraceSpanUsage({ traceUsage, traceSpans = [], spanUsage, className }) {
16558
16717
  console.warn("Only one of traceUsage or spanUsage should be provided");
16559
16718
  return null;
16560
16719
  }
16561
- const generationSpans = traceSpans.filter((span) => span.spanType === "llm_generation");
16720
+ const generationSpans = traceSpans.filter((span) => span.spanType === "model_generation");
16562
16721
  const hasV5Format = generationSpans.some(
16563
16722
  (span) => span.attributes?.usage?.inputTokens !== void 0 || span.attributes?.usage?.outputTokens !== void 0
16564
16723
  );