@@ -80,6 +80,7 @@ async def get_schema(ctx: ReadonlyContext) -> dict[str, Any]:
8080import inspect
8181import json
8282import logging
83+ import re
8384from typing import Any , Awaitable , Callable , Optional , TypeAlias , Union
8485
8586import jsonschema
@@ -252,17 +253,27 @@ async def run_async(
252253 f" arg { self .A2UI_JSON_ARG_NAME } "
253254 )
254255
255- a2ui_json_payload = json .loads (a2ui_json )
256+ a2ui_schema = await self .get_a2ui_schema (tool_context )
257+ try :
258+ # Attempt to parse and validate
259+ a2ui_json_payload = json .loads (a2ui_json )
260+ jsonschema .validate (instance = a2ui_json_payload , schema = a2ui_schema )
256261
257- # Auto-wrap single object in list
258- if not isinstance (a2ui_json_payload , list ):
259- logger .info (
260- "Received a single JSON object, wrapping in a list for validation."
261- )
262- a2ui_json_payload = [a2ui_json_payload ]
262+ except (jsonschema .exceptions .ValidationError , json .JSONDecodeError ) as e :
263+ logger .warning (f"Initial A2UI JSON validation failed: { e } " )
263264
264- a2ui_schema = await self .get_a2ui_schema (tool_context )
265- jsonschema .validate (instance = a2ui_json_payload , schema = a2ui_schema )
265+ # Run Fixer
266+ fixed_a2ui_json = re .sub (r",(?=\s*[\]}])" , "" , a2ui_json )
267+
268+ if fixed_a2ui_json != a2ui_json :
269+ # Emit Warning
270+ logger .warning ("Detected trailing commas in LLM output; applied autofix." )
271+
272+ # Re-parse and Re-validate
273+ a2ui_json_payload = json .loads (fixed_a2ui_json )
274+ jsonschema .validate (instance = a2ui_json_payload , schema = a2ui_schema )
275+ else :
276+ raise e
266277
267278 logger .info (
268279 f"Validated call to tool { self .TOOL_NAME } with { self .A2UI_JSON_ARG_NAME } "
@@ -328,4 +339,4 @@ def convert_send_a2ui_to_client_genai_part_to_a2a_part(
328339 converted_part = part_converter .convert_genai_part_to_a2a_part (part )
329340
330341 logger .info (f"Returning converted part: { converted_part } " )
331- return [converted_part ] if converted_part else []
342+ return [converted_part ] if converted_part else []
0 commit comments