fix(v0_9): resolve v0.9.1 payload compatibility gap (Issue #1749)#1973
fix(v0_9): resolve v0.9.1 payload compatibility gap (Issue #1749)#1973Varun-S10 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request adds support for the v0.9.1 specification across the Angular, Lit, React, and Web Core renderers, including basic catalog alias resolution, Zod schema updates to accept both 'v0.9' and 'v0.9.1' versions, and package subpath exports. The feedback suggests improving the protocol version negotiation in MessageProcessor by advertising support for 'v0.9.1' in getClientCapabilities and dynamically returning the negotiated version in getClientDataModel instead of hardcoding 'v0.9'.
| const capabilities: A2uiClientCapabilities = { | ||
| 'v0.9': { | ||
| supportedCatalogIds: this.catalogs.map(c => c.id), | ||
| supportedCatalogIds: this.catalogs.flatMap(c => | ||
| c.aliases ? [c.id, ...c.aliases] : [c.id], | ||
| ), | ||
| }, | ||
| }; |
There was a problem hiding this comment.
To fully support v0.9.1 clients and servers, the getClientCapabilities method should also advertise support for the 'v0.9.1' protocol version in the returned capabilities object, rather than only advertising 'v0.9'. This ensures that v0.9.1 servers can correctly detect that the client supports this version during the capabilities exchange.
| const capabilities: A2uiClientCapabilities = { | |
| 'v0.9': { | |
| supportedCatalogIds: this.catalogs.map(c => c.id), | |
| supportedCatalogIds: this.catalogs.flatMap(c => | |
| c.aliases ? [c.id, ...c.aliases] : [c.id], | |
| ), | |
| }, | |
| }; | |
| const capabilities: Record<string, any> = { | |
| 'v0.9': { | |
| supportedCatalogIds: this.catalogs.flatMap(c => | |
| c.aliases ? [c.id, ...c.aliases] : [c.id], | |
| ), | |
| }, | |
| }; | |
| capabilities['v0.9.1'] = capabilities['v0.9']; |
There was a problem hiding this comment.
Yes, this would be needed.
| export const A2uiClientDataModelSchema = z | ||
| .object({ | ||
| version: z.literal('v0.9'), | ||
| version: z.enum(['v0.9', 'v0.9.1']), |
There was a problem hiding this comment.
Since A2uiClientDataModelSchema now allows both 'v0.9' and 'v0.9.1' versions, we should ensure that getClientDataModel() in MessageProcessor returns the correct negotiated version dynamically instead of hardcoding 'v0.9'. This prevents potential validation failures on the server side when interacting with a v0.9.1 server.
You can implement this by tracking the version of the last processed message in MessageProcessor (e.g., via a private property updated in processMessage) and returning that version in getClientDataModel().
| /** | ||
| * An optional array of alias URLs for the catalog. | ||
| */ | ||
| aliases?: readonly string[]; |
There was a problem hiding this comment.
This isn't correct, since the v0_9_1 catalog and the v0_9 catalog are different and aren't interchangable. They aren't aliases for each other, and need to be treated separately.
| id?: string; | ||
|
|
||
| /** | ||
| * An optional array of alias URLs for the catalog. |
There was a problem hiding this comment.
They're not necessarily URLs. They are often written that way, but they can be any string.
| const capabilities: A2uiClientCapabilities = { | ||
| 'v0.9': { | ||
| supportedCatalogIds: this.catalogs.map(c => c.id), | ||
| supportedCatalogIds: this.catalogs.flatMap(c => | ||
| c.aliases ? [c.id, ...c.aliases] : [c.id], | ||
| ), | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Yes, this would be needed.
|
|
||
| // `__dirname` will be `dist/src/v0_9/schema` when run via `node --test dist/**/*.test.js` | ||
| const SPEC_DIR_V0_9 = resolve(__dirname, '../../../../../../specification/v0_9/json'); | ||
| const SPEC_DIR_V0_9 = resolve(__dirname, '../../../../../../specification/v0_9_1/json'); |
There was a problem hiding this comment.
This effectively ignores the v0_9 directory. We should be testing them independently to make sure they are both still valid.
| "types": "./dist/src/v0_9/basic_catalog/index.d.ts", | ||
| "default": "./dist/src/v0_9/basic_catalog/index.js" | ||
| }, | ||
| "./v0_9_1": { |
There was a problem hiding this comment.
This treats the v0_9_1 catalog as if it were the v0_9 catalog. They do have differences, and so this should point to the v0_9_1 catalog.
There was a problem hiding this comment.
Why are there differences in the v0.9 and 0.9.1 catalogs? I thought 0.9.1 was only to release the mimetype update?
There was a problem hiding this comment.
Yeah, you're right, that's the only difference. Hmm. Maybe in this case the parsing of the catalogs is the same, but I'm thinking of it as "what if we release 0.9.2 and it has extra fields/components?" I don't see that happening for 0.9, but I'm pretty sure it will happen sometime soon, e.g. for v1.1.
I'm wary of just aliasing them like this becoming a pattern.
There was a problem hiding this comment.
I really think we should hide/remove any actual implementation code for v0.9.1, and just make 0.9 accept both 0.9 and 0.9.1. The aliasing of the catalog id should be a one-time only thing because of the way 0.9.1 was made (that I guess can live in the v0.9 directory only). Maybe we can leave instructions for agents not to replicate that pattern later? :)
|
|
||
| super(id, components, functions); | ||
| const aliases = options.aliases ?? [ | ||
| 'https://a2ui.org/specification/v0_9_1/catalogs/basic/catalog.json', |
There was a problem hiding this comment.
This is saying that if you have a v0_9 renderer you can render v0_9_1 content, and while that is often true (they are similar), where they are different, it will fail.
| "./v0_9_1": { | ||
| "import": { | ||
| "types": "./dist/v0_9/index.d.ts", | ||
| "default": "./dist/v0_9/index.js" | ||
| }, | ||
| "require": { | ||
| "types": "./dist/v0_9/index.d.cts", | ||
| "default": "./dist/v0_9/index.cjs" | ||
| } | ||
| }, |
There was a problem hiding this comment.
/cc @gspencergoog for example, I would not recommend adding this alias. People should be importing from v0_9 only.
As we discussed before, IMO the versions of the protocols shouldn't necessarily map to the versions of the renderers.
There was a problem hiding this comment.
Yes, I agree in this case that they are functionally the same unless you're using A2A. There is one other minor spec change besides the MIME change: in v0.9 the surfaceId had to be globally unique for the entire lifetime of the renderer, and in v0.9.1 it was relaxed so that the surfaceId only needs to be unique among currently active surfaces. But I think that's backward compatible by design.
I'm OK with just using 0.9 code for 0.9.1 (and 0.9) everywhere except A2A support, but we should probably restructure the spec itself so that there isn't duplication and so it makes it abundantly clear that this is a special case and not the norm. I'm pretty sure that from now on dot releases will contain additional features.
|
I took a stab at some of this here: #1993 |
Description
This PR adds support for v0.9.1 protocol payloads in the
v0_9runtime acrossweb_core,react,lit, andangular. Previously, the runtime rejected v0.9.1 messages because of hard-coded version strings and missing catalog aliases.What changed:
"v0.9"to"v0.9" | "v0.9.1".MessageProcessorso surfaces referencing the v0.9.1 basic catalog URL resolve correctly../v0_9_1package subpath exports toweb_core,react, andlit.This change is 100% backward compatible and does not affect any existing v0.9 features.
Fixes #1749
Pre-launch Checklist
One time:
For this PR:
If you need help, consider asking for advice on the discussion board.