@page-speed/agent-everywhere 0.3.1 → 0.5.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.js CHANGED
@@ -6,7 +6,7 @@ import { createContext, forwardRef, useRef, useImperativeHandle, useCallback, us
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { AnimatePresence, motion } from 'motion/react';
8
8
  import { Markdown } from '@page-speed/markdown-to-jsx';
9
- import { SendIcon, PaperclipIcon, FileTextIcon, MicIcon, ImageIcon, XIcon, SearchIcon, UploadIcon, FileIcon, UserCircleIcon, CheckIcon, SparklesIcon, BookmarkIcon, InfoIcon, CheckCircle2Icon, AlertTriangleIcon, LightbulbIcon, BrainIcon, ChevronDownIcon, ZapIcon, CopyIcon, ThumbsUpIcon, ThumbsDownIcon, BotIcon, UserIcon, DownloadIcon, MinusIcon, TrendingDownIcon, TrendingUpIcon, ChevronUpIcon, ArrowUpDownIcon, LinkIcon, PlayIcon, ExternalLinkIcon, WandIcon, LayoutGridIcon, Grid3X3Icon, ArrowUpRightIcon, ShuffleIcon, SkipForwardIcon, ChevronLeftIcon, ChevronRightIcon, XCircleIcon, HelpCircleIcon, Minimize2Icon, Maximize2Icon, RotateCcwIcon, MessageSquareIcon, GripVerticalIcon, PanelLeftOpenIcon, PanelLeftCloseIcon, CheckCircleIcon, AlertCircleIcon, MoreHorizontalIcon, ArrowLeftIcon, MoreVerticalIcon, Loader2Icon, ArrowRightIcon, AlignLeftIcon, ListIcon, HashIcon, TypeIcon, ClockIcon, CoinsIcon, ActivityIcon, ArrowUpIcon, ArrowDownIcon } from 'lucide-react';
9
+ import { SendIcon, PaperclipIcon, FileTextIcon, MicIcon, ImageIcon, XIcon, SearchIcon, UploadIcon, FileIcon, UserCircleIcon, CheckIcon, SparklesIcon, BookmarkIcon, InfoIcon, CheckCircle2Icon, AlertTriangleIcon, LightbulbIcon, BrainIcon, ChevronDownIcon, ZapIcon, CopyIcon, ThumbsUpIcon, ThumbsDownIcon, BotIcon, UserIcon, DownloadIcon, MinusIcon, TrendingDownIcon, TrendingUpIcon, ChevronUpIcon, ArrowUpDownIcon, LinkIcon, PlayIcon, ExternalLinkIcon, WandIcon, LayoutGridIcon, Grid3X3Icon, ArrowUpRightIcon, ShuffleIcon, SkipForwardIcon, ChevronLeftIcon, ChevronRightIcon, XCircleIcon, HelpCircleIcon, Minimize2Icon, Maximize2Icon, RotateCcwIcon, MessageSquareIcon, GripVerticalIcon, PanelLeftOpenIcon, PanelLeftCloseIcon, CheckCircleIcon, AlertCircleIcon, MoreHorizontalIcon, ClipboardListIcon, ArrowLeftIcon, MoreVerticalIcon, Loader2Icon, ArrowRightIcon, AlignLeftIcon, ListIcon, HashIcon, TypeIcon, ClockIcon, CoinsIcon, ActivityIcon, ArrowUpIcon, ArrowDownIcon } from 'lucide-react';
10
10
  import { Slot } from '@radix-ui/react-slot';
11
11
  import { cva } from 'class-variance-authority';
12
12
  import * as AvatarPrimitive from '@radix-ui/react-avatar';
@@ -1212,7 +1212,7 @@ var PromptInput = forwardRef(
1212
1212
  [handleSubmit]
1213
1213
  );
1214
1214
  const variantStyles = {
1215
- default: "border-t px-3 py-2.5",
1215
+ default: "px-3 py-2.5",
1216
1216
  minimal: "px-3 py-2",
1217
1217
  bordered: "border rounded-lg px-3 py-2.5"
1218
1218
  };
@@ -1221,41 +1221,48 @@ var PromptInput = forwardRef(
1221
1221
  minimal: "bg-transparent px-0",
1222
1222
  bordered: "bg-muted/50"
1223
1223
  };
1224
- return /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, className: cn(variantStyles[variant], className), children: /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
1225
- leftActions,
1226
- /* @__PURE__ */ jsx(
1227
- "textarea",
1228
- {
1229
- ref: textareaRef,
1230
- value,
1231
- onChange: (e) => onChange(e.target.value),
1232
- onKeyDown: handleKeyDown,
1233
- placeholder,
1234
- disabled: disabled || loading,
1235
- autoFocus,
1236
- rows: minRows,
1237
- className: cn(
1238
- "flex-1 resize-none border-0 px-0 py-1 text-sm leading-5 shadow-none",
1239
- "placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0",
1240
- "disabled:cursor-not-allowed disabled:opacity-50",
1241
- inputVariantStyles[variant],
1242
- inputClassName
1224
+ return /* @__PURE__ */ jsx(
1225
+ "form",
1226
+ {
1227
+ onSubmit: handleSubmit,
1228
+ className: cn(variantStyles[variant], className),
1229
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
1230
+ leftActions,
1231
+ /* @__PURE__ */ jsx(
1232
+ "textarea",
1233
+ {
1234
+ ref: textareaRef,
1235
+ value,
1236
+ onChange: (e) => onChange(e.target.value),
1237
+ onKeyDown: handleKeyDown,
1238
+ placeholder,
1239
+ disabled: disabled || loading,
1240
+ autoFocus,
1241
+ rows: minRows,
1242
+ className: cn(
1243
+ "flex-1 resize-none border-0 px-0 py-1 text-sm leading-5 shadow-none",
1244
+ "placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0",
1245
+ "disabled:cursor-not-allowed disabled:opacity-50",
1246
+ inputVariantStyles[variant],
1247
+ inputClassName
1248
+ )
1249
+ }
1250
+ ),
1251
+ rightActions,
1252
+ showSendButton && /* @__PURE__ */ jsx(
1253
+ Button,
1254
+ {
1255
+ type: "submit",
1256
+ size: "sm",
1257
+ variant: variant === "minimal" ? "ghost" : "outline",
1258
+ disabled: !value.trim() || disabled || loading,
1259
+ className: "size-8 shrink-0 p-0",
1260
+ children: sendButtonContent || /* @__PURE__ */ jsx(SendIcon, { className: "size-4" })
1261
+ }
1243
1262
  )
1244
- }
1245
- ),
1246
- rightActions,
1247
- showSendButton && /* @__PURE__ */ jsx(
1248
- Button,
1249
- {
1250
- type: "submit",
1251
- size: "sm",
1252
- variant: variant === "minimal" ? "ghost" : "outline",
1253
- disabled: !value.trim() || disabled || loading,
1254
- className: "size-8 shrink-0 p-0",
1255
- children: sendButtonContent || /* @__PURE__ */ jsx(SendIcon, { className: "size-4" })
1256
- }
1257
- )
1258
- ] }) });
1263
+ ] })
1264
+ }
1265
+ );
1259
1266
  }
1260
1267
  );
1261
1268
  PromptInput.displayName = "PromptInput";
@@ -7189,6 +7196,7 @@ function useSemanticBuilder({
7189
7196
  onGeneratedBlocks,
7190
7197
  onUndoRequest,
7191
7198
  buildWelcomeMessage,
7199
+ seedWelcomeMessage = true,
7192
7200
  webSocketImpl
7193
7201
  }) {
7194
7202
  const [messages, setMessages] = useState([]);
@@ -7222,6 +7230,7 @@ function useSemanticBuilder({
7222
7230
  resolveSocketUrlRef.current = resolveSocketUrl;
7223
7231
  }, [resolveSocketUrl]);
7224
7232
  useEffect(() => {
7233
+ if (!seedWelcomeMessage) return;
7225
7234
  const hasContentBrief = !!contentBrief;
7226
7235
  const content = buildWelcomeMessage?.({ pageName, hasContentBrief }) ?? (hasContentBrief ? `Connected to ${pageName}. The page brief is loaded and ready. Describe the page you want and I'll stream back layout guidance and design reasoning.` : `Connected to ${pageName}. There is no saved content brief yet, so I'll work from the current page structure and brand context.`);
7227
7236
  setMessages([
@@ -7232,7 +7241,7 @@ function useSemanticBuilder({
7232
7241
  createdAt: Date.now()
7233
7242
  }
7234
7243
  ]);
7235
- }, [contentBrief, pageName, pageSlug]);
7244
+ }, [contentBrief, pageName, pageSlug, seedWelcomeMessage]);
7236
7245
  const handleEnvelope = useCallback((envelope) => {
7237
7246
  switch (envelope.type) {
7238
7247
  case "connection_ready":
@@ -7444,6 +7453,14 @@ function useSemanticBuilder({
7444
7453
  const retry = useCallback(() => {
7445
7454
  clientRef.current?.retry();
7446
7455
  }, []);
7456
+ const reset = useCallback(() => {
7457
+ pendingHiddenRequestsRef.current = 0;
7458
+ hiddenAssistantMessageIdsRef.current.clear();
7459
+ clientRef.current?.close();
7460
+ setConnectionState("idle");
7461
+ setConnectionError(null);
7462
+ setMessages([]);
7463
+ }, []);
7447
7464
  const isConnected = connectionState === "ready" || connectionState === "streaming";
7448
7465
  const isStreaming = connectionState === "streaming";
7449
7466
  const statusLabel = useMemo(() => {
@@ -7470,7 +7487,8 @@ function useSemanticBuilder({
7470
7487
  isConnected,
7471
7488
  isStreaming,
7472
7489
  sendMessage,
7473
- retry
7490
+ retry,
7491
+ reset
7474
7492
  };
7475
7493
  }
7476
7494
  var ScrollArea = React4.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
@@ -7691,10 +7709,58 @@ function ReportView({ report, className }) {
7691
7709
  ))
7692
7710
  ] });
7693
7711
  }
7712
+ function ConfirmationPanel({
7713
+ title = "Proposed plan",
7714
+ summary,
7715
+ body,
7716
+ markdown = true,
7717
+ icon,
7718
+ actions,
7719
+ onAction,
7720
+ ariaLabel,
7721
+ className
7722
+ }) {
7723
+ const hasBody = body !== void 0 && body !== null && body !== "";
7724
+ return /* @__PURE__ */ jsxs(
7725
+ motion.section,
7726
+ {
7727
+ initial: { opacity: 0, y: 6 },
7728
+ animate: { opacity: 1, y: 0 },
7729
+ transition: { duration: 0.2 },
7730
+ "aria-label": ariaLabel ?? title,
7731
+ className: cn(
7732
+ "flex w-full min-w-0 flex-col rounded-lg border bg-card p-4",
7733
+ className
7734
+ ),
7735
+ children: [
7736
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center gap-2", children: [
7737
+ /* @__PURE__ */ jsx("span", { className: "flex size-6 shrink-0 items-center justify-center rounded-md bg-muted/60 text-muted-foreground", children: icon ?? /* @__PURE__ */ jsx(ClipboardListIcon, { className: "size-3.5" }) }),
7738
+ /* @__PURE__ */ jsx("h4", { className: "min-w-0 flex-1 truncate font-medium text-sm", children: title }),
7739
+ summary && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "shrink-0 text-[10px] font-normal", children: summary })
7740
+ ] }),
7741
+ hasBody && /* @__PURE__ */ jsx("div", { className: "mt-2 min-w-0", children: typeof body === "string" ? /* @__PURE__ */ jsx(MessageContent, { markdown, children: body }) : body }),
7742
+ actions && actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: actions.map((action, index) => /* @__PURE__ */ jsx(
7743
+ Button,
7744
+ {
7745
+ type: "button",
7746
+ size: "sm",
7747
+ variant: action.variant ?? (index === 0 ? "default" : "outline"),
7748
+ disabled: action.disabled || action.busy,
7749
+ "aria-busy": action.busy || void 0,
7750
+ onClick: () => onAction?.(action.id),
7751
+ children: action.label
7752
+ },
7753
+ action.id
7754
+ )) })
7755
+ ]
7756
+ }
7757
+ );
7758
+ }
7694
7759
  function MessageList({
7695
7760
  messages,
7696
7761
  showAvatars = true,
7697
7762
  renderMessage,
7763
+ onConfirmAction,
7698
7764
  className
7699
7765
  }) {
7700
7766
  return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-4", className), children: messages.map((message) => {
@@ -7711,7 +7777,18 @@ function MessageList({
7711
7777
  hasSteps && /* @__PURE__ */ jsx(MessageWithSteps, { steps: message.steps }),
7712
7778
  message.content && /* @__PURE__ */ jsx(MessageBubble, { role: message.role, children: /* @__PURE__ */ jsx(MessageContent, { children: message.content }) }),
7713
7779
  hasAttachments && /* @__PURE__ */ jsx(MessageWithAttachments, { attachments: message.attachments }),
7714
- message.data && /* @__PURE__ */ jsx(DataPayloadView, { payload: message.data })
7780
+ message.data && /* @__PURE__ */ jsx(DataPayloadView, { payload: message.data }),
7781
+ message.confirmation && /* @__PURE__ */ jsx(
7782
+ ConfirmationPanel,
7783
+ {
7784
+ title: message.confirmation.title,
7785
+ summary: message.confirmation.summary,
7786
+ body: message.confirmation.body,
7787
+ markdown: message.confirmation.markdown,
7788
+ actions: message.confirmation.actions,
7789
+ onAction: (actionId) => onConfirmAction?.(message.id, actionId)
7790
+ }
7791
+ )
7715
7792
  ] })
7716
7793
  ] }, message.id);
7717
7794
  }) });
@@ -7915,6 +7992,54 @@ function FullBleedSurface({
7915
7992
  }
7916
7993
  );
7917
7994
  }
7995
+ function NativeSurface({
7996
+ children,
7997
+ input,
7998
+ title,
7999
+ subtitle,
8000
+ icon,
8001
+ headerActions,
8002
+ suggestions,
8003
+ footer,
8004
+ isLoading = false,
8005
+ autoScroll = true,
8006
+ className,
8007
+ contentClassName
8008
+ }) {
8009
+ const scrollRef = useRef(null);
8010
+ useEffect(() => {
8011
+ if (autoScroll && scrollRef.current) {
8012
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
8013
+ }
8014
+ }, [children, isLoading, autoScroll]);
8015
+ const showHeader = !!title || !!headerActions || !!icon;
8016
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 flex-col", className), children: [
8017
+ showHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-4 py-3", children: [
8018
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
8019
+ icon,
8020
+ (title || subtitle) && /* @__PURE__ */ jsxs("div", { children: [
8021
+ title && /* @__PURE__ */ jsx("span", { className: "font-medium text-sm", children: title }),
8022
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", children: subtitle })
8023
+ ] })
8024
+ ] }),
8025
+ headerActions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: headerActions })
8026
+ ] }),
8027
+ /* @__PURE__ */ jsx(
8028
+ "div",
8029
+ {
8030
+ ref: scrollRef,
8031
+ className: cn("min-h-0 flex-1 overflow-y-auto", contentClassName),
8032
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4", children: [
8033
+ children,
8034
+ isLoading && /* @__PURE__ */ jsx(TypingIndicator, {})
8035
+ ] })
8036
+ }
8037
+ ),
8038
+ suggestions && /* @__PURE__ */ jsx("div", { className: "border-t px-4 py-2", children: suggestions }),
8039
+ input,
8040
+ footer && /* @__PURE__ */ jsx("div", { className: "border-t px-4 py-1.5", children: footer })
8041
+ ] });
8042
+ }
7918
8043
  function AgentSurface({
7919
8044
  mode,
7920
8045
  messages,
@@ -7932,6 +8057,7 @@ function AgentSurface({
7932
8057
  showAvatars = true,
7933
8058
  renderMessage,
7934
8059
  onFeedback,
8060
+ onConfirmAction,
7935
8061
  report,
7936
8062
  dataPanel,
7937
8063
  isOpen = true,
@@ -7948,7 +8074,8 @@ function AgentSurface({
7948
8074
  messages,
7949
8075
  showAvatars,
7950
8076
  renderMessage,
7951
- onFeedback
8077
+ onFeedback,
8078
+ onConfirmAction
7952
8079
  }
7953
8080
  );
7954
8081
  const resolvedInput = input ?? (onInputChange && onSubmit !== void 0 ? /* @__PURE__ */ jsx("div", { className: "border-t p-2", children: /* @__PURE__ */ jsx(
@@ -8036,6 +8163,21 @@ function AgentSurface({
8036
8163
  children: conversation
8037
8164
  }
8038
8165
  );
8166
+ case "native":
8167
+ return /* @__PURE__ */ jsx(
8168
+ NativeSurface,
8169
+ {
8170
+ title,
8171
+ subtitle,
8172
+ icon,
8173
+ headerActions,
8174
+ input: resolvedInput,
8175
+ suggestions,
8176
+ isLoading,
8177
+ className,
8178
+ children: conversation
8179
+ }
8180
+ );
8039
8181
  case "panel":
8040
8182
  default:
8041
8183
  return /* @__PURE__ */ jsx(
@@ -8054,7 +8196,337 @@ function AgentSurface({
8054
8196
  );
8055
8197
  }
8056
8198
  }
8199
+ var NativeAgentContext = createContext(
8200
+ null
8201
+ );
8202
+ function useNativeAgent() {
8203
+ const ctx = useContext(NativeAgentContext);
8204
+ if (!ctx) {
8205
+ throw new Error(
8206
+ "useNativeAgent must be used within a <NativeAgentProvider>."
8207
+ );
8208
+ }
8209
+ return ctx;
8210
+ }
8211
+ function useNativeAgentOptional() {
8212
+ return useContext(NativeAgentContext);
8213
+ }
8214
+ var EMPTY_BLOCKS = [];
8215
+ var REASONING_STATUS = {
8216
+ active: "active",
8217
+ complete: "complete"
8218
+ };
8219
+ function toAgentMessage(message) {
8220
+ const reasoning = message.thinking ? [
8221
+ {
8222
+ id: `${message.id}__thinking`,
8223
+ label: "Thinking",
8224
+ content: message.thinking,
8225
+ status: message.streaming ? REASONING_STATUS.active : REASONING_STATUS.complete
8226
+ }
8227
+ ] : void 0;
8228
+ return {
8229
+ id: message.id,
8230
+ role: message.role,
8231
+ content: message.content,
8232
+ timestamp: new Date(message.createdAt),
8233
+ reasoning
8234
+ };
8235
+ }
8236
+ function deriveStatus(connectionState) {
8237
+ switch (connectionState) {
8238
+ case "streaming":
8239
+ return "busy";
8240
+ case "ready":
8241
+ return "online";
8242
+ case "connecting":
8243
+ return "away";
8244
+ default:
8245
+ return "offline";
8246
+ }
8247
+ }
8248
+ function NativeAgentProvider({
8249
+ children,
8250
+ socketUrl,
8251
+ resolveSocketUrl,
8252
+ websiteId,
8253
+ pageCategoryId,
8254
+ pageName = "",
8255
+ pageSlug,
8256
+ blocks,
8257
+ contentBrief,
8258
+ onGeneratedBlocks,
8259
+ webSocketImpl,
8260
+ connectionStrategy = "lazy",
8261
+ seedWelcomeMessage = false,
8262
+ onError,
8263
+ onActivate
8264
+ }) {
8265
+ const [enabled, setEnabled] = useState(connectionStrategy === "eager");
8266
+ const [isActive, setIsActive] = useState(false);
8267
+ const [input, setInput] = useState("");
8268
+ const [pendingCount, setPendingCount] = useState(0);
8269
+ const [optimistic, setOptimistic] = useState([]);
8270
+ const blocksValue = blocks ?? EMPTY_BLOCKS;
8271
+ const {
8272
+ messages: builderMessages,
8273
+ connectionState,
8274
+ connectionError,
8275
+ statusLabel,
8276
+ isConnected,
8277
+ isStreaming,
8278
+ sendMessage,
8279
+ retry,
8280
+ reset: resetSession
8281
+ } = useSemanticBuilder({
8282
+ socketUrl,
8283
+ resolveSocketUrl,
8284
+ websiteId,
8285
+ pageCategoryId,
8286
+ pageName,
8287
+ pageSlug,
8288
+ blocks: blocksValue,
8289
+ contentBrief,
8290
+ enabled,
8291
+ onGeneratedBlocks,
8292
+ webSocketImpl,
8293
+ seedWelcomeMessage
8294
+ });
8295
+ const pendingPromptsRef = useRef([]);
8296
+ const optimisticSeqRef = useRef(0);
8297
+ const onActivateRef = useRef(onActivate);
8298
+ const onErrorRef = useRef(onError);
8299
+ useEffect(() => {
8300
+ onActivateRef.current = onActivate;
8301
+ }, [onActivate]);
8302
+ useEffect(() => {
8303
+ onErrorRef.current = onError;
8304
+ }, [onError]);
8305
+ useEffect(() => {
8306
+ if (connectionError) onErrorRef.current?.(connectionError);
8307
+ }, [connectionError]);
8308
+ const markActive = useCallback(() => {
8309
+ setIsActive((prev) => {
8310
+ if (!prev) onActivateRef.current?.();
8311
+ return true;
8312
+ });
8313
+ }, []);
8314
+ useEffect(() => {
8315
+ if (connectionState !== "ready" || pendingPromptsRef.current.length === 0) {
8316
+ return;
8317
+ }
8318
+ const next = pendingPromptsRef.current.shift();
8319
+ if (next === void 0) return;
8320
+ setPendingCount(pendingPromptsRef.current.length);
8321
+ setOptimistic((prev) => prev.slice(1));
8322
+ void sendMessage(next).then((ok) => {
8323
+ if (!ok) {
8324
+ pendingPromptsRef.current.unshift(next);
8325
+ setPendingCount(pendingPromptsRef.current.length);
8326
+ }
8327
+ });
8328
+ }, [connectionState, pendingCount, sendMessage]);
8329
+ const submit = useCallback(
8330
+ (content) => {
8331
+ const text = (content ?? input).trim();
8332
+ if (!text) return;
8333
+ markActive();
8334
+ setEnabled(true);
8335
+ setInput("");
8336
+ pendingPromptsRef.current.push(text);
8337
+ setPendingCount(pendingPromptsRef.current.length);
8338
+ const id = `native-pending-${optimisticSeqRef.current}`;
8339
+ optimisticSeqRef.current += 1;
8340
+ setOptimistic((prev) => [
8341
+ ...prev,
8342
+ { id, role: "user", content: text, timestamp: /* @__PURE__ */ new Date() }
8343
+ ]);
8344
+ },
8345
+ [input, markActive]
8346
+ );
8347
+ const activate = useCallback(() => {
8348
+ markActive();
8349
+ setEnabled(true);
8350
+ }, [markActive]);
8351
+ const reset = useCallback(() => {
8352
+ pendingPromptsRef.current = [];
8353
+ setPendingCount(0);
8354
+ setOptimistic([]);
8355
+ setIsActive(false);
8356
+ setInput("");
8357
+ setEnabled(false);
8358
+ resetSession();
8359
+ }, [resetSession]);
8360
+ const messages = useMemo(
8361
+ () => [...builderMessages.map(toAgentMessage), ...optimistic],
8362
+ [builderMessages, optimistic]
8363
+ );
8364
+ const isResponding = isStreaming || pendingCount > 0 && !connectionError && connectionState !== "error" && connectionState !== "requires_shared_domain";
8365
+ const status = deriveStatus(connectionState);
8366
+ const value = useMemo(
8367
+ () => ({
8368
+ messages,
8369
+ isActive,
8370
+ isConnected,
8371
+ isResponding,
8372
+ isStreaming,
8373
+ connectionState,
8374
+ statusLabel,
8375
+ status,
8376
+ error: connectionError,
8377
+ input,
8378
+ setInput,
8379
+ submit,
8380
+ activate,
8381
+ reset,
8382
+ retry
8383
+ }),
8384
+ [
8385
+ messages,
8386
+ isActive,
8387
+ isConnected,
8388
+ isResponding,
8389
+ isStreaming,
8390
+ connectionState,
8391
+ statusLabel,
8392
+ status,
8393
+ connectionError,
8394
+ input,
8395
+ submit,
8396
+ activate,
8397
+ reset,
8398
+ retry
8399
+ ]
8400
+ );
8401
+ return /* @__PURE__ */ jsx(NativeAgentContext.Provider, { value, children });
8402
+ }
8403
+ var noop = () => {
8404
+ };
8405
+ function warnDev(message) {
8406
+ const env = globalThis.process?.env;
8407
+ if (env && env.NODE_ENV !== "production") {
8408
+ console.warn(`[AgentComposer] ${message}`);
8409
+ }
8410
+ }
8411
+ function AgentComposer({
8412
+ value: valueProp,
8413
+ onChange,
8414
+ onSubmit,
8415
+ loading: loadingProp,
8416
+ disabled: disabledProp,
8417
+ placeholder = "Ask anything\u2026",
8418
+ variant = "default",
8419
+ bare = false,
8420
+ suggestions,
8421
+ footer,
8422
+ leftActions,
8423
+ rightActions,
8424
+ autoFocus = false,
8425
+ className,
8426
+ inputClassName
8427
+ }) {
8428
+ const ctx = useNativeAgentOptional();
8429
+ const [draft, setDraft] = useState("");
8430
+ const propsControlEditing = valueProp !== void 0 || onChange !== void 0;
8431
+ const value = propsControlEditing ? valueProp ?? "" : ctx ? ctx.input : draft;
8432
+ const handleChange = propsControlEditing ? onChange ?? noop : ctx ? ctx.setInput : setDraft;
8433
+ const loading = loadingProp ?? ctx?.isResponding ?? false;
8434
+ const disabled = disabledProp ?? false;
8435
+ const handleSubmit = useCallback(() => {
8436
+ if (onSubmit) {
8437
+ onSubmit(value);
8438
+ return;
8439
+ }
8440
+ if (!propsControlEditing && ctx) {
8441
+ ctx.submit();
8442
+ return;
8443
+ }
8444
+ warnDev(
8445
+ "submit was ignored: provide `onSubmit`, or render inside a <NativeAgentProvider>."
8446
+ );
8447
+ }, [onSubmit, propsControlEditing, ctx, value]);
8448
+ return /* @__PURE__ */ jsxs(
8449
+ "div",
8450
+ {
8451
+ className: cn(
8452
+ !bare && "rounded-2xl border bg-background shadow-sm",
8453
+ className
8454
+ ),
8455
+ children: [
8456
+ suggestions && /* @__PURE__ */ jsx("div", { className: cn("px-3", bare ? "pb-2" : "pt-3"), children: suggestions }),
8457
+ /* @__PURE__ */ jsx(
8458
+ PromptInput,
8459
+ {
8460
+ value,
8461
+ onChange: handleChange,
8462
+ onSubmit: handleSubmit,
8463
+ placeholder,
8464
+ loading,
8465
+ disabled,
8466
+ variant,
8467
+ autoFocus,
8468
+ leftActions,
8469
+ rightActions,
8470
+ inputClassName
8471
+ }
8472
+ ),
8473
+ footer && /* @__PURE__ */ jsx("div", { className: "px-4 pb-2 text-muted-foreground text-xs", children: footer })
8474
+ ]
8475
+ }
8476
+ );
8477
+ }
8478
+ var EMPTY_MESSAGES = [];
8479
+ function AgentConversation({
8480
+ messages: messagesProp,
8481
+ isLoading: isLoadingProp,
8482
+ header,
8483
+ emptyState,
8484
+ showAvatars = true,
8485
+ renderMessage,
8486
+ onFeedback,
8487
+ onConfirmAction,
8488
+ autoScroll = true,
8489
+ className,
8490
+ contentClassName
8491
+ }) {
8492
+ const ctx = useNativeAgentOptional();
8493
+ const messages = useMemo(
8494
+ () => messagesProp ?? ctx?.messages ?? EMPTY_MESSAGES,
8495
+ [messagesProp, ctx?.messages]
8496
+ );
8497
+ const isLoading = isLoadingProp ?? ctx?.isResponding ?? false;
8498
+ const scrollRef = useRef(null);
8499
+ useEffect(() => {
8500
+ if (autoScroll && scrollRef.current) {
8501
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
8502
+ }
8503
+ }, [messages, isLoading, autoScroll]);
8504
+ const showEmptyState = messages.length === 0 && !isLoading && !!emptyState;
8505
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 flex-col", className), children: [
8506
+ header,
8507
+ /* @__PURE__ */ jsx(
8508
+ "div",
8509
+ {
8510
+ ref: scrollRef,
8511
+ className: cn("min-h-0 flex-1 overflow-y-auto", contentClassName),
8512
+ children: showEmptyState ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center p-6", children: emptyState }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4", children: [
8513
+ /* @__PURE__ */ jsx(
8514
+ MessageList,
8515
+ {
8516
+ messages,
8517
+ showAvatars,
8518
+ renderMessage,
8519
+ onFeedback,
8520
+ onConfirmAction
8521
+ }
8522
+ ),
8523
+ isLoading && /* @__PURE__ */ jsx(TypingIndicator, {})
8524
+ ] })
8525
+ }
8526
+ )
8527
+ ] });
8528
+ }
8057
8529
 
8058
- export { AgentAvatar, AgentHandoff, AgentProvider, AgentSurface, AllocationBreakdown, AnalyticsDashboard, Avatar, AvatarFallback, AvatarImage, Badge, Button, ChartContainer, ChatPanel, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, ControlGrid, ConversationAnalytics, ConversationArtifact, DataPayloadView, DataTable, DynamicRenderer, EntityCard, FileDropZone, FloatingWidget, FullBleedSurface, FullscreenDashboard, GuidedLessonFlow, ImageGenerator, InlineSuggestionsInput, Input, ListingFeed, MediaEditorCanvas, MediaGallery, MessageActions, MessageBubble, MessageList, MessageWithAttachments, MessageWithFeedback, MessageWithReasoning, MessageWithSteps, MetricsGrid, MobileShell, MultimodalInput, OnboardingWizard, OptionCards, OverlayModal, PerformanceMetrics, PersonaSelector, Progress, ProgressTracker, PromptInput, PromptLibrary, QuickReplies, QuizCard, RecommendationCards, ReportView, ScheduleTimeline, ScrollArea, ScrollBar, SemanticBuilderSocketClient, SentimentDisplay, SettingsPanel, SlotRenderer, SplitView, StatusBadge, SystemMessage, TemplateSelector, Textarea, Timestamp, Tooltip4 as Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TypingIndicator, WritingAssistant, badgeVariants, buildSocketUrl, buttonVariants, calculatePercentage, cn, componentManifest, componentMap, componentRegistry, copyToClipboard, createMockBackend, debounce, delay, findComponentsByCapability, findComponentsByCategory, findComponentsBySurface, formatBytes, formatCurrency, formatNumber, formatRelativeTime, formatTime, generateId, getInitials, getManifestEntry, getSentimentBgColor, getSentimentColor, isBrowser, isInIframe, normalizeWebsiteId, parseTextWithBold, registerAllComponents, truncate, useAgent, useAgentBackend, useAgentInput, useAgentLayout, useAgentMessages, useSemanticBuilder };
8530
+ export { AgentAvatar, AgentComposer, AgentConversation, AgentHandoff, AgentProvider, AgentSurface, AllocationBreakdown, AnalyticsDashboard, Avatar, AvatarFallback, AvatarImage, Badge, Button, ChartContainer, ChatPanel, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, ConfirmationPanel, ControlGrid, ConversationAnalytics, ConversationArtifact, DataPayloadView, DataTable, DynamicRenderer, EntityCard, FileDropZone, FloatingWidget, FullBleedSurface, FullscreenDashboard, GuidedLessonFlow, ImageGenerator, InlineSuggestionsInput, Input, ListingFeed, MediaEditorCanvas, MediaGallery, MessageActions, MessageBubble, MessageContainer, MessageContent, MessageList, MessageWithAttachments, MessageWithFeedback, MessageWithReasoning, MessageWithSteps, MetricsGrid, MobileShell, MultimodalInput, NativeAgentProvider, NativeSurface, OnboardingWizard, OptionCards, OverlayModal, PerformanceMetrics, PersonaSelector, Progress, ProgressTracker, PromptInput, PromptLibrary, QuickReplies, QuizCard, RecommendationCards, ReportView, ScheduleTimeline, ScrollArea, ScrollBar, SemanticBuilderSocketClient, SentimentDisplay, SettingsPanel, SlotRenderer, SplitView, StatusBadge, SystemMessage, TemplateSelector, Textarea, Timestamp, Tooltip4 as Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TypingIndicator, WritingAssistant, badgeVariants, buildSocketUrl, buttonVariants, calculatePercentage, cn, componentManifest, componentMap, componentRegistry, copyToClipboard, createMockBackend, debounce, delay, findComponentsByCapability, findComponentsByCategory, findComponentsBySurface, formatBytes, formatCurrency, formatNumber, formatRelativeTime, formatTime, generateId, getInitials, getManifestEntry, getSentimentBgColor, getSentimentColor, isBrowser, isInIframe, normalizeWebsiteId, parseTextWithBold, registerAllComponents, truncate, useAgent, useAgentBackend, useAgentInput, useAgentLayout, useAgentMessages, useNativeAgent, useNativeAgentOptional, useSemanticBuilder };
8059
8531
  //# sourceMappingURL=index.js.map
8060
8532
  //# sourceMappingURL=index.js.map