Skip to content

Commit 63819d0

Browse files
authored
Merge branch 'main' into add-react-renderer
2 parents c1e0b59 + 8f541b7 commit 63819d0

File tree

230 files changed

+29818
-8688
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

230 files changed

+29818
-8688
lines changed

.github/CODEOWNERS

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# CODEOWNERS file
2+
#
3+
# It allows us to define individuals or teams that are responsible for code in the repository.
4+
#
5+
# Syntax:
6+
# pattern owner1 owner2
7+
#
8+
# The pattern is a glob pattern relative to the root of the repository.
9+
# Owners can be:
10+
# - A GitHub username (e.g., @octocat)
11+
# - An organization team (e.g., @org/team-name)
12+
# - An email address (e.g., octocat@github.com)
13+
14+
# Default ownership (is overriden by specfic rules below)
15+
* @dmandar @gspencergoog @jacobsimionato
16+
17+
# Agents
18+
/a2a_agents/ @nan-yu @dmandar
19+
20+
# Documentation
21+
/docs/ @zeroasterisk @dmandar @gspencer @jacobsimionato
22+
23+
# Renderers
24+
/renderers/angular/ @ditman @ava-cassiopeia @crisbeto
25+
/renderers/lit/ @ditman @ava-cassiopeia @paullewis
26+
/renderers/web_core/ @ditman @ava-cassiopeia
27+
28+
# Samples
29+
/samples/ @dmandar @zeroasterisk
30+
31+
# Specifications
32+
/specification/ @gspencergoog @jacobsimionato
33+
34+
# Tools
35+
/tools/ @dmandar @jacobsimionato @paullewis

.github/workflows/docs.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,18 @@ jobs:
7272
- name: Validate documentation conversion script
7373
run: pip install pytest && pytest docs/scripts/test_convert_docs.py
7474

75+
- name: Copy schemas to documentation
76+
run: |
77+
cp -R specification/* docs/specification/
78+
# Flatten JSON files to version roots to support clean URLs without redirects
79+
for version in v0_8 v0_9; do
80+
if [ -d "docs/specification/$version/json" ]; then
81+
cp docs/specification/$version/json/*.json docs/specification/$version/
82+
fi
83+
done
84+
7585
- name: Convert Admonitions in Documentation
76-
run: python docs/scripts/convert_docs.py --mode github-to-mkdocs
86+
run: python docs/scripts/convert_docs.py
7787

7888
- name: Build Documentation (PR Check)
7989
if: github.event_name == 'pull_request'

.github/workflows/python_a2ui_agent_build_and_test.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,14 @@ jobs:
4646
working-directory: a2a_agents/python/a2ui_agent
4747
run: uv run pyink --check .
4848

49+
- name: Run unit tests
50+
working-directory: a2a_agents/python/a2ui_agent
51+
run: uv run --with pytest pytest tests/
52+
4953
- name: Build the python SDK
5054
working-directory: a2a_agents/python/a2ui_agent
5155
run: uv build .
5256

53-
- name: Run unit tests
57+
- name: Run validation scripts on assets packing
5458
working-directory: a2a_agents/python/a2ui_agent
55-
run: uv run --with pytest pytest tests/
59+
run: uv run python tests/integration/verify_load_real.py

.github/workflows/python_samples_build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ jobs:
4545
python -m pip install --upgrade pip
4646
pip install uv
4747
48+
- name: Check Formatting
49+
working-directory: samples/agent/adk
50+
run: uv run pyink --check .
51+
4852
- name: Build contact_lookup
4953
working-directory: samples/agent/adk/contact_lookup
5054
run: uv build .
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
src/a2ui/assets/**/*.json
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import importlib.util
16+
import os
17+
import shutil
18+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
19+
20+
21+
def load_constants(project_root):
22+
"""Loads the shared constants module directly from its path in src/."""
23+
constants_path = os.path.join(
24+
project_root, "src", "a2ui", "inference", "schema", "constants.py"
25+
)
26+
if not os.path.exists(constants_path):
27+
raise RuntimeError(f"Could not find shared constants at {constants_path}")
28+
29+
spec = importlib.util.spec_from_file_location("_constants_load", constants_path)
30+
if spec and spec.loader:
31+
module = importlib.util.module_from_spec(spec)
32+
spec.loader.exec_module(module)
33+
return module
34+
raise RuntimeError(f"Could not load shared constants from {constants_path}")
35+
36+
37+
class PackSpecsBuildHook(BuildHookInterface):
38+
39+
def initialize(self, version, build_data):
40+
project_root = self.root
41+
42+
# Load constants dynamically from src/a2ui/inference/schema/constants.py
43+
a2ui_constants = load_constants(project_root)
44+
45+
spec_version_map = a2ui_constants.SPEC_VERSION_MAP
46+
a2ui_asset_package = a2ui_constants.A2UI_ASSET_PACKAGE
47+
specification_dir = a2ui_constants.SPECIFICATION_DIR
48+
49+
# project root is in a2a_agents/python/a2ui_agent
50+
# Dynamically find repo root by looking for specification_dir
51+
repo_root = a2ui_constants.find_repo_root(project_root)
52+
if not repo_root:
53+
# Check for PKG-INFO which implies a packaged state (sdist).
54+
# If PKG-INFO is present, trust the bundled assets.
55+
if os.path.exists(os.path.join(project_root, "PKG-INFO")):
56+
print("Repository root not found, but PKG-INFO present (sdist). Skipping copy.")
57+
return
58+
59+
raise RuntimeError(
60+
f"Could not find repository root (looked for '{specification_dir}'"
61+
" directory)."
62+
)
63+
64+
# Target directory: src/a2ui/assets
65+
target_base = os.path.join(
66+
project_root, "src", a2ui_asset_package.replace(".", os.sep)
67+
)
68+
69+
for ver, schema_map in spec_version_map.items():
70+
target_dir = os.path.join(target_base, ver)
71+
os.makedirs(target_dir, exist_ok=True)
72+
73+
for _schema_key, source_rel_path in schema_map.items():
74+
source_path = os.path.join(repo_root, source_rel_path)
75+
76+
if not os.path.exists(source_path):
77+
print(
78+
f"WARNING: Source schema file not found at {source_path}. Build"
79+
" might produce incomplete wheel if not running from monorepo"
80+
" root."
81+
)
82+
continue
83+
84+
filename = os.path.basename(source_path)
85+
dst_file = os.path.join(target_dir, filename)
86+
87+
print(f"Copying {source_path} -> {dst_file}")
88+
shutil.copy2(source_path, dst_file)

a2a_agents/python/a2ui_agent/pyproject.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,18 @@ dependencies = [
1212
]
1313

1414
[build-system]
15-
requires = ["hatchling"]
15+
requires = ["hatchling", "jsonschema"]
1616
build-backend = "hatchling.build"
1717

1818
[tool.hatch.build.targets.wheel]
1919
packages = ["src/a2ui"]
20+
artifacts = ["src/a2ui/assets/**"]
21+
22+
[tool.hatch.build.targets.sdist]
23+
artifacts = ["src/a2ui/assets/**"]
24+
25+
[tool.hatch.build.hooks.custom]
26+
path = "pack_specs_hook.py"
2027

2128
[[tool.uv.index]]
2229
url = "https://pypi.org/simple"

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ async def get_schema(ctx: ReadonlyContext) -> dict[str, Any]:
8787
from a2a import types as a2a_types
8888
from a2ui.extension.a2ui_extension import create_a2ui_part
8989
from a2ui.extension.a2ui_schema_utils import wrap_as_json_array
90+
from a2ui.extension.validation import validate_a2ui_json
9091
from google.adk.a2a.converters import part_converter
9192
from google.adk.agents.readonly_context import ReadonlyContext
9293
from google.adk.models import LlmRequest
@@ -262,7 +263,7 @@ async def run_async(
262263
a2ui_json_payload = [a2ui_json_payload]
263264

264265
a2ui_schema = await self.get_a2ui_schema(tool_context)
265-
jsonschema.validate(instance=a2ui_json_payload, schema=a2ui_schema)
266+
validate_a2ui_json(a2ui_json_payload, a2ui_schema)
266267

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

0 commit comments

Comments
 (0)