Skip to content
Open
Show file tree
Hide file tree
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
36 changes: 31 additions & 5 deletions docs/artifacts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Understanding artifacts involves grasping a few key components: the service that
* `List Artifact keys`: Lists the unique filenames of artifacts within a given scope.
* `Delete Artifact`: Removes an artifact (and potentially all its versions, depending on implementation).
* `List versions`: Lists all available version numbers for a specific artifact filename.
* `List artifact versions` and `Get artifact version` (Python): Return `ArtifactVersion` metadata (version number, canonical URI, MIME type, creation time, custom metadata) instead of the artifact payload.

* **Configuration:** You provide an instance of an artifact service (e.g., `InMemoryArtifactService`, `GcsArtifactService`) when initializing the `Runner`. The `Runner` then makes this service available to agents and tools via the `InvocationContext`.

Expand Down Expand Up @@ -351,6 +352,8 @@ Understanding artifacts involves grasping a few key components: the service that

* **User Scope (`"user:"` prefix):** If you prefix the filename with `"user:"`, like `"user:profile.png"`, the artifact is associated only with the `app_name` and `user_id`. It can be accessed or updated from *any* session belonging to that user within the app.

* **Listing behavior:** In Python, listing artifacts from within a session returns the session-scoped filenames *and* that user's user-scoped filenames, with the `"user:"` prefix retained (e.g. `["summary.txt", "user:settings.json"]`).


=== "Python"

Expand Down Expand Up @@ -429,7 +432,7 @@ These core concepts work together to provide a flexible system for managing bina

The primary way you interact with artifacts within your agent's logic (specifically within callbacks or tools) is through methods provided by the `CallbackContext` and `ToolContext` objects. These methods abstract away the underlying storage details managed by the `ArtifactService`.

*(Note: In TypeScript, `CallbackContext` and `ToolContext` are unified into a single `Context` type.)*
*(Note: In Python and TypeScript, `CallbackContext` and `ToolContext` are unified into a single `Context` type. In Python both names remain as aliases of `Context` and can be used interchangeably.)*

### Prerequisite: Configuring the `ArtifactService`

Expand Down Expand Up @@ -553,7 +556,7 @@ Before you can use any artifact methods via the context objects, you **must** pr

### Accessing Methods

The artifact interaction methods are available directly on instances of `CallbackContext` (passed to agent and model callbacks) and `ToolContext` (passed to tool callbacks) in Python, Go, and Java and available on the unified `Context` in TypeScript.
The artifact interaction methods are available directly on instances of `CallbackContext` (passed to agent and model callbacks) and `ToolContext` (passed to tool callbacks) in Go and Java, and available on the unified `Context` in Python and TypeScript (in Python, `CallbackContext` and `ToolContext` are aliases of `Context`).

#### Saving Artifacts

Expand Down Expand Up @@ -933,7 +936,7 @@ artifact in a later turn.
```python
from google.adk.tools.tool_context import ToolContext

def list_user_files_py(tool_context: ToolContext) -> str:
async def list_user_files_py(tool_context: ToolContext) -> str:
"""Tool to list available artifacts for the user."""
try:
available_files = await tool_context.list_artifacts()
Expand Down Expand Up @@ -1090,7 +1093,7 @@ ADK provides concrete implementations of the `BaseArtifactService` interface, of
### InMemoryArtifactService

* **Storage Mechanism:**
* Python: Uses a Python dictionary (`self.artifacts`) held in the application's memory. The dictionary keys represent the artifact path, and the values are lists of `types.Part`, where each list element is a version.
* Python: Uses a Python dictionary (`self.artifacts`) held in the application's memory. The dictionary keys represent the artifact path, and the values are lists of entries, where each list element is a version holding the `types.Part` payload plus its `ArtifactVersion` metadata.
* Java: Uses nested `HashMap` instances (`private final Map<String, Map<String, Map<String, Map<String, List<Part>>>>> artifacts;`) held in memory. The keys at each level are `appName`, `userId`, `sessionId`, and `filename` respectively. The innermost `List<Part>` stores the versions of the artifact, where the list index corresponds to the version number.
* **Key Features:**
* **Simplicity:** Requires no external setup or dependencies beyond the core ADK library.
Expand Down Expand Up @@ -1165,6 +1168,29 @@ ADK provides concrete implementations of the `BaseArtifactService` interface, of
```kotlin
--8<-- "examples/kotlin/snippets/artifacts/ArtifactExamples.kt:in_memory_service"
```
### FileArtifactService

* **Storage Mechanism:** Stores artifacts on the local filesystem, beneath a root directory you choose. Each version of an artifact is a directory holding the payload file plus a `metadata.json` sidecar, so the tree can be inspected with ordinary file tools.
* **Key Features:**
* **Persistence:** Artifacts survive application restarts, as long as the root directory does.
* **No external dependencies:** Needs no cloud project, credentials, or network access, only a writable directory. The root directory is created on instantiation if it does not exist.
* **Use Cases:**
* Local development and single-machine deployments that need artifacts to outlive the process.
* In Python, this is also the service behind `--artifact_service_uri file://<path>` for `adk web` / `adk run`.
* **Instantiation:**

=== "Python"

```python
from google.adk.artifacts import FileArtifactService

# Point it at the directory that should hold the artifact tree
file_service_py = FileArtifactService(root_dir="/path/to/adk-artifacts")

# Then pass it to the Runner
# runner = Runner(..., artifact_service=file_service_py)
```

### GcsArtifactService


Expand All @@ -1173,7 +1199,7 @@ ADK provides concrete implementations of the `BaseArtifactService` interface, of
* **Key Features:**
* **Persistence:** Artifacts stored in GCS persist across application restarts and deployments.
* **Scalability:** Leverages the scalability and durability of Google Cloud Storage.
* **Versioning:** Explicitly stores each version as a distinct GCS object. The `saveArtifact` method in `GcsArtifactService`.
* **Versioning:** Explicitly stores each version as a distinct GCS object. In Python, `save_artifact` assigns the next version number (the first version is `0`) rather than overwriting an existing object.
* **Permissions Required:** The application environment needs appropriate credentials (e.g., Application Default Credentials) and IAM permissions to read from and write to the specified GCS bucket.
* **Use Cases:**
* Production environments requiring persistent artifact storage.
Expand Down
16 changes: 8 additions & 8 deletions docs/events/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Events are the fundamental units of information flow within the Agent Developmen

## 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.
An `Event` in ADK is a 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.
Expand Down Expand Up @@ -157,7 +157,7 @@ In essence, the entire process, from a user's query to the agent's final answer,
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.
The specific parameters or method names for the primitives may vary slightly by SDK language (e.g., the `event.content` attribute in Python, `event.content().get().parts()` in Java). Refer to the language-specific API documentation for details.

### Identifying Event Origin and Type

Expand Down Expand Up @@ -733,10 +733,10 @@ The `event.actions` object signals changes that occurred or should occur. Always

Use the built-in helper method `event.is_final_response()` to identify events suitable for display as the agent's complete output for a turn.

* **Purpose:** Filters out intermediate steps (like tool calls, partial streaming text, internal state updates) from the final user-facing message(s).
* **Purpose:** Filters out intermediate steps (like tool calls and partial streaming text) from the final user-facing message(s).
* **When `True`?**
1. The event contains a tool result (`function_response`) and `skip_summarization` is `True`.
2. The event contains a tool call (`function_call`) for a tool marked as `is_long_running=True`. In Java, check if the `longRunningToolIds` list is empty:
1. The `skip_summarization` action is `True`. In Python this flag alone is enough; the event does not need to carry a tool result (`function_response`).
2. The event's `long_running_tool_ids` is non-empty, meaning a tool marked as `is_long_running=True` was called. In Python this list alone is enough; the event does not need to carry the tool call (`function_call`) itself. In Java, check if the `longRunningToolIds` list is empty:
* `event.longRunningToolIds().isPresent() && !event.longRunningToolIds().get().isEmpty()` is `true`.
3. OR, **all** of the following are met:
* No function calls (`get_function_calls()` is empty).
Expand Down Expand Up @@ -955,7 +955,7 @@ Events are created at different points and processed systematically by the frame
2. **Runner Receives:** The main `Runner` executing the agent receives the event.
3. **SessionService Processing:** The `Runner` sends the event to the configured `SessionService`. This is a critical step:
* **Applies Deltas:** The service merges `event.actions.state_delta` into `session.state` and updates internal records based on `event.actions.artifact_delta`. (Note: The actual artifact *saving* usually happened earlier when `context.save_artifact` was called).
* **Finalizes Metadata:** Assigns a unique `event.id` if not present, may update `event.timestamp`.
* **Event Metadata:** In Python, `event.id` and `event.timestamp` are already populated when the `Event` object is constructed (a random `id` if none was supplied, and the current time), so the service does not assign them; it records the event as it received it.
* **Persists to History:** Appends the processed event to the `session.events` list.
4. **External Yield:** The `Runner` yields (Python) or returns/emits (Java) the processed event outwards to the calling application (e.g., the code that invoked `runner.run_async`).

Expand Down Expand Up @@ -1018,7 +1018,7 @@ Here are concise examples of typical events you might see in the stream:
// actions might have skip_summarization=True
}
```
* **State/Artifact Update Only:** (`is_final_response() == False`)
* **State/Artifact Update Only:** (`is_final_response() == True`: no function call or function response, and not partial)
```json
{
"author": "InternalUpdater",
Expand All @@ -1039,7 +1039,7 @@ Here are concise examples of typical events you might see in the stream:
"actions": {"transfer_to_agent": "BillingAgent"} // Added by framework
}
```
* **Loop Escalation Signal:** (`is_final_response() == False`)
* **Loop Escalation Signal:** (`is_final_response() == True`: the `escalate` action does not affect the check)
```json
{
"author": "CheckerAgent",
Expand Down
7 changes: 4 additions & 3 deletions docs/sessions/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ to decide which is the best fit for your agent.
| **Dependencies** | None. | Google Cloud Project, Agent Platform API | Google Cloud Project, Knowledge Engine, the Agent Platform SDK (optional install). |
| **When to use it** | When you want to search across multiple sessions’ chat histories for prototyping. | When you want your agent to remember and learn from past interactions. | When you already have RAG infrastructure or want to retrieve over raw conversation transcripts. |

`VertexAiRagMemoryService` is only exported from `google.adk.memory` when the
Agent Platform SDK is installed. Memory Bank and RAG-backed memory are
You can always import `VertexAiRagMemoryService` from `google.adk.memory`, but
constructing it raises `ImportError` unless the Agent Platform SDK is installed
(`pip install google-adk[gcp]`). Memory Bank and RAG-backed memory are
documented in [Memory Bank](#memory-bank) and [RAG Memory](#rag-memory) below.


Expand Down Expand Up @@ -611,7 +612,7 @@ The memory workflow includes the following steps:
6. **Results Returned:** The `MemoryService` searches its store, using keyword
matching or semantic search, and returns matching snippets as a
`SearchMemoryResponse` containing a list of `MemoryEntry` objects, each
holding `content`, and all optional: `author`, `timestamp`, and
holding `content`, and all optional: `id`, `author`, `timestamp`, and
`custom_metadata`.
7. **Agent Uses Results:** The tool returns these results to the agent, usually
as part of the context or function response. The agent can then use this
Expand Down
10 changes: 6 additions & 4 deletions docs/sessions/session/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ the storage backend that best suits your needs:
* **Persistence:** Yes. Data is managed reliably and scalably via [Agent
Runtime](/deploy/agent-runtime/).
* **Requires:**
* A Google Cloud project (`pip install vertexai`)
* A Google Cloud project.
* The `gcp` extra (`pip install google-adk[gcp]`).
* A Google Cloud storage bucket that can be configured by this
[step](https://cloud.google.com/vertex-ai/docs/pipelines/configure-project#storage).
* An Agent Runtime resource name/ID that can setup following this
Expand All @@ -261,7 +262,7 @@ the storage backend that best suits your needs:
=== "Python"

```py
# Requires: pip install google-adk[vertexai]
# Requires: pip install google-adk[gcp]
# Plus GCP setup and authentication
from google.adk.sessions import VertexAiSessionService

Expand All @@ -272,7 +273,7 @@ the storage backend that best suits your needs:

session_service = VertexAiSessionService(project=PROJECT_ID, location=LOCATION)
# Use REASONING_ENGINE_APP_NAME when calling service methods, e.g.:
# session_service = await session_service.create_session(app_name=REASONING_ENGINE_APP_NAME, ...)
# session = await session_service.create_session(app_name=REASONING_ENGINE_APP_NAME, ...)
```

=== "Go"
Expand Down Expand Up @@ -331,7 +332,8 @@ For more information on connecting to Google Cloud from ADK agents, see
* **How it works:** Connects to a relational database (e.g., PostgreSQL, MySQL,
SQLite) to store session data persistently in tables.
* **Persistence:** Yes. Data survives application restarts.
* **Requires:** A configured database.
* **Requires:** A configured database and the `db` extra
(`pip install google-adk[db]`).
* **Best for:** Applications needing reliable, persistent storage that you
manage yourself.

Expand Down
17 changes: 10 additions & 7 deletions docs/sessions/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Prefixes on state keys define their scope and persistence behavior, especially w
* **Scope:** Tied to the `user_id`, shared across *all* sessions for that user (within the same `app_name`).
* **Persistence:** Persistent with `Database` or `VertexAI`. (Stored by `InMemory` but lost on restart).
* **Use Cases:** User preferences (e.g., `'user:theme'`), profile details (e.g., `'user:name'`).
* **Reading without a session:** In Python, `await session_service.get_user_state(app_name=..., user_id=...)` returns the user-scoped keys with the `user:` prefix stripped, so you can read them before a session exists. `VertexAiSessionService` is the exception: it always raises `NotImplementedError`, because the Agent Runtime API does not expose user state independently of a session. There, enumerate sessions with `list_sessions` and call `get_session` on each result instead.
* **Example:** `session.state['user:preferred_language'] = 'fr'`

* **`app:` Prefix (App State):**
Expand Down Expand Up @@ -340,8 +341,9 @@ This is the simplest method for saving an agent's final text response directly i
print(f"Initial state: {session.state}")

# --- Run the Agent ---
# Runner handles calling append_event, which uses the output_key
# to automatically create the state_delta.
# The agent uses the output_key to put its response into the event's
# state_delta; the Runner hands that event to append_event, which
# applies the delta to the session state.
user_message = Content(parts=[Part(text="Hello")])
for event in runner.run(user_id=user_id,
session_id=session_id,
Expand Down Expand Up @@ -418,7 +420,7 @@ This is the simplest method for saving an agent's final text response directly i
--8<-- "examples/java/snippets/src/main/java/state/GreetingAgentExample.java:full_code"
```

Behind the scenes, the `Runner` uses the `output_key` to create the necessary `EventActions` with a `state_delta` and calls `append_event`.
Behind the scenes, the agent itself uses the `output_key` to write the response into the `state_delta` of the `EventActions` on the event it yields; the `Runner` then passes that event to the `SessionService`'s `append_event`, which applies the delta.

**2\. The Standard Way: `EventActions.state_delta` (for Complex Updates)**

Expand Down Expand Up @@ -551,9 +553,9 @@ For more complex scenarios (updating multiple keys, non-string values, specific

**3. Via `CallbackContext` or `ToolContext` (Recommended for Callbacks and Tools)**

*(Note: In TypeScript, this is done via the unified `Context` type.)*
*(Note: In Python and TypeScript, `CallbackContext` and `ToolContext` are unified into a single `Context` type. In Python both names remain as aliases of `Context` and can be used interchangeably.)*

Modifying state within agent callbacks (e.g., `on_before_agent_call`, `on_after_agent_call`) or tool functions is best done using the `state` attribute of the `CallbackContext` or `ToolContext` provided to your function.
Modifying state within agent callbacks (e.g., `before_agent_callback`, `after_agent_callback`) or tool functions is best done using the `state` attribute of the `CallbackContext` or `ToolContext` provided to your function.

* `callback_context.state['my_key'] = my_value`
* `tool_context.state['my_key'] = my_value`
Expand All @@ -568,7 +570,8 @@ For more comprehensive details on context objects, refer to the [Context documen

```python
# In an agent callback or tool function
from google.adk.agents import CallbackContext # or ToolContext
from google.adk.agents.callback_context import CallbackContext
# or, equivalently: from google.adk.tools.tool_context import ToolContext

def my_callback_or_tool_function(context: CallbackContext, # Or ToolContext
# ... other parameters ...
Expand Down Expand Up @@ -646,7 +649,7 @@ For more comprehensive details on context objects, refer to the [Context documen
* Reads the `state_delta` from the event's `actions`.
* Applies these changes to the state managed by the `SessionService`, correctly handling prefixes and persistence based on the service type.
* Updates the session's `last_update_time`.
* Ensures thread-safety for concurrent updates.
* Serializes concurrent updates to the same session where the service supports it: `DatabaseSessionService` takes a per-session lock, while `InMemorySessionService` is not safe for multi-threaded use.

### ⚠️ A Warning About Direct State Modification

Expand Down
Loading