Create initial implementation for a2ui_agent. - #1020
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces the a2ui_agent package, which provides the A2UI Agent SDK including support for the Direct JSON inference format, streaming parsers, catalog document utilities, and payload validation. The review feedback highlights a critical syntax error in catalog_document.dart where invalid null-aware map syntax is used, and a medium-severity issue in streaming.dart regarding the use of a literal null character in a string literal.
Note: Security Review did not run due to the size of the PR.
|
If looks ok, I will resolve circlular dependencies. |
jacobsimionato
left a comment
There was a problem hiding this comment.
Hey this is looking great - nice work Polina and Gemini! It is a lot of code!
I'm actually finding it okay to review, because it's mostly about the interfaces. But I do wonder about trying to split it a little... e.g. you could probably omit the express format completely in the first PR for example.
I like Nan's idea of trying to do conformance tests up front too. Though they will only really test the implementation, and the more interesting part to review as a human is the APIs and how you've translated them to Dart. So maybe we can human-review the APIs here and not worry too much about the implementation, then add conformance tests and have an agent fix the implementations where necessary.
I dunno, curious about @nan-yu 's thoughts on the best process also. I'd like to make sure that both of us get a proper chance to review the APIs here, because they are important and difficult to change later.
| /// currently being streamed. Formats only implement [emitDelta], which is | ||
| /// handed the whole raw block accumulated so far and returns the messages that | ||
| /// have not been emitted yet. | ||
| abstract class IncrementalStreamProcessor { |
There was a problem hiding this comment.
This seems like a useful utility - I wonder if it should be in the shared design!
| /// Client functions execute on the renderer, so the agent side carries the | ||
| /// signature but cannot run it. [execute] throws to make an accidental | ||
| /// server-side invocation loud instead of silently wrong. | ||
| class DeclaredFunction extends FunctionImplementation { |
There was a problem hiding this comment.
I think we should instead handle FunctionApi and FunctionImplementation similar to how we handle ComponentApi and ComponentImplementation in the core library.
E.g. FunctionApi does not declare execute at all, and FunctionImplementation extends FunctionApi.
Then we have Catalog<C extends ComponentApi, F extends FunctionApi> perhaps.
There was a problem hiding this comment.
This should also be moved to the a2ui_core layer.
There was a problem hiding this comment.
@gspencergoog used ANTLR to generate the core parts of this for Python and Kotlin, based on some language definition file. Can we do that for Dart too? It seems supported - https://github.com/antlr/antlr4
There was a problem hiding this comment.
Also, feel free to omit the express stuff from the initial PR if you like - it's easy to add as a followup because it's behind a well-defined narrow interface (InferenceFormatFactory, InferenceFormat).
| /// [protocolVersion] and [catalogId], when given, must agree with what the | ||
| /// document declares; a conflict throws [A2uiValidationError] rather than | ||
| /// silently loading a catalog the renderer did not ask for. | ||
| Catalog<ComponentApi> catalogFromDocument( |
There was a problem hiding this comment.
I think the protocol version and catalog Id should be declared in the document anyway, right?
I think this should be implemented in the core library, possibly on the Catalog and Component classes / interfaces themselves.
There was a problem hiding this comment.
Yes, the Catalog class is designed to have from_json and catalog_schema, which builds a Catalog class from a JSON schema, and returns the catalog schema in JSON representation.
| /// | ||
| /// The key of the surrounding map describes the example turn; the value is the | ||
| /// A2UI payload the model is expected to produce for it. | ||
| typedef PromptExamples = Map<String, List<AgentToRendererMessage>>; |
| /// Optional few-shot example turns, keyed by a description of the turn. | ||
| final PromptExamples? examples; | ||
|
|
||
| const PromptGenerator(this.catalogs, {this.examples}); |
There was a problem hiding this comment.
I can't remember what is in the standard design, but I'm wondering if we maybe don't need to expose the catalogs or examples or define a constructor here. Instead, we just expose generate() and each inference format can implement this however it wants.
There was a problem hiding this comment.
@nan-yu if we don't have them already, let's add conformance tests requiring that each prompt generator implementation returns exactly the same prompt for a given catalog. Then we know that the eval work we do will translate across library implementations.
There was a problem hiding this comment.
We have it already in https://github.com/a2ui-project/a2ui/blob/a70e0ebc7ec37d848f1bd6194d10cc135efb5ab0/agent_sdks/conformance/suites/inference_format.yaml#L191.
Just a heads up, we're planning to restructure the conformance suite to be more modularized, but it will have same coverage.
|
Also, I think we reached consensus to do this in the A2uI repo, right? I know that was after you created this PR though! |
I am confused. I thought we have agreement to copy it to a2ui repo after a2ui repo is ready, together with a2ui_core, that is in monorepo with this code (see a2ui-project/a2ui#2234). Do you suggest to hold development? |
There was a problem hiding this comment.
This should belong to the Dart a2ui_core library, which maps the web_core version, https://github.com/a2ui-project/a2ui/blob/main/renderers/web_core/src/v0_9/schema/client-capabilities.ts#L55.
It actually brings up a broader issue. Should we update the Dart a2ui_core library first, and then build the a2ui_agent on the latest a2ui_core?
There was a problem hiding this comment.
The validation layer should also reside in the a2ui_core layer.
There was a problem hiding this comment.
We have it already in https://github.com/a2ui-project/a2ui/blob/a70e0ebc7ec37d848f1bd6194d10cc135efb5ab0/agent_sdks/conformance/suites/inference_format.yaml#L191.
Just a heads up, we're planning to restructure the conformance suite to be more modularized, but it will have same coverage.
|
|
||
| @override | ||
| Catalog<ComponentApi> load() { | ||
| if (protocolVersion == ProtocolVersion.v09) return MinimalCatalog(); |
There was a problem hiding this comment.
Why MinimalCatalog? Do we have a BasicCatalog in Dart?
| /// `package:a2ui_core` bundles the minimal catalog for `v0.9`. Other versions | ||
| /// have no bundled catalog in Dart yet, so asking for one is an error rather | ||
| /// than a silent fallback to a catalog the renderer never agreed to. | ||
| class BundledCatalogProvider extends CatalogProvider { |
There was a problem hiding this comment.
I forgot to update the blueprint when we decided to remove the BundledCatalogProvider class. Nothing needs to be bundled with the SDK. We can use the BasicCatalog directly from a2ui_core. I'll update the blueprint separately.
| /// Client functions execute on the renderer, so the agent side carries the | ||
| /// signature but cannot run it. [execute] throws to make an accidental | ||
| /// server-side invocation loud instead of silently wrong. | ||
| class DeclaredFunction extends FunctionImplementation { |
There was a problem hiding this comment.
This should also be moved to the a2ui_core layer.
| /// [protocolVersion] and [catalogId], when given, must agree with what the | ||
| /// document declares; a conflict throws [A2uiValidationError] rather than | ||
| /// silently loading a catalog the renderer did not ask for. | ||
| Catalog<ComponentApi> catalogFromDocument( |
There was a problem hiding this comment.
Yes, the Catalog class is designed to have from_json and catalog_schema, which builds a Catalog class from a JSON schema, and returns the catalog schema in JSON representation.
| import '../utils/schema_utils.dart'; | ||
|
|
||
| /// A single problem found in an A2UI payload. | ||
| class A2uiValidationIssue { |
There was a problem hiding this comment.
Can we rename to A2uiValidationError? It should also go to the a2ui_core layer.
| /// This is the agent SDK's validation layer. The A2UI agent specification | ||
| /// delegates it to `A2uiValidator` in the core package; | ||
| /// `package:a2ui_core` does not ship one yet, so the checks live here and | ||
| /// operate on the `v0.9` envelopes that package models. |
There was a problem hiding this comment.
The validator in a2ui_core should support validation against all protocol versions.
There was a problem hiding this comment.
Most of these unit tests should be moved to conformance spec, so we don't repeat for each implementation.
Prompt:
Use this blueprint to implement the library a2ui_agent: https://github.com/a2ui-project/a2ui/blob/main/blueprints/modules/a2ui_agent.blueprint.md
Next steps: