@openuidev/a2ui 0.3.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.cjs ADDED
@@ -0,0 +1,795 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_json_pointer = require("./json-pointer-CA9LEWAP.cjs");
3
+ let _openuidev_lang_core = require("@openuidev/lang-core");
4
+ let zod_v4 = require("zod/v4");
5
+ //#region src/protocol-schema.ts
6
+ const jsonValueSchema = zod_v4.z.json();
7
+ const jsonObjectSchema = zod_v4.z.record(zod_v4.z.string(), jsonValueSchema);
8
+ const versionSchema = zod_v4.z.literal("v1.0");
9
+ const surfaceIdSchema = zod_v4.z.string();
10
+ const extensionKeySchema = zod_v4.z.string().regex(/^[\p{XID_Start}_][\p{XID_Continue}]*$/u);
11
+ const extensionsSchema = zod_v4.z.record(extensionKeySchema, jsonValueSchema);
12
+ const messageMetadataSchema = zod_v4.z.strictObject({ extensions: extensionsSchema.optional() });
13
+ const langComponentsSchema = zod_v4.z.array(zod_v4.z.string().min(1)).min(1).describe("Complete OpenUI Lang statements or statement blocks, merged by statement ID in array order.");
14
+ const a2uiFunctionCallSchema = zod_v4.z.strictObject({
15
+ call: zod_v4.z.string(),
16
+ catalogId: zod_v4.z.string().optional(),
17
+ args: jsonObjectSchema.optional()
18
+ });
19
+ const a2uiFunctionResponseSchema = zod_v4.z.union([zod_v4.z.strictObject({
20
+ functionCallId: zod_v4.z.string(),
21
+ value: jsonValueSchema
22
+ }), zod_v4.z.strictObject({
23
+ functionCallId: zod_v4.z.string(),
24
+ error: zod_v4.z.strictObject({
25
+ code: zod_v4.z.string(),
26
+ message: zod_v4.z.string()
27
+ })
28
+ })]);
29
+ const createSurfaceMessageSchema = zod_v4.z.strictObject({
30
+ version: versionSchema,
31
+ createSurface: zod_v4.z.strictObject({
32
+ surfaceId: surfaceIdSchema,
33
+ catalogId: zod_v4.z.string().optional(),
34
+ sendDataModel: zod_v4.z.boolean().optional().meta({ default: false }),
35
+ components: langComponentsSchema.optional().describe("Optional initial OpenUI Lang statements for single-message surface creation."),
36
+ dataModel: jsonObjectSchema.optional(),
37
+ metadata: messageMetadataSchema.optional()
38
+ })
39
+ });
40
+ const updateComponentsMessageSchema = zod_v4.z.strictObject({
41
+ version: versionSchema,
42
+ updateComponents: zod_v4.z.strictObject({
43
+ surfaceId: surfaceIdSchema,
44
+ components: langComponentsSchema
45
+ })
46
+ });
47
+ const updateDataModelMessageSchema = zod_v4.z.strictObject({
48
+ version: versionSchema,
49
+ updateDataModel: zod_v4.z.strictObject({
50
+ surfaceId: surfaceIdSchema,
51
+ path: zod_v4.z.string().optional(),
52
+ value: jsonValueSchema
53
+ })
54
+ });
55
+ const deleteSurfaceMessageSchema = zod_v4.z.strictObject({
56
+ version: versionSchema,
57
+ deleteSurface: zod_v4.z.strictObject({ surfaceId: surfaceIdSchema })
58
+ });
59
+ const callRendererFunctionMessageSchema = zod_v4.z.strictObject({
60
+ version: versionSchema,
61
+ callRendererFunction: zod_v4.z.strictObject({
62
+ functionCallId: zod_v4.z.string(),
63
+ callFunction: a2uiFunctionCallSchema.extend({ catalogId: zod_v4.z.string() })
64
+ })
65
+ });
66
+ const agentFunctionResponseMessageSchema = zod_v4.z.strictObject({
67
+ version: versionSchema,
68
+ agentFunctionResponse: a2uiFunctionResponseSchema
69
+ });
70
+ const agentToRendererMessageSchema = zod_v4.z.union([
71
+ createSurfaceMessageSchema,
72
+ updateComponentsMessageSchema,
73
+ updateDataModelMessageSchema,
74
+ deleteSurfaceMessageSchema,
75
+ callRendererFunctionMessageSchema,
76
+ agentFunctionResponseMessageSchema
77
+ ]);
78
+ const actionMessageSchema = zod_v4.z.strictObject({
79
+ version: versionSchema,
80
+ action: zod_v4.z.strictObject({
81
+ name: zod_v4.z.string(),
82
+ userMessage: zod_v4.z.string().optional(),
83
+ surfaceId: surfaceIdSchema,
84
+ sourceComponentId: zod_v4.z.string(),
85
+ timestamp: zod_v4.z.iso.datetime({ offset: true }),
86
+ context: jsonObjectSchema,
87
+ metadata: messageMetadataSchema.optional()
88
+ })
89
+ });
90
+ const callAgentFunctionMessageSchema = zod_v4.z.strictObject({
91
+ version: versionSchema,
92
+ callAgentFunction: zod_v4.z.strictObject({
93
+ surfaceId: surfaceIdSchema,
94
+ functionCallId: zod_v4.z.string(),
95
+ callFunction: a2uiFunctionCallSchema
96
+ })
97
+ });
98
+ const rendererFunctionResponseMessageSchema = zod_v4.z.strictObject({
99
+ version: versionSchema,
100
+ rendererFunctionResponse: a2uiFunctionResponseSchema
101
+ });
102
+ const validationErrorCodeSchema = zod_v4.z.enum([
103
+ "VALIDATION_FAILED",
104
+ "UNALLOWED_PARENT",
105
+ "UNALLOWED_CHILD"
106
+ ]);
107
+ const validationFailedErrorMessageSchema = zod_v4.z.strictObject({
108
+ version: versionSchema,
109
+ error: zod_v4.z.strictObject({
110
+ code: validationErrorCodeSchema,
111
+ surfaceId: surfaceIdSchema,
112
+ path: zod_v4.z.string(),
113
+ message: zod_v4.z.string()
114
+ })
115
+ });
116
+ const genericErrorCodeSchema = zod_v4.z.string().refine((code) => !validationErrorCodeSchema.options.includes(code));
117
+ const genericErrorMessageSchema = zod_v4.z.union([zod_v4.z.strictObject({
118
+ version: versionSchema,
119
+ error: zod_v4.z.strictObject({
120
+ code: genericErrorCodeSchema,
121
+ message: zod_v4.z.string(),
122
+ surfaceId: surfaceIdSchema
123
+ })
124
+ }), zod_v4.z.strictObject({
125
+ version: versionSchema,
126
+ error: zod_v4.z.strictObject({
127
+ code: genericErrorCodeSchema,
128
+ message: zod_v4.z.string(),
129
+ functionCallId: zod_v4.z.string()
130
+ })
131
+ })]);
132
+ const rendererToAgentMessageSchema = zod_v4.z.union([
133
+ actionMessageSchema,
134
+ callAgentFunctionMessageSchema,
135
+ rendererFunctionResponseMessageSchema,
136
+ validationFailedErrorMessageSchema,
137
+ genericErrorMessageSchema
138
+ ]);
139
+ const rendererCapabilitiesSchema = zod_v4.z.strictObject({ "v1.0": zod_v4.z.strictObject({
140
+ supportedCatalogIds: zod_v4.z.array(zod_v4.z.string()),
141
+ inlineCatalogs: zod_v4.z.array(jsonObjectSchema).optional()
142
+ }) });
143
+ const agentCapabilitiesSchema = zod_v4.z.strictObject({ "v1.0": zod_v4.z.strictObject({
144
+ supportedCatalogIds: zod_v4.z.array(zod_v4.z.string()).optional(),
145
+ acceptsInlineCatalogs: zod_v4.z.boolean().optional().meta({ default: false })
146
+ }) });
147
+ const rendererDataModelSchema = zod_v4.z.strictObject({
148
+ version: versionSchema,
149
+ surfaces: zod_v4.z.record(zod_v4.z.string(), jsonObjectSchema)
150
+ });
151
+ //#endregion
152
+ //#region src/runtime-schema.ts
153
+ function escapePointerToken(token) {
154
+ return String(token).replace(/~/g, "~0").replace(/\//g, "~1");
155
+ }
156
+ function issuePath(path) {
157
+ return path.length === 0 ? "/" : `/${path.map(escapePointerToken).join("/")}`;
158
+ }
159
+ function validateAgentToRendererMessage(input) {
160
+ const object = input != null && typeof input === "object" && !Array.isArray(input) ? input : void 0;
161
+ const presentKeys = object ? [
162
+ "createSurface",
163
+ "updateComponents",
164
+ "updateDataModel",
165
+ "deleteSurface",
166
+ "callRendererFunction",
167
+ "agentFunctionResponse"
168
+ ].filter((key) => Object.prototype.hasOwnProperty.call(object, key)) : [];
169
+ const result = (presentKeys.length === 1 ? {
170
+ createSurface: createSurfaceMessageSchema,
171
+ updateComponents: updateComponentsMessageSchema,
172
+ updateDataModel: updateDataModelMessageSchema,
173
+ deleteSurface: deleteSurfaceMessageSchema,
174
+ callRendererFunction: callRendererFunctionMessageSchema,
175
+ agentFunctionResponse: agentFunctionResponseMessageSchema
176
+ }[presentKeys[0]] : agentToRendererMessageSchema).safeParse(input);
177
+ if (result.success) return {
178
+ success: true,
179
+ message: result.data
180
+ };
181
+ return {
182
+ success: false,
183
+ issues: result.error.issues.map((issue) => ({
184
+ path: issuePath(issue.path),
185
+ message: issue.message
186
+ }))
187
+ };
188
+ }
189
+ //#endregion
190
+ //#region src/statement-patch.ts
191
+ const STATEMENT_PATTERN = /^(\$?[A-Za-z_][A-Za-z0-9_]*)\s*=\s*([\s\S]*)$/u;
192
+ function stripFences(source) {
193
+ const trimmed = source.trim();
194
+ if (!trimmed.startsWith("```")) return trimmed;
195
+ const firstLineEnd = trimmed.indexOf("\n");
196
+ const lastFence = trimmed.lastIndexOf("```");
197
+ if (firstLineEnd === -1 || lastFence <= firstLineEnd) return trimmed;
198
+ return trimmed.slice(firstLineEnd + 1, lastFence).trim();
199
+ }
200
+ function splitStatements(source) {
201
+ const statements = [];
202
+ let depth = 0;
203
+ let ternaryDepth = 0;
204
+ let quote = false;
205
+ let escaped = false;
206
+ let start = 0;
207
+ for (let index = 0; index < source.length; index += 1) {
208
+ const character = source[index];
209
+ if (escaped) {
210
+ escaped = false;
211
+ continue;
212
+ }
213
+ if (character === "\\" && quote) {
214
+ escaped = true;
215
+ continue;
216
+ }
217
+ if (quote) {
218
+ if (character === quote) quote = false;
219
+ continue;
220
+ }
221
+ if (character === "\"" || character === "'") {
222
+ quote = character;
223
+ continue;
224
+ }
225
+ if (character === "(" || character === "[" || character === "{") depth += 1;
226
+ else if (character === ")" || character === "]" || character === "}") depth = Math.max(0, depth - 1);
227
+ else if (character === "?" && depth === 0) ternaryDepth += 1;
228
+ else if (character === ":" && depth === 0 && ternaryDepth > 0) ternaryDepth -= 1;
229
+ else if (character === "\n" && depth === 0 && ternaryDepth === 0) {
230
+ let next = index + 1;
231
+ while (next < source.length && /\s/u.test(source[next])) next += 1;
232
+ if (source[next] === "?") continue;
233
+ const statement = source.slice(start, index).trim();
234
+ if (statement) statements.push(statement);
235
+ start = index + 1;
236
+ }
237
+ }
238
+ const finalStatement = source.slice(start).trim();
239
+ if (finalStatement) statements.push(finalStatement);
240
+ return statements;
241
+ }
242
+ function parseStatements(source) {
243
+ return splitStatements(stripFences(source)).map((raw) => {
244
+ const match = STATEMENT_PATTERN.exec(raw);
245
+ if (!match) throw new Error(`Invalid OpenUI Lang statement: ${raw}`);
246
+ return {
247
+ id: match[1],
248
+ expression: match[2].trim(),
249
+ raw
250
+ };
251
+ });
252
+ }
253
+ /**
254
+ * Applies statement-level A2UI component patches without removing temporarily
255
+ * unreachable statements. A later update may attach those statements to root.
256
+ */
257
+ function mergeComponentStatements(existing, components) {
258
+ const statements = /* @__PURE__ */ new Map();
259
+ const order = [];
260
+ const upsert = (source, allowDeletion) => {
261
+ for (const statement of parseStatements(source)) {
262
+ if (allowDeletion && statement.expression === "null") {
263
+ statements.delete(statement.id);
264
+ const index = order.indexOf(statement.id);
265
+ if (index !== -1) order.splice(index, 1);
266
+ continue;
267
+ }
268
+ if (!statements.has(statement.id)) order.push(statement.id);
269
+ statements.set(statement.id, statement.raw);
270
+ }
271
+ };
272
+ if (existing.trim()) upsert(existing, false);
273
+ for (const component of components) upsert(component, true);
274
+ return order.map((id) => statements.get(id)).join("\n");
275
+ }
276
+ //#endregion
277
+ //#region src/client.ts
278
+ var A2UIFunctionError = class extends Error {
279
+ code;
280
+ constructor(code, message) {
281
+ super(message);
282
+ this.name = "A2UIFunctionError";
283
+ this.code = code;
284
+ }
285
+ };
286
+ function defaultId() {
287
+ return globalThis.crypto?.randomUUID?.() ?? `a2ui-${Date.now()}-${Math.random().toString(16).slice(2)}`;
288
+ }
289
+ function parseError(error) {
290
+ return {
291
+ source: "parser",
292
+ code: error.code,
293
+ message: error.message,
294
+ statementId: error.statementId,
295
+ component: error.component,
296
+ path: error.path
297
+ };
298
+ }
299
+ function isCreateSurface(message) {
300
+ return "createSurface" in message;
301
+ }
302
+ function isUpdateComponents(message) {
303
+ return "updateComponents" in message;
304
+ }
305
+ function isUpdateDataModel(message) {
306
+ return "updateDataModel" in message;
307
+ }
308
+ function isDeleteSurface(message) {
309
+ return "deleteSurface" in message;
310
+ }
311
+ function isCallRendererFunction(message) {
312
+ return "callRendererFunction" in message;
313
+ }
314
+ function record(value) {
315
+ return value != null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
316
+ }
317
+ function validationTarget(input) {
318
+ const message = record(input);
319
+ if (!message) return {};
320
+ for (const key of [
321
+ "createSurface",
322
+ "updateComponents",
323
+ "updateDataModel",
324
+ "deleteSurface"
325
+ ]) {
326
+ const payload = record(message[key]);
327
+ if (typeof payload?.surfaceId === "string") return { surfaceId: payload.surfaceId };
328
+ }
329
+ for (const key of ["callRendererFunction", "agentFunctionResponse"]) {
330
+ const payload = record(message[key]);
331
+ if (typeof payload?.functionCallId === "string") return { functionCallId: payload.functionCallId };
332
+ }
333
+ return {};
334
+ }
335
+ var A2UIClient = class {
336
+ #parser;
337
+ #functions;
338
+ #onMessage;
339
+ #rendererCapabilities;
340
+ #now;
341
+ #createId;
342
+ #surfaces = /* @__PURE__ */ new Map();
343
+ #surfaceListeners = /* @__PURE__ */ new Set();
344
+ #messageListeners = /* @__PURE__ */ new Set();
345
+ #pendingAgentFunctions = /* @__PURE__ */ new Map();
346
+ #revision = 0;
347
+ constructor(options) {
348
+ this.#parser = (0, _openuidev_lang_core.createParser)(options.schema, options.rootName);
349
+ this.#functions = options.functions;
350
+ this.#onMessage = options.onMessage;
351
+ this.#rendererCapabilities = options.rendererCapabilities;
352
+ this.#now = options.now ?? (() => /* @__PURE__ */ new Date());
353
+ this.#createId = options.createId ?? defaultId;
354
+ }
355
+ subscribe(listener) {
356
+ this.#surfaceListeners.add(listener);
357
+ return () => this.#surfaceListeners.delete(listener);
358
+ }
359
+ subscribeMessages(listener) {
360
+ this.#messageListeners.add(listener);
361
+ return () => this.#messageListeners.delete(listener);
362
+ }
363
+ getSurface(surfaceId) {
364
+ return this.#surfaces.get(surfaceId);
365
+ }
366
+ getSurfaces() {
367
+ return [...this.#surfaces.values()];
368
+ }
369
+ getRendererDataModel() {
370
+ const surfaces = Object.fromEntries([...this.#surfaces].filter(([, surface]) => surface.sendDataModel).map(([surfaceId, surface]) => [surfaceId, structuredClone(surface.dataModel)]));
371
+ if (Object.keys(surfaces).length === 0) return void 0;
372
+ return {
373
+ version: "v1.0",
374
+ surfaces
375
+ };
376
+ }
377
+ getRendererMetadata() {
378
+ const dataModel = this.getRendererDataModel();
379
+ return {
380
+ ...this.#rendererCapabilities ? { a2uiRendererCapabilities: structuredClone(this.#rendererCapabilities) } : {},
381
+ ...dataModel ? { a2uiRendererDataModel: dataModel } : {}
382
+ };
383
+ }
384
+ async process(input) {
385
+ const outbound = [];
386
+ const capture = (next) => outbound.push(next);
387
+ this.#messageListeners.add(capture);
388
+ try {
389
+ const validated = validateAgentToRendererMessage(input);
390
+ if (!validated.success) return this.#invalidMessage(input, validated.issues, outbound);
391
+ const message = validated.message;
392
+ if (isCreateSurface(message)) return this.#createSurface(message, outbound);
393
+ if (isUpdateComponents(message)) return this.#updateComponents(message, outbound);
394
+ if (isUpdateDataModel(message)) return this.#updateDataModel(message, outbound);
395
+ if (isDeleteSurface(message)) return this.#deleteSurface(message, outbound);
396
+ if (isCallRendererFunction(message)) return await this.#callRendererFunction(message, outbound);
397
+ return this.#agentFunctionResponse(message, outbound);
398
+ } finally {
399
+ this.#messageListeners.delete(capture);
400
+ }
401
+ }
402
+ updateSurfaceFromOpenUIState(surfaceId, state) {
403
+ const surface = this.#surfaces.get(surfaceId);
404
+ if (!surface) return false;
405
+ const dataModel = require_json_pointer.mergeOpenUIStateIntoDataModel(surface.dataModel, state);
406
+ if (JSON.stringify(dataModel) === JSON.stringify(surface.dataModel)) return false;
407
+ this.#replaceSurface({
408
+ ...surface,
409
+ dataModel
410
+ });
411
+ return true;
412
+ }
413
+ dispatchOpenUIAction(surfaceId, event, options = {}) {
414
+ const eventSourceComponentId = event.sourceComponentId;
415
+ const context = {
416
+ ...require_json_pointer.toJsonObject(event.params),
417
+ ...event.formState ? { formState: require_json_pointer.toJsonObject(event.formState) } : {},
418
+ ...options.context
419
+ };
420
+ this.dispatchAction({
421
+ surfaceId,
422
+ sourceComponentId: options.sourceComponentId ?? (typeof eventSourceComponentId === "string" ? eventSourceComponentId : "root"),
423
+ name: options.name ?? event.type,
424
+ userMessage: (options.userMessage ?? event.humanFriendlyMessage) || void 0,
425
+ context,
426
+ metadata: options.metadata
427
+ });
428
+ }
429
+ dispatchAction(input) {
430
+ if (!this.#surfaces.has(input.surfaceId)) {
431
+ this.#emitGenericError("SURFACE_NOT_FOUND", `Unknown surface: ${input.surfaceId}`, input.surfaceId);
432
+ return;
433
+ }
434
+ const message = {
435
+ version: "v1.0",
436
+ action: {
437
+ name: input.name,
438
+ ...input.userMessage ? { userMessage: input.userMessage } : {},
439
+ surfaceId: input.surfaceId,
440
+ sourceComponentId: input.sourceComponentId,
441
+ timestamp: this.#now().toISOString(),
442
+ context: input.context ?? {},
443
+ ...input.metadata ? { metadata: input.metadata } : {}
444
+ }
445
+ };
446
+ this.#emit(message);
447
+ }
448
+ callAgentFunction(input) {
449
+ if (!this.#surfaces.has(input.surfaceId)) {
450
+ const message = `Unknown surface: ${input.surfaceId}`;
451
+ this.#emitGenericError("SURFACE_NOT_FOUND", message, input.surfaceId);
452
+ return Promise.reject(new A2UIFunctionError("SURFACE_NOT_FOUND", message));
453
+ }
454
+ const functionCallId = this.#createId();
455
+ return new Promise((resolve, reject) => {
456
+ this.#pendingAgentFunctions.set(functionCallId, {
457
+ surfaceId: input.surfaceId,
458
+ resolve,
459
+ reject
460
+ });
461
+ this.#emit({
462
+ version: "v1.0",
463
+ callAgentFunction: {
464
+ surfaceId: input.surfaceId,
465
+ functionCallId,
466
+ callFunction: {
467
+ call: input.call,
468
+ ...input.catalogId ? { catalogId: input.catalogId } : {},
469
+ ...input.args ? { args: input.args } : {}
470
+ }
471
+ }
472
+ });
473
+ });
474
+ }
475
+ dispose() {
476
+ for (const pending of this.#pendingAgentFunctions.values()) pending.reject(new A2UIFunctionError("CLIENT_DISPOSED", "A2UI client was disposed"));
477
+ this.#pendingAgentFunctions.clear();
478
+ this.#surfaces.clear();
479
+ this.#surfaceListeners.clear();
480
+ this.#messageListeners.clear();
481
+ }
482
+ #createSurface(message, outbound) {
483
+ const input = message.createSurface;
484
+ if (this.#surfaces.has(input.surfaceId)) {
485
+ this.#emitGenericError("SURFACE_ALREADY_EXISTS", `Surface already exists: ${input.surfaceId}`, input.surfaceId);
486
+ return {
487
+ ok: false,
488
+ outbound
489
+ };
490
+ }
491
+ const supportedCatalogIds = this.#rendererCapabilities?.["v1.0"].supportedCatalogIds ?? [];
492
+ if (input.catalogId && supportedCatalogIds.length > 0 && !supportedCatalogIds.includes(input.catalogId)) {
493
+ this.#emitGenericError("UNSUPPORTED_CATALOG", `Renderer does not support catalog: ${input.catalogId}`, input.surfaceId);
494
+ return {
495
+ ok: false,
496
+ outbound
497
+ };
498
+ }
499
+ let source = "";
500
+ let parseResult = null;
501
+ let errors = [];
502
+ if (input.components) try {
503
+ ({source, parseResult, errors} = this.#mergeComponents("", input.components));
504
+ } catch (error) {
505
+ this.#emitValidationError(input.surfaceId, "/createSurface/components", error instanceof Error ? error.message : String(error));
506
+ return {
507
+ ok: false,
508
+ outbound
509
+ };
510
+ }
511
+ this.#replaceSurface({
512
+ surfaceId: input.surfaceId,
513
+ catalogId: input.catalogId,
514
+ metadata: input.metadata,
515
+ sendDataModel: input.sendDataModel ?? false,
516
+ source,
517
+ dataModel: structuredClone(input.dataModel ?? {}),
518
+ parseResult,
519
+ errors,
520
+ revision: 0
521
+ });
522
+ for (const error of errors) this.#emitValidationError(input.surfaceId, "/createSurface/components", error.statementId ? `${error.statementId}: ${error.message}` : error.message);
523
+ return {
524
+ ok: errors.length === 0,
525
+ outbound
526
+ };
527
+ }
528
+ #updateComponents(message, outbound) {
529
+ const input = message.updateComponents;
530
+ const surface = this.#requireSurface(input.surfaceId);
531
+ if (!surface) return {
532
+ ok: false,
533
+ outbound
534
+ };
535
+ try {
536
+ const { source, parseResult, errors } = this.#mergeComponents(surface.source, input.components);
537
+ this.#replaceSurface({
538
+ ...surface,
539
+ source,
540
+ parseResult,
541
+ errors
542
+ });
543
+ for (const error of errors) this.#emitValidationError(input.surfaceId, "/updateComponents/components", error.statementId ? `${error.statementId}: ${error.message}` : error.message);
544
+ return {
545
+ ok: errors.length === 0,
546
+ outbound
547
+ };
548
+ } catch (error) {
549
+ this.#emitValidationError(input.surfaceId, "/updateComponents/components", error instanceof Error ? error.message : String(error));
550
+ return {
551
+ ok: false,
552
+ outbound
553
+ };
554
+ }
555
+ }
556
+ #updateDataModel(message, outbound) {
557
+ const input = message.updateDataModel;
558
+ const surface = this.#requireSurface(input.surfaceId);
559
+ if (!surface) return {
560
+ ok: false,
561
+ outbound
562
+ };
563
+ try {
564
+ const dataModel = require_json_pointer.applyDataModelUpdate(surface.dataModel, input.path, input.value);
565
+ this.#replaceSurface({
566
+ ...surface,
567
+ dataModel
568
+ });
569
+ return {
570
+ ok: true,
571
+ outbound
572
+ };
573
+ } catch (error) {
574
+ this.#emitValidationError(input.surfaceId, "/updateDataModel/path", error instanceof Error ? error.message : String(error));
575
+ return {
576
+ ok: false,
577
+ outbound
578
+ };
579
+ }
580
+ }
581
+ #deleteSurface(message, outbound) {
582
+ const surfaceId = message.deleteSurface.surfaceId;
583
+ if (!this.#requireSurface(surfaceId)) return {
584
+ ok: false,
585
+ outbound
586
+ };
587
+ this.#surfaces.delete(surfaceId);
588
+ for (const [functionCallId, pending] of this.#pendingAgentFunctions) if (pending.surfaceId === surfaceId) {
589
+ pending.reject(new A2UIFunctionError("SURFACE_DELETED", `Surface was deleted: ${surfaceId}`));
590
+ this.#pendingAgentFunctions.delete(functionCallId);
591
+ }
592
+ this.#notify();
593
+ return {
594
+ ok: true,
595
+ outbound
596
+ };
597
+ }
598
+ async #callRendererFunction(message, outbound) {
599
+ const { functionCallId, callFunction } = message.callRendererFunction;
600
+ const { call, catalogId, args = {} } = callFunction;
601
+ const registration = this.#functions?.[call];
602
+ if (!registration) {
603
+ this.#emitGenericError("INVALID_FUNCTION_CALL", `Renderer function is not registered: ${call}`, void 0, functionCallId);
604
+ return {
605
+ ok: false,
606
+ outbound
607
+ };
608
+ }
609
+ const fn = typeof registration === "function" ? registration : registration.handler;
610
+ if (typeof registration === "function" || (registration.allowedCallers ?? "rendererOnly") === "rendererOnly" || registration.catalogId !== catalogId) {
611
+ this.#emitGenericError("INVALID_FUNCTION_CALL", `Renderer function is not callable from catalog ${catalogId}: ${call}`, void 0, functionCallId);
612
+ return {
613
+ ok: false,
614
+ outbound
615
+ };
616
+ }
617
+ try {
618
+ const value = await fn(args);
619
+ this.#emit({
620
+ version: "v1.0",
621
+ rendererFunctionResponse: {
622
+ functionCallId,
623
+ value
624
+ }
625
+ });
626
+ return {
627
+ ok: true,
628
+ outbound
629
+ };
630
+ } catch (error) {
631
+ this.#emit({
632
+ version: "v1.0",
633
+ rendererFunctionResponse: {
634
+ functionCallId,
635
+ error: {
636
+ code: "EXECUTION_FAILED",
637
+ message: error instanceof Error ? error.message : String(error)
638
+ }
639
+ }
640
+ });
641
+ return {
642
+ ok: false,
643
+ outbound
644
+ };
645
+ }
646
+ }
647
+ #agentFunctionResponse(message, outbound) {
648
+ const response = message.agentFunctionResponse;
649
+ const pending = this.#pendingAgentFunctions.get(response.functionCallId);
650
+ if (!pending) return {
651
+ ok: false,
652
+ outbound,
653
+ issues: [{
654
+ path: "/agentFunctionResponse/functionCallId",
655
+ message: `Unknown functionCallId: ${response.functionCallId}`
656
+ }]
657
+ };
658
+ this.#pendingAgentFunctions.delete(response.functionCallId);
659
+ if ("error" in response) {
660
+ pending.reject(new A2UIFunctionError(response.error.code, response.error.message));
661
+ return {
662
+ ok: true,
663
+ outbound
664
+ };
665
+ }
666
+ pending.resolve(response.value);
667
+ return {
668
+ ok: true,
669
+ outbound
670
+ };
671
+ }
672
+ #replaceSurface(surface) {
673
+ this.#revision += 1;
674
+ this.#surfaces.set(surface.surfaceId, {
675
+ ...surface,
676
+ revision: this.#revision
677
+ });
678
+ this.#notify();
679
+ }
680
+ #mergeComponents(existing, components) {
681
+ const source = mergeComponentStatements(existing, components);
682
+ const parseResult = this.#parser.parse(source);
683
+ return {
684
+ source,
685
+ parseResult,
686
+ errors: parseResult.meta.errors.map(parseError)
687
+ };
688
+ }
689
+ #invalidMessage(input, issues, outbound) {
690
+ const target = validationTarget(input);
691
+ const issue = issues[0] ?? {
692
+ path: "/",
693
+ message: "Invalid A2UI message"
694
+ };
695
+ if (target.surfaceId !== void 0) {
696
+ this.#emitValidationError(target.surfaceId, issue.path, issue.message);
697
+ return {
698
+ ok: false,
699
+ outbound,
700
+ issues
701
+ };
702
+ }
703
+ if (target.functionCallId !== void 0) {
704
+ this.#emitGenericError("INVALID_MESSAGE", `${issue.path}: ${issue.message}`, void 0, target.functionCallId);
705
+ return {
706
+ ok: false,
707
+ outbound,
708
+ issues
709
+ };
710
+ }
711
+ return {
712
+ ok: false,
713
+ outbound,
714
+ issues
715
+ };
716
+ }
717
+ #requireSurface(surfaceId) {
718
+ const surface = this.#surfaces.get(surfaceId);
719
+ if (!surface) this.#emitGenericError("SURFACE_NOT_FOUND", `Unknown surface: ${surfaceId}`, surfaceId);
720
+ return surface;
721
+ }
722
+ #emitValidationError(surfaceId, path, message) {
723
+ const error = {
724
+ version: "v1.0",
725
+ error: {
726
+ code: "VALIDATION_FAILED",
727
+ surfaceId,
728
+ path,
729
+ message
730
+ }
731
+ };
732
+ this.#emit(error);
733
+ }
734
+ #emitGenericError(code, message, surfaceId, functionCallId) {
735
+ if (surfaceId === void 0 && functionCallId === void 0) return;
736
+ const error = surfaceId !== void 0 ? {
737
+ version: "v1.0",
738
+ error: {
739
+ code,
740
+ message,
741
+ surfaceId
742
+ }
743
+ } : {
744
+ version: "v1.0",
745
+ error: {
746
+ code,
747
+ message,
748
+ functionCallId
749
+ }
750
+ };
751
+ this.#emit(error);
752
+ }
753
+ #emit(message) {
754
+ const metadata = this.getRendererMetadata();
755
+ this.#onMessage?.(message, metadata);
756
+ for (const listener of this.#messageListeners) listener(message, metadata);
757
+ }
758
+ #notify() {
759
+ for (const listener of this.#surfaceListeners) listener();
760
+ }
761
+ };
762
+ function createA2UIClient(options) {
763
+ return new A2UIClient(options);
764
+ }
765
+ //#endregion
766
+ exports.A2UIClient = A2UIClient;
767
+ exports.A2UIFunctionError = A2UIFunctionError;
768
+ exports.a2uiFunctionCallSchema = a2uiFunctionCallSchema;
769
+ exports.a2uiFunctionResponseSchema = a2uiFunctionResponseSchema;
770
+ exports.actionMessageSchema = actionMessageSchema;
771
+ exports.agentCapabilitiesSchema = agentCapabilitiesSchema;
772
+ exports.agentFunctionResponseMessageSchema = agentFunctionResponseMessageSchema;
773
+ exports.agentToRendererMessageSchema = agentToRendererMessageSchema;
774
+ exports.applyDataModelUpdate = require_json_pointer.applyDataModelUpdate;
775
+ exports.callAgentFunctionMessageSchema = callAgentFunctionMessageSchema;
776
+ exports.callRendererFunctionMessageSchema = callRendererFunctionMessageSchema;
777
+ exports.createA2UIClient = createA2UIClient;
778
+ exports.createSurfaceMessageSchema = createSurfaceMessageSchema;
779
+ exports.dataModelToOpenUIState = require_json_pointer.dataModelToOpenUIState;
780
+ exports.deleteSurfaceMessageSchema = deleteSurfaceMessageSchema;
781
+ exports.genericErrorMessageSchema = genericErrorMessageSchema;
782
+ exports.jsonObjectSchema = jsonObjectSchema;
783
+ exports.jsonValueSchema = jsonValueSchema;
784
+ exports.mergeOpenUIStateIntoDataModel = require_json_pointer.mergeOpenUIStateIntoDataModel;
785
+ exports.messageMetadataSchema = messageMetadataSchema;
786
+ exports.rendererCapabilitiesSchema = rendererCapabilitiesSchema;
787
+ exports.rendererDataModelSchema = rendererDataModelSchema;
788
+ exports.rendererFunctionResponseMessageSchema = rendererFunctionResponseMessageSchema;
789
+ exports.rendererToAgentMessageSchema = rendererToAgentMessageSchema;
790
+ exports.updateComponentsMessageSchema = updateComponentsMessageSchema;
791
+ exports.updateDataModelMessageSchema = updateDataModelMessageSchema;
792
+ exports.validateAgentToRendererMessage = validateAgentToRendererMessage;
793
+ exports.validationFailedErrorMessageSchema = validationFailedErrorMessageSchema;
794
+
795
+ //# sourceMappingURL=index.cjs.map