Skip to content

Commit f398270

Browse files
committed
Update the rizzcharts sample
It updates the sample to use the A2uiSchemaManager from the a2ui-agent python SDK. Tested: - [x] The `rizzcharts` Angular client successfully connected to the `rizzcharts` agent and rendered the response correctly.
1 parent 4bd12e5 commit f398270

8 files changed

Lines changed: 220 additions & 354 deletions

File tree

a2a_agents/python/a2ui_agent/src/a2ui/extension/send_a2ui_to_client_toolset.py

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@
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
)
@@ -86,7 +86,7 @@ async def get_schema(ctx: ReadonlyContext) -> dict[str, Any]:
8686

8787
from a2a import types as a2a_types
8888
from a2ui.extension.a2ui_extension import create_a2ui_part
89-
from a2ui.extension.a2ui_schema_utils import wrap_as_json_array
89+
from a2ui.inference.schema.catalog import A2uiCatalog
9090
from google.adk.a2a.converters import part_converter
9191
from google.adk.agents.readonly_context import ReadonlyContext
9292
from google.adk.models import LlmRequest
@@ -101,8 +101,11 @@ async def get_schema(ctx: ReadonlyContext) -> dict[str, Any]:
101101
A2uiEnabledProvider: TypeAlias = Callable[
102102
[ReadonlyContext], Union[bool, Awaitable[bool]]
103103
]
104-
A2uiSchemaProvider: TypeAlias = Callable[
105-
[ReadonlyContext], Union[dict[str, Any], Awaitable[dict[str, Any]]]
104+
A2uiCatalogProvider: TypeAlias = Callable[
105+
[ReadonlyContext], Union[A2uiCatalog, Awaitable[A2uiCatalog]]
106+
]
107+
A2uiExamplesProvider: TypeAlias = Callable[
108+
[ReadonlyContext], Union[str, Awaitable[str]]
106109
]
107110

108111

@@ -113,11 +116,12 @@ class SendA2uiToClientToolset(base_toolset.BaseToolset):
113116
def __init__(
114117
self,
115118
a2ui_enabled: Union[bool, A2uiEnabledProvider],
116-
a2ui_schema: Union[dict[str, Any], A2uiSchemaProvider],
119+
a2ui_catalog: Union[A2uiCatalog, A2uiCatalogProvider],
120+
a2ui_examples: Union[str, A2uiExamplesProvider],
117121
):
118122
super().__init__()
119123
self._a2ui_enabled = a2ui_enabled
120-
self._ui_tools = [self._SendA2uiJsonToClientTool(a2ui_schema)]
124+
self._ui_tools = [self._SendA2uiJsonToClientTool(a2ui_catalog, a2ui_examples)]
121125

122126
async def _resolve_a2ui_enabled(self, ctx: ReadonlyContext) -> bool:
123127
"""The resolved self.a2ui_enabled field to construct instruction for this agent.
@@ -164,8 +168,13 @@ class _SendA2uiJsonToClientTool(BaseTool):
164168
A2UI_JSON_ARG_NAME = "a2ui_json"
165169
TOOL_ERROR_KEY = "error"
166170

167-
def __init__(self, a2ui_schema: Union[dict[str, Any], A2uiSchemaProvider]):
168-
self._a2ui_schema = a2ui_schema
171+
def __init__(
172+
self,
173+
a2ui_catalog: Union[A2uiCatalog, A2uiCatalogProvider],
174+
a2ui_examples: Union[str, A2uiExamplesProvider],
175+
):
176+
self._a2ui_catalog = a2ui_catalog
177+
self._a2ui_examples = a2ui_examples
169178
super().__init__(
170179
name=self.TOOL_NAME,
171180
description=(
@@ -195,34 +204,39 @@ def _get_declaration(self) -> genai_types.FunctionDeclaration | None:
195204
),
196205
)
197206

198-
async def _resolve_a2ui_schema(self, ctx: ReadonlyContext) -> dict[str, Any]:
199-
"""The resolved self.a2ui_schema field to construct instruction for this agent.
207+
async def _resolve_a2ui_examples(self, ctx: ReadonlyContext) -> str:
208+
"""The resolved self.a2ui_examples field to construct instruction for this agent.
200209
201210
Args:
202211
ctx: The ReadonlyContext to resolve the provider with.
203212
204213
Returns:
205-
The A2UI schema to send to the client.
214+
The A2UI examples string.
206215
"""
207-
if isinstance(self._a2ui_schema, dict):
208-
return self._a2ui_schema
216+
if isinstance(self._a2ui_examples, str):
217+
return self._a2ui_examples
209218
else:
210-
a2ui_schema = self._a2ui_schema(ctx)
211-
if inspect.isawaitable(a2ui_schema):
212-
a2ui_schema = await a2ui_schema
213-
return a2ui_schema
219+
a2ui_examples = self._a2ui_examples(ctx)
220+
if inspect.isawaitable(a2ui_examples):
221+
a2ui_examples = await a2ui_examples
222+
return a2ui_examples
214223

215-
async def get_a2ui_schema(self, ctx: ReadonlyContext) -> dict[str, Any]:
216-
"""Retrieves and wraps the A2UI schema.
224+
async def _resolve_a2ui_catalog(self, ctx: ReadonlyContext) -> A2uiCatalog:
225+
"""The resolved self.a2ui_catalog field to construct instruction for this agent.
217226
218227
Args:
219-
ctx: The ReadonlyContext for resolving the schema.
228+
ctx: The ReadonlyContext to resolve the provider with.
220229
221230
Returns:
222-
The wrapped A2UI schema.
231+
The A2UI catalog object.
223232
"""
224-
a2ui_schema = await self._resolve_a2ui_schema(ctx)
225-
return wrap_as_json_array(a2ui_schema)
233+
if isinstance(self._a2ui_catalog, A2uiCatalog):
234+
return self._a2ui_catalog
235+
else:
236+
a2ui_catalog = self._a2ui_catalog(ctx)
237+
if inspect.isawaitable(a2ui_catalog):
238+
a2ui_catalog = await a2ui_catalog
239+
return a2ui_catalog
226240

227241
async def process_llm_request(
228242
self, *, tool_context: ToolContext, llm_request: LlmRequest
@@ -231,15 +245,14 @@ async def process_llm_request(
231245
tool_context=tool_context, llm_request=llm_request
232246
)
233247

234-
a2ui_schema = await self.get_a2ui_schema(tool_context)
248+
a2ui_catalog = await self._resolve_a2ui_catalog(tool_context)
249+
250+
instruction = a2ui_catalog.render_as_llm_instructions()
251+
examples = await self._resolve_a2ui_examples(tool_context)
235252

236-
llm_request.append_instructions([f"""
237-
---BEGIN A2UI JSON SCHEMA---
238-
{json.dumps(a2ui_schema)}
239-
---END A2UI JSON SCHEMA---
240-
"""])
253+
llm_request.append_instructions([instruction, examples])
241254

242-
logger.info("Added a2ui_schema to system instructions")
255+
logger.info("Added A2UI schema and examples to system instructions")
243256

244257
async def run_async(
245258
self, *, args: dict[str, Any], tool_context: ToolContext
@@ -261,8 +274,9 @@ async def run_async(
261274
)
262275
a2ui_json_payload = [a2ui_json_payload]
263276

264-
a2ui_schema = await self.get_a2ui_schema(tool_context)
265-
jsonschema.validate(instance=a2ui_json_payload, schema=a2ui_schema)
277+
a2ui_catalog = await self._resolve_a2ui_catalog(tool_context)
278+
279+
a2ui_catalog.validator.validate(a2ui_json_payload)
266280

267281
logger.info(
268282
f"Validated call to tool {self.TOOL_NAME} with {self.A2UI_JSON_ARG_NAME}"

renderers/lit/package-lock.json

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

renderers/web_core/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/agent/adk/rizzcharts/__main__.py

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
from a2a.server.apps import A2AStarletteApplication
2222
from a2a.server.request_handlers import DefaultRequestHandler
2323
from a2a.server.tasks import InMemoryTaskStore
24-
from agent_executor import RizzchartsAgentExecutor, get_a2ui_enabled, get_a2ui_schema
24+
from a2ui.inference.schema.manager import A2uiSchemaManager, CustomCatalogConfig
25+
from agent_executor import RizzchartsAgentExecutor, get_a2ui_enabled, get_a2ui_catalog, get_a2ui_examples
2526
from agent import RizzchartsAgent
2627
from google.adk.artifacts import InMemoryArtifactService
2728
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
@@ -54,10 +55,27 @@ def main(host, port):
5455
)
5556

5657
lite_llm_model = os.getenv("LITELLM_MODEL", "gemini/gemini-2.5-flash")
58+
59+
base_url = f"http://{host}:{port}"
60+
61+
schema_manager = A2uiSchemaManager(
62+
version="0.8",
63+
basic_examples_path="examples/standard_catalog",
64+
custom_catalogs=[CustomCatalogConfig(
65+
name="rizzcharts",
66+
catalog_path="rizzcharts_catalog_definition.json",
67+
examples_path="examples/rizzcharts_catalog"
68+
)],
69+
accepts_inline_catalogs=True,
70+
)
71+
5772
agent = RizzchartsAgent(
73+
base_url=base_url,
5874
model=LiteLlm(model=lite_llm_model),
75+
schema_manager=schema_manager,
5976
a2ui_enabled_provider=get_a2ui_enabled,
60-
a2ui_schema_provider=get_a2ui_schema,
77+
a2ui_catalog_provider=get_a2ui_catalog,
78+
a2ui_examples_provider=get_a2ui_examples,
6179
)
6280
runner = Runner(
6381
app_name=agent.name,
@@ -67,38 +85,18 @@ def main(host, port):
6785
memory_service=InMemoryMemoryService(),
6886
)
6987

70-
current_dir = pathlib.Path(__file__).resolve().parent
71-
spec_root = current_dir / "../../../../specification/v0_8/json"
72-
73-
try:
74-
a2ui_schema_content = (spec_root / "server_to_client.json").read_text()
75-
standard_catalog_content = (
76-
spec_root / "standard_catalog_definition.json"
77-
).read_text()
78-
rizzcharts_catalog_content = (
79-
current_dir / "rizzcharts_catalog_definition.json"
80-
).read_text()
81-
except FileNotFoundError as e:
82-
logger.error(f"Failed to load required JSON files: {e}")
83-
exit(1)
84-
85-
logger.info(f"Loaded schema from {spec_root}")
86-
87-
base_url = f"http://{host}:{port}"
8888
agent_executor = RizzchartsAgentExecutor(
8989
base_url=base_url,
9090
runner=runner,
91-
a2ui_schema_content=a2ui_schema_content,
92-
standard_catalog_content=standard_catalog_content,
93-
rizzcharts_catalog_content=rizzcharts_catalog_content,
91+
schema_manager=schema_manager,
9492
)
9593

9694
request_handler = DefaultRequestHandler(
9795
agent_executor=agent_executor,
9896
task_store=InMemoryTaskStore(),
9997
)
10098
server = A2AStarletteApplication(
101-
agent_card=agent_executor.get_agent_card(), http_handler=request_handler
99+
agent_card=agent.get_agent_card(), http_handler=request_handler
102100
)
103101
import uvicorn
104102

0 commit comments

Comments
 (0)