Skip to content

Commit 1c5447b

Browse files
authored
Merge branch 'google:main' into feat/evaluate-full-response
2 parents af1c183 + 5195ba7 commit 1c5447b

16 files changed

Lines changed: 333 additions & 50 deletions
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "1.29.0"
2+
".": "1.30.0"
33
}

.github/release-please-config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
3-
"last-release-sha": "6b1600fbf53bcf634c5fe4793f02921bc0b75125",
3+
"last-release-sha": "80a7ecf4b31e4c6de4a1425b03422f384c1a032d",
44
"packages": {
55
".": {
66
"release-type": "python",

CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
# Changelog
22

3+
## [1.30.0](https://github.com/google/adk-python/compare/v1.29.0...v1.30.0) (2026-04-13)
4+
5+
6+
### Features
7+
8+
* Add Auth Provider support to agent registry ([f2c68eb](https://github.com/google/adk-python/commit/f2c68eb1536f1c0018c2cf7ee3f4417ca442080c))
9+
* Add Parameter Manager integration to ADK ([b0715d7](https://github.com/google/adk-python/commit/b0715d77a2a433bb2ed07a2475cc4d1f2d662b6c))
10+
* Add support for Gemma 4 models in ADK ([9d4ecbe](https://github.com/google/adk-python/commit/9d4ecbe9fd1141693e4682cbfe4d542cc62b76ac)), closes [#5156](https://github.com/google/adk-python/issues/5156)
11+
* allow users to include artifacts from artifact_service in A2A events using provided interceptor ([e63d991](https://github.com/google/adk-python/commit/e63d991be84e373fd31be29d4b6b0e32fdbde557))
12+
* emit a `TaskStatusUpdateEvent` for ADK events with no output parts but with event.actions ([dcc485b](https://github.com/google/adk-python/commit/dcc485b23e3509e2e386636d841033b91c9a401c))
13+
* Live avatar support in ADK ([a64a8e4](https://github.com/google/adk-python/commit/a64a8e46480753439b91b9cfd41fd190b4dad493))
14+
* **live:** expose live_session_resumption_update as Event in BaseLlmFlow ([2626ad7](https://github.com/google/adk-python/commit/2626ad7c69fb64a88372225d5583085fc08b1fcd)), closes [#4357](https://github.com/google/adk-python/issues/4357)
15+
* Promote BigQuery tools to Stable ([abcf14c](https://github.com/google/adk-python/commit/abcf14c166baf4f8cc6e919b1eb4c063bf3a92af))
16+
* **samples:** add sample for skill activation via environment tools ([2cbb523](https://github.com/google/adk-python/commit/2cbb52306910fac994fe1d29bdfcfacb258703b4))
17+
18+
19+
### Bug Fixes
20+
21+
* Add "gcloud config unset project" command to express mode flow ([e7d8160](https://github.com/google/adk-python/commit/e7d81604126cbdb4d9ee4624e1d1410b06585750))
22+
* avoid load all agents in adk web server ([cb4dd42](https://github.com/google/adk-python/commit/cb4dd42eff2df6d20c5e53211718ecb023f127fc))
23+
* Change express mode user flow so it's more clear that an express mode project is being created ([0fedb3b](https://github.com/google/adk-python/commit/0fedb3b5eb2074999d8ccdb839e054ea80da486f))
24+
* Custom pickling in McpToolset to exclude unpicklable objects like errlog ([d62558c](https://github.com/google/adk-python/commit/d62558cc2d7d6c0372e43c9f009c8c7a6863ff0a))
25+
* Fix credential leakage vulnerability in Agent Registry ([e3567a6](https://github.com/google/adk-python/commit/e3567a65196bb453cdac4a5ae42f7f079476d748))
26+
* Include a link to the deployed agent ([547766a](https://github.com/google/adk-python/commit/547766a47779915a8a47745237a46882a02dae9a))
27+
* preserve interaction ids for interactions SSE tool calls ([9a19304](https://github.com/google/adk-python/commit/9a1930407a4eff67093ea9f14292f1931631a661)), closes [#5169](https://github.com/google/adk-python/issues/5169)
28+
* validate user_id and session_id against path traversal ([cbcb5e6](https://github.com/google/adk-python/commit/cbcb5e6002b5bae89de5309caf7b9bb02d563cfc)), closes [#5110](https://github.com/google/adk-python/issues/5110)
29+
330
## [1.29.0](https://github.com/google/adk-python/compare/v1.28.0...v1.29.0) (2026-04-09)
431

532

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ dependencies = [
4444
"google-cloud-spanner>=3.56.0, <4.0.0", # For Spanner database
4545
"google-cloud-speech>=2.30.0, <3.0.0", # For Audio Transcription
4646
"google-cloud-storage>=2.18.0, <4.0.0", # For GCS Artifact service
47-
"google-genai>=1.64.0, <2.0.0", # Google GenAI SDK
47+
"google-genai>=1.72.0, <2.0.0", # Google GenAI SDK
4848
"graphviz>=0.20.2, <1.0.0", # Graphviz for graph rendering
4949
"httpx>=0.27.0, <1.0.0", # HTTP client library
5050
"jsonschema>=4.23.0, <5.0.0", # Agent Builder config validation

src/google/adk/agents/run_config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ class RunConfig(BaseModel):
198198
response_modalities: Optional[list[str]] = None
199199
"""The output modalities. If not set, it's default to AUDIO."""
200200

201+
avatar_config: Optional[types.AvatarConfig] = None
202+
"""Avatar configuration for the live agent."""
203+
201204
save_input_blobs_as_artifacts: bool = Field(
202205
default=False,
203206
deprecated=True,

src/google/adk/flows/llm_flows/basic.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ def _build_basic_request(
9090
llm_request.live_connect_config.context_window_compression = (
9191
invocation_context.run_config.context_window_compression
9292
)
93+
llm_request.live_connect_config.avatar_config = (
94+
invocation_context.run_config.avatar_config
95+
)
9396

9497

9598
class _BasicLlmRequestProcessor(BaseLlmRequestProcessor):

src/google/adk/models/gemini_llm_connection.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,7 @@ async def send_content(self, content: types.Content):
115115
is_gemini_31 = model_name_utils.is_gemini_3_1_flash_live(
116116
self._model_version
117117
)
118-
is_gemini_api = self._api_backend == GoogleLLMVariant.GEMINI_API
119-
120-
# As of now, Gemini 3.1 Flash Live is only available in Gemini API, not
121-
# Vertex AI.
122-
if (
123-
is_gemini_31
124-
and is_gemini_api
125-
and len(content.parts) == 1
126-
and content.parts[0].text
127-
):
118+
if is_gemini_31 and len(content.parts) == 1 and content.parts[0].text:
128119
logger.debug('Using send_realtime_input for Gemini 3.1 text input')
129120
await self._gemini_session.send_realtime_input(
130121
text=content.parts[0].text
@@ -149,11 +140,7 @@ async def send_realtime(self, input: RealtimeInput):
149140
is_gemini_31 = model_name_utils.is_gemini_3_1_flash_live(
150141
self._model_version
151142
)
152-
is_gemini_api = self._api_backend == GoogleLLMVariant.GEMINI_API
153-
154-
# As of now, Gemini 3.1 Flash Live is only available in Gemini API, not
155-
# Vertex AI.
156-
if is_gemini_31 and is_gemini_api:
143+
if is_gemini_31:
157144
if input.mime_type and input.mime_type.startswith('audio/'):
158145
await self._gemini_session.send_realtime_input(audio=input)
159146
elif input.mime_type and input.mime_type.startswith('image/'):

src/google/adk/sessions/vertex_ai_session_service.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ async def append_event(self, session: Session, event: Event) -> Event:
270270

271271
reasoning_engine_id = self._get_reasoning_engine_id(session.app_name)
272272

273+
# Build config (Monolithic approach)
273274
config = {}
274275
if event.content:
275276
config['content'] = event.content.model_dump(
@@ -286,9 +287,6 @@ async def append_event(self, session: Session, event: Event) -> Event:
286287
k: json.loads(v.model_dump_json(exclude_none=True, by_alias=True))
287288
for k, v in event.actions.requested_auth_configs.items()
288289
},
289-
# TODO: add requested_tool_confirmations, agent_state once
290-
# they are available in the API.
291-
# Note: compaction is stored via event_metadata.custom_metadata.
292290
}
293291
if event.error_code:
294292
config['error_code'] = event.error_code
@@ -311,10 +309,8 @@ async def append_event(self, session: Session, event: Event) -> Event:
311309
metadata_dict['grounding_metadata'] = event.grounding_metadata.model_dump(
312310
exclude_none=True, mode='json'
313311
)
314-
# Store compaction data in custom_metadata since the Vertex AI service
315-
# does not yet support the compaction field.
316-
# TODO: Stop writing to custom_metadata once the Vertex AI service
317-
# supports the compaction field natively in EventActions.
312+
313+
# ALWAYS write to custom_metadata
318314
if event.actions and event.actions.compaction:
319315
compaction_dict = event.actions.compaction.model_dump(
320316
exclude_none=True, mode='json'
@@ -324,8 +320,6 @@ async def append_event(self, session: Session, event: Event) -> Event:
324320
key=_COMPACTION_CUSTOM_METADATA_KEY,
325321
value=compaction_dict,
326322
)
327-
# Store usage_metadata in custom_metadata since the Vertex AI service
328-
# does not persist it in EventMetadata.
329323
if event.usage_metadata:
330324
usage_dict = event.usage_metadata.model_dump(
331325
exclude_none=True, mode='json'
@@ -335,7 +329,12 @@ async def append_event(self, session: Session, event: Event) -> Event:
335329
key=_USAGE_METADATA_CUSTOM_METADATA_KEY,
336330
value=usage_dict,
337331
)
332+
338333
config['event_metadata'] = metadata_dict
334+
335+
# Persist the full event state using raw_event. If the client-side SDK
336+
# does not support this field, it will raise a ValidationError, and we
337+
# will fall back to legacy field-based storage.
339338
config['raw_event'] = event.model_dump(
340339
exclude_none=True,
341340
mode='json',
@@ -345,7 +344,8 @@ async def append_event(self, session: Session, event: Event) -> Event:
345344
# Retry without raw_event if client side validation fails for older SDK
346345
# versions.
347346
async with self._get_api_client() as api_client:
348-
try:
347+
348+
async def _do_append(cfg: dict[str, Any]):
349349
await api_client.agent_engines.sessions.events.append(
350350
name=(
351351
f'reasoningEngines/{reasoning_engine_id}/sessions/{session.id}'
@@ -355,22 +355,16 @@ async def append_event(self, session: Session, event: Event) -> Event:
355355
timestamp=datetime.datetime.fromtimestamp(
356356
event.timestamp, tz=datetime.timezone.utc
357357
),
358-
config=config,
358+
config=cfg,
359359
)
360+
361+
try:
362+
await _do_append(config)
360363
except pydantic.ValidationError:
364+
logger.warning('Vertex SDK does not support raw_event, falling back.')
361365
if 'raw_event' in config:
362366
del config['raw_event']
363-
await api_client.agent_engines.sessions.events.append(
364-
name=(
365-
f'reasoningEngines/{reasoning_engine_id}/sessions/{session.id}'
366-
),
367-
author=event.author,
368-
invocation_id=event.invocation_id,
369-
timestamp=datetime.datetime.fromtimestamp(
370-
event.timestamp, tz=datetime.timezone.utc
371-
),
372-
config=config,
373-
)
367+
await _do_append(config)
374368
return event
375369

376370
def _get_reasoning_engine_id(self, app_name: str):
@@ -429,8 +423,8 @@ def _get_raw_event(api_event_obj: Any) -> dict[str, Any] | None:
429423

430424
def _from_api_event(api_event_obj: vertexai.types.SessionEvent) -> Event:
431425
"""Converts an API event object to an Event object."""
432-
# Read event data from raw_event first before falling back to top level
433-
# fields.
426+
# Prioritize reading from raw_event to restore full state. Fall back to
427+
# top-level fields for older data that lacks raw_event.
434428
raw_event_dict = _get_raw_event(api_event_obj)
435429
if raw_event_dict:
436430
event_dict = copy.deepcopy(raw_event_dict)
@@ -439,8 +433,9 @@ def _from_api_event(api_event_obj: vertexai.types.SessionEvent) -> Event:
439433
'id': api_event_obj.name.split('/')[-1],
440434
'invocation_id': getattr(api_event_obj, 'invocation_id', None),
441435
'author': getattr(api_event_obj, 'author', None),
442-
'timestamp': timestamp_obj.timestamp() if timestamp_obj else None,
443436
})
437+
if timestamp_obj:
438+
event_dict['timestamp'] = timestamp_obj.timestamp()
444439
return Event.model_validate(event_dict)
445440

446441
actions = getattr(api_event_obj, 'actions', None)
@@ -514,6 +509,13 @@ def _from_api_event(api_event_obj: vertexai.types.SessionEvent) -> Event:
514509
usage_metadata_data
515510
)
516511

512+
timestamp_obj = getattr(api_event_obj, 'timestamp', None)
513+
timestamp = (
514+
timestamp_obj.timestamp()
515+
if timestamp_obj
516+
else datetime.datetime.now(datetime.timezone.utc).timestamp()
517+
)
518+
517519
return Event(
518520
id=api_event_obj.name.split('/')[-1],
519521
invocation_id=api_event_obj.invocation_id,
@@ -522,7 +524,7 @@ def _from_api_event(api_event_obj: vertexai.types.SessionEvent) -> Event:
522524
content=_session_util.decode_model(
523525
getattr(api_event_obj, 'content', None), types.Content
524526
),
525-
timestamp=api_event_obj.timestamp.timestamp(),
527+
timestamp=timestamp,
526528
error_code=getattr(api_event_obj, 'error_code', None),
527529
error_message=getattr(api_event_obj, 'error_message', None),
528530
partial=partial,

src/google/adk/tools/_automatic_function_calling_util.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ def from_function_with_options(
368368
parameters_json_schema[name] = types.Schema.model_validate(
369369
json_schema_dict
370370
)
371+
if param.default is not inspect.Parameter.empty:
372+
if param.default is not None:
373+
parameters_json_schema[name].default = param.default
374+
else:
375+
parameters_json_schema[name].nullable = True
371376
except Exception as e:
372377
_function_parameter_parse_util._raise_for_unsupported_param(
373378
param, func.__name__, e
@@ -392,6 +397,11 @@ def from_function_with_options(
392397
type='OBJECT',
393398
properties=parameters_json_schema,
394399
)
400+
declaration.parameters.required = (
401+
_function_parameter_parse_util._get_required_fields(
402+
declaration.parameters
403+
)
404+
)
395405

396406
if variant == GoogleLLMVariant.GEMINI_API:
397407
return declaration

src/google/adk/utils/model_name_utils.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,6 @@ def is_gemini_2_or_above(model_string: Optional[str]) -> bool:
130130
def is_gemini_3_1_flash_live(model_string: Optional[str]) -> bool:
131131
"""Check if the model is a Gemini 3.1 Flash Live model.
132132
133-
Note: This is a very specific model name for live bidi streaming, so we check
134-
for exact match.
135-
136133
Args:
137134
model_string: The model name
138135
@@ -141,5 +138,4 @@ def is_gemini_3_1_flash_live(model_string: Optional[str]) -> bool:
141138
"""
142139
if not model_string:
143140
return False
144-
145-
return model_string == 'gemini-3.1-flash-live-preview'
141+
return model_string.startswith('gemini-3.1-flash-live')

0 commit comments

Comments
 (0)