Files
google__adk-docs/docs/sessions/memory.md
Kristopher Overholt 50f7df7f46 Add Kotlin language support to ADK docs (#1768)
* Add Kotlin to hero / front page

* Add quickstart page for Kotlin

* Complete Kotlin quickstart guide and fix hero code sample (#2)

* Replace GitHub repo links with language icons in header (#3)

* Fix header icon FOUC and homepage font weight regression (#4)

* Testing staging pipeline

* Revert test edit (for staging pipeline)

* Update language icon tooltips to indicate GitHub destination (#5)

* Add link to ADK Kotlin release notes (#7)

* Initial commit of ADK Kotlin API reference docs (#6)

* Add script to generate ADK Kotlin API reference docs (#8)

* Update links and link checker ignore list (temporarily) (#9)

* Add ADK Kotlin for Android getting started guide to Advanced setup page (#10)

* Add advanced setup page with steps to "Use ADK Kotlin in Android projects"

* Update temp link checker rules

* Add placeholder folder for adk-samples (#13)

* adding linter/compilation checks for kotlin snippets (#12)

* adding linter/compilation checks for kotlin snippets

* Add Kotlin validation scripts

* Initial commit of Kotlin sample agents for adk-samples (#15)

* Adding kotlin snippet for llm agents (#16)

* Adding kotlin snippets to  Events (#17)

* Pull changes to docs/events/index.md from glaforge-kotlin-snippets

* fixing kotlin event timestamp and longRunningToolIds

* Fix language tags (#19)

* Fix language tags

* Update

* Fix wrapping

* Fix wrapping (again)

* Fix wrapping/format

* Fix language tag on integration page

* Enable check_paths in PyMdown Snippets Extension to make the build fail if a snippet can't be found (#20)

* Update mkdocs config (#21)

* Fix broken links, update URLs to adk.dev, and improve (temp) lychee config (#22)

* Add Kotlin/maven badge to README (#23)

* Adding Kotlin snippets for artifacts  (#18)

* Pull Kotlin snippets for artifacts from glaforge-kotlin-snippets

* Add comprehensive Kotlin snippets for artifacts

* Refactor artifacts documentation to use external Kotlin snippets

* Update Kotlin model to gemini-flash-latest

* Fix GCS initialization in Kotlin artifact snippet

* afixi failing test with capital-agent added to files_to_check

* Fix snippet label syntax for MkDocs build

* Configure proper Gradle project for Kotlin snippets and fix dependencies

* Add KSP support and generated sources to Kotlin snippets build

* fixing capital_agent turnComplete

* Fix syntax error in build.gradle.kts by removing invalid placeholders (#25)

* Adding Kotlin snippets to google-gemini.md (#27)

Pulling kotlin changes to google-gemini.md from glaforge-kotlin-snippets

* Add a warning about not adding an api key to production code. (#28)

* Add a warning about not adding an api key to production code.

* Update note

---------

Co-authored-by: Kristopher Overholt <koverholt@google.com>

* Add ADK Demo App sample showcasing Gemini-powered agents (#29)

This sample demonstrates how to use the Google ADK (Agent Development Kit) in an Android application to create a chat interface powered by a Gemini-based "Fun Facts" agent. The implementation features:
*   Integration with the Kotlin ADK core and processor libraries.
*   A `FunFactsAgent` defined using `LlmAgent` and the Gemini model.
*   A `ChatViewModel` utilizing `InMemoryRunner` for asynchronous message streaming.
*   A modern UI built with Jetpack Compose and Material 3.
*   Build configuration logic for secure API key management via environment variables or `local.properties`.

* Update Kotlin docs and samples to align with adk-kotlin API changes (#30)

Rename GeminiModel to Gemini, @AdkTool/@AdkParam to @Tool/@Param,
adkTools() to generatedTools(), replace DebugRunner with InMemoryRunner,
fix AgentLoader import path, use SingleAgentLoader, bump Kotlin to
2.3.21 and KSP to 2.3.7, and update Android minSdk from 24 to 26.

* adding kotlin info to READMEs (#14)

* Reorganize Android sample agent and add READMEs (#31)

* Move Android sample agent

* Update repo README, add Android README, update sample agent README

* Minor edit to language support tags (#32)

* Remove blog post link (#33)

Will re-add after it's published

* Remove examples link (#34)

* Adding Kotlin snippets for Sessions docs (#26)

* initial kotlins snippets additions to sessions docs

* Updating memory docs with kotlin snippets

* Adding kotlin snippets to session state docs.

* update model to gemini-flash-latest

* sessions examples clean-up

* fixing sessions snippet markers

* adding kotlin session snippets to files to test

* adding callback to memory_example

* Fixing capital agent snippet  (#35)

Fixing file name
Updating adkTool > Tool
Updating GeminiModel > Gemini

* Adding kotlin snippets for tools docs (#36)

* adding function tool kotlin snippets

* adding function_tools snippets to files to test

* Adding kotlin snippets to observability docs (#37)

* initial kotlin observability updates

* adding observability snippets to file check (#38)

* Adding Kotlin snippets to Callbacks docs (#39)

*  kotlin callbacks snippets

* adding callbacks snippets to file check

* Align Kotlin and KSP versions with published 0.1.0 artifacts (#40)

* switch CLI entry points from InMemoryRunner to ReplRunner (#41)

* Switch CLI entry points from InMemoryRunner to ReplRunner

* Fix wording

* Update API reference docs for Kotlin, 2026-05-18 (#42)

* Remove ADK on Android note until published (#43)

* Update Kotlin code samples (#44)

* Rename GeminiModel to Gemini in Kotlin snippets and docs

* Remove broken SessionKey call and use sessionId directly in AgentTool snippet

* Rewrite Go hero snippet to use llmagent API

* Use isFinalResponse with safe access in CapitalAgent snippet

* Use Role.USER constant instead of raw string in SetupExample

* Use full semver v0.1.0 in Kotlin language support tags

* Remove Android setup steps, moving to new property (#45)

* Tutorial Kotlin agent (#46)

* Adding multi-tool-agent snippet and updating tutorial
* Fixing Go language order on tutorial page
* adding multi tool agent example to files to test

* Inline Kotlin get-started code sample

* Kotlin Multi agents snippets (#47)

* Multi-agent kotlin snippets

* Fixing docs tags in multiagent example

* Fix Kotlin language support tags, code samples, and google-gemini.md cleanup (#48)

* Add Kotlin v0.1.0 to language support tags across docs

* Fix MultiToolAgent.kt model string and argument style

* Update MultiAgentExample.kt to use gemini-flash-latest model string

* Fix google-gemini.md: add Kotlin sample, remove unsupported Java tabs

* Remove explicit apiKey from CallbackBasic.kt for consistency

* Standardize Gemini() constructor to use named args in all snippets

* Remove adk-samples directory (moved to google/adk-samples#1969)

* Remove adk-samples directory (moved to google/adk-samples#1969) (#49)

* Update API reference docs for ADK Kotlin 0.1.0 (#50)

* Remove adk-samples directory (moved to google/adk-samples#1969)

* Update API reference docs for ADK Kotlin 0.1.0

* Remove kotlin lycheeignore config (#51)

* Remove adk-samples directory (moved to google/adk-samples#1969)

* Remove Kotlin .lycheeignore config links

---------

Co-authored-by: Toni Klopfenstein <2359976+ToniCorinne@users.noreply.github.com>
Co-authored-by: Jolanda Verhoef <JolandaVerhoef@users.noreply.github.com>
2026-05-19 11:43:42 -05:00

22 KiB
Raw Permalink Blame History

Memory: Long-Term Knowledge with MemoryService

Supported in ADKPython v0.1.0Typescript v0.2.0Go v0.1.0Java v0.1.0Kotlin v0.1.0

We've seen how Session tracks the history (events) and temporary data (state) for a single, ongoing conversation. But what if an agent needs to recall information from past conversations? This is where the concept of Long-Term Knowledge and the MemoryService come into play.

Think of it this way:

  • Session / State: Like your short-term memory during one specific chat.
  • Long-Term Knowledge (MemoryService): Like a searchable archive or knowledge library the agent can consult, potentially containing information from many past chats or other sources.

The MemoryService Role

The BaseMemoryService (or Service in Go) defines the interface for managing this searchable, long-term knowledge store. It supports four operations:

  1. Ingesting a session (add_session_to_memory): Take the contents of a (usually completed) Session and add relevant information to the long-term knowledge store.
  2. Ingesting events incrementally (add_events_to_memory): Append a delta of events (e.g., the latest turn) without re-ingesting the full session. Useful when you want to write to memory partway through a long-running session.
  3. Writing memory items directly (add_memory): Insert pre-built MemoryEntry items, for services that support direct writes alongside event-based extraction.
  4. Searching (search_memory): Allow an agent (typically via a Tool) to query the knowledge store and retrieve relevant snippets based on a search query.

Operations 2 and 3 are optional — the base class implementations of add_events_to_memory and add_memory raise NotImplementedError, so check your concrete service before relying on them.

Choosing the Right Memory Service

The Python ADK ships three MemoryService implementations. Use the table below to decide which is the best fit for your agent.

Feature InMemoryMemoryService VertexAiMemoryBankService VertexAiRagMemoryService
Persistence None (data is lost on restart) Yes (Managed by Agent Platform) Yes (stored in Knowledge Engine)
Primary Use Case Prototyping, local development, and simple testing. Building meaningful, evolving memories from user conversations. Vector-search retrieval over the full conversation corpus, or alongside other RAG-indexed content.
Memory Extraction Stores full conversation Extracts meaningful information from conversations and consolidates it with existing memories (powered by LLM) Stores full conversation, indexed by Knowledge Engine.
Search Capability Basic keyword matching. Advanced semantic search. Vector similarity search over Knowledge Engine.
Setup Complexity None. It's the default. Low. Requires an Agent Runtime instance on Agent Platform. Medium. Requires Knowledge Engine.
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 documented in Memory Bank and RAG Memory below.

In-Memory Memory

The InMemoryMemoryService stores session information in the application's memory and performs basic keyword matching for searches. It requires no setup and is best for prototyping and simple testing scenarios where persistence isn't required.

=== "Python"

```py
from google.adk.memory import InMemoryMemoryService
memory_service = InMemoryMemoryService()
```

=== "TypeScript"

```typescript
import { InMemoryMemoryService } from '@google/adk';
const memoryService = new InMemoryMemoryService();
```

=== "Go" ```go import ( "google.golang.org/adk/memory" "google.golang.org/adk/session" )

// Services must be shared across runners to share state and memory.
sessionService := session.InMemoryService()
memoryService := memory.InMemoryService()
```

=== "Java" ```java import com.google.adk.memory.InMemoryMemoryService;

InMemoryMemoryService memoryService = new InMemoryMemoryService();
```

=== "Kotlin" kotlin --8<-- "examples/kotlin/snippets/sessions/MemoryExample.kt:instantiate_service"

Example: Adding and Searching Memory

This example demonstrates the basic flow using the InMemoryMemoryService for simplicity.

=== "Python"

```py
import asyncio
from google.adk.agents import LlmAgent
from google.adk.sessions import InMemorySessionService, Session
from google.adk.memory import InMemoryMemoryService # Import MemoryService
from google.adk.runners import Runner
from google.adk.tools import load_memory # Tool to query memory
from google.genai.types import Content, Part

# --- Constants ---
APP_NAME = "memory_example_app"
USER_ID = "mem_user"
MODEL = "gemini-flash-latest" # Use a valid model

# --- Agent Definitions ---
# Agent 1: Simple agent to capture information
info_capture_agent = LlmAgent(
    model=MODEL,
    name="InfoCaptureAgent",
    instruction="Acknowledge the user's statement.",
)

# Agent 2: Agent that can use memory
memory_recall_agent = LlmAgent(
    model=MODEL,
    name="MemoryRecallAgent",
    instruction="Answer the user's question. Use the 'load_memory' tool "
                "if the answer might be in past conversations.",
    tools=[load_memory] # Give the agent the tool
)

# --- Services ---
# Services must be shared across runners to share state and memory
session_service = InMemorySessionService()
memory_service = InMemoryMemoryService() # Use in-memory for demo

async def run_scenario():
    # --- Scenario ---

    # Turn 1: Capture some information in a session
    print("--- Turn 1: Capturing Information ---")
    runner1 = Runner(
        # Start with the info capture agent
        agent=info_capture_agent,
        app_name=APP_NAME,
        session_service=session_service,
        memory_service=memory_service # Provide the memory service to the Runner
    )
    session1_id = "session_info"
    await runner1.session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=session1_id)
    user_input1 = Content(parts=[Part(text="My favorite project is Project Alpha.")], role="user")

    # Run the agent
    final_response_text = "(No final response)"
    async for event in runner1.run_async(user_id=USER_ID, session_id=session1_id, new_message=user_input1):
        if event.is_final_response() and event.content and event.content.parts:
            final_response_text = event.content.parts[0].text
    print(f"Agent 1 Response: {final_response_text}")

    # Get the completed session
    completed_session1 = await runner1.session_service.get_session(app_name=APP_NAME, user_id=USER_ID, session_id=session1_id)

    # Add this session's content to the Memory Service
    print("\n--- Adding Session 1 to Memory ---")
    await memory_service.add_session_to_memory(completed_session1)
    print("Session added to memory.")

    # Turn 2: Recall the information in a new session
    print("\n--- Turn 2: Recalling Information ---")
    runner2 = Runner(
        # Use the second agent, which has the memory tool
        agent=memory_recall_agent,
        app_name=APP_NAME,
        session_service=session_service, # Reuse the same service
        memory_service=memory_service   # Reuse the same service
    )
    session2_id = "session_recall"
    await runner2.session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=session2_id)
    user_input2 = Content(parts=[Part(text="What is my favorite project?")], role="user")

    # Run the second agent
    final_response_text_2 = "(No final response)"
    async for event in runner2.run_async(user_id=USER_ID, session_id=session2_id, new_message=user_input2):
        if event.is_final_response() and event.content and event.content.parts:
            final_response_text_2 = event.content.parts[0].text
    print(f"Agent 2 Response: {final_response_text_2}")

# To run this example, you can use the following snippet:
# asyncio.run(run_scenario())

# await run_scenario()
```

=== "TypeScript"

```typescript
--8<-- "examples/typescript/snippets/sessions/memory_example.ts:full_example"
```

=== "Go"

```go
--8<-- "examples/go/snippets/sessions/memory_example/memory_example.go:full_example"
```

=== "Java"

```java
package com.google.adk.examples.sessions;
...
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/sessions/MemoryExample.kt:full_example"
```

Searching Memory Within a Tool

You can also search memory from within a custom tool by using the tool context.

=== "Python"

```python
from google.adk.tools import ToolContext

async def search_past_conversations(
    query: str, tool_context: ToolContext
) -> dict:
    response = await tool_context.search_memory(query)
    return {
        "results": [
            part.text
            for entry in response.memories
            for part in (entry.content.parts or [])
            if part.text
        ]
    }
```

=== "Go"

```go
--8<-- "examples/go/snippets/sessions/memory_example/memory_example.go:tool_search"
```

=== "TypeScript"

```typescript
// Within a tool implementation
async runAsync({ args, toolContext }: RunAsyncToolRequest) {
  const query = args['query'] as string;
  const response = await toolContext.searchMemory(query);
  // process response
  return {
    memories: response.memories.map(m => m.content.parts?.map(p => p.text).join(' ')).join('\n')
  };
}
```

=== "Java"

```java
// Within a tool implementation
public Single<ToolOutput> execute(ToolContext context) {
  String query = ...; // get query from arguments
  return context.searchMemory(query)
      .map(response -> {
          // process response
          return new ToolOutput(response.memories().toString());
      });
}
```

=== "Kotlin"

```kotlin
--8<-- "examples/kotlin/snippets/sessions/MemoryExample.kt:search_within_tool"
```

Memory Bank

The VertexAiMemoryBankService connects your agent to Memory Bank, a fully managed Google Cloud service that provides sophisticated, persistent memory capabilities for conversational agents.

How It Works

The service handles two key operations:

  • Generating Memories: At the end of a conversation, you can send the session's events to the Memory Bank, which intelligently processes and stores the information as "memories."
  • Retrieving Memories: Your agent code can issue a search query against the Memory Bank to retrieve relevant memories from past conversations.

Prerequisites

Before you can use this feature, you must have:

  1. A Google Cloud Project: With the Agent Platform API enabled.
  2. An Agent Runtime: You need to create an Agent Runtime on Agent Platform. You do not need to deploy your agent to Agent Runtime to use Memory Bank. This will provide you with the Agent Runtime ID required for configuration.
  3. Authentication: Ensure your local environment is authenticated to access Google Cloud services. The simplest way is to run:
    gcloud auth application-default login
    
  4. Environment Variables: The service requires your Google Cloud Project ID and Location. Set them as environment variables:
    export GOOGLE_CLOUD_PROJECT="your-gcp-project-id"
    export GOOGLE_CLOUD_LOCATION="your-gcp-location"
    

Configuration

To connect your agent to the Memory Bank, you use the --memory_service_uri flag when starting the ADK server (adk web or adk api_server). The URI must be in the format agentengine://<agent_engine_id>.

adk web path/to/your/agents_dir --memory_service_uri="agentengine://1234567890"

Or, you can configure your agent to use the Memory Bank by manually instantiating the VertexAiMemoryBankService and passing it to the Runner.

=== "Python"

from google import adk
from google.adk.memory import VertexAiMemoryBankService

agent_engine_id = agent_engine.api_resource.name.split("/")[-1]

memory_service = VertexAiMemoryBankService(
    project="PROJECT_ID",
    location="LOCATION",
    agent_engine_id=agent_engine_id
)

runner = adk.Runner(
    ...
    memory_service=memory_service
)

RAG Memory

The VertexAiRagMemoryService stores conversations in Knowledge Engine and retrieves them by vector similarity. Use it when you already have RAG infrastructure or want raw transcript retrieval rather than the LLM-extracted memories produced by Memory Bank. Requires the Agent Platform SDK.

=== "Python"

```py
from google.adk.memory import VertexAiRagMemoryService

memory_service = VertexAiRagMemoryService(
    rag_corpus="projects/PROJECT_ID/locations/LOCATION/ragCorpora/CORPUS_ID",
    similarity_top_k=5,
    vector_distance_threshold=0.6,
)
```

Using Memory in Your Agent

When a memory service is configured, your agent can use a tool or callback to retrieve memories. ADK includes two pre-built tools for retrieving memories:

  • PreloadMemory: Always retrieve memory at the beginning of each turn (similar to a callback).
  • LoadMemory: Retrieve memory when your agent decides it would be helpful.

Example:

=== "Python" ```python from google.adk.agents import Agent from google.adk.tools.preload_memory_tool import PreloadMemoryTool

agent = Agent(
    model=MODEL_ID,
    name='weather_sentiment_agent',
    instruction="...",
    tools=[PreloadMemoryTool()]
)
```

=== "TypeScript" ```typescript import { LlmAgent, PRELOAD_MEMORY } from '@google/adk';

const agent = new LlmAgent({
    model: MODEL_ID,
    name: 'weather_sentiment_agent',
    instruction: "...",
    tools: [PRELOAD_MEMORY]
});
```

=== "Go" ```go import ( "google.golang.org/adk/agent/llmagent" "google.golang.org/adk/tool" "google.golang.org/adk/tool/preloadmemorytool" )

agent, _ := llmagent.New(llmagent.Config{
    Model:       model,
    Name:        "weather_sentiment_agent",
    Instruction: "...",
    Tools:       []tool.Tool{preloadmemorytool.New()},
})
```

=== "Java" ```java import com.google.adk.agents.LlmAgent; import com.google.adk.tools.LoadMemoryTool;

LlmAgent agent = new LlmAgent.Builder()
    .model(MODEL_ID)
    .name("weather_sentiment_agent")
    .instruction("...")
    .tools(new LoadMemoryTool())
    .build();
```

=== "Kotlin" kotlin --8<-- "examples/kotlin/snippets/sessions/MemoryExample.kt:preload_memory_agent"

To extract memories from your session, you need to call add_session_to_memory. For example, you can automate this via a callback:

=== "Python" ```python from google.adk.agents import Agent from google import adk

async def auto_save_session_to_memory_callback(callback_context):
    await callback_context.add_session_to_memory()

agent = Agent(
    model=MODEL,
    name="Generic_QA_Agent",
    instruction="Answer the user's questions",
    tools=[adk.tools.preload_memory_tool.PreloadMemoryTool()],
    after_agent_callback=auto_save_session_to_memory_callback,
)
```

=== "TypeScript" ```typescript import { LlmAgent, PRELOAD_MEMORY, SingleAgentCallback } from '@google/adk';

const autoSaveSessionToMemoryCallback: SingleAgentCallback = async (callbackContext) => {
    if (callbackContext.invocationContext.memoryService) {
        await callbackContext.invocationContext.memoryService.addSessionToMemory(
            callbackContext.invocationContext.session
        );
    }
};

const agent = new LlmAgent({
    model: MODEL,
    name: "Generic_QA_Agent",
    instruction: "Answer the user's questions",
    tools: [PRELOAD_MEMORY],
    afterAgentCallback: autoSaveSessionToMemoryCallback,
});
```

=== "Go" ```go import ( "context" "google.golang.org/adk/agent" "google.golang.org/adk/agent/llmagent" "google.golang.org/adk/session" "google.golang.org/adk/tool" "google.golang.org/adk/tool/loadmemorytool" )

func autoSaveSessionToMemoryCallback(ctx agent.CallbackContext, s session.Session) (*genai.Content, error) {
    if err := ctx.Memory().AddSessionToMemory(context.Background(), s); err != nil {
        return nil, err
    }
    return nil, nil
}

agent, _ := llmagent.New(llmagent.Config{
    Model:               model,
    Name:                "Generic_QA_Agent",
    Instruction:         "Answer the user's questions",
    Tools:               []tool.Tool{loadmemorytool.New()},
    AfterAgentCallbacks: []agent.AfterAgentCallback{autoSaveSessionToMemoryCallback},
})
```

=== "Kotlin" kotlin --8<-- "examples/kotlin/snippets/sessions/MemoryExample.kt:auto_save_callback"

Advanced Concepts

How Memory Works in Practice

The memory workflow internally involves these steps:

  1. Session Interaction: A user interacts with an agent via a Session, managed by a SessionService. Events are added, and state might be updated.
  2. Ingestion into Memory: At some point (often when a session is considered complete or has yielded significant information), your application calls memory_service.add_session_to_memory(session). This extracts relevant information from the session's events and adds it to the long-term knowledge store (in-memory dictionary or Agent Runtime Memory Bank).
  3. Later Query: In a different (or the same) session, the user might ask a question requiring past context (e.g., "What did we discuss about project X last week?").
  4. Agent Uses Memory Tool: An agent equipped with a memory-retrieval tool (like the built-in load_memory tool) recognizes the need for past context. It calls the tool, providing a search query (e.g., "discussion project X last week").
  5. Search Execution: The tool internally calls memory_service.search_memory(app_name=..., user_id=..., query=...).
  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, optional author, optional timestamp, and optional 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 retrieved information to formulate its final answer to the user.

Can an agent have access to more than one memory service?

  • Through Standard Configuration: No. The framework (adk web, adk api_server) is designed to be configured with one memory service at a time via the --memory_service_uri flag. That single service is wired into the runner and exposed through tool_context.search_memory() and callback_context.search_memory().

  • Within Your Agent's Code: Yes. Nothing stops you from importing and instantiating a second BaseMemoryService directly. The cleanest place to consult it is from a custom tool, which already has a ToolContext for the framework-configured service.

For example, your agent can use the framework-configured InMemoryMemoryService for conversation history and manually instantiate a second service (a VertexAiMemoryBankService, a VertexAiRagMemoryService over a docs corpus, or any other BaseMemoryService implementation) for a separate knowledge base.

Example: Using Two Memory Services

=== "Python" ```python from google.adk.agents import Agent from google.adk.memory import InMemoryMemoryService from google.adk.tools import ToolContext

# Second memory service for docs lookup; could be any BaseMemoryService.
docs_memory = InMemoryMemoryService()


async def search_all_memory(query: str, tool_context: ToolContext) -> dict:
    """Search both the conversational memory and the docs corpus."""
    conversational = await tool_context.search_memory(query)
    docs = await docs_memory.search_memory(
        app_name="docs", user_id="shared", query=query
    )
    return {
        "from_conversations": [
            part.text
            for entry in conversational.memories
            for part in (entry.content.parts or [])
            if part.text
        ],
        "from_docs": [
            part.text
            for entry in docs.memories
            for part in (entry.content.parts or [])
            if part.text
        ],
    }


agent = Agent(
    model="gemini-flash-latest",
    name="multi_memory_agent",
    instruction=(
        "Answer questions using both your conversation history and the "
        "docs knowledge base. Use the search_all_memory tool."
    ),
    tools=[search_all_memory],
)
```