Skip to content

Commit 895e3c8

Browse files
committed
fix: Use candidates_token_count for output tokens in telemetry
1 parent f46396f commit 895e3c8

File tree

17 files changed

+243
-195
lines changed

17 files changed

+243
-195
lines changed

src/google/adk/agents/remote_a2a_agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,11 +481,11 @@ async def _run_async_impl(
481481
),
482482
)
483483

484-
logger.info(build_a2a_request_log(a2a_request))
484+
logger.debug(build_a2a_request_log(a2a_request))
485485

486486
try:
487487
a2a_response = await self._a2a_client.send_message(request=a2a_request)
488-
logger.info(build_a2a_response_log(a2a_response))
488+
logger.debug(build_a2a_response_log(a2a_response))
489489

490490
event = await self._handle_a2a_response(a2a_response, ctx)
491491

src/google/adk/cli/browser/index.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

src/google/adk/cli/browser/main-SRBSE46V.js renamed to src/google/adk/cli/browser/main-W7QZBYAR.js

Lines changed: 139 additions & 139 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/google/adk/cli/cli_eval.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from typing_extensions import deprecated
2929

30-
from ..agents import Agent
30+
from ..agents.llm_agent import Agent
3131
from ..artifacts.base_artifact_service import BaseArtifactService
3232
from ..evaluation.base_eval_service import BaseEvalService
3333
from ..evaluation.base_eval_service import EvaluateConfig

src/google/adk/cli/fast_api.py

Lines changed: 17 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
from typing import Any
2828
from typing import List
2929
from typing import Literal
30-
from typing import Mapping
3130
from typing import Optional
3231

3332
import click
@@ -407,20 +406,7 @@ def _parse_agent_engine_resource_name(agent_engine_id_or_resource_name):
407406

408407
@app.get("/list-apps")
409408
def list_apps() -> list[str]:
410-
base_path = Path.cwd() / agents_dir
411-
if not base_path.exists():
412-
raise HTTPException(status_code=404, detail="Path not found")
413-
if not base_path.is_dir():
414-
raise HTTPException(status_code=400, detail="Not a directory")
415-
agent_names = [
416-
x
417-
for x in os.listdir(base_path)
418-
if os.path.isdir(os.path.join(base_path, x))
419-
and not x.startswith(".")
420-
and x != "__pycache__"
421-
]
422-
agent_names.sort()
423-
return agent_names
409+
return agent_loader.list_agents()
424410

425411
@app.get("/debug/trace/{event_id}")
426412
def get_trace_dict(event_id: str) -> Any:
@@ -525,13 +511,6 @@ async def create_session(
525511

526512
return session
527513

528-
def _get_eval_set_file_path(app_name, agents_dir, eval_set_id) -> str:
529-
return os.path.join(
530-
agents_dir,
531-
app_name,
532-
eval_set_id + _EVAL_SET_FILE_EXTENSION,
533-
)
534-
535514
@app.post(
536515
"/apps/{app_name}/eval_sets/{eval_set_id}",
537516
response_model_exclude_none=True,
@@ -675,23 +654,24 @@ async def run_eval(
675654
app_name: str, eval_set_id: str, req: RunEvalRequest
676655
) -> list[RunEvalResult]:
677656
"""Runs an eval given the details in the eval request."""
678-
from ..evaluation.local_eval_service import LocalEvalService
679-
from .cli_eval import _collect_eval_results
680-
from .cli_eval import _collect_inferences
681-
682657
# Create a mapping from eval set file to all the evals that needed to be
683658
# run.
684-
eval_set = eval_sets_manager.get_eval_set(app_name, eval_set_id)
659+
try:
660+
from ..evaluation.local_eval_service import LocalEvalService
661+
from .cli_eval import _collect_eval_results
662+
from .cli_eval import _collect_inferences
685663

686-
if not eval_set:
687-
raise HTTPException(
688-
status_code=400, detail=f"Eval set `{eval_set_id}` not found."
689-
)
664+
eval_set = eval_sets_manager.get_eval_set(app_name, eval_set_id)
690665

691-
root_agent = agent_loader.load_agent(app_name)
666+
if not eval_set:
667+
raise HTTPException(
668+
status_code=400, detail=f"Eval set `{eval_set_id}` not found."
669+
)
670+
671+
root_agent = agent_loader.load_agent(app_name)
672+
673+
eval_case_results = []
692674

693-
eval_case_results = []
694-
try:
695675
eval_service = LocalEvalService(
696676
root_agent=root_agent,
697677
eval_sets_manager=eval_sets_manager,
@@ -894,7 +874,8 @@ async def agent_run(req: AgentRunRequest) -> list[Event]:
894874
new_message=req.new_message,
895875
)
896876
]
897-
logger.info("Generated %s events in agent run: %s", len(events), events)
877+
logger.info("Generated %s events in agent run", len(events))
878+
logger.debug("Events generated: %s", events)
898879
return events
899880

900881
@app.post("/run_sse")
@@ -920,7 +901,7 @@ async def event_generator():
920901
):
921902
# Format as SSE data
922903
sse_event = event.model_dump_json(exclude_none=True, by_alias=True)
923-
logger.info("Generated event in agent run streaming: %s", sse_event)
904+
logger.debug("Generated event in agent run streaming: %s", sse_event)
924905
yield f"data: {sse_event}\n\n"
925906
except Exception as e:
926907
logger.exception("Error in event_generator: %s", e)

src/google/adk/cli/utils/agent_loader.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@
1717
import importlib
1818
import logging
1919
import os
20+
from pathlib import Path
2021
import sys
2122
from typing import Optional
2223

2324
from pydantic import ValidationError
25+
from typing_extensions import override
2426

2527
from . import envs
2628
from ...agents import config_agent_utils
2729
from ...agents.base_agent import BaseAgent
2830
from ...utils.feature_decorator import working_in_progress
31+
from .base_agent_loader import BaseAgentLoader
2932

3033
logger = logging.getLogger("google_adk." + __name__)
3134

3235

33-
class AgentLoader:
36+
class AgentLoader(BaseAgentLoader):
3437
"""Centralized agent loading with proper isolation, caching, and .env loading.
3538
Support loading agents from below folder/file structures:
3639
a) {agent_name}.agent as a module name:
@@ -188,6 +191,7 @@ def _perform_load(self, agent_name: str) -> BaseAgent:
188191
" exposed."
189192
)
190193

194+
@override
191195
def load_agent(self, agent_name: str) -> BaseAgent:
192196
"""Load an agent module (with caching & .env) and return its root_agent."""
193197
if agent_name in self._agent_cache:
@@ -199,6 +203,20 @@ def load_agent(self, agent_name: str) -> BaseAgent:
199203
self._agent_cache[agent_name] = agent
200204
return agent
201205

206+
@override
207+
def list_agents(self) -> list[str]:
208+
"""Lists all agents available in the agent loader (sorted alphabetically)."""
209+
base_path = Path.cwd() / self.agents_dir
210+
agent_names = [
211+
x
212+
for x in os.listdir(base_path)
213+
if os.path.isdir(os.path.join(base_path, x))
214+
and not x.startswith(".")
215+
and x != "__pycache__"
216+
]
217+
agent_names.sort()
218+
return agent_names
219+
202220
def remove_agent_from_cache(self, agent_name: str):
203221
# Clear module cache for the agent and its submodules
204222
keys_to_delete = [
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
"""Base class for agent loaders."""
16+
17+
from __future__ import annotations
18+
19+
from abc import ABC
20+
from abc import abstractmethod
21+
22+
from ...agents.base_agent import BaseAgent
23+
24+
25+
class BaseAgentLoader(ABC):
26+
"""Abstract base class for agent loaders."""
27+
28+
@abstractmethod
29+
def load_agent(self, agent_name: str) -> BaseAgent:
30+
"""Loads an instance of an agent with the given name."""
31+
32+
@abstractmethod
33+
def list_agents(self) -> list[str]:
34+
"""Lists all agents available in the agent loader in alphabetical order."""

src/google/adk/events/event.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class Event(LlmResponse):
4242
branch: The branch of the event.
4343
id: The unique identifier of the event.
4444
timestamp: The timestamp of the event.
45-
is_final_response: Whether the event is the final response of the agent.
4645
get_function_calls: Returns the function calls in the event.
4746
"""
4847

@@ -92,7 +91,13 @@ def model_post_init(self, __context):
9291
self.id = Event.new_id()
9392

9493
def is_final_response(self) -> bool:
95-
"""Returns whether the event is the final response of the agent."""
94+
"""Returns whether the event is the final response of an agent.
95+
96+
NOTE: This method is ONLY for use by Agent Development Kit.
97+
98+
Note that when multiple agents participage in one invocation, there could be
99+
one event has `is_final_response()` as True for each participating agent.
100+
"""
96101
if self.actions.skip_summarization or self.long_running_tool_ids:
97102
return True
98103
return (

src/google/adk/memory/vertex_ai_memory_bank_service.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ async def add_session_to_memory(self, session: Session):
8686
path=f'reasoningEngines/{self._agent_engine_id}/memories:generate',
8787
request_dict=request_dict,
8888
)
89-
logger.info('Generate memory response: %s', api_response)
89+
logger.info('Generate memory response received.')
90+
logger.debug('Generate memory response: %s', api_response)
9091
else:
9192
logger.info('No events to add to memory.')
9293

@@ -108,7 +109,8 @@ async def search_memory(self, *, app_name: str, user_id: str, query: str):
108109
},
109110
)
110111
api_response = _convert_api_response(api_response)
111-
logger.info('Search memory response: %s', api_response)
112+
logger.info('Search memory response received.')
113+
logger.debug('Search memory response: %s', api_response)
112114

113115
if not api_response or not api_response.get('retrievedMemories', None):
114116
return SearchMemoryResponse()

src/google/adk/models/anthropic_llm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ def content_block_to_part(
174174
def message_to_generate_content_response(
175175
message: anthropic_types.Message,
176176
) -> LlmResponse:
177-
logger.info(
177+
logger.info("Received response from Claude.")
178+
logger.debug(
178179
"Claude response: %s",
179180
message.model_dump_json(indent=2, exclude_none=True),
180181
)

0 commit comments

Comments
 (0)