Skip to content

Commit ea2ac9e

Browse files
committed
Merge branch 'fix-agent-transfer-error-handling' into feature/approval-mechanism
2 parents aca8932 + 19ef066 commit ea2ac9e

File tree

21 files changed

+650
-140
lines changed

21 files changed

+650
-140
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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+
name: "Check file contents"
16+
17+
on:
18+
pull_request:
19+
paths:
20+
- '**.py'
21+
22+
jobs:
23+
check-file-contents:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Checkout Code
27+
uses: actions/checkout@v4
28+
with:
29+
fetch-depth: 2
30+
31+
- name: Check for logger pattern in all changed Python files
32+
run: |
33+
git fetch origin ${{ github.base_ref }}
34+
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.py$' || true)
35+
if [ -n "$CHANGED_FILES" ]; then
36+
echo "Changed Python files to check:"
37+
echo "$CHANGED_FILES"
38+
echo ""
39+
40+
# Check for 'logger = logging.getLogger(__name__)' in changed .py files.
41+
# The grep command will exit with a non-zero status code if the pattern is not found.
42+
# We invert the exit code with ! so the step succeeds if the pattern is NOT found.
43+
set +e
44+
FILES_WITH_FORBIDDEN_LOGGER=$(grep -lE 'logger = logging\.getLogger\(__name__\)' $CHANGED_FILES)
45+
GREP_EXIT_CODE=$?
46+
set -e
47+
48+
# grep exits with 0 if matches are found, 1 if no matches are found.
49+
# A non-zero exit code other than 1 indicates an error.
50+
if [ $GREP_EXIT_CODE -eq 0 ]; then
51+
echo "❌ Found forbidden use of 'logger = logging.getLogger(__name__)'. Please use 'logger = logging.getLogger('google_adk.' + __name__)' instead."
52+
echo "The following files contain the forbidden pattern:"
53+
echo "$FILES_WITH_FORBIDDEN_LOGGER"
54+
exit 1
55+
elif [ $GREP_EXIT_CODE -eq 1 ]; then
56+
echo "✅ No instances of 'logger = logging.getLogger(__name__)' found in changed Python files."
57+
fi
58+
else
59+
echo "✅ No relevant Python files found."
60+
fi
61+
62+
- name: Check for import pattern in certain changed Python files
63+
run: |
64+
git fetch origin ${{ github.base_ref }}
65+
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.py$' | grep -v -E '__init__.py$|version.py$|tests/.*|contributing/samples/' || true)
66+
if [ -n "$CHANGED_FILES" ]; then
67+
echo "Changed Python files to check:"
68+
echo "$CHANGED_FILES"
69+
echo ""
70+
71+
# Use grep -L to find files that DO NOT contain the pattern.
72+
# This command will output a list of non-compliant files.
73+
FILES_MISSING_IMPORT=$(grep -L 'from __future__ import annotations' $CHANGED_FILES)
74+
75+
# Check if the list of non-compliant files is empty
76+
if [ -z "$FILES_MISSING_IMPORT" ]; then
77+
echo "✅ All modified Python files include 'from __future__ import annotations'."
78+
exit 0
79+
else
80+
echo "❌ The following files are missing 'from __future__ import annotations':"
81+
echo "$FILES_MISSING_IMPORT"
82+
echo "This import is required to allow forward references in type annotations without quotes."
83+
exit 1
84+
fi
85+
else
86+
echo "✅ No relevant Python files found."
87+
fi
88+
89+
- name: Check for import from cli package in certain changed Python files
90+
run: |
91+
git fetch origin ${{ github.base_ref }}
92+
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.py$' | grep -v -E 'cli/.*|tests/.*|contributing/samples/' || true)
93+
if [ -n "$CHANGED_FILES" ]; then
94+
echo "Changed Python files to check:"
95+
echo "$CHANGED_FILES"
96+
echo ""
97+
98+
set +e
99+
FILES_WITH_FORBIDDEN_IMPORT=$(grep -lE '^from.*cli.*import.*$' $CHANGED_FILES)
100+
GREP_EXIT_CODE=$?
101+
set -e
102+
103+
if [[ $GREP_EXIT_CODE -eq 0 ]]; then
104+
echo "❌ Do not import from the cli package outside of the cli package. If you need to reuse the code elsewhere, please move the code outside of the cli package."
105+
echo "The following files contain the forbidden pattern:"
106+
echo "$FILES_WITH_FORBIDDEN_IMPORT"
107+
exit 1
108+
else
109+
echo "✅ No instances of importing from the cli package found in relevant changed Python files."
110+
fi
111+
else
112+
echo "✅ No relevant Python files found."
113+
fi
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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+
import os
16+
import random
17+
import time
18+
19+
from google.adk import Agent
20+
from google.adk.tools.tool_context import ToolContext
21+
from google.genai import types
22+
import requests
23+
24+
# Read the PAT from the environment variable
25+
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN") # Ensure you've set this in your shell
26+
if not GITHUB_TOKEN:
27+
raise ValueError("GITHUB_TOKEN environment variable not set")
28+
29+
# Repository information
30+
OWNER = "google"
31+
REPO = "adk-python"
32+
33+
# Base URL for the GitHub API
34+
BASE_URL = "https://api.github.com"
35+
36+
# Headers including the Authorization header
37+
headers = {
38+
"Authorization": f"token {GITHUB_TOKEN}",
39+
"Accept": "application/vnd.github.v3+json",
40+
}
41+
42+
43+
def list_issues(per_page: int):
44+
"""
45+
Generator to list all issues for the repository by handling pagination.
46+
47+
Args:
48+
per_page: number of pages to return per page.
49+
50+
"""
51+
state = "open"
52+
# only process the 1st page for testing for now
53+
page = 1
54+
results = []
55+
url = ( # :contentReference[oaicite:16]{index=16}
56+
f"{BASE_URL}/repos/{OWNER}/{REPO}/issues"
57+
)
58+
# Warning: let's only handle max 10 issues at a time to avoid bad results
59+
params = {"state": state, "per_page": per_page, "page": page}
60+
response = requests.get(url, headers=headers, params=params)
61+
response.raise_for_status() # :contentReference[oaicite:17]{index=17}
62+
issues = response.json()
63+
if not issues:
64+
return []
65+
for issue in issues:
66+
# Skip pull requests (issues API returns PRs as well)
67+
if "pull_request" in issue:
68+
continue
69+
results.append(issue)
70+
return results
71+
72+
73+
def add_label_to_issue(issue_number: str, label: str):
74+
"""
75+
Add the specified label to the given issue number.
76+
77+
Args:
78+
issue_number: issue number of the Github issue, in string foramt.
79+
label: label to assign
80+
"""
81+
url = f"{BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/labels"
82+
payload = [label]
83+
response = requests.post(url, headers=headers, json=payload)
84+
response.raise_for_status()
85+
return response.json()
86+
87+
88+
root_agent = Agent(
89+
model="gemini-2.5-pro-preview-05-06",
90+
name="adk_triaging_assistant",
91+
description="Triage ADK issues.",
92+
instruction="""
93+
You are a Github adk-python repo triaging bot. You will help get issues, and label them.
94+
Here are the rules for labeling:
95+
- If the user is asking about documentation-related questions, label it with "documentation".
96+
- If it's about session, memory services, label it with "services"
97+
- If it's about UI/web, label it with "question"
98+
- If it's related to tools, label it with "tools"
99+
- If it's about agent evalaution, then label it with "eval".
100+
- If it's about streaming/live, label it with "live".
101+
- If it's about model support(non-Gemini, like Litellm, Ollama, OpenAI models), label it with "models".
102+
- If it's about tracing, label it with "tracing".
103+
- If it's agent orchestration, agent definition, label it with "core".
104+
- If you can't find a appropriate labels for the issue, return the issues to user to decide.
105+
""",
106+
tools=[
107+
list_issues,
108+
add_label_to_issue,
109+
],
110+
generate_content_config=types.GenerateContentConfig(
111+
safety_settings=[
112+
types.SafetySetting( # avoid false alarm about rolling dice.
113+
category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
114+
threshold=types.HarmBlockThreshold.OFF,
115+
),
116+
]
117+
),
118+
)

contributing/samples/mcp_stdio_server_agent/agent.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
import os
1717

1818
from google.adk.agents.llm_agent import LlmAgent
19+
from google.adk.tools.mcp_tool import StdioConnectionParams
1920
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
20-
from google.adk.tools.mcp_tool.mcp_toolset import StdioServerParameters
21+
from mcp import StdioServerParameters
2122

2223
_allowed_path = os.path.dirname(os.path.abspath(__file__))
2324

@@ -31,13 +32,16 @@
3132
""",
3233
tools=[
3334
MCPToolset(
34-
connection_params=StdioServerParameters(
35-
command='npx',
36-
args=[
37-
'-y', # Arguments for the command
38-
'@modelcontextprotocol/server-filesystem',
39-
_allowed_path,
40-
],
35+
connection_params=StdioConnectionParams(
36+
server_params=StdioServerParameters(
37+
command='npx',
38+
args=[
39+
'-y', # Arguments for the command
40+
'@modelcontextprotocol/server-filesystem',
41+
_allowed_path,
42+
],
43+
),
44+
timeout=5,
4145
),
4246
# don't want agent to do write operation
4347
# you can also do below

src/google/adk/cli/agent_graph.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def should_build_agent_cluster(tool_or_agent: Union[BaseAgent, BaseTool]):
145145
return False
146146

147147
def build_cluster(child: graphviz.Digraph, agent: BaseAgent, name: str):
148-
if isinstance(agent, LoopAgent):
148+
if isinstance(agent, LoopAgent) and parent_agent:
149149
# Draw the edge from the parent agent to the first sub-agent
150150
draw_edge(parent_agent.name, agent.sub_agents[0].name)
151151
length = len(agent.sub_agents)
@@ -162,7 +162,7 @@ def build_cluster(child: graphviz.Digraph, agent: BaseAgent, name: str):
162162
].name,
163163
)
164164
currLength += 1
165-
elif isinstance(agent, SequentialAgent):
165+
elif isinstance(agent, SequentialAgent) and parent_agent:
166166
# Draw the edge from the parent agent to the first sub-agent
167167
draw_edge(parent_agent.name, agent.sub_agents[0].name)
168168
length = len(agent.sub_agents)
@@ -179,7 +179,7 @@ def build_cluster(child: graphviz.Digraph, agent: BaseAgent, name: str):
179179
) if currLength != length - 1 else None
180180
currLength += 1
181181

182-
elif isinstance(agent, ParallelAgent):
182+
elif isinstance(agent, ParallelAgent) and parent_agent:
183183
# Draw the edge from the parent agent to every sub-agent
184184
for sub_agent in agent.sub_agents:
185185
build_graph(child, sub_agent, highlight_pairs)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@
2929
<style>html{color-scheme:dark}html{--mat-sys-background:light-dark(#fcf9f8, #131314);--mat-sys-error:light-dark(#ba1a1a, #ffb4ab);--mat-sys-error-container:light-dark(#ffdad6, #93000a);--mat-sys-inverse-on-surface:light-dark(#f3f0f0, #313030);--mat-sys-inverse-primary:light-dark(#c1c7cd, #595f65);--mat-sys-inverse-surface:light-dark(#313030, #e5e2e2);--mat-sys-on-background:light-dark(#1c1b1c, #e5e2e2);--mat-sys-on-error:light-dark(#ffffff, #690005);--mat-sys-on-error-container:light-dark(#410002, #ffdad6);--mat-sys-on-primary:light-dark(#ffffff, #2b3136);--mat-sys-on-primary-container:light-dark(#161c21, #dde3e9);--mat-sys-on-primary-fixed:light-dark(#161c21, #161c21);--mat-sys-on-primary-fixed-variant:light-dark(#41474d, #41474d);--mat-sys-on-secondary:light-dark(#ffffff, #003061);--mat-sys-on-secondary-container:light-dark(#001b3c, #d5e3ff);--mat-sys-on-secondary-fixed:light-dark(#001b3c, #001b3c);--mat-sys-on-secondary-fixed-variant:light-dark(#0f4784, #0f4784);--mat-sys-on-surface:light-dark(#1c1b1c, #e5e2e2);--mat-sys-on-surface-variant:light-dark(#44474a, #e1e2e6);--mat-sys-on-tertiary:light-dark(#ffffff, #2b3136);--mat-sys-on-tertiary-container:light-dark(#161c21, #dde3e9);--mat-sys-on-tertiary-fixed:light-dark(#161c21, #161c21);--mat-sys-on-tertiary-fixed-variant:light-dark(#41474d, #41474d);--mat-sys-outline:light-dark(#74777b, #8e9194);--mat-sys-outline-variant:light-dark(#c4c7ca, #44474a);--mat-sys-primary:light-dark(#595f65, #c1c7cd);--mat-sys-primary-container:light-dark(#dde3e9, #41474d);--mat-sys-primary-fixed:light-dark(#dde3e9, #dde3e9);--mat-sys-primary-fixed-dim:light-dark(#c1c7cd, #c1c7cd);--mat-sys-scrim:light-dark(#000000, #000000);--mat-sys-secondary:light-dark(#305f9d, #a7c8ff);--mat-sys-secondary-container:light-dark(#d5e3ff, #0f4784);--mat-sys-secondary-fixed:light-dark(#d5e3ff, #d5e3ff);--mat-sys-secondary-fixed-dim:light-dark(#a7c8ff, #a7c8ff);--mat-sys-shadow:light-dark(#000000, #000000);--mat-sys-surface:light-dark(#fcf9f8, #131314);--mat-sys-surface-bright:light-dark(#fcf9f8, #393939);--mat-sys-surface-container:light-dark(#f0eded, #201f20);--mat-sys-surface-container-high:light-dark(#eae7e7, #2a2a2a);--mat-sys-surface-container-highest:light-dark(#e5e2e2, #393939);--mat-sys-surface-container-low:light-dark(#f6f3f3, #1c1b1c);--mat-sys-surface-container-lowest:light-dark(#ffffff, #0e0e0e);--mat-sys-surface-dim:light-dark(#dcd9d9, #131314);--mat-sys-surface-tint:light-dark(#595f65, #c1c7cd);--mat-sys-surface-variant:light-dark(#e1e2e6, #44474a);--mat-sys-tertiary:light-dark(#595f65, #c1c7cd);--mat-sys-tertiary-container:light-dark(#dde3e9, #41474d);--mat-sys-tertiary-fixed:light-dark(#dde3e9, #dde3e9);--mat-sys-tertiary-fixed-dim:light-dark(#c1c7cd, #c1c7cd);--mat-sys-neutral-variant20:#2d3134;--mat-sys-neutral10:#1c1b1c}html{--mat-sys-level0:0px 0px 0px 0px rgba(0, 0, 0, .2), 0px 0px 0px 0px rgba(0, 0, 0, .14), 0px 0px 0px 0px rgba(0, 0, 0, .12)}html{--mat-sys-level1:0px 2px 1px -1px rgba(0, 0, 0, .2), 0px 1px 1px 0px rgba(0, 0, 0, .14), 0px 1px 3px 0px rgba(0, 0, 0, .12)}html{--mat-sys-level2:0px 3px 3px -2px rgba(0, 0, 0, .2), 0px 3px 4px 0px rgba(0, 0, 0, .14), 0px 1px 8px 0px rgba(0, 0, 0, .12)}html{--mat-sys-level3:0px 3px 5px -1px rgba(0, 0, 0, .2), 0px 6px 10px 0px rgba(0, 0, 0, .14), 0px 1px 18px 0px rgba(0, 0, 0, .12)}html{--mat-sys-level4:0px 5px 5px -3px rgba(0, 0, 0, .2), 0px 8px 10px 1px rgba(0, 0, 0, .14), 0px 3px 14px 2px rgba(0, 0, 0, .12)}html{--mat-sys-level5:0px 7px 8px -4px rgba(0, 0, 0, .2), 0px 12px 17px 2px rgba(0, 0, 0, .14), 0px 5px 22px 4px rgba(0, 0, 0, .12)}html{--mat-sys-corner-extra-large:28px;--mat-sys-corner-extra-large-top:28px 28px 0 0;--mat-sys-corner-extra-small:4px;--mat-sys-corner-extra-small-top:4px 4px 0 0;--mat-sys-corner-full:9999px;--mat-sys-corner-large:16px;--mat-sys-corner-large-end:0 16px 16px 0;--mat-sys-corner-large-start:16px 0 0 16px;--mat-sys-corner-large-top:16px 16px 0 0;--mat-sys-corner-medium:12px;--mat-sys-corner-none:0;--mat-sys-corner-small:8px}html{--mat-sys-dragged-state-layer-opacity:.16;--mat-sys-focus-state-layer-opacity:.12;--mat-sys-hover-state-layer-opacity:.08;--mat-sys-pressed-state-layer-opacity:.12}html{font-family:Google Sans,Helvetica Neue,sans-serif!important}body{height:100vh;margin:0}:root{--mat-sys-primary:black;--mdc-checkbox-selected-icon-color:white;--mat-sys-background:#131314;--mat-tab-header-active-label-text-color:#8AB4F8;--mat-tab-header-active-hover-label-text-color:#8AB4F8;--mat-tab-header-active-focus-label-text-color:#8AB4F8;--mat-tab-header-label-text-weight:500;--mdc-text-button-label-text-color:#89b4f8}:root{--mdc-dialog-container-color:#2b2b2f}:root{--mdc-dialog-subhead-color:white}:root{--mdc-circular-progress-active-indicator-color:#a8c7fa}:root{--mdc-circular-progress-size:80}</style><link rel="stylesheet" href="./styles-4VDSPQ37.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="./styles-4VDSPQ37.css"></noscript></head>
3030
<body>
3131
<app-root></app-root>
32-
<script src="./polyfills-FFHMD2TL.js" type="module"></script><script src="./main-CS5OLUMF.js" type="module"></script></body>
32+
<script src="./polyfills-FFHMD2TL.js" type="module"></script><script src="./main-DY547BWY.js" type="module"></script></body>
3333
</html>

0 commit comments

Comments
 (0)