@mcp-b/react-components 0.13.0 → 0.14.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.
@@ -1,8 +1,9 @@
1
- import { tt as PromptInputMessage } from "./PromptInput-p5KmOmt1.js";
1
+ import { W as PromptInputDictationProps, tt as PromptInputMessage } from "./PromptInput-ClNqBiIw.js";
2
2
  import * as React from "react";
3
3
  import { ChatAddToolApproveResponseFunction, ChatStatus, UIMessage } from "ai";
4
4
  import { PendingApproval, Think } from "@cloudflare/think";
5
5
  import { AgentStub } from "agents/client";
6
+ import { UseVoiceInputReturn } from "@cloudflare/voice/react";
6
7
 
7
8
  //#region src/components/AgentChat.d.ts
8
9
  type AgentChatPart<MessageT extends UIMessage = UIMessage> = MessageT["parts"][number];
@@ -85,6 +86,10 @@ interface AgentChatProps<MessageT extends UIMessage = UIMessage> {
85
86
  emptyState?: React.ReactNode;
86
87
  /** Extra controls rendered in the composer toolbar. */
87
88
  composerTools?: React.ReactNode;
89
+ /** Whole upstream voice-input hook result used by the built-in dictation recorder. */
90
+ voiceInput?: UseVoiceInputReturn;
91
+ /** Host prerequisite run before the built-in recorder calls `voiceInput.start()`. */
92
+ beforeVoiceStart?: PromptInputDictationProps["beforeStart"];
88
93
  /**
89
94
  * Rendered in the prompt-composer header before attachments and the text
90
95
  * field. Use it to compose a compact Activity, task state, or app-specific
@@ -175,6 +180,8 @@ declare function AgentChat<MessageT extends UIMessage = UIMessage>({
175
180
  emptyState,
176
181
  composerHeader,
177
182
  composerTools,
183
+ voiceInput,
184
+ beforeVoiceStart,
178
185
  composerAddMenuItems,
179
186
  notice,
180
187
  onRegenerate,
@@ -235,6 +235,16 @@ declare function PromptInputButton({
235
235
  interface PromptInputDictationProps extends Omit<PromptInputButtonProps, "children" | "onClick" | "tooltip"> {
236
236
  /** The whole upstream `useVoiceInput` result; authentication and transport stay in the host. */
237
237
  voice: UseVoiceInputReturn;
238
+ /**
239
+ * Runs immediately before the unchanged upstream `voice.start()` call.
240
+ * Use this for host-specific prerequisites, such as opening an extension tab
241
+ * that can present Chrome's microphone permission prompt. Reject to prevent
242
+ * `voice.start()` and surface the error in the composer.
243
+ *
244
+ * @see https://github.com/cloudflare/agents/blob/main/examples/voice-input/src/client.tsx
245
+ * @see https://developer.chrome.com/docs/extensions/reference/api/offscreen#type-Reason
246
+ */
247
+ beforeStart?: (voice: UseVoiceInputReturn) => void | Promise<void>;
238
248
  }
239
249
  /**
240
250
  * Voice-dictation control for PromptInput. Final upstream transcripts are
@@ -242,6 +252,7 @@ interface PromptInputDictationProps extends Omit<PromptInputButtonProps, "childr
242
252
  */
243
253
  declare function PromptInputDictation({
244
254
  voice,
255
+ beforeStart,
245
256
  className,
246
257
  disabled,
247
258
  ref,
@@ -1,4 +1,4 @@
1
- import { a as AgentChatRenderPartContext, r as AgentChatProps } from "./AgentChat-Br6tKEl8.js";
1
+ import { a as AgentChatRenderPartContext, r as AgentChatProps } from "./AgentChat-Cgb1xuT7.js";
2
2
  import { s as ThinkChatPart } from "./ThinkChatToolParts-Cv4o7j6F.js";
3
3
  import * as React from "react";
4
4
  import { DynamicToolUIPart, ToolUIPart, UIMessage } from "ai";
@@ -1,2 +1,2 @@
1
- import { a as AgentChatRenderPartContext, i as AgentChatRenderMessageContext, n as AgentChatPart, r as AgentChatProps, t as AgentChat } from "../AgentChat-Br6tKEl8.js";
1
+ import { a as AgentChatRenderPartContext, i as AgentChatRenderMessageContext, n as AgentChatPart, r as AgentChatProps, t as AgentChat } from "../AgentChat-Cgb1xuT7.js";
2
2
  export { AgentChat, AgentChatPart, AgentChatProps, AgentChatRenderMessageContext, AgentChatRenderPartContext };
@@ -7,7 +7,7 @@ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, Message
7
7
  import { ConversationEmptyState } from "./Conversation.js";
8
8
  import { Message, MessageAction, MessageActions, MessageAttachment, MessageContent, MessageResponse } from "./Message.js";
9
9
  import { Marker, MarkerContent } from "./Marker.js";
10
- import { PromptInput, PromptInputActionAddAttachments, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuTrigger, PromptInputApproval, PromptInputAttachments, PromptInputBody, PromptInputButton, PromptInputFooter, PromptInputHeader, PromptInputPermissionSelector, PromptInputSubmit, PromptInputTextarea, PromptInputTools, getApprovalRequestId, getApprovalStateKey, getPendingToolApprovals, usePromptInputAttachments } from "./PromptInput.js";
10
+ import { PromptInput, PromptInputActionAddAttachments, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuTrigger, PromptInputApproval, PromptInputAttachments, PromptInputBody, PromptInputButton, PromptInputDictation, PromptInputFooter, PromptInputHeader, PromptInputPermissionSelector, PromptInputSubmit, PromptInputTextarea, PromptInputTools, getApprovalRequestId, getApprovalStateKey, getPendingToolApprovals, usePromptInputAttachments } from "./PromptInput.js";
11
11
  import { Reasoning, ReasoningContent, ReasoningTrigger } from "./Reasoning.js";
12
12
  import { Source, Sources, SourcesContent, SourcesTrigger } from "./Sources.js";
13
13
  import { t as CopyButton } from "../copy-button-DUMLYdsk.js";
@@ -310,7 +310,7 @@ function renderDefaultPart(part) {
310
310
  * transport. Product code that talks to a Cloudflare Think agent should render
311
311
  * `ThinkChat`; use this directly only for plain AI SDK or read-only messages.
312
312
  */
313
- function AgentChat({ className, messages, status = "ready", onSubmit, onStop, placeholder = "Ask anything...", disabled, emptyState, composerHeader, composerTools, composerAddMenuItems, notice, onRegenerate, onEditAndResend, onApprovalResponse, thinkStub, onExecutionSettled, pendingApprovals: durableApprovals = EMPTY_PENDING_APPROVALS, contextWindow, renderPart, renderMessageAfter, ref }) {
313
+ function AgentChat({ className, messages, status = "ready", onSubmit, onStop, placeholder = "Ask anything...", disabled, emptyState, composerHeader, composerTools, voiceInput, beforeVoiceStart, composerAddMenuItems, notice, onRegenerate, onEditAndResend, onApprovalResponse, thinkStub, onExecutionSettled, pendingApprovals: durableApprovals = EMPTY_PENDING_APPROVALS, contextWindow, renderPart, renderMessageAfter, ref }) {
314
314
  const [copyAnnouncement, setCopyAnnouncement] = React.useState("");
315
315
  const copyAnnouncementTimer = React.useRef(null);
316
316
  const announceCopyStatus = React.useCallback((message) => {
@@ -551,7 +551,12 @@ function AgentChat({ className, messages, status = "ready", onSubmit, onStop, pl
551
551
  value: permissionMode,
552
552
  onValueChange: setPermissionMode
553
553
  }) : null,
554
- composerTools
554
+ composerTools,
555
+ voiceInput ? /* @__PURE__ */ jsx(PromptInputDictation, {
556
+ voice: voiceInput,
557
+ beforeStart: beforeVoiceStart,
558
+ disabled
559
+ }) : null
555
560
  ] }), /* @__PURE__ */ jsxs("div", {
556
561
  className: "prompt-input__footer-end",
557
562
  children: [contextWindow ? /* @__PURE__ */ jsxs(Context, {
@@ -16,7 +16,7 @@ interface McpServerPickerProps {
16
16
  onRetry?: McpServerConnectionAction;
17
17
  /** Called when a ready/connected server should refresh discovery through an app-owned Agent RPC. */
18
18
  onRefresh?: McpServerConnectionAction;
19
- /** Called when a server transport should close but the stored config should remain. */
19
+ /** Called when an authenticating or connected server should be removed or disconnected. */
20
20
  onDisconnect?: McpServerConnectionAction;
21
21
  /** Offset from the plus trigger to the menu, useful for prompt composers. */
22
22
  sideOffset?: number;
@@ -120,6 +120,12 @@ function McpServerPickerRow({ server, mcp, onConnect, onAuthorize, onDisconnect,
120
120
  label: pending("authorize") ? `Opening ${server.name}` : `Authorize ${server.name}`,
121
121
  onClick: () => onAuthorize(connectedServerId, connectedServer)
122
122
  }) : null,
123
+ connectedServer?.state === "authenticating" && connectedServerId && onDisconnect ? /* @__PURE__ */ jsx(McpServerActionItem, {
124
+ disabled: pending("disconnect"),
125
+ icon: /* @__PURE__ */ jsx(MinusIcon, {}),
126
+ label: pending("disconnect") ? `Cancelling ${server.name} authentication` : `Cancel ${server.name} authentication`,
127
+ onClick: () => onDisconnect(connectedServerId, connectedServer)
128
+ }) : null,
123
129
  connectedServer?.state === "failed" && connectedServerId && onRetry ? /* @__PURE__ */ jsx(McpServerActionItem, {
124
130
  disabled: pending("retry"),
125
131
  icon: /* @__PURE__ */ jsx(RefreshIcon, {}),
@@ -1,2 +1,2 @@
1
- import { $ as PromptInputHoverCardTrigger, A as PromptInputCommandEmptyProps, At as getPendingToolApprovals, B as PromptInputCommandSeparator, C as PromptInputBody, Ct as PromptInputTools, D as PromptInputButtonTooltip, Dt as TooltipSide, E as PromptInputButtonProps, Et as TextInputContext, F as PromptInputCommandItem, G as PromptInputFooter, H as PromptInputControllerProps, I as PromptInputCommandItemProps, J as PromptInputHeaderProps, K as PromptInputFooterProps, L as PromptInputCommandList, M as PromptInputCommandGroupProps, Mt as usePromptInputController, N as PromptInputCommandInput, Nt as useProviderAttachments, O as PromptInputCommand, Ot as getApprovalRequestId, P as PromptInputCommandInputProps, Q as PromptInputHoverCardProps, R as PromptInputCommandListProps, S as PromptInputAttachmentsProps, St as PromptInputTextareaProps, T as PromptInputButton, Tt as PromptInputTooltipConfig, U as PromptInputDictation, V as PromptInputCommandSeparatorProps, W as PromptInputDictationProps, X as PromptInputHoverCardContent, Y as PromptInputHoverCard, Z as PromptInputHoverCardContentProps, _ as PromptInputApproval, _t as PromptInputTabLabelProps, a as PromptInputActionAddAttachments, at as PromptInputProvider, b as PromptInputAttachmentProps, bt as PromptInputTabsListProps, c as PromptInputActionAddScreenshotProps, ct as PromptInputSelectProps, d as PromptInputActionMenuContentProps, dt as PromptInputTab, et as PromptInputHoverCardTriggerProps, f as PromptInputActionMenuItem, ft as PromptInputTabBody, g as PromptInputActionMenuTriggerProps, gt as PromptInputTabLabel, h as PromptInputActionMenuTrigger, ht as PromptInputTabItemProps, i as PromptInput, it as PromptInputProps, j as PromptInputCommandGroup, jt as usePromptInputAttachments, k as PromptInputCommandEmpty, kt as getApprovalStateKey, l as PromptInputActionMenu, lt as PromptInputSubmit, m as PromptInputActionMenuProps, mt as PromptInputTabItem, n as PendingToolApproval, nt as PromptInputPermissionSelector, o as PromptInputActionAddAttachmentsProps, ot as PromptInputProviderProps, p as PromptInputActionMenuItemProps, pt as PromptInputTabBodyProps, q as PromptInputHeader, r as PermissionMode, rt as PromptInputPermissionSelectorProps, s as PromptInputActionAddScreenshot, st as PromptInputSelect, t as AttachmentsContext, tt as PromptInputMessage, u as PromptInputActionMenuContent, ut as PromptInputSubmitProps, v as PromptInputApprovalProps, vt as PromptInputTabProps, w as PromptInputBodyProps, wt as PromptInputToolsProps, x as PromptInputAttachments, xt as PromptInputTextarea, y as PromptInputAttachment, yt as PromptInputTabsList, z as PromptInputCommandProps } from "../PromptInput-p5KmOmt1.js";
1
+ import { $ as PromptInputHoverCardTrigger, A as PromptInputCommandEmptyProps, At as getPendingToolApprovals, B as PromptInputCommandSeparator, C as PromptInputBody, Ct as PromptInputTools, D as PromptInputButtonTooltip, Dt as TooltipSide, E as PromptInputButtonProps, Et as TextInputContext, F as PromptInputCommandItem, G as PromptInputFooter, H as PromptInputControllerProps, I as PromptInputCommandItemProps, J as PromptInputHeaderProps, K as PromptInputFooterProps, L as PromptInputCommandList, M as PromptInputCommandGroupProps, Mt as usePromptInputController, N as PromptInputCommandInput, Nt as useProviderAttachments, O as PromptInputCommand, Ot as getApprovalRequestId, P as PromptInputCommandInputProps, Q as PromptInputHoverCardProps, R as PromptInputCommandListProps, S as PromptInputAttachmentsProps, St as PromptInputTextareaProps, T as PromptInputButton, Tt as PromptInputTooltipConfig, U as PromptInputDictation, V as PromptInputCommandSeparatorProps, W as PromptInputDictationProps, X as PromptInputHoverCardContent, Y as PromptInputHoverCard, Z as PromptInputHoverCardContentProps, _ as PromptInputApproval, _t as PromptInputTabLabelProps, a as PromptInputActionAddAttachments, at as PromptInputProvider, b as PromptInputAttachmentProps, bt as PromptInputTabsListProps, c as PromptInputActionAddScreenshotProps, ct as PromptInputSelectProps, d as PromptInputActionMenuContentProps, dt as PromptInputTab, et as PromptInputHoverCardTriggerProps, f as PromptInputActionMenuItem, ft as PromptInputTabBody, g as PromptInputActionMenuTriggerProps, gt as PromptInputTabLabel, h as PromptInputActionMenuTrigger, ht as PromptInputTabItemProps, i as PromptInput, it as PromptInputProps, j as PromptInputCommandGroup, jt as usePromptInputAttachments, k as PromptInputCommandEmpty, kt as getApprovalStateKey, l as PromptInputActionMenu, lt as PromptInputSubmit, m as PromptInputActionMenuProps, mt as PromptInputTabItem, n as PendingToolApproval, nt as PromptInputPermissionSelector, o as PromptInputActionAddAttachmentsProps, ot as PromptInputProviderProps, p as PromptInputActionMenuItemProps, pt as PromptInputTabBodyProps, q as PromptInputHeader, r as PermissionMode, rt as PromptInputPermissionSelectorProps, s as PromptInputActionAddScreenshot, st as PromptInputSelect, t as AttachmentsContext, tt as PromptInputMessage, u as PromptInputActionMenuContent, ut as PromptInputSubmitProps, v as PromptInputApprovalProps, vt as PromptInputTabProps, w as PromptInputBodyProps, wt as PromptInputToolsProps, x as PromptInputAttachments, xt as PromptInputTextarea, y as PromptInputAttachment, yt as PromptInputTabsList, z as PromptInputCommandProps } from "../PromptInput-ClNqBiIw.js";
2
2
  export { AttachmentsContext, 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, PromptInputDictation, PromptInputDictationProps, PromptInputFooter, PromptInputFooterProps, PromptInputHeader, PromptInputHeaderProps, PromptInputHoverCard, PromptInputHoverCardContent, PromptInputHoverCardContentProps, PromptInputHoverCardProps, PromptInputHoverCardTrigger, PromptInputHoverCardTriggerProps, PromptInputMessage, PromptInputPermissionSelector, PromptInputPermissionSelectorProps, PromptInputProps, PromptInputProvider, PromptInputProviderProps, PromptInputSelect, PromptInputSelectProps, PromptInputSubmit, PromptInputSubmitProps, PromptInputTab, PromptInputTabBody, PromptInputTabBodyProps, PromptInputTabItem, PromptInputTabItemProps, PromptInputTabLabel, PromptInputTabLabelProps, PromptInputTabProps, PromptInputTabsList, PromptInputTabsListProps, PromptInputTextarea, PromptInputTextareaProps, PromptInputTools, PromptInputToolsProps, PromptInputTooltipConfig, TextInputContext, TooltipSide, getApprovalRequestId, getApprovalStateKey, getPendingToolApprovals, usePromptInputAttachments, usePromptInputController, useProviderAttachments };
@@ -1,5 +1,5 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { D as PencilIcon, F as StopIcon, L as WarningIcon, N as SpinnerIcon, P as SquareIcon, S as MicrophoneIcon, T as PaperclipIcon, h as FileIcon, i as ArrowUpIcon, k as PlusIcon, o as ChevronDownIcon, w as MonitorIcon, z as XIcon } from "../icons-Ba9THQKz.js";
2
+ import { D as PencilIcon, F as StopIcon, L as WarningIcon, N as SpinnerIcon, P as SquareIcon, R as WrenchIcon, S as MicrophoneIcon, T as PaperclipIcon, h as FileIcon, i as ArrowUpIcon, k as PlusIcon, o as ChevronDownIcon, w as MonitorIcon, z as XIcon } from "../icons-Ba9THQKz.js";
3
3
  import { Button } from "./Button.js";
4
4
  import { Tooltip } from "./Tooltip.js";
5
5
  import { t as AttachmentPreview } from "../attachment-preview-DIs50Q0h.js";
@@ -450,6 +450,7 @@ function PromptInputButton({ className, tooltip, variant = "ghost", color = "neu
450
450
  const resolvedSize = size ?? (React.Children.count(children) > 1 ? "xs" : "icon-xs");
451
451
  const tooltipConfig = typeof tooltip === "string" ? { content: tooltip } : tooltip;
452
452
  const fallbackLabel = ariaLabel ?? (typeof tooltipConfig?.content === "string" ? tooltipConfig.content : void 0);
453
+ const hasResponsiveLabel = Boolean(tooltipConfig && React.Children.count(children) > 1);
453
454
  const button = /* @__PURE__ */ jsx(Button, {
454
455
  ref,
455
456
  type: "button",
@@ -458,6 +459,7 @@ function PromptInputButton({ className, tooltip, variant = "ghost", color = "neu
458
459
  size: resolvedSize,
459
460
  className: cx("prompt-input__button", className),
460
461
  "aria-label": fallbackLabel,
462
+ "data-responsive-label": hasResponsiveLabel || void 0,
461
463
  ...props,
462
464
  children
463
465
  });
@@ -478,10 +480,14 @@ function PromptInputButton({ className, tooltip, variant = "ghost", color = "neu
478
480
  * Voice-dictation control for PromptInput. Final upstream transcripts are
479
481
  * appended to the composer while interim text remains ephemeral.
480
482
  */
481
- function PromptInputDictation({ voice, className, disabled, ref, ...props }) {
483
+ function PromptInputDictation({ voice, beforeStart, className, disabled, ref, ...props }) {
482
484
  const controller = useOptionalPromptInputController();
485
+ const attachments = usePromptInputAttachments();
483
486
  const buttonRef = React.useRef(null);
484
487
  const committedTranscriptRef = React.useRef("");
488
+ const submitAfterStopRef = React.useRef(false);
489
+ const recordingStartedAtRef = React.useRef(null);
490
+ const [elapsedSeconds, setElapsedSeconds] = React.useState(0);
485
491
  const [isStarting, setIsStarting] = React.useState(false);
486
492
  const [startError, setStartError] = React.useState(null);
487
493
  React.useImperativeHandle(ref, () => buttonRef.current, []);
@@ -501,49 +507,195 @@ function PromptInputDictation({ voice, className, disabled, ref, ...props }) {
501
507
  textarea.value = appendDictationTranscript(textarea.value, addition);
502
508
  textarea.dispatchEvent(new Event("input", { bubbles: true }));
503
509
  }, [controller, voice.transcript]);
510
+ React.useEffect(() => {
511
+ if (!voice.isListening) {
512
+ recordingStartedAtRef.current = null;
513
+ setElapsedSeconds(0);
514
+ if (submitAfterStopRef.current) {
515
+ submitAfterStopRef.current = false;
516
+ window.requestAnimationFrame(() => buttonRef.current?.form?.requestSubmit());
517
+ }
518
+ return;
519
+ }
520
+ recordingStartedAtRef.current ??= Date.now();
521
+ const updateElapsed = () => {
522
+ setElapsedSeconds(Math.floor((Date.now() - (recordingStartedAtRef.current ?? Date.now())) / 1e3));
523
+ };
524
+ updateElapsed();
525
+ const timer = window.setInterval(updateElapsed, 250);
526
+ return () => window.clearInterval(timer);
527
+ }, [voice.isListening]);
504
528
  const error = startError ?? voice.error;
505
529
  const listening = voice.isListening;
506
530
  const label = listening ? "Stop dictation" : error ? "Retry dictation" : "Start dictation";
507
531
  const status = error ? `Dictation failed: ${error}` : listening ? voice.interimTranscript ? "Listening. Speech detected." : "Listening for speech." : isStarting ? "Starting dictation." : "";
508
532
  const level = Math.min(Math.max(voice.audioLevel, 0), 1);
509
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(PromptInputButton, {
510
- ref: buttonRef,
511
- className: cx("prompt-input__dictation", className),
512
- tooltip: {
513
- content: label,
514
- side: "top"
515
- },
516
- "aria-label": label,
517
- "aria-pressed": listening,
518
- "data-error": error ? "true" : void 0,
519
- "data-listening": listening ? "true" : void 0,
520
- "data-starting": isStarting ? "true" : void 0,
521
- disabled: disabled || isStarting,
522
- onClick: () => {
523
- setStartError(null);
524
- if (listening) {
525
- voice.stop();
533
+ const elapsed = formatDictationElapsed(elapsedSeconds);
534
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
535
+ /* @__PURE__ */ jsx(PromptInputButton, {
536
+ ref: buttonRef,
537
+ className: cx("prompt-input__dictation", className),
538
+ tooltip: {
539
+ content: label,
540
+ side: "top"
541
+ },
542
+ "aria-label": label,
543
+ "aria-hidden": listening || void 0,
544
+ "aria-pressed": listening,
545
+ "data-error": error ? "true" : void 0,
546
+ "data-listening": listening ? "true" : void 0,
547
+ "data-starting": isStarting ? "true" : void 0,
548
+ disabled: disabled || isStarting || listening,
549
+ tabIndex: listening ? -1 : void 0,
550
+ onClick: () => {
551
+ setStartError(null);
552
+ if (listening) {
553
+ voice.stop();
554
+ return;
555
+ }
556
+ setIsStarting(true);
557
+ Promise.resolve().then(() => beforeStart?.(voice)).then(() => voice.start()).catch((reason) => {
558
+ setStartError(reason instanceof Error ? reason.message : String(reason));
559
+ }).finally(() => setIsStarting(false));
560
+ },
561
+ ...props,
562
+ children: /* @__PURE__ */ jsx("span", {
563
+ className: "prompt-input__dictation-icon",
564
+ style: { "--prompt-input-dictation-level": level },
565
+ "aria-hidden": "true",
566
+ children: isStarting ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : listening ? /* @__PURE__ */ jsx(StopIcon, {}) : /* @__PURE__ */ jsx(MicrophoneIcon, {})
567
+ })
568
+ }),
569
+ listening ? /* @__PURE__ */ jsxs("div", {
570
+ className: "prompt-input__recording",
571
+ role: "group",
572
+ "aria-label": "Voice recording controls",
573
+ children: [
574
+ /* @__PURE__ */ jsx(PromptInputButton, {
575
+ className: "prompt-input__recording-add",
576
+ tooltip: "Add photos or files",
577
+ onClick: () => attachments.openFileDialog(),
578
+ children: /* @__PURE__ */ jsx(PlusIcon, {})
579
+ }),
580
+ /* @__PURE__ */ jsx(PromptInputRecordingWaveform, {
581
+ active: true,
582
+ level
583
+ }),
584
+ /* @__PURE__ */ jsx("time", {
585
+ className: "prompt-input__recording-time",
586
+ dateTime: `PT${elapsedSeconds}S`,
587
+ children: elapsed
588
+ }),
589
+ /* @__PURE__ */ jsx(Button, {
590
+ className: "prompt-input__recording-button",
591
+ type: "button",
592
+ variant: "normal",
593
+ color: "neutral",
594
+ size: "icon",
595
+ "aria-label": "Stop dictation",
596
+ onClick: () => voice.stop(),
597
+ children: /* @__PURE__ */ jsx(SquareIcon, { size: 12 })
598
+ }),
599
+ /* @__PURE__ */ jsx(Button, {
600
+ className: "prompt-input__recording-button",
601
+ type: "button",
602
+ color: "primary",
603
+ size: "icon",
604
+ "aria-label": "Stop dictation and send",
605
+ onClick: () => {
606
+ submitAfterStopRef.current = true;
607
+ voice.stop();
608
+ },
609
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, { size: 18 })
610
+ })
611
+ ]
612
+ }) : null,
613
+ /* @__PURE__ */ jsx("span", {
614
+ className: "prompt-input__dictation-status",
615
+ role: "status",
616
+ "aria-live": "polite",
617
+ "aria-atomic": "true",
618
+ children: status
619
+ })
620
+ ] });
621
+ }
622
+ /**
623
+ * Scrolling canvas waveform adapted from ElevenLabs UI's Waveform component.
624
+ * Cloudflare Voice already owns the microphone stream, so this renderer
625
+ * consumes its upstream `audioLevel` instead of requesting a second stream.
626
+ */
627
+ function PromptInputRecordingWaveform({ active, level }) {
628
+ const canvasRef = React.useRef(null);
629
+ const containerRef = React.useRef(null);
630
+ const historyRef = React.useRef([]);
631
+ const levelRef = React.useRef(level);
632
+ levelRef.current = level;
633
+ React.useEffect(() => {
634
+ const canvas = canvasRef.current;
635
+ const container = containerRef.current;
636
+ if (!canvas || !container) return;
637
+ const resize = () => {
638
+ const rect = container.getBoundingClientRect();
639
+ const dpr = window.devicePixelRatio || 1;
640
+ canvas.width = Math.max(1, Math.round(rect.width * dpr));
641
+ canvas.height = Math.max(1, Math.round(rect.height * dpr));
642
+ canvas.style.width = `${rect.width}px`;
643
+ canvas.style.height = `${rect.height}px`;
644
+ canvas.getContext("2d")?.setTransform(dpr, 0, 0, dpr, 0, 0);
645
+ };
646
+ const observer = new ResizeObserver(resize);
647
+ observer.observe(container);
648
+ resize();
649
+ const barWidth = 2;
650
+ const step = 4;
651
+ let animationFrame = 0;
652
+ let lastUpdate = 0;
653
+ let smoothedLevel = levelRef.current;
654
+ const draw = (time) => {
655
+ const context = canvas.getContext("2d");
656
+ const rect = canvas.getBoundingClientRect();
657
+ if (!context || rect.width === 0 || rect.height === 0) {
658
+ animationFrame = window.requestAnimationFrame(draw);
526
659
  return;
527
660
  }
528
- setIsStarting(true);
529
- voice.start().catch((reason) => {
530
- setStartError(reason instanceof Error ? reason.message : String(reason));
531
- }).finally(() => setIsStarting(false));
532
- },
533
- ...props,
534
- children: /* @__PURE__ */ jsx("span", {
535
- className: "prompt-input__dictation-icon",
536
- style: { "--prompt-input-dictation-level": level },
537
- "aria-hidden": "true",
538
- children: isStarting ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : listening ? /* @__PURE__ */ jsx(StopIcon, {}) : /* @__PURE__ */ jsx(MicrophoneIcon, {})
539
- })
540
- }), /* @__PURE__ */ jsx("span", {
541
- className: "prompt-input__dictation-status",
542
- role: "status",
543
- "aria-live": "polite",
544
- "aria-atomic": "true",
545
- children: status
546
- })] });
661
+ const barCount = Math.max(1, Math.floor(rect.width / step));
662
+ if (active && time - lastUpdate >= 50) {
663
+ smoothedLevel += (levelRef.current - smoothedLevel) * .45;
664
+ historyRef.current.push(Math.max(.08, Math.min(1, smoothedLevel)));
665
+ if (historyRef.current.length > barCount) historyRef.current.shift();
666
+ lastUpdate = time;
667
+ }
668
+ context.clearRect(0, 0, rect.width, rect.height);
669
+ context.fillStyle = getComputedStyle(canvas).color;
670
+ const centerY = rect.height / 2;
671
+ for (let index = 0; index < barCount; index += 1) {
672
+ const historyIndex = historyRef.current.length - barCount + index;
673
+ const value = historyIndex >= 0 ? historyRef.current[historyIndex] ?? .08 : .08;
674
+ const barHeight = Math.max(2, value * rect.height * .9);
675
+ const x = index * step;
676
+ context.globalAlpha = .45 + value * .55;
677
+ context.beginPath();
678
+ context.roundRect(x, centerY - barHeight / 2, barWidth, barHeight, 1);
679
+ context.fill();
680
+ }
681
+ context.globalAlpha = 1;
682
+ animationFrame = window.requestAnimationFrame(draw);
683
+ };
684
+ animationFrame = window.requestAnimationFrame(draw);
685
+ return () => {
686
+ observer.disconnect();
687
+ window.cancelAnimationFrame(animationFrame);
688
+ };
689
+ }, [active]);
690
+ return /* @__PURE__ */ jsx("div", {
691
+ ref: containerRef,
692
+ className: "prompt-input__recording-waveform",
693
+ "aria-hidden": "true",
694
+ children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef })
695
+ });
696
+ }
697
+ function formatDictationElapsed(totalSeconds) {
698
+ return `${Math.floor(totalSeconds / 60)}:${(totalSeconds % 60).toString().padStart(2, "0")}`;
547
699
  }
548
700
  function appendDictationTranscript(current, transcript) {
549
701
  if (!current) return transcript;
@@ -635,23 +787,38 @@ const PERMISSION_MODES = [{
635
787
  */
636
788
  function PromptInputPermissionSelector({ value, onValueChange, question = "How should agent actions be approved?" }) {
637
789
  const selected = PERMISSION_MODES.find((mode) => mode.value === value) ?? PERMISSION_MODES[0];
638
- return /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsx(Menu.Trigger, {
790
+ const trigger = /* @__PURE__ */ jsx(Menu.Trigger, {
639
791
  unstyled: true,
640
792
  render: /* @__PURE__ */ jsxs(PromptInputButton, {
641
793
  size: "xs",
642
794
  className: "prompt-input__permissions-trigger",
643
795
  "data-mode": value,
644
796
  "aria-label": selected.label,
645
- children: [/* @__PURE__ */ jsx("span", {
646
- className: "prompt-input__permissions-current",
647
- children: PERMISSION_MODES.map((mode) => /* @__PURE__ */ jsxs("span", {
648
- className: "prompt-input__permissions-current-option",
649
- "data-active": mode.value === value || void 0,
650
- children: [mode.value === "bypass" ? /* @__PURE__ */ jsx(WarningIcon, { size: 14 }) : null, mode.label]
651
- }, mode.value))
652
- }), /* @__PURE__ */ jsx(ChevronDownIcon, { size: 12 })]
797
+ children: [
798
+ /* @__PURE__ */ jsx("span", {
799
+ className: "prompt-input__permissions-icon",
800
+ children: value === "bypass" ? /* @__PURE__ */ jsx(WarningIcon, { size: 14 }) : /* @__PURE__ */ jsx(WrenchIcon, { size: 14 })
801
+ }),
802
+ /* @__PURE__ */ jsx("span", {
803
+ className: "prompt-input__permissions-current",
804
+ children: PERMISSION_MODES.map((mode) => /* @__PURE__ */ jsx("span", {
805
+ className: "prompt-input__permissions-current-option",
806
+ "data-active": mode.value === value || void 0,
807
+ children: mode.label
808
+ }, mode.value))
809
+ }),
810
+ /* @__PURE__ */ jsx(ChevronDownIcon, {
811
+ className: "prompt-input__permissions-chevron",
812
+ size: 12
813
+ })
814
+ ]
653
815
  })
654
- }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsxs(Menu.Popup, {
816
+ });
817
+ return /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsxs(Tooltip.Root, { children: [/* @__PURE__ */ jsx(Tooltip.Trigger, { render: trigger }), /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
818
+ side: "top",
819
+ sideOffset: 6,
820
+ children: /* @__PURE__ */ jsx(Tooltip.Popup, { children: selected.label })
821
+ }) })] }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsxs(Menu.Popup, {
655
822
  className: "prompt-input__permissions-menu",
656
823
  children: [/* @__PURE__ */ jsx("div", {
657
824
  className: "prompt-input__permissions-question",
@@ -1,8 +1,8 @@
1
- import { a as AgentChatRenderPartContext, r as AgentChatProps } from "../AgentChat-Br6tKEl8.js";
1
+ import { a as AgentChatRenderPartContext, r as AgentChatProps } from "../AgentChat-Cgb1xuT7.js";
2
2
  import { n as BrowserLiveViewProps, t as BrowserLiveView } from "../BrowserLiveView-BV5qgFgI.js";
3
3
  import { n as BrowserReplayProps, t as BrowserReplay } from "../BrowserReplay-xWvRjRAC.js";
4
4
  import { _ as isThinkChatActivityPart } from "../ThinkChatToolParts-Cv4o7j6F.js";
5
- import { a as ThinkChatToolRenderers, c as renderThinkChatActivityPart, i as ThinkChatToolRenderer, n as ThinkChatActivityProps, o as createThinkChatActivityRenderer, r as ThinkChatActivityRendererOptions, s as describeThinkChatActivityPart, t as ThinkChatActivity } from "../ThinkChatActivity-Cuk28Js_.js";
5
+ import { a as ThinkChatToolRenderers, c as renderThinkChatActivityPart, i as ThinkChatToolRenderer, n as ThinkChatActivityProps, o as createThinkChatActivityRenderer, r as ThinkChatActivityRendererOptions, s as describeThinkChatActivityPart, t as ThinkChatActivity } from "../ThinkChatActivity-m9orbdeI.js";
6
6
  import { n as ThinkChatValue } from "../ThinkChatContext-C3Eb1Xpi.js";
7
7
  import { FileInfo, UseWorkspaceOptions, WorkspaceExplorer, WorkspaceExplorerProps, WorkspaceFileState, WorkspaceInfo, WorkspaceSource, WorkspaceState, inferWorkspaceLanguage, useWorkspace } from "./WorkspaceExplorer.js";
8
8
  import * as React from "react";
@@ -10,6 +10,7 @@ import { UIMessage } from "ai";
10
10
  import { UseAgentOptions } from "agents/react";
11
11
  import { PendingApproval, Think } from "@cloudflare/think";
12
12
  import { AgentStub } from "agents/client";
13
+ import { UseVoiceInputReturn } from "@cloudflare/voice/react";
13
14
 
14
15
  //#region src/components/ThinkChat.d.ts
15
16
  interface ThinkChatProviderProps<State = unknown, MessageT extends UIMessage = UIMessage> {
@@ -32,6 +33,10 @@ interface ThinkChatMessagesProps<MessageT extends UIMessage = UIMessage> extends
32
33
  emptyState?: React.ReactNode;
33
34
  /** Extra controls rendered inside the composer, next to the send button. */
34
35
  composerTools?: React.ReactNode;
36
+ /** Whole upstream `useVoiceInput` result for the built-in microphone recorder. */
37
+ voiceInput?: UseVoiceInputReturn;
38
+ /** Host prerequisite run before the built-in recorder calls `voiceInput.start()`. */
39
+ beforeVoiceStart?: AgentChatProps<MessageT>["beforeVoiceStart"];
35
40
  /** Optional product state rendered in the PromptInput header, such as an Activity. */
36
41
  composerHeader?: AgentChatProps<MessageT>["composerHeader"];
37
42
  /** Extra rows rendered in the built-in plus menu after files. */
@@ -1,3 +1,3 @@
1
1
  import { _ as isThinkChatActivityPart } from "../ThinkChatToolParts-Cv4o7j6F.js";
2
- import { a as ThinkChatToolRenderers, c as renderThinkChatActivityPart, i as ThinkChatToolRenderer, n as ThinkChatActivityProps, o as createThinkChatActivityRenderer, r as ThinkChatActivityRendererOptions, s as describeThinkChatActivityPart, t as ThinkChatActivity } from "../ThinkChatActivity-Cuk28Js_.js";
2
+ import { a as ThinkChatToolRenderers, c as renderThinkChatActivityPart, i as ThinkChatToolRenderer, n as ThinkChatActivityProps, o as createThinkChatActivityRenderer, r as ThinkChatActivityRendererOptions, s as describeThinkChatActivityPart, t as ThinkChatActivity } from "../ThinkChatActivity-m9orbdeI.js";
3
3
  export { ThinkChatActivity, ThinkChatActivityProps, ThinkChatActivityRendererOptions, ThinkChatToolRenderer, ThinkChatToolRenderers, createThinkChatActivityRenderer, describeThinkChatActivityPart, isThinkChatActivityPart, renderThinkChatActivityPart };
@@ -4,11 +4,15 @@
4
4
  display: flex;
5
5
  flex-direction: column;
6
6
  width: 100%;
7
+ min-width: 0;
7
8
  /* Hard cap, Codex-style, on the WHOLE unit — collapsed line and expanded
8
9
  log alike — so toggling never reflows the conversation width. Plain rem,
9
10
  not min(100%, …): percentages are ignored in intrinsic-size contributions,
10
11
  so the min() let wide nowrap rows inflate content-sized ancestors. */
11
12
  max-width: 36rem;
13
+ /* Live tool labels and panels must never contribute a wider intrinsic size
14
+ when Activity is inserted into a narrow chat transcript. */
15
+ contain: inline-size;
12
16
  /* Whitespace separates the work log from message prose around it */
13
17
  margin-block: 0.5rem;
14
18
  font-family: inherit;
@@ -17,6 +21,8 @@
17
21
 
18
22
  .activity__trigger {
19
23
  display: flex;
24
+ width: 100%;
25
+ min-width: 0;
20
26
  align-items: center;
21
27
  gap: var(--sigvelo-spacing-1-5);
22
28
  padding-block: var(--sigvelo-spacing-1-5);
@@ -3,6 +3,7 @@
3
3
  position: relative;
4
4
  width: 100%;
5
5
  height: 100%;
6
+ min-width: 0;
6
7
  min-height: 0;
7
8
  background-color: var(--sigvelo-color-surface);
8
9
  color: var(--sigvelo-color-text);
@@ -10,6 +11,7 @@
10
11
  }
11
12
 
12
13
  .agent-chat__conversation {
14
+ min-width: 0;
13
15
  height: 100%;
14
16
  min-height: 0;
15
17
  }
@@ -18,6 +20,8 @@
18
20
  --agent-chat-composer-size is set from a ResizeObserver in AgentChat. */
19
21
  .agent-chat__transcript-content {
20
22
  gap: 0.875rem;
23
+ min-inline-size: 0;
24
+ max-inline-size: 100%;
21
25
  inline-size: min(100%, var(--agent-chat-content-max-inline-size));
22
26
  margin-inline: auto;
23
27
  padding-block: 1rem calc(var(--agent-chat-composer-size, 5rem) + 0.5rem);
@@ -35,7 +39,9 @@
35
39
  }
36
40
 
37
41
  .agent-chat__scroll-button {
38
- inset-block-end: calc(var(--agent-chat-composer-size, 5rem) + 0.5rem);
42
+ --message-scroller-button-inset-block-end: calc(
43
+ var(--agent-chat-composer-size, 5rem) + var(--sigvelo-spacing-2)
44
+ );
39
45
  }
40
46
 
41
47
  /* Floating over the transcript: solid behind the controls, fading out
@@ -60,7 +60,7 @@
60
60
  .message-scroller__button {
61
61
  position: absolute;
62
62
  inset-inline-start: 50%;
63
- inset-block-end: 1rem;
63
+ inset-block-end: var(--message-scroller-button-inset-block-end, 1rem);
64
64
  z-index: 1;
65
65
  translate: -50% 0;
66
66
  border-radius: 999rem;
@@ -3,6 +3,7 @@
3
3
  flex-direction: column;
4
4
  gap: 0.25rem;
5
5
  width: 100%;
6
+ min-width: 0;
6
7
  font-family: inherit;
7
8
  color: var(--sigvelo-color-text);
8
9
  }
@@ -20,6 +21,7 @@
20
21
  .message__content {
21
22
  display: inline-block;
22
23
  max-width: min(42rem, 85%);
24
+ min-width: 0;
23
25
  padding-block: 0.5rem;
24
26
  padding-inline: var(--sigvelo-spacing-3);
25
27
  border-radius: var(--sigvelo-radius-lg);
@@ -1,4 +1,6 @@
1
1
  .prompt-input {
2
+ container: prompt-input / inline-size;
3
+ position: relative;
2
4
  display: flex;
3
5
  flex-direction: column;
4
6
  gap: var(--sigvelo-spacing-1-5);
@@ -17,6 +19,55 @@
17
19
  box-shadow var(--sigvelo-duration-fast) var(--sigvelo-ease-standard);
18
20
  }
19
21
 
22
+ .prompt-input__recording {
23
+ display: flex;
24
+ align-items: center;
25
+ gap: var(--sigvelo-spacing-2);
26
+ flex: 1;
27
+ min-width: 0;
28
+ }
29
+
30
+ .prompt-input__recording-add {
31
+ flex: 0 0 auto;
32
+ }
33
+
34
+ .prompt-input__recording-waveform {
35
+ flex: 1 1 auto;
36
+ min-inline-size: 0;
37
+ block-size: var(--sigvelo-spacing-4);
38
+ color: var(--sigvelo-color-text);
39
+ }
40
+
41
+ .prompt-input__recording-waveform canvas {
42
+ display: block;
43
+ inline-size: 100%;
44
+ block-size: 100%;
45
+ }
46
+
47
+ .prompt-input__recording-time {
48
+ min-inline-size: 2.5rem;
49
+ color: var(--sigvelo-color-text-muted);
50
+ font-variant-numeric: tabular-nums;
51
+ font-size: var(--sigvelo-text-sm);
52
+ text-align: end;
53
+ }
54
+
55
+ .prompt-input__recording-button {
56
+ flex: 0 0 auto;
57
+ border-radius: var(--sigvelo-radius-full);
58
+ }
59
+
60
+ .prompt-input__tools:has(.prompt-input__recording) {
61
+ flex: 1;
62
+ flex-wrap: nowrap;
63
+ width: 100%;
64
+ }
65
+
66
+ .prompt-input__tools:has(.prompt-input__recording) > :not(.prompt-input__recording),
67
+ .prompt-input__footer:has(.prompt-input__recording) > :not(.prompt-input__tools) {
68
+ display: none;
69
+ }
70
+
20
71
  .prompt-input__file-input {
21
72
  position: fixed;
22
73
  inline-size: 1px;
@@ -288,6 +339,13 @@
288
339
  gap: 0.25rem;
289
340
  }
290
341
 
342
+ .prompt-input__permissions-icon {
343
+ display: inline-flex;
344
+ align-items: center;
345
+ justify-content: center;
346
+ flex: 0 0 auto;
347
+ }
348
+
291
349
  .prompt-input__permissions-trigger:hover,
292
350
  .prompt-input__permissions-trigger[data-popup-open] {
293
351
  background-color: color-mix(in oklab, transparent, var(--sigvelo-color-text) 5%);
@@ -314,6 +372,38 @@
314
372
  white-space: nowrap;
315
373
  }
316
374
 
375
+ @container prompt-input (max-width: 36rem) {
376
+ .prompt-input__footer {
377
+ gap: var(--sigvelo-spacing-1);
378
+ }
379
+
380
+ .prompt-input__tools {
381
+ min-width: 0;
382
+ flex-wrap: nowrap;
383
+ }
384
+
385
+ .prompt-input__button[data-responsive-label] {
386
+ inline-size: 2.75rem;
387
+ min-block-size: 2.75rem;
388
+ padding-inline: 0;
389
+ border-radius: var(--sigvelo-radius-full);
390
+ }
391
+
392
+ .prompt-input__button[data-responsive-label] > span,
393
+ .prompt-input__permissions-current,
394
+ .prompt-input__permissions-chevron {
395
+ display: none;
396
+ }
397
+
398
+ .prompt-input__permissions-trigger {
399
+ inline-size: 2.75rem;
400
+ min-block-size: 2.75rem;
401
+ padding-inline: 0;
402
+ justify-content: center;
403
+ border-radius: var(--sigvelo-radius-full);
404
+ }
405
+ }
406
+
317
407
  .prompt-input__permissions-current-option:not([data-active]) {
318
408
  visibility: hidden;
319
409
  }
@@ -21,6 +21,16 @@
21
21
  overflow-wrap: anywhere;
22
22
  }
23
23
 
24
+ .message[data-from="user"] [data-streamdown="link"] {
25
+ color: var(--sigvelo-color-primary-text-on-bg);
26
+ }
27
+
28
+ [data-streamdown="link"]:focus-visible {
29
+ outline: var(--sigvelo-focus-width) solid currentColor;
30
+ outline-offset: var(--sigvelo-focus-offset);
31
+ border-radius: var(--sigvelo-radius-xs);
32
+ }
33
+
24
34
  /* Links render as <button> when link safety is enabled. */
25
35
  button[data-streamdown="link"] {
26
36
  appearance: none;
@@ -108,6 +108,7 @@
108
108
  }
109
109
 
110
110
  .workspace-explorer__tree .file-tree__name {
111
+ flex: 0 1 auto;
111
112
  line-height: 1.4;
112
113
  }
113
114
 
@@ -78,7 +78,7 @@ declare const CHECKED_IN_CODEX_MODELS: readonly [{
78
78
  readonly upgradeInfo: null;
79
79
  readonly availabilityNux: null;
80
80
  readonly hidden: boolean;
81
- readonly inputModalities: ("image" | "text")[];
81
+ readonly inputModalities: ("text" | "image")[];
82
82
  readonly supportsPersonality: boolean;
83
83
  readonly additionalSpeedTiers: never[];
84
84
  readonly serviceTiers: never[];
@@ -98,7 +98,7 @@ declare const CHECKED_IN_CODEX_MODELS: readonly [{
98
98
  readonly upgradeInfo: null;
99
99
  readonly availabilityNux: null;
100
100
  readonly hidden: boolean;
101
- readonly inputModalities: ("image" | "text")[];
101
+ readonly inputModalities: ("text" | "image")[];
102
102
  readonly supportsPersonality: boolean;
103
103
  readonly additionalSpeedTiers: never[];
104
104
  readonly serviceTiers: never[];
@@ -115,7 +115,7 @@ declare const CHECKED_IN_CODEX_MODELS: readonly [{
115
115
  readonly upgradeInfo: null;
116
116
  readonly availabilityNux: null;
117
117
  readonly hidden: boolean;
118
- readonly inputModalities: ("image" | "text")[];
118
+ readonly inputModalities: ("text" | "image")[];
119
119
  readonly supportsPersonality: boolean;
120
120
  readonly additionalSpeedTiers: never[];
121
121
  readonly serviceTiers: never[];
@@ -132,7 +132,7 @@ declare const CHECKED_IN_CODEX_MODELS: readonly [{
132
132
  readonly upgradeInfo: null;
133
133
  readonly availabilityNux: null;
134
134
  readonly hidden: boolean;
135
- readonly inputModalities: ("image" | "text")[];
135
+ readonly inputModalities: ("text" | "image")[];
136
136
  readonly supportsPersonality: boolean;
137
137
  readonly additionalSpeedTiers: never[];
138
138
  readonly serviceTiers: never[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-b/react-components",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "MCP-B React components built on Base UI and shared design tokens, including Cloudflare Think chat primitives.",
5
5
  "homepage": "https://design-system.sigvelo.com",
6
6
  "bugs": {
@@ -53,7 +53,7 @@
53
53
  "lucide-react": "^1.23.0",
54
54
  "shiki": "^3.23.0",
55
55
  "streamdown": "^2.5.0",
56
- "@mcp-b/design-tokens": "0.13.0"
56
+ "@mcp-b/design-tokens": "0.14.1"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@ai-sdk/react": "^3.0.222",