chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.10) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.11) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.12) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.10) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.11) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.12) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.14) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Waiting to run
Copybara PR Handler / close-imported-pr (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 13:25:13 +08:00
commit ec2b666284
2231 changed files with 491535 additions and 0 deletions
@@ -0,0 +1,36 @@
# Node as Tool
## Overview
Demonstrates wrapping both a regular ADK `Node` (using the `@node` decorator) and a `Workflow` as tools that can be automatically called by a parent `Agent`.
In this sample:
1. The parent agent receives an inquiry about a customer's discount.
1. It invokes `customer_lookup_workflow` (a `Workflow` wrapped as a tool) to retrieve customer status.
1. It then invokes `calculate_discount` (a regular `Node` wrapped as a tool) using the retrieved status.
## Sample Inputs
- `What discount does customer c123 get?`
*The parent agent first invokes `customer_lookup_workflow` to verify status, then invokes `calculate_discount` to determine the discount percentage, and summarizes the results.*
## Agent Topology Graph
```mermaid
graph TD
customer_service_agent[customer_service_agent] -->|calls| customer_lookup_workflow(customer_lookup_workflow)
customer_service_agent -->|calls| calculate_discount(calculate_discount)
```
## How To
To expose an existing `Node` or `Workflow` as a tool callable by an `Agent`:
1. Define your `Node` (or `@node`) or `Workflow` and assign both an `input_schema` and a `description`.
1. Pass the node/workflow directly into your parent agent's `tools` list: `Agent(..., tools=[my_node, my_workflow])`.
## Related Guides
- [Workflows](../../../../docs/guides/workflows/workflows.md) - Explains building complex multi-step graphs.
@@ -0,0 +1,73 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from typing import Generator
from google.adk import Agent
from google.adk import Event
from google.adk import Workflow
from google.adk.workflow import node
from pydantic import BaseModel
from pydantic import Field
# 1. Define schemas
class CustomerLookupArgs(BaseModel):
user_id: str = Field(description="The customer's unique identifier.")
# 2. Define a regular Node using the @node decorator.
# This Node is wrapped as a NodeTool automatically by the Agent.
# As a NodeTool, it has the ability to yield intermediate Events during execution.
@node
def calculate_discount(tier: str, ctx) -> Generator[Event | str, None, None]:
"""Calculates the discount percentage based on customer tier.
Args:
tier: The customer's membership tier (e.g., VIP, Standard).
"""
yield Event(message=f"Checking discount rules for tier '{tier}'...")
discount = "20% off" if "VIP" in tier else "5% off"
yield discount
# 3. Define a Workflow.
# This Workflow is wrapped as a NodeTool automatically by the Agent.
def lookup_customer_data(node_input: CustomerLookupArgs, ctx) -> dict[str, str]:
return {"user_id": node_input.user_id, "tier": "Verified VIP Member"}
customer_lookup_workflow = Workflow(
name="customer_lookup_workflow",
description="Looks up customer status and tier by user_id.",
input_schema=CustomerLookupArgs,
edges=[
("START", lookup_customer_data),
],
)
# 4. Define the Agent that uses both Node and Workflow as tools.
root_agent = Agent(
name="customer_service_agent",
instruction="""
You are a customer service assistant.
1. First, call `customer_lookup_workflow` using the user_id to get their membership tier.
2. Then, call `calculate_discount` node with that tier to find out what discount they get.
Summarize these details for the customer.
""",
tools=[customer_lookup_workflow, calculate_discount],
)
@@ -0,0 +1,182 @@
{
"appName": "node_as_tool",
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "What discount does customer c123 get?"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "customer_service_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"user_id": "c123"
},
"id": "fc-1",
"name": "customer_lookup_workflow"
}
}
],
"role": "model"
},
"id": "e-2",
"invocationId": "i-1",
"longRunningToolIds": [
"fc-1"
],
"nodeInfo": {
"path": "customer_service_agent@1"
}
},
{
"author": "customer_lookup_workflow",
"branch": "customer_lookup_workflow@fc-1",
"id": "e-3",
"invocationId": "i-1",
"nodeInfo": {
"outputFor": [
"customer_lookup_workflow@1/lookup_customer_data@1",
"customer_lookup_workflow@1"
],
"path": "customer_lookup_workflow@1/lookup_customer_data@1"
},
"output": {
"tier": "Verified VIP Member",
"user_id": "c123"
}
},
{
"author": "customer_service_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "customer_lookup_workflow",
"response": {
"tier": "Verified VIP Member",
"user_id": "c123"
}
}
}
],
"role": "user"
},
"id": "e-4",
"invocationId": "i-1",
"nodeInfo": {
"path": "customer_service_agent@1"
}
},
{
"author": "customer_service_agent",
"content": {
"parts": [
{
"functionCall": {
"args": {
"tier": "Verified VIP Member"
},
"id": "fc-2",
"name": "calculate_discount"
}
}
],
"role": "model"
},
"id": "e-5",
"invocationId": "i-1",
"longRunningToolIds": [
"fc-2"
],
"nodeInfo": {
"path": "customer_service_agent@1"
}
},
{
"author": "calculate_discount",
"branch": "calculate_discount@fc-2",
"content": {
"parts": [
{
"text": "Checking discount rules for tier 'Verified VIP Member'..."
}
],
"role": "user"
},
"id": "e-6",
"invocationId": "i-1",
"nodeInfo": {
"path": "calculate_discount@1"
}
},
{
"author": "calculate_discount",
"branch": "calculate_discount@fc-2",
"id": "e-7",
"invocationId": "i-1",
"nodeInfo": {
"outputFor": [
"calculate_discount@1"
],
"path": "calculate_discount@1"
},
"output": "20% off"
},
{
"author": "customer_service_agent",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-2",
"name": "calculate_discount",
"response": {
"result": "20% off"
}
}
}
],
"role": "user"
},
"id": "e-8",
"invocationId": "i-1",
"nodeInfo": {
"path": "customer_service_agent@1"
}
},
{
"author": "customer_service_agent",
"content": {
"parts": [
{
"text": "Customer c123 is a Verified VIP Member and gets a 20% discount."
}
],
"role": "model"
},
"id": "e-9",
"invocationId": "i-1",
"nodeInfo": {
"path": "customer_service_agent@1"
}
}
],
"id": "12345678-1234-1234-1234-123456789abc",
"userId": "user"
}