@uix-ai/adapter-a2ui 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.
- package/README.md +138 -0
- package/dist/index.d.ts +334 -0
- package/dist/index.js +350 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @uix-ai/adapter-a2ui
|
|
2
|
+
|
|
3
|
+
Adapter to convert [Google A2UI](https://github.com/google/A2UI) protocol payloads to UIX Lucid IR format.
|
|
4
|
+
|
|
5
|
+
> **Experimental.** A2UI is an early-stage protocol and its specification may change. This adapter tracks the latest available version (`v0.10`).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @uix-ai/adapter-a2ui
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Peer dependency: `@uix-ai/core`
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { fromA2UIPayload, toA2UIPayload } from '@uix-ai/adapter-a2ui'
|
|
19
|
+
|
|
20
|
+
// A2UI -> UIX Lucid IR
|
|
21
|
+
const conversation = fromA2UIPayload(a2uiPayload)
|
|
22
|
+
|
|
23
|
+
// UIX Lucid IR -> A2UI
|
|
24
|
+
const payload = toA2UIPayload(conversation)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## `fromA2UIPayload(payload, options?)`
|
|
28
|
+
|
|
29
|
+
Converts an A2UI `updateComponents` payload into a `LucidConversation`. The A2UI component tree is flattened into a linear sequence of `LucidBlock` items. Container components (Row, Column, Card, etc.) are traversed but not emitted as blocks.
|
|
30
|
+
|
|
31
|
+
Returns `null` if the payload does not contain `updateComponents`.
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { fromA2UIPayload } from '@uix-ai/adapter-a2ui'
|
|
35
|
+
import type { A2UIPayload } from '@uix-ai/adapter-a2ui'
|
|
36
|
+
|
|
37
|
+
const payload: A2UIPayload = {
|
|
38
|
+
version: 'v0.10',
|
|
39
|
+
updateComponents: {
|
|
40
|
+
surfaceId: 'form_1',
|
|
41
|
+
components: [
|
|
42
|
+
{ id: 'root', component: 'Column', children: ['title', 'img'] },
|
|
43
|
+
{ id: 'title', component: 'Text', text: 'Hello World' },
|
|
44
|
+
{ id: 'img', component: 'Image', url: 'https://example.com/photo.png' },
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const conversation = fromA2UIPayload(payload)
|
|
50
|
+
// conversation.blocks[0] -> text block "Hello World"
|
|
51
|
+
// conversation.blocks[1] -> image block
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Batch conversion
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { fromA2UIPayloads } from '@uix-ai/adapter-a2ui'
|
|
58
|
+
|
|
59
|
+
const conversations = fromA2UIPayloads(payloadArray)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## `toA2UIPayload(conversation, surfaceId?, version?)`
|
|
63
|
+
|
|
64
|
+
Converts a `LucidConversation` back to an A2UI `updateComponents` payload. All blocks are wrapped in a root `Column` layout.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { toA2UIPayload } from '@uix-ai/adapter-a2ui'
|
|
68
|
+
|
|
69
|
+
const payload = toA2UIPayload(conversation)
|
|
70
|
+
// payload.updateComponents.components -> [Column root, Text, Image, ...]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Supported Component Types
|
|
74
|
+
|
|
75
|
+
### Display Components
|
|
76
|
+
|
|
77
|
+
| A2UI Component | UIX Block Type | Notes |
|
|
78
|
+
|----------------|----------------|-------|
|
|
79
|
+
| `Text` | `text` | Direct mapping |
|
|
80
|
+
| `Image` | `image` | Direct mapping |
|
|
81
|
+
| `Icon` | `text` | Rendered as `[Icon: name]` |
|
|
82
|
+
| `Video` | `text` | Rendered as `[Video: url]` |
|
|
83
|
+
| `AudioPlayer` | `text` | Rendered as `[Audio: url]` |
|
|
84
|
+
|
|
85
|
+
### Container Components (traversed, not emitted)
|
|
86
|
+
|
|
87
|
+
`Row`, `Column`, `Card`, `List`, `Tabs`, `Modal`
|
|
88
|
+
|
|
89
|
+
Containers are walked to collect child components but do not produce blocks themselves. `Tabs` children are emitted with bold tab titles.
|
|
90
|
+
|
|
91
|
+
### Input Components
|
|
92
|
+
|
|
93
|
+
| A2UI Component | UIX Block Type | Notes |
|
|
94
|
+
|----------------|----------------|-------|
|
|
95
|
+
| `TextField` | `text` | `[TextField: label]` |
|
|
96
|
+
| `CheckBox` | `text` | `[CheckBox: label]` |
|
|
97
|
+
| `DateTimeInput` | `text` | `[DateTimeInput: label]` |
|
|
98
|
+
| `ChoicePicker` | `text` | `[ChoicePicker: label] options=[...]` |
|
|
99
|
+
| `Slider` | `text` | `[Slider: label] range=[min, max]` |
|
|
100
|
+
|
|
101
|
+
### Interactive Components
|
|
102
|
+
|
|
103
|
+
| A2UI Component | UIX Block Type | Notes |
|
|
104
|
+
|----------------|----------------|-------|
|
|
105
|
+
| `Button` | `text` | `[Button: label] (action:name)` |
|
|
106
|
+
| `Divider` | `text` | Rendered as `---` |
|
|
107
|
+
|
|
108
|
+
## Conversion Options
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import type { A2UIConversionOptions } from '@uix-ai/adapter-a2ui'
|
|
112
|
+
|
|
113
|
+
const options: A2UIConversionOptions = {
|
|
114
|
+
generateConversationId: (surfaceId) => `my-${surfaceId}`,
|
|
115
|
+
generateBlockId: (componentId) => `blk-${componentId}`,
|
|
116
|
+
resolveValue: (dynamic) => {
|
|
117
|
+
// Resolve data-binding expressions against your data model
|
|
118
|
+
if (typeof dynamic === 'object' && 'path' in dynamic) {
|
|
119
|
+
return lookupPath(dynamic.path)
|
|
120
|
+
}
|
|
121
|
+
return String(dynamic)
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Dynamic Values
|
|
127
|
+
|
|
128
|
+
A2UI supports dynamic data bindings. Without a `resolveValue` function, bindings are rendered as placeholders:
|
|
129
|
+
|
|
130
|
+
- Path binding: `{ path: "user.name" }` renders as `{{user.name}}`
|
|
131
|
+
- Function call: `{ call: "formatDate", args: {...} }` renders as `{{formatDate(...)}}`
|
|
132
|
+
|
|
133
|
+
Provide a `resolveValue` callback to resolve these against your application's data model.
|
|
134
|
+
|
|
135
|
+
## Links
|
|
136
|
+
|
|
137
|
+
- [UIX Repository](https://github.com/Deepractice/UIX)
|
|
138
|
+
- [Google A2UI Protocol](https://github.com/google/A2UI)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { LucidConversation } from '@uix-ai/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @uix-ai/adapter-a2ui
|
|
5
|
+
*
|
|
6
|
+
* Adapter to convert Google A2UI protocol payloads to UIX Lucid IR format.
|
|
7
|
+
*
|
|
8
|
+
* A2UI is a declarative UI protocol where agents generate JSON payloads
|
|
9
|
+
* describing UI components. Unlike AG-UI (event streaming), A2UI is
|
|
10
|
+
* snapshot-based - the agent sends a complete UI description as JSON.
|
|
11
|
+
*
|
|
12
|
+
* This adapter converts A2UI's component tree into UIX LucidConversation
|
|
13
|
+
* and LucidBlock structures for rendering with UIX components.
|
|
14
|
+
*
|
|
15
|
+
* @see https://github.com/google/A2UI
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { fromA2UIPayload, toA2UIPayload } from '@uix-ai/adapter-a2ui'
|
|
20
|
+
*
|
|
21
|
+
* // Convert A2UI payload to UIX Lucid IR
|
|
22
|
+
* const conversation = fromA2UIPayload(a2uiPayload)
|
|
23
|
+
*
|
|
24
|
+
* // Convert UIX Lucid IR back to A2UI payload
|
|
25
|
+
* const payload = toA2UIPayload(conversation)
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A2UI protocol version
|
|
31
|
+
*/
|
|
32
|
+
type A2UIVersion = 'v0.8' | 'v0.9' | 'v0.10';
|
|
33
|
+
/**
|
|
34
|
+
* A2UI display component types
|
|
35
|
+
*/
|
|
36
|
+
type A2UIDisplayComponent = 'Text' | 'Image' | 'Icon' | 'Video' | 'AudioPlayer';
|
|
37
|
+
/**
|
|
38
|
+
* A2UI container component types
|
|
39
|
+
*/
|
|
40
|
+
type A2UIContainerComponent = 'Row' | 'Column' | 'Card' | 'List' | 'Tabs' | 'Modal';
|
|
41
|
+
/**
|
|
42
|
+
* A2UI input component types
|
|
43
|
+
*/
|
|
44
|
+
type A2UIInputComponent = 'TextField' | 'CheckBox' | 'DateTimeInput' | 'ChoicePicker' | 'Slider';
|
|
45
|
+
/**
|
|
46
|
+
* A2UI interactive component types
|
|
47
|
+
*/
|
|
48
|
+
type A2UIInteractiveComponent = 'Button' | 'Divider';
|
|
49
|
+
/**
|
|
50
|
+
* Union of all A2UI component type names
|
|
51
|
+
*/
|
|
52
|
+
type A2UIComponentType = A2UIDisplayComponent | A2UIContainerComponent | A2UIInputComponent | A2UIInteractiveComponent;
|
|
53
|
+
/**
|
|
54
|
+
* A2UI dynamic string - either a literal or a data-binding reference
|
|
55
|
+
*/
|
|
56
|
+
type A2UIDynamicString = string | {
|
|
57
|
+
path: string;
|
|
58
|
+
} | {
|
|
59
|
+
call: string;
|
|
60
|
+
args: Record<string, unknown>;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* A2UI dynamic number
|
|
64
|
+
*/
|
|
65
|
+
type A2UIDynamicNumber = number | {
|
|
66
|
+
path: string;
|
|
67
|
+
} | {
|
|
68
|
+
call: string;
|
|
69
|
+
args: Record<string, unknown>;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* A2UI dynamic boolean
|
|
73
|
+
*/
|
|
74
|
+
type A2UIDynamicBoolean = boolean | {
|
|
75
|
+
path: string;
|
|
76
|
+
} | {
|
|
77
|
+
call: string;
|
|
78
|
+
args: Record<string, unknown>;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* A2UI child list - either an array of IDs or a template binding
|
|
82
|
+
*/
|
|
83
|
+
type A2UIChildList = string[] | {
|
|
84
|
+
path: string;
|
|
85
|
+
componentId: string;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* A2UI validation check
|
|
89
|
+
*/
|
|
90
|
+
interface A2UICheck {
|
|
91
|
+
call: string;
|
|
92
|
+
args: Record<string, unknown>;
|
|
93
|
+
message: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A2UI event action
|
|
97
|
+
*/
|
|
98
|
+
interface A2UIEventAction {
|
|
99
|
+
name: string;
|
|
100
|
+
context?: Record<string, unknown>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A2UI function call action
|
|
104
|
+
*/
|
|
105
|
+
interface A2UIFunctionCallAction {
|
|
106
|
+
name: string;
|
|
107
|
+
args?: Record<string, unknown>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* A2UI action - either an event or a function call
|
|
111
|
+
*/
|
|
112
|
+
interface A2UIAction {
|
|
113
|
+
event?: A2UIEventAction;
|
|
114
|
+
functionCall?: A2UIFunctionCallAction;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* A2UI component object in the flat adjacency list
|
|
118
|
+
*
|
|
119
|
+
* Components are stored as a flat array and reference each other by ID.
|
|
120
|
+
* The tree structure is built via `children` and `child` properties.
|
|
121
|
+
*/
|
|
122
|
+
interface A2UIComponent {
|
|
123
|
+
/** Unique identifier for this component */
|
|
124
|
+
id: string;
|
|
125
|
+
/** Component type name */
|
|
126
|
+
component: A2UIComponentType | string;
|
|
127
|
+
/** Child component IDs (for container components like Row, Column, List) */
|
|
128
|
+
children?: A2UIChildList;
|
|
129
|
+
/** Single child component ID (for Card, Modal) */
|
|
130
|
+
child?: string;
|
|
131
|
+
/** Text content (for Text, Button) */
|
|
132
|
+
text?: A2UIDynamicString;
|
|
133
|
+
/** Label (for input components) */
|
|
134
|
+
label?: A2UIDynamicString;
|
|
135
|
+
/** URL (for Image, Video, AudioPlayer) */
|
|
136
|
+
url?: A2UIDynamicString;
|
|
137
|
+
/** Icon name (for Icon) */
|
|
138
|
+
name?: A2UIDynamicString;
|
|
139
|
+
/** Value binding (for input components) */
|
|
140
|
+
value?: A2UIDynamicString | A2UIDynamicNumber | A2UIDynamicBoolean;
|
|
141
|
+
/** Action on interaction (for Button) */
|
|
142
|
+
action?: A2UIAction;
|
|
143
|
+
/** Validation checks (for TextField, Button) */
|
|
144
|
+
checks?: A2UICheck[];
|
|
145
|
+
/** Button variant */
|
|
146
|
+
variant?: string;
|
|
147
|
+
/** Layout alignment */
|
|
148
|
+
justify?: string;
|
|
149
|
+
/** Layout cross-axis alignment */
|
|
150
|
+
align?: string;
|
|
151
|
+
/** Axis for Divider */
|
|
152
|
+
axis?: string;
|
|
153
|
+
/** Tabs configuration */
|
|
154
|
+
tabs?: Array<{
|
|
155
|
+
title: A2UIDynamicString;
|
|
156
|
+
child: string;
|
|
157
|
+
}>;
|
|
158
|
+
/** Slider min value */
|
|
159
|
+
min?: number;
|
|
160
|
+
/** Slider max value */
|
|
161
|
+
max?: number;
|
|
162
|
+
/** Choice picker options */
|
|
163
|
+
options?: Array<{
|
|
164
|
+
label: A2UIDynamicString;
|
|
165
|
+
value: string;
|
|
166
|
+
}>;
|
|
167
|
+
/** Any additional properties from custom or extended components */
|
|
168
|
+
[key: string]: unknown;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* A2UI surface theme configuration
|
|
172
|
+
*/
|
|
173
|
+
interface A2UITheme {
|
|
174
|
+
primaryColor?: string;
|
|
175
|
+
[key: string]: unknown;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* createSurface message - initializes a new UI surface
|
|
179
|
+
*/
|
|
180
|
+
interface A2UICreateSurface {
|
|
181
|
+
surfaceId: string;
|
|
182
|
+
catalogId?: string;
|
|
183
|
+
theme?: A2UITheme;
|
|
184
|
+
sendDataModel?: boolean;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* updateComponents message - adds or updates UI components
|
|
188
|
+
*/
|
|
189
|
+
interface A2UIUpdateComponents {
|
|
190
|
+
surfaceId: string;
|
|
191
|
+
components: A2UIComponent[];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* updateDataModel message - modifies data model via JSON pointer
|
|
195
|
+
*/
|
|
196
|
+
interface A2UIUpdateDataModel {
|
|
197
|
+
surfaceId: string;
|
|
198
|
+
path?: string;
|
|
199
|
+
value?: unknown;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* deleteSurface message - removes a surface
|
|
203
|
+
*/
|
|
204
|
+
interface A2UIDeleteSurface {
|
|
205
|
+
surfaceId: string;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Top-level A2UI message payload.
|
|
209
|
+
*
|
|
210
|
+
* Each message contains exactly one of the four message types:
|
|
211
|
+
* - `createSurface`: Initialize a new UI surface
|
|
212
|
+
* - `updateComponents`: Add or update components on a surface
|
|
213
|
+
* - `updateDataModel`: Modify the surface data model
|
|
214
|
+
* - `deleteSurface`: Remove a surface
|
|
215
|
+
*/
|
|
216
|
+
interface A2UIPayload {
|
|
217
|
+
/** A2UI protocol version */
|
|
218
|
+
version: string;
|
|
219
|
+
/** Create a new surface */
|
|
220
|
+
createSurface?: A2UICreateSurface;
|
|
221
|
+
/** Update components on a surface */
|
|
222
|
+
updateComponents?: A2UIUpdateComponents;
|
|
223
|
+
/** Update the data model */
|
|
224
|
+
updateDataModel?: A2UIUpdateDataModel;
|
|
225
|
+
/** Delete a surface */
|
|
226
|
+
deleteSurface?: A2UIDeleteSurface;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Options for A2UI to Lucid IR conversion
|
|
230
|
+
*/
|
|
231
|
+
interface A2UIConversionOptions {
|
|
232
|
+
/**
|
|
233
|
+
* Custom ID generator for conversations
|
|
234
|
+
* @default () => `a2ui-conv-${surfaceId}`
|
|
235
|
+
*/
|
|
236
|
+
generateConversationId?: (surfaceId: string) => string;
|
|
237
|
+
/**
|
|
238
|
+
* Custom ID generator for blocks
|
|
239
|
+
* @default () => `a2ui-block-${componentId}`
|
|
240
|
+
*/
|
|
241
|
+
generateBlockId?: (componentId: string) => string;
|
|
242
|
+
/**
|
|
243
|
+
* Resolve dynamic string values against a data model.
|
|
244
|
+
* If not provided, dynamic bindings are serialized as-is.
|
|
245
|
+
*/
|
|
246
|
+
resolveValue?: (dynamic: A2UIDynamicString | A2UIDynamicNumber | A2UIDynamicBoolean) => string;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Convert an A2UI payload (containing updateComponents) to a UIX LucidConversation.
|
|
250
|
+
*
|
|
251
|
+
* The A2UI component tree is flattened into a linear sequence of LucidBlocks:
|
|
252
|
+
* - `Text` components become text blocks
|
|
253
|
+
* - `Image` components become image blocks
|
|
254
|
+
* - Input and interactive components become text blocks with structured descriptions
|
|
255
|
+
* - Container components (Row, Column, Card, etc.) are traversed but not emitted
|
|
256
|
+
*
|
|
257
|
+
* @param payload - An A2UI payload message (must contain updateComponents)
|
|
258
|
+
* @param options - Conversion options
|
|
259
|
+
* @returns A LucidConversation representing the A2UI surface, or null if the payload
|
|
260
|
+
* does not contain updateComponents
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```typescript
|
|
264
|
+
* const payload: A2UIPayload = {
|
|
265
|
+
* version: 'v0.10',
|
|
266
|
+
* updateComponents: {
|
|
267
|
+
* surfaceId: 'form_1',
|
|
268
|
+
* components: [
|
|
269
|
+
* { id: 'root', component: 'Column', children: ['title', 'img'] },
|
|
270
|
+
* { id: 'title', component: 'Text', text: 'Hello World' },
|
|
271
|
+
* { id: 'img', component: 'Image', url: 'https://example.com/photo.png' }
|
|
272
|
+
* ]
|
|
273
|
+
* }
|
|
274
|
+
* }
|
|
275
|
+
*
|
|
276
|
+
* const conversation = fromA2UIPayload(payload)
|
|
277
|
+
* // conversation.blocks[0] -> text block "Hello World"
|
|
278
|
+
* // conversation.blocks[1] -> image block
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
declare function fromA2UIPayload(payload: A2UIPayload, options?: A2UIConversionOptions): LucidConversation | null;
|
|
282
|
+
/**
|
|
283
|
+
* Convert multiple A2UI payloads (a stream of messages) to LucidConversations.
|
|
284
|
+
*
|
|
285
|
+
* Processes an array of A2UI messages and returns one LucidConversation per
|
|
286
|
+
* updateComponents message encountered.
|
|
287
|
+
*
|
|
288
|
+
* @param payloads - Array of A2UI payload messages
|
|
289
|
+
* @param options - Conversion options
|
|
290
|
+
* @returns Array of LucidConversations
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```typescript
|
|
294
|
+
* const messages: A2UIPayload[] = [
|
|
295
|
+
* { version: 'v0.10', createSurface: { surfaceId: 's1', catalogId: '...' } },
|
|
296
|
+
* { version: 'v0.10', updateComponents: { surfaceId: 's1', components: [...] } },
|
|
297
|
+
* ]
|
|
298
|
+
*
|
|
299
|
+
* const conversations = fromA2UIPayloads(messages)
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
declare function fromA2UIPayloads(payloads: A2UIPayload[], options?: A2UIConversionOptions): LucidConversation[];
|
|
303
|
+
/**
|
|
304
|
+
* Convert a UIX LucidConversation back to an A2UI payload.
|
|
305
|
+
*
|
|
306
|
+
* Maps LucidBlocks back to A2UI components wrapped in a Column layout:
|
|
307
|
+
* - text blocks -> Text components
|
|
308
|
+
* - image blocks -> Image components
|
|
309
|
+
* - Other block types -> Text components with type annotation
|
|
310
|
+
*
|
|
311
|
+
* @param conversation - A UIX LucidConversation
|
|
312
|
+
* @param surfaceId - Optional surface ID (defaults to conversation.id)
|
|
313
|
+
* @param version - A2UI protocol version (defaults to 'v0.10')
|
|
314
|
+
* @returns An A2UI payload with updateComponents
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* ```typescript
|
|
318
|
+
* const conversation: LucidConversation = {
|
|
319
|
+
* id: 'conv-1',
|
|
320
|
+
* role: 'assistant',
|
|
321
|
+
* status: 'completed',
|
|
322
|
+
* blocks: [
|
|
323
|
+
* { id: 'b1', type: 'text', status: 'completed', content: { text: 'Hello' } },
|
|
324
|
+
* { id: 'b2', type: 'image', status: 'completed', content: { url: 'https://...' } }
|
|
325
|
+
* ],
|
|
326
|
+
* timestamp: Date.now()
|
|
327
|
+
* }
|
|
328
|
+
*
|
|
329
|
+
* const payload = toA2UIPayload(conversation)
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
332
|
+
declare function toA2UIPayload(conversation: LucidConversation, surfaceId?: string, version?: string): A2UIPayload;
|
|
333
|
+
|
|
334
|
+
export { type A2UIAction, type A2UICheck, type A2UIChildList, type A2UIComponent, type A2UIComponentType, type A2UIContainerComponent, type A2UIConversionOptions, type A2UICreateSurface, type A2UIDeleteSurface, type A2UIDisplayComponent, type A2UIDynamicBoolean, type A2UIDynamicNumber, type A2UIDynamicString, type A2UIEventAction, type A2UIFunctionCallAction, type A2UIInputComponent, type A2UIInteractiveComponent, type A2UIPayload, type A2UITheme, type A2UIUpdateComponents, type A2UIUpdateDataModel, type A2UIVersion, fromA2UIPayload, fromA2UIPayloads, toA2UIPayload };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var blockIdCounter = 0;
|
|
3
|
+
function defaultConversationId(surfaceId) {
|
|
4
|
+
return `a2ui-conv-${surfaceId}`;
|
|
5
|
+
}
|
|
6
|
+
function defaultBlockId(componentId) {
|
|
7
|
+
return `a2ui-block-${componentId}-${++blockIdCounter}`;
|
|
8
|
+
}
|
|
9
|
+
function resolveDynamic(value, resolver) {
|
|
10
|
+
if (value === void 0 || value === null) return "";
|
|
11
|
+
if (typeof value === "string") return value;
|
|
12
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
13
|
+
if (resolver) return resolver(value);
|
|
14
|
+
if ("path" in value) return `{{${value.path}}}`;
|
|
15
|
+
if ("call" in value) return `{{${value.call}(...)}}`;
|
|
16
|
+
return JSON.stringify(value);
|
|
17
|
+
}
|
|
18
|
+
function buildComponentMap(components) {
|
|
19
|
+
const map = /* @__PURE__ */ new Map();
|
|
20
|
+
for (const comp of components) {
|
|
21
|
+
map.set(comp.id, comp);
|
|
22
|
+
}
|
|
23
|
+
return map;
|
|
24
|
+
}
|
|
25
|
+
function findRoot(components) {
|
|
26
|
+
return components.find((c) => c.id === "root");
|
|
27
|
+
}
|
|
28
|
+
function getChildIds(component) {
|
|
29
|
+
if (component.child) return [component.child];
|
|
30
|
+
if (Array.isArray(component.children)) return component.children;
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
function componentToBlock(component, options = {}) {
|
|
34
|
+
const genBlockId = options.generateBlockId ?? defaultBlockId;
|
|
35
|
+
const blockId = genBlockId(component.id);
|
|
36
|
+
const resolve = (v) => resolveDynamic(v, options.resolveValue);
|
|
37
|
+
switch (component.component) {
|
|
38
|
+
case "Text":
|
|
39
|
+
return {
|
|
40
|
+
id: blockId,
|
|
41
|
+
type: "text",
|
|
42
|
+
status: "completed",
|
|
43
|
+
content: {
|
|
44
|
+
text: resolve(component.text)
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
case "Image":
|
|
48
|
+
return {
|
|
49
|
+
id: blockId,
|
|
50
|
+
type: "image",
|
|
51
|
+
status: "completed",
|
|
52
|
+
content: {
|
|
53
|
+
url: resolve(component.url),
|
|
54
|
+
alt: component.id
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
case "Button": {
|
|
58
|
+
const label = resolve(component.text) || component.id;
|
|
59
|
+
const actionDesc = component.action?.event ? `action:${component.action.event.name}` : component.action?.functionCall ? `call:${component.action.functionCall.name}` : "";
|
|
60
|
+
return {
|
|
61
|
+
id: blockId,
|
|
62
|
+
type: "text",
|
|
63
|
+
status: "completed",
|
|
64
|
+
content: {
|
|
65
|
+
text: `[Button: ${label}]${actionDesc ? ` (${actionDesc})` : ""}`
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
case "TextField": {
|
|
70
|
+
const label = resolve(component.label) || component.id;
|
|
71
|
+
const val = resolve(component.value);
|
|
72
|
+
return {
|
|
73
|
+
id: blockId,
|
|
74
|
+
type: "text",
|
|
75
|
+
status: "completed",
|
|
76
|
+
content: {
|
|
77
|
+
text: `[TextField: ${label}]${val ? ` value="${val}"` : ""}`
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
case "CheckBox": {
|
|
82
|
+
const label = resolve(component.label) || component.id;
|
|
83
|
+
return {
|
|
84
|
+
id: blockId,
|
|
85
|
+
type: "text",
|
|
86
|
+
status: "completed",
|
|
87
|
+
content: {
|
|
88
|
+
text: `[CheckBox: ${label}]`
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
case "DateTimeInput": {
|
|
93
|
+
const label = resolve(component.label) || component.id;
|
|
94
|
+
return {
|
|
95
|
+
id: blockId,
|
|
96
|
+
type: "text",
|
|
97
|
+
status: "completed",
|
|
98
|
+
content: {
|
|
99
|
+
text: `[DateTimeInput: ${label}]`
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
case "ChoicePicker": {
|
|
104
|
+
const label = resolve(component.label) || component.id;
|
|
105
|
+
const optionLabels = component.options ? component.options.map((o) => resolve(o.label)).join(", ") : "";
|
|
106
|
+
return {
|
|
107
|
+
id: blockId,
|
|
108
|
+
type: "text",
|
|
109
|
+
status: "completed",
|
|
110
|
+
content: {
|
|
111
|
+
text: `[ChoicePicker: ${label}]${optionLabels ? ` options=[${optionLabels}]` : ""}`
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
case "Slider": {
|
|
116
|
+
const label = resolve(component.label) || component.id;
|
|
117
|
+
const min = component.min ?? 0;
|
|
118
|
+
const max = component.max ?? 100;
|
|
119
|
+
return {
|
|
120
|
+
id: blockId,
|
|
121
|
+
type: "text",
|
|
122
|
+
status: "completed",
|
|
123
|
+
content: {
|
|
124
|
+
text: `[Slider: ${label}] range=[${min}, ${max}]`
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
case "Video":
|
|
129
|
+
return {
|
|
130
|
+
id: blockId,
|
|
131
|
+
type: "text",
|
|
132
|
+
status: "completed",
|
|
133
|
+
content: {
|
|
134
|
+
text: `[Video: ${resolve(component.url)}]`
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
case "AudioPlayer":
|
|
138
|
+
return {
|
|
139
|
+
id: blockId,
|
|
140
|
+
type: "text",
|
|
141
|
+
status: "completed",
|
|
142
|
+
content: {
|
|
143
|
+
text: `[Audio: ${resolve(component.url)}]`
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
case "Icon":
|
|
147
|
+
return {
|
|
148
|
+
id: blockId,
|
|
149
|
+
type: "text",
|
|
150
|
+
status: "completed",
|
|
151
|
+
content: {
|
|
152
|
+
text: `[Icon: ${resolve(component.name)}]`
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
case "Divider":
|
|
156
|
+
return {
|
|
157
|
+
id: blockId,
|
|
158
|
+
type: "text",
|
|
159
|
+
status: "completed",
|
|
160
|
+
content: {
|
|
161
|
+
text: "---"
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
// Container components (Row, Column, Card, List, Tabs, Modal)
|
|
165
|
+
// are flattened - their children are emitted as separate blocks.
|
|
166
|
+
// A container itself does not produce a block.
|
|
167
|
+
// This default handles any unknown/custom component types.
|
|
168
|
+
default:
|
|
169
|
+
return {
|
|
170
|
+
id: blockId,
|
|
171
|
+
type: "text",
|
|
172
|
+
status: "completed",
|
|
173
|
+
content: {
|
|
174
|
+
text: `[${component.component}: ${component.id}]`
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
var CONTAINER_TYPES = /* @__PURE__ */ new Set(["Row", "Column", "Card", "List", "Tabs", "Modal"]);
|
|
180
|
+
function flattenComponents(rootId, componentMap, options = {}, visited = /* @__PURE__ */ new Set()) {
|
|
181
|
+
if (visited.has(rootId)) return [];
|
|
182
|
+
visited.add(rootId);
|
|
183
|
+
const component = componentMap.get(rootId);
|
|
184
|
+
if (!component) return [];
|
|
185
|
+
const isContainer = CONTAINER_TYPES.has(component.component);
|
|
186
|
+
const childIds = getChildIds(component);
|
|
187
|
+
if (component.component === "Tabs" && component.tabs) {
|
|
188
|
+
const blocks2 = [];
|
|
189
|
+
for (const tab of component.tabs) {
|
|
190
|
+
const title = resolveDynamic(tab.title, options.resolveValue);
|
|
191
|
+
const genBlockId = options.generateBlockId ?? defaultBlockId;
|
|
192
|
+
blocks2.push({
|
|
193
|
+
id: genBlockId(`${component.id}-tab-${tab.child}`),
|
|
194
|
+
type: "text",
|
|
195
|
+
status: "completed",
|
|
196
|
+
content: { text: `**${title}**` }
|
|
197
|
+
});
|
|
198
|
+
blocks2.push(...flattenComponents(tab.child, componentMap, options, visited));
|
|
199
|
+
}
|
|
200
|
+
return blocks2;
|
|
201
|
+
}
|
|
202
|
+
if (isContainer) {
|
|
203
|
+
const blocks2 = [];
|
|
204
|
+
for (const childId of childIds) {
|
|
205
|
+
blocks2.push(...flattenComponents(childId, componentMap, options, visited));
|
|
206
|
+
}
|
|
207
|
+
return blocks2;
|
|
208
|
+
}
|
|
209
|
+
const blocks = [componentToBlock(component, options)];
|
|
210
|
+
for (const childId of childIds) {
|
|
211
|
+
blocks.push(...flattenComponents(childId, componentMap, options, visited));
|
|
212
|
+
}
|
|
213
|
+
return blocks;
|
|
214
|
+
}
|
|
215
|
+
function fromA2UIPayload(payload, options = {}) {
|
|
216
|
+
const update = payload.updateComponents;
|
|
217
|
+
if (!update) return null;
|
|
218
|
+
const { surfaceId, components } = update;
|
|
219
|
+
const genConvId = options.generateConversationId ?? defaultConversationId;
|
|
220
|
+
const componentMap = buildComponentMap(components);
|
|
221
|
+
const root = findRoot(components);
|
|
222
|
+
let blocks;
|
|
223
|
+
if (root) {
|
|
224
|
+
blocks = flattenComponents(root.id, componentMap, options);
|
|
225
|
+
} else {
|
|
226
|
+
blocks = components.filter((c) => !CONTAINER_TYPES.has(c.component)).map((c) => componentToBlock(c, options));
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
id: genConvId(surfaceId),
|
|
230
|
+
role: "assistant",
|
|
231
|
+
status: "completed",
|
|
232
|
+
blocks,
|
|
233
|
+
timestamp: Date.now()
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function fromA2UIPayloads(payloads, options = {}) {
|
|
237
|
+
const results = [];
|
|
238
|
+
for (const payload of payloads) {
|
|
239
|
+
const conv = fromA2UIPayload(payload, options);
|
|
240
|
+
if (conv) results.push(conv);
|
|
241
|
+
}
|
|
242
|
+
return results;
|
|
243
|
+
}
|
|
244
|
+
function toA2UIPayload(conversation, surfaceId, version = "v0.10") {
|
|
245
|
+
const sid = surfaceId ?? conversation.id;
|
|
246
|
+
const components = [];
|
|
247
|
+
const childIds = [];
|
|
248
|
+
for (const block of conversation.blocks) {
|
|
249
|
+
const compId = `comp-${block.id}`;
|
|
250
|
+
childIds.push(compId);
|
|
251
|
+
switch (block.type) {
|
|
252
|
+
case "text": {
|
|
253
|
+
const content = block.content;
|
|
254
|
+
components.push({
|
|
255
|
+
id: compId,
|
|
256
|
+
component: "Text",
|
|
257
|
+
text: content.text
|
|
258
|
+
});
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
case "image": {
|
|
262
|
+
const content = block.content;
|
|
263
|
+
components.push({
|
|
264
|
+
id: compId,
|
|
265
|
+
component: "Image",
|
|
266
|
+
url: content.url
|
|
267
|
+
});
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
case "thinking": {
|
|
271
|
+
const content = block.content;
|
|
272
|
+
components.push({
|
|
273
|
+
id: compId,
|
|
274
|
+
component: "Text",
|
|
275
|
+
text: `*Thinking: ${content.reasoning}*`
|
|
276
|
+
});
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
case "tool": {
|
|
280
|
+
const content = block.content;
|
|
281
|
+
const parts = [`**Tool: ${content.name}**`];
|
|
282
|
+
if (content.input) parts.push(`Input: \`${JSON.stringify(content.input)}\``);
|
|
283
|
+
if (content.output) parts.push(`Output: \`${JSON.stringify(content.output)}\``);
|
|
284
|
+
parts.push(`Status: ${content.status}`);
|
|
285
|
+
components.push({
|
|
286
|
+
id: compId,
|
|
287
|
+
component: "Text",
|
|
288
|
+
text: parts.join("\n\n")
|
|
289
|
+
});
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case "error": {
|
|
293
|
+
const content = block.content;
|
|
294
|
+
components.push({
|
|
295
|
+
id: compId,
|
|
296
|
+
component: "Text",
|
|
297
|
+
text: `**Error [${content.code}]:** ${content.message}`
|
|
298
|
+
});
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case "file": {
|
|
302
|
+
const content = block.content;
|
|
303
|
+
components.push({
|
|
304
|
+
id: compId,
|
|
305
|
+
component: "Text",
|
|
306
|
+
text: `[File: ${content.name}](${content.url})`
|
|
307
|
+
});
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
case "source": {
|
|
311
|
+
const content = block.content;
|
|
312
|
+
const text = content.url ? `[Source: ${content.title}](${content.url})` : `Source: ${content.title}`;
|
|
313
|
+
components.push({
|
|
314
|
+
id: compId,
|
|
315
|
+
component: "Text",
|
|
316
|
+
text: content.excerpt ? `${text}
|
|
317
|
+
|
|
318
|
+
> ${content.excerpt}` : text
|
|
319
|
+
});
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
default: {
|
|
323
|
+
components.push({
|
|
324
|
+
id: compId,
|
|
325
|
+
component: "Text",
|
|
326
|
+
text: `[${block.type}: ${block.id}]`
|
|
327
|
+
});
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
components.unshift({
|
|
333
|
+
id: "root",
|
|
334
|
+
component: "Column",
|
|
335
|
+
children: childIds
|
|
336
|
+
});
|
|
337
|
+
return {
|
|
338
|
+
version,
|
|
339
|
+
updateComponents: {
|
|
340
|
+
surfaceId: sid,
|
|
341
|
+
components
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
export {
|
|
346
|
+
fromA2UIPayload,
|
|
347
|
+
fromA2UIPayloads,
|
|
348
|
+
toA2UIPayload
|
|
349
|
+
};
|
|
350
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @uix-ai/adapter-a2ui\n *\n * Adapter to convert Google A2UI protocol payloads to UIX Lucid IR format.\n *\n * A2UI is a declarative UI protocol where agents generate JSON payloads\n * describing UI components. Unlike AG-UI (event streaming), A2UI is\n * snapshot-based - the agent sends a complete UI description as JSON.\n *\n * This adapter converts A2UI's component tree into UIX LucidConversation\n * and LucidBlock structures for rendering with UIX components.\n *\n * @see https://github.com/google/A2UI\n *\n * @example\n * ```typescript\n * import { fromA2UIPayload, toA2UIPayload } from '@uix-ai/adapter-a2ui'\n *\n * // Convert A2UI payload to UIX Lucid IR\n * const conversation = fromA2UIPayload(a2uiPayload)\n *\n * // Convert UIX Lucid IR back to A2UI payload\n * const payload = toA2UIPayload(conversation)\n * ```\n */\n\nimport type {\n LucidConversation,\n LucidBlock,\n ContentStatus,\n BlockType,\n TextBlockContent,\n ImageBlockContent,\n ErrorBlockContent,\n} from '@uix-ai/core'\n\n// ============================================================================\n// A2UI Protocol Types\n// ============================================================================\n\n/**\n * A2UI protocol version\n */\nexport type A2UIVersion = 'v0.8' | 'v0.9' | 'v0.10'\n\n/**\n * A2UI display component types\n */\nexport type A2UIDisplayComponent = 'Text' | 'Image' | 'Icon' | 'Video' | 'AudioPlayer'\n\n/**\n * A2UI container component types\n */\nexport type A2UIContainerComponent = 'Row' | 'Column' | 'Card' | 'List' | 'Tabs' | 'Modal'\n\n/**\n * A2UI input component types\n */\nexport type A2UIInputComponent = 'TextField' | 'CheckBox' | 'DateTimeInput' | 'ChoicePicker' | 'Slider'\n\n/**\n * A2UI interactive component types\n */\nexport type A2UIInteractiveComponent = 'Button' | 'Divider'\n\n/**\n * Union of all A2UI component type names\n */\nexport type A2UIComponentType =\n | A2UIDisplayComponent\n | A2UIContainerComponent\n | A2UIInputComponent\n | A2UIInteractiveComponent\n\n// ============================================================================\n// A2UI Dynamic Value Types\n// ============================================================================\n\n/**\n * A2UI dynamic string - either a literal or a data-binding reference\n */\nexport type A2UIDynamicString = string | { path: string } | { call: string; args: Record<string, unknown> }\n\n/**\n * A2UI dynamic number\n */\nexport type A2UIDynamicNumber = number | { path: string } | { call: string; args: Record<string, unknown> }\n\n/**\n * A2UI dynamic boolean\n */\nexport type A2UIDynamicBoolean = boolean | { path: string } | { call: string; args: Record<string, unknown> }\n\n/**\n * A2UI child list - either an array of IDs or a template binding\n */\nexport type A2UIChildList = string[] | { path: string; componentId: string }\n\n// ============================================================================\n// A2UI Validation & Actions\n// ============================================================================\n\n/**\n * A2UI validation check\n */\nexport interface A2UICheck {\n call: string\n args: Record<string, unknown>\n message: string\n}\n\n/**\n * A2UI event action\n */\nexport interface A2UIEventAction {\n name: string\n context?: Record<string, unknown>\n}\n\n/**\n * A2UI function call action\n */\nexport interface A2UIFunctionCallAction {\n name: string\n args?: Record<string, unknown>\n}\n\n/**\n * A2UI action - either an event or a function call\n */\nexport interface A2UIAction {\n event?: A2UIEventAction\n functionCall?: A2UIFunctionCallAction\n}\n\n// ============================================================================\n// A2UI Component Definition\n// ============================================================================\n\n/**\n * A2UI component object in the flat adjacency list\n *\n * Components are stored as a flat array and reference each other by ID.\n * The tree structure is built via `children` and `child` properties.\n */\nexport interface A2UIComponent {\n /** Unique identifier for this component */\n id: string\n /** Component type name */\n component: A2UIComponentType | string\n /** Child component IDs (for container components like Row, Column, List) */\n children?: A2UIChildList\n /** Single child component ID (for Card, Modal) */\n child?: string\n /** Text content (for Text, Button) */\n text?: A2UIDynamicString\n /** Label (for input components) */\n label?: A2UIDynamicString\n /** URL (for Image, Video, AudioPlayer) */\n url?: A2UIDynamicString\n /** Icon name (for Icon) */\n name?: A2UIDynamicString\n /** Value binding (for input components) */\n value?: A2UIDynamicString | A2UIDynamicNumber | A2UIDynamicBoolean\n /** Action on interaction (for Button) */\n action?: A2UIAction\n /** Validation checks (for TextField, Button) */\n checks?: A2UICheck[]\n /** Button variant */\n variant?: string\n /** Layout alignment */\n justify?: string\n /** Layout cross-axis alignment */\n align?: string\n /** Axis for Divider */\n axis?: string\n /** Tabs configuration */\n tabs?: Array<{ title: A2UIDynamicString; child: string }>\n /** Slider min value */\n min?: number\n /** Slider max value */\n max?: number\n /** Choice picker options */\n options?: Array<{ label: A2UIDynamicString; value: string }>\n /** Any additional properties from custom or extended components */\n [key: string]: unknown\n}\n\n// ============================================================================\n// A2UI Theme\n// ============================================================================\n\n/**\n * A2UI surface theme configuration\n */\nexport interface A2UITheme {\n primaryColor?: string\n [key: string]: unknown\n}\n\n// ============================================================================\n// A2UI Message Types\n// ============================================================================\n\n/**\n * createSurface message - initializes a new UI surface\n */\nexport interface A2UICreateSurface {\n surfaceId: string\n catalogId?: string\n theme?: A2UITheme\n sendDataModel?: boolean\n}\n\n/**\n * updateComponents message - adds or updates UI components\n */\nexport interface A2UIUpdateComponents {\n surfaceId: string\n components: A2UIComponent[]\n}\n\n/**\n * updateDataModel message - modifies data model via JSON pointer\n */\nexport interface A2UIUpdateDataModel {\n surfaceId: string\n path?: string\n value?: unknown\n}\n\n/**\n * deleteSurface message - removes a surface\n */\nexport interface A2UIDeleteSurface {\n surfaceId: string\n}\n\n// ============================================================================\n// A2UI Payload (Top-Level Message)\n// ============================================================================\n\n/**\n * Top-level A2UI message payload.\n *\n * Each message contains exactly one of the four message types:\n * - `createSurface`: Initialize a new UI surface\n * - `updateComponents`: Add or update components on a surface\n * - `updateDataModel`: Modify the surface data model\n * - `deleteSurface`: Remove a surface\n */\nexport interface A2UIPayload {\n /** A2UI protocol version */\n version: string\n /** Create a new surface */\n createSurface?: A2UICreateSurface\n /** Update components on a surface */\n updateComponents?: A2UIUpdateComponents\n /** Update the data model */\n updateDataModel?: A2UIUpdateDataModel\n /** Delete a surface */\n deleteSurface?: A2UIDeleteSurface\n}\n\n// ============================================================================\n// Conversion Options\n// ============================================================================\n\n/**\n * Options for A2UI to Lucid IR conversion\n */\nexport interface A2UIConversionOptions {\n /**\n * Custom ID generator for conversations\n * @default () => `a2ui-conv-${surfaceId}`\n */\n generateConversationId?: (surfaceId: string) => string\n\n /**\n * Custom ID generator for blocks\n * @default () => `a2ui-block-${componentId}`\n */\n generateBlockId?: (componentId: string) => string\n\n /**\n * Resolve dynamic string values against a data model.\n * If not provided, dynamic bindings are serialized as-is.\n */\n resolveValue?: (dynamic: A2UIDynamicString | A2UIDynamicNumber | A2UIDynamicBoolean) => string\n}\n\n// ============================================================================\n// Internal Helpers\n// ============================================================================\n\nlet blockIdCounter = 0\n\nfunction defaultConversationId(surfaceId: string): string {\n return `a2ui-conv-${surfaceId}`\n}\n\nfunction defaultBlockId(componentId: string): string {\n return `a2ui-block-${componentId}-${++blockIdCounter}`\n}\n\n/**\n * Resolve a dynamic value to a plain string.\n * Literal values are returned directly; bindings are serialized for display.\n */\nfunction resolveDynamic(\n value: A2UIDynamicString | A2UIDynamicNumber | A2UIDynamicBoolean | undefined,\n resolver?: (v: A2UIDynamicString | A2UIDynamicNumber | A2UIDynamicBoolean) => string\n): string {\n if (value === undefined || value === null) return ''\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean') return String(value)\n if (resolver) return resolver(value)\n // Fallback: serialize binding as a readable placeholder\n if ('path' in value) return `{{${value.path}}}`\n if ('call' in value) return `{{${value.call}(...)}}`\n return JSON.stringify(value)\n}\n\n/**\n * Build a lookup map from component array\n */\nfunction buildComponentMap(components: A2UIComponent[]): Map<string, A2UIComponent> {\n const map = new Map<string, A2UIComponent>()\n for (const comp of components) {\n map.set(comp.id, comp)\n }\n return map\n}\n\n/**\n * Find the root component (id === 'root') in the component list\n */\nfunction findRoot(components: A2UIComponent[]): A2UIComponent | undefined {\n return components.find((c) => c.id === 'root')\n}\n\n/**\n * Get direct children IDs from a component\n */\nfunction getChildIds(component: A2UIComponent): string[] {\n if (component.child) return [component.child]\n if (Array.isArray(component.children)) return component.children\n // Template children (data-bound) cannot be resolved without a data model\n return []\n}\n\n// ============================================================================\n// A2UI Component to LucidBlock Mapping\n// ============================================================================\n\n/**\n * Map an A2UI component type to a UIX BlockType.\n *\n * Direct mappings:\n * - Text -> 'text'\n * - Image -> 'image'\n *\n * Components without a direct mapping are represented as 'text' blocks\n * with a structured description of the component.\n */\nfunction mapComponentType(componentType: string): BlockType {\n switch (componentType) {\n case 'Text':\n return 'text'\n case 'Image':\n return 'image'\n default:\n return 'text'\n }\n}\n\n/**\n * Convert a single A2UI component to a LucidBlock.\n *\n * For components that map directly to UIX block types (Text, Image),\n * the content is converted to the matching block content type.\n *\n * For other components (Button, TextField, Card, etc.), a text block\n * is produced with a structured markdown representation.\n */\nfunction componentToBlock(\n component: A2UIComponent,\n options: A2UIConversionOptions = {}\n): LucidBlock {\n const genBlockId = options.generateBlockId ?? defaultBlockId\n const blockId = genBlockId(component.id)\n const resolve = (v: A2UIDynamicString | A2UIDynamicNumber | A2UIDynamicBoolean | undefined) =>\n resolveDynamic(v, options.resolveValue)\n\n switch (component.component) {\n case 'Text':\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: resolve(component.text),\n } as TextBlockContent,\n }\n\n case 'Image':\n return {\n id: blockId,\n type: 'image',\n status: 'completed' as ContentStatus,\n content: {\n url: resolve(component.url),\n alt: component.id,\n } as ImageBlockContent,\n }\n\n case 'Button': {\n const label = resolve(component.text) || component.id\n const actionDesc = component.action?.event\n ? `action:${component.action.event.name}`\n : component.action?.functionCall\n ? `call:${component.action.functionCall.name}`\n : ''\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[Button: ${label}]${actionDesc ? ` (${actionDesc})` : ''}`,\n } as TextBlockContent,\n }\n }\n\n case 'TextField': {\n const label = resolve(component.label) || component.id\n const val = resolve(component.value)\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[TextField: ${label}]${val ? ` value=\"${val}\"` : ''}`,\n } as TextBlockContent,\n }\n }\n\n case 'CheckBox': {\n const label = resolve(component.label) || component.id\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[CheckBox: ${label}]`,\n } as TextBlockContent,\n }\n }\n\n case 'DateTimeInput': {\n const label = resolve(component.label) || component.id\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[DateTimeInput: ${label}]`,\n } as TextBlockContent,\n }\n }\n\n case 'ChoicePicker': {\n const label = resolve(component.label) || component.id\n const optionLabels = component.options\n ? component.options.map((o) => resolve(o.label)).join(', ')\n : ''\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[ChoicePicker: ${label}]${optionLabels ? ` options=[${optionLabels}]` : ''}`,\n } as TextBlockContent,\n }\n }\n\n case 'Slider': {\n const label = resolve(component.label) || component.id\n const min = component.min ?? 0\n const max = component.max ?? 100\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[Slider: ${label}] range=[${min}, ${max}]`,\n } as TextBlockContent,\n }\n }\n\n case 'Video':\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[Video: ${resolve(component.url)}]`,\n } as TextBlockContent,\n }\n\n case 'AudioPlayer':\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[Audio: ${resolve(component.url)}]`,\n } as TextBlockContent,\n }\n\n case 'Icon':\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[Icon: ${resolve(component.name)}]`,\n } as TextBlockContent,\n }\n\n case 'Divider':\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: '---',\n } as TextBlockContent,\n }\n\n // Container components (Row, Column, Card, List, Tabs, Modal)\n // are flattened - their children are emitted as separate blocks.\n // A container itself does not produce a block.\n // This default handles any unknown/custom component types.\n default:\n return {\n id: blockId,\n type: 'text',\n status: 'completed' as ContentStatus,\n content: {\n text: `[${component.component}: ${component.id}]`,\n } as TextBlockContent,\n }\n }\n}\n\n/**\n * Container component types whose children should be traversed\n * but which do not produce blocks themselves.\n */\nconst CONTAINER_TYPES = new Set(['Row', 'Column', 'Card', 'List', 'Tabs', 'Modal'])\n\n/**\n * Recursively flatten the A2UI component tree into LucidBlocks.\n *\n * Container components are traversed but not emitted as blocks.\n * Leaf/display/input/interactive components are converted to blocks.\n */\nfunction flattenComponents(\n rootId: string,\n componentMap: Map<string, A2UIComponent>,\n options: A2UIConversionOptions = {},\n visited: Set<string> = new Set()\n): LucidBlock[] {\n if (visited.has(rootId)) return []\n visited.add(rootId)\n\n const component = componentMap.get(rootId)\n if (!component) return []\n\n const isContainer = CONTAINER_TYPES.has(component.component)\n const childIds = getChildIds(component)\n\n // For Tabs, children are defined differently\n if (component.component === 'Tabs' && component.tabs) {\n const blocks: LucidBlock[] = []\n for (const tab of component.tabs) {\n const title = resolveDynamic(tab.title, options.resolveValue)\n const genBlockId = options.generateBlockId ?? defaultBlockId\n blocks.push({\n id: genBlockId(`${component.id}-tab-${tab.child}`),\n type: 'text',\n status: 'completed' as ContentStatus,\n content: { text: `**${title}**` } as TextBlockContent,\n })\n blocks.push(...flattenComponents(tab.child, componentMap, options, visited))\n }\n return blocks\n }\n\n if (isContainer) {\n // Recurse into children, skip the container itself\n const blocks: LucidBlock[] = []\n for (const childId of childIds) {\n blocks.push(...flattenComponents(childId, componentMap, options, visited))\n }\n return blocks\n }\n\n // Leaf component - convert to block, then also traverse any children\n const blocks: LucidBlock[] = [componentToBlock(component, options)]\n for (const childId of childIds) {\n blocks.push(...flattenComponents(childId, componentMap, options, visited))\n }\n return blocks\n}\n\n// ============================================================================\n// Public Conversion Functions\n// ============================================================================\n\n/**\n * Convert an A2UI payload (containing updateComponents) to a UIX LucidConversation.\n *\n * The A2UI component tree is flattened into a linear sequence of LucidBlocks:\n * - `Text` components become text blocks\n * - `Image` components become image blocks\n * - Input and interactive components become text blocks with structured descriptions\n * - Container components (Row, Column, Card, etc.) are traversed but not emitted\n *\n * @param payload - An A2UI payload message (must contain updateComponents)\n * @param options - Conversion options\n * @returns A LucidConversation representing the A2UI surface, or null if the payload\n * does not contain updateComponents\n *\n * @example\n * ```typescript\n * const payload: A2UIPayload = {\n * version: 'v0.10',\n * updateComponents: {\n * surfaceId: 'form_1',\n * components: [\n * { id: 'root', component: 'Column', children: ['title', 'img'] },\n * { id: 'title', component: 'Text', text: 'Hello World' },\n * { id: 'img', component: 'Image', url: 'https://example.com/photo.png' }\n * ]\n * }\n * }\n *\n * const conversation = fromA2UIPayload(payload)\n * // conversation.blocks[0] -> text block \"Hello World\"\n * // conversation.blocks[1] -> image block\n * ```\n */\nexport function fromA2UIPayload(\n payload: A2UIPayload,\n options: A2UIConversionOptions = {}\n): LucidConversation | null {\n const update = payload.updateComponents\n if (!update) return null\n\n const { surfaceId, components } = update\n const genConvId = options.generateConversationId ?? defaultConversationId\n\n const componentMap = buildComponentMap(components)\n const root = findRoot(components)\n\n let blocks: LucidBlock[]\n if (root) {\n blocks = flattenComponents(root.id, componentMap, options)\n } else {\n // No root found - convert all components linearly\n blocks = components\n .filter((c) => !CONTAINER_TYPES.has(c.component))\n .map((c) => componentToBlock(c, options))\n }\n\n return {\n id: genConvId(surfaceId),\n role: 'assistant',\n status: 'completed',\n blocks,\n timestamp: Date.now(),\n }\n}\n\n/**\n * Convert multiple A2UI payloads (a stream of messages) to LucidConversations.\n *\n * Processes an array of A2UI messages and returns one LucidConversation per\n * updateComponents message encountered.\n *\n * @param payloads - Array of A2UI payload messages\n * @param options - Conversion options\n * @returns Array of LucidConversations\n *\n * @example\n * ```typescript\n * const messages: A2UIPayload[] = [\n * { version: 'v0.10', createSurface: { surfaceId: 's1', catalogId: '...' } },\n * { version: 'v0.10', updateComponents: { surfaceId: 's1', components: [...] } },\n * ]\n *\n * const conversations = fromA2UIPayloads(messages)\n * ```\n */\nexport function fromA2UIPayloads(\n payloads: A2UIPayload[],\n options: A2UIConversionOptions = {}\n): LucidConversation[] {\n const results: LucidConversation[] = []\n for (const payload of payloads) {\n const conv = fromA2UIPayload(payload, options)\n if (conv) results.push(conv)\n }\n return results\n}\n\n/**\n * Convert a UIX LucidConversation back to an A2UI payload.\n *\n * Maps LucidBlocks back to A2UI components wrapped in a Column layout:\n * - text blocks -> Text components\n * - image blocks -> Image components\n * - Other block types -> Text components with type annotation\n *\n * @param conversation - A UIX LucidConversation\n * @param surfaceId - Optional surface ID (defaults to conversation.id)\n * @param version - A2UI protocol version (defaults to 'v0.10')\n * @returns An A2UI payload with updateComponents\n *\n * @example\n * ```typescript\n * const conversation: LucidConversation = {\n * id: 'conv-1',\n * role: 'assistant',\n * status: 'completed',\n * blocks: [\n * { id: 'b1', type: 'text', status: 'completed', content: { text: 'Hello' } },\n * { id: 'b2', type: 'image', status: 'completed', content: { url: 'https://...' } }\n * ],\n * timestamp: Date.now()\n * }\n *\n * const payload = toA2UIPayload(conversation)\n * ```\n */\nexport function toA2UIPayload(\n conversation: LucidConversation,\n surfaceId?: string,\n version: string = 'v0.10'\n): A2UIPayload {\n const sid = surfaceId ?? conversation.id\n const components: A2UIComponent[] = []\n const childIds: string[] = []\n\n for (const block of conversation.blocks) {\n const compId = `comp-${block.id}`\n childIds.push(compId)\n\n switch (block.type) {\n case 'text': {\n const content = block.content as TextBlockContent\n components.push({\n id: compId,\n component: 'Text',\n text: content.text,\n })\n break\n }\n\n case 'image': {\n const content = block.content as ImageBlockContent\n components.push({\n id: compId,\n component: 'Image',\n url: content.url,\n })\n break\n }\n\n case 'thinking': {\n const content = block.content as { reasoning: string }\n components.push({\n id: compId,\n component: 'Text',\n text: `*Thinking: ${content.reasoning}*`,\n })\n break\n }\n\n case 'tool': {\n const content = block.content as { name: string; input: unknown; output?: unknown; status: string }\n const parts = [`**Tool: ${content.name}**`]\n if (content.input) parts.push(`Input: \\`${JSON.stringify(content.input)}\\``)\n if (content.output) parts.push(`Output: \\`${JSON.stringify(content.output)}\\``)\n parts.push(`Status: ${content.status}`)\n components.push({\n id: compId,\n component: 'Text',\n text: parts.join('\\n\\n'),\n })\n break\n }\n\n case 'error': {\n const content = block.content as ErrorBlockContent\n components.push({\n id: compId,\n component: 'Text',\n text: `**Error [${content.code}]:** ${content.message}`,\n })\n break\n }\n\n case 'file': {\n const content = block.content as { name: string; url: string; type: string }\n components.push({\n id: compId,\n component: 'Text',\n text: `[File: ${content.name}](${content.url})`,\n })\n break\n }\n\n case 'source': {\n const content = block.content as { title: string; url?: string; excerpt?: string }\n const text = content.url\n ? `[Source: ${content.title}](${content.url})`\n : `Source: ${content.title}`\n components.push({\n id: compId,\n component: 'Text',\n text: content.excerpt ? `${text}\\n\\n> ${content.excerpt}` : text,\n })\n break\n }\n\n default: {\n components.push({\n id: compId,\n component: 'Text',\n text: `[${block.type}: ${block.id}]`,\n })\n break\n }\n }\n }\n\n // Wrap all components in a root Column\n components.unshift({\n id: 'root',\n component: 'Column',\n children: childIds,\n })\n\n return {\n version,\n updateComponents: {\n surfaceId: sid,\n components,\n },\n }\n}\n"],"mappings":";AAuSA,IAAI,iBAAiB;AAErB,SAAS,sBAAsB,WAA2B;AACxD,SAAO,aAAa,SAAS;AAC/B;AAEA,SAAS,eAAe,aAA6B;AACnD,SAAO,cAAc,WAAW,IAAI,EAAE,cAAc;AACtD;AAMA,SAAS,eACP,OACA,UACQ;AACR,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AAChF,MAAI,SAAU,QAAO,SAAS,KAAK;AAEnC,MAAI,UAAU,MAAO,QAAO,KAAK,MAAM,IAAI;AAC3C,MAAI,UAAU,MAAO,QAAO,KAAK,MAAM,IAAI;AAC3C,SAAO,KAAK,UAAU,KAAK;AAC7B;AAKA,SAAS,kBAAkB,YAAyD;AAClF,QAAM,MAAM,oBAAI,IAA2B;AAC3C,aAAW,QAAQ,YAAY;AAC7B,QAAI,IAAI,KAAK,IAAI,IAAI;AAAA,EACvB;AACA,SAAO;AACT;AAKA,SAAS,SAAS,YAAwD;AACxE,SAAO,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM;AAC/C;AAKA,SAAS,YAAY,WAAoC;AACvD,MAAI,UAAU,MAAO,QAAO,CAAC,UAAU,KAAK;AAC5C,MAAI,MAAM,QAAQ,UAAU,QAAQ,EAAG,QAAO,UAAU;AAExD,SAAO,CAAC;AACV;AAoCA,SAAS,iBACP,WACA,UAAiC,CAAC,GACtB;AACZ,QAAM,aAAa,QAAQ,mBAAmB;AAC9C,QAAM,UAAU,WAAW,UAAU,EAAE;AACvC,QAAM,UAAU,CAAC,MACf,eAAe,GAAG,QAAQ,YAAY;AAExC,UAAQ,UAAU,WAAW;AAAA,IAC3B,KAAK;AACH,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,QAAQ,UAAU,IAAI;AAAA,QAC9B;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,KAAK,QAAQ,UAAU,GAAG;AAAA,UAC1B,KAAK,UAAU;AAAA,QACjB;AAAA,MACF;AAAA,IAEF,KAAK,UAAU;AACb,YAAM,QAAQ,QAAQ,UAAU,IAAI,KAAK,UAAU;AACnD,YAAM,aAAa,UAAU,QAAQ,QACjC,UAAU,UAAU,OAAO,MAAM,IAAI,KACrC,UAAU,QAAQ,eAChB,QAAQ,UAAU,OAAO,aAAa,IAAI,KAC1C;AACN,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,YAAY,KAAK,IAAI,aAAa,KAAK,UAAU,MAAM,EAAE;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,aAAa;AAChB,YAAM,QAAQ,QAAQ,UAAU,KAAK,KAAK,UAAU;AACpD,YAAM,MAAM,QAAQ,UAAU,KAAK;AACnC,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,eAAe,KAAK,IAAI,MAAM,WAAW,GAAG,MAAM,EAAE;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,YAAY;AACf,YAAM,QAAQ,QAAQ,UAAU,KAAK,KAAK,UAAU;AACpD,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,cAAc,KAAK;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,iBAAiB;AACpB,YAAM,QAAQ,QAAQ,UAAU,KAAK,KAAK,UAAU;AACpD,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,mBAAmB,KAAK;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,gBAAgB;AACnB,YAAM,QAAQ,QAAQ,UAAU,KAAK,KAAK,UAAU;AACpD,YAAM,eAAe,UAAU,UAC3B,UAAU,QAAQ,IAAI,CAAC,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,KAAK,IAAI,IACxD;AACJ,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,kBAAkB,KAAK,IAAI,eAAe,aAAa,YAAY,MAAM,EAAE;AAAA,QACnF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,UAAU;AACb,YAAM,QAAQ,QAAQ,UAAU,KAAK,KAAK,UAAU;AACpD,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,MAAM,UAAU,OAAO;AAC7B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,YAAY,KAAK,YAAY,GAAG,KAAK,GAAG;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,WAAW,QAAQ,UAAU,GAAG,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,WAAW,QAAQ,UAAU,GAAG,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,UAAU,QAAQ,UAAU,IAAI,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IAEF,KAAK;AACH,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM;AAAA,QACR;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA,IAMF;AACE,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,MAAM,IAAI,UAAU,SAAS,KAAK,UAAU,EAAE;AAAA,QAChD;AAAA,MACF;AAAA,EACJ;AACF;AAMA,IAAM,kBAAkB,oBAAI,IAAI,CAAC,OAAO,UAAU,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAQlF,SAAS,kBACP,QACA,cACA,UAAiC,CAAC,GAClC,UAAuB,oBAAI,IAAI,GACjB;AACd,MAAI,QAAQ,IAAI,MAAM,EAAG,QAAO,CAAC;AACjC,UAAQ,IAAI,MAAM;AAElB,QAAM,YAAY,aAAa,IAAI,MAAM;AACzC,MAAI,CAAC,UAAW,QAAO,CAAC;AAExB,QAAM,cAAc,gBAAgB,IAAI,UAAU,SAAS;AAC3D,QAAM,WAAW,YAAY,SAAS;AAGtC,MAAI,UAAU,cAAc,UAAU,UAAU,MAAM;AACpD,UAAMA,UAAuB,CAAC;AAC9B,eAAW,OAAO,UAAU,MAAM;AAChC,YAAM,QAAQ,eAAe,IAAI,OAAO,QAAQ,YAAY;AAC5D,YAAM,aAAa,QAAQ,mBAAmB;AAC9C,MAAAA,QAAO,KAAK;AAAA,QACV,IAAI,WAAW,GAAG,UAAU,EAAE,QAAQ,IAAI,KAAK,EAAE;AAAA,QACjD,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS,EAAE,MAAM,KAAK,KAAK,KAAK;AAAA,MAClC,CAAC;AACD,MAAAA,QAAO,KAAK,GAAG,kBAAkB,IAAI,OAAO,cAAc,SAAS,OAAO,CAAC;AAAA,IAC7E;AACA,WAAOA;AAAA,EACT;AAEA,MAAI,aAAa;AAEf,UAAMA,UAAuB,CAAC;AAC9B,eAAW,WAAW,UAAU;AAC9B,MAAAA,QAAO,KAAK,GAAG,kBAAkB,SAAS,cAAc,SAAS,OAAO,CAAC;AAAA,IAC3E;AACA,WAAOA;AAAA,EACT;AAGA,QAAM,SAAuB,CAAC,iBAAiB,WAAW,OAAO,CAAC;AAClE,aAAW,WAAW,UAAU;AAC9B,WAAO,KAAK,GAAG,kBAAkB,SAAS,cAAc,SAAS,OAAO,CAAC;AAAA,EAC3E;AACA,SAAO;AACT;AAuCO,SAAS,gBACd,SACA,UAAiC,CAAC,GACR;AAC1B,QAAM,SAAS,QAAQ;AACvB,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,EAAE,WAAW,WAAW,IAAI;AAClC,QAAM,YAAY,QAAQ,0BAA0B;AAEpD,QAAM,eAAe,kBAAkB,UAAU;AACjD,QAAM,OAAO,SAAS,UAAU;AAEhC,MAAI;AACJ,MAAI,MAAM;AACR,aAAS,kBAAkB,KAAK,IAAI,cAAc,OAAO;AAAA,EAC3D,OAAO;AAEL,aAAS,WACN,OAAO,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,SAAS,CAAC,EAC/C,IAAI,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAAA,EAC5C;AAEA,SAAO;AAAA,IACL,IAAI,UAAU,SAAS;AAAA,IACvB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR;AAAA,IACA,WAAW,KAAK,IAAI;AAAA,EACtB;AACF;AAsBO,SAAS,iBACd,UACA,UAAiC,CAAC,GACb;AACrB,QAAM,UAA+B,CAAC;AACtC,aAAW,WAAW,UAAU;AAC9B,UAAM,OAAO,gBAAgB,SAAS,OAAO;AAC7C,QAAI,KAAM,SAAQ,KAAK,IAAI;AAAA,EAC7B;AACA,SAAO;AACT;AA+BO,SAAS,cACd,cACA,WACA,UAAkB,SACL;AACb,QAAM,MAAM,aAAa,aAAa;AACtC,QAAM,aAA8B,CAAC;AACrC,QAAM,WAAqB,CAAC;AAE5B,aAAW,SAAS,aAAa,QAAQ;AACvC,UAAM,SAAS,QAAQ,MAAM,EAAE;AAC/B,aAAS,KAAK,MAAM;AAEpB,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK,QAAQ;AACX,cAAM,UAAU,MAAM;AACtB,mBAAW,KAAK;AAAA,UACd,IAAI;AAAA,UACJ,WAAW;AAAA,UACX,MAAM,QAAQ;AAAA,QAChB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,SAAS;AACZ,cAAM,UAAU,MAAM;AACtB,mBAAW,KAAK;AAAA,UACd,IAAI;AAAA,UACJ,WAAW;AAAA,UACX,KAAK,QAAQ;AAAA,QACf,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,YAAY;AACf,cAAM,UAAU,MAAM;AACtB,mBAAW,KAAK;AAAA,UACd,IAAI;AAAA,UACJ,WAAW;AAAA,UACX,MAAM,cAAc,QAAQ,SAAS;AAAA,QACvC,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,cAAM,UAAU,MAAM;AACtB,cAAM,QAAQ,CAAC,WAAW,QAAQ,IAAI,IAAI;AAC1C,YAAI,QAAQ,MAAO,OAAM,KAAK,YAAY,KAAK,UAAU,QAAQ,KAAK,CAAC,IAAI;AAC3E,YAAI,QAAQ,OAAQ,OAAM,KAAK,aAAa,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI;AAC9E,cAAM,KAAK,WAAW,QAAQ,MAAM,EAAE;AACtC,mBAAW,KAAK;AAAA,UACd,IAAI;AAAA,UACJ,WAAW;AAAA,UACX,MAAM,MAAM,KAAK,MAAM;AAAA,QACzB,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,SAAS;AACZ,cAAM,UAAU,MAAM;AACtB,mBAAW,KAAK;AAAA,UACd,IAAI;AAAA,UACJ,WAAW;AAAA,UACX,MAAM,YAAY,QAAQ,IAAI,QAAQ,QAAQ,OAAO;AAAA,QACvD,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,cAAM,UAAU,MAAM;AACtB,mBAAW,KAAK;AAAA,UACd,IAAI;AAAA,UACJ,WAAW;AAAA,UACX,MAAM,UAAU,QAAQ,IAAI,KAAK,QAAQ,GAAG;AAAA,QAC9C,CAAC;AACD;AAAA,MACF;AAAA,MAEA,KAAK,UAAU;AACb,cAAM,UAAU,MAAM;AACtB,cAAM,OAAO,QAAQ,MACjB,YAAY,QAAQ,KAAK,KAAK,QAAQ,GAAG,MACzC,WAAW,QAAQ,KAAK;AAC5B,mBAAW,KAAK;AAAA,UACd,IAAI;AAAA,UACJ,WAAW;AAAA,UACX,MAAM,QAAQ,UAAU,GAAG,IAAI;AAAA;AAAA,IAAS,QAAQ,OAAO,KAAK;AAAA,QAC9D,CAAC;AACD;AAAA,MACF;AAAA,MAEA,SAAS;AACP,mBAAW,KAAK;AAAA,UACd,IAAI;AAAA,UACJ,WAAW;AAAA,UACX,MAAM,IAAI,MAAM,IAAI,KAAK,MAAM,EAAE;AAAA,QACnC,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,aAAW,QAAQ;AAAA,IACjB,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,UAAU;AAAA,EACZ,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB;AAAA,MAChB,WAAW;AAAA,MACX;AAAA,IACF;AAAA,EACF;AACF;","names":["blocks"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uix-ai/adapter-a2ui",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Adapter to convert Google A2UI protocol payloads to UIX Lucid IR format",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"dev": "tsup --watch",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"clean": "rm -rf dist"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@uix-ai/core": "workspace:*"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"tsup": "^8.0.0",
|
|
29
|
+
"typescript": "^5.3.0",
|
|
30
|
+
"vitest": "^3.2.4"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"uix",
|
|
34
|
+
"a2ui",
|
|
35
|
+
"agent-ui",
|
|
36
|
+
"adapter",
|
|
37
|
+
"protocol",
|
|
38
|
+
"converter",
|
|
39
|
+
"google"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/Deepractice/UIX.git",
|
|
45
|
+
"directory": "packages/adapter-a2ui"
|
|
46
|
+
}
|
|
47
|
+
}
|