@mcp-b/react-components 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/{CodeBlock-BrCoypnc.js → CodeBlock-C2Xjxu9M.js} +1 -1
  2. package/dist/FileTree-D0c9Yj9U.js +310 -0
  3. package/dist/attachment-preview-ChtC3HiU.js +25 -0
  4. package/dist/components/Activity.js +1 -1
  5. package/dist/components/AgentChat.d.ts +56 -9
  6. package/dist/components/AgentChat.js +146 -47
  7. package/dist/components/AgentConnection.js +3 -3
  8. package/dist/components/Artifact.js +1 -1
  9. package/dist/components/BrowserLiveView.d.ts +47 -0
  10. package/dist/components/BrowserLiveView.js +135 -0
  11. package/dist/components/BrowserReplay.d.ts +40 -0
  12. package/dist/components/BrowserReplay.js +187 -0
  13. package/dist/components/ChainOfThought.d.ts +1 -1
  14. package/dist/components/ChainOfThought.js +1 -1
  15. package/dist/components/CodeBlock.js +1 -1
  16. package/dist/components/Commit.js +1 -1
  17. package/dist/components/Context.d.ts +28 -27
  18. package/dist/components/Context.js +48 -47
  19. package/dist/components/ContextMenu.js +1 -1
  20. package/dist/components/Conversation.js +1 -1
  21. package/dist/components/Dialog.js +1 -1
  22. package/dist/components/EnvironmentVariables.js +1 -1
  23. package/dist/components/FileTree.js +1 -309
  24. package/dist/components/Menubar.js +1 -1
  25. package/dist/components/Message.d.ts +17 -2
  26. package/dist/components/Message.js +36 -2
  27. package/dist/components/ModelSelector.js +1 -1
  28. package/dist/components/NavigationMenu.js +1 -1
  29. package/dist/components/PricingPage.js +2 -2
  30. package/dist/components/PromptInput.d.ts +143 -10
  31. package/dist/components/PromptInput.js +318 -5
  32. package/dist/components/Queue.js +1 -1
  33. package/dist/components/Reasoning.js +1 -1
  34. package/dist/components/Select.js +1 -1
  35. package/dist/components/Sources.js +1 -1
  36. package/dist/components/Stepper.js +1 -1
  37. package/dist/components/Suggestion.d.ts +43 -0
  38. package/dist/components/Suggestion.js +39 -0
  39. package/dist/components/Task.js +1 -1
  40. package/dist/components/Terminal.js +2 -2
  41. package/dist/components/TestResults.js +1 -1
  42. package/dist/components/ThinkChat.d.ts +207 -0
  43. package/dist/components/ThinkChat.js +798 -0
  44. package/dist/components/Tool.d.ts +32 -28
  45. package/dist/components/Tool.js +29 -16
  46. package/dist/components/WebPreview.js +1 -1
  47. package/dist/components/WorkspaceExplorer.d.ts +102 -0
  48. package/dist/components/WorkspaceExplorer.js +352 -0
  49. package/dist/components/icons.d.ts +2 -2
  50. package/dist/components/icons.js +2 -2
  51. package/dist/{copy-button-DAPlB8Z0.js → copy-button-Dd6DEhOm.js} +1 -1
  52. package/dist/{icons-Bf7JMKk-.js → icons-DQC4Zw5R.js} +5 -1
  53. package/dist/{icons-BklFyZbx.d.ts → icons-ctdVxng0.d.ts} +2 -1
  54. package/dist/styles/agent-chat.css +19 -0
  55. package/dist/styles/attachment-preview.css +21 -0
  56. package/dist/styles/context.css +9 -17
  57. package/dist/styles/index.css +2 -0
  58. package/dist/styles/message.css +48 -0
  59. package/dist/styles/prompt-input.css +321 -0
  60. package/dist/styles/suggestions.css +21 -0
  61. package/package.json +26 -3
@@ -1,7 +1,8 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { n as ArrowLeftIcon, r as ArrowRightIcon } from "../icons-Bf7JMKk-.js";
2
+ import { h as FileIcon, n as ArrowLeftIcon, r as ArrowRightIcon } from "../icons-DQC4Zw5R.js";
3
3
  import { Button } from "./Button.js";
4
4
  import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
5
+ import { t as AttachmentPreview } from "../attachment-preview-ChtC3HiU.js";
5
6
  import * as React from "react";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
8
  import { cjk } from "@streamdown/cjk";
@@ -66,6 +67,39 @@ const MessageResponse = React.memo(function MessageResponse({ className, ...prop
66
67
  });
67
68
  });
68
69
  /**
70
+ * A `file` part inside a message: images render inline (click to zoom),
71
+ * anything else becomes a download chip. Covers both directions — files the
72
+ * user attached and files the agent emitted.
73
+ */
74
+ function MessageAttachment({ part, className, ...props }) {
75
+ const name = part.filename ?? (part.mediaType || "attachment");
76
+ if (part.mediaType.startsWith("image/")) return /* @__PURE__ */ jsx(AttachmentPreview, {
77
+ url: part.url,
78
+ filename: part.filename,
79
+ children: /* @__PURE__ */ jsx("button", {
80
+ type: "button",
81
+ className: cx("message__attachment-zoom", className),
82
+ "aria-label": `Preview ${name}`,
83
+ ...props,
84
+ children: /* @__PURE__ */ jsx("img", {
85
+ className: "message__attachment-image",
86
+ src: part.url,
87
+ alt: part.filename ?? "Attached image"
88
+ })
89
+ })
90
+ });
91
+ return /* @__PURE__ */ jsxs("a", {
92
+ className: cx("message__attachment", className),
93
+ href: part.url,
94
+ download: part.filename,
95
+ ...props,
96
+ children: [/* @__PURE__ */ jsx(FileIcon, { className: "message__attachment-icon" }), /* @__PURE__ */ jsx("span", {
97
+ className: "message__attachment-name",
98
+ children: name
99
+ })]
100
+ });
101
+ }
102
+ /**
69
103
  * Horizontal list of action buttons (copy, retry, thumbs-up, etc.) shown
70
104
  * alongside or beneath a message.
71
105
  */
@@ -242,4 +276,4 @@ function MessageBranchPage({ className, format, ref, ...props }) {
242
276
  });
243
277
  }
244
278
  //#endregion
245
- export { Message, MessageAction, MessageActions, MessageBranch, MessageBranchContent, MessageBranchNext, MessageBranchPage, MessageBranchPrevious, MessageBranchSelector, MessageContent, MessageResponse, MessageToolbar };
279
+ export { Message, MessageAction, MessageActions, MessageAttachment, MessageBranch, MessageBranchContent, MessageBranchNext, MessageBranchPage, MessageBranchPrevious, MessageBranchSelector, MessageContent, MessageResponse, MessageToolbar };
@@ -1,5 +1,5 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { O as SearchIcon, s as ChevronDownIcon } from "../icons-Bf7JMKk-.js";
2
+ import { k as SearchIcon, s as ChevronDownIcon } from "../icons-DQC4Zw5R.js";
3
3
  import { Button } from "./Button.js";
4
4
  import { Dialog, DialogBackdrop, DialogPopup, DialogPortal, DialogTitle, DialogTrigger } from "./Dialog.js";
5
5
  import * as React from "react";
@@ -1,4 +1,4 @@
1
- import { s as ChevronDownIcon } from "../icons-Bf7JMKk-.js";
1
+ import { s as ChevronDownIcon } from "../icons-DQC4Zw5R.js";
2
2
  import * as React from "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { NavigationMenu as NavigationMenu$1 } from "@base-ui/react/navigation-menu";
@@ -1,15 +1,15 @@
1
1
  import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger } from "./Accordion.js";
2
+ import { Separator } from "./Separator.js";
2
3
  import { Button } from "./Button.js";
3
4
  import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
4
5
  import { Badge } from "./Badge.js";
5
6
  import { AlertDialog, AlertDialogBackdrop, AlertDialogClose, AlertDialogDescription, AlertDialogPopup, AlertDialogPortal, AlertDialogTitle } from "./AlertDialog.js";
7
+ import { Slider, SliderControl, SliderIndicator, SliderThumb, SliderTrack } from "./Slider.js";
6
8
  import { Card } from "./Card.js";
7
9
  import { Checkbox } from "./Checkbox.js";
8
- import { Separator } from "./Separator.js";
9
10
  import { Switch, SwitchThumb } from "./Switch.js";
10
11
  import { Label } from "./Label.js";
11
12
  import { ToggleGroup, ToggleGroupItem } from "./ToggleGroup.js";
12
- import { Slider, SliderControl, SliderIndicator, SliderThumb, SliderTrack } from "./Slider.js";
13
13
  import { Progress, ProgressIndicator, ProgressTrack } from "./Progress.js";
14
14
  import * as React from "react";
15
15
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -4,15 +4,15 @@ import { h as MenuItemProps, w as MenuProps, y as MenuPopupProps } from "../Menu
4
4
  import { c as TabsList, n as TabPanel, t as Tab } from "../Tabs-D9EAq09D.js";
5
5
  import { r as ButtonProps } from "../Button-Ct5I6aTu.js";
6
6
  import * as React from "react";
7
+ import { ChatAddToolApproveResponseFunction, ChatStatus, DynamicToolUIPart, FileUIPart, ToolUIPart, UIMessage } from "ai";
7
8
 
8
9
  //#region src/components/PromptInput.d.ts
9
- interface PromptInputFilePart {
10
- type: "file";
11
- id?: string;
12
- filename?: string;
13
- mediaType?: string;
14
- url?: string;
15
- }
10
+ /**
11
+ * The AI SDK's `FileUIPart`, taken whole — an attachment IS the `file` part
12
+ * that ends up on the sent message, so submitted files feed straight into
13
+ * `sendMessage({ text, files })`.
14
+ */
15
+ type PromptInputFilePart = FileUIPart;
16
16
  interface PromptInputReferencedSource {
17
17
  id?: string;
18
18
  title?: string;
@@ -24,8 +24,8 @@ interface PromptInputMessage {
24
24
  text: string;
25
25
  files: PromptInputFilePart[];
26
26
  }
27
- /** Lifecycle status of an in-flight model request. */
28
- type PromptInputStatus = "ready" | "submitted" | "streaming" | "error";
27
+ /** Lifecycle status of an in-flight model request — the AI SDK's `ChatStatus`. */
28
+ type PromptInputStatus = ChatStatus;
29
29
  interface AttachmentsContext {
30
30
  files: Array<PromptInputFilePart & {
31
31
  id: string;
@@ -143,6 +143,43 @@ declare function PromptInputHeader({
143
143
  }: PromptInputHeaderProps & {
144
144
  ref?: React.Ref<HTMLDivElement>;
145
145
  }): React.JSX.Element;
146
+ interface PromptInputAttachmentProps extends React.HTMLAttributes<HTMLDivElement> {
147
+ /** The pending attachment — the AI SDK `file` part plus the local list id. */
148
+ file: PromptInputFilePart & {
149
+ id: string;
150
+ };
151
+ }
152
+ /**
153
+ * One pending attachment chip: image files show a thumbnail, everything else
154
+ * a file icon and name. The corner button removes it from the pending list.
155
+ */
156
+ declare function PromptInputAttachment({
157
+ file,
158
+ className,
159
+ ref,
160
+ ...props
161
+ }: PromptInputAttachmentProps & {
162
+ ref?: React.Ref<HTMLDivElement>;
163
+ }): React.JSX.Element;
164
+ interface PromptInputAttachmentsProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
165
+ /** Override chip rendering per attachment. */
166
+ children?: (file: PromptInputFilePart & {
167
+ id: string;
168
+ }) => React.ReactNode;
169
+ }
170
+ /**
171
+ * The pending-attachment chip row. Renders nothing while the list is empty,
172
+ * so it can sit in the composer unconditionally — files added via the file
173
+ * dialog, paste, or drop appear here until submit sends and clears them.
174
+ */
175
+ declare function PromptInputAttachments({
176
+ className,
177
+ children,
178
+ ref,
179
+ ...props
180
+ }: PromptInputAttachmentsProps & {
181
+ ref?: React.Ref<HTMLDivElement>;
182
+ }): React.JSX.Element | null;
146
183
  interface PromptInputBodyProps extends React.HTMLAttributes<HTMLDivElement> {}
147
184
  declare function PromptInputBody({
148
185
  className,
@@ -253,6 +290,25 @@ declare function PromptInputActionAddScreenshot({
253
290
  children,
254
291
  ...props
255
292
  }: PromptInputActionAddScreenshotProps): React.JSX.Element;
293
+ /** How the agent's approval requests are handled. */
294
+ type PermissionMode = "ask" | "bypass";
295
+ interface PromptInputPermissionSelectorProps {
296
+ /** Current mode. `"ask"` surfaces approvals in the composer; `"bypass"` auto-approves. */
297
+ value: PermissionMode;
298
+ onValueChange: (mode: PermissionMode) => void;
299
+ /** Overrides the menu's header question. */
300
+ question?: string;
301
+ }
302
+ /**
303
+ * Footer control for choosing how approval requests are handled — ask each
304
+ * time, or bypass. Purely a picker: the auto-approve behavior lives with
305
+ * whoever owns the approvals (`AgentChat` wires both ends).
306
+ */
307
+ declare function PromptInputPermissionSelector({
308
+ value,
309
+ onValueChange,
310
+ question
311
+ }: PromptInputPermissionSelectorProps): React.JSX.Element;
256
312
  interface PromptInputSubmitProps extends Omit<ButtonProps, "children" | "className" | "type"> {
257
313
  className?: string;
258
314
  status?: PromptInputStatus;
@@ -275,6 +331,83 @@ declare function PromptInputSubmit({
275
331
  }: PromptInputSubmitProps & {
276
332
  ref?: React.Ref<HTMLButtonElement>;
277
333
  }): React.JSX.Element;
334
+ /** A tool part that may carry a pending approval request. Upstream AI SDK types, taken whole. */
335
+ type ApprovalToolPart = ToolUIPart | DynamicToolUIPart;
336
+ /**
337
+ * Resolve paused codemode executions (`execute` / `browser_execute`) in the
338
+ * same composer approval UI as AI SDK tool approvals. Wire to the Think
339
+ * agent's client-callable RPCs — they ride the `useAgent` stub, not the chat
340
+ * socket, which is why this package can't reach them itself:
341
+ *
342
+ * ```tsx
343
+ * executionApprovals={{
344
+ * approve: (id) => agent.stub.approveExecution(id),
345
+ * reject: (id, reason) => agent.stub.rejectExecution(id, reason),
346
+ * }}
347
+ * ```
348
+ *
349
+ * On approve, upstream resumes the run, replaces the paused tool output in the
350
+ * transcript, and auto-continues the chat — no client bookkeeping needed.
351
+ * Both RPCs are idempotent, so a stale click resolves to "already handled".
352
+ */
353
+ interface ExecutionApprovals {
354
+ approve: (executionId: string) => unknown;
355
+ reject: (executionId: string, reason?: string) => unknown;
356
+ }
357
+ /** The id a response must carry: the approval id, or the paused run's executionId. */
358
+ declare function getApprovalRequestId(part: ApprovalToolPart): string | undefined;
359
+ interface PendingToolApproval<MessageT extends UIMessage = UIMessage> {
360
+ message: MessageT;
361
+ messageIndex: number;
362
+ part: ApprovalToolPart;
363
+ partIndex: number;
364
+ }
365
+ /** Derives pending tool approvals straight from the messages — no app-owned shapes. */
366
+ declare function getPendingToolApprovals<MessageT extends UIMessage>(messages: readonly MessageT[], {
367
+ pausedExecutions
368
+ }?: {
369
+ pausedExecutions?: boolean;
370
+ }): Array<PendingToolApproval<MessageT>>;
371
+ interface PromptInputApprovalProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "part"> {
372
+ /**
373
+ * The `approval-requested` tool part — or a paused codemode execution —
374
+ * passed whole. Renders nothing for other states.
375
+ */
376
+ part: ApprovalToolPart;
377
+ /** Pass `addToolApprovalResponse` from `useAgentChat`/`useChat` directly. */
378
+ onRespond?: ChatAddToolApproveResponseFunction;
379
+ /** Resolves paused executions instead of `onRespond`. See {@link ExecutionApprovals}. */
380
+ executionApprovals?: ExecutionApprovals;
381
+ /**
382
+ * Renders a Skip action that dismisses the confirmation without responding —
383
+ * the approval stays pending upstream.
384
+ */
385
+ onSkip?: () => void;
386
+ /** Overrides the default "Do you want to allow…" question. */
387
+ question?: React.ReactNode;
388
+ /** Total pending approvals, for the "1 of N" hint. */
389
+ count?: number;
390
+ }
391
+ /**
392
+ * The composer's approval state: when a tool call awaits human approval the
393
+ * prompt input area becomes the confirmation. "Yes" approves on click; typing
394
+ * in the "No, and tell the agent what to do differently" row selects deny and
395
+ * sends the text as the native approval `reason`. Submit (or Enter) sends the
396
+ * current selection — approve by default.
397
+ */
398
+ declare function PromptInputApproval({
399
+ part,
400
+ onRespond,
401
+ executionApprovals,
402
+ onSkip,
403
+ question,
404
+ count,
405
+ className,
406
+ ref,
407
+ ...props
408
+ }: PromptInputApprovalProps & {
409
+ ref?: React.Ref<HTMLDivElement>;
410
+ }): React.JSX.Element | null;
278
411
  type PromptInputSelectProps = SelectProps;
279
412
  declare const PromptInputSelect: typeof Select;
280
413
  type PromptInputSelectTriggerProps = SelectTriggerProps;
@@ -396,4 +529,4 @@ declare const PromptInputCommandItem: typeof ComboboxItem;
396
529
  type PromptInputCommandSeparatorProps = React.ComponentPropsWithoutRef<typeof ComboboxSeparator>;
397
530
  declare const PromptInputCommandSeparator: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").SeparatorProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
398
531
  //#endregion
399
- export { AttachmentsContext, PromptInput, PromptInputActionAddAttachments, PromptInputActionAddAttachmentsProps, PromptInputActionAddScreenshot, PromptInputActionAddScreenshotProps, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuContentProps, PromptInputActionMenuItem, PromptInputActionMenuItemProps, PromptInputActionMenuProps, PromptInputActionMenuTrigger, PromptInputActionMenuTriggerProps, PromptInputBody, PromptInputBodyProps, PromptInputButton, PromptInputButtonProps, PromptInputButtonTooltip, PromptInputCommand, PromptInputCommandEmpty, PromptInputCommandEmptyProps, PromptInputCommandGroup, PromptInputCommandGroupProps, PromptInputCommandInput, PromptInputCommandInputProps, PromptInputCommandItem, PromptInputCommandItemProps, PromptInputCommandList, PromptInputCommandListProps, PromptInputCommandProps, PromptInputCommandSeparator, PromptInputCommandSeparatorProps, PromptInputControllerProps, PromptInputFilePart, PromptInputFooter, PromptInputFooterProps, PromptInputHeader, PromptInputHeaderProps, PromptInputHoverCard, PromptInputHoverCardContent, PromptInputHoverCardContentProps, PromptInputHoverCardProps, PromptInputHoverCardTrigger, PromptInputHoverCardTriggerProps, PromptInputMessage, PromptInputProps, PromptInputProvider, PromptInputProviderProps, PromptInputReferencedSource, PromptInputSelect, PromptInputSelectContent, PromptInputSelectContentProps, PromptInputSelectItem, PromptInputSelectItemProps, PromptInputSelectProps, PromptInputSelectTrigger, PromptInputSelectTriggerProps, PromptInputSelectValue, PromptInputSelectValueProps, PromptInputStatus, PromptInputSubmit, PromptInputSubmitProps, PromptInputTab, PromptInputTabBody, PromptInputTabBodyProps, PromptInputTabItem, PromptInputTabItemProps, PromptInputTabLabel, PromptInputTabLabelProps, PromptInputTabProps, PromptInputTabsList, PromptInputTabsListProps, PromptInputTextarea, PromptInputTextareaProps, PromptInputTools, PromptInputToolsProps, PromptInputTooltipConfig, ReferencedSourcesContext, TextInputContext, TooltipSide, usePromptInputAttachments, usePromptInputController, usePromptInputReferencedSources, useProviderAttachments };
532
+ export { ApprovalToolPart, AttachmentsContext, ExecutionApprovals, PendingToolApproval, PermissionMode, PromptInput, PromptInputActionAddAttachments, PromptInputActionAddAttachmentsProps, PromptInputActionAddScreenshot, PromptInputActionAddScreenshotProps, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuContentProps, PromptInputActionMenuItem, PromptInputActionMenuItemProps, PromptInputActionMenuProps, PromptInputActionMenuTrigger, PromptInputActionMenuTriggerProps, PromptInputApproval, PromptInputApprovalProps, PromptInputAttachment, PromptInputAttachmentProps, PromptInputAttachments, PromptInputAttachmentsProps, PromptInputBody, PromptInputBodyProps, PromptInputButton, PromptInputButtonProps, PromptInputButtonTooltip, PromptInputCommand, PromptInputCommandEmpty, PromptInputCommandEmptyProps, PromptInputCommandGroup, PromptInputCommandGroupProps, PromptInputCommandInput, PromptInputCommandInputProps, PromptInputCommandItem, PromptInputCommandItemProps, PromptInputCommandList, PromptInputCommandListProps, PromptInputCommandProps, PromptInputCommandSeparator, PromptInputCommandSeparatorProps, PromptInputControllerProps, PromptInputFilePart, PromptInputFooter, PromptInputFooterProps, PromptInputHeader, PromptInputHeaderProps, PromptInputHoverCard, PromptInputHoverCardContent, PromptInputHoverCardContentProps, PromptInputHoverCardProps, PromptInputHoverCardTrigger, PromptInputHoverCardTriggerProps, PromptInputMessage, PromptInputPermissionSelector, PromptInputPermissionSelectorProps, PromptInputProps, PromptInputProvider, PromptInputProviderProps, PromptInputReferencedSource, PromptInputSelect, PromptInputSelectContent, PromptInputSelectContentProps, PromptInputSelectItem, PromptInputSelectItemProps, PromptInputSelectProps, PromptInputSelectTrigger, PromptInputSelectTriggerProps, PromptInputSelectValue, PromptInputSelectValueProps, PromptInputStatus, PromptInputSubmit, PromptInputSubmitProps, PromptInputTab, PromptInputTabBody, PromptInputTabBodyProps, PromptInputTabItem, PromptInputTabItemProps, PromptInputTabLabel, PromptInputTabLabelProps, PromptInputTabProps, PromptInputTabsList, PromptInputTabsListProps, PromptInputTextarea, PromptInputTextareaProps, PromptInputTools, PromptInputToolsProps, PromptInputTooltipConfig, ReferencedSourcesContext, TextInputContext, TooltipSide, getApprovalRequestId, getPendingToolApprovals, usePromptInputAttachments, usePromptInputController, usePromptInputReferencedSources, useProviderAttachments };
@@ -1,13 +1,15 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { A as SquareIcon, C as MonitorIcon, E as PlusIcon, M as WarningIcon, i as ArrowUpIcon, k as SpinnerIcon, v as ImageIcon } from "../icons-Bf7JMKk-.js";
2
+ import { A as SpinnerIcon, C as MonitorIcon, D as PlusIcon, F as XIcon, N as WarningIcon, T as PencilIcon, h as FileIcon, i as ArrowUpIcon, j as SquareIcon, s as ChevronDownIcon, v as ImageIcon } from "../icons-DQC4Zw5R.js";
3
3
  import { Button } from "./Button.js";
4
4
  import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
5
+ import { t as AttachmentPreview } from "../attachment-preview-ChtC3HiU.js";
5
6
  import { Combobox, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxList, ComboboxSeparator } from "./Combobox.js";
6
- import { MenuItem, MenuPopup, MenuPortal, MenuPositioner, MenuRoot, MenuTrigger } from "./Menu.js";
7
+ import { MenuItem, MenuPopup, MenuPortal, MenuPositioner, MenuRadioGroup, MenuRadioItem, MenuRadioItemIndicator, MenuRoot, MenuTrigger } from "./Menu.js";
7
8
  import { Select, SelectContent, SelectItem, SelectPortal, SelectPositioner, SelectTrigger, SelectValue } from "./Select.js";
8
9
  import { Tab, TabPanel, TabsList } from "./Tabs.js";
9
10
  import * as React from "react";
10
11
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
+ import { getToolName, isToolOrDynamicToolUIPart } from "ai";
11
13
  //#region src/components/PromptInput.tsx
12
14
  const PromptInputContext = React.createContext(null);
13
15
  const PromptInputController = React.createContext(null);
@@ -338,6 +340,59 @@ function PromptInputHeader({ className, children, ref, ...props }) {
338
340
  children
339
341
  });
340
342
  }
343
+ /**
344
+ * One pending attachment chip: image files show a thumbnail, everything else
345
+ * a file icon and name. The corner button removes it from the pending list.
346
+ */
347
+ function PromptInputAttachment({ file, className, ref, ...props }) {
348
+ const attachments = usePromptInputAttachments();
349
+ const isImage = file.mediaType.startsWith("image/");
350
+ const name = file.filename ?? "attachment";
351
+ return /* @__PURE__ */ jsxs("div", {
352
+ ref,
353
+ className: cx("prompt-input__attachment", className),
354
+ "data-image": isImage || void 0,
355
+ ...props,
356
+ children: [isImage ? /* @__PURE__ */ jsx(AttachmentPreview, {
357
+ url: file.url,
358
+ filename: file.filename,
359
+ children: /* @__PURE__ */ jsx("button", {
360
+ type: "button",
361
+ className: "prompt-input__attachment-zoom",
362
+ "aria-label": `Preview ${name}`,
363
+ children: /* @__PURE__ */ jsx("img", {
364
+ className: "prompt-input__attachment-thumb",
365
+ src: file.url,
366
+ alt: ""
367
+ })
368
+ })
369
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(FileIcon, { className: "prompt-input__attachment-icon" }), /* @__PURE__ */ jsx("span", {
370
+ className: "prompt-input__attachment-name",
371
+ children: name
372
+ })] }), /* @__PURE__ */ jsx("button", {
373
+ type: "button",
374
+ className: "prompt-input__attachment-remove",
375
+ "aria-label": `Remove ${name}`,
376
+ onClick: () => attachments.remove(file.id),
377
+ children: /* @__PURE__ */ jsx(XIcon, { size: 12 })
378
+ })]
379
+ });
380
+ }
381
+ /**
382
+ * The pending-attachment chip row. Renders nothing while the list is empty,
383
+ * so it can sit in the composer unconditionally — files added via the file
384
+ * dialog, paste, or drop appear here until submit sends and clears them.
385
+ */
386
+ function PromptInputAttachments({ className, children, ref, ...props }) {
387
+ const attachments = usePromptInputAttachments();
388
+ if (attachments.files.length === 0) return null;
389
+ return /* @__PURE__ */ jsx("div", {
390
+ ref,
391
+ className: cx("prompt-input__attachments", className),
392
+ ...props,
393
+ children: attachments.files.map((file) => /* @__PURE__ */ jsx(React.Fragment, { children: children ? children(file) : /* @__PURE__ */ jsx(PromptInputAttachment, { file }) }, file.id))
394
+ });
395
+ }
341
396
  function PromptInputBody({ className, children, ref, ...props }) {
342
397
  return /* @__PURE__ */ jsx("div", {
343
398
  ref,
@@ -524,6 +579,60 @@ function PromptInputActionAddScreenshot({ label = "Take screenshot", onClick, ch
524
579
  children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MonitorIcon, { className: "prompt-input__action-menu-icon" }), label] })
525
580
  });
526
581
  }
582
+ const PERMISSION_MODES = [{
583
+ value: "ask",
584
+ label: "Ask for approval",
585
+ description: "Pause and ask before sensitive actions run"
586
+ }, {
587
+ value: "bypass",
588
+ label: "Bypass permissions",
589
+ description: "Approve every request automatically"
590
+ }];
591
+ /**
592
+ * Footer control for choosing how approval requests are handled — ask each
593
+ * time, or bypass. Purely a picker: the auto-approve behavior lives with
594
+ * whoever owns the approvals (`AgentChat` wires both ends).
595
+ */
596
+ function PromptInputPermissionSelector({ value, onValueChange, question = "How should agent actions be approved?" }) {
597
+ return /* @__PURE__ */ jsxs(MenuRoot, { children: [/* @__PURE__ */ jsx(MenuTrigger, { render: /* @__PURE__ */ jsxs(PromptInputButton, {
598
+ size: "sm",
599
+ className: "prompt-input__permissions-trigger",
600
+ "data-mode": value,
601
+ "aria-label": (PERMISSION_MODES.find((mode) => mode.value === value) ?? PERMISSION_MODES[0]).label,
602
+ children: [/* @__PURE__ */ jsx("span", {
603
+ className: "prompt-input__permissions-current",
604
+ children: PERMISSION_MODES.map((mode) => /* @__PURE__ */ jsxs("span", {
605
+ className: "prompt-input__permissions-current-option",
606
+ "data-active": mode.value === value || void 0,
607
+ children: [mode.value === "bypass" ? /* @__PURE__ */ jsx(WarningIcon, { size: 14 }) : null, mode.label]
608
+ }, mode.value))
609
+ }), /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12 })]
610
+ }) }), /* @__PURE__ */ jsx(MenuPortal, { children: /* @__PURE__ */ jsx(MenuPositioner, { children: /* @__PURE__ */ jsxs(MenuPopup, {
611
+ className: "prompt-input__permissions-menu",
612
+ children: [/* @__PURE__ */ jsx("div", {
613
+ className: "prompt-input__permissions-question",
614
+ children: question
615
+ }), /* @__PURE__ */ jsx(MenuRadioGroup, {
616
+ value,
617
+ onValueChange: (mode) => onValueChange(mode),
618
+ children: PERMISSION_MODES.map((mode) => /* @__PURE__ */ jsxs(MenuRadioItem, {
619
+ value: mode.value,
620
+ closeOnClick: true,
621
+ className: "prompt-input__permissions-option",
622
+ children: [/* @__PURE__ */ jsxs("span", {
623
+ className: "prompt-input__permissions-option-text",
624
+ children: [/* @__PURE__ */ jsx("span", {
625
+ className: "prompt-input__permissions-option-label",
626
+ children: mode.label
627
+ }), /* @__PURE__ */ jsx("span", {
628
+ className: "prompt-input__permissions-option-description",
629
+ children: mode.description
630
+ })]
631
+ }), /* @__PURE__ */ jsx(MenuRadioItemIndicator, { className: "prompt-input__permissions-check" })]
632
+ }, mode.value))
633
+ })]
634
+ }) }) })] });
635
+ }
527
636
  function PromptInputSubmit({ className, status = "ready", onStop, variant = "normal", color = "primary", size = "icon", onClick, children, label, ref, ...props }) {
528
637
  const isStopping = status === "submitted" || status === "streaming";
529
638
  const resolvedLabel = label ?? defaultSubmitLabel(status);
@@ -548,6 +657,210 @@ function PromptInputSubmit({ className, status = "ready", onStop, variant = "nor
548
657
  children: children ?? defaultSubmitIcon(status)
549
658
  });
550
659
  }
660
+ function getPausedExecution(part) {
661
+ if (part.state !== "output-available") return void 0;
662
+ const output = part.output;
663
+ return output?.status === "paused" && typeof output.executionId === "string" ? output : void 0;
664
+ }
665
+ /** The id a response must carry: the approval id, or the paused run's executionId. */
666
+ function getApprovalRequestId(part) {
667
+ if (part.state === "approval-requested") return part.approval.id;
668
+ return getPausedExecution(part)?.executionId;
669
+ }
670
+ /** Derives pending tool approvals straight from the messages — no app-owned shapes. */
671
+ function getPendingToolApprovals(messages, { pausedExecutions = false } = {}) {
672
+ const pending = [];
673
+ messages.forEach((message, messageIndex) => {
674
+ message.parts.forEach((part, partIndex) => {
675
+ if (isToolOrDynamicToolUIPart(part) && (part.state === "approval-requested" || pausedExecutions && getPausedExecution(part))) pending.push({
676
+ message,
677
+ messageIndex,
678
+ part,
679
+ partIndex
680
+ });
681
+ });
682
+ });
683
+ return pending;
684
+ }
685
+ function formatApprovalValue(value) {
686
+ if (typeof value === "string") return value;
687
+ return JSON.stringify(value);
688
+ }
689
+ /**
690
+ * The composer's approval state: when a tool call awaits human approval the
691
+ * prompt input area becomes the confirmation. "Yes" approves on click; typing
692
+ * in the "No, and tell the agent what to do differently" row selects deny and
693
+ * sends the text as the native approval `reason`. Submit (or Enter) sends the
694
+ * current selection — approve by default.
695
+ */
696
+ function PromptInputApproval({ part, onRespond, executionApprovals, onSkip, question, count, className, ref, ...props }) {
697
+ const [selected, setSelected] = React.useState("approve");
698
+ const [reason, setReason] = React.useState("");
699
+ const [busy, setBusy] = React.useState(false);
700
+ const yesRef = React.useRef(null);
701
+ const reasonRef = React.useRef(null);
702
+ const approval = part.state === "approval-requested" ? part.approval : void 0;
703
+ const paused = getPausedExecution(part);
704
+ const approvalId = approval?.id ?? paused?.executionId;
705
+ React.useEffect(() => {
706
+ setSelected("approve");
707
+ setReason("");
708
+ setBusy(false);
709
+ }, [approvalId]);
710
+ if (approval ? !onRespond : !(paused && executionApprovals)) return null;
711
+ const toolName = getToolName(part);
712
+ const respond = (approved) => {
713
+ if (busy) return;
714
+ setBusy(true);
715
+ const trimmed = reason.trim();
716
+ const denyReason = !approved && trimmed ? trimmed : void 0;
717
+ if (approval) onRespond?.({
718
+ id: approval.id,
719
+ approved,
720
+ reason: denyReason
721
+ });
722
+ else if (paused) approved ? executionApprovals?.approve(paused.executionId) : executionApprovals?.reject(paused.executionId, denyReason);
723
+ };
724
+ const submit = () => respond(selected === "approve");
725
+ const input = "input" in part ? part.input : void 0;
726
+ const inputEntries = input && typeof input === "object" && !Array.isArray(input) ? Object.entries(input) : void 0;
727
+ return /* @__PURE__ */ jsxs("div", {
728
+ ref,
729
+ role: "group",
730
+ "aria-label": `Approve ${toolName}`,
731
+ className: cx("prompt-input__approval", className),
732
+ onKeyDown: (event) => {
733
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
734
+ event.preventDefault();
735
+ (selected === "approve" ? reasonRef : yesRef).current?.focus();
736
+ } else if (event.key === "1" && event.target !== reasonRef.current) yesRef.current?.focus();
737
+ },
738
+ ...props,
739
+ children: [
740
+ /* @__PURE__ */ jsxs("div", {
741
+ className: "prompt-input__approval-question",
742
+ children: [/* @__PURE__ */ jsx("span", { children: question ?? (paused ? /* @__PURE__ */ jsx(Fragment, { children: "The agent's code is paused on these calls. Allow it to continue?" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
743
+ "Do you want to allow the agent to run ",
744
+ /* @__PURE__ */ jsx("code", { children: toolName }),
745
+ "?"
746
+ ] })) }), count && count > 1 ? /* @__PURE__ */ jsxs("span", {
747
+ className: "prompt-input__approval-count",
748
+ children: ["1 of ", count]
749
+ }) : null]
750
+ }),
751
+ paused ? /* @__PURE__ */ jsx("div", {
752
+ className: "prompt-input__approval-preview",
753
+ children: paused.pending.map((action) => /* @__PURE__ */ jsxs("div", {
754
+ className: "prompt-input__approval-preview-row",
755
+ children: [
756
+ /* @__PURE__ */ jsxs("span", {
757
+ className: "prompt-input__approval-preview-key",
758
+ children: [
759
+ action.connector,
760
+ ".",
761
+ action.method
762
+ ]
763
+ }),
764
+ " ",
765
+ action.args === void 0 ? null : formatApprovalValue(action.args)
766
+ ]
767
+ }, action.seq))
768
+ }) : input !== void 0 ? /* @__PURE__ */ jsx("div", {
769
+ className: "prompt-input__approval-preview",
770
+ children: inputEntries ? inputEntries.map(([key, value]) => /* @__PURE__ */ jsxs("div", {
771
+ className: "prompt-input__approval-preview-row",
772
+ children: [
773
+ /* @__PURE__ */ jsx("span", {
774
+ className: "prompt-input__approval-preview-key",
775
+ children: key
776
+ }),
777
+ " ",
778
+ formatApprovalValue(value)
779
+ ]
780
+ }, key)) : /* @__PURE__ */ jsx("div", {
781
+ className: "prompt-input__approval-preview-row",
782
+ children: formatApprovalValue(input)
783
+ })
784
+ }) : null,
785
+ /* @__PURE__ */ jsxs("div", {
786
+ className: "prompt-input__approval-options",
787
+ children: [/* @__PURE__ */ jsxs("button", {
788
+ ref: yesRef,
789
+ type: "button",
790
+ className: "prompt-input__approval-option",
791
+ "data-selected": selected === "approve" || void 0,
792
+ disabled: busy,
793
+ onClick: () => respond(true),
794
+ onFocus: () => setSelected("approve"),
795
+ children: [
796
+ /* @__PURE__ */ jsx("span", {
797
+ className: "prompt-input__approval-key",
798
+ children: "1"
799
+ }),
800
+ "Yes",
801
+ /* @__PURE__ */ jsx("span", {
802
+ className: "prompt-input__approval-arrows",
803
+ "aria-hidden": "true",
804
+ children: "↑↓"
805
+ })
806
+ ]
807
+ }), /* @__PURE__ */ jsxs("div", {
808
+ className: "prompt-input__approval-option prompt-input__approval-deny",
809
+ "data-selected": selected === "deny" || void 0,
810
+ children: [
811
+ /* @__PURE__ */ jsx("span", {
812
+ className: "prompt-input__approval-key",
813
+ "aria-hidden": "true",
814
+ children: /* @__PURE__ */ jsx(PencilIcon, { size: 11 })
815
+ }),
816
+ /* @__PURE__ */ jsx("input", {
817
+ ref: reasonRef,
818
+ type: "text",
819
+ className: "prompt-input__approval-reason",
820
+ "aria-label": `Deny ${toolName} and tell the agent what to do differently`,
821
+ placeholder: "No, and tell the agent what to do differently",
822
+ value: reason,
823
+ disabled: busy,
824
+ onFocus: () => setSelected("deny"),
825
+ onChange: (event) => {
826
+ setSelected("deny");
827
+ setReason(event.currentTarget.value);
828
+ },
829
+ onKeyDown: (event) => {
830
+ if (event.key === "Enter" && !event.nativeEvent.isComposing) {
831
+ event.preventDefault();
832
+ respond(false);
833
+ }
834
+ }
835
+ }),
836
+ onSkip ? /* @__PURE__ */ jsx(Button, {
837
+ type: "button",
838
+ size: "sm",
839
+ variant: "ghost",
840
+ color: "neutral",
841
+ className: "prompt-input__approval-skip",
842
+ disabled: busy,
843
+ onClick: onSkip,
844
+ children: "Skip"
845
+ }) : null,
846
+ /* @__PURE__ */ jsxs(Button, {
847
+ type: "button",
848
+ size: "sm",
849
+ color: "primary",
850
+ className: "prompt-input__approval-submit",
851
+ disabled: busy,
852
+ onClick: submit,
853
+ children: [selected === "approve" ? "Approve" : "Submit", /* @__PURE__ */ jsx("kbd", {
854
+ className: "prompt-input__approval-kbd",
855
+ children: "⏎"
856
+ })]
857
+ })
858
+ ]
859
+ })]
860
+ })
861
+ ]
862
+ });
863
+ }
551
864
  const PromptInputSelect = Select;
552
865
  function PromptInputSelectTrigger(props) {
553
866
  return /* @__PURE__ */ jsx(SelectTrigger, { ...props });
@@ -669,11 +982,11 @@ function fileToPart(file) {
669
982
  };
670
983
  }
671
984
  function revokeFileUrls(files) {
672
- for (const file of files) if (file.url?.startsWith("blob:")) URL.revokeObjectURL(file.url);
985
+ for (const file of files) if (file.url.startsWith("blob:")) URL.revokeObjectURL(file.url);
673
986
  }
674
987
  async function resolveSubmittedFile(file) {
675
988
  const { id: _id, ...part } = file;
676
- if (!part.url?.startsWith("blob:")) return part;
989
+ if (!part.url.startsWith("blob:")) return part;
677
990
  const dataUrl = await blobUrlToDataUrl(part.url);
678
991
  return {
679
992
  ...part,
@@ -734,4 +1047,4 @@ function createId() {
734
1047
  return globalThis.crypto?.randomUUID?.() ?? `prompt-input-${Date.now()}-${Math.random()}`;
735
1048
  }
736
1049
  //#endregion
737
- export { PromptInput, PromptInputActionAddAttachments, PromptInputActionAddScreenshot, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuItem, PromptInputActionMenuTrigger, PromptInputBody, PromptInputButton, PromptInputCommand, PromptInputCommandEmpty, PromptInputCommandGroup, PromptInputCommandInput, PromptInputCommandItem, PromptInputCommandList, PromptInputCommandSeparator, PromptInputFooter, PromptInputHeader, PromptInputHoverCard, PromptInputHoverCardContent, PromptInputHoverCardTrigger, PromptInputProvider, PromptInputSelect, PromptInputSelectContent, PromptInputSelectItem, PromptInputSelectTrigger, PromptInputSelectValue, PromptInputSubmit, PromptInputTab, PromptInputTabBody, PromptInputTabItem, PromptInputTabLabel, PromptInputTabsList, PromptInputTextarea, PromptInputTools, usePromptInputAttachments, usePromptInputController, usePromptInputReferencedSources, useProviderAttachments };
1050
+ export { PromptInput, PromptInputActionAddAttachments, PromptInputActionAddScreenshot, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuItem, PromptInputActionMenuTrigger, PromptInputApproval, PromptInputAttachment, PromptInputAttachments, PromptInputBody, PromptInputButton, PromptInputCommand, PromptInputCommandEmpty, PromptInputCommandGroup, PromptInputCommandInput, PromptInputCommandItem, PromptInputCommandList, PromptInputCommandSeparator, PromptInputFooter, PromptInputHeader, PromptInputHoverCard, PromptInputHoverCardContent, PromptInputHoverCardTrigger, PromptInputPermissionSelector, PromptInputProvider, PromptInputSelect, PromptInputSelectContent, PromptInputSelectItem, PromptInputSelectTrigger, PromptInputSelectValue, PromptInputSubmit, PromptInputTab, PromptInputTabBody, PromptInputTabItem, PromptInputTabLabel, PromptInputTabsList, PromptInputTextarea, PromptInputTools, getApprovalRequestId, getPendingToolApprovals, usePromptInputAttachments, usePromptInputController, usePromptInputReferencedSources, useProviderAttachments };
@@ -1,6 +1,6 @@
1
1
  import { CollapsiblePanel, CollapsibleRoot, CollapsibleTrigger } from "./Collapsible.js";
2
2
  import { t as cx } from "../class-names-9UtZwb0J.js";
3
- import { d as DotIcon, h as FileIcon, l as ChevronRightIcon, o as CheckIcon } from "../icons-Bf7JMKk-.js";
3
+ import { d as DotIcon, h as FileIcon, l as ChevronRightIcon, o as CheckIcon } from "../icons-DQC4Zw5R.js";
4
4
  import { Button } from "./Button.js";
5
5
  import { Badge } from "./Badge.js";
6
6
  import { ScrollArea } from "./ScrollArea.js";