Skip to content

Commit 68b5433

Browse files
authored
Merge branch 'main' into fix-a2a-json-unboundlocal
2 parents 484d682 + bf4143a commit 68b5433

117 files changed

Lines changed: 7343 additions & 840 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/analyze-releases-for-adk-docs-updates.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ jobs:
4545

4646
steps:
4747
- name: Checkout repository
48-
uses: actions/checkout@v6
48+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
4949

5050
- name: Set up Python
51-
uses: actions/setup-python@v6
51+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
5252
with:
5353
python-version: '3.11'
5454

5555
- name: Load adk-bot SSH Private Key
56-
uses: webfactory/ssh-agent@v0.9.1
56+
uses: webfactory/ssh-agent@a6f90b1f127823b31d4d4a8d96047790581349bd # v0.9.1
5757
with:
5858
ssh-private-key: ${{ secrets.ADK_BOT_SSH_PRIVATE_KEY }}
5959

@@ -64,7 +64,7 @@ jobs:
6464
6565
- name: Restore session DB from cache
6666
if: ${{ github.event.inputs.resume == 'true' }}
67-
uses: actions/cache/restore@v4
67+
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
6868
with:
6969
path: contributing/samples/adk_team/adk_documentation/adk_release_analyzer/sessions.db
7070
key: analyzer-session-db-${{ github.run_id }}-${{ github.run_attempt }}
@@ -102,7 +102,7 @@ jobs:
102102
103103
- name: Save session DB to cache
104104
if: always()
105-
uses: actions/cache/save@v4
105+
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
106106
with:
107107
path: contributing/samples/adk_team/adk_documentation/adk_release_analyzer/sessions.db
108108
key: analyzer-session-db-${{ github.run_id }}-${{ github.run_attempt }}

.github/workflows/release-finalize.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
echo "manifest_file=.github/.release-please-manifest.json" >> $GITHUB_OUTPUT
6060
fi
6161
62-
- uses: actions/checkout@v6
62+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
6363
if: steps.check.outputs.is_release_pr == 'true'
6464
with:
6565
ref: ${{ github.event.pull_request.base.ref }}

.github/workflows/release-update-adk-web.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636

3737
steps:
3838
- name: Checkout repository
39-
uses: actions/checkout@v6
39+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
4040
with:
4141
persist-credentials: false
4242

@@ -78,7 +78,7 @@ jobs:
7878
echo "email=$(echo "$USER_JSON" | jq -r '.id')+$(echo "$USER_JSON" | jq -r '.login')@users.noreply.github.com" >> $GITHUB_OUTPUT
7979
8080
- name: Create Pull Request
81-
uses: peter-evans/create-pull-request@v6
81+
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6
8282
with:
8383
token: ${{ secrets.RELEASE_PAT }}
8484
commit-message: "Update compiled adk web files from ${{ github.event.inputs.adk_web_repo }}@${{ github.event.inputs.adk_web_tag || 'latest' }}"
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Eventarc Tools Sample
2+
3+
## Introduction
4+
5+
This sample agent demonstrates the Eventarc first-party tool in ADK,
6+
distributed via the `google.adk.integrations.eventarc` module. This tool suite currently includes:
7+
8+
1. `publish_message`
9+
10+
Publishes a structured event in CloudEvents format to a Google Cloud Eventarc message bus.
11+
12+
## How to use
13+
14+
Set up environment variables in your `.env` file for using
15+
[Google AI Studio](https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-ai-studio)
16+
or
17+
[Google Cloud Vertex AI](https://google.github.io/adk-docs/get-started/quickstart/#gemini---google-cloud-vertex-ai)
18+
for the LLM service for your agent. For example, for using Google AI Studio you
19+
would set:
20+
21+
- GOOGLE_GENAI_USE_VERTEXAI=FALSE
22+
- GOOGLE_API_KEY={your api key}
23+
24+
### With Application Default Credentials
25+
26+
This mode is useful for quick development when the agent builder is the only
27+
user interacting with the agent. The tools are run with these credentials.
28+
29+
1. Create application default credentials on the machine where the agent would
30+
be running by following https://cloud.google.com/docs/authentication/provide-credentials-adc.
31+
32+
1. Set `CREDENTIALS_TYPE=None` in `agent.py`
33+
34+
1. Run the agent
35+
36+
### With Service Account Keys
37+
38+
This mode is useful for quick development when the agent builder wants to run
39+
the agent with service account credentials. The tools are run with these
40+
credentials.
41+
42+
1. Create service account key by following https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys.
43+
44+
1. Set `CREDENTIALS_TYPE=AuthCredentialTypes.SERVICE_ACCOUNT` in `agent.py`
45+
46+
1. Download the key file and replace `"service_account_key.json"` with the path
47+
48+
1. Run the agent
49+
50+
### With Interactive OAuth
51+
52+
1. Follow
53+
https://developers.google.com/identity/protocols/oauth2#1.-obtain-oauth-2.0-credentials-from-the-dynamic_data.setvar.console_name.
54+
to get your client id and client secret. Be sure to choose "web" as your client
55+
type.
56+
57+
1. Follow https://developers.google.com/workspace/guides/configure-oauth-consent to add scope "https://www.googleapis.com/auth/cloud-platform".
58+
59+
1. Follow https://developers.google.com/identity/protocols/oauth2/web-server#creatingcred to add http://localhost/dev-ui/ to "Authorized redirect URIs".
60+
61+
Note: localhost here is just a hostname that you use to access the dev ui,
62+
replace it with the actual hostname you use to access the dev ui.
63+
64+
1. For 1st run, allow popup for localhost in Chrome.
65+
66+
1. Configure your `.env` file to add two more variables before running the agent:
67+
68+
- OAUTH_CLIENT_ID={your client id}
69+
- OAUTH_CLIENT_SECRET={your client secret}
70+
71+
Note: don't create a separate .env, instead put it to the same .env file that
72+
stores your Vertex AI or Dev ML credentials
73+
74+
1. Set `CREDENTIALS_TYPE=AuthCredentialTypes.OAUTH2` in `agent.py` and run the agent
75+
76+
### With Agent Identity (in Agent Runtime / Vertex AI Reasoning Engine)
77+
78+
When deploying this agent to Agent Runtime, it can use its unique SPIFFE-based Agent Identity to authenticate. This is the recommended security best practice.
79+
80+
1. **Configure Deployment**: Create a `.agent_engine_config.json` file in this directory to specify the identity type:
81+
82+
```json
83+
{
84+
"identity_type": "AGENT_IDENTITY"
85+
}
86+
```
87+
88+
1. **Use Default Credentials**: Leave `CREDENTIALS_TYPE = None` in `agent.py` (which is the default). This configures the agent to use Application Default Credentials (ADC), which automatically resolves to the Agent Identity in the container runtime environment.
89+
90+
1. **Deploy the Agent**: Deploy your agent using the ADK CLI:
91+
92+
```bash
93+
uv run adk deploy agent_engine \
94+
--project=YOUR_PROJECT_ID \
95+
--region=YOUR_REGION \
96+
--display_name=eventarc-agent-test \
97+
contributing/samples/integrations/eventarc
98+
```
99+
100+
Take note of the generated **Reasoning Engine ID** (e.g., `1234567890`) and the **Project Number** of your project.
101+
102+
1. **Grant IAM Permissions**: Grant the Eventarc Message Bus User role (`roles/eventarc.messageBusUser`) to the Agent Identity principal at the project level:
103+
104+
```bash
105+
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
106+
--member="principal://agents.global.org-171145599760.system.id.goog/resources/aiplatform/projects/YOUR_PROJECT_NUMBER/locations/YOUR_REGION/reasoningEngines/YOUR_REASONING_ENGINE_ID" \
107+
--role="roles/eventarc.messageBusUser"
108+
```
109+
110+
*Note: Eventarc Advanced message buses require `roles/eventarc.messageBusUser` for publishing, rather than `roles/eventarc.publisher`.*
111+
112+
## Sample prompts
113+
114+
- "Publish an event of type 'com.example.hello' to bus 'projects/my-project/locations/global/messageBuses/my-bus' with data 'Hello World' and source '//my/agent'"
115+
- "Send a JSON payload to Eventarc bus 'projects/my-project/locations/global/messageBuses/my-bus' representing a user sign-up event"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
import os
16+
import textwrap
17+
18+
from google.adk.agents.llm_agent import LlmAgent
19+
from google.adk.auth.auth_credential import AuthCredentialTypes
20+
from google.adk.integrations.eventarc import EventarcCredentialsConfig
21+
from google.adk.integrations.eventarc import EventarcToolConfig
22+
from google.adk.integrations.eventarc import EventarcToolset
23+
import google.auth
24+
25+
# Define the desired credential type.
26+
# By default use Application Default Credentials (ADC) from the local
27+
# environment, which can be set up by following
28+
# https://cloud.google.com/docs/authentication/provide-credentials-adc.
29+
CREDENTIALS_TYPE = None
30+
31+
# Define an appropriate application name
32+
EVENTARC_AGENT_NAME = "adk_sample_eventarc_agent"
33+
34+
35+
# Define Eventarc tool config.
36+
# You can optionally set the project_id here, or let the agent infer it from context/user input.
37+
tool_config = EventarcToolConfig(project_id=os.getenv("GOOGLE_CLOUD_PROJECT"))
38+
39+
if CREDENTIALS_TYPE == AuthCredentialTypes.OAUTH2:
40+
# Initialize the tools to do interactive OAuth
41+
# The environment variables OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET
42+
# must be set
43+
credentials_config = EventarcCredentialsConfig(
44+
client_id=os.getenv("OAUTH_CLIENT_ID"),
45+
client_secret=os.getenv("OAUTH_CLIENT_SECRET"),
46+
)
47+
elif CREDENTIALS_TYPE == AuthCredentialTypes.SERVICE_ACCOUNT:
48+
# Initialize the tools to use the credentials in the service account key.
49+
# If this flow is enabled, make sure to replace the file path with your own
50+
# service account key file
51+
# https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys
52+
creds, _ = google.auth.load_credentials_from_file("service_account_key.json")
53+
credentials_config = EventarcCredentialsConfig(credentials=creds)
54+
else:
55+
# Initialize the tools to use the application default credentials.
56+
# https://cloud.google.com/docs/authentication/provide-credentials-adc
57+
application_default_credentials, _ = google.auth.default()
58+
credentials_config = EventarcCredentialsConfig(
59+
credentials=application_default_credentials
60+
)
61+
62+
eventarc_toolset = EventarcToolset(
63+
credentials_config=credentials_config, tool_config=tool_config
64+
)
65+
66+
# The variable name `root_agent` determines what your root agent is for the
67+
# debug CLI
68+
root_agent = LlmAgent(
69+
name=EVENTARC_AGENT_NAME,
70+
description=(
71+
"Agent to publish structured CloudEvents to Google Cloud Eventarc."
72+
),
73+
instruction=textwrap.dedent("""\
74+
You are a cloud engineer agent with access to Google Cloud Eventarc tools.
75+
You can publish CloudEvents structured messages to Eventarc message buses.
76+
"""),
77+
tools=[eventarc_toolset],
78+
)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Managed Agent — System Instruction
2+
3+
> For setup, authentication, backends, and background on `ManagedAgent`, see the
4+
> [ManagedAgent guide](../../../../docs/guides/agents/managed_agent/index.md).
5+
6+
## Overview
7+
8+
This sample runs a `ManagedAgent` whose behavior is shaped by its `instruction`
9+
field. `instruction` is forwarded to the Managed Agents API as the interaction's
10+
system instruction (the same role `LlmAgent.instruction` plays for a local
11+
model). Here it pins a persona and output format, so its effect is visible in
12+
every reply.
13+
14+
`instruction` accepts either a plain string (which may embed `{state_var}`
15+
placeholders resolved from session state) or an `InstructionProvider` callable.
16+
This sample uses an **`InstructionProvider`**: `persona_instruction` takes a
17+
`ReadonlyContext`, reads the reply language from `state['response_language']`
18+
(defaulting to English), and returns the instruction string. Because a provider
19+
is invoked on every turn, the instruction is rebuilt each turn from the current
20+
state; unlike a string, it bypasses `{placeholder}` injection, so you build the
21+
final text yourself. A provider may also be `async` (return an awaitable `str`).
22+
23+
## Sample Inputs
24+
25+
- `What is the capital of France?`
26+
27+
The reply obeys the instruction: a single terse sentence ending with a
28+
relevant emoji, in the language from `state['response_language']` (English by
29+
default).
30+
31+
- `And Japan?`
32+
33+
A follow-up turn that reuses the recovered remote sandbox and previous
34+
interaction. The provider runs again on this turn, demonstrating that the
35+
system instruction is resolved and sent on chained turns too — and would pick
36+
up any change to `response_language` in session state.
37+
38+
## Graph
39+
40+
```mermaid
41+
graph LR
42+
User -->|message| ManagedAgent
43+
ManagedAgent -->|interactions.create + system_instruction| ManagedAgentsAPI
44+
ManagedAgentsAPI -->|streamed events| ManagedAgent
45+
ManagedAgent -->|reply shaped by the instruction| User
46+
```
47+
48+
## How To
49+
50+
- **Set the instruction**: pass `instruction=...` to `ManagedAgent`. A string is
51+
sent as-is (after `{placeholder}` resolution); an `InstructionProvider`
52+
callable is invoked per turn and bypasses placeholder injection.
53+
- **Use an `InstructionProvider`**: define a callable that takes a
54+
`ReadonlyContext` and returns a `str` (or an awaitable `str`), then pass it as
55+
`instruction`. Read `readonly_context.state` to build the instruction
56+
dynamically — here `state['response_language']` selects the reply language.
57+
- **Observe the effect**: every reply follows the persona/format the instruction
58+
specifies, on the first turn and on chained follow-up turns.
59+
- **Drive it**: a `ManagedAgent` is a `BaseAgent`, so a standard `Runner` runs it
60+
just like any other agent.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
from . import agent

0 commit comments

Comments
 (0)