From 3c9444438e3260322ea6ebe828917f438621b915 Mon Sep 17 00:00:00 2001 From: Jainish Date: Sat, 22 Nov 2025 17:40:11 +0530 Subject: [PATCH] docs: Add nested state access documentation for template injection This commit adds comprehensive documentation for the nested state access feature in template injection, which allows developers to access deeply nested properties using dot notation and optional chaining. Previously, developers could only access top-level state variables in instruction templates (e.g., {user}). This enhancement enables accessing nested properties like {user.profile.role} without needing to flatten the state structure. Key features documented: - Dot notation for accessing nested dictionaries and object attributes - Optional chaining with ? operator for safe navigation - Error handling behavior for missing keys - Support for mixed dictionary and object attribute access Example usage: ```python # Define nested state callback_context.state["user"] = { "name": "Alice", "profile": {"role": "Software Engineer"} } # Use in instruction template template = "Current user is {user.name} and {user.profile.role}" ``` This documentation supports the implementation in adk-python. Related issue: https://github.com/google/adk-python/issues/575 --- docs/sessions/state.md | 78 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/docs/sessions/state.md b/docs/sessions/state.md index 74855f811..f7f712225 100644 --- a/docs/sessions/state.md +++ b/docs/sessions/state.md @@ -108,11 +108,83 @@ To inject a value from the session state, enclose the key of the desired state v --8<-- "examples/go/snippets/sessions/instruction_template/instruction_template_example.go:key_template" ``` +#### Accessing Nested State with Dot Notation + +The templating system supports accessing nested values within your state objects using dot notation. This allows you to directly reference deeply nested properties without needing to flatten your state structure. + +**Syntax:** + +* **Dot Notation:** Use dots to traverse nested dictionaries or object attributes: `{user.profile.role}` +* **Optional Chaining:** Add a `?` after any key to safely handle missing values: `{user?.profile?.role?}` + * If any part of the path is missing or `None`, the template will insert an empty string instead of raising an error. + +**Example:** + +=== "Python" + + ```python + from google.adk.agents import LlmAgent, CallbackContext + from google.adk.agents.readonly_context import ReadonlyContext + from google.adk.utils import instructions_utils + + # Define a callback to populate nested state + def inject_nested_state(callback_context: CallbackContext): + callback_context.state["user"] = { + "name": "Alice", + "profile": { + "role": "Software Engineer", + "team": "AI Research" + } + } + + # Use nested state in instruction template + async def build_instruction(readonly_context: ReadonlyContext) -> str: + template = ( + "Current user is {user.name} and {user.profile.role}. " + "Please greet them by name and role." + ) + return await instructions_utils.inject_session_state(template, readonly_context) + + agent = LlmAgent( + name="GreetingAgent", + model="gemini-2.0-flash", + instruction=build_instruction, + on_before_agent_call=inject_nested_state + ) + + # The LLM will receive: + # "Current user is Alice and Software Engineer. Please greet them by name and role." + ``` + +**With Optional Chaining:** + +=== "Python" + + ```python + # If user.profile.department might not exist + template = "User {user.name} from {user?.profile?.department?} department" + + # If department is missing, this becomes: + # "User Alice from department" + # Instead of raising an error + ``` + +**Behavior:** + +* **Dictionary Access:** Works with nested dictionaries (e.g., `{config.database.host}`) +* **Object Attributes:** Works with object attributes (e.g., `{user.profile.email}`) +* **Mixed Access:** Can traverse both dictionaries and objects in the same path +* **Error Handling:** + * Without `?`: Raises a `KeyError` if any key in the path is missing + * With `?`: Returns an empty string if any key in the path is missing or `None` + #### Important Considerations -* Key Existence: Ensure that the key you reference in the instruction string exists in the session.state. If the key is missing, the agent will throw an error. To use a key that may or may not be present, you can include a question mark (?) after the key (e.g. {topic?}). -* Data Types: The value associated with the key should be a string or a type that can be easily converted to a string. -* Escaping: If you need to use literal curly braces in your instruction (e.g., for JSON formatting), you'll need to escape them. +* **Key Existence:** Ensure that the keys you reference in the instruction string exist in the session.state. If a key is missing, the agent will throw an error. To use a key that may or may not be present, include a question mark (?) after the key: + * Flat keys: `{topic?}` + * Nested keys: `{user?.profile?.role?}` +* **Data Types:** The value associated with the key should be a string or a type that can be easily converted to a string. +* **Escaping:** If you need to use literal curly braces in your instruction (e.g., for JSON formatting), you'll need to escape them. #### Bypassing State Injection with `InstructionProvider`