# Events
Supported in ADKPython v0.1.0TypeScript v0.2.0Go v0.1.0Java v0.1.0
Events are the fundamental units of information flow within the Agent Development Kit (ADK). They represent every significant occurrence during an agent's interaction lifecycle, from initial user input to the final response and all the steps in between. Understanding events is crucial because they are the primary way components communicate, state is managed, and control flow is directed.
## What Events Are and Why They Matter
An `Event` in ADK is an immutable record representing a specific point in the agent's execution. It captures user messages, agent replies, requests to use tools (function calls), tool results, state changes, control signals, and errors.
=== "Python"
Technically, it's an instance of the `google.adk.events.Event` class, which builds upon the basic `LlmResponse` structure by adding essential ADK-specific metadata and an `actions` payload.
```python
# Conceptual Structure of an Event (Python)
# from google.adk.events import Event, EventActions
# from google.genai import types
# class Event(LlmResponse): # Simplified view
# # --- LlmResponse fields ---
# content: Optional[types.Content]
# partial: Optional[bool]
# # ... other response fields ...
# # --- ADK specific additions ---
# author: str # 'user' or agent name
# invocation_id: str # ID for the whole interaction run
# id: str # Unique ID for this specific event
# timestamp: float # Creation time
# actions: EventActions # Important for side-effects & control
# branch: Optional[str] # Hierarchy path
# # ...
```
=== "Go"
In Go, this is a struct of type `google.golang.org/adk/session.Event`.
```go
// Conceptual Structure of an Event (Go - See session/session.go)
// Simplified view based on the session.Event struct
type Event struct {
// --- Fields from embedded model.LLMResponse ---
model.LLMResponse
// --- ADK specific additions ---
Author string // 'user' or agent name
InvocationID string // ID for the whole interaction run
ID string // Unique ID for this specific event
Timestamp time.Time // Creation time
Actions EventActions // Important for side-effects & control
Branch string // Hierarchy path
// ... other fields
}
// model.LLMResponse contains the Content field
type LLMResponse struct {
Content *genai.Content
// ... other fields
}
```
=== "Java"
In Java, this is an instance of the `com.google.adk.events.Event` class. It also builds upon a basic response structure by adding essential ADK-specific metadata and an `actions` payload.
```java
// Conceptual Structure of an Event (Java - See com.google.adk.events.Event.java)
// Simplified view based on the provided com.google.adk.events.Event.java
// public class Event extends JsonBaseModel {
// // --- Fields analogous to LlmResponse ---
// private Optional content;
// private Optional partial;
// // ... other response fields like errorCode, errorMessage ...
// // --- ADK specific additions ---
// private String author; // 'user' or agent name
// private String invocationId; // ID for the whole interaction run
// private String id; // Unique ID for this specific event
// private long timestamp; // Creation time (epoch milliseconds)
// private EventActions actions; // Important for side-effects & control
// private Optional branch; // Hierarchy path
// // ... other fields like turnComplete, longRunningToolIds etc.
// }
```
Events are central to ADK's operation for several key reasons:
1. **Communication:** They serve as the standard message format between the user interface, the `Runner`, agents, the LLM, and tools. Everything flows as an `Event`.
2. **Signaling State & Artifact Changes:** Events carry instructions for state modifications and track artifact updates. The `SessionService` uses these signals to ensure persistence. In Python changes are signaled via `event.actions.state_delta` and `event.actions.artifact_delta`.
3. **Control Flow:** Specific fields like `event.actions.transfer_to_agent` or `event.actions.escalate` act as signals that direct the framework, determining which agent runs next or if a loop should terminate.
4. **History & Observability:** The sequence of events recorded in `session.events` provides a complete, chronological history of an interaction, invaluable for debugging, auditing, and understanding agent behavior step-by-step.
In essence, the entire process, from a user's query to the agent's final answer, is orchestrated through the generation, interpretation, and processing of `Event` objects.
## Understanding and Using Events
As a developer, you'll primarily interact with the stream of events yielded by the `Runner`. Here's how to understand and extract information from them:
!!! Note
The specific parameters or method names for the primitives may vary slightly by SDK language (e.g., `event.content()` in Python, `event.content().get().parts()` in Java). Refer to the language-specific API documentation for details.
### Identifying Event Origin and Type
Quickly determine what an event represents by checking:
* **Who sent it? (`event.author`)**
* `'user'`: Indicates input directly from the end-user.
* `'AgentName'`: Indicates output or action from a specific agent (e.g., `'WeatherAgent'`, `'SummarizerAgent'`).
* **What's the main payload? (`event.content` and `event.content.parts`)**
* **Text:** Indicates a conversational message. For Python, check if `event.content.parts[0].text` exists. For Java, check if `event.content()` is present, its `parts()` are present and not empty, and the first part's `text()` is present.
* **Tool Call Request:** Check `event.get_function_calls()`. If not empty, the LLM is asking to execute one or more tools. Each item in the list has `.name` and `.args`.
* **Tool Result:** Check `event.get_function_responses()`. If not empty, this event carries the result(s) from tool execution(s). Each item has `.name` and `.response` (the dictionary returned by the tool). *Note:* For history structuring, the `role` inside the `content` is often `'user'`, but the event `author` is typically the agent that requested the tool call.
* **Is it streaming output? (`event.partial`)**
Indicates whether this is an incomplete chunk of text from the LLM.
* `True`: More text will follow.
* `False` or `None`/`Optional.empty()`: This part of the content is complete (though the overall turn might not be finished if `turn_complete` is also false).
=== "Python"
```python
# Pseudocode: Basic event identification (Python)
# async for event in runner.run_async(...):
# print(f"Event from: {event.author}")
#
# if event.content and event.content.parts:
# if event.get_function_calls():
# print(" Type: Tool Call Request")
# elif event.get_function_responses():
# print(" Type: Tool Result")
# elif event.content.parts[0].text:
# if event.partial:
# print(" Type: Streaming Text Chunk")
# else:
# print(" Type: Complete Text Message")
# else:
# print(" Type: Other Content (e.g., code result)")
# elif event.actions and (event.actions.state_delta or event.actions.artifact_delta):
# print(" Type: State/Artifact Update")
# else:
# print(" Type: Control Signal or Other")
```
=== "Go"
```go
// Pseudocode: Basic event identification (Go)
import (
"fmt"
"google.golang.org/adk/session"
"google.golang.org/genai"
)
func hasFunctionCalls(content *genai.Content) bool {
if content == nil {
return false
}
for _, part := range content.Parts {
if part.FunctionCall != nil {
return true
}
}
return false
}
func hasFunctionResponses(content *genai.Content) bool {
if content == nil {
return false
}
for _, part := range content.Parts {
if part.FunctionResponse != nil {
return true
}
}
return false
}
func processEvents(events <-chan *session.Event) {
for event := range events {
fmt.Printf("Event from: %s\n", event.Author)
if event.LLMResponse != nil && event.LLMResponse.Content != nil {
if hasFunctionCalls(event.LLMResponse.Content) {
fmt.Println(" Type: Tool Call Request")
} else if hasFunctionResponses(event.LLMResponse.Content) {
fmt.Println(" Type: Tool Result")
} else if len(event.LLMResponse.Content.Parts) > 0 {
if event.LLMResponse.Content.Parts[0].Text != "" {
if event.LLMResponse.Partial {
fmt.Println(" Type: Streaming Text Chunk")
} else {
fmt.Println(" Type: Complete Text Message")
}
} else {
fmt.Println(" Type: Other Content (e.g., code result)")
}
}
} else if len(event.Actions.StateDelta) > 0 {
fmt.Println(" Type: State Update")
} else {
fmt.Println(" Type: Control Signal or Other")
}
}
}
```
=== "Java"
```java
// Pseudocode: Basic event identification (Java)
// import com.google.genai.types.Content;
// import com.google.adk.events.Event;
// import com.google.adk.events.EventActions;
// runner.runAsync(...).forEach(event -> { // Assuming a synchronous stream or reactive stream
// System.out.println("Event from: " + event.author());
//
// if (event.content().isPresent()) {
// Content content = event.content().get();
// if (!event.functionCalls().isEmpty()) {
// System.out.println(" Type: Tool Call Request");
// } else if (!event.functionResponses().isEmpty()) {
// System.out.println(" Type: Tool Result");
// } else if (content.parts().isPresent() && !content.parts().get().isEmpty() &&
// content.parts().get().get(0).text().isPresent()) {
// if (event.partial().orElse(false)) {
// System.out.println(" Type: Streaming Text Chunk");
// } else {
// System.out.println(" Type: Complete Text Message");
// }
// } else {
// System.out.println(" Type: Other Content (e.g., code result)");
// }
// } else if (event.actions() != null &&
// ((event.actions().stateDelta() != null && !event.actions().stateDelta().isEmpty()) ||
// (event.actions().artifactDelta() != null && !event.actions().artifactDelta().isEmpty()))) {
// System.out.println(" Type: State/Artifact Update");
// } else {
// System.out.println(" Type: Control Signal or Other");
// }
// });
```
### Extracting Key Information
Once you know the event type, access the relevant data:
* **Text Content:**
Always check for the presence of content and parts before accessing text. In Python its `text = event.content.parts[0].text`.
* **Function Call Details:**
=== "Python"
```python
calls = event.get_function_calls()
if calls:
for call in calls:
tool_name = call.name
arguments = call.args # This is usually a dictionary
print(f" Tool: {tool_name}, Args: {arguments}")
# Application might dispatch execution based on this
```
=== "Go"
```go
import (
"fmt"
"google.golang.org/adk/session"
"google.golang.org/genai"
)
func handleFunctionCalls(event *session.Event) {
if event.LLMResponse == nil || event.LLMResponse.Content == nil {
return
}
calls := event.Content.FunctionCalls()
if len(calls) > 0 {
for _, call := range calls {
toolName := call.Name
arguments := call.Args
fmt.Printf(" Tool: %s, Args: %v\n", toolName, arguments)
// Application might dispatch execution based on this
}
}
}
```
=== "Java"
```java
import com.google.genai.types.FunctionCall;
import com.google.common.collect.ImmutableList;
import java.util.Map;
ImmutableList calls = event.functionCalls(); // from Event.java
if (!calls.isEmpty()) {
for (FunctionCall call : calls) {
String toolName = call.name().get();
// args is Optional