Skip to content

Commit 18d1ed3

Browse files
committed
Merge remote-tracking branch 'upstream/main' into fix-explorer-build-and-test
2 parents 471f694 + c712e0f commit 18d1ed3

131 files changed

Lines changed: 21965 additions & 78 deletions

File tree

Some content is hidden

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

agent_sdks/agent_sdk_guide.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ Once validated, the A2UI payload must be transmitted over the network. In typica
201201

202202
### Standards for Transport
203203

204-
1. **MIME Type**: Mark A2UI JSON payloads with `application/json+a2ui`. This tells the frontend renderer (e.g., the browser or mobile app) how to interpret the stream.
204+
1. **MIME Type**: Mark A2UI JSON payloads with `application/a2ui+json`. This tells the frontend renderer (e.g., the browser or mobile app) how to interpret the stream.
205205
2. **Standard Helpers**: Provide a `createA2uiPart` helper to automate this wrapping process.
206206
3. **Yielding Strategy**: Support both complete objects (when the LLM finishes speaking) and incremental streaming parser yielding (for partial JSON display).
207207

agent_sdks/conformance/suites/a2a_integration.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717
args:
1818
data: {"foo": "bar"}
1919
expect:
20-
mime_type: "application/json+a2ui"
20+
mime_type: "application/a2ui+json"
2121

2222
- name: test_is_a2ui_part
2323
action: is_a2ui_part
2424
args:
25-
mime_type: "application/json+a2ui"
25+
mime_type: "application/a2ui+json"
2626
expect: true
2727

2828
- name: test_try_activate_extension_success
@@ -58,7 +58,7 @@
5858
- kind: "text"
5959
text: "Here is your chart:"
6060
- kind: "data"
61-
mimeType: "application/json+a2ui"
61+
mimeType: "application/a2ui+json"
6262
data: {"beginRendering": {"surfaceId": "sales-dashboard"}}
6363
- kind: "text"
6464
text: "Enjoy!"

agent_sdks/kotlin/src/main/kotlin/com/google/a2ui/a2a/A2uiA2a.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,22 @@ import kotlinx.serialization.json.JsonElement
2626
object A2uiA2a {
2727
const val A2UI_EXTENSION_BASE_URI = "https://a2ui.org/a2a-extension/a2ui/v"
2828
const val MIME_TYPE_KEY = "mimeType"
29-
const val A2UI_MIME_TYPE = "application/json+a2ui"
29+
const val A2UI_MIME_TYPE = "application/a2ui+json"
30+
const val DEPRECATED_A2UI_MIME_TYPE = "application/json+a2ui"
3031

3132
/** Creates an A2A Part containing A2UI data. */
32-
fun createA2uiPart(a2uiData: JsonElement): Part<*> =
33-
DataPart(a2uiData, mapOf(MIME_TYPE_KEY to A2UI_MIME_TYPE))
33+
@JvmOverloads
34+
fun createA2uiPart(a2uiData: JsonElement, version: String? = null): Part<*> {
35+
val mimeType =
36+
if (version == "0.8" || version == "0.9") DEPRECATED_A2UI_MIME_TYPE else A2UI_MIME_TYPE
37+
return DataPart(a2uiData, mapOf(MIME_TYPE_KEY to mimeType))
38+
}
3439

3540
/** Checks if an A2A Part contains A2UI data. */
3641
fun isA2uiPart(part: Part<*>): Boolean =
37-
part is DataPart && part.metadata?.get(MIME_TYPE_KEY) == A2UI_MIME_TYPE
42+
part is DataPart &&
43+
(part.metadata?.get(MIME_TYPE_KEY) == A2UI_MIME_TYPE ||
44+
part.metadata?.get(MIME_TYPE_KEY) == DEPRECATED_A2UI_MIME_TYPE)
3845

3946
/** Extracts the A2UI data from an A2A Part if present. */
4047
fun getA2uiData(part: Part<*>): JsonElement? =

agent_sdks/kotlin/src/main/kotlin/com/google/a2ui/basic_catalog/BasicCatalogProvider.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class BundledCatalogProvider(private val version: A2uiVersion) : A2uiCatalogProv
4141
val filename =
4242
if (version == A2uiVersion.VERSION_0_9) {
4343
relPath.substringAfter("specification/v0_9/")
44+
} else if (version == A2uiVersion.VERSION_0_9_1) {
45+
relPath.substringAfter("specification/v0_9_1/")
4446
} else {
4547
relPath.substringAfterLast('/')
4648
}
@@ -81,6 +83,10 @@ object BasicCatalog {
8183
),
8284
A2uiVersion.VERSION_0_9 to
8385
mapOf(A2uiConstants.CATALOG_SCHEMA_KEY to "specification/v0_9/catalogs/basic/catalog.json"),
86+
A2uiVersion.VERSION_0_9_1 to
87+
mapOf(
88+
A2uiConstants.CATALOG_SCHEMA_KEY to "specification/v0_9_1/catalogs/basic/catalog.json"
89+
),
8490
)
8591

8692
/**

agent_sdks/kotlin/src/main/kotlin/com/google/a2ui/schema/A2uiConstants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ object A2uiConstants {
3838

3939
const val VERSION_0_8 = "0.8"
4040
const val VERSION_0_9 = "0.9"
41+
const val VERSION_0_9_1 = "0.9.1"
4142

4243
const val A2UI_OPEN_TAG = "<a2ui-json>"
4344
const val A2UI_CLOSE_TAG = "</a2ui-json>"

agent_sdks/kotlin/src/main/kotlin/com/google/a2ui/schema/A2uiSchemaManager.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum class A2uiVersion(
3030
) {
3131
VERSION_0_8(A2uiConstants.VERSION_0_8, "server_to_client.json"),
3232
VERSION_0_9(A2uiConstants.VERSION_0_9, "server_to_client.json", "common_types.json"),
33+
VERSION_0_9_1(A2uiConstants.VERSION_0_9_1, "server_to_client.json", "common_types.json"),
3334
}
3435

3536
/**

agent_sdks/python/agent_development.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ for part in response_parts:
169169

170170
**2. Stream the A2UI Payload**
171171

172-
Wrap the validated payloads in an A2A `DataPart` with the correct MIME type (`application/json+a2ui`) and stream it.
172+
Wrap the validated payloads in an A2A `DataPart` with the correct MIME type (`application/a2ui+json`) and stream it.
173173

174174
**Recommendation:** Use the `create_a2ui_part` helper.
175175

agent_sdks/python/src/a2ui/a2a/parts.py

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,29 @@
2626
logger = logging.getLogger(__name__)
2727

2828
MIME_TYPE_KEY = "mimeType"
29-
A2UI_MIME_TYPE = "application/json+a2ui"
29+
A2UI_MIME_TYPE = "application/a2ui+json"
30+
DEPRECATED_A2UI_MIME_TYPE = "application/json+a2ui"
3031

3132

32-
def create_a2ui_part(a2ui_data: dict[str, Any]) -> Part:
33+
def create_a2ui_part(a2ui_data: dict[str, Any], version: Optional[str] = None) -> Part:
3334
"""Creates an A2A Part containing A2UI data.
3435
3536
Args:
3637
a2ui_data: The A2UI data dictionary.
38+
version: Optional version string.
3739
3840
Returns:
3941
An A2A Part with a DataPart containing the A2UI data.
4042
"""
43+
mime_type = A2UI_MIME_TYPE
44+
if version in ("0.8", "0.9", "v0.8", "v0.9"):
45+
mime_type = DEPRECATED_A2UI_MIME_TYPE
46+
4147
return Part(
4248
root=DataPart(
4349
data=a2ui_data,
4450
metadata={
45-
MIME_TYPE_KEY: A2UI_MIME_TYPE,
51+
MIME_TYPE_KEY: mime_type,
4652
},
4753
)
4854
)
@@ -60,7 +66,8 @@ def is_a2ui_part(part: Part) -> bool:
6066
return (
6167
isinstance(part.root, DataPart)
6268
and part.root.metadata
63-
and part.root.metadata.get(MIME_TYPE_KEY) == A2UI_MIME_TYPE
69+
and part.root.metadata.get(MIME_TYPE_KEY)
70+
in (A2UI_MIME_TYPE, DEPRECATED_A2UI_MIME_TYPE)
6471
)
6572

6673

@@ -82,13 +89,15 @@ def parse_response_to_parts(
8289
content: str,
8390
validator: Optional[Any] = None,
8491
fallback_text: Optional[str] = None,
92+
version: Optional[str] = None,
8593
) -> List[Part]:
8694
"""Helper to parse LLM response content into A2A Parts, with optional validation.
8795
8896
Args:
8997
content: The LLM response content, potentially containing A2UI delimiters.
9098
validator: Optional validator to run against extracted JSON payloads.
9199
fallback_text: Optional text to return if no parts are successfully created.
100+
version: Optional version string.
92101
93102
Returns:
94103
A list of A2A Part objects (TextPart and/or DataPart).
@@ -110,9 +119,9 @@ def parse_response_to_parts(
110119

111120
if isinstance(json_data, list):
112121
for message in json_data:
113-
parts.append(create_a2ui_part(message))
122+
parts.append(create_a2ui_part(message, version=version))
114123
else:
115-
parts.append(create_a2ui_part(json_data))
124+
parts.append(create_a2ui_part(json_data, version=version))
116125

117126
except Exception as e:
118127
logger.warning(f"Failed to parse or validate A2UI response: {e}")
@@ -126,12 +135,14 @@ def parse_response_to_parts(
126135
async def stream_response_to_parts(
127136
parser: "A2uiStreamParser",
128137
token_stream: AsyncIterable[str],
138+
version: Optional[str] = None,
129139
) -> AsyncIterable[Part]:
130140
"""Helper to parse a stream of LLM tokens into A2A Parts incrementally.
131141
132142
Args:
133143
parser: A2uiStreamParser instance to process the stream.
134144
token_stream: An async iterable of strings (tokens).
145+
version: Optional version string.
135146
136147
Yields:
137148
A2A Part objects as they are discovered in the stream.
@@ -154,6 +165,6 @@ async def stream_response_to_parts(
154165

155166
if isinstance(json_data, list):
156167
for message in json_data:
157-
yield create_a2ui_part(message)
168+
yield create_a2ui_part(message, version=version)
158169
else:
159-
yield create_a2ui_part(json_data)
170+
yield create_a2ui_part(json_data, version=version)

agent_sdks/python/src/a2ui/basic_catalog/constants.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from ..schema.constants import CATALOG_SCHEMA_KEY, VERSION_0_8, VERSION_0_9
15+
from ..schema.constants import CATALOG_SCHEMA_KEY, VERSION_0_8, VERSION_0_9, VERSION_0_9_1
1616

1717
BASIC_CATALOG_NAME = "basic"
1818

@@ -22,4 +22,7 @@
2222
CATALOG_SCHEMA_KEY: "specification/v0_8/json/standard_catalog_definition.json"
2323
},
2424
VERSION_0_9: {CATALOG_SCHEMA_KEY: "specification/v0_9/catalogs/basic/catalog.json"},
25+
VERSION_0_9_1: {
26+
CATALOG_SCHEMA_KEY: "specification/v0_9_1/catalogs/basic/catalog.json"
27+
},
2528
}

agent_sdks/python/src/a2ui/schema/constants.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
VERSION_0_8 = "0.8"
3434
VERSION_0_9 = "0.9"
35+
VERSION_0_9_1 = "0.9.1"
3536

3637
SPEC_VERSION_MAP = {
3738
VERSION_0_8: {
@@ -41,6 +42,10 @@
4142
SERVER_TO_CLIENT_SCHEMA_KEY: "specification/v0_9/json/server_to_client.json",
4243
COMMON_TYPES_SCHEMA_KEY: "specification/v0_9/json/common_types.json",
4344
},
45+
VERSION_0_9_1: {
46+
SERVER_TO_CLIENT_SCHEMA_KEY: "specification/v0_9_1/json/server_to_client.json",
47+
COMMON_TYPES_SCHEMA_KEY: "specification/v0_9_1/json/common_types.json",
48+
},
4449
}
4550

4651
SPECIFICATION_DIR = "specification"

0 commit comments

Comments
 (0)