3939
4040 ```python
4141 # Simple boolean and dict
42- toolset = SendA2uiToClientToolset(a2ui_enabled=True, a2ui_schema=MY_SCHEMA )
42+ toolset = SendA2uiToClientToolset(a2ui_enabled=True, a2ui_catalog=MY_CATALOG )
4343
4444 # Async providers
4545 async def check_enabled(ctx: ReadonlyContext) -> bool:
4646 return await some_condition(ctx)
4747
48- async def get_schema (ctx: ReadonlyContext) -> dict[str, Any] :
49- return await fetch_schema (ctx)
48+ async def get_catalog (ctx: ReadonlyContext) -> A2uiCatalog :
49+ return await fetch_catalog (ctx)
5050
51- toolset = SendA2uiToClientToolset(a2ui_enabled=check_enabled, a2ui_schema=get_schema )
51+ toolset = SendA2uiToClientToolset(a2ui_enabled=check_enabled, a2ui_catalog=get_catalog )
5252 ```
5353
5454 2. Integration with Agent:
@@ -60,7 +60,7 @@ async def get_schema(ctx: ReadonlyContext) -> dict[str, Any]:
6060 tools=[
6161 SendA2uiToClientToolset(
6262 a2ui_enabled=True,
63- a2ui_schema=MY_SCHEMA
63+ a2ui_catalog=MY_CATALOG
6464 )
6565 ]
6666 )
@@ -87,7 +87,7 @@ async def get_schema(ctx: ReadonlyContext) -> dict[str, Any]:
8787
8888from a2a import types as a2a_types
8989from a2ui .extension .a2ui_extension import create_a2ui_part
90- from a2ui .extension . a2ui_schema_utils import wrap_as_json_array
90+ from a2ui .inference . schema . catalog import A2uiCatalog
9191from google .adk .a2a .converters import part_converter
9292from google .adk .agents .readonly_context import ReadonlyContext
9393from google .adk .models import LlmRequest
@@ -102,8 +102,11 @@ async def get_schema(ctx: ReadonlyContext) -> dict[str, Any]:
102102A2uiEnabledProvider : TypeAlias = Callable [
103103 [ReadonlyContext ], Union [bool , Awaitable [bool ]]
104104]
105- A2uiSchemaProvider : TypeAlias = Callable [
106- [ReadonlyContext ], Union [dict [str , Any ], Awaitable [dict [str , Any ]]]
105+ A2uiCatalogProvider : TypeAlias = Callable [
106+ [ReadonlyContext ], Union [A2uiCatalog , Awaitable [A2uiCatalog ]]
107+ ]
108+ A2uiExamplesProvider : TypeAlias = Callable [
109+ [ReadonlyContext ], Union [str , Awaitable [str ]]
107110]
108111
109112
@@ -114,11 +117,12 @@ class SendA2uiToClientToolset(base_toolset.BaseToolset):
114117 def __init__ (
115118 self ,
116119 a2ui_enabled : Union [bool , A2uiEnabledProvider ],
117- a2ui_schema : Union [dict [str , Any ], A2uiSchemaProvider ],
120+ a2ui_catalog : Union [A2uiCatalog , A2uiCatalogProvider ],
121+ a2ui_examples : Union [str , A2uiExamplesProvider ],
118122 ):
119123 super ().__init__ ()
120124 self ._a2ui_enabled = a2ui_enabled
121- self ._ui_tools = [self ._SendA2uiJsonToClientTool (a2ui_schema )]
125+ self ._ui_tools = [self ._SendA2uiJsonToClientTool (a2ui_catalog , a2ui_examples )]
122126
123127 async def _resolve_a2ui_enabled (self , ctx : ReadonlyContext ) -> bool :
124128 """The resolved self.a2ui_enabled field to construct instruction for this agent.
@@ -165,8 +169,13 @@ class _SendA2uiJsonToClientTool(BaseTool):
165169 A2UI_JSON_ARG_NAME = "a2ui_json"
166170 TOOL_ERROR_KEY = "error"
167171
168- def __init__ (self , a2ui_schema : Union [dict [str , Any ], A2uiSchemaProvider ]):
169- self ._a2ui_schema = a2ui_schema
172+ def __init__ (
173+ self ,
174+ a2ui_catalog : Union [A2uiCatalog , A2uiCatalogProvider ],
175+ a2ui_examples : Union [str , A2uiExamplesProvider ],
176+ ):
177+ self ._a2ui_catalog = a2ui_catalog
178+ self ._a2ui_examples = a2ui_examples
170179 super ().__init__ (
171180 name = self .TOOL_NAME ,
172181 description = (
@@ -196,34 +205,39 @@ def _get_declaration(self) -> genai_types.FunctionDeclaration | None:
196205 ),
197206 )
198207
199- async def _resolve_a2ui_schema (self , ctx : ReadonlyContext ) -> dict [ str , Any ] :
200- """The resolved self.a2ui_schema field to construct instruction for this agent.
208+ async def _resolve_a2ui_examples (self , ctx : ReadonlyContext ) -> str :
209+ """The resolved self.a2ui_examples field to construct instruction for this agent.
201210
202211 Args:
203212 ctx: The ReadonlyContext to resolve the provider with.
204213
205214 Returns:
206- The A2UI schema to send to the client .
215+ The A2UI examples string .
207216 """
208- if isinstance (self ._a2ui_schema , dict ):
209- return self ._a2ui_schema
217+ if isinstance (self ._a2ui_examples , str ):
218+ return self ._a2ui_examples
210219 else :
211- a2ui_schema = self ._a2ui_schema (ctx )
212- if inspect .isawaitable (a2ui_schema ):
213- a2ui_schema = await a2ui_schema
214- return a2ui_schema
220+ a2ui_examples = self ._a2ui_examples (ctx )
221+ if inspect .isawaitable (a2ui_examples ):
222+ a2ui_examples = await a2ui_examples
223+ return a2ui_examples
215224
216- async def get_a2ui_schema (self , ctx : ReadonlyContext ) -> dict [ str , Any ] :
217- """Retrieves and wraps the A2UI schema .
225+ async def _resolve_a2ui_catalog (self , ctx : ReadonlyContext ) -> A2uiCatalog :
226+ """The resolved self.a2ui_catalog field to construct instruction for this agent .
218227
219228 Args:
220- ctx: The ReadonlyContext for resolving the schema .
229+ ctx: The ReadonlyContext to resolve the provider with .
221230
222231 Returns:
223- The wrapped A2UI schema .
232+ The A2UI catalog object .
224233 """
225- a2ui_schema = await self ._resolve_a2ui_schema (ctx )
226- return wrap_as_json_array (a2ui_schema )
234+ if isinstance (self ._a2ui_catalog , A2uiCatalog ):
235+ return self ._a2ui_catalog
236+ else :
237+ a2ui_catalog = self ._a2ui_catalog (ctx )
238+ if inspect .isawaitable (a2ui_catalog ):
239+ a2ui_catalog = await a2ui_catalog
240+ return a2ui_catalog
227241
228242 async def process_llm_request (
229243 self , * , tool_context : ToolContext , llm_request : LlmRequest
@@ -232,15 +246,14 @@ async def process_llm_request(
232246 tool_context = tool_context , llm_request = llm_request
233247 )
234248
235- a2ui_schema = await self .get_a2ui_schema (tool_context )
249+ a2ui_catalog = await self ._resolve_a2ui_catalog (tool_context )
236250
237- llm_request .append_instructions ([f"""
238- ---BEGIN A2UI JSON SCHEMA---
239- { json .dumps (a2ui_schema )}
240- ---END A2UI JSON SCHEMA---
241- """ ])
251+ instruction = a2ui_catalog .render_as_llm_instructions ()
252+ examples = await self ._resolve_a2ui_examples (tool_context )
242253
243- logger .info ("Added a2ui_schema to system instructions" )
254+ llm_request .append_instructions ([instruction , examples ])
255+
256+ logger .info ("Added A2UI schema and examples to system instructions" )
244257
245258 async def run_async (
246259 self , * , args : dict [str , Any ], tool_context : ToolContext
@@ -253,44 +266,8 @@ async def run_async(
253266 f" arg { self .A2UI_JSON_ARG_NAME } "
254267 )
255268
256- a2ui_schema = await self .get_a2ui_schema (tool_context )
257-
258- try :
259- # Attempt to parse and validate
260- a2ui_json_payload = json .loads (a2ui_json )
261-
262- # Auto-wrap single object in list
263- if not isinstance (a2ui_json_payload , list ):
264- logger .info (
265- "Received a single JSON object, wrapping in a list for validation."
266- )
267- a2ui_json_payload = [a2ui_json_payload ]
268-
269- jsonschema .validate (instance = a2ui_json_payload , schema = a2ui_schema )
270-
271- except (jsonschema .exceptions .ValidationError , json .JSONDecodeError ) as e :
272- logger .warning (f"Initial A2UI JSON validation failed: { e } " )
273-
274- # Run Fixer
275- fixed_a2ui_json = re .sub (r",(?=\s*[\]}])" , "" , a2ui_json )
276-
277- if fixed_a2ui_json != a2ui_json :
278- # Emit Warning
279- logger .warning ("Detected trailing commas in LLM output; applied autofix." )
280-
281- # Re-parse and Re-validate
282- a2ui_json_payload = json .loads (fixed_a2ui_json )
283-
284- # Auto-wrap single object in list
285- if not isinstance (a2ui_json_payload , list ):
286- logger .info (
287- "Received a single JSON object, wrapping in a list for validation."
288- )
289- a2ui_json_payload = [a2ui_json_payload ]
290-
291- jsonschema .validate (instance = a2ui_json_payload , schema = a2ui_schema )
292- else :
293- raise e
269+ a2ui_catalog = await self ._resolve_a2ui_catalog (tool_context )
270+ a2ui_json_payload = a2ui_catalog .payload_fixer .fix (a2ui_json )
294271
295272 logger .info (
296273 f"Validated call to tool { self .TOOL_NAME } with { self .A2UI_JSON_ARG_NAME } "
0 commit comments