google-adk 1.4.1__py3-none-any.whl → 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. google/adk/a2a/converters/event_converter.py +382 -0
  2. google/adk/a2a/converters/part_converter.py +4 -2
  3. google/adk/a2a/converters/request_converter.py +90 -0
  4. google/adk/a2a/converters/utils.py +71 -0
  5. google/adk/agents/llm_agent.py +5 -3
  6. google/adk/artifacts/gcs_artifact_service.py +3 -2
  7. google/adk/auth/auth_tool.py +2 -2
  8. google/adk/auth/credential_service/session_state_credential_service.py +83 -0
  9. google/adk/cli/cli_deploy.py +9 -2
  10. google/adk/cli/cli_tools_click.py +110 -52
  11. google/adk/cli/fast_api.py +26 -2
  12. google/adk/cli/utils/evals.py +53 -0
  13. google/adk/evaluation/final_response_match_v1.py +110 -0
  14. google/adk/evaluation/gcs_eval_sets_manager.py +8 -5
  15. google/adk/evaluation/response_evaluator.py +12 -1
  16. google/adk/events/event.py +5 -5
  17. google/adk/flows/llm_flows/contents.py +49 -4
  18. google/adk/flows/llm_flows/functions.py +32 -0
  19. google/adk/memory/__init__.py +3 -1
  20. google/adk/memory/vertex_ai_memory_bank_service.py +150 -0
  21. google/adk/models/lite_llm.py +9 -1
  22. google/adk/runners.py +10 -0
  23. google/adk/sessions/vertex_ai_session_service.py +70 -19
  24. google/adk/telemetry.py +10 -0
  25. google/adk/tools/bigquery/bigquery_credentials.py +28 -11
  26. google/adk/tools/bigquery/bigquery_tool.py +1 -1
  27. google/adk/tools/bigquery/client.py +1 -1
  28. google/adk/tools/bigquery/metadata_tool.py +1 -1
  29. google/adk/tools/bigquery/query_tool.py +1 -1
  30. google/adk/version.py +1 -1
  31. {google_adk-1.4.1.dist-info → google_adk-1.5.0.dist-info}/METADATA +6 -5
  32. {google_adk-1.4.1.dist-info → google_adk-1.5.0.dist-info}/RECORD +35 -29
  33. {google_adk-1.4.1.dist-info → google_adk-1.5.0.dist-info}/WHEEL +0 -0
  34. {google_adk-1.4.1.dist-info → google_adk-1.5.0.dist-info}/entry_points.txt +0 -0
  35. {google_adk-1.4.1.dist-info → google_adk-1.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,382 @@
1
+ # Copyright 2025 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
+ # http://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
+ from __future__ import annotations
16
+
17
+ import datetime
18
+ import logging
19
+ from typing import Any
20
+ from typing import Dict
21
+ from typing import List
22
+ from typing import Optional
23
+ import uuid
24
+
25
+ from a2a.server.events import Event as A2AEvent
26
+ from a2a.types import Artifact
27
+ from a2a.types import DataPart
28
+ from a2a.types import Message
29
+ from a2a.types import Role
30
+ from a2a.types import TaskArtifactUpdateEvent
31
+ from a2a.types import TaskState
32
+ from a2a.types import TaskStatus
33
+ from a2a.types import TaskStatusUpdateEvent
34
+ from a2a.types import TextPart
35
+
36
+ from ...agents.invocation_context import InvocationContext
37
+ from ...events.event import Event
38
+ from ...utils.feature_decorator import working_in_progress
39
+ from .part_converter import A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL
40
+ from .part_converter import A2A_DATA_PART_METADATA_TYPE_KEY
41
+ from .part_converter import convert_genai_part_to_a2a_part
42
+ from .utils import _get_adk_metadata_key
43
+
44
+ # Constants
45
+
46
+ ARTIFACT_ID_SEPARATOR = "-"
47
+ DEFAULT_ERROR_MESSAGE = "An error occurred during processing"
48
+
49
+ # Logger
50
+ logger = logging.getLogger("google_adk." + __name__)
51
+
52
+
53
+ def _serialize_metadata_value(value: Any) -> str:
54
+ """Safely serializes metadata values to string format.
55
+
56
+ Args:
57
+ value: The value to serialize.
58
+
59
+ Returns:
60
+ String representation of the value.
61
+ """
62
+ if hasattr(value, "model_dump"):
63
+ try:
64
+ return value.model_dump(exclude_none=True, by_alias=True)
65
+ except Exception as e:
66
+ logger.warning("Failed to serialize metadata value: %s", e)
67
+ return str(value)
68
+ return str(value)
69
+
70
+
71
+ def _get_context_metadata(
72
+ event: Event, invocation_context: InvocationContext
73
+ ) -> Dict[str, str]:
74
+ """Gets the context metadata for the event.
75
+
76
+ Args:
77
+ event: The ADK event to extract metadata from.
78
+ invocation_context: The invocation context containing session information.
79
+
80
+ Returns:
81
+ A dictionary containing the context metadata.
82
+
83
+ Raises:
84
+ ValueError: If required fields are missing from event or context.
85
+ """
86
+ if not event:
87
+ raise ValueError("Event cannot be None")
88
+ if not invocation_context:
89
+ raise ValueError("Invocation context cannot be None")
90
+
91
+ try:
92
+ metadata = {
93
+ _get_adk_metadata_key("app_name"): invocation_context.app_name,
94
+ _get_adk_metadata_key("user_id"): invocation_context.user_id,
95
+ _get_adk_metadata_key("session_id"): invocation_context.session.id,
96
+ _get_adk_metadata_key("invocation_id"): event.invocation_id,
97
+ _get_adk_metadata_key("author"): event.author,
98
+ }
99
+
100
+ # Add optional metadata fields if present
101
+ optional_fields = [
102
+ ("branch", event.branch),
103
+ ("grounding_metadata", event.grounding_metadata),
104
+ ("custom_metadata", event.custom_metadata),
105
+ ("usage_metadata", event.usage_metadata),
106
+ ("error_code", event.error_code),
107
+ ]
108
+
109
+ for field_name, field_value in optional_fields:
110
+ if field_value is not None:
111
+ metadata[_get_adk_metadata_key(field_name)] = _serialize_metadata_value(
112
+ field_value
113
+ )
114
+
115
+ return metadata
116
+
117
+ except Exception as e:
118
+ logger.error("Failed to create context metadata: %s", e)
119
+ raise
120
+
121
+
122
+ def _create_artifact_id(
123
+ app_name: str, user_id: str, session_id: str, filename: str, version: int
124
+ ) -> str:
125
+ """Creates a unique artifact ID.
126
+
127
+ Args:
128
+ app_name: The application name.
129
+ user_id: The user ID.
130
+ session_id: The session ID.
131
+ filename: The artifact filename.
132
+ version: The artifact version.
133
+
134
+ Returns:
135
+ A unique artifact ID string.
136
+ """
137
+ components = [app_name, user_id, session_id, filename, str(version)]
138
+ return ARTIFACT_ID_SEPARATOR.join(components)
139
+
140
+
141
+ def _convert_artifact_to_a2a_events(
142
+ event: Event,
143
+ invocation_context: InvocationContext,
144
+ filename: str,
145
+ version: int,
146
+ ) -> TaskArtifactUpdateEvent:
147
+ """Converts a new artifact version to an A2A TaskArtifactUpdateEvent.
148
+
149
+ Args:
150
+ event: The ADK event containing the artifact information.
151
+ invocation_context: The invocation context.
152
+ filename: The name of the artifact file.
153
+ version: The version number of the artifact.
154
+
155
+ Returns:
156
+ A TaskArtifactUpdateEvent representing the artifact update.
157
+
158
+ Raises:
159
+ ValueError: If required parameters are invalid.
160
+ RuntimeError: If artifact loading fails.
161
+ """
162
+ if not filename:
163
+ raise ValueError("Filename cannot be empty")
164
+ if version < 0:
165
+ raise ValueError("Version must be non-negative")
166
+
167
+ try:
168
+ artifact_part = invocation_context.artifact_service.load_artifact(
169
+ app_name=invocation_context.app_name,
170
+ user_id=invocation_context.user_id,
171
+ session_id=invocation_context.session.id,
172
+ filename=filename,
173
+ version=version,
174
+ )
175
+
176
+ converted_part = convert_genai_part_to_a2a_part(part=artifact_part)
177
+ if not converted_part:
178
+ raise RuntimeError(f"Failed to convert artifact part for {filename}")
179
+
180
+ artifact_id = _create_artifact_id(
181
+ invocation_context.app_name,
182
+ invocation_context.user_id,
183
+ invocation_context.session.id,
184
+ filename,
185
+ version,
186
+ )
187
+
188
+ return TaskArtifactUpdateEvent(
189
+ taskId=str(uuid.uuid4()),
190
+ append=False,
191
+ contextId=invocation_context.session.id,
192
+ lastChunk=True,
193
+ artifact=Artifact(
194
+ artifactId=artifact_id,
195
+ name=filename,
196
+ metadata={
197
+ "filename": filename,
198
+ "version": version,
199
+ },
200
+ parts=[converted_part],
201
+ ),
202
+ )
203
+ except Exception as e:
204
+ logger.error(
205
+ "Failed to convert artifact for %s, version %s: %s",
206
+ filename,
207
+ version,
208
+ e,
209
+ )
210
+ raise RuntimeError(f"Artifact conversion failed: {e}") from e
211
+
212
+
213
+ def _process_long_running_tool(a2a_part, event: Event) -> None:
214
+ """Processes long-running tool metadata for an A2A part.
215
+
216
+ Args:
217
+ a2a_part: The A2A part to potentially mark as long-running.
218
+ event: The ADK event containing long-running tool information.
219
+ """
220
+ if (
221
+ isinstance(a2a_part.root, DataPart)
222
+ and event.long_running_tool_ids
223
+ and a2a_part.root.metadata.get(
224
+ _get_adk_metadata_key(A2A_DATA_PART_METADATA_TYPE_KEY)
225
+ )
226
+ == A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL
227
+ and a2a_part.root.metadata.get("id") in event.long_running_tool_ids
228
+ ):
229
+ a2a_part.root.metadata[_get_adk_metadata_key("is_long_running")] = True
230
+
231
+
232
+ @working_in_progress
233
+ def convert_event_to_a2a_status_message(
234
+ event: Event, invocation_context: InvocationContext
235
+ ) -> Optional[Message]:
236
+ """Converts an ADK event to an A2A message.
237
+
238
+ Args:
239
+ event: The ADK event to convert.
240
+ invocation_context: The invocation context.
241
+
242
+ Returns:
243
+ An A2A Message if the event has content, None otherwise.
244
+
245
+ Raises:
246
+ ValueError: If required parameters are invalid.
247
+ """
248
+ if not event:
249
+ raise ValueError("Event cannot be None")
250
+ if not invocation_context:
251
+ raise ValueError("Invocation context cannot be None")
252
+
253
+ if not event.content or not event.content.parts:
254
+ return None
255
+
256
+ try:
257
+ a2a_parts = []
258
+ for part in event.content.parts:
259
+ a2a_part = convert_genai_part_to_a2a_part(part)
260
+ if a2a_part:
261
+ a2a_parts.append(a2a_part)
262
+ _process_long_running_tool(a2a_part, event)
263
+
264
+ if a2a_parts:
265
+ return Message(
266
+ messageId=str(uuid.uuid4()), role=Role.agent, parts=a2a_parts
267
+ )
268
+
269
+ except Exception as e:
270
+ logger.error("Failed to convert event to status message: %s", e)
271
+ raise
272
+
273
+ return None
274
+
275
+
276
+ def _create_error_status_event(
277
+ event: Event, invocation_context: InvocationContext
278
+ ) -> TaskStatusUpdateEvent:
279
+ """Creates a TaskStatusUpdateEvent for error scenarios.
280
+
281
+ Args:
282
+ event: The ADK event containing error information.
283
+ invocation_context: The invocation context.
284
+
285
+ Returns:
286
+ A TaskStatusUpdateEvent with FAILED state.
287
+ """
288
+ error_message = getattr(event, "error_message", None) or DEFAULT_ERROR_MESSAGE
289
+
290
+ return TaskStatusUpdateEvent(
291
+ taskId=str(uuid.uuid4()),
292
+ contextId=invocation_context.session.id,
293
+ final=False,
294
+ metadata=_get_context_metadata(event, invocation_context),
295
+ status=TaskStatus(
296
+ state=TaskState.failed,
297
+ message=Message(
298
+ messageId=str(uuid.uuid4()),
299
+ role=Role.agent,
300
+ parts=[TextPart(text=error_message)],
301
+ ),
302
+ timestamp=datetime.datetime.now().isoformat(),
303
+ ),
304
+ )
305
+
306
+
307
+ def _create_running_status_event(
308
+ message: Message, invocation_context: InvocationContext, event: Event
309
+ ) -> TaskStatusUpdateEvent:
310
+ """Creates a TaskStatusUpdateEvent for running scenarios.
311
+
312
+ Args:
313
+ message: The A2A message to include.
314
+ invocation_context: The invocation context.
315
+ event: The ADK event.
316
+
317
+ Returns:
318
+ A TaskStatusUpdateEvent with RUNNING state.
319
+ """
320
+ return TaskStatusUpdateEvent(
321
+ taskId=str(uuid.uuid4()),
322
+ contextId=invocation_context.session.id,
323
+ final=False,
324
+ status=TaskStatus(
325
+ state=TaskState.working,
326
+ message=message,
327
+ timestamp=datetime.datetime.now().isoformat(),
328
+ ),
329
+ metadata=_get_context_metadata(event, invocation_context),
330
+ )
331
+
332
+
333
+ @working_in_progress
334
+ def convert_event_to_a2a_events(
335
+ event: Event, invocation_context: InvocationContext
336
+ ) -> List[A2AEvent]:
337
+ """Converts a GenAI event to a list of A2A events.
338
+
339
+ Args:
340
+ event: The ADK event to convert.
341
+ invocation_context: The invocation context.
342
+
343
+ Returns:
344
+ A list of A2A events representing the converted ADK event.
345
+
346
+ Raises:
347
+ ValueError: If required parameters are invalid.
348
+ """
349
+ if not event:
350
+ raise ValueError("Event cannot be None")
351
+ if not invocation_context:
352
+ raise ValueError("Invocation context cannot be None")
353
+
354
+ a2a_events = []
355
+
356
+ try:
357
+ # Handle artifact deltas
358
+ if event.actions.artifact_delta:
359
+ for filename, version in event.actions.artifact_delta.items():
360
+ artifact_event = _convert_artifact_to_a2a_events(
361
+ event, invocation_context, filename, version
362
+ )
363
+ a2a_events.append(artifact_event)
364
+
365
+ # Handle error scenarios
366
+ if event.error_code:
367
+ error_event = _create_error_status_event(event, invocation_context)
368
+ a2a_events.append(error_event)
369
+
370
+ # Handle regular message content
371
+ message = convert_event_to_a2a_status_message(event, invocation_context)
372
+ if message:
373
+ running_event = _create_running_status_event(
374
+ message, invocation_context, event
375
+ )
376
+ a2a_events.append(running_event)
377
+
378
+ except Exception as e:
379
+ logger.error("Failed to convert event to A2A events: %s", e)
380
+ raise
381
+
382
+ return a2a_events
@@ -23,6 +23,8 @@ import logging
23
23
  import sys
24
24
  from typing import Optional
25
25
 
26
+ from .utils import _get_adk_metadata_key
27
+
26
28
  try:
27
29
  from a2a import types as a2a_types
28
30
  except ImportError as e:
@@ -84,7 +86,7 @@ def convert_a2a_part_to_genai_part(
84
86
  # logic accordinlgy
85
87
  if part.metadata and A2A_DATA_PART_METADATA_TYPE_KEY in part.metadata:
86
88
  if (
87
- part.metadata[A2A_DATA_PART_METADATA_TYPE_KEY]
89
+ part.metadata[_get_adk_metadata_key(A2A_DATA_PART_METADATA_TYPE_KEY)]
88
90
  == A2A_DATA_PART_METADATA_TYPE_FUNCTION_CALL
89
91
  ):
90
92
  return genai_types.Part(
@@ -93,7 +95,7 @@ def convert_a2a_part_to_genai_part(
93
95
  )
94
96
  )
95
97
  if (
96
- part.metadata[A2A_DATA_PART_METADATA_TYPE_KEY]
98
+ part.metadata[_get_adk_metadata_key(A2A_DATA_PART_METADATA_TYPE_KEY)]
97
99
  == A2A_DATA_PART_METADATA_TYPE_FUNCTION_RESPONSE
98
100
  ):
99
101
  return genai_types.Part(
@@ -0,0 +1,90 @@
1
+ # Copyright 2025 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
+ # http://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
+ from __future__ import annotations
16
+
17
+ import sys
18
+ from typing import Any
19
+
20
+ try:
21
+ from a2a.server.agent_execution import RequestContext
22
+ except ImportError as e:
23
+ if sys.version_info < (3, 10):
24
+ raise ImportError(
25
+ 'A2A Tool requires Python 3.10 or above. Please upgrade your Python'
26
+ ' version.'
27
+ ) from e
28
+ else:
29
+ raise e
30
+
31
+ from google.genai import types as genai_types
32
+
33
+ from ...runners import RunConfig
34
+ from ...utils.feature_decorator import working_in_progress
35
+ from .part_converter import convert_a2a_part_to_genai_part
36
+ from .utils import _from_a2a_context_id
37
+ from .utils import _get_adk_metadata_key
38
+
39
+
40
+ def _get_user_id(request: RequestContext, user_id_from_context: str) -> str:
41
+ # Get user from call context if available (auth is enabled on a2a server)
42
+ if request.call_context and request.call_context.user:
43
+ return request.call_context.user.user_name
44
+
45
+ # Get user from context id if available
46
+ if user_id_from_context:
47
+ return user_id_from_context
48
+
49
+ # Get user from message metadata if available (client is an ADK agent)
50
+ if request.message.metadata:
51
+ user_id = request.message.metadata.get(_get_adk_metadata_key('user_id'))
52
+ if user_id:
53
+ return f'ADK_USER_{user_id}'
54
+
55
+ # Get user from task if available (client is a an ADK agent)
56
+ if request.current_task:
57
+ user_id = request.current_task.metadata.get(
58
+ _get_adk_metadata_key('user_id')
59
+ )
60
+ if user_id:
61
+ return f'ADK_USER_{user_id}'
62
+ return (
63
+ f'temp_user_{request.task_id}'
64
+ if request.task_id
65
+ else f'TEMP_USER_{request.message.messageId}'
66
+ )
67
+
68
+
69
+ @working_in_progress
70
+ def convert_a2a_request_to_adk_run_args(
71
+ request: RequestContext,
72
+ ) -> dict[str, Any]:
73
+
74
+ if not request.message:
75
+ raise ValueError('Request message cannot be None')
76
+
77
+ _, user_id, session_id = _from_a2a_context_id(request.context_id)
78
+
79
+ return {
80
+ 'user_id': _get_user_id(request, user_id),
81
+ 'session_id': session_id,
82
+ 'new_message': genai_types.Content(
83
+ role='user',
84
+ parts=[
85
+ convert_a2a_part_to_genai_part(part)
86
+ for part in request.message.parts
87
+ ],
88
+ ),
89
+ 'run_config': RunConfig(),
90
+ }
@@ -0,0 +1,71 @@
1
+ # Copyright 2025 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
+ # http://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
+ from __future__ import annotations
16
+
17
+ ADK_METADATA_KEY_PREFIX = "adk_"
18
+ ADK_CONTEXT_ID_PREFIX = "ADK"
19
+
20
+
21
+ def _get_adk_metadata_key(key: str) -> str:
22
+ """Gets the A2A event metadata key for the given key.
23
+
24
+ Args:
25
+ key: The metadata key to prefix.
26
+
27
+ Returns:
28
+ The prefixed metadata key.
29
+
30
+ Raises:
31
+ ValueError: If key is empty or None.
32
+ """
33
+ if not key:
34
+ raise ValueError("Metadata key cannot be empty or None")
35
+ return f"{ADK_METADATA_KEY_PREFIX}{key}"
36
+
37
+
38
+ def _to_a2a_context_id(app_name: str, user_id: str, session_id: str) -> str:
39
+ """Converts app name, user id and session id to an A2A context id.
40
+
41
+ Args:
42
+ app_name: The app name.
43
+ user_id: The user id.
44
+ session_id: The session id.
45
+
46
+ Returns:
47
+ The A2A context id.
48
+ """
49
+ return [ADK_CONTEXT_ID_PREFIX, app_name, user_id, session_id].join("$")
50
+
51
+
52
+ def _from_a2a_context_id(context_id: str) -> tuple[str, str, str]:
53
+ """Converts an A2A context id to app name, user id and session id.
54
+ if context_id is None, return None, None, None
55
+ if context_id is not None, but not in the format of
56
+ ADK$app_name$user_id$session_id, return None, None, None
57
+
58
+ Args:
59
+ context_id: The A2A context id.
60
+
61
+ Returns:
62
+ The app name, user id and session id.
63
+ """
64
+ if not context_id:
65
+ return None, None, None
66
+
67
+ prefix, app_name, user_id, session_id = context_id.split("$")
68
+ if prefix == "ADK" and app_name and user_id and session_id:
69
+ return app_name, user_id, session_id
70
+
71
+ return None, None, None
@@ -161,10 +161,12 @@ class LlmAgent(BaseAgent):
161
161
  # LLM-based agent transfer configs - End
162
162
 
163
163
  include_contents: Literal['default', 'none'] = 'default'
164
- """Whether to include contents in the model request.
164
+ """Controls content inclusion in model requests.
165
165
 
166
- When set to 'none', the model request will not include any contents, such as
167
- user messages, tool results, etc.
166
+ Options:
167
+ default: Model receives relevant conversation history
168
+ none: Model receives no prior history, operates solely on current
169
+ instruction and input
168
170
  """
169
171
 
170
172
  # Controlled input/output configurations - Start
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """An artifact service implementation using Google Cloud Storage (GCS)."""
16
+ from __future__ import annotations
16
17
 
17
18
  import logging
18
19
  from typing import Optional
@@ -151,7 +152,7 @@ class GcsArtifactService(BaseArtifactService):
151
152
  self.bucket, prefix=session_prefix
152
153
  )
153
154
  for blob in session_blobs:
154
- _, _, _, filename, _ = blob.name.split("/")
155
+ *_, filename, _ = blob.name.split("/")
155
156
  filenames.add(filename)
156
157
 
157
158
  user_namespace_prefix = f"{app_name}/{user_id}/user/"
@@ -159,7 +160,7 @@ class GcsArtifactService(BaseArtifactService):
159
160
  self.bucket, prefix=user_namespace_prefix
160
161
  )
161
162
  for blob in user_namespace_blobs:
162
- _, _, _, filename, _ = blob.name.split("/")
163
+ *_, filename, _ = blob.name.split("/")
163
164
  filenames.add(filename)
164
165
 
165
166
  return sorted(list(filenames))
@@ -31,12 +31,12 @@ class AuthConfig(BaseModelWithConfig):
31
31
 
32
32
  auth_scheme: AuthScheme
33
33
  """The auth scheme used to collect credentials"""
34
- raw_auth_credential: AuthCredential = None
34
+ raw_auth_credential: Optional[AuthCredential] = None
35
35
  """The raw auth credential used to collect credentials. The raw auth
36
36
  credentials are used in some auth scheme that needs to exchange auth
37
37
  credentials. e.g. OAuth2 and OIDC. For other auth scheme, it could be None.
38
38
  """
39
- exchanged_auth_credential: AuthCredential = None
39
+ exchanged_auth_credential: Optional[AuthCredential] = None
40
40
  """The exchanged auth credential used to collect credentials. adk and client
41
41
  will work together to fill it. For those auth scheme that doesn't need to
42
42
  exchange auth credentials, e.g. API key, service account etc. It's filled by