Created a new agent to showcase the list of components in the std catalog. Also fixed a few component bugs#596
Created a new agent to showcase the list of components in the std catalog. Also fixed a few component bugs#596
Conversation
…ging on-the-wire a2UI JSON and actions
There was a problem hiding this comment.
Code Review
This pull request introduces a new component gallery sample, which is a valuable addition for demonstrating A2UI capabilities. The changes include a new agent, a Lit-based client, and improvements to existing UI components, notably a much-improved MultipleChoice component. While this is a great feature, there are several areas for improvement. The new code appears to have been partially copied from another sample, resulting in confusing naming and some irrelevant files that should be cleaned up. The new agent code also has some Python style guide violations. Finally, this large addition of functionality lacks corresponding tests for the agent logic, which is something to address per the repository's contribution guidelines.
| ]; | ||
|
|
||
| #setBoundValue(value: string[]) { | ||
| console.log(value); |
| from starlette.middleware.cors import CORSMiddleware | ||
| from dotenv import load_dotenv | ||
|
|
||
| from agent import ComponentGalleryAgent |
| from google.adk.agents.llm_agent import LlmAgent | ||
| from google.adk.artifacts import InMemoryArtifactService | ||
| from google.adk.memory.in_memory_memory_service import InMemoryMemoryService | ||
| from google.adk.runners import Runner | ||
| from google.adk.sessions import InMemorySessionService |
There was a problem hiding this comment.
| if "---a2ui_JSON---" in content: | ||
| text_content, json_string = content.split("---a2ui_JSON---", 1) | ||
| if text_content.strip(): | ||
| final_parts.append(Part(root=TextPart(text=text_content.strip()))) | ||
|
|
||
| if json_string.strip(): | ||
| try: | ||
| json_data = json.loads(json_string.strip()) | ||
| if isinstance(json_data, list): | ||
| for msg in json_data: | ||
| final_parts.append(create_a2ui_part(msg)) | ||
| else: | ||
| final_parts.append(create_a2ui_part(json_data)) | ||
| except Exception as e: | ||
| logger.error(f"Failed to parse JSON: {e}") |
There was a problem hiding this comment.
Using a custom string separator (---a2ui_JSON---) to embed JSON within a text response is fragile and not ideal. The A2A protocol is designed to handle mixed content by using multiple Part objects in a single message.
A more robust approach would be for the agent to yield a list of Part objects (e.g., a TextPart for text and one or more DataParts for the A2UI JSON). The executor could then process these parts directly without needing to perform string splitting and parsing, making the communication cleaner and less error-prone.
| if (isJson(originalBody)) { | ||
| console.log( | ||
| "[a2a-middleware] Received JSON UI event:", | ||
| originalBody | ||
| ); | ||
|
|
||
| const clientEvent = JSON.parse(originalBody); | ||
| sendParams = { | ||
| message: { | ||
| messageId: uuidv4(), | ||
| role: "user", | ||
| parts: [ | ||
| { | ||
| kind: "data", | ||
| data: clientEvent, | ||
| metadata: { 'mimeType': A2UI_MIME_TYPE }, | ||
| } as Part, | ||
| ], | ||
| kind: "message", | ||
| }, | ||
| }; | ||
| } else { | ||
| console.log( | ||
| "[a2a-middleware] Received text query:", | ||
| originalBody | ||
| ); | ||
| sendParams = { | ||
| message: { | ||
| messageId: uuidv4(), | ||
| role: "user", | ||
| parts: [ | ||
| { | ||
| kind: "text", | ||
| text: originalBody, | ||
| }, | ||
| ], | ||
| kind: "message", | ||
| }, | ||
| }; | ||
| } |
There was a problem hiding this comment.
The current logic for determining if the request body is JSON is inefficient because it results in parsing the string twice: once in isJson() and again to get clientEvent.
A more idiomatic and efficient approach is to use a single try-catch block. Attempt to parse the body, and if it succeeds, treat it as a JSON UI event. If it fails, catch the exception and treat the body as a plain text query. This avoids the redundant parsing.
try {
const clientEvent = JSON.parse(originalBody);
console.log(
"[a2a-middleware] Received JSON UI event:",
originalBody
);
sendParams = {
message: {
messageId: uuidv4(),
role: "user",
parts: [
{
kind: "data",
data: clientEvent,
metadata: { 'mimeType': A2UI_MIME_TYPE },
} as Part,
],
kind: "message",
},
};
} catch (e) {
console.log(
"[a2a-middleware] Received text query:",
originalBody
);
sendParams = {
message: {
messageId: uuidv4(),
role: "user",
parts: [
{
kind: "text",
text: originalBody,
},
],
kind: "message",
},
};
}|
Will be overhauling docs for this and other changes in a followup PR |
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
… into md-componentslistagent
jacobsimionato
left a comment
There was a problem hiding this comment.
I'm wondering if we can tweak the structure of this to try to aim for consistency and reduce the overall side of the code we are maintaining.
There are already a couple of examples of galleries:
-
Catalog gallery at
samples/client/angular/projects/gallery, see https://github.com/google/A2UI/blob/main/samples/client/angular/projects/gallery/src/app/features/library/library.component.ts -
AG-UI's composer has a gallery: #365, https://a2ui-composer.ag-ui.com/components
I do think it'd be nice to have a gallery for each renderer, so we can compare how they render. I believe the other two galleries use the React and Angular renderers, so there is value in creating a Lit sample. How about trying to follow the structure of the other apps, to aim for consistency? This might involve:
-
Building this as a client-only app rather than an agent + client. I'm not sure if the agent adds much value if it just outputs canned content.
-
Reusing the same sample content as the other gallery apps. I think AG-UI folk provided nice sample content. Maybe we can reuse that in the other galleries? Then it's easy to compare between them.

Description
Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.
List which issues are fixed by this PR. For larger changes, raising an issue first helps reduce redundant work.
Pre-launch Checklist
If you need help, consider asking for advice on the discussion board.