Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 57 additions & 30 deletions docs/context/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ The central piece holding all this information together for a single, complete u

## The Different types of Context

While `InvocationContext` acts as the comprehensive internal container, ADK provides specialized context objects tailored to specific situations. This ensures you have the right tools and permissions for the task at hand without needing to handle the full complexity of the internal context everywhere. Here are the different "flavors" you'll encounter:
While `InvocationContext` acts as the comprehensive internal container, ADK provides specialized context objects tailored to specific situations. This ensures you have the right tools and permissions for the task at hand without needing to handle the full complexity of the internal context everywhere.

With the introduction of a unified `Context` class, the ADK now provides a more consistent and powerful way to interact with the agent's environment. This new `Context` class is used in most situations, including callbacks and tool execution.

Here are the different "flavors" you'll encounter:

1. **`InvocationContext`**
* **Where Used:** Received as the `ctx` argument directly within an agent's core implementation methods (`_run_async_impl`, `_run_live_impl`).
Expand Down Expand Up @@ -282,31 +286,32 @@ While `InvocationContext` acts as the comprehensive internal container, ADK prov
}
```

3. **`CallbackContext`**
* **Where Used:** Passed as `callback_context` to agent lifecycle callbacks (`before_agent_callback`, `after_agent_callback`) and model interaction callbacks (`before_model_callback`, `after_model_callback`).
* **Purpose:** Facilitates inspecting and modifying state, interacting with artifacts, and accessing invocation details *specifically within callbacks*.
3. **`Context` (formerly `CallbackContext`)**
* **Where Used:** Passed as `context` to agent lifecycle callbacks (`before_agent_callback`, `after_agent_callback`) and model interaction callbacks (`before_model_callback`, `after_model_callback`). `CallbackContext` is now an alias for `Context`.
* **Purpose:** Facilitates inspecting and modifying state, interacting with artifacts, accessing credentials, leveraging memory, and accessing invocation details *specifically within callbacks*.
* **Key Capabilities (Adds to `ReadonlyContext`):**
* **Mutable `state` Property:** Allows reading *and writing* to session state. Changes made here (`callback_context.state['key'] = value`) are tracked and associated with the event generated by the framework after the callback.
* **Mutable `state` Property:** Allows reading *and writing* to session state. Changes made here (`context.state['key'] = value`) are tracked and associated with the event generated by the framework after the callback.
* **Artifact Methods:** `load_artifact(filename)` and `save_artifact(filename, part)` methods for interacting with the configured `artifact_service`.
* **Memory Methods:** `add_memory(memories)` to add memories to the memory service.
* Direct `user_content` access.

=== "Python"

```python
# Pseudocode: Callback receiving CallbackContext
from google.adk.agents.callback_context import CallbackContext
# Pseudocode: Callback receiving Context
from google.adk.agents.context import Context
from google.adk.models import LlmRequest
from google.genai import types
from typing import Optional

def my_before_model_cb(callback_context: CallbackContext, request: LlmRequest) -> Optional[types.Content]:
def my_before_model_cb(context: Context, request: LlmRequest) -> Optional[types.Content]:
# Read/Write state example
call_count = callback_context.state.get("model_calls", 0)
callback_context.state["model_calls"] = call_count + 1 # Modify state
call_count = context.state.get("model_calls", 0)
context.state["model_calls"] = call_count + 1 # Modify state

# Optionally load an artifact
# config_part = callback_context.load_artifact("model_config.json")
print(f"Preparing model call #{call_count + 1} for invocation {callback_context.invocation_id}")
# config_part = context.load_artifact("model_config.json")
print(f"Preparing model call #{call_count + 1} for invocation {context.invocation_id}")
return None # Allow model call to proceed
```

Expand Down Expand Up @@ -363,8 +368,8 @@ While `InvocationContext` acts as the comprehensive internal container, ADK prov

4. **`ToolContext`**
* **Where Used:** Passed as `tool_context` to the functions backing `FunctionTool`s and to tool execution callbacks (`before_tool_callback`, `after_tool_callback`).
* **Purpose:** Provides everything `CallbackContext` does, plus specialized methods essential for tool execution, like handling authentication, searching memory, and listing artifacts.
* **Key Capabilities (Adds to `CallbackContext`):**
* **Purpose:** Provides everything `Context` does, plus specialized methods essential for tool execution, like handling authentication, searching memory, and listing artifacts.
* **Key Capabilities (Adds to `Context`):**
* **Authentication Methods:** `request_credential(auth_config)` to trigger an auth flow, and `get_auth_response(auth_config)` to retrieve credentials provided by the user/system.
* **Artifact Listing:** `list_artifacts()` to discover available artifacts in the session.
* **Memory Search:** `search_memory(query)` to query the configured `memory_service`.
Expand Down Expand Up @@ -447,7 +452,7 @@ While `InvocationContext` acts as the comprehensive internal container, ADK prov

// Assume this function is wrapped by a FunctionTool
public Map<String, Object> searchExternalApi(String query, ToolContext toolContext){
String apiKey = toolContext.state.get("api_key");
String apiKey = toolContext.state().get("api_key");
if(apiKey.isEmpty()){
// Define required auth config
// authConfig = AuthConfig(...);
Expand Down Expand Up @@ -496,10 +501,10 @@ You'll frequently need to read information stored within the context.
# ... rest of tool logic ...

# Pseudocode: In a Callback function
from google.adk.agents.callback_context import CallbackContext
from google.adk.agents.context import Context

def my_callback(callback_context: CallbackContext, **kwargs):
last_tool_result = callback_context.state.get("temp:last_api_result") # Read temporary state
def my_callback(context: Context, **kwargs):
last_tool_result = context.state.get("temp:last_api_result") # Read temporary state
if last_tool_result:
print(f"Found temporary result from last tool: {last_tool_result}")
# ... callback logic ...
Expand Down Expand Up @@ -638,12 +643,12 @@ You'll frequently need to read information stored within the context.

```python
# Pseudocode: In a Callback
from google.adk.agents.callback_context import CallbackContext
from google.adk.agents.context import Context

def check_initial_intent(callback_context: CallbackContext, **kwargs):
def check_initial_intent(context: Context, **kwargs):
initial_text = "N/A"
if callback_context.user_content and callback_context.user_content.parts:
initial_text = callback_context.user_content.parts[0].text or "Non-text input"
if context.user_content and context.user_content.parts:
initial_text = context.user_content.parts[0].text or "Non-text input"

print(f"This invocation started with user input: '{initial_text}'")

Expand Down Expand Up @@ -701,9 +706,9 @@ You'll frequently need to read information stored within the context.

### Managing State

State is crucial for memory and data flow. When you modify state using `CallbackContext` or `ToolContext`, the changes are automatically tracked and persisted by the framework.
State is crucial for memory and data flow. When you modify state using `Context` or `ToolContext`, the changes are automatically tracked and persisted by the framework.

* **How it Works:** Writing to `callback_context.state['my_key'] = my_value` or `tool_context.state['my_key'] = my_value` adds this change to the `EventActions.state_delta` associated with the current step's event. The `SessionService` then applies these deltas when persisting the event.
* **How it Works:** Writing to `context.state['my_key'] = my_value` or `tool_context.state['my_key'] = my_value` adds this change to the `EventActions.state_delta` associated with the current step's event. The `SessionService` then applies these deltas when persisting the event.

* **Passing Data Between Tools**

Expand Down Expand Up @@ -800,7 +805,7 @@ State is crucial for memory and data flow. When you modify state using `Callback

```python
# Pseudocode: Tool or Callback identifies a preference
from google.adk.tools import ToolContext # Or CallbackContext
from google.adk.tools import ToolContext # Or Context

def set_user_preference(tool_context: ToolContext, preference: str, value: str) -> dict:
# Use 'user:' prefix for user-level state (if using a persistent SessionService)
Expand Down Expand Up @@ -862,10 +867,10 @@ Use artifacts to handle files or large data blobs associated with the session. C

```python
# Pseudocode: In a callback or initial tool
from google.adk.agents.callback_context import CallbackContext # Or ToolContext
from google.adk.agents.context import Context # Or ToolContext
from google.genai import types

def save_document_reference(context: CallbackContext, file_path: str) -> None:
def save_document_reference(context: Context, file_path: str) -> None:
# Assume file_path is something like "gs://my-bucket/docs/report.pdf" or "/local/path/to/report.pdf"
try:
# Create a Part containing the path/URI text
Expand All @@ -880,7 +885,7 @@ Use artifacts to handle files or large data blobs associated with the session. C
print(f"Unexpected error saving artifact reference: {e}")

# Example usage:
# save_document_reference(callback_context, "gs://my-bucket/docs/report.pdf")
# save_document_reference(context, "gs://my-bucket/docs/report.pdf")
```

=== "TypeScript"
Expand Down Expand Up @@ -1332,6 +1337,28 @@ Access relevant information from the past or external sources.
except Exception as e:
return {"error": f"Unexpected error searching memory: {e}"}
```
```python
# Pseudocode: Callback adding to memory
from google.adk.agents.context import Context
from google.adk.memory.memory_entry import MemoryEntry
from google.genai.types import content_types

async def my_after_agent_callback(context: Context):
# Add the last user message and agent response to memory
user_message = context.user_content.parts[0].text
agent_response = "..." # get agent response from the context
await context.add_memory(
memories=[
MemoryEntry(
content=content_types.to_content(user_message), role="user"
),
MemoryEntry(
content=content_types.to_content(agent_response),
role="model",
),
]
)
```

=== "TypeScript"

Expand Down Expand Up @@ -1362,7 +1389,7 @@ Access relevant information from the past or external sources.
<span class="lst-supported">Supported in ADK</span><span class="lst-python">Python v0.1.0</span><span class="lst-typescript">TypeScript v0.2.0</span>
</div>

While most interactions happen via `CallbackContext` or `ToolContext`, sometimes the agent's core logic (`_run_async_impl`/`_run_live_impl`) needs direct access.
While most interactions happen via `Context` or `ToolContext`, sometimes the agent's core logic (`_run_async_impl`/`_run_live_impl`) needs direct access.

=== "Python"

Expand Down Expand Up @@ -1429,7 +1456,7 @@ Setting `ctx.end_invocation = True` is a way to gracefully stop the entire reque

## Key Takeaways & Best Practices

* **Use the Right Context:** Always use the most specific context object provided (`ToolContext` in tools/tool-callbacks, `CallbackContext` in agent/model-callbacks, `ReadonlyContext` where applicable). Use the full `InvocationContext` (`ctx`) directly in `_run_async_impl` / `_run_live_impl` only when necessary.
* **Use the Right Context:** Always use the most specific context object provided (`ToolContext` in tools/tool-callbacks, `Context` in agent/model-callbacks, `ReadonlyContext` where applicable). Use the full `InvocationContext` (`ctx`) directly in `_run_async_impl` / `_run_live_impl` only when necessary.
* **State for Data Flow:** `context.state` is the primary way to share data, remember preferences, and manage conversational memory *within* an invocation. Use prefixes (`app:`, `user:`, `temp:`) thoughtfully when using persistent storage.
* **Artifacts for Files:** Use `context.save_artifact` and `context.load_artifact` for managing file references (like paths or URIs) or larger data blobs. Store references, load content on demand.
* **Tracked Changes:** Modifications to state or artifacts made via context methods are automatically linked to the current step's `EventActions` and handled by the `SessionService`.
Expand Down
Loading