diff --git a/docs/context/index.md b/docs/context/index.md index 3c159361ef..4a114acd26 100644 --- a/docs/context/index.md +++ b/docs/context/index.md @@ -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`). @@ -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 ``` @@ -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`. @@ -447,7 +452,7 @@ While `InvocationContext` acts as the comprehensive internal container, ADK prov // Assume this function is wrapped by a FunctionTool public Map 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(...); @@ -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 ... @@ -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}'") @@ -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** @@ -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) @@ -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 @@ -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" @@ -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" @@ -1362,7 +1389,7 @@ Access relevant information from the past or external sources. Supported in ADKPython v0.1.0TypeScript v0.2.0 -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" @@ -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`.