aui-mcp-server 0.0.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.
Files changed (62) hide show
  1. package/README.md +122 -0
  2. package/dist/cli.cjs +1088 -0
  3. package/dist/cli.cjs.map +1 -0
  4. package/dist/cli.d.cts +1 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +1076 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/client/index.cjs +619 -0
  9. package/dist/client/index.cjs.map +1 -0
  10. package/dist/client/index.d.cts +194 -0
  11. package/dist/client/index.d.ts +194 -0
  12. package/dist/client/index.js +584 -0
  13. package/dist/client/index.js.map +1 -0
  14. package/dist/index.cjs +1053 -0
  15. package/dist/index.cjs.map +1 -0
  16. package/dist/index.d.cts +163 -0
  17. package/dist/index.d.ts +163 -0
  18. package/dist/index.js +1036 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/rsbuild.cjs +1049 -0
  21. package/dist/rsbuild.cjs.map +1 -0
  22. package/dist/rsbuild.d.cts +12 -0
  23. package/dist/rsbuild.d.ts +12 -0
  24. package/dist/rsbuild.js +1038 -0
  25. package/dist/rsbuild.js.map +1 -0
  26. package/dist/rspack.cjs +1016 -0
  27. package/dist/rspack.cjs.map +1 -0
  28. package/dist/rspack.d.cts +40 -0
  29. package/dist/rspack.d.ts +40 -0
  30. package/dist/rspack.js +1005 -0
  31. package/dist/rspack.js.map +1 -0
  32. package/dist/server.cjs +304 -0
  33. package/dist/server.cjs.map +1 -0
  34. package/dist/server.d.cts +16 -0
  35. package/dist/server.d.ts +16 -0
  36. package/dist/server.js +297 -0
  37. package/dist/server.js.map +1 -0
  38. package/package.json +72 -0
  39. package/src/catalog/build.ts +89 -0
  40. package/src/catalog/entry.ts +183 -0
  41. package/src/catalog/parser.ts +173 -0
  42. package/src/catalog/tool_parser.ts +145 -0
  43. package/src/cli.ts +318 -0
  44. package/src/client/handshake.ts +166 -0
  45. package/src/client/index.ts +6 -0
  46. package/src/client/registry.tsx +184 -0
  47. package/src/client/types.ts +136 -0
  48. package/src/client/useA2UIStream.ts +378 -0
  49. package/src/client/useLogger.ts +147 -0
  50. package/src/generator.ts +100 -0
  51. package/src/index.ts +17 -0
  52. package/src/mcp-app-poc.html +69 -0
  53. package/src/poc.ts +88 -0
  54. package/src/rsbuild.ts +46 -0
  55. package/src/rspack.ts +282 -0
  56. package/src/server.ts +391 -0
  57. package/src/templates.ts +51 -0
  58. package/src/types.ts +195 -0
  59. package/src/utils.ts +29 -0
  60. package/test.js +16 -0
  61. package/tsconfig.json +19 -0
  62. package/tsup.config.ts +27 -0
@@ -0,0 +1,584 @@
1
+ import React, { useRef, useEffect, lazy, useState, useCallback } from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { createInstance } from '@module-federation/enhanced/runtime';
4
+ import * as A2UI from '@a2ui/react';
5
+ import { ComponentRegistry, registerDefaultCatalog, useA2UIActions } from '@a2ui/react';
6
+ import { jsx, jsxs } from 'react/jsx-runtime';
7
+
8
+ /* aui-mcp-server */
9
+
10
+ // src/client/types.ts
11
+ var A2UI_EXTENSION_URI = "https://a2ui.org/a2a-extension/a2ui/v0.8";
12
+ var A2UI_MIME_TYPE = "application/json+a2ui";
13
+ var RemoteLogger = class {
14
+ constructor(endpoint) {
15
+ this.endpoint = endpoint;
16
+ }
17
+ queue = [];
18
+ isProcessing = false;
19
+ setEndpoint(endpoint) {
20
+ this.endpoint = endpoint;
21
+ }
22
+ async flush() {
23
+ if (this.isProcessing || this.queue.length === 0) return;
24
+ this.isProcessing = true;
25
+ while (this.queue.length > 0) {
26
+ const entry = this.queue.shift();
27
+ try {
28
+ await fetch(this.endpoint, {
29
+ method: "POST",
30
+ headers: { "Content-Type": "application/json" },
31
+ body: JSON.stringify(entry)
32
+ });
33
+ } catch (e) {
34
+ console.warn("[AUI Logger] Failed to sync log to backend", e);
35
+ break;
36
+ }
37
+ }
38
+ this.isProcessing = false;
39
+ }
40
+ log(level, ...args) {
41
+ const time = (/* @__PURE__ */ new Date()).toISOString();
42
+ const message = args.map((arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)).join(" ");
43
+ const consoleMethod = level.toLowerCase();
44
+ const original = typeof window !== "undefined" && window.__AUI_ORIGINAL_CONSOLE__?.[consoleMethod] || // eslint-disable-next-line no-console
45
+ console[consoleMethod];
46
+ original(`[${level}]`, ...args);
47
+ this.queue.push({ time, level, message });
48
+ void this.flush();
49
+ }
50
+ };
51
+ var remoteLogger = null;
52
+ var globalLogger = null;
53
+ function ensureRemoteLogger(endpoint) {
54
+ if (!remoteLogger) {
55
+ remoteLogger = new RemoteLogger(endpoint);
56
+ } else {
57
+ remoteLogger.setEndpoint(endpoint);
58
+ }
59
+ return remoteLogger;
60
+ }
61
+ function hijackConsoleIfNeeded(logger2) {
62
+ if (typeof window === "undefined") return;
63
+ const w = window;
64
+ if (w.__AUI_CONSOLE_HIJACKED__) return;
65
+ w.__AUI_ORIGINAL_CONSOLE__ = {
66
+ debug: console.debug,
67
+ info: console.info,
68
+ log: console.log,
69
+ warn: console.warn,
70
+ error: console.error
71
+ };
72
+ console.debug = (...args) => logger2.debug(...args);
73
+ console.info = (...args) => logger2.info(...args);
74
+ console.log = (...args) => logger2.info(...args);
75
+ console.warn = (...args) => logger2.warn(...args);
76
+ console.error = (...args) => logger2.error(...args);
77
+ w.__AUI_CONSOLE_HIJACKED__ = true;
78
+ }
79
+ function createLogger(options) {
80
+ const endpoint = options?.endpoint ?? "/api/log";
81
+ const hijackConsole = options?.hijackConsole ?? false;
82
+ const remote = ensureRemoteLogger(endpoint);
83
+ const logger2 = {
84
+ debug: (...args) => remote.log("DEBUG", ...args),
85
+ info: (...args) => remote.log("INFO", ...args),
86
+ warn: (...args) => remote.log("WARN", ...args),
87
+ error: (...args) => remote.log("ERROR", ...args)
88
+ };
89
+ if (hijackConsole) {
90
+ hijackConsoleIfNeeded(logger2);
91
+ }
92
+ globalLogger = logger2;
93
+ return logger2;
94
+ }
95
+ var logger = createLogger();
96
+ function useLogger(options) {
97
+ const optionsRef = useRef(options);
98
+ useEffect(() => {
99
+ createLogger(optionsRef.current);
100
+ }, []);
101
+ return globalLogger ?? logger;
102
+ }
103
+ var ErrorPlaceholder = ({
104
+ title = "Component load failed",
105
+ message
106
+ }) => /* @__PURE__ */ jsxs(
107
+ "div",
108
+ {
109
+ style: {
110
+ padding: "0.75rem 1rem",
111
+ borderRadius: 6,
112
+ border: "1px solid #f5c2c7",
113
+ background: "#f8d7da",
114
+ color: "#842029",
115
+ fontSize: 14
116
+ },
117
+ children: [
118
+ /* @__PURE__ */ jsx("strong", { children: title }),
119
+ message && /* @__PURE__ */ jsx("div", { style: { marginTop: 4 }, children: message })
120
+ ]
121
+ }
122
+ );
123
+ var mfInstance = null;
124
+ var registryInstance = null;
125
+ function ensureMFInstance(options) {
126
+ if (mfInstance) return mfInstance;
127
+ const baseShared = {
128
+ react: {
129
+ version: React.version,
130
+ scope: "default",
131
+ lib: () => React,
132
+ shareConfig: {
133
+ singleton: true,
134
+ requiredVersion: "^18.0.0"
135
+ }
136
+ },
137
+ "react-dom": {
138
+ version: React.version,
139
+ scope: "default",
140
+ lib: () => ReactDOM,
141
+ shareConfig: {
142
+ singleton: true,
143
+ requiredVersion: "^18.0.0"
144
+ }
145
+ },
146
+ "@a2ui/react": {
147
+ version: "0.8.0",
148
+ scope: "default",
149
+ lib: () => A2UI,
150
+ shareConfig: {
151
+ singleton: true,
152
+ requiredVersion: "^0.8.0"
153
+ }
154
+ }
155
+ };
156
+ const shared = {
157
+ ...baseShared,
158
+ ...options?.shared ?? {}
159
+ };
160
+ mfInstance = createInstance({
161
+ name: "aui_mcp_client",
162
+ remotes: [],
163
+ shared
164
+ });
165
+ return mfInstance;
166
+ }
167
+ function createMFRegistry(options) {
168
+ ensureMFInstance(options);
169
+ if (!registryInstance) {
170
+ registryInstance = ComponentRegistry.getInstance();
171
+ registerDefaultCatalog(registryInstance);
172
+ logger.info("[aui-mcp-server/react] ComponentRegistry initialized with default catalog");
173
+ }
174
+ if (typeof window !== "undefined" && options?.exposeGlobal) {
175
+ window.__AUI_REGISTRY__ = registryInstance;
176
+ }
177
+ return registryInstance;
178
+ }
179
+ function registerMFComponent(registry, componentType, xLoader) {
180
+ const mf = ensureMFInstance();
181
+ const { url, scope, module: modulePath } = xLoader;
182
+ const exposeName = modulePath.replace(/^\.\//, "");
183
+ const remoteId = `${scope}/${exposeName}`;
184
+ const LazyComponent = lazy(async () => {
185
+ logger.debug(`[AUI-X] MF lazy load triggered: ${componentType} (${remoteId})`);
186
+ try {
187
+ mf.registerRemotes([{ name: scope, entry: url }], { force: false });
188
+ const mod = await mf.loadRemote(remoteId);
189
+ if (!mod) {
190
+ throw new Error(`[AUI-X] loadRemote returned null for "${remoteId}"`);
191
+ }
192
+ const Component = mod.default ?? mod;
193
+ logger.info(`[AUI-X] \u2705 MF component loaded OK: ${componentType}`);
194
+ return { default: Component };
195
+ } catch (error) {
196
+ logger.error(
197
+ `[AUI-X] \u274C Failed to load MF component "${componentType}" from "${remoteId}":`,
198
+ error
199
+ );
200
+ const Fallback = () => /* @__PURE__ */ jsx(
201
+ ErrorPlaceholder,
202
+ {
203
+ title: "Failed to load MF component",
204
+ message: `Unable to load remote component: ${componentType}`
205
+ }
206
+ );
207
+ return { default: Fallback };
208
+ }
209
+ });
210
+ const registration = {
211
+ component: LazyComponent
212
+ };
213
+ registry.register(componentType, registration);
214
+ logger.info(
215
+ `[AUI-X] MF component registered (runtime): ${componentType} \u2190 ${url} \u2192 ${remoteId}`
216
+ );
217
+ }
218
+ function syncRegistryFromCatalog(registry, catalog) {
219
+ Object.entries(catalog).forEach(([type, schema]) => {
220
+ const anySchema = schema;
221
+ const xLoader = anySchema.x_loader || anySchema["x-loader"];
222
+ if (!xLoader || xLoader.type !== "module-federation") return;
223
+ registerMFComponent(registry, type, xLoader);
224
+ });
225
+ }
226
+
227
+ // src/client/handshake.ts
228
+ function toLiteralStringValue(value) {
229
+ if (value === void 0 || value === null) return void 0;
230
+ if (typeof value === "string") {
231
+ return { literalString: value };
232
+ }
233
+ if (typeof value === "object") {
234
+ const obj = value;
235
+ if (typeof obj.literalString === "string" || typeof obj.path === "string") {
236
+ return {
237
+ ...obj.literalString ? { literalString: obj.literalString } : {},
238
+ ...obj.path ? { path: obj.path } : {}
239
+ };
240
+ }
241
+ }
242
+ return { literalString: String(value) };
243
+ }
244
+ async function performHandshake(agentUrl, registry) {
245
+ try {
246
+ const base = agentUrl.replace(/\/$/, "");
247
+ const handshakeUrl = base.endsWith("/agent-card") ? base : `${base}/agent-card`;
248
+ const response = await fetch(handshakeUrl);
249
+ if (!response.ok) {
250
+ throw new Error(`Failed to fetch AgentCard from ${handshakeUrl}: ${response.statusText}`);
251
+ }
252
+ const agentCard = await response.json();
253
+ const a2uiExt = agentCard.capabilities?.extensions?.find(
254
+ (ext) => ext.uri === A2UI_EXTENSION_URI
255
+ );
256
+ if (!a2uiExt || !a2uiExt.params?.inlineCatalogs) {
257
+ logger.warn("[AUI-X] No inlineCatalogs found in AgentCard. Handshake skipped.");
258
+ return {};
259
+ }
260
+ const catalogs = a2uiExt.params.inlineCatalogs;
261
+ const allComponents = {};
262
+ const effectiveRegistry = registry ?? createMFRegistry();
263
+ catalogs.forEach((cat) => {
264
+ if (!cat.components) return;
265
+ const count = Object.keys(cat.components).length;
266
+ logger.info(
267
+ `[AUI-X] Found catalog "${cat.id ?? "inline"}", syncing ${count} components from handshake`
268
+ );
269
+ Object.assign(allComponents, cat.components);
270
+ syncRegistryFromCatalog(effectiveRegistry, cat.components);
271
+ });
272
+ return allComponents;
273
+ } catch (error) {
274
+ logger.error("[AUI-X] Handshake error:", error);
275
+ return {};
276
+ }
277
+ }
278
+ function render(toolCall, catalog) {
279
+ const { tool_name, tool_input } = toolCall;
280
+ let componentType = tool_name;
281
+ if (tool_name.startsWith("render_")) {
282
+ const parts = tool_name.split("_").slice(1);
283
+ componentType = parts.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
284
+ }
285
+ const schema = catalog[componentType];
286
+ if (!schema) {
287
+ throw new Error(
288
+ `[AUI-X] Component type "${componentType}" not found in catalog for tool "${tool_name}"`
289
+ );
290
+ }
291
+ const surfaceId = `${tool_name}-surface-handshake`;
292
+ const rootId = "root-column";
293
+ const props = {};
294
+ if (tool_input) {
295
+ Object.entries(tool_input).forEach(([key, value]) => {
296
+ if (key === "mfData" || key === "dataModel") {
297
+ props[key] = value;
298
+ } else {
299
+ const val = toLiteralStringValue(value);
300
+ if (val) props[key] = val;
301
+ }
302
+ });
303
+ }
304
+ const components = [
305
+ {
306
+ id: rootId,
307
+ component: {
308
+ Column: {
309
+ children: {
310
+ explicitList: ["dynamic-card"]
311
+ }
312
+ }
313
+ }
314
+ },
315
+ {
316
+ id: "dynamic-card",
317
+ component: {
318
+ [componentType]: props
319
+ }
320
+ }
321
+ ];
322
+ return [
323
+ {
324
+ beginRendering: {
325
+ surfaceId,
326
+ root: rootId,
327
+ styles: {
328
+ primaryColor: "#1DB954",
329
+ font: "Roboto"
330
+ }
331
+ }
332
+ },
333
+ {
334
+ surfaceUpdate: {
335
+ surfaceId,
336
+ components
337
+ }
338
+ }
339
+ ];
340
+ }
341
+ function isTaskStatusUpdateEvent(e) {
342
+ return "result" in e && "status" in e.result;
343
+ }
344
+ function isTaskArtifactUpdateEvent(e) {
345
+ return "result" in e && "artifact" in e.result;
346
+ }
347
+ function isA2UIPart(part) {
348
+ return part.kind === "data" && (part.metadata?.mimeType === A2UI_MIME_TYPE || // snake_case compatibility
349
+ part.metadata?.mime_type === A2UI_MIME_TYPE);
350
+ }
351
+ function extractText(parts) {
352
+ return parts.filter((p) => p.kind === "text").map((p) => p.text).join("");
353
+ }
354
+ function extractA2UIData(parts) {
355
+ return parts.filter(isA2UIPart).map((p) => p.data);
356
+ }
357
+ function useA2UIStream(options) {
358
+ const actions = useA2UIActions();
359
+ const agentUrl = options?.agentUrl ?? "/api";
360
+ const defaultIsActionPayload = options?.defaultIsActionPayload ?? false;
361
+ const [messages, setMessages] = useState([]);
362
+ const [isLoading, setIsLoading] = useState(false);
363
+ const [lastPerf, setLastPerf] = useState(null);
364
+ const contextIdRef = useRef(crypto.randomUUID());
365
+ const taskIdRef = useRef(void 0);
366
+ const perfStateRef = useRef({});
367
+ const now = () => typeof performance !== "undefined" && performance.now ? performance.now() : Date.now();
368
+ const markFirstComponentRendered = () => {
369
+ const state = perfStateRef.current;
370
+ if (!state.t0 || state.t1 || state.completed) return;
371
+ state.t1 = now();
372
+ };
373
+ const finalizePerf = (reason) => {
374
+ const state = perfStateRef.current;
375
+ if (!state.t0 || state.completed) return;
376
+ state.completed = true;
377
+ state.t2 = state.t2 ?? now();
378
+ const t0 = state.t0;
379
+ const t1 = state.t1;
380
+ const t2 = state.t2;
381
+ const ttfcMs = t1 ? t1 - t0 : void 0;
382
+ const ttlcMs = t2 - t0;
383
+ const snapshot = {
384
+ t0,
385
+ t1,
386
+ t2,
387
+ ttfcMs,
388
+ ttlcMs,
389
+ reason
390
+ };
391
+ setLastPerf(snapshot);
392
+ const ttfcLabel = ttfcMs !== void 0 ? `${(ttfcMs / 1e3).toFixed(2)}s` : "N/A";
393
+ const totalLabel = `${(ttlcMs / 1e3).toFixed(2)}s`;
394
+ console.log("[AUI-X Perf] TTFC: %s, Total: %s", ttfcLabel, totalLabel, {
395
+ t0,
396
+ t1,
397
+ t2,
398
+ ttfcMs,
399
+ ttlcMs,
400
+ reason
401
+ });
402
+ };
403
+ const sendMessage = useCallback(
404
+ async (userText, isActionPayload = defaultIsActionPayload) => {
405
+ if (!userText.trim() || isLoading) return;
406
+ setIsLoading(true);
407
+ perfStateRef.current = {
408
+ t0: now(),
409
+ t1: void 0,
410
+ t2: void 0,
411
+ hasFirstComponent: false,
412
+ completed: false
413
+ };
414
+ if (!isActionPayload) {
415
+ setMessages((prev) => [...prev, { role: "user", text: userText }]);
416
+ }
417
+ let assistantText = "";
418
+ let renderedSurface = false;
419
+ try {
420
+ let parts;
421
+ if (isActionPayload) {
422
+ let actionData;
423
+ try {
424
+ actionData = JSON.parse(userText);
425
+ } catch {
426
+ actionData = { userAction: { actionName: userText, context: {} } };
427
+ }
428
+ parts = [{ kind: "data", data: actionData }];
429
+ } else {
430
+ parts = [{ kind: "text", text: userText }];
431
+ }
432
+ const rpcRequest = {
433
+ jsonrpc: "2.0",
434
+ id: crypto.randomUUID(),
435
+ method: "message/stream",
436
+ params: {
437
+ message: {
438
+ kind: "message",
439
+ role: "user",
440
+ messageId: crypto.randomUUID(),
441
+ contextId: contextIdRef.current,
442
+ ...taskIdRef.current ? { taskId: taskIdRef.current } : {},
443
+ extensions: [A2UI_EXTENSION_URI],
444
+ parts
445
+ }
446
+ }
447
+ };
448
+ const response = await fetch(agentUrl, {
449
+ method: "POST",
450
+ headers: { "Content-Type": "application/json" },
451
+ body: JSON.stringify(rpcRequest)
452
+ });
453
+ if (!response.ok) {
454
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
455
+ }
456
+ if (!response.body) {
457
+ throw new Error("No response body");
458
+ }
459
+ const reader = response.body.getReader();
460
+ const decoder = new TextDecoder();
461
+ let buffer = "";
462
+ while (true) {
463
+ const { done, value } = await reader.read();
464
+ if (done) break;
465
+ buffer += decoder.decode(value, { stream: true });
466
+ const lines = buffer.split("\n");
467
+ buffer = lines.pop() ?? "";
468
+ for (const line of lines) {
469
+ if (!line.startsWith("data: ")) continue;
470
+ const jsonStr = line.slice(6).trim();
471
+ if (!jsonStr || jsonStr === "[DONE]") continue;
472
+ let event;
473
+ try {
474
+ event = JSON.parse(jsonStr);
475
+ } catch {
476
+ continue;
477
+ }
478
+ if (isTaskStatusUpdateEvent(event)) {
479
+ const { id: taskId, status } = event.result;
480
+ if (taskId) taskIdRef.current = taskId;
481
+ const rawParts = status.message?.parts ?? [];
482
+ const textChunk = extractText(rawParts);
483
+ if (textChunk) {
484
+ assistantText += textChunk;
485
+ setMessages((prev) => {
486
+ const last = prev[prev.length - 1];
487
+ if (last?.role === "assistant") {
488
+ return [...prev.slice(0, -1), { ...last, text: assistantText }];
489
+ }
490
+ return [...prev, { role: "assistant", text: assistantText }];
491
+ });
492
+ }
493
+ const a2uiData = extractA2UIData(rawParts);
494
+ if (a2uiData.length > 0) {
495
+ markFirstComponentRendered();
496
+ logger.info("[A2UI] Received UI update part", {
497
+ taskId,
498
+ componentCount: a2uiData.length
499
+ });
500
+ actions.processMessages(a2uiData);
501
+ const surfaces = actions.getSurfaces();
502
+ logger.debug("[A2UI] Surfaces after process:", Array.from(surfaces.keys()));
503
+ renderedSurface = true;
504
+ setMessages((prev) => {
505
+ const last = prev[prev.length - 1];
506
+ if (last?.role === "assistant") {
507
+ return [...prev.slice(0, -1), { ...last, hasSurface: true }];
508
+ }
509
+ return [...prev, { role: "assistant", text: assistantText, hasSurface: true }];
510
+ });
511
+ }
512
+ }
513
+ if (isTaskArtifactUpdateEvent(event)) {
514
+ const { artifact } = event.result;
515
+ const rawParts = artifact.parts ?? [];
516
+ const textChunk = extractText(rawParts);
517
+ if (textChunk) {
518
+ assistantText += textChunk;
519
+ setMessages((prev) => {
520
+ const last = prev[prev.length - 1];
521
+ if (last?.role === "assistant") {
522
+ return [...prev.slice(0, -1), { ...last, text: assistantText }];
523
+ }
524
+ return [...prev, { role: "assistant", text: assistantText }];
525
+ });
526
+ }
527
+ const a2uiData = extractA2UIData(rawParts);
528
+ if (a2uiData.length > 0) {
529
+ markFirstComponentRendered();
530
+ actions.processMessages(a2uiData);
531
+ renderedSurface = true;
532
+ setMessages((prev) => {
533
+ const last = prev[prev.length - 1];
534
+ if (last?.role === "assistant") {
535
+ return [...prev.slice(0, -1), { ...last, hasSurface: true }];
536
+ }
537
+ return [...prev, { role: "assistant", text: assistantText, hasSurface: true }];
538
+ });
539
+ }
540
+ }
541
+ if (isTaskStatusUpdateEvent(event) && (event.result.final || event.result.status.state === "completed")) {
542
+ finalizePerf("status-completed");
543
+ }
544
+ }
545
+ }
546
+ if (!assistantText && !renderedSurface) {
547
+ setMessages((prev) => [...prev, { role: "assistant", text: "\u2026" }]);
548
+ }
549
+ } catch (err) {
550
+ setMessages((prev) => [
551
+ ...prev,
552
+ { role: "assistant", text: `Connection error: ${String(err)}` }
553
+ ]);
554
+ } finally {
555
+ setIsLoading(false);
556
+ finalizePerf("sse-end");
557
+ }
558
+ },
559
+ [agentUrl, defaultIsActionPayload, isLoading, actions]
560
+ );
561
+ const processLocalMessages = useCallback(
562
+ (serverMessages, label = "Local tool call: rendered UI surface") => {
563
+ if (!serverMessages || serverMessages.length === 0) return;
564
+ logger.info("[A2UI] processLocalMessages:", label, `(${serverMessages.length} messages)`);
565
+ logger.debug("[A2UI] Surfaces BEFORE process:", Array.from(actions.getSurfaces().keys()));
566
+ actions.processMessages(serverMessages);
567
+ logger.debug("[A2UI] Surfaces AFTER process:", Array.from(actions.getSurfaces().keys()));
568
+ setMessages((prev) => [
569
+ ...prev,
570
+ {
571
+ role: "assistant",
572
+ text: label,
573
+ hasSurface: true
574
+ }
575
+ ]);
576
+ },
577
+ [actions]
578
+ );
579
+ return { messages, isLoading, sendMessage, processLocalMessages, lastPerf };
580
+ }
581
+
582
+ export { A2UI_EXTENSION_URI, A2UI_MIME_TYPE, createLogger, createMFRegistry, logger, performHandshake, registerMFComponent, render, syncRegistryFromCatalog, useA2UIStream, useLogger };
583
+ //# sourceMappingURL=index.js.map
584
+ //# sourceMappingURL=index.js.map