Skip to content

Commit 3eb788c

Browse files
authored
Merge branch 'main' into use-starred-tuple-unpacking-on-gcs-artifact-blob-names-versions
2 parents 0157537 + f52df2b commit 3eb788c

File tree

25 files changed

+514
-183
lines changed

25 files changed

+514
-183
lines changed

contributing/samples/a2a_auth/agent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515

1616
from google.adk.agents import Agent
17+
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
1718
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
1819
from google.adk.tools.langchain_tool import LangchainTool
1920
from langchain_community.tools import YouTubeSearchTool
@@ -41,7 +42,7 @@
4142
name="bigquery_agent",
4243
description="Help customer to manage notion workspace.",
4344
agent_card=(
44-
"http://localhost:8001/a2a/bigquery_agent/.well-known/agent.json"
45+
f"http://localhost:8001/a2a/bigquery_agent{AGENT_CARD_WELL_KNOWN_PATH}"
4546
),
4647
)
4748

contributing/samples/a2a_basic/agent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import random
1616

1717
from google.adk.agents import Agent
18+
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
1819
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
1920
from google.adk.tools.example_tool import ExampleTool
2021
from google.genai import types
@@ -87,7 +88,7 @@ def roll_die(sides: int) -> int:
8788
name="prime_agent",
8889
description="Agent that handles checking if numbers are prime.",
8990
agent_card=(
90-
"http://localhost:8001/a2a/check_prime_agent/.well-known/agent.json"
91+
f"http://localhost:8001/a2a/check_prime_agent{AGENT_CARD_WELL_KNOWN_PATH}"
9192
),
9293
)
9394

contributing/samples/a2a_human_in_loop/agent.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515

1616
from google.adk import Agent
17+
from google.adk.agents.remote_a2a_agent import AGENT_CARD_WELL_KNOWN_PATH
1718
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
1819
from google.genai import types
1920

@@ -28,7 +29,9 @@ def reimburse(purpose: str, amount: float) -> str:
2829
approval_agent = RemoteA2aAgent(
2930
name='approval_agent',
3031
description='Help approve the reimburse if the amount is greater than 100.',
31-
agent_card='http://localhost:8001/a2a/human_in_loop/.well-known/agent.json',
32+
agent_card=(
33+
f'http://localhost:8001/a2a/human_in_loop{AGENT_CARD_WELL_KNOWN_PATH}'
34+
),
3235
)
3336

3437

contributing/samples/adk_answering_agent/agent.py

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from typing import Any
1616

17+
from adk_answering_agent.settings import BOT_RESPONSE_LABEL
1718
from adk_answering_agent.settings import IS_INTERACTIVE
1819
from adk_answering_agent.settings import OWNER
1920
from adk_answering_agent.settings import REPO
@@ -57,7 +58,14 @@ def get_discussion_and_comments(discussion_number: int) -> dict[str, Any]:
5758
author {
5859
login
5960
}
60-
# For each comment, fetch the latest 100 comments.
61+
# For each discussion, fetch the latest 20 labels.
62+
labels(last: 20) {
63+
nodes {
64+
id
65+
name
66+
}
67+
}
68+
# For each discussion, fetch the latest 100 comments.
6169
comments(last: 100) {
6270
nodes {
6371
id
@@ -66,7 +74,7 @@ def get_discussion_and_comments(discussion_number: int) -> dict[str, Any]:
6674
author {
6775
login
6876
}
69-
# For each comment, fetch the latest 50 replies
77+
# For each discussion, fetch the latest 50 replies
7078
replies(last: 50) {
7179
nodes {
7280
id
@@ -142,6 +150,76 @@ def add_comment_to_discussion(
142150
return error_response(str(e))
143151

144152

153+
def get_label_id(label_name: str) -> str | None:
154+
"""Helper function to find the GraphQL node ID for a given label name."""
155+
print(f"Finding ID for label '{label_name}'...")
156+
query = """
157+
query($owner: String!, $repo: String!, $labelName: String!) {
158+
repository(owner: $owner, name: $repo) {
159+
label(name: $labelName) {
160+
id
161+
}
162+
}
163+
}
164+
"""
165+
variables = {"owner": OWNER, "repo": REPO, "labelName": label_name}
166+
167+
try:
168+
response = run_graphql_query(query, variables)
169+
if "errors" in response:
170+
print(
171+
f"[Warning] Error from GitHub API response for label '{label_name}':"
172+
f" {response['errors']}"
173+
)
174+
return None
175+
label_info = response["data"].get("repository", {}).get("label")
176+
if label_info:
177+
return label_info.get("id")
178+
print(f"[Warning] Label information for '{label_name}' not found.")
179+
return None
180+
except requests.exceptions.RequestException as e:
181+
print(f"[Warning] Error from GitHub API: {e}")
182+
return None
183+
184+
185+
def add_label_to_discussion(
186+
discussion_id: str, label_name: str
187+
) -> dict[str, Any]:
188+
"""Adds a label to a specific discussion.
189+
190+
Args:
191+
discussion_id: The GraphQL node ID of the discussion.
192+
label_name: The name of the label to add (e.g., "bug").
193+
194+
Returns:
195+
The status of the request and the label details.
196+
"""
197+
print(
198+
f"Attempting to add label '{label_name}' to discussion {discussion_id}..."
199+
)
200+
# First, get the GraphQL ID of the label by its name
201+
label_id = get_label_id(label_name)
202+
if not label_id:
203+
return error_response(f"Label '{label_name}' not found.")
204+
205+
# Then, perform the mutation to add the label to the discussion
206+
mutation = """
207+
mutation AddLabel($discussionId: ID!, $labelId: ID!) {
208+
addLabelsToLabelable(input: {labelableId: $discussionId, labelIds: [$labelId]}) {
209+
clientMutationId
210+
}
211+
}
212+
"""
213+
variables = {"discussionId": discussion_id, "labelId": label_id}
214+
try:
215+
response = run_graphql_query(mutation, variables)
216+
if "errors" in response:
217+
return error_response(str(response["errors"]))
218+
return {"status": "success", "label_id": label_id, "label_name": label_name}
219+
except requests.exceptions.RequestException as e:
220+
return error_response(str(e))
221+
222+
145223
root_agent = Agent(
146224
model="gemini-2.5-pro",
147225
name="adk_answering_agent",
@@ -160,6 +238,10 @@ def add_comment_to_discussion(
160238
* The latest comment is not from you or other agents (marked as "Response from XXX Agent").
161239
* The latest comment is asking a question or requesting information.
162240
4. Use the `VertexAiSearchTool` to find relevant information before answering.
241+
5. If you can find relevant information, use the `add_comment_to_discussion` tool to add a comment to the discussion.
242+
6. If you post a commment and the discussion does not have a label named {BOT_RESPONSE_LABEL},
243+
add the label {BOT_RESPONSE_LABEL} to the discussion using the `add_label_to_discussion` tool.
244+
163245
164246
IMPORTANT:
165247
* {APPROVAL_INSTRUCTION}
@@ -188,5 +270,6 @@ def add_comment_to_discussion(
188270
VertexAiSearchTool(data_store_id=VERTEXAI_DATASTORE_ID),
189271
get_discussion_and_comments,
190272
add_comment_to_discussion,
273+
add_label_to_discussion,
191274
],
192275
)

contributing/samples/adk_answering_agent/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
OWNER = os.getenv("OWNER", "google")
3333
REPO = os.getenv("REPO", "adk-python")
34+
BOT_RESPONSE_LABEL = os.getenv("BOT_RESPONSE_LABEL", "bot_responded")
3435
DISCUSSION_NUMBER = os.getenv("DISCUSSION_NUMBER")
3536

3637
IS_INTERACTIVE = os.getenv("INTERACTIVE", "1").lower() in ["true", "1"]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ dev = [
8080

8181
a2a = [
8282
# go/keep-sorted start
83-
"a2a-sdk>=0.2.7;python_version>='3.10'"
83+
"a2a-sdk>=0.2.11;python_version>='3.10'"
8484
# go/keep-sorted end
8585
]
8686

src/google/adk/agents/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
from .base_agent import BaseAgent
16+
from .invocation_context import InvocationContext
1617
from .live_request_queue import LiveRequest
1718
from .live_request_queue import LiveRequestQueue
1819
from .llm_agent import Agent
@@ -29,4 +30,8 @@
2930
'LoopAgent',
3031
'ParallelAgent',
3132
'SequentialAgent',
33+
'InvocationContext',
34+
'LiveRequest',
35+
'LiveRequestQueue',
36+
'RunConfig',
3237
]

src/google/adk/agents/invocation_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ class InvocationContext(BaseModel):
149149
"""The running streaming tools of this invocation."""
150150

151151
transcription_cache: Optional[list[TranscriptionEntry]] = None
152-
"""Caches necessary, data audio or contents, that are needed by transcription."""
152+
"""Caches necessary data, audio or contents, that are needed by transcription."""
153153

154154
run_config: Optional[RunConfig] = None
155155
"""Configurations for live agents under this invocation."""

src/google/adk/agents/llm_agent.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ class LlmAgent(BaseAgent):
168168
"""Controls content inclusion in model requests.
169169
170170
Options:
171-
default: Model receives relevant conversation history
172-
none: Model receives no prior history, operates solely on current
173-
instruction and input
171+
default: Model receives relevant conversation history
172+
none: Model receives no prior history, operates solely on current
173+
instruction and input
174174
"""
175175

176176
# Controlled input/output configurations - Start
@@ -179,8 +179,9 @@ class LlmAgent(BaseAgent):
179179
output_schema: Optional[type[BaseModel]] = None
180180
"""The output schema when agent replies.
181181
182-
NOTE: when this is set, agent can ONLY reply and CANNOT use any tools, such as
183-
function tools, RAGs, agent transfer, etc.
182+
NOTE:
183+
When this is set, agent can ONLY reply and CANNOT use any tools, such as
184+
function tools, RAGs, agent transfer, etc.
184185
"""
185186
output_key: Optional[str] = None
186187
"""The key in session state to store the output of the agent.
@@ -195,9 +196,9 @@ class LlmAgent(BaseAgent):
195196
planner: Optional[BasePlanner] = None
196197
"""Instructs the agent to make a plan and execute it step by step.
197198
198-
NOTE: to use model's built-in thinking features, set the `thinking_config`
199-
field in `google.adk.planners.built_in_planner`.
200-
199+
NOTE:
200+
To use model's built-in thinking features, set the `thinking_config`
201+
field in `google.adk.planners.built_in_planner`.
201202
"""
202203

203204
code_executor: Optional[BaseCodeExecutor] = None
@@ -206,7 +207,8 @@ class LlmAgent(BaseAgent):
206207
207208
Check out available code executions in `google.adk.code_executor` package.
208209
209-
NOTE: to use model's built-in code executor, use the `BuiltInCodeExecutor`.
210+
NOTE:
211+
To use model's built-in code executor, use the `BuiltInCodeExecutor`.
210212
"""
211213
# Advance features - End
212214

src/google/adk/agents/remote_a2a_agent.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
try:
2828
from a2a.client import A2AClient
29-
from a2a.client.client import A2ACardResolver # Import A2ACardResolver
29+
from a2a.client.client import A2ACardResolver
3030
from a2a.types import AgentCard
3131
from a2a.types import Message as A2AMessage
3232
from a2a.types import MessageSendParams as A2AMessageSendParams
@@ -35,7 +35,6 @@
3535
from a2a.types import SendMessageRequest
3636
from a2a.types import SendMessageSuccessResponse
3737
from a2a.types import Task as A2ATask
38-
3938
except ImportError as e:
4039
import sys
4140

@@ -46,6 +45,12 @@
4645
else:
4746
raise e
4847

48+
try:
49+
from a2a.utils.constants import AGENT_CARD_WELL_KNOWN_PATH
50+
except ImportError:
51+
# Fallback for older versions of a2a-sdk.
52+
AGENT_CARD_WELL_KNOWN_PATH = "/.well-known/agent.json"
53+
4954
from google.genai import types as genai_types
5055
import httpx
5156

@@ -63,11 +68,18 @@
6368
from ..utils.feature_decorator import experimental
6469
from .base_agent import BaseAgent
6570

71+
__all__ = [
72+
"A2AClientError",
73+
"AGENT_CARD_WELL_KNOWN_PATH",
74+
"AgentCardResolutionError",
75+
"RemoteA2aAgent",
76+
]
77+
78+
6679
# Constants
6780
A2A_METADATA_PREFIX = "a2a:"
6881
DEFAULT_TIMEOUT = 600.0
6982

70-
7183
logger = logging.getLogger("google_adk." + __name__)
7284

7385

0 commit comments

Comments
 (0)