@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/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/client-D0JsJgUP.d.cts +399 -0
- package/dist/client-D0JsJgUP.d.cts.map +1 -0
- package/dist/client-QtfEE14J.d.mts +399 -0
- package/dist/client-QtfEE14J.d.mts.map +1 -0
- package/dist/index.cjs +795 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +767 -0
- package/dist/index.mjs.map +1 -0
- package/dist/json-pointer-CA9LEWAP.cjs +117 -0
- package/dist/json-pointer-CA9LEWAP.cjs.map +1 -0
- package/dist/json-pointer-DCdSrMT3.mjs +94 -0
- package/dist/json-pointer-DCdSrMT3.mjs.map +1 -0
- package/dist/react.cjs +95 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +42 -0
- package/dist/react.d.cts.map +1 -0
- package/dist/react.d.mts +42 -0
- package/dist/react.d.mts.map +1 -0
- package/dist/react.mjs +94 -0
- package/dist/react.mjs.map +1 -0
- package/package.json +93 -0
package/dist/react.mjs
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { i as toJsonObject, n as dataModelToOpenUIState } from "./json-pointer-DCdSrMT3.mjs";
|
|
2
|
+
import { BuiltinActionType } from "@openuidev/lang-core";
|
|
3
|
+
import { Renderer } from "@openuidev/react-lang";
|
|
4
|
+
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region src/Renderer.tsx
|
|
7
|
+
function collectFormStateKeys(result) {
|
|
8
|
+
const keys = /* @__PURE__ */ new Set();
|
|
9
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
10
|
+
const visit = (value) => {
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
for (const item of value) visit(item);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (!value || typeof value !== "object" || seen.has(value)) return;
|
|
16
|
+
seen.add(value);
|
|
17
|
+
const object = value;
|
|
18
|
+
if (object.type === "element" && object.typeName === "Form") {
|
|
19
|
+
const props = object.props;
|
|
20
|
+
if (typeof props?.name === "string") keys.add(props.name);
|
|
21
|
+
}
|
|
22
|
+
for (const child of Object.values(object)) visit(child);
|
|
23
|
+
};
|
|
24
|
+
visit(result?.root);
|
|
25
|
+
return [...keys];
|
|
26
|
+
}
|
|
27
|
+
function A2UIRenderer({ client, surfaceId, library, mapAction, onAction, onOpenUrl, onStateUpdate, onParseResult, onError, isStreaming = false, formStateKeys, toolProvider, queryLoader }) {
|
|
28
|
+
const subscribe = useCallback((notify) => client.subscribe(notify), [client]);
|
|
29
|
+
const getSnapshot = useCallback(() => client.getSurface(surfaceId), [client, surfaceId]);
|
|
30
|
+
const surface = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
31
|
+
const initialState = useMemo(() => {
|
|
32
|
+
if (!surface) return void 0;
|
|
33
|
+
const keys = new Set([...collectFormStateKeys(surface.parseResult), ...formStateKeys ?? []]);
|
|
34
|
+
return dataModelToOpenUIState(surface.dataModel, keys);
|
|
35
|
+
}, [formStateKeys, surface]);
|
|
36
|
+
const agentToolProvider = useMemo(() => ({ async callTool({ name, arguments: args }) {
|
|
37
|
+
return {
|
|
38
|
+
content: [],
|
|
39
|
+
structuredContent: await client.callAgentFunction({
|
|
40
|
+
surfaceId,
|
|
41
|
+
call: name,
|
|
42
|
+
args: toJsonObject(args)
|
|
43
|
+
})
|
|
44
|
+
};
|
|
45
|
+
} }), [client, surfaceId]);
|
|
46
|
+
const handleAction = useCallback((event) => {
|
|
47
|
+
const current = client.getSurface(surfaceId);
|
|
48
|
+
if (!current) return;
|
|
49
|
+
if (event.type === BuiltinActionType.OpenUrl) {
|
|
50
|
+
const url = event.params?.url;
|
|
51
|
+
if (typeof url === "string") {
|
|
52
|
+
if (onOpenUrl) onOpenUrl(url, event, current);
|
|
53
|
+
else if (typeof window !== "undefined") window.open(url, "_blank", "noopener,noreferrer");
|
|
54
|
+
}
|
|
55
|
+
onAction?.(event, current);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const options = mapAction?.(event, current) ?? {};
|
|
59
|
+
client.dispatchOpenUIAction(surfaceId, event, options);
|
|
60
|
+
onAction?.(event, current);
|
|
61
|
+
}, [
|
|
62
|
+
client,
|
|
63
|
+
mapAction,
|
|
64
|
+
onAction,
|
|
65
|
+
onOpenUrl,
|
|
66
|
+
surfaceId
|
|
67
|
+
]);
|
|
68
|
+
const handleStateUpdate = useCallback((state) => {
|
|
69
|
+
if (!client.updateSurfaceFromOpenUIState(surfaceId, state)) return;
|
|
70
|
+
const current = client.getSurface(surfaceId);
|
|
71
|
+
if (current) onStateUpdate?.(state, current);
|
|
72
|
+
}, [
|
|
73
|
+
client,
|
|
74
|
+
onStateUpdate,
|
|
75
|
+
surfaceId
|
|
76
|
+
]);
|
|
77
|
+
if (!surface) return null;
|
|
78
|
+
return /* @__PURE__ */ jsx(Renderer, {
|
|
79
|
+
response: surface.source,
|
|
80
|
+
library,
|
|
81
|
+
initialState,
|
|
82
|
+
isStreaming,
|
|
83
|
+
onAction: handleAction,
|
|
84
|
+
onStateUpdate: handleStateUpdate,
|
|
85
|
+
onParseResult,
|
|
86
|
+
onError,
|
|
87
|
+
toolProvider: toolProvider ?? agentToolProvider,
|
|
88
|
+
queryLoader
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { A2UIRenderer };
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=react.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.mjs","names":["OpenUIRenderer"],"sources":["../src/Renderer.tsx"],"sourcesContent":["import {\n BuiltinActionType,\n type ActionEvent,\n type OpenUIError,\n type ParseResult,\n} from \"@openuidev/lang-core\";\nimport {\n Renderer as OpenUIRenderer,\n type Library,\n type RendererProps as OpenUIRendererProps,\n} from \"@openuidev/react-lang\";\nimport { useCallback, useMemo, useSyncExternalStore } from \"react\";\nimport type { A2UIClient } from \"./client\";\nimport { dataModelToOpenUIState, toJsonObject } from \"./json-pointer\";\nimport type { MapOpenUIAction, OpenUIActionOptions, SurfaceSnapshot } from \"./types\";\n\nexport interface A2UIRendererProps {\n client: A2UIClient;\n surfaceId: string;\n library: Library;\n mapAction?: MapOpenUIAction;\n onAction?: (event: ActionEvent, surface: SurfaceSnapshot) => void;\n /** Handles OpenUI @OpenUrl locally. Defaults to window.open in browsers. */\n onOpenUrl?: (url: string, event: ActionEvent, surface: SurfaceSnapshot) => void;\n onStateUpdate?: (state: Record<string, unknown>, surface: SurfaceSnapshot) => void;\n onParseResult?: (result: ParseResult | null) => void;\n onError?: (errors: OpenUIError[]) => void;\n /** Whether the surrounding A2UI transport is still delivering this agent turn. */\n isStreaming?: boolean;\n /** Additional top-level data-model keys that should hydrate form namespaces. */\n formStateKeys?: readonly string[];\n toolProvider?: OpenUIRendererProps[\"toolProvider\"];\n queryLoader?: OpenUIRendererProps[\"queryLoader\"];\n}\n\nfunction collectFormStateKeys(result: ParseResult | null): string[] {\n const keys = new Set<string>();\n const seen = new WeakSet<object>();\n const visit = (value: unknown): void => {\n if (Array.isArray(value)) {\n for (const item of value) visit(item);\n return;\n }\n if (!value || typeof value !== \"object\" || seen.has(value)) return;\n seen.add(value);\n const object = value as Record<string, unknown>;\n if (object.type === \"element\" && object.typeName === \"Form\") {\n const props = object.props as Record<string, unknown> | undefined;\n if (typeof props?.name === \"string\") keys.add(props.name);\n }\n for (const child of Object.values(object)) visit(child);\n };\n visit(result?.root);\n return [...keys];\n}\n\nexport function A2UIRenderer({\n client,\n surfaceId,\n library,\n mapAction,\n onAction,\n onOpenUrl,\n onStateUpdate,\n onParseResult,\n onError,\n isStreaming = false,\n formStateKeys,\n toolProvider,\n queryLoader,\n}: A2UIRendererProps) {\n const subscribe = useCallback((notify: () => void) => client.subscribe(notify), [client]);\n const getSnapshot = useCallback(() => client.getSurface(surfaceId), [client, surfaceId]);\n const surface = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n const initialState = useMemo(() => {\n if (!surface) return undefined;\n const keys = new Set([...collectFormStateKeys(surface.parseResult), ...(formStateKeys ?? [])]);\n return dataModelToOpenUIState(surface.dataModel, keys);\n }, [formStateKeys, surface]);\n const agentToolProvider = useMemo<NonNullable<OpenUIRendererProps[\"toolProvider\"]>>(\n () => ({\n async callTool({\n name,\n arguments: args,\n }: {\n name: string;\n arguments?: Record<string, unknown>;\n }) {\n const value = await client.callAgentFunction({\n surfaceId,\n call: name,\n args: toJsonObject(args),\n });\n return { content: [], structuredContent: value };\n },\n }),\n [client, surfaceId],\n );\n\n const handleAction = useCallback(\n (event: ActionEvent) => {\n const current = client.getSurface(surfaceId);\n if (!current) return;\n if (event.type === BuiltinActionType.OpenUrl) {\n const url = event.params?.url;\n if (typeof url === \"string\") {\n if (onOpenUrl) onOpenUrl(url, event, current);\n else if (typeof window !== \"undefined\") window.open(url, \"_blank\", \"noopener,noreferrer\");\n }\n onAction?.(event, current);\n return;\n }\n const options: OpenUIActionOptions = mapAction?.(event, current) ?? {};\n client.dispatchOpenUIAction(surfaceId, event, options);\n onAction?.(event, current);\n },\n [client, mapAction, onAction, onOpenUrl, surfaceId],\n );\n\n const handleStateUpdate = useCallback(\n (state: Record<string, unknown>) => {\n if (!client.updateSurfaceFromOpenUIState(surfaceId, state)) return;\n const current = client.getSurface(surfaceId);\n if (current) onStateUpdate?.(state, current);\n },\n [client, onStateUpdate, surfaceId],\n );\n\n if (!surface) return null;\n\n return (\n <OpenUIRenderer\n response={surface.source}\n library={library}\n initialState={initialState}\n isStreaming={isStreaming}\n onAction={handleAction}\n onStateUpdate={handleStateUpdate}\n onParseResult={onParseResult}\n onError={onError}\n toolProvider={toolProvider ?? agentToolProvider}\n queryLoader={queryLoader}\n />\n );\n}\n"],"mappings":";;;;;;AAmCA,SAAS,qBAAqB,QAAsC;CAClE,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,uBAAO,IAAI,SAAiB;CAClC,MAAM,SAAS,UAAyB;AACtC,MAAI,MAAM,QAAQ,MAAM,EAAE;AACxB,QAAK,MAAM,QAAQ,MAAO,OAAM,KAAK;AACrC;;AAEF,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,KAAK,IAAI,MAAM,CAAE;AAC5D,OAAK,IAAI,MAAM;EACf,MAAM,SAAS;AACf,MAAI,OAAO,SAAS,aAAa,OAAO,aAAa,QAAQ;GAC3D,MAAM,QAAQ,OAAO;AACrB,OAAI,OAAO,OAAO,SAAS,SAAU,MAAK,IAAI,MAAM,KAAK;;AAE3D,OAAK,MAAM,SAAS,OAAO,OAAO,OAAO,CAAE,OAAM,MAAM;;AAEzD,OAAM,QAAQ,KAAK;AACnB,QAAO,CAAC,GAAG,KAAK;;AAGlB,SAAgB,aAAa,EAC3B,QACA,WACA,SACA,WACA,UACA,WACA,eACA,eACA,SACA,cAAc,OACd,eACA,cACA,eACoB;CACpB,MAAM,YAAY,aAAa,WAAuB,OAAO,UAAU,OAAO,EAAE,CAAC,OAAO,CAAC;CACzF,MAAM,cAAc,kBAAkB,OAAO,WAAW,UAAU,EAAE,CAAC,QAAQ,UAAU,CAAC;CACxF,MAAM,UAAU,qBAAqB,WAAW,aAAa,YAAY;CACzE,MAAM,eAAe,cAAc;AACjC,MAAI,CAAC,QAAS,QAAO,KAAA;EACrB,MAAM,OAAO,IAAI,IAAI,CAAC,GAAG,qBAAqB,QAAQ,YAAY,EAAE,GAAI,iBAAiB,EAAE,CAAE,CAAC;AAC9F,SAAO,uBAAuB,QAAQ,WAAW,KAAK;IACrD,CAAC,eAAe,QAAQ,CAAC;CAC5B,MAAM,oBAAoB,eACjB,EACL,MAAM,SAAS,EACb,MACA,WAAW,QAIV;AAMD,SAAO;GAAE,SAAS,EAAE;GAAE,mBAAmB,MALrB,OAAO,kBAAkB;IAC3C;IACA,MAAM;IACN,MAAM,aAAa,KAAK;IACzB,CAAC;GAC8C;IAEnD,GACD,CAAC,QAAQ,UAAU,CACpB;CAED,MAAM,eAAe,aAClB,UAAuB;EACtB,MAAM,UAAU,OAAO,WAAW,UAAU;AAC5C,MAAI,CAAC,QAAS;AACd,MAAI,MAAM,SAAS,kBAAkB,SAAS;GAC5C,MAAM,MAAM,MAAM,QAAQ;AAC1B,OAAI,OAAO,QAAQ;QACb,UAAW,WAAU,KAAK,OAAO,QAAQ;aACpC,OAAO,WAAW,YAAa,QAAO,KAAK,KAAK,UAAU,sBAAsB;;AAE3F,cAAW,OAAO,QAAQ;AAC1B;;EAEF,MAAM,UAA+B,YAAY,OAAO,QAAQ,IAAI,EAAE;AACtE,SAAO,qBAAqB,WAAW,OAAO,QAAQ;AACtD,aAAW,OAAO,QAAQ;IAE5B;EAAC;EAAQ;EAAW;EAAU;EAAW;EAAU,CACpD;CAED,MAAM,oBAAoB,aACvB,UAAmC;AAClC,MAAI,CAAC,OAAO,6BAA6B,WAAW,MAAM,CAAE;EAC5D,MAAM,UAAU,OAAO,WAAW,UAAU;AAC5C,MAAI,QAAS,iBAAgB,OAAO,QAAQ;IAE9C;EAAC;EAAQ;EAAe;EAAU,CACnC;AAED,KAAI,CAAC,QAAS,QAAO;AAErB,QACE,oBAACA,UAAD;EACE,UAAU,QAAQ;EACT;EACK;EACD;EACb,UAAU;EACV,eAAe;EACA;EACN;EACT,cAAc,gBAAgB;EACjB;EACb,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openuidev/a2ui",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "A2UI v1.0 protocol support with OpenUI Lang component updates and React rendering",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.cjs",
|
|
8
|
+
"module": "dist/index.mjs",
|
|
9
|
+
"types": "dist/index.d.cts",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": {
|
|
18
|
+
"types": "./dist/index.d.mts",
|
|
19
|
+
"default": "./dist/index.mjs"
|
|
20
|
+
},
|
|
21
|
+
"require": {
|
|
22
|
+
"types": "./dist/index.d.cts",
|
|
23
|
+
"default": "./dist/index.cjs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"./react": {
|
|
27
|
+
"import": {
|
|
28
|
+
"types": "./dist/react.d.mts",
|
|
29
|
+
"default": "./dist/react.mjs"
|
|
30
|
+
},
|
|
31
|
+
"require": {
|
|
32
|
+
"types": "./dist/react.d.cts",
|
|
33
|
+
"default": "./dist/react.cjs"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"a2ui",
|
|
39
|
+
"openui",
|
|
40
|
+
"openui-lang",
|
|
41
|
+
"generative-ui",
|
|
42
|
+
"renderer",
|
|
43
|
+
"protocol"
|
|
44
|
+
],
|
|
45
|
+
"homepage": "https://openui.com",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/thesysdev/openui.git",
|
|
49
|
+
"directory": "packages/a2ui"
|
|
50
|
+
},
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/thesysdev/openui/issues"
|
|
53
|
+
},
|
|
54
|
+
"author": "engineering@thesys.dev",
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@openuidev/lang-core": "^0.3.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@openuidev/react-lang": ">=0.3.0 <0.4.0",
|
|
60
|
+
"react": "^18.3.1 || ^19.0.0",
|
|
61
|
+
"zod": "^3.25.0 || ^4.0.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"@openuidev/react-lang": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"react": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@types/react": ">=19.0.0",
|
|
73
|
+
"@types/react-dom": ">=19.0.0",
|
|
74
|
+
"jsdom": "^26.1.0",
|
|
75
|
+
"react": "^18.3.1 || ^19.0.0",
|
|
76
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
77
|
+
"vitest": "^4.0.18",
|
|
78
|
+
"@openuidev/react-lang": "^0.3.0"
|
|
79
|
+
},
|
|
80
|
+
"scripts": {
|
|
81
|
+
"test": "vitest run",
|
|
82
|
+
"build": "tsdown",
|
|
83
|
+
"watch": "tsdown --watch",
|
|
84
|
+
"typecheck": "tsc --noEmit",
|
|
85
|
+
"lint:check": "eslint ./src",
|
|
86
|
+
"lint:fix": "eslint ./src --fix",
|
|
87
|
+
"format:fix": "prettier --write ./src README.md",
|
|
88
|
+
"format:check": "prettier --check ./src README.md",
|
|
89
|
+
"check:publint": "publint",
|
|
90
|
+
"check:attw": "attw --pack . --ignore-rules=no-resolution",
|
|
91
|
+
"ci": "pnpm run lint:check && pnpm run format:check"
|
|
92
|
+
}
|
|
93
|
+
}
|