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