@copilotkit/react-core 1.55.0-next.9 → 1.55.1-next.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/CHANGELOG.md +46 -6
- package/dist/{copilotkit-DeOzjPsb.mjs → copilotkit-BY5S1-0P.mjs} +2402 -552
- package/dist/copilotkit-BY5S1-0P.mjs.map +1 -0
- package/dist/{copilotkit-BqcyhQjT.d.mts → copilotkit-BuhSUZHb.d.mts} +228 -17
- package/dist/copilotkit-BuhSUZHb.d.mts.map +1 -0
- package/dist/{copilotkit-BDNjFNmk.cjs → copilotkit-Bz5-ImDl.cjs} +2421 -541
- package/dist/copilotkit-Bz5-ImDl.cjs.map +1 -0
- package/dist/{copilotkit-l-IBF4Xp.d.cts → copilotkit-dwDWYpya.d.cts} +228 -17
- package/dist/copilotkit-dwDWYpya.d.cts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +1400 -238
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +13 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +3 -3
- package/dist/v2/index.d.mts +3 -3
- package/dist/v2/index.mjs +3 -2
- package/dist/v2/index.umd.js +2442 -552
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +62 -54
- package/scripts/scope-preflight.mjs +1 -2
- package/src/components/CopilotListeners.tsx +41 -8
- package/src/components/copilot-provider/copilotkit-props.tsx +4 -2
- package/src/components/toast/toast-provider.tsx +269 -194
- package/src/v2/__tests__/A2UIMessageRenderer.test.tsx +86 -22
- package/src/v2/__tests__/utils/test-helpers.tsx +67 -0
- package/src/v2/a2ui/A2UICatalogContext.tsx +79 -0
- package/src/v2/a2ui/A2UIMessageRenderer.tsx +125 -37
- package/src/v2/a2ui/A2UIToolCallRenderer.tsx +290 -0
- package/src/v2/components/CopilotKitInspector.tsx +2 -0
- package/src/v2/components/OpenGenerativeUIRenderer.tsx +598 -0
- package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.tsx +665 -0
- package/src/v2/components/chat/CopilotChat.tsx +193 -50
- package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +17 -2
- package/src/v2/components/chat/CopilotChatAttachmentQueue.tsx +481 -0
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.tsx +139 -0
- package/src/v2/components/chat/CopilotChatInput.tsx +146 -77
- package/src/v2/components/chat/CopilotChatMessageView.tsx +253 -149
- package/src/v2/components/chat/CopilotChatSuggestionView.tsx +1 -0
- package/src/v2/components/chat/CopilotChatUserMessage.tsx +54 -0
- package/src/v2/components/chat/CopilotChatView.tsx +179 -66
- package/src/v2/components/chat/__tests__/CopilotChat.attachments.test.tsx +168 -0
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +63 -2
- package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +544 -1
- package/src/v2/components/chat/__tests__/CopilotChatPerf.e2e.test.tsx +268 -0
- package/src/v2/components/chat/__tests__/CopilotChatPropsRerender.e2e.test.tsx +249 -0
- package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +43 -2
- package/src/v2/components/chat/__tests__/copilot-chat-throttle.test.tsx +138 -0
- package/src/v2/components/chat/index.ts +9 -0
- package/src/v2/components/chat/scroll-element-context.ts +13 -0
- package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +1003 -0
- package/src/v2/hooks/__tests__/use-attachments.test.tsx +169 -0
- package/src/v2/hooks/__tests__/use-threads.test.tsx +54 -0
- package/src/v2/hooks/index.ts +5 -0
- package/src/v2/hooks/use-agent.tsx +95 -10
- package/src/v2/hooks/use-attachments.tsx +269 -0
- package/src/v2/hooks/use-frontend-tool.tsx +5 -2
- package/src/v2/hooks/use-render-activity-message.tsx +9 -2
- package/src/v2/hooks/use-threads.tsx +35 -15
- package/src/v2/index.ts +5 -1
- package/src/v2/lib/__tests__/processPartialHtml.test.ts +112 -0
- package/src/v2/lib/__tests__/slots.test.ts +56 -0
- package/src/v2/lib/processPartialHtml.ts +45 -0
- package/src/v2/lib/slots.tsx +42 -1
- package/src/v2/providers/CopilotChatConfigurationProvider.tsx +9 -3
- package/src/v2/providers/CopilotKitProvider.tsx +268 -32
- package/src/v2/providers/SandboxFunctionsContext.ts +10 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.tsx +198 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.test.tsx +71 -0
- package/src/v2/providers/index.ts +7 -0
- package/src/v2/styles/globals.css +2 -1
- package/src/v2/types/index.ts +1 -0
- package/src/v2/types/sandbox-function.ts +11 -0
- package/dist/copilotkit-BDNjFNmk.cjs.map +0 -1
- package/dist/copilotkit-BqcyhQjT.d.mts.map +0 -1
- package/dist/copilotkit-DeOzjPsb.mjs.map +0 -1
- package/dist/copilotkit-l-IBF4Xp.d.cts.map +0 -1
- package/src/v2/components/__tests__/license-warning-banner.test.tsx +0 -46
|
@@ -97,6 +97,269 @@ export function useToast() {
|
|
|
97
97
|
return context;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
function formatBannerMessage(message: string): string {
|
|
101
|
+
// Try to extract the useful message from JSON first
|
|
102
|
+
const jsonMatch = message.match(/'message':\s*'([^']+)'/);
|
|
103
|
+
if (jsonMatch) {
|
|
104
|
+
return jsonMatch[1];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Strip technical garbage but keep the meaningful message
|
|
108
|
+
let cleaned = message.split(" - ")[0];
|
|
109
|
+
cleaned = cleaned.split(": Error code")[0];
|
|
110
|
+
cleaned = cleaned.replace(/:\s*\d{3}$/, "");
|
|
111
|
+
cleaned = cleaned.replace(/See more:.*$/g, "");
|
|
112
|
+
cleaned = cleaned.trim();
|
|
113
|
+
|
|
114
|
+
return cleaned || "An error occurred.";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function extractUrl(message: string): { url: string; text: string } | null {
|
|
118
|
+
const markdownMatch = /\[([^\]]+)\]\(([^)]+)\)/.exec(message);
|
|
119
|
+
if (markdownMatch) {
|
|
120
|
+
return { url: markdownMatch[2], text: "See More" };
|
|
121
|
+
}
|
|
122
|
+
const plainMatch = /(https?:\/\/[^\s)]+)/.exec(message);
|
|
123
|
+
if (plainMatch) {
|
|
124
|
+
return {
|
|
125
|
+
url: plainMatch[0].replace(/[.,;:'"]*$/, ""),
|
|
126
|
+
text: "See More",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function BannerErrorDisplay({
|
|
133
|
+
bannerError,
|
|
134
|
+
onDismiss,
|
|
135
|
+
}: {
|
|
136
|
+
bannerError: CopilotKitError;
|
|
137
|
+
onDismiss: () => void;
|
|
138
|
+
}) {
|
|
139
|
+
const [detailsExpanded, setDetailsExpanded] = useState(false);
|
|
140
|
+
const severity = getErrorSeverity(bannerError);
|
|
141
|
+
const colors = getErrorColors(severity);
|
|
142
|
+
|
|
143
|
+
// Extract optional error details attached by CopilotListeners
|
|
144
|
+
const details = (bannerError as any).details as
|
|
145
|
+
| {
|
|
146
|
+
code?: string;
|
|
147
|
+
context?: Record<string, any>;
|
|
148
|
+
stack?: string;
|
|
149
|
+
originalMessage?: string;
|
|
150
|
+
}
|
|
151
|
+
| undefined;
|
|
152
|
+
|
|
153
|
+
const link = extractUrl(bannerError.message);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<div
|
|
157
|
+
style={{
|
|
158
|
+
position: "fixed",
|
|
159
|
+
bottom: "20px",
|
|
160
|
+
left: "50%",
|
|
161
|
+
transform: "translateX(-50%)",
|
|
162
|
+
zIndex: 9999,
|
|
163
|
+
backgroundColor: colors.background,
|
|
164
|
+
border: `1px solid ${colors.border}`,
|
|
165
|
+
borderLeft: `4px solid ${colors.border}`,
|
|
166
|
+
borderRadius: "8px",
|
|
167
|
+
padding: "12px 16px",
|
|
168
|
+
fontSize: "13px",
|
|
169
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
170
|
+
backdropFilter: "blur(8px)",
|
|
171
|
+
maxWidth: "min(90vw, 700px)",
|
|
172
|
+
width: "100%",
|
|
173
|
+
boxSizing: "border-box",
|
|
174
|
+
overflow: "hidden",
|
|
175
|
+
}}
|
|
176
|
+
>
|
|
177
|
+
<div
|
|
178
|
+
style={{
|
|
179
|
+
display: "flex",
|
|
180
|
+
justifyContent: "space-between",
|
|
181
|
+
alignItems: "center",
|
|
182
|
+
gap: "10px",
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
<div
|
|
186
|
+
style={{
|
|
187
|
+
display: "flex",
|
|
188
|
+
alignItems: "center",
|
|
189
|
+
gap: "8px",
|
|
190
|
+
flex: 1,
|
|
191
|
+
minWidth: 0,
|
|
192
|
+
}}
|
|
193
|
+
>
|
|
194
|
+
<div
|
|
195
|
+
style={{
|
|
196
|
+
width: "12px",
|
|
197
|
+
height: "12px",
|
|
198
|
+
borderRadius: "50%",
|
|
199
|
+
backgroundColor: colors.border,
|
|
200
|
+
flexShrink: 0,
|
|
201
|
+
}}
|
|
202
|
+
/>
|
|
203
|
+
<div
|
|
204
|
+
style={{
|
|
205
|
+
display: "flex",
|
|
206
|
+
alignItems: "center",
|
|
207
|
+
gap: "10px",
|
|
208
|
+
flex: 1,
|
|
209
|
+
minWidth: 0,
|
|
210
|
+
}}
|
|
211
|
+
>
|
|
212
|
+
<div
|
|
213
|
+
style={{
|
|
214
|
+
color: colors.text,
|
|
215
|
+
lineHeight: "1.4",
|
|
216
|
+
fontWeight: "400",
|
|
217
|
+
fontSize: "13px",
|
|
218
|
+
flex: 1,
|
|
219
|
+
wordBreak: "break-all",
|
|
220
|
+
overflowWrap: "break-word",
|
|
221
|
+
maxWidth: "550px",
|
|
222
|
+
overflow: "hidden",
|
|
223
|
+
display: "-webkit-box",
|
|
224
|
+
WebkitLineClamp: 10,
|
|
225
|
+
WebkitBoxOrient: "vertical",
|
|
226
|
+
}}
|
|
227
|
+
>
|
|
228
|
+
{formatBannerMessage(bannerError.message)}
|
|
229
|
+
</div>
|
|
230
|
+
|
|
231
|
+
{link && (
|
|
232
|
+
<button
|
|
233
|
+
onClick={() =>
|
|
234
|
+
window.open(link.url, "_blank", "noopener,noreferrer")
|
|
235
|
+
}
|
|
236
|
+
style={{
|
|
237
|
+
background: colors.border,
|
|
238
|
+
color: "white",
|
|
239
|
+
border: "none",
|
|
240
|
+
borderRadius: "5px",
|
|
241
|
+
padding: "4px 10px",
|
|
242
|
+
fontSize: "11px",
|
|
243
|
+
fontWeight: "500",
|
|
244
|
+
cursor: "pointer",
|
|
245
|
+
transition: "all 0.2s ease",
|
|
246
|
+
flexShrink: 0,
|
|
247
|
+
}}
|
|
248
|
+
onMouseEnter={(e) => {
|
|
249
|
+
e.currentTarget.style.opacity = "0.9";
|
|
250
|
+
e.currentTarget.style.transform = "translateY(-1px)";
|
|
251
|
+
}}
|
|
252
|
+
onMouseLeave={(e) => {
|
|
253
|
+
e.currentTarget.style.opacity = "1";
|
|
254
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
255
|
+
}}
|
|
256
|
+
>
|
|
257
|
+
{link.text}
|
|
258
|
+
</button>
|
|
259
|
+
)}
|
|
260
|
+
|
|
261
|
+
{details && (
|
|
262
|
+
<button
|
|
263
|
+
onClick={() => setDetailsExpanded(!detailsExpanded)}
|
|
264
|
+
style={{
|
|
265
|
+
background: "transparent",
|
|
266
|
+
border: `1px solid ${colors.border}`,
|
|
267
|
+
borderRadius: "5px",
|
|
268
|
+
padding: "4px 10px",
|
|
269
|
+
fontSize: "11px",
|
|
270
|
+
fontWeight: "500",
|
|
271
|
+
cursor: "pointer",
|
|
272
|
+
color: colors.text,
|
|
273
|
+
flexShrink: 0,
|
|
274
|
+
transition: "all 0.2s ease",
|
|
275
|
+
}}
|
|
276
|
+
onMouseEnter={(e) => {
|
|
277
|
+
e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
|
|
278
|
+
}}
|
|
279
|
+
onMouseLeave={(e) => {
|
|
280
|
+
e.currentTarget.style.background = "transparent";
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
{detailsExpanded ? "Hide Details" : "Show Details"}
|
|
284
|
+
</button>
|
|
285
|
+
)}
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
<button
|
|
289
|
+
onClick={onDismiss}
|
|
290
|
+
style={{
|
|
291
|
+
background: "transparent",
|
|
292
|
+
border: "none",
|
|
293
|
+
color: colors.text,
|
|
294
|
+
cursor: "pointer",
|
|
295
|
+
padding: "2px",
|
|
296
|
+
borderRadius: "3px",
|
|
297
|
+
fontSize: "14px",
|
|
298
|
+
lineHeight: "1",
|
|
299
|
+
opacity: 0.6,
|
|
300
|
+
transition: "all 0.2s ease",
|
|
301
|
+
flexShrink: 0,
|
|
302
|
+
}}
|
|
303
|
+
title="Dismiss"
|
|
304
|
+
onMouseEnter={(e) => {
|
|
305
|
+
e.currentTarget.style.opacity = "1";
|
|
306
|
+
e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
|
|
307
|
+
}}
|
|
308
|
+
onMouseLeave={(e) => {
|
|
309
|
+
e.currentTarget.style.opacity = "0.6";
|
|
310
|
+
e.currentTarget.style.background = "transparent";
|
|
311
|
+
}}
|
|
312
|
+
>
|
|
313
|
+
x
|
|
314
|
+
</button>
|
|
315
|
+
</div>
|
|
316
|
+
|
|
317
|
+
{detailsExpanded && details && (
|
|
318
|
+
<div
|
|
319
|
+
style={{
|
|
320
|
+
marginTop: "10px",
|
|
321
|
+
padding: "10px",
|
|
322
|
+
background: "rgba(0, 0, 0, 0.04)",
|
|
323
|
+
borderRadius: "6px",
|
|
324
|
+
fontSize: "11px",
|
|
325
|
+
fontFamily: "monospace",
|
|
326
|
+
color: colors.text,
|
|
327
|
+
lineHeight: "1.5",
|
|
328
|
+
maxHeight: "200px",
|
|
329
|
+
overflowY: "auto",
|
|
330
|
+
whiteSpace: "pre-wrap",
|
|
331
|
+
wordBreak: "break-all",
|
|
332
|
+
}}
|
|
333
|
+
>
|
|
334
|
+
{details.code && (
|
|
335
|
+
<div>
|
|
336
|
+
<strong>Code:</strong> {details.code}
|
|
337
|
+
</div>
|
|
338
|
+
)}
|
|
339
|
+
{details.originalMessage && (
|
|
340
|
+
<div style={{ marginTop: "4px" }}>
|
|
341
|
+
<strong>Message:</strong> {details.originalMessage}
|
|
342
|
+
</div>
|
|
343
|
+
)}
|
|
344
|
+
{details.context && Object.keys(details.context).length > 0 && (
|
|
345
|
+
<div style={{ marginTop: "4px" }}>
|
|
346
|
+
<strong>Context:</strong>{" "}
|
|
347
|
+
{JSON.stringify(details.context, null, 2)}
|
|
348
|
+
</div>
|
|
349
|
+
)}
|
|
350
|
+
{details.stack && (
|
|
351
|
+
<div style={{ marginTop: "4px", opacity: 0.7 }}>
|
|
352
|
+
<strong>Stack:</strong>
|
|
353
|
+
{"\n"}
|
|
354
|
+
{details.stack}
|
|
355
|
+
</div>
|
|
356
|
+
)}
|
|
357
|
+
</div>
|
|
358
|
+
)}
|
|
359
|
+
</div>
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
100
363
|
export function ToastProvider({
|
|
101
364
|
enabled,
|
|
102
365
|
children,
|
|
@@ -169,200 +432,12 @@ export function ToastProvider({
|
|
|
169
432
|
return (
|
|
170
433
|
<ToastContext.Provider value={value}>
|
|
171
434
|
{/* Banner Error Display */}
|
|
172
|
-
{bannerError &&
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<div
|
|
179
|
-
style={{
|
|
180
|
-
position: "fixed",
|
|
181
|
-
bottom: "20px",
|
|
182
|
-
left: "50%",
|
|
183
|
-
transform: "translateX(-50%)",
|
|
184
|
-
zIndex: 9999,
|
|
185
|
-
backgroundColor: colors.background,
|
|
186
|
-
border: `1px solid ${colors.border}`,
|
|
187
|
-
borderLeft: `4px solid ${colors.border}`,
|
|
188
|
-
borderRadius: "8px",
|
|
189
|
-
padding: "12px 16px",
|
|
190
|
-
fontSize: "13px",
|
|
191
|
-
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
192
|
-
backdropFilter: "blur(8px)",
|
|
193
|
-
maxWidth: "min(90vw, 700px)",
|
|
194
|
-
width: "100%",
|
|
195
|
-
boxSizing: "border-box",
|
|
196
|
-
overflow: "hidden",
|
|
197
|
-
}}
|
|
198
|
-
>
|
|
199
|
-
<div
|
|
200
|
-
style={{
|
|
201
|
-
display: "flex",
|
|
202
|
-
justifyContent: "space-between",
|
|
203
|
-
alignItems: "center",
|
|
204
|
-
gap: "10px",
|
|
205
|
-
}}
|
|
206
|
-
>
|
|
207
|
-
<div
|
|
208
|
-
style={{
|
|
209
|
-
display: "flex",
|
|
210
|
-
alignItems: "center",
|
|
211
|
-
gap: "8px",
|
|
212
|
-
flex: 1,
|
|
213
|
-
minWidth: 0,
|
|
214
|
-
}}
|
|
215
|
-
>
|
|
216
|
-
<div
|
|
217
|
-
style={{
|
|
218
|
-
width: "12px",
|
|
219
|
-
height: "12px",
|
|
220
|
-
borderRadius: "50%",
|
|
221
|
-
backgroundColor: colors.border,
|
|
222
|
-
flexShrink: 0,
|
|
223
|
-
}}
|
|
224
|
-
/>
|
|
225
|
-
<div
|
|
226
|
-
style={{
|
|
227
|
-
display: "flex",
|
|
228
|
-
alignItems: "center",
|
|
229
|
-
gap: "10px",
|
|
230
|
-
flex: 1,
|
|
231
|
-
minWidth: 0,
|
|
232
|
-
}}
|
|
233
|
-
>
|
|
234
|
-
<div
|
|
235
|
-
style={{
|
|
236
|
-
color: colors.text,
|
|
237
|
-
lineHeight: "1.4",
|
|
238
|
-
fontWeight: "400",
|
|
239
|
-
fontSize: "13px",
|
|
240
|
-
flex: 1,
|
|
241
|
-
wordBreak: "break-all",
|
|
242
|
-
overflowWrap: "break-word",
|
|
243
|
-
maxWidth: "550px",
|
|
244
|
-
overflow: "hidden",
|
|
245
|
-
display: "-webkit-box",
|
|
246
|
-
WebkitLineClamp: 10,
|
|
247
|
-
WebkitBoxOrient: "vertical",
|
|
248
|
-
}}
|
|
249
|
-
>
|
|
250
|
-
{(() => {
|
|
251
|
-
let message = bannerError.message;
|
|
252
|
-
|
|
253
|
-
// Try to extract the useful message from JSON first
|
|
254
|
-
const jsonMatch = message.match(
|
|
255
|
-
/'message':\s*'([^']+)'/,
|
|
256
|
-
);
|
|
257
|
-
if (jsonMatch) {
|
|
258
|
-
return jsonMatch[1]; // Return the actual error message
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Strip technical garbage but keep the meaningful message
|
|
262
|
-
message = message.split(" - ")[0]; // Remove everything after " - {"
|
|
263
|
-
message = message.split(": Error code")[0]; // Remove ": Error code: 401"
|
|
264
|
-
message = message.replace(/:\s*\d{3}$/, ""); // Remove trailing ": 401"
|
|
265
|
-
message = message.replace(/See more:.*$/g, ""); // Remove "See more" links
|
|
266
|
-
message = message.trim();
|
|
267
|
-
|
|
268
|
-
// If it's still garbage (contains { or '), use fallback
|
|
269
|
-
// if (message.includes("{") || message.includes("'")) {
|
|
270
|
-
// return "Configuration error.... Please check your setup.";
|
|
271
|
-
// }
|
|
272
|
-
|
|
273
|
-
return message || "Configuration error occurred.";
|
|
274
|
-
})()}
|
|
275
|
-
</div>
|
|
276
|
-
|
|
277
|
-
{(() => {
|
|
278
|
-
const message = bannerError.message;
|
|
279
|
-
const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
280
|
-
const plainUrlRegex = /(https?:\/\/[^\s)]+)/g;
|
|
281
|
-
|
|
282
|
-
// Extract the first URL found
|
|
283
|
-
let url = null;
|
|
284
|
-
let buttonText = "See More";
|
|
285
|
-
|
|
286
|
-
// Check for markdown links first
|
|
287
|
-
const markdownMatch = markdownLinkRegex.exec(message);
|
|
288
|
-
if (markdownMatch) {
|
|
289
|
-
url = markdownMatch[2];
|
|
290
|
-
buttonText = "See More";
|
|
291
|
-
} else {
|
|
292
|
-
// Check for plain URLs
|
|
293
|
-
const urlMatch = plainUrlRegex.exec(message);
|
|
294
|
-
if (urlMatch) {
|
|
295
|
-
url = urlMatch[0].replace(/[.,;:'"]*$/, ""); // Remove trailing punctuation
|
|
296
|
-
buttonText = "See More";
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (!url) return null;
|
|
301
|
-
|
|
302
|
-
return (
|
|
303
|
-
<button
|
|
304
|
-
onClick={() =>
|
|
305
|
-
window.open(url, "_blank", "noopener,noreferrer")
|
|
306
|
-
}
|
|
307
|
-
style={{
|
|
308
|
-
background: colors.border,
|
|
309
|
-
color: "white",
|
|
310
|
-
border: "none",
|
|
311
|
-
borderRadius: "5px",
|
|
312
|
-
padding: "4px 10px",
|
|
313
|
-
fontSize: "11px",
|
|
314
|
-
fontWeight: "500",
|
|
315
|
-
cursor: "pointer",
|
|
316
|
-
transition: "all 0.2s ease",
|
|
317
|
-
flexShrink: 0,
|
|
318
|
-
}}
|
|
319
|
-
onMouseEnter={(e) => {
|
|
320
|
-
e.currentTarget.style.opacity = "0.9";
|
|
321
|
-
e.currentTarget.style.transform =
|
|
322
|
-
"translateY(-1px)";
|
|
323
|
-
}}
|
|
324
|
-
onMouseLeave={(e) => {
|
|
325
|
-
e.currentTarget.style.opacity = "1";
|
|
326
|
-
e.currentTarget.style.transform = "translateY(0)";
|
|
327
|
-
}}
|
|
328
|
-
>
|
|
329
|
-
{buttonText}
|
|
330
|
-
</button>
|
|
331
|
-
);
|
|
332
|
-
})()}
|
|
333
|
-
</div>
|
|
334
|
-
</div>
|
|
335
|
-
<button
|
|
336
|
-
onClick={() => setBannerError(null)}
|
|
337
|
-
style={{
|
|
338
|
-
background: "transparent",
|
|
339
|
-
border: "none",
|
|
340
|
-
color: colors.text,
|
|
341
|
-
cursor: "pointer",
|
|
342
|
-
padding: "2px",
|
|
343
|
-
borderRadius: "3px",
|
|
344
|
-
fontSize: "14px",
|
|
345
|
-
lineHeight: "1",
|
|
346
|
-
opacity: 0.6,
|
|
347
|
-
transition: "all 0.2s ease",
|
|
348
|
-
flexShrink: 0,
|
|
349
|
-
}}
|
|
350
|
-
title="Dismiss"
|
|
351
|
-
onMouseEnter={(e) => {
|
|
352
|
-
e.currentTarget.style.opacity = "1";
|
|
353
|
-
e.currentTarget.style.background = "rgba(0, 0, 0, 0.05)";
|
|
354
|
-
}}
|
|
355
|
-
onMouseLeave={(e) => {
|
|
356
|
-
e.currentTarget.style.opacity = "0.6";
|
|
357
|
-
e.currentTarget.style.background = "transparent";
|
|
358
|
-
}}
|
|
359
|
-
>
|
|
360
|
-
×
|
|
361
|
-
</button>
|
|
362
|
-
</div>
|
|
363
|
-
</div>
|
|
364
|
-
);
|
|
365
|
-
})()}
|
|
435
|
+
{bannerError && (
|
|
436
|
+
<BannerErrorDisplay
|
|
437
|
+
bannerError={bannerError}
|
|
438
|
+
onDismiss={() => setBannerError(null)}
|
|
439
|
+
/>
|
|
440
|
+
)}
|
|
366
441
|
|
|
367
442
|
{/* Toast Display - Deprecated: All errors now show as banners */}
|
|
368
443
|
{children}
|
|
@@ -22,19 +22,25 @@ describe("A2UIMessageRenderer rendering integration", () => {
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
const content = {
|
|
25
|
-
|
|
25
|
+
a2ui_operations: [
|
|
26
26
|
{
|
|
27
|
-
|
|
27
|
+
version: "v0.9",
|
|
28
|
+
createSurface: {
|
|
28
29
|
surfaceId: "test-surface",
|
|
29
|
-
|
|
30
|
-
styles: {},
|
|
30
|
+
catalogId: "https://a2ui.org/specification/v0_9/basic_catalog.json",
|
|
31
31
|
},
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
|
-
|
|
34
|
+
version: "v0.9",
|
|
35
|
+
updateComponents: {
|
|
35
36
|
surfaceId: "test-surface",
|
|
36
37
|
components: [
|
|
37
|
-
{
|
|
38
|
+
{
|
|
39
|
+
id: "root",
|
|
40
|
+
component: "Text",
|
|
41
|
+
text: "Hello World",
|
|
42
|
+
variant: "body",
|
|
43
|
+
},
|
|
38
44
|
],
|
|
39
45
|
},
|
|
40
46
|
},
|
|
@@ -69,12 +75,27 @@ describe("A2UIMessageRenderer rendering integration", () => {
|
|
|
69
75
|
let setContent: (content: any) => void;
|
|
70
76
|
const TestWrapper = () => {
|
|
71
77
|
const [content, _setContent] = useState({
|
|
72
|
-
|
|
73
|
-
{ beginRendering: { surfaceId: "test", root: "root", styles: {} } },
|
|
78
|
+
a2ui_operations: [
|
|
74
79
|
{
|
|
75
|
-
|
|
80
|
+
version: "v0.9",
|
|
81
|
+
createSurface: {
|
|
76
82
|
surfaceId: "test",
|
|
77
|
-
|
|
83
|
+
catalogId:
|
|
84
|
+
"https://a2ui.org/specification/v0_9/basic_catalog.json",
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
version: "v0.9",
|
|
89
|
+
updateComponents: {
|
|
90
|
+
surfaceId: "test",
|
|
91
|
+
components: [
|
|
92
|
+
{
|
|
93
|
+
id: "root",
|
|
94
|
+
component: "Text",
|
|
95
|
+
text: "Initial",
|
|
96
|
+
variant: "body",
|
|
97
|
+
},
|
|
98
|
+
],
|
|
78
99
|
},
|
|
79
100
|
},
|
|
80
101
|
],
|
|
@@ -94,12 +115,27 @@ describe("A2UIMessageRenderer rendering integration", () => {
|
|
|
94
115
|
|
|
95
116
|
await act(async () => {
|
|
96
117
|
setContent({
|
|
97
|
-
|
|
98
|
-
{
|
|
118
|
+
a2ui_operations: [
|
|
119
|
+
{
|
|
120
|
+
version: "v0.9",
|
|
121
|
+
createSurface: {
|
|
122
|
+
surfaceId: "test",
|
|
123
|
+
catalogId:
|
|
124
|
+
"https://a2ui.org/specification/v0_9/basic_catalog.json",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
99
127
|
{
|
|
100
|
-
|
|
128
|
+
version: "v0.9",
|
|
129
|
+
updateComponents: {
|
|
101
130
|
surfaceId: "test",
|
|
102
|
-
components: [
|
|
131
|
+
components: [
|
|
132
|
+
{
|
|
133
|
+
id: "root",
|
|
134
|
+
component: "Text",
|
|
135
|
+
text: "Updated",
|
|
136
|
+
variant: "body",
|
|
137
|
+
},
|
|
138
|
+
],
|
|
103
139
|
},
|
|
104
140
|
},
|
|
105
141
|
],
|
|
@@ -119,7 +155,7 @@ describe("A2UIMessageRenderer rendering integration", () => {
|
|
|
119
155
|
const RenderComponent = renderer.render as React.FC<any>;
|
|
120
156
|
|
|
121
157
|
const TestWrapper = () => (
|
|
122
|
-
<RenderComponent content={{
|
|
158
|
+
<RenderComponent content={{ a2ui_operations: [] }} agent={null} />
|
|
123
159
|
);
|
|
124
160
|
|
|
125
161
|
let container: HTMLElement;
|
|
@@ -140,19 +176,47 @@ describe("A2UIMessageRenderer rendering integration", () => {
|
|
|
140
176
|
const RenderComponent = renderer.render as React.FC<any>;
|
|
141
177
|
|
|
142
178
|
const content = {
|
|
143
|
-
|
|
144
|
-
{
|
|
145
|
-
|
|
179
|
+
a2ui_operations: [
|
|
180
|
+
{
|
|
181
|
+
version: "v0.9",
|
|
182
|
+
createSurface: {
|
|
183
|
+
surfaceId: "s1",
|
|
184
|
+
catalogId: "https://a2ui.org/specification/v0_9/basic_catalog.json",
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
version: "v0.9",
|
|
189
|
+
createSurface: {
|
|
190
|
+
surfaceId: "s2",
|
|
191
|
+
catalogId: "https://a2ui.org/specification/v0_9/basic_catalog.json",
|
|
192
|
+
},
|
|
193
|
+
},
|
|
146
194
|
{
|
|
147
|
-
|
|
195
|
+
version: "v0.9",
|
|
196
|
+
updateComponents: {
|
|
148
197
|
surfaceId: "s1",
|
|
149
|
-
components: [
|
|
198
|
+
components: [
|
|
199
|
+
{
|
|
200
|
+
id: "root",
|
|
201
|
+
component: "Text",
|
|
202
|
+
text: "Surface 1",
|
|
203
|
+
variant: "body",
|
|
204
|
+
},
|
|
205
|
+
],
|
|
150
206
|
},
|
|
151
207
|
},
|
|
152
208
|
{
|
|
153
|
-
|
|
209
|
+
version: "v0.9",
|
|
210
|
+
updateComponents: {
|
|
154
211
|
surfaceId: "s2",
|
|
155
|
-
components: [
|
|
212
|
+
components: [
|
|
213
|
+
{
|
|
214
|
+
id: "root",
|
|
215
|
+
component: "Text",
|
|
216
|
+
text: "Surface 2",
|
|
217
|
+
variant: "body",
|
|
218
|
+
},
|
|
219
|
+
],
|
|
156
220
|
},
|
|
157
221
|
},
|
|
158
222
|
],
|