google-adk 1.1.1__py3-none-any.whl → 1.2.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.
- google/adk/agents/base_agent.py +0 -2
- google/adk/agents/invocation_context.py +3 -3
- google/adk/agents/parallel_agent.py +17 -7
- google/adk/agents/sequential_agent.py +8 -8
- google/adk/auth/auth_preprocessor.py +18 -17
- google/adk/cli/agent_graph.py +165 -23
- google/adk/cli/browser/assets/ADK-512-color.svg +9 -0
- google/adk/cli/browser/index.html +2 -2
- google/adk/cli/browser/{main-PKDNKWJE.js → main-CS5OLUMF.js} +59 -59
- google/adk/cli/browser/polyfills-FFHMD2TL.js +17 -0
- google/adk/cli/cli.py +9 -9
- google/adk/cli/cli_deploy.py +157 -0
- google/adk/cli/cli_tools_click.py +228 -99
- google/adk/cli/fast_api.py +119 -34
- google/adk/cli/utils/agent_loader.py +60 -44
- google/adk/cli/utils/envs.py +1 -1
- google/adk/code_executors/unsafe_local_code_executor.py +11 -0
- google/adk/errors/__init__.py +13 -0
- google/adk/errors/not_found_error.py +28 -0
- google/adk/evaluation/agent_evaluator.py +1 -1
- google/adk/evaluation/eval_sets_manager.py +36 -6
- google/adk/evaluation/evaluation_generator.py +5 -4
- google/adk/evaluation/local_eval_sets_manager.py +101 -6
- google/adk/flows/llm_flows/agent_transfer.py +2 -2
- google/adk/flows/llm_flows/base_llm_flow.py +19 -0
- google/adk/flows/llm_flows/contents.py +4 -4
- google/adk/flows/llm_flows/functions.py +140 -127
- google/adk/memory/vertex_ai_rag_memory_service.py +2 -2
- google/adk/models/anthropic_llm.py +7 -10
- google/adk/models/google_llm.py +46 -18
- google/adk/models/lite_llm.py +63 -26
- google/adk/py.typed +0 -0
- google/adk/sessions/_session_util.py +10 -16
- google/adk/sessions/database_session_service.py +81 -66
- google/adk/sessions/vertex_ai_session_service.py +32 -6
- google/adk/telemetry.py +91 -24
- google/adk/tools/_automatic_function_calling_util.py +31 -25
- google/adk/tools/{function_parameter_parse_util.py → _function_parameter_parse_util.py} +9 -3
- google/adk/tools/_gemini_schema_util.py +158 -0
- google/adk/tools/apihub_tool/apihub_toolset.py +3 -2
- google/adk/tools/application_integration_tool/clients/connections_client.py +7 -0
- google/adk/tools/application_integration_tool/integration_connector_tool.py +5 -7
- google/adk/tools/base_tool.py +4 -8
- google/adk/tools/bigquery/bigquery_credentials.py +7 -3
- google/adk/tools/function_tool.py +4 -4
- google/adk/tools/langchain_tool.py +20 -13
- google/adk/tools/load_memory_tool.py +1 -0
- google/adk/tools/mcp_tool/conversion_utils.py +4 -2
- google/adk/tools/mcp_tool/mcp_session_manager.py +63 -5
- google/adk/tools/mcp_tool/mcp_tool.py +3 -2
- google/adk/tools/mcp_tool/mcp_toolset.py +15 -8
- google/adk/tools/openapi_tool/common/common.py +4 -43
- google/adk/tools/openapi_tool/openapi_spec_parser/__init__.py +0 -2
- google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py +4 -2
- google/adk/tools/openapi_tool/openapi_spec_parser/operation_parser.py +4 -2
- google/adk/tools/openapi_tool/openapi_spec_parser/rest_api_tool.py +7 -127
- google/adk/tools/openapi_tool/openapi_spec_parser/tool_auth_handler.py +2 -7
- google/adk/tools/transfer_to_agent_tool.py +8 -1
- google/adk/tools/vertex_ai_search_tool.py +8 -1
- google/adk/utils/variant_utils.py +51 -0
- google/adk/version.py +1 -1
- {google_adk-1.1.1.dist-info → google_adk-1.2.0.dist-info}/METADATA +7 -7
- {google_adk-1.1.1.dist-info → google_adk-1.2.0.dist-info}/RECORD +66 -60
- google/adk/cli/browser/polyfills-B6TNHZQ6.js +0 -17
- {google_adk-1.1.1.dist-info → google_adk-1.2.0.dist-info}/WHEEL +0 -0
- {google_adk-1.1.1.dist-info → google_adk-1.2.0.dist-info}/entry_points.txt +0 -0
- {google_adk-1.1.1.dist-info → google_adk-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -32,8 +32,8 @@ from ...agents.invocation_context import InvocationContext
|
|
32
32
|
from ...auth.auth_tool import AuthToolArguments
|
33
33
|
from ...events.event import Event
|
34
34
|
from ...events.event_actions import EventActions
|
35
|
+
from ...telemetry import trace_merged_tool_calls
|
35
36
|
from ...telemetry import trace_tool_call
|
36
|
-
from ...telemetry import trace_tool_response
|
37
37
|
from ...telemetry import tracer
|
38
38
|
from ...tools.base_tool import BaseTool
|
39
39
|
from ...tools.tool_context import ToolContext
|
@@ -148,62 +148,69 @@ async def handle_function_calls_async(
|
|
148
148
|
function_call,
|
149
149
|
tools_dict,
|
150
150
|
)
|
151
|
-
# do not use "args" as the variable name, because it is a reserved keyword
|
152
|
-
# in python debugger.
|
153
|
-
function_args = function_call.args or {}
|
154
|
-
function_response: Optional[dict] = None
|
155
|
-
|
156
|
-
for callback in agent.canonical_before_tool_callbacks:
|
157
|
-
function_response = callback(
|
158
|
-
tool=tool, args=function_args, tool_context=tool_context
|
159
|
-
)
|
160
|
-
if inspect.isawaitable(function_response):
|
161
|
-
function_response = await function_response
|
162
|
-
if function_response:
|
163
|
-
break
|
164
|
-
|
165
|
-
if not function_response:
|
166
|
-
function_response = await __call_tool_async(
|
167
|
-
tool, args=function_args, tool_context=tool_context
|
168
|
-
)
|
169
151
|
|
170
|
-
|
171
|
-
|
152
|
+
with tracer.start_as_current_span(f'execute_tool {tool.name}'):
|
153
|
+
# do not use "args" as the variable name, because it is a reserved keyword
|
154
|
+
# in python debugger.
|
155
|
+
function_args = function_call.args or {}
|
156
|
+
function_response: Optional[dict] = None
|
157
|
+
|
158
|
+
for callback in agent.canonical_before_tool_callbacks:
|
159
|
+
function_response = callback(
|
160
|
+
tool=tool, args=function_args, tool_context=tool_context
|
161
|
+
)
|
162
|
+
if inspect.isawaitable(function_response):
|
163
|
+
function_response = await function_response
|
164
|
+
if function_response:
|
165
|
+
break
|
166
|
+
|
167
|
+
if not function_response:
|
168
|
+
function_response = await __call_tool_async(
|
169
|
+
tool, args=function_args, tool_context=tool_context
|
170
|
+
)
|
171
|
+
|
172
|
+
for callback in agent.canonical_after_tool_callbacks:
|
173
|
+
altered_function_response = callback(
|
174
|
+
tool=tool,
|
175
|
+
args=function_args,
|
176
|
+
tool_context=tool_context,
|
177
|
+
tool_response=function_response,
|
178
|
+
)
|
179
|
+
if inspect.isawaitable(altered_function_response):
|
180
|
+
altered_function_response = await altered_function_response
|
181
|
+
if altered_function_response is not None:
|
182
|
+
function_response = altered_function_response
|
183
|
+
break
|
184
|
+
|
185
|
+
if tool.is_long_running:
|
186
|
+
# Allow long running function to return None to not provide function response.
|
187
|
+
if not function_response:
|
188
|
+
continue
|
189
|
+
|
190
|
+
# Builds the function response event.
|
191
|
+
function_response_event = __build_response_event(
|
192
|
+
tool, function_response, tool_context, invocation_context
|
193
|
+
)
|
194
|
+
trace_tool_call(
|
172
195
|
tool=tool,
|
173
196
|
args=function_args,
|
174
|
-
|
175
|
-
tool_response=function_response,
|
197
|
+
function_response_event=function_response_event,
|
176
198
|
)
|
177
|
-
|
178
|
-
altered_function_response = await altered_function_response
|
179
|
-
if altered_function_response is not None:
|
180
|
-
function_response = altered_function_response
|
181
|
-
break
|
182
|
-
|
183
|
-
if tool.is_long_running:
|
184
|
-
# Allow long running function to return None to not provide function response.
|
185
|
-
if not function_response:
|
186
|
-
continue
|
187
|
-
|
188
|
-
# Builds the function response event.
|
189
|
-
function_response_event = __build_response_event(
|
190
|
-
tool, function_response, tool_context, invocation_context
|
191
|
-
)
|
192
|
-
function_response_events.append(function_response_event)
|
199
|
+
function_response_events.append(function_response_event)
|
193
200
|
|
194
201
|
if not function_response_events:
|
195
202
|
return None
|
196
203
|
merged_event = merge_parallel_function_response_events(
|
197
204
|
function_response_events
|
198
205
|
)
|
206
|
+
|
199
207
|
if len(function_response_events) > 1:
|
200
208
|
# this is needed for debug traces of parallel calls
|
201
209
|
# individual response with tool.name is traced in __build_response_event
|
202
210
|
# (we drop tool.name from span name here as this is merged event)
|
203
|
-
with tracer.start_as_current_span('
|
204
|
-
|
205
|
-
|
206
|
-
event_id=merged_event.id,
|
211
|
+
with tracer.start_as_current_span('execute_tool (merged)'):
|
212
|
+
trace_merged_tool_calls(
|
213
|
+
response_event_id=merged_event.id,
|
207
214
|
function_response_event=merged_event,
|
208
215
|
)
|
209
216
|
return merged_event
|
@@ -225,65 +232,81 @@ async def handle_function_calls_live(
|
|
225
232
|
tool, tool_context = _get_tool_and_context(
|
226
233
|
invocation_context, function_call_event, function_call, tools_dict
|
227
234
|
)
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
235
|
+
with tracer.start_as_current_span(f'execute_tool {tool.name}'):
|
236
|
+
# do not use "args" as the variable name, because it is a reserved keyword
|
237
|
+
# in python debugger.
|
238
|
+
function_args = function_call.args or {}
|
239
|
+
function_response = None
|
240
|
+
# # Calls the tool if before_tool_callback does not exist or returns None.
|
241
|
+
# if agent.before_tool_callback:
|
242
|
+
# function_response = agent.before_tool_callback(
|
243
|
+
# tool, function_args, tool_context
|
244
|
+
# )
|
245
|
+
if agent.before_tool_callback:
|
246
|
+
function_response = agent.before_tool_callback(
|
247
|
+
tool=tool, args=function_args, tool_context=tool_context
|
248
|
+
)
|
249
|
+
if inspect.isawaitable(function_response):
|
250
|
+
function_response = await function_response
|
243
251
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
252
|
+
if not function_response:
|
253
|
+
function_response = await _process_function_live_helper(
|
254
|
+
tool, tool_context, function_call, function_args, invocation_context
|
255
|
+
)
|
248
256
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
257
|
+
# Calls after_tool_callback if it exists.
|
258
|
+
# if agent.after_tool_callback:
|
259
|
+
# new_response = agent.after_tool_callback(
|
260
|
+
# tool,
|
261
|
+
# function_args,
|
262
|
+
# tool_context,
|
263
|
+
# function_response,
|
264
|
+
# )
|
265
|
+
# if new_response:
|
266
|
+
# function_response = new_response
|
267
|
+
if agent.after_tool_callback:
|
268
|
+
altered_function_response = agent.after_tool_callback(
|
269
|
+
tool=tool,
|
270
|
+
args=function_args,
|
271
|
+
tool_context=tool_context,
|
272
|
+
tool_response=function_response,
|
273
|
+
)
|
274
|
+
if inspect.isawaitable(altered_function_response):
|
275
|
+
altered_function_response = await altered_function_response
|
276
|
+
if altered_function_response is not None:
|
277
|
+
function_response = altered_function_response
|
278
|
+
|
279
|
+
if tool.is_long_running:
|
280
|
+
# Allow async function to return None to not provide function response.
|
281
|
+
if not function_response:
|
282
|
+
continue
|
283
|
+
|
284
|
+
# Builds the function response event.
|
285
|
+
function_response_event = __build_response_event(
|
286
|
+
tool, function_response, tool_context, invocation_context
|
287
|
+
)
|
288
|
+
trace_tool_call(
|
261
289
|
tool=tool,
|
262
290
|
args=function_args,
|
263
|
-
|
264
|
-
|
291
|
+
response_event_id=function_response_event.id,
|
292
|
+
function_response=function_response,
|
265
293
|
)
|
266
|
-
|
267
|
-
altered_function_response = await altered_function_response
|
268
|
-
if altered_function_response is not None:
|
269
|
-
function_response = altered_function_response
|
270
|
-
|
271
|
-
if tool.is_long_running:
|
272
|
-
# Allow async function to return None to not provide function response.
|
273
|
-
if not function_response:
|
274
|
-
continue
|
275
|
-
|
276
|
-
# Builds the function response event.
|
277
|
-
function_response_event = __build_response_event(
|
278
|
-
tool, function_response, tool_context, invocation_context
|
279
|
-
)
|
280
|
-
function_response_events.append(function_response_event)
|
294
|
+
function_response_events.append(function_response_event)
|
281
295
|
|
282
296
|
if not function_response_events:
|
283
297
|
return None
|
284
298
|
merged_event = merge_parallel_function_response_events(
|
285
299
|
function_response_events
|
286
300
|
)
|
301
|
+
if len(function_response_events) > 1:
|
302
|
+
# this is needed for debug traces of parallel calls
|
303
|
+
# individual response with tool.name is traced in __build_response_event
|
304
|
+
# (we drop tool.name from span name here as this is merged event)
|
305
|
+
with tracer.start_as_current_span('execute_tool (merged)'):
|
306
|
+
trace_merged_tool_calls(
|
307
|
+
response_event_id=merged_event.id,
|
308
|
+
function_response_event=merged_event,
|
309
|
+
)
|
287
310
|
return merged_event
|
288
311
|
|
289
312
|
|
@@ -410,14 +433,12 @@ async def __call_tool_live(
|
|
410
433
|
invocation_context: InvocationContext,
|
411
434
|
) -> AsyncGenerator[Event, None]:
|
412
435
|
"""Calls the tool asynchronously (awaiting the coroutine)."""
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
):
|
420
|
-
yield item
|
436
|
+
async for item in tool._call_live(
|
437
|
+
args=args,
|
438
|
+
tool_context=tool_context,
|
439
|
+
invocation_context=invocation_context,
|
440
|
+
):
|
441
|
+
yield item
|
421
442
|
|
422
443
|
|
423
444
|
async def __call_tool_async(
|
@@ -426,9 +447,7 @@ async def __call_tool_async(
|
|
426
447
|
tool_context: ToolContext,
|
427
448
|
) -> Any:
|
428
449
|
"""Calls the tool."""
|
429
|
-
|
430
|
-
trace_tool_call(args=args)
|
431
|
-
return await tool.run_async(args=args, tool_context=tool_context)
|
450
|
+
return await tool.run_async(args=args, tool_context=tool_context)
|
432
451
|
|
433
452
|
|
434
453
|
def __build_response_event(
|
@@ -437,35 +456,29 @@ def __build_response_event(
|
|
437
456
|
tool_context: ToolContext,
|
438
457
|
invocation_context: InvocationContext,
|
439
458
|
) -> Event:
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
function_result = {'result': function_result}
|
459
|
+
# Specs requires the result to be a dict.
|
460
|
+
if not isinstance(function_result, dict):
|
461
|
+
function_result = {'result': function_result}
|
444
462
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
463
|
+
part_function_response = types.Part.from_function_response(
|
464
|
+
name=tool.name, response=function_result
|
465
|
+
)
|
466
|
+
part_function_response.function_response.id = tool_context.function_call_id
|
449
467
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
468
|
+
content = types.Content(
|
469
|
+
role='user',
|
470
|
+
parts=[part_function_response],
|
471
|
+
)
|
454
472
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
473
|
+
function_response_event = Event(
|
474
|
+
invocation_id=invocation_context.invocation_id,
|
475
|
+
author=invocation_context.agent.name,
|
476
|
+
content=content,
|
477
|
+
actions=tool_context.actions,
|
478
|
+
branch=invocation_context.branch,
|
479
|
+
)
|
462
480
|
|
463
|
-
|
464
|
-
invocation_context=invocation_context,
|
465
|
-
event_id=function_response_event.id,
|
466
|
-
function_response_event=function_response_event,
|
467
|
-
)
|
468
|
-
return function_response_event
|
481
|
+
return function_response_event
|
469
482
|
|
470
483
|
|
471
484
|
def merge_parallel_function_response_events(
|
@@ -124,8 +124,8 @@ class VertexAiRagMemoryService(BaseMemoryService):
|
|
124
124
|
for context in response.contexts.contexts:
|
125
125
|
# filter out context that is not related
|
126
126
|
# TODO: Add server side filtering by app_name and user_id.
|
127
|
-
|
128
|
-
|
127
|
+
if not context.source_display_name.startswith(f"{app_name}.{user_id}."):
|
128
|
+
continue
|
129
129
|
session_id = context.source_display_name.split(".")[-1]
|
130
130
|
events = []
|
131
131
|
if context.text:
|
@@ -135,6 +135,10 @@ def content_block_to_part(
|
|
135
135
|
def message_to_generate_content_response(
|
136
136
|
message: anthropic_types.Message,
|
137
137
|
) -> LlmResponse:
|
138
|
+
logger.info(
|
139
|
+
"Claude response: %s",
|
140
|
+
message.model_dump_json(indent=2, exclude_none=True),
|
141
|
+
)
|
138
142
|
|
139
143
|
return LlmResponse(
|
140
144
|
content=types.Content(
|
@@ -208,7 +212,7 @@ class Claude(BaseLlm):
|
|
208
212
|
@staticmethod
|
209
213
|
@override
|
210
214
|
def supported_models() -> list[str]:
|
211
|
-
return [r"claude-3-.*"]
|
215
|
+
return [r"claude-3-.*", r"claude-.*-4.*"]
|
212
216
|
|
213
217
|
@override
|
214
218
|
async def generate_content_async(
|
@@ -229,14 +233,11 @@ class Claude(BaseLlm):
|
|
229
233
|
for tool in llm_request.config.tools[0].function_declarations
|
230
234
|
]
|
231
235
|
tool_choice = (
|
232
|
-
anthropic_types.ToolChoiceAutoParam(
|
233
|
-
type="auto",
|
234
|
-
# TODO: allow parallel tool use.
|
235
|
-
disable_parallel_tool_use=True,
|
236
|
-
)
|
236
|
+
anthropic_types.ToolChoiceAutoParam(type="auto")
|
237
237
|
if llm_request.tools_dict
|
238
238
|
else NOT_GIVEN
|
239
239
|
)
|
240
|
+
# TODO(b/421255973): Enable streaming for anthropic models.
|
240
241
|
message = self._anthropic_client.messages.create(
|
241
242
|
model=llm_request.model,
|
242
243
|
system=llm_request.config.system_instruction,
|
@@ -245,10 +246,6 @@ class Claude(BaseLlm):
|
|
245
246
|
tool_choice=tool_choice,
|
246
247
|
max_tokens=MAX_TOKEN,
|
247
248
|
)
|
248
|
-
logger.info(
|
249
|
-
"Claude response: %s",
|
250
|
-
message.model_dump_json(indent=2, exclude_none=True),
|
251
|
-
)
|
252
249
|
yield message_to_generate_content_response(message)
|
253
250
|
|
254
251
|
@cached_property
|
google/adk/models/google_llm.py
CHANGED
@@ -18,6 +18,7 @@ from __future__ import annotations
|
|
18
18
|
import contextlib
|
19
19
|
from functools import cached_property
|
20
20
|
import logging
|
21
|
+
import os
|
21
22
|
import sys
|
22
23
|
from typing import AsyncGenerator
|
23
24
|
from typing import cast
|
@@ -28,6 +29,7 @@ from google.genai import types
|
|
28
29
|
from typing_extensions import override
|
29
30
|
|
30
31
|
from .. import version
|
32
|
+
from ..utils.variant_utils import GoogleLLMVariant
|
31
33
|
from .base_llm import BaseLlm
|
32
34
|
from .base_llm_connection import BaseLlmConnection
|
33
35
|
from .gemini_llm_connection import GeminiLlmConnection
|
@@ -40,6 +42,8 @@ logger = logging.getLogger('google_adk.' + __name__)
|
|
40
42
|
|
41
43
|
_NEW_LINE = '\n'
|
42
44
|
_EXCLUDED_PART_FIELD = {'inline_data': {'data'}}
|
45
|
+
_AGENT_ENGINE_TELEMETRY_TAG = 'remote_reasoning_engine'
|
46
|
+
_AGENT_ENGINE_TELEMETRY_ENV_VARIABLE_NAME = 'GOOGLE_CLOUD_AGENT_ENGINE_ID'
|
43
47
|
|
44
48
|
|
45
49
|
class Gemini(BaseLlm):
|
@@ -80,7 +84,7 @@ class Gemini(BaseLlm):
|
|
80
84
|
Yields:
|
81
85
|
LlmResponse: The model response.
|
82
86
|
"""
|
83
|
-
|
87
|
+
self._preprocess_request(llm_request)
|
84
88
|
self._maybe_append_user_content(llm_request)
|
85
89
|
logger.info(
|
86
90
|
'Sending out request, model: %s, backend: %s, stream: %s',
|
@@ -97,6 +101,7 @@ class Gemini(BaseLlm):
|
|
97
101
|
config=llm_request.config,
|
98
102
|
)
|
99
103
|
response = None
|
104
|
+
thought_text = ''
|
100
105
|
text = ''
|
101
106
|
usage_metadata = None
|
102
107
|
# for sse, similar as bidi (see receive method in gemini_llm_connecton.py),
|
@@ -113,32 +118,43 @@ class Gemini(BaseLlm):
|
|
113
118
|
and llm_response.content.parts
|
114
119
|
and llm_response.content.parts[0].text
|
115
120
|
):
|
116
|
-
|
121
|
+
part0 = llm_response.content.parts[0]
|
122
|
+
if part0.thought:
|
123
|
+
thought_text += part0.text
|
124
|
+
else:
|
125
|
+
text += part0.text
|
117
126
|
llm_response.partial = True
|
118
|
-
elif text and (
|
127
|
+
elif (thought_text or text) and (
|
119
128
|
not llm_response.content
|
120
129
|
or not llm_response.content.parts
|
121
130
|
# don't yield the merged text event when receiving audio data
|
122
131
|
or not llm_response.content.parts[0].inline_data
|
123
132
|
):
|
133
|
+
parts = []
|
134
|
+
if thought_text:
|
135
|
+
parts.append(types.Part(text=thought_text, thought=True))
|
136
|
+
if text:
|
137
|
+
parts.append(types.Part.from_text(text=text))
|
124
138
|
yield LlmResponse(
|
125
|
-
content=types.ModelContent(
|
126
|
-
|
127
|
-
),
|
128
|
-
usage_metadata=usage_metadata,
|
139
|
+
content=types.ModelContent(parts=parts),
|
140
|
+
usage_metadata=llm_response.usage_metadata,
|
129
141
|
)
|
142
|
+
thought_text = ''
|
130
143
|
text = ''
|
131
144
|
yield llm_response
|
132
145
|
if (
|
133
|
-
text
|
146
|
+
(text or thought_text)
|
134
147
|
and response
|
135
148
|
and response.candidates
|
136
149
|
and response.candidates[0].finish_reason == types.FinishReason.STOP
|
137
150
|
):
|
151
|
+
parts = []
|
152
|
+
if thought_text:
|
153
|
+
parts.append(types.Part(text=thought_text, thought=True))
|
154
|
+
if text:
|
155
|
+
parts.append(types.Part.from_text(text=text))
|
138
156
|
yield LlmResponse(
|
139
|
-
content=types.ModelContent(
|
140
|
-
parts=[types.Part.from_text(text=text)],
|
141
|
-
),
|
157
|
+
content=types.ModelContent(parts=parts),
|
142
158
|
usage_metadata=usage_metadata,
|
143
159
|
)
|
144
160
|
|
@@ -163,12 +179,18 @@ class Gemini(BaseLlm):
|
|
163
179
|
)
|
164
180
|
|
165
181
|
@cached_property
|
166
|
-
def _api_backend(self) ->
|
167
|
-
return
|
182
|
+
def _api_backend(self) -> GoogleLLMVariant:
|
183
|
+
return (
|
184
|
+
GoogleLLMVariant.VERTEX_AI
|
185
|
+
if self.api_client.vertexai
|
186
|
+
else GoogleLLMVariant.GEMINI_API
|
187
|
+
)
|
168
188
|
|
169
189
|
@cached_property
|
170
190
|
def _tracking_headers(self) -> dict[str, str]:
|
171
191
|
framework_label = f'google-adk/{version.__version__}'
|
192
|
+
if os.environ.get(_AGENT_ENGINE_TELEMETRY_ENV_VARIABLE_NAME):
|
193
|
+
framework_label = f'{framework_label}+{_AGENT_ENGINE_TELEMETRY_TAG}'
|
172
194
|
language_label = 'gl-python/' + sys.version.split()[0]
|
173
195
|
version_header_value = f'{framework_label} {language_label}'
|
174
196
|
tracking_headers = {
|
@@ -179,7 +201,7 @@ class Gemini(BaseLlm):
|
|
179
201
|
|
180
202
|
@cached_property
|
181
203
|
def _live_api_client(self) -> Client:
|
182
|
-
if self._api_backend ==
|
204
|
+
if self._api_backend == GoogleLLMVariant.VERTEX_AI:
|
183
205
|
# use beta version for vertex api
|
184
206
|
api_version = 'v1beta1'
|
185
207
|
# use default api version for vertex
|
@@ -189,7 +211,7 @@ class Gemini(BaseLlm):
|
|
189
211
|
)
|
190
212
|
)
|
191
213
|
else:
|
192
|
-
# use v1alpha for
|
214
|
+
# use v1alpha for using API KEY from Google AI Studio
|
193
215
|
api_version = 'v1alpha'
|
194
216
|
return Client(
|
195
217
|
http_options=types.HttpOptions(
|
@@ -220,6 +242,12 @@ class Gemini(BaseLlm):
|
|
220
242
|
) as live_session:
|
221
243
|
yield GeminiLlmConnection(live_session)
|
222
244
|
|
245
|
+
def _preprocess_request(self, llm_request: LlmRequest) -> None:
|
246
|
+
|
247
|
+
if llm_request.config and self._api_backend == GoogleLLMVariant.GEMINI_API:
|
248
|
+
# Using API key from Google AI Studio to call model doesn't support labels.
|
249
|
+
llm_request.config.labels = None
|
250
|
+
|
223
251
|
|
224
252
|
def _build_function_declaration_log(
|
225
253
|
func_decl: types.FunctionDeclaration,
|
@@ -230,10 +258,10 @@ def _build_function_declaration_log(
|
|
230
258
|
k: v.model_dump(exclude_none=True)
|
231
259
|
for k, v in func_decl.parameters.properties.items()
|
232
260
|
})
|
233
|
-
return_str = '
|
261
|
+
return_str = ''
|
234
262
|
if func_decl.response:
|
235
|
-
return_str = str(func_decl.response.model_dump(exclude_none=True))
|
236
|
-
return f'{func_decl.name}: {param_str}
|
263
|
+
return_str = '-> ' + str(func_decl.response.model_dump(exclude_none=True))
|
264
|
+
return f'{func_decl.name}: {param_str} {return_str}'
|
237
265
|
|
238
266
|
|
239
267
|
def _build_request_log(req: LlmRequest) -> str:
|