-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: add specification for A2UI web app iframe component (v0.9) #2123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4026670
b2c3ece
217dbbe
c7bffed
60e6fab
f6ba5ae
b2a7a2c
abb268e
afe14b2
62cd582
ade0236
38917de
71044a2
3d23d91
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,6 +87,65 @@ | |
| ], | ||
| "unevaluatedProperties": false | ||
| }, | ||
| "WebAppFrameUrl": { | ||
| "type": "object", | ||
| "allOf": [ | ||
| { | ||
| "$ref": "common_types.json#/$defs/ComponentCommon" | ||
| }, | ||
| { | ||
| "type": "object", | ||
| "properties": { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could it make sense to also have a way to pass arbitrary static data to the embedded app as a property, rather than needing to pass it via the data model?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Love the idea. I have introduced a new property
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let me know if you think |
||
| "component": { | ||
| "const": "WebAppFrameUrl", | ||
| "description": "The component type identifier." | ||
| }, | ||
| "url": { | ||
| "$ref": "common_types.json#/$defs/DynamicString", | ||
| "description": "The external URL to load inside the iframe." | ||
| }, | ||
| "height": { | ||
| "$ref": "common_types.json#/$defs/DynamicNumber", | ||
| "description": "The height of the iframe in pixels." | ||
| }, | ||
| "allowedEvents": { | ||
| "type": "object", | ||
| "description": "A map of authorized action names to JSON Schemas defining the expected data payload.", | ||
| "additionalProperties": {"type": "object"} | ||
| }, | ||
| "allowedFunctions": { | ||
| "type": "object", | ||
| "description": "A map of authorized host client functions to JSON Schemas defining their expected arguments.", | ||
| "additionalProperties": {"type": "object"} | ||
| }, | ||
| "mutableData": { | ||
| "type": "object", | ||
| "description": "A map of data model keys that the embedded application is authorized to mutate in the parent A2UI Data Model, mapped to JSON Schemas defining their allowed values.", | ||
| "additionalProperties": {"type": "object"} | ||
| }, | ||
| "config": { | ||
| "type": "object", | ||
| "description": "A dictionary of static key-value initialization properties passed directly to the embedded application without reactive data model binding." | ||
| }, | ||
| "data": { | ||
| "type": "object", | ||
| "description": "Data binding configuration for the component.", | ||
| "properties": { | ||
| "paths": { | ||
| "type": "object", | ||
| "description": "A dictionary mapping custom state keys to distinct JSON Pointer paths in the data model.", | ||
| "additionalProperties": {"type": "string"} | ||
| } | ||
| }, | ||
| "required": ["paths"], | ||
| "additionalProperties": false | ||
| } | ||
| }, | ||
| "required": ["component", "url"] | ||
| } | ||
| ], | ||
| "unevaluatedProperties": false | ||
| }, | ||
| "PongScoreBoard": { | ||
| "type": "object", | ||
| "allOf": [ | ||
|
|
@@ -156,6 +215,9 @@ | |
| }, | ||
| { | ||
| "$ref": "#/components/Column" | ||
| }, | ||
| { | ||
| "$ref": "#/components/WebAppFrameUrl" | ||
| } | ||
| ] | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,7 @@ import {McpApp} from './mcp-app'; | |
| import {PongScoreBoard} from './pong-scoreboard'; | ||
| import {PongLayout} from './pong-layout'; | ||
| import {Column} from '@a2ui/angular'; | ||
| import {WebAppFrameUrl} from './web-app-frame-url'; | ||
|
|
||
| /** | ||
| * The catalog ID for the MCP App catalog. | ||
|
|
@@ -53,6 +54,16 @@ const PongLayoutSchema = z.object({ | |
| scoreboardComponent: z.string().optional(), | ||
| }); | ||
|
|
||
| const WebAppFrameUrlSchema = z.object({ | ||
| url: DynamicStringSchema, | ||
| data: DynamicValueSchema.optional(), | ||
| height: DynamicNumberSchema.optional(), | ||
| allowedEvents: z.record(z.any()).optional(), | ||
| allowedFunctions: z.record(z.any()).optional(), | ||
| mutableData: z.record(z.any()).optional(), | ||
| disableSchemaValidation: z.boolean().optional(), | ||
| }); | ||
|
|
||
| export const SHOW_WINNER_MODAL_FN = createFunctionImplementation( | ||
| { | ||
| name: 'showWinnerModal', | ||
|
|
@@ -127,6 +138,7 @@ export const DEMO_CATALOG = new Catalog( | |
| {name: 'McpApp', component: McpApp, schema: McpAppSchema}, | ||
| {name: 'PongScoreBoard', component: PongScoreBoard, schema: PongScoreBoardSchema}, | ||
| {name: 'PongLayout', component: PongLayout, schema: PongLayoutSchema}, | ||
| {name: 'WebAppFrameUrl', component: WebAppFrameUrl, schema: WebAppFrameUrlSchema}, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @josemontesp is there some way in Angular that we the application developer could pass some configuration data to the Component when installing it in a catalog? I think it could be great for a developer to be able to set some static domain allowlist for these apps here, to statically protect the client against loading apps at arbitrary domains.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oooo This would be cool. Maintaining an allowlist on the client-side catalog would be a nice protection against Agent hallucination and compromised A2UI payloads coming from Agent/MCP servers.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Angular we could use injection tokens that are provided at the app root level, with an optional type-safe configuration. The component can then inject that configuration directly into the component class. |
||
| // Column should use ColumnApi.schema from @a2ui/web_core, but it is not currently | ||
| // exported by the version of @a2ui/web_core resolved in this community sample. | ||
| // We use z.any() to avoid duplicating the schema definition here. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.