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
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:
@@ -0,0 +1,112 @@
|
||||
# Event and NodeInfo
|
||||
|
||||
The `event.py` file defines the `Event` and `NodeInfo` classes, which are the fundamental data structures used in the Agent Development Kit (ADK) to represent interactions, actions, and metadata within a workflow.
|
||||
|
||||
## Introduction
|
||||
|
||||
In ADK, conversations and workflow executions are modeled as a sequence of events. The `Event` class represents a single unit of this sequence, capturing:
|
||||
- **Content:** Messages exchanged between users and agents (text, function calls, function responses).
|
||||
- **Actions:** Side-effects or instructions, such as state updates, routing decisions, agent transfers, and UI rendering requests.
|
||||
- **Metadata:** Information about who generated the event, when, and from which part of the workflow.
|
||||
|
||||
`NodeInfo` specifically carries metadata about the workflow node that generated the event, enabling tracking of execution paths and run IDs.
|
||||
|
||||
Key classes depending on `Event` include `Session` (which stores the event history) and `Workflow` / `NodeRunner` (which use events for execution flow and state management).
|
||||
|
||||
## Get started
|
||||
|
||||
Here is how to create and use `Event` objects.
|
||||
|
||||
### Basic Message Event
|
||||
|
||||
You can create a simple event with a text message:
|
||||
|
||||
```python
|
||||
from google.adk.events.event import Event
|
||||
|
||||
# Create a user message event
|
||||
user_event = Event(author="user", message="Hello, agent!")
|
||||
|
||||
# The 'message' argument is a convenience alias for 'content'
|
||||
print(user_event.message.parts[0].text) # Output: Hello, agent!
|
||||
```
|
||||
|
||||
### Event with State Delta
|
||||
|
||||
Events can carry state updates that should be applied to the session state:
|
||||
|
||||
```python
|
||||
from google.adk.events.event import Event
|
||||
|
||||
# Create an agent event that updates the state
|
||||
state_event = Event(
|
||||
author="my_agent",
|
||||
message="I've updated the user preference.",
|
||||
state={"user_theme": "dark"}
|
||||
)
|
||||
|
||||
print(state_event.actions.state_delta) # Output: {'user_theme': 'dark'}
|
||||
```
|
||||
|
||||
### Event with Node Metadata
|
||||
|
||||
When events are generated within a workflow, they usually include node information.
|
||||
|
||||
> [!NOTE]
|
||||
> `NodeInfo` is automatically populated by the ADK framework. While you can access these fields, you should not manually construct or modify `node_info` in your application logic.
|
||||
|
||||
```python
|
||||
from google.adk.events.event import Event, NodeInfo
|
||||
|
||||
node_event = Event(
|
||||
author="agent_node",
|
||||
node_path="parent_workflow/child_node@run-123",
|
||||
output="some_result"
|
||||
)
|
||||
|
||||
print(node_event.node_info.path) # Output: parent_workflow/child_node@run-123
|
||||
print(node_event.node_info.name) # Output: child_node
|
||||
print(node_event.node_info.run_id) # Output: run-123
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
`Event` inherits from `LlmResponse`, which allows it to directly wrap responses from Gemini models, including content, grounding metadata, and token usage.
|
||||
|
||||
### Convenience Kwargs Routing
|
||||
|
||||
The `Event` constructor accepts several convenience arguments that are automatically routed to nested Pydantic models:
|
||||
- `message`: Automatically converted to `types.Content` and set to the `content` field.
|
||||
- `state`: Mapped to `actions.state_delta`.
|
||||
- `route`: Mapped to `actions.route`.
|
||||
- `node_path`: Mapped to `node_info.path`.
|
||||
|
||||
This routing is handled by the `@model_validator(mode='before')` method `_accept_convenience_kwargs`.
|
||||
|
||||
### Serialization
|
||||
|
||||
Both `Event` and `NodeInfo` are Pydantic models configured to use camelCase aliases for serialization. When sending events over the wire or saving them, use `model_dump(by_alias=True)` to ensure compatibility with ADK APIs.
|
||||
|
||||
### Lifecycle
|
||||
|
||||
Every event is assigned a unique UUID `id` and a `timestamp` upon initialization if they are not explicitly provided.
|
||||
|
||||
## Advanced applications
|
||||
|
||||
### Workflow Routing
|
||||
|
||||
Workflows use `Event` to communicate routing decisions. By setting `route` (which maps to `actions.route`), a node can signal to the workflow engine which edge to follow next.
|
||||
|
||||
```python
|
||||
routing_event = Event(author="router_node", route="success_path")
|
||||
```
|
||||
|
||||
### Context Isolation
|
||||
|
||||
The `isolation_scope` field is used by the Task API to isolate conversations of delegated agents. Events with a specific `isolation_scope` (e.g., `"task:fc-987"`) will only be visible to agents running within that same scope, preventing them from seeing the main conversation history.
|
||||
|
||||
## Limitations
|
||||
|
||||
- **NodeInfo Assignment:** The `node_info` field (and the `node_path` constructor argument) is managed and assigned by the ADK framework during workflow execution. Developers should not manually set or modify `node_info` in production code.
|
||||
- **Internal Fields:** The `isolation_scope` field is an internal implementation detail. External developers should not rely on it or modify it directly.
|
||||
- **Mutual Exclusion:** You cannot specify both `message` and `content` in the `Event` constructor; doing so will raise a `ValueError`.
|
||||
@@ -0,0 +1,53 @@
|
||||
# RequestInput
|
||||
|
||||
The `RequestInput` class represents a structured request for input from the user, typically used to trigger an interrupt in a workflow (Human-in-the-loop).
|
||||
|
||||
## Introduction
|
||||
|
||||
In ADK, workflows can be configured to pause and wait for user intervention. The `RequestInput` event is the data structure that represents this interrupt request. It is typically yielded by a workflow node and translated into an `Event` with a special function call (`adk_request_input`) that the client application handles.
|
||||
|
||||
Key classes depending on `RequestInput` include `Workflow` (which pauses execution when encountering this event) and various HITL helper utilities (like `create_request_input_event` and `create_request_input_response`) that wrap it. It solves the developer problem of pausing a workflow and gathering structured feedback from a user before resuming.
|
||||
|
||||
## Get started
|
||||
|
||||
To request input from a user within a workflow, you yield a `RequestInput` object from a node function.
|
||||
|
||||
Here is a basic example of a node that requests user details:
|
||||
|
||||
```python
|
||||
from typing import Any, AsyncGenerator
|
||||
from google.adk import Context
|
||||
from google.adk.events.request_input import RequestInput
|
||||
from pydantic import BaseModel
|
||||
|
||||
class UserDetails(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
|
||||
async def request_input_node(
|
||||
ctx: Context,
|
||||
node_input: Any,
|
||||
) -> AsyncGenerator[Any, None]:
|
||||
"""A simple node that requests input from the user."""
|
||||
# Yield RequestInput to pause and request user details.
|
||||
# The response must conform to UserDetails schema.
|
||||
yield RequestInput(
|
||||
interrupt_id="get-user-details-1",
|
||||
message="Please provide user details.",
|
||||
response_schema=UserDetails,
|
||||
)
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
When a node yields a `RequestInput` object, the following process occurs:
|
||||
|
||||
1. **Workflow Pause**: The workflow engine detects the `RequestInput` event and pauses the execution of the workflow.
|
||||
2. **Event Translation**: The `RequestInput` is wrapped into an `Event` containing a mock function call named `adk_request_input`. The fields `message`, `payload`, and `response_schema` are passed as arguments to this function call.
|
||||
3. **Client Interaction**: The client application receiving this event displays the message to the user (optionally validating the input against the provided `response_schema`).
|
||||
4. **Resuming execution**: To resume the workflow, the client sends back a `FunctionResponse` matching the `interrupt_id` (used as the function call `id`) and named `adk_request_input`. The response payload is placed inside the `response` dictionary.
|
||||
5. **Resume**: The workflow engine delivers this response back to the node, allowing it to continue execution.
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Client-Side Validation**: When using `response_schema`, the client application is responsible for validating that the user's input conforms to the schema before sending it back to resume the workflow. ADK handles parsing on resume, but client-side validation is recommended for a better user experience.
|
||||
Reference in New Issue
Block a user