@page-speed/agent-everywhere 0.3.1 → 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.
package/README.md CHANGED
@@ -71,6 +71,41 @@ import { AgentSurface } from '@page-speed/agent-everywhere';
71
71
  />;
72
72
  ```
73
73
 
74
+ ### Inline confirmation / proposed-plan panels
75
+
76
+ Confirmation and proposed-plan panels flow **inline in the transcript** — attach
77
+ one to a message via `message.confirmation` and it renders after that message's
78
+ content, never pinned over the response. The plan body reuses the same markdown
79
+ rendering and spacing as assistant messages, so long multi-paragraph / bulleted
80
+ plans stay readable. Wire `onConfirmAction` (or use `ConfirmationPanel`
81
+ directly) to handle the action buttons.
82
+
83
+ ```tsx
84
+ const messages = [
85
+ {
86
+ id: 'm1',
87
+ role: 'assistant',
88
+ content: 'Here is the response and the plan.',
89
+ timestamp: new Date(),
90
+ confirmation: {
91
+ title: 'Proposed plan',
92
+ summary: '3 pages to change',
93
+ body: '## What changes\n\n- Rebuild the platform page\n- Refresh OG images',
94
+ actions: [
95
+ { id: 'apply', label: 'Apply changes' },
96
+ { id: 'cancel', label: 'Cancel', variant: 'outline' },
97
+ ],
98
+ },
99
+ },
100
+ ];
101
+
102
+ <AgentSurface
103
+ mode="widget"
104
+ messages={messages}
105
+ onConfirmAction={(messageId, actionId) => apply(messageId, actionId)}
106
+ />;
107
+ ```
108
+
74
109
  ## Artifacts
75
110
 
76
111
  Components an agent can render inside responses, grouped by category. All are
@@ -81,7 +116,7 @@ prop-driven and individually importable:
81
116
  `AnalyticsDashboard`, `ReportView`.
82
117
  - **Interactive** — `EntityCard`, `OptionCards`, `ListingFeed`, `ControlGrid`,
83
118
  `RecommendationCards`, `ScheduleTimeline`, `SettingsPanel`, `AgentHandoff`,
84
- `PersonaSelector`.
119
+ `ConfirmationPanel`, `PersonaSelector`.
85
120
  - **Messages** — `MessageList`, `MessageWithReasoning`, `MessageWithSteps`,
86
121
  `MessageWithFeedback`, `MessageWithAttachments`, `ConversationArtifact`.
87
122
  - **Input** — `PromptInput`, `MultimodalInput`, `QuickReplies`,
package/dist/index.cjs CHANGED
@@ -1238,7 +1238,7 @@ var PromptInput = React4.forwardRef(
1238
1238
  [handleSubmit]
1239
1239
  );
1240
1240
  const variantStyles = {
1241
- default: "border-t px-3 py-2.5",
1241
+ default: "px-3 py-2.5",
1242
1242
  minimal: "px-3 py-2",
1243
1243
  bordered: "border rounded-lg px-3 py-2.5"
1244
1244
  };
@@ -1247,41 +1247,48 @@ var PromptInput = React4.forwardRef(
1247
1247
  minimal: "bg-transparent px-0",
1248
1248
  bordered: "bg-muted/50"
1249
1249
  };
1250
- return /* @__PURE__ */ jsxRuntime.jsx("form", { onSubmit: handleSubmit, className: cn(variantStyles[variant], className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-2", children: [
1251
- leftActions,
1252
- /* @__PURE__ */ jsxRuntime.jsx(
1253
- "textarea",
1254
- {
1255
- ref: textareaRef,
1256
- value,
1257
- onChange: (e) => onChange(e.target.value),
1258
- onKeyDown: handleKeyDown,
1259
- placeholder,
1260
- disabled: disabled || loading,
1261
- autoFocus,
1262
- rows: minRows,
1263
- className: cn(
1264
- "flex-1 resize-none border-0 px-0 py-1 text-sm leading-5 shadow-none",
1265
- "placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0",
1266
- "disabled:cursor-not-allowed disabled:opacity-50",
1267
- inputVariantStyles[variant],
1268
- inputClassName
1250
+ return /* @__PURE__ */ jsxRuntime.jsx(
1251
+ "form",
1252
+ {
1253
+ onSubmit: handleSubmit,
1254
+ className: cn(variantStyles[variant], className),
1255
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end gap-2", children: [
1256
+ leftActions,
1257
+ /* @__PURE__ */ jsxRuntime.jsx(
1258
+ "textarea",
1259
+ {
1260
+ ref: textareaRef,
1261
+ value,
1262
+ onChange: (e) => onChange(e.target.value),
1263
+ onKeyDown: handleKeyDown,
1264
+ placeholder,
1265
+ disabled: disabled || loading,
1266
+ autoFocus,
1267
+ rows: minRows,
1268
+ className: cn(
1269
+ "flex-1 resize-none border-0 px-0 py-1 text-sm leading-5 shadow-none",
1270
+ "placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0",
1271
+ "disabled:cursor-not-allowed disabled:opacity-50",
1272
+ inputVariantStyles[variant],
1273
+ inputClassName
1274
+ )
1275
+ }
1276
+ ),
1277
+ rightActions,
1278
+ showSendButton && /* @__PURE__ */ jsxRuntime.jsx(
1279
+ Button,
1280
+ {
1281
+ type: "submit",
1282
+ size: "sm",
1283
+ variant: variant === "minimal" ? "ghost" : "outline",
1284
+ disabled: !value.trim() || disabled || loading,
1285
+ className: "size-8 shrink-0 p-0",
1286
+ children: sendButtonContent || /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendIcon, { className: "size-4" })
1287
+ }
1269
1288
  )
1270
- }
1271
- ),
1272
- rightActions,
1273
- showSendButton && /* @__PURE__ */ jsxRuntime.jsx(
1274
- Button,
1275
- {
1276
- type: "submit",
1277
- size: "sm",
1278
- variant: variant === "minimal" ? "ghost" : "outline",
1279
- disabled: !value.trim() || disabled || loading,
1280
- className: "size-8 shrink-0 p-0",
1281
- children: sendButtonContent || /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendIcon, { className: "size-4" })
1282
- }
1283
- )
1284
- ] }) });
1289
+ ] })
1290
+ }
1291
+ );
1285
1292
  }
1286
1293
  );
1287
1294
  PromptInput.displayName = "PromptInput";
@@ -7717,10 +7724,58 @@ function ReportView({ report, className }) {
7717
7724
  ))
7718
7725
  ] });
7719
7726
  }
7727
+ function ConfirmationPanel({
7728
+ title = "Proposed plan",
7729
+ summary,
7730
+ body,
7731
+ markdown = true,
7732
+ icon,
7733
+ actions,
7734
+ onAction,
7735
+ ariaLabel,
7736
+ className
7737
+ }) {
7738
+ const hasBody = body !== void 0 && body !== null && body !== "";
7739
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7740
+ react.motion.section,
7741
+ {
7742
+ initial: { opacity: 0, y: 6 },
7743
+ animate: { opacity: 1, y: 0 },
7744
+ transition: { duration: 0.2 },
7745
+ "aria-label": ariaLabel ?? title,
7746
+ className: cn(
7747
+ "flex w-full min-w-0 flex-col rounded-lg border bg-card p-4",
7748
+ className
7749
+ ),
7750
+ children: [
7751
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center gap-2", children: [
7752
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-6 shrink-0 items-center justify-center rounded-md bg-muted/60 text-muted-foreground", children: icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardListIcon, { className: "size-3.5" }) }),
7753
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "min-w-0 flex-1 truncate font-medium text-sm", children: title }),
7754
+ summary && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", className: "shrink-0 text-[10px] font-normal", children: summary })
7755
+ ] }),
7756
+ hasBody && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 min-w-0", children: typeof body === "string" ? /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { markdown, children: body }) : body }),
7757
+ actions && actions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: actions.map((action, index) => /* @__PURE__ */ jsxRuntime.jsx(
7758
+ Button,
7759
+ {
7760
+ type: "button",
7761
+ size: "sm",
7762
+ variant: action.variant ?? (index === 0 ? "default" : "outline"),
7763
+ disabled: action.disabled || action.busy,
7764
+ "aria-busy": action.busy || void 0,
7765
+ onClick: () => onAction?.(action.id),
7766
+ children: action.label
7767
+ },
7768
+ action.id
7769
+ )) })
7770
+ ]
7771
+ }
7772
+ );
7773
+ }
7720
7774
  function MessageList({
7721
7775
  messages,
7722
7776
  showAvatars = true,
7723
7777
  renderMessage,
7778
+ onConfirmAction,
7724
7779
  className
7725
7780
  }) {
7726
7781
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col gap-4", className), children: messages.map((message) => {
@@ -7737,7 +7792,18 @@ function MessageList({
7737
7792
  hasSteps && /* @__PURE__ */ jsxRuntime.jsx(MessageWithSteps, { steps: message.steps }),
7738
7793
  message.content && /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { role: message.role, children: /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { children: message.content }) }),
7739
7794
  hasAttachments && /* @__PURE__ */ jsxRuntime.jsx(MessageWithAttachments, { attachments: message.attachments }),
7740
- message.data && /* @__PURE__ */ jsxRuntime.jsx(DataPayloadView, { payload: message.data })
7795
+ message.data && /* @__PURE__ */ jsxRuntime.jsx(DataPayloadView, { payload: message.data }),
7796
+ message.confirmation && /* @__PURE__ */ jsxRuntime.jsx(
7797
+ ConfirmationPanel,
7798
+ {
7799
+ title: message.confirmation.title,
7800
+ summary: message.confirmation.summary,
7801
+ body: message.confirmation.body,
7802
+ markdown: message.confirmation.markdown,
7803
+ actions: message.confirmation.actions,
7804
+ onAction: (actionId) => onConfirmAction?.(message.id, actionId)
7805
+ }
7806
+ )
7741
7807
  ] })
7742
7808
  ] }, message.id);
7743
7809
  }) });
@@ -7958,6 +8024,7 @@ function AgentSurface({
7958
8024
  showAvatars = true,
7959
8025
  renderMessage,
7960
8026
  onFeedback,
8027
+ onConfirmAction,
7961
8028
  report,
7962
8029
  dataPanel,
7963
8030
  isOpen = true,
@@ -7974,7 +8041,8 @@ function AgentSurface({
7974
8041
  messages,
7975
8042
  showAvatars,
7976
8043
  renderMessage,
7977
- onFeedback
8044
+ onFeedback,
8045
+ onConfirmAction
7978
8046
  }
7979
8047
  );
7980
8048
  const resolvedInput = input ?? (onInputChange && onSubmit !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -8097,6 +8165,7 @@ exports.ChatPanel = ChatPanel;
8097
8165
  exports.Collapsible = Collapsible;
8098
8166
  exports.CollapsibleContent = CollapsibleContent2;
8099
8167
  exports.CollapsibleTrigger = CollapsibleTrigger2;
8168
+ exports.ConfirmationPanel = ConfirmationPanel;
8100
8169
  exports.ControlGrid = ControlGrid;
8101
8170
  exports.ConversationAnalytics = ConversationAnalytics;
8102
8171
  exports.ConversationArtifact = ConversationArtifact;
@@ -8117,6 +8186,8 @@ exports.MediaEditorCanvas = MediaEditorCanvas;
8117
8186
  exports.MediaGallery = MediaGallery;
8118
8187
  exports.MessageActions = MessageActions;
8119
8188
  exports.MessageBubble = MessageBubble;
8189
+ exports.MessageContainer = MessageContainer;
8190
+ exports.MessageContent = MessageContent;
8120
8191
  exports.MessageList = MessageList;
8121
8192
  exports.MessageWithAttachments = MessageWithAttachments;
8122
8193
  exports.MessageWithFeedback = MessageWithFeedback;