Skip to content

Commit 54c6dc9

Browse files
authored
Merge branch 'main' into feat/agent-tool-event-callback
2 parents ef26363 + 631b583 commit 54c6dc9

File tree

20 files changed

+566
-110
lines changed

20 files changed

+566
-110
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![PyPI](https://img.shields.io/pypi/v/google-adk)](https://pypi.org/project/google-adk/)
55
[![Python Unit Tests](https://github.com/google/adk-python/actions/workflows/python-unit-tests.yml/badge.svg)](https://github.com/google/adk-python/actions/workflows/python-unit-tests.yml)
66
[![r/agentdevelopmentkit](https://img.shields.io/badge/Reddit-r%2Fagentdevelopmentkit-FF4500?style=flat&logo=reddit&logoColor=white)](https://www.reddit.com/r/agentdevelopmentkit/)
7-
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/google/adk-python)
7+
<a href="https://codewiki.google/github.com/google/adk-python"><img src="https://www.gstatic.com/_/boq-sdlc-agents-ui/_/r/Mvosg4klCA4.svg" alt="Ask Code Wiki" height="20"></a>
88

99
<html>
1010
<h2 align="center">

contributing/samples/computer_use/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ The computer use agent consists of:
1919
Install the required Python packages from the requirements file:
2020

2121
```bash
22-
uv pip install -r internal/samples/computer_use/requirements.txt
22+
uv pip install -r contributing/samples/computer_use/requirements.txt
2323
```
2424

2525
### 2. Install Playwright Dependencies
@@ -45,7 +45,7 @@ playwright install chromium
4545
To start the computer use agent, run the following command from the project root:
4646

4747
```bash
48-
adk web internal/samples
48+
adk web contributing/samples
4949
```
5050

5151
This will start the ADK web interface where you can interact with the computer_use agent.

src/google/adk/cli/adk_web_server.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,17 @@ class ListMetricsInfoResponse(common.BaseModel):
280280
metrics_info: list[MetricInfo]
281281

282282

283+
class AppInfo(common.BaseModel):
284+
name: str
285+
root_agent_name: str
286+
description: str
287+
language: Literal["yaml", "python"]
288+
289+
290+
class ListAppsResponse(common.BaseModel):
291+
apps: list[AppInfo]
292+
293+
283294
def _setup_telemetry(
284295
otel_to_cloud: bool = False,
285296
internal_exporters: Optional[list[SpanProcessor]] = None,
@@ -699,7 +710,14 @@ async def internal_lifespan(app: FastAPI):
699710
)
700711

701712
@app.get("/list-apps")
702-
async def list_apps() -> list[str]:
713+
async def list_apps(
714+
detailed: bool = Query(
715+
default=False, description="Return detailed app information"
716+
)
717+
) -> list[str] | ListAppsResponse:
718+
if detailed:
719+
apps_info = self.agent_loader.list_agents_detailed()
720+
return ListAppsResponse(apps=[AppInfo(**app) for app in apps_info])
703721
return self.agent_loader.list_agents()
704722

705723
@app.get("/debug/trace/{event_id}", tags=[TAG_DEBUG])

src/google/adk/cli/cli.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ async def run_cli(
218218
session_id=session.id,
219219
)
220220
with open(session_path, 'w', encoding='utf-8') as f:
221-
f.write(session.model_dump_json(indent=2, exclude_none=True))
221+
f.write(
222+
session.model_dump_json(indent=2, exclude_none=True, by_alias=True)
223+
)
222224

223225
print('Session saved to', session_path)

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import os
2121
from pathlib import Path
2222
import sys
23+
from typing import Any
24+
from typing import Literal
2325
from typing import Optional
2426
from typing import Union
2527

@@ -341,6 +343,50 @@ def list_agents(self) -> list[str]:
341343
agent_names.sort()
342344
return agent_names
343345

346+
def list_agents_detailed(self) -> list[dict[str, Any]]:
347+
"""Lists all agents with detailed metadata (name, description, type)."""
348+
agent_names = self.list_agents()
349+
apps_info = []
350+
351+
for agent_name in agent_names:
352+
try:
353+
loaded = self.load_agent(agent_name)
354+
if isinstance(loaded, App):
355+
agent = loaded.root_agent
356+
else:
357+
agent = loaded
358+
359+
language = self._determine_agent_language(agent_name)
360+
361+
app_info = {
362+
"name": agent_name,
363+
"root_agent_name": agent.name,
364+
"description": agent.description,
365+
"language": language,
366+
}
367+
apps_info.append(app_info)
368+
369+
except Exception as e:
370+
logger.error("Failed to load agent '%s': %s", agent_name, e)
371+
continue
372+
373+
return apps_info
374+
375+
def _determine_agent_language(
376+
self, agent_name: str
377+
) -> Literal["yaml", "python"]:
378+
"""Determine the type of agent based on file structure."""
379+
base_path = Path.cwd() / self.agents_dir / agent_name
380+
381+
if (base_path / "root_agent.yaml").exists():
382+
return "yaml"
383+
elif (base_path / "agent.py").exists():
384+
return "python"
385+
elif (base_path / "__init__.py").exists():
386+
return "python"
387+
388+
raise ValueError(f"Could not determine agent type for '{agent_name}'.")
389+
344390
def remove_agent_from_cache(self, agent_name: str):
345391
# Clear module cache for the agent and its submodules
346392
keys_to_delete = [

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from abc import ABC
2020
from abc import abstractmethod
21+
from typing import Any
2122
from typing import Union
2223

2324
from ...agents.base_agent import BaseAgent
@@ -34,3 +35,15 @@ def load_agent(self, agent_name: str) -> Union[BaseAgent, App]:
3435
@abstractmethod
3536
def list_agents(self) -> list[str]:
3637
"""Lists all agents available in the agent loader in alphabetical order."""
38+
39+
def list_agents_detailed(self) -> list[dict[str, Any]]:
40+
agent_names = self.list_agents()
41+
return [
42+
{
43+
'name': name,
44+
'display_name': None,
45+
'description': None,
46+
'type': None,
47+
}
48+
for name in agent_names
49+
]

src/google/adk/code_executors/unsafe_local_code_executor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def execute_code(
7272
_prepare_globals(code_execution_input.code, globals_)
7373
stdout = io.StringIO()
7474
with redirect_stdout(stdout):
75-
exec(code_execution_input.code, globals_)
75+
exec(code_execution_input.code, globals_, globals_)
7676
output = stdout.getvalue()
7777
except Exception as e:
7878
error = str(e)

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ def _contains_empty_content(event: Event) -> bool:
224224
225225
This can happen to the events that only changed session state.
226226
When both content and transcriptions are empty, the event will be considered
227-
as empty.
227+
as empty. The content is considered empty if none of its parts contain text,
228+
inline data, file data, function call, or function response.
228229
229230
Args:
230231
event: The event to check.
@@ -239,7 +240,14 @@ def _contains_empty_content(event: Event) -> bool:
239240
not event.content
240241
or not event.content.role
241242
or not event.content.parts
242-
or event.content.parts[0].text == ''
243+
or all(
244+
not p.text
245+
and not p.inline_data
246+
and not p.file_data
247+
and not p.function_call
248+
and not p.function_response
249+
for p in [event.content.parts[0]]
250+
)
243251
) and (not event.output_transcription and not event.input_transcription)
244252

245253

0 commit comments

Comments
 (0)