Skip to content

Commit 944ce77

Browse files
authored
Merge branch 'main' into feature/ollama-llm
2 parents a4494c0 + b0715d7 commit 944ce77

142 files changed

Lines changed: 10712 additions & 824 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/triage.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ jobs:
1717
if: >-
1818
github.repository == 'google/adk-python' && (
1919
github.event_name == 'schedule' ||
20-
github.event.action == 'opened' ||
21-
github.event.label.name == 'planned'
20+
github.event.action == 'opened'
2221
)
2322
permissions:
2423
issues: write

contributing/samples/adk_triaging_agent/agent.py

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@
4242
"workflow": "DeanChensj",
4343
}
4444

45+
46+
LABEL_TO_GTECH = [
47+
"klateefa",
48+
"llalitkumarrr",
49+
"surajksharma07",
50+
"sanketpatil06",
51+
]
52+
4553
LABEL_GUIDELINES = """
4654
Label rubric and disambiguation rules:
4755
- "documentation": Tutorials, README content, reference docs, or samples.
@@ -121,15 +129,13 @@ def list_untriaged_issues(issue_count: int) -> dict[str, Any]:
121129

122130
existing_component_labels = issue_labels & component_labels
123131
has_component = bool(existing_component_labels)
124-
has_planned = "planned" in issue_labels
125132

126133
# Determine what actions are needed
127134
needs_component_label = not has_component
128-
needs_owner = has_planned and not assignees
135+
needs_owner = not assignees
129136

130137
# Include issue if it needs any action
131138
if needs_component_label or needs_owner:
132-
issue["has_planned_label"] = has_planned
133139
issue["has_component_label"] = has_component
134140
issue["existing_component_label"] = (
135141
list(existing_component_labels)[0]
@@ -146,7 +152,6 @@ def list_untriaged_issues(issue_count: int) -> dict[str, Any]:
146152

147153
def add_label_to_issue(issue_number: int, label: str) -> dict[str, Any]:
148154
"""Add the specified component label to the given issue number.
149-
150155
Args:
151156
issue_number: issue number of the GitHub issue.
152157
label: label to assign
@@ -177,37 +182,30 @@ def add_label_to_issue(issue_number: int, label: str) -> dict[str, Any]:
177182
}
178183

179184

180-
def add_owner_to_issue(issue_number: int, label: str) -> dict[str, Any]:
181-
"""Assign an owner to the issue based on the component label.
185+
def assign_gtech_owner_to_issue(issue_number: int) -> dict[str, Any]:
186+
"""Assign an owner from the GTech team to the given issue number.
182187
183-
This should only be called for issues that have the 'planned' label.
188+
This is go to option irrespective of component label or planned label,
189+
as long as the issue needs an owner.
190+
191+
All unassigned issues will be considered for GTech ownership. Unassigned
192+
issues will seperated in two categories: issues with type "Bug" and issues
193+
with type "Feature". Then bug issues and feature issues will be equally
194+
assigned to the Gtech members in such a way that every day all members get
195+
equal number of bug and feature issues.
184196
185197
Args:
186198
issue_number: issue number of the GitHub issue.
187-
label: component label that determines the owner to assign
188199
189200
Returns:
190201
The status of this request, with the assigned owner when successful.
191202
"""
192-
print(
193-
f"Attempting to assign owner for label '{label}' to issue #{issue_number}"
194-
)
195-
if label not in LABEL_TO_OWNER:
196-
return error_response(
197-
f"Error: Label '{label}' is not a valid component label."
198-
)
199-
200-
owner = LABEL_TO_OWNER.get(label, None)
201-
if not owner:
202-
return {
203-
"status": "warning",
204-
"message": f"Label '{label}' does not have an owner. Will not assign.",
205-
}
206-
203+
print(f"Attempting to assign GTech owner to issue #{issue_number}")
204+
gtech_assignee = LABEL_TO_GTECH[issue_number % len(LABEL_TO_GTECH)]
207205
assignee_url = (
208206
f"{GITHUB_BASE_URL}/repos/{OWNER}/{REPO}/issues/{issue_number}/assignees"
209207
)
210-
assignee_payload = {"assignees": [owner]}
208+
assignee_payload = {"assignees": [gtech_assignee]}
211209

212210
try:
213211
response = post_request(assignee_url, assignee_payload)
@@ -217,7 +215,7 @@ def add_owner_to_issue(issue_number: int, label: str) -> dict[str, Any]:
217215
return {
218216
"status": "success",
219217
"message": response,
220-
"assigned_owner": owner,
218+
"assigned_owner": gtech_assignee,
221219
}
222220

223221

@@ -259,7 +257,7 @@ def change_issue_type(issue_number: int, issue_type: str) -> dict[str, Any]:
259257
260258
Each issue will have flags indicating what actions are needed:
261259
- `needs_component_label`: true if the issue needs a component label
262-
- `needs_owner`: true if the issue needs an owner assigned (has 'planned' label but no assignee)
260+
- `needs_owner`: true if the issue needs an owner assigned
263261
264262
For each issue, perform ONLY the required actions based on the flags:
265263
@@ -271,8 +269,8 @@ def change_issue_type(issue_number: int, issue_type: str) -> dict[str, Any]:
271269
- Otherwise → do not change the issue type
272270
273271
2. **If `needs_owner` is true**:
274-
- Use `add_owner_to_issue` to assign an owner based on the component label
275-
- Note: If the issue already has a component label (`has_component_label: true`), use that existing label to determine the owner
272+
- Use `assign_gtech_owner_to_issue` to assign an owner.
273+
276274
277275
Do NOT add a component label if `needs_component_label` is false.
278276
Do NOT assign an owner if `needs_owner` is false.
@@ -282,19 +280,18 @@ def change_issue_type(issue_number: int, issue_type: str) -> dict[str, Any]:
282280
placeholders (never output text like "[fill in later]").
283281
- Justify the chosen label with a short explanation referencing the issue
284282
details.
285-
- Mention the assigned owner only when you actually assign one (i.e., when
286-
the issue has the 'planned' label).
283+
- Mention the assigned owner only when you actually assign one.
287284
- If no label is applied, clearly state why.
288285
289286
Present the following in an easy to read format highlighting issue number and your label.
290287
- the issue summary in a few sentence
291288
- your label recommendation and justification
292-
- the owner of the label if you assign the issue to an owner (only for planned issues)
289+
- the owner, if you assign the issue to an owner
293290
""",
294291
tools=[
295292
list_untriaged_issues,
296293
add_label_to_issue,
297-
add_owner_to_issue,
294+
assign_gtech_owner_to_issue,
298295
change_issue_type,
299296
],
300297
)

contributing/samples/adk_triaging_agent/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ async def fetch_specific_issue_details(issue_number: int):
5757

5858
# Determine what actions are needed
5959
needs_component_label = not has_component
60-
needs_owner = has_planned and not has_assignee
60+
needs_owner = not has_assignee
6161

6262
if needs_component_label or needs_owner:
6363
print(

contributing/samples/agent_registry_agent/agent.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from google.adk.agents.llm_agent import LlmAgent
2020
from google.adk.integrations.agent_registry import AgentRegistry
21+
from google.adk.models.google_llm import Gemini
2122

2223
# Project and location can be set via environment variables:
2324
# GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION
@@ -27,6 +28,8 @@
2728
# Initialize Agent Registry client
2829
registry = AgentRegistry(project_id=project_id, location=location)
2930

31+
# List agents, MCP servers, and endpoints resource names from the registry.
32+
# They can be used to initialize the agent, toolset, and model below.
3033
print(f"Listing agents in {project_id}/{location}...")
3134
agents = registry.list_agents()
3235
for agent in agents.get("agents", []):
@@ -37,6 +40,11 @@
3740
for server in mcp_servers.get("mcpServers", []):
3841
print(f"- MCP Server: {server.get('displayName')} ({server.get('name')})")
3942

43+
print(f"\nListing endpoints in {project_id}/{location}...")
44+
endpoints = registry.list_endpoints()
45+
for endpoint in endpoints.get("endpoints", []):
46+
print(f"- Endpoint: {endpoint.get('displayName')} ({endpoint.get('name')})")
47+
4048
# Example of using a specific agent or MCP server from the registry:
4149
# (Note: These names should be full resource names as returned by list methods)
4250

@@ -52,8 +60,19 @@
5260
f"projects/{project_id}/locations/{location}/mcpServers/MCP_SERVER_NAME"
5361
)
5462

63+
# 3. Getting a specific model endpoint configuration
64+
# This returns a string like:
65+
# "projects/adk12345/locations/us-central1/publishers/google/models/gemini-2.5-flash"
66+
# TODO: Replace ENDPOINT_NAME with your endpoint name
67+
model_name = registry.get_model_name(
68+
f"projects/{project_id}/locations/{location}/endpoints/ENDPOINT_NAME"
69+
)
70+
71+
# Initialize the model using the resolved model name from registry.
72+
gemini_model = Gemini(model=model_name)
73+
5574
root_agent = LlmAgent(
56-
model="gemini-2.5-flash",
75+
model=gemini_model,
5776
name="discovery_agent",
5877
instruction=(
5978
"You have access to tools and sub-agents discovered via Registry."
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
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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 random
17+
18+
from dotenv import load_dotenv
19+
from google.adk import Agent
20+
from google.adk.tools.agent_tool import AgentTool
21+
from google.adk.tools.tool_context import ToolContext
22+
from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool
23+
24+
load_dotenv(override=True)
25+
26+
VERTEXAI_DATASTORE_ID = os.getenv("VERTEXAI_DATASTORE_ID")
27+
if not VERTEXAI_DATASTORE_ID:
28+
raise ValueError("VERTEXAI_DATASTORE_ID environment variable not set")
29+
30+
31+
def roll_die(sides: int, tool_context: ToolContext) -> int:
32+
"""Roll a die and return the rolled result.
33+
34+
Args:
35+
sides: The integer number of sides the die has.
36+
37+
Returns:
38+
An integer of the result of rolling the die.
39+
"""
40+
result = random.randint(1, sides)
41+
if "rolls" not in tool_context.state:
42+
tool_context.state["rolls"] = []
43+
44+
tool_context.state["rolls"] = tool_context.state["rolls"] + [result]
45+
return result
46+
47+
48+
vertex_ai_search_agent = Agent(
49+
model="gemini-3-flash-preview",
50+
name="vertex_ai_search_agent",
51+
description="An agent for performing Vertex AI search.",
52+
tools=[
53+
VertexAiSearchTool(
54+
data_store_id=VERTEXAI_DATASTORE_ID,
55+
)
56+
],
57+
)
58+
59+
root_agent = Agent(
60+
model="gemini-3.1-pro-preview",
61+
name="hello_world_agent",
62+
description="A hello world agent with multiple tools.",
63+
instruction="""
64+
You are a helpful assistant which can help user to roll dice and search for information.
65+
- Use `roll_die` tool to roll dice.
66+
- Use `vertex_ai_search_agent` to search for Google Agent Development Kit (ADK) information in the datastore.
67+
""",
68+
tools=[
69+
roll_die,
70+
AgentTool(
71+
agent=vertex_ai_search_agent, propagate_grounding_metadata=True
72+
),
73+
],
74+
)

contributing/samples/bigquery/agent.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from google.adk.tools.bigquery.config import BigQueryToolConfig
2222
from google.adk.tools.bigquery.config import WriteMode
2323
import google.auth
24+
import google.auth.transport.requests
2425

2526
# Define the desired credential type.
2627
# By default use Application Default Credentials (ADC) from the local
@@ -57,6 +58,8 @@
5758
# service account key file
5859
# https://cloud.google.com/iam/docs/service-account-creds#user-managed-keys
5960
creds, _ = google.auth.load_credentials_from_file("service_account_key.json")
61+
if not creds.valid:
62+
creds.refresh(google.auth.transport.requests.Request())
6063
credentials_config = BigQueryCredentialsConfig(credentials=creds)
6164
elif CREDENTIALS_TYPE == AuthCredentialTypes.HTTP:
6265
# Initialize the tools to use the externally provided access token. One such
@@ -73,6 +76,10 @@
7376
# Initialize the tools to use the application default credentials.
7477
# https://cloud.google.com/docs/authentication/provide-credentials-adc
7578
application_default_credentials, _ = google.auth.default()
79+
if not application_default_credentials.valid:
80+
application_default_credentials.refresh(
81+
google.auth.transport.requests.Request()
82+
)
7683
credentials_config = BigQueryCredentialsConfig(
7784
credentials=application_default_credentials
7885
)

contributing/samples/data_agent/agent.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
# Initialize the tools to use the application default credentials.
5252
# https://cloud.google.com/docs/authentication/provide-credentials-adc
5353
application_default_credentials, _ = google.auth.default()
54+
if not application_default_credentials.valid:
55+
application_default_credentials.refresh(
56+
google.auth.transport.requests.Request()
57+
)
5458
credentials_config = DataAgentCredentialsConfig(
5559
credentials=application_default_credentials
5660
)

contributing/samples/hello_world/main.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,15 @@ async def run_prompt(session: Session, new_message: str):
4848
session_id=session.id,
4949
new_message=content,
5050
):
51-
if event.content.parts and event.content.parts[0].text:
52-
print(f'** {event.author}: {event.content.parts[0].text}')
51+
if event.content.parts:
52+
for part in event.content.parts:
53+
if part.text:
54+
print(f'** {event.author}: {part.text}')
55+
if part.function_call:
56+
print(
57+
f'** {event.author} calls tool: {part.function_call.name} with'
58+
f' args {part.function_call.args}'
59+
)
5360

5461
async def run_prompt_bytes(session: Session, new_message: str):
5562
content = types.Content(
@@ -74,6 +81,7 @@ async def check_rolls_in_state(rolls_size: int):
7481
session = await runner.session_service.get_session(
7582
app_name=app_name, user_id=user_id_1, session_id=session_11.id
7683
)
84+
print('** session.state:', session.state)
7785
assert len(session.state['rolls']) == rolls_size
7886
for roll in session.state['rolls']:
7987
assert roll > 0 and roll <= 100
@@ -82,9 +90,9 @@ async def check_rolls_in_state(rolls_size: int):
8290
print('Start time:', start_time)
8391
print('------------------------------------')
8492
await run_prompt(session_11, 'Hi')
85-
await run_prompt(session_11, 'Roll a die with 100 sides')
93+
await run_prompt(session_11, 'Roll a dice with 100 sides')
8694
await check_rolls_in_state(1)
87-
await run_prompt(session_11, 'Roll a die again with 100 sides.')
95+
await run_prompt(session_11, 'Roll a dice again with 100 sides.')
8896
await check_rolls_in_state(2)
8997
await run_prompt(session_11, 'What numbers did I got?')
9098
await run_prompt_bytes(session_11, 'Hi bytes')

0 commit comments

Comments
 (0)