Skip to content

Commit 80b6e8d

Browse files
authored
Merge branch 'main' into olliefr-4500
2 parents 79382b4 + 7b7ddda commit 80b6e8d

31 files changed

+2730
-125
lines changed

.github/release-please-config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"packages": {
55
".": {
66
"release-type": "python",
7+
"versioning": "always-bump-minor",
78
"package-name": "google-adk",
89
"include-component-in-tag": false,
910
"skip-github-release": true,

.github/workflows/check-file-contents.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ jobs:
3030

3131
- name: Check for logger pattern in all changed Python files
3232
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)
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)
3535
if [ -n "$CHANGED_FILES" ]; then
3636
echo "Changed Python files to check:"
3737
echo "$CHANGED_FILES"
@@ -61,8 +61,8 @@ jobs:
6161
6262
- name: Check for import pattern in certain changed Python files
6363
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)
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)
6666
if [ -n "$CHANGED_FILES" ]; then
6767
echo "Changed Python files to check:"
6868
echo "$CHANGED_FILES"
@@ -88,8 +88,8 @@ jobs:
8888
8989
- name: Check for import from cli package in certain changed Python files
9090
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/.*|src/google/adk/tools/apihub_tool/apihub_toolset.py|tests/.*|contributing/samples/' || true)
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/.*|src/google/adk/tools/apihub_tool/apihub_toolset.py|tests/.*|contributing/samples/' || true)
9393
if [ -n "$CHANGED_FILES" ]; then
9494
echo "Changed Python files to check:"
9595
echo "$CHANGED_FILES"
@@ -110,4 +110,4 @@ jobs:
110110
fi
111111
else
112112
echo "✅ No relevant Python files found."
113-
fi
113+
fi

.github/workflows/isort.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ jobs:
4242
- name: Run isort on changed files
4343
id: run_isort
4444
run: |
45-
git fetch origin ${{ github.base_ref }}
46-
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.py$' || true)
45+
git fetch origin ${GITHUB_BASE_REF}
46+
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' || true)
4747
if [ -n "$CHANGED_FILES" ]; then
4848
echo "Changed Python files:"
4949
echo "$CHANGED_FILES"

.github/workflows/pyink.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ jobs:
4242
- name: Run pyink on changed files
4343
id: run_pyink
4444
run: |
45-
git fetch origin ${{ github.base_ref }}
46-
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.py$' || true)
45+
git fetch origin ${GITHUB_BASE_REF}
46+
CHANGED_FILES=$(git diff --diff-filter=ACMR --name-only origin/${GITHUB_BASE_REF}...HEAD | grep -E '\.py$' || true)
4747
if [ -n "$CHANGED_FILES" ]; then
4848
echo "Changed Python files:"
4949
echo "$CHANGED_FILES"

.github/workflows/release-cherry-pick.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ jobs:
3030
3131
- name: Cherry-pick commit
3232
run: |
33-
echo "Cherry-picking ${{ inputs.commit_sha }} to release/candidate"
34-
git cherry-pick ${{ inputs.commit_sha }}
33+
echo "Cherry-picking ${INPUTS_COMMIT_SHA} to release/candidate"
34+
git cherry-pick ${INPUTS_COMMIT_SHA}
35+
env:
36+
INPUTS_COMMIT_SHA: ${{ inputs.commit_sha }}
3537

3638
- name: Push changes
3739
run: |

.github/workflows/release-finalize.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ jobs:
6868
- name: Rename release/candidate to release/v{version}
6969
if: steps.check.outputs.is_release_pr == 'true'
7070
run: |
71-
VERSION="v${{ steps.version.outputs.version }}"
71+
VERSION="v${STEPS_VERSION_OUTPUTS_VERSION}"
7272
git push origin "release/candidate:refs/heads/release/$VERSION" ":release/candidate"
7373
echo "Renamed release/candidate to release/$VERSION"
74+
env:
75+
STEPS_VERSION_OUTPUTS_VERSION: ${{ steps.version.outputs.version }}
7476

7577
- name: Update PR label to tagged
7678
if: steps.check.outputs.is_release_pr == 'true'

.github/workflows/release-publish.yml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ jobs:
1515
steps:
1616
- name: Validate branch
1717
run: |
18-
if [[ ! "${{ github.ref_name }}" =~ ^release/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
18+
if [[ ! "${GITHUB_REF_NAME}" =~ ^release/v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
1919
echo "Error: Must run from a release/v* branch (e.g., release/v0.3.0)"
2020
exit 1
2121
fi
2222
2323
- name: Extract version
2424
id: version
2525
run: |
26-
VERSION="${{ github.ref_name }}"
26+
VERSION="${GITHUB_REF_NAME}"
2727
VERSION="${VERSION#release/v}"
2828
echo "version=$VERSION" >> $GITHUB_OUTPUT
2929
echo "Publishing version: $VERSION"
@@ -51,9 +51,10 @@ jobs:
5151
- name: Create merge-back PR
5252
env:
5353
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
54+
STEPS_VERSION_OUTPUTS_VERSION: ${{ steps.version.outputs.version }}
5455
run: |
5556
gh pr create \
5657
--base main \
57-
--head "${{ github.ref_name }}" \
58-
--title "chore: merge release v${{ steps.version.outputs.version }} to main" \
59-
--body "Syncs version bump and CHANGELOG from release v${{ steps.version.outputs.version }} to main."
58+
--head "${GITHUB_REF_NAME}" \
59+
--title "chore: merge release v${STEPS_VERSION_OUTPUTS_VERSION} to main" \
60+
--body "Syncs version bump and CHANGELOG from release v${STEPS_VERSION_OUTPUTS_VERSION} to main."

contributing/samples/bigtable/agent.py

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@
1616

1717
from google.adk.agents.llm_agent import LlmAgent
1818
from google.adk.auth.auth_credential import AuthCredentialTypes
19+
from google.adk.tools.bigtable import query_tool as bigtable_query_tool
1920
from google.adk.tools.bigtable.bigtable_credentials import BigtableCredentialsConfig
2021
from google.adk.tools.bigtable.bigtable_toolset import BigtableToolset
2122
from google.adk.tools.bigtable.settings import BigtableToolSettings
23+
from google.adk.tools.google_tool import GoogleTool
2224
import google.auth
25+
from google.cloud.bigtable.data.execute_query.metadata import SqlType
2326

24-
# Define an appropriate credential type
25-
CREDENTIALS_TYPE = AuthCredentialTypes.OAUTH2
26-
27+
# Define an appropriate credential type.
28+
# None for Application Default Credentials
29+
CREDENTIALS_TYPE = None
2730

2831
# Define Bigtable tool config with read capability set to allowed.
2932
tool_settings = BigtableToolSettings()
@@ -59,6 +62,53 @@
5962
credentials_config=credentials_config, bigtable_tool_settings=tool_settings
6063
)
6164

65+
_BIGTABLE_PROJECT_ID = "google.com:cloud-bigtable-dev"
66+
_BIGTABLE_INSTANCE_ID = "annenguyen-bus-instance"
67+
68+
69+
def search_hotels_by_location(
70+
location_name: str,
71+
credentials: google.auth.credentials.Credentials,
72+
settings: BigtableToolSettings,
73+
tool_context: google.adk.tools.tool_context.ToolContext,
74+
):
75+
"""Search hotels by location name.
76+
77+
This function takes a location name and returns a list of hotels
78+
in that area.
79+
80+
Args:
81+
location_name (str): The geographical location (e.g., city or town) for the
82+
hotel search.
83+
Example: { "location_name": "Basel" }
84+
85+
Returns:
86+
The hotels name, price tier.
87+
"""
88+
89+
sql_template = """
90+
SELECT
91+
TO_INT64(cf['id']) as id,
92+
CAST(cf['name'] AS STRING) AS name,
93+
CAST(cf['location'] AS STRING) AS location,
94+
CAST(cf['price_tier'] AS STRING) AS price_tier,
95+
CAST(cf['checkin_date'] AS STRING) AS checkin_date,
96+
CAST(cf['checkout_date'] AS STRING) AS checkout_date
97+
FROM hotels
98+
WHERE LOWER(CAST(cf['location'] AS STRING)) LIKE LOWER(CONCAT('%', @location_name, '%'))
99+
"""
100+
return bigtable_query_tool.execute_sql(
101+
project_id=_BIGTABLE_PROJECT_ID,
102+
instance_id=_BIGTABLE_INSTANCE_ID,
103+
query=sql_template,
104+
credentials=credentials,
105+
settings=settings,
106+
tool_context=tool_context,
107+
parameters={"location": location_name},
108+
parameter_types={"location": SqlType.String()},
109+
)
110+
111+
62112
# The variable name `root_agent` determines what your root agent is for the
63113
# debug CLI
64114
root_agent = LlmAgent(
@@ -72,5 +122,13 @@
72122
You are a data agent with access to several Bigtable tools.
73123
Make use of those tools to answer the user's questions.
74124
""",
75-
tools=[bigtable_toolset],
125+
tools=[
126+
bigtable_toolset,
127+
# Or, uncomment to use customized Bigtable tools.
128+
# GoogleTool(
129+
# func=search_hotels_by_location,
130+
# credentials_config=credentials_config,
131+
# tool_settings=tool_settings,
132+
# ),
133+
],
76134
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2026 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+
"""A2A agents package."""
16+
17+
from .config import A2aRemoteAgentConfig
18+
from .config import ParametersConfig
19+
from .config import RequestInterceptor
20+
21+
__all__ = [
22+
"A2aRemoteAgentConfig",
23+
"ParametersConfig",
24+
"RequestInterceptor",
25+
]

src/google/adk/a2a/agent/config.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Copyright 2026 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+
"""Configuration for A2A agents."""
16+
17+
from __future__ import annotations
18+
19+
from typing import Any
20+
from typing import Awaitable
21+
from typing import Callable
22+
from typing import Optional
23+
from typing import Union
24+
25+
from a2a.client.middleware import ClientCallContext
26+
from a2a.server.events import Event as A2AEvent
27+
from a2a.types import Message as A2AMessage
28+
from a2a.types import MessageSendConfiguration
29+
from pydantic import BaseModel
30+
31+
from ...agents.invocation_context import InvocationContext
32+
from ...events.event import Event
33+
34+
35+
class ParametersConfig(BaseModel):
36+
"""Configuration for the parameters passed to the A2A send_message request."""
37+
38+
request_metadata: Optional[dict[str, Any]] = None
39+
client_call_context: Optional[ClientCallContext] = None
40+
# TODO: Add support for requested_extension and
41+
# message_send_configuration once they are supported by the A2A client.
42+
#
43+
# requested_extension: Optional[list[str]] = None
44+
# message_send_configuration: Optional[MessageSendConfiguration] = None
45+
46+
47+
class RequestInterceptor(BaseModel):
48+
"""Interceptor for A2A requests."""
49+
50+
before_request: Optional[
51+
Callable[
52+
[InvocationContext, A2AMessage, ParametersConfig],
53+
Awaitable[tuple[Union[A2AMessage, Event], ParametersConfig]],
54+
]
55+
] = None
56+
"""Hook executed before the agent starts processing the request.
57+
58+
Returns an Event if the request should be aborted and the Event
59+
returned to the caller.
60+
"""
61+
62+
after_request: Optional[
63+
Callable[
64+
[InvocationContext, A2AEvent, Event], Awaitable[Union[Event, None]]
65+
]
66+
] = None
67+
"""Hook executed after the agent has processed the request.
68+
69+
Returns None if the event should not be sent to the caller.
70+
"""
71+
72+
73+
class A2aRemoteAgentConfig(BaseModel):
74+
"""Configuration for the RemoteA2aAgent."""
75+
76+
request_interceptors: Optional[list[RequestInterceptor]] = None

0 commit comments

Comments
 (0)