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

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,76 @@
# ADK Workflow Request Input Advanced Sample
## Overview
This sample demonstrates advanced features for requesting Human-in-the-Loop (HITL) input dynamically during an **ADK Workflow** execution.
Specifically, it highlights how to pass structured data to the client UI using the `payload` parameter, and how to mandate a structured response type using the `response_schema` parameter on the yielded `RequestInput` event.
In this scenario, an employee requests time off by providing a natural language description of their request (e.g., "I need next Monday off to go to the dentist").
- An LLM agent (`process_request`) parses the natural language into a structured Pydantic model containing the number of `days` and a `reason`.
- A python node (`evaluate_request`) evaluates the parsed request:
- If `days <= 1`, it yields a `TimeOffDecision` approving the request.
- If `days > 1`, it yields a `RequestInput` to a manager. It attaches the request details to the `payload` so the client UI can render it. It enforces that the manager must respond with a JSON object containing an `approved` boolean and an optional `approved_days` integer by specifying `response_schema` with a valid Pydantic JSON schema.
## Sample Inputs
Start the workflow by providing the initial time off request in natural language:
- `I'm feeling under the weather and need to take today off.`
*Parses as 1 day, auto-approves.*
- `Taking my family to Disney World, I'll be out for 5 days next week.`
*Parses as 5 days, routes to manager review.*
When the terminal prompts you as the manager, provide valid JSON matching the schema:
- `{"approved": true, "approved_days": 5}`
- `{"approved": false, "approved_days": 0}`
## Graph
```mermaid
graph TD
START --> process_request[process_request <br/>LLM Agent]
process_request --> evaluate_request
evaluate_request -->|Yields TimeOffDecision OR RequestInput| process_decision
process_decision --> END[END]
```
## How To
1. **Define the Response Schema:** Use a Pydantic model's `model_json_schema()` to get a standard layout of what the human should return.
```python
from typing import Optional
from pydantic import BaseModel, Field
class TimeOffDecision(BaseModel):
approved: bool = Field(...)
approved_days: Optional[int] = Field(None)
```
1. **Yield a RequestInput:** Pass the schema and optionally a `payload` for the client to display.
```python
def evaluate_request(request: TimeOffRequest):
# ... logic to check if manager review is needed ...
yield RequestInput(
interrupt_id="manager_approval",
message="Please review this time off request.",
payload=request,
response_schema=TimeOffDecision.model_json_schema()
)
```
1. **Parse the Resumed Input:** When the workflow resumes, the `node_input` to the next node will be the parsed Pydantic model implicitly (if type-hinted).
```python
def process_decision(request: TimeOffRequest, node_input: TimeOffDecision):
if node_input.approved:
# ...
```
@@ -0,0 +1,87 @@
# 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 typing import Optional
from google.adk import Agent
from google.adk import Event
from google.adk import Workflow
from google.adk.events import RequestInput
from pydantic import BaseModel
from pydantic import Field
class TimeOffRequest(BaseModel):
days: int = Field(description="Number of days requested.")
reason: str = Field(description="Reason for the time off.")
class TimeOffDecision(BaseModel):
"""The structured response we expect back from the human manager."""
approved: bool = Field(description="Whether the time off is approved.")
approved_days: Optional[int] = Field(
default=None, description="Number of days approved."
)
process_request = Agent(
name="process_request",
instruction=(
"Extract the number of days and the reason from the user's natural"
" language time off request."
),
output_schema=TimeOffRequest,
output_key="request",
)
def evaluate_request(request: TimeOffRequest):
"""
If days <= 1, it's auto-approved. Otherwise, routes to manager review.
"""
if request.days <= 1:
return TimeOffDecision(approved=True)
else:
return RequestInput(
interrupt_id="manager_approval",
message="Please review this time off request.",
payload=request,
response_schema=TimeOffDecision,
)
def process_decision(request: TimeOffRequest, node_input: TimeOffDecision):
if node_input.approved:
approved_days = (
node_input.approved_days
if node_input.approved_days is not None
else request.days
)
message = (
f"Time Off Approved! {approved_days} out of {request.days} days"
" granted."
)
else:
message = "Time Off Denied."
yield Event(message=message)
root_agent = Workflow(
name="request_input_advanced",
edges=[
("START", process_request, evaluate_request, process_decision),
],
)
@@ -0,0 +1,157 @@
{
"appName": "request_input_advanced",
"events": [
{
"author": "user",
"content": {
"parts": [
{
"text": "2 sick days"
}
],
"role": "user"
},
"id": "e-1",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"actions": {
"stateDelta": {
"request": {
"days": 2,
"reason": "sick"
}
}
},
"author": "process_request",
"content": {
"parts": [
{
"text": "{\"days\":2,\"reason\":\"sick\"}"
}
],
"role": "model"
},
"finishReason": "STOP",
"id": "e-2",
"invocationId": "i-1",
"nodeInfo": {
"messageAsOutput": true,
"outputFor": [
"request_input_advanced@1/process_request@1"
],
"path": "request_input_advanced@1/process_request@1"
}
},
{
"author": "request_input_advanced",
"content": {
"parts": [
{
"functionCall": {
"args": {
"interruptId": "fc-1",
"message": "Please review this time off request.",
"payload": {
"days": 2,
"reason": "sick"
},
"response_schema": {
"description": "The structured response we expect back from the human manager.",
"properties": {
"approved": {
"description": "Whether the time off is approved.",
"title": "Approved",
"type": "boolean"
},
"approved_days": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Number of days approved.",
"title": "Approved Days"
}
},
"required": [
"approved"
],
"title": "TimeOffDecision",
"type": "object"
}
},
"id": "fc-1",
"name": "adk_request_input"
}
}
],
"role": "model"
},
"id": "e-3",
"invocationId": "i-1",
"longRunningToolIds": [
"fc-1"
],
"nodeInfo": {
"path": "request_input_advanced@1/evaluate_request@1"
}
},
{
"author": "user",
"content": {
"parts": [
{
"functionResponse": {
"id": "fc-1",
"name": "adk_request_input",
"response": {
"result": "{\"approved\": true}"
}
}
}
],
"role": "user"
},
"id": "e-4",
"invocationId": "i-1",
"nodeInfo": {
"path": ""
}
},
{
"author": "request_input_advanced",
"content": {
"parts": [
{
"text": "Time Off Approved! 2 out of 2 days granted."
}
],
"role": "user"
},
"id": "e-5",
"invocationId": "i-1",
"nodeInfo": {
"path": "request_input_advanced@1/process_decision@1"
}
}
],
"id": "131bfe8b-de90-47bd-b442-957f27dc58a6",
"state": {
"__session_metadata__": {
"displayName": "2 sick days"
},
"request": {
"days": 2,
"reason": "sick days"
}
},
"userId": "user"
}