Skip to main content

Guide: Add Google ADK Memory with Hindsight

· 6 min read
Ben Bartholomew
Hindsight Team

Guide: Add Google ADK Memory with Hindsight

If you want Google ADK memory with Hindsight, the cleanest setup is the hindsight-google-adk package. It implements ADK's BaseMemoryService, so you pass it to Runner(memory_service=...) and sessions are retained automatically when they end, while agents that call search_memory get matching results back from Hindsight. That gives ADK agents long-term memory across sessions instead of starting cold every time.

This fits ADK because ADK already has a memory service interface built in. Rather than bolting memory on from the outside, the integration plugs Hindsight directly into that interface. Memory is scoped per (app_name, user_id) by default, so each app and user gets its own isolated bank.

If you want the agent to decide when to store or recall mid-turn instead of relying on automatic session retention, the package also ships explicit FunctionTool wrappers. This guide covers both patterns, plus a quick verification flow. Keep the docs home and the quickstart guide nearby while you work.

Quick answer

  1. pip install hindsight-google-adk.
  2. Create HindsightMemoryService.from_url(hindsight_api_url=..., api_key="hsk_...").
  3. Pass it to Runner(memory_service=memory) — sessions retain automatically on end.
  4. Agents calling search_memory recall from the same bank, keyed by (app_name, user_id).
  5. Verify that a later session recalls what an earlier one stored.

Prerequisites

Before you start, make sure you have:

  • Python 3.10+
  • google-adk>=2.0 installed and a working ADK agent
  • A reachable Hindsight backend, Hindsight Cloud or a self-hosted server

Step 1: Install the package

pip install hindsight-google-adk

This pulls in hindsight-client>=0.4.0, which the integration uses to talk to your Hindsight backend.

Step 2: Wire up the memory service

The main pattern implements ADK's BaseMemoryService. Construct it with from_url and pass it to Runner:

import asyncio
from google.adk.agents import LlmAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService

from hindsight_google_adk import HindsightMemoryService

memory = HindsightMemoryService.from_url(
hindsight_api_url="https://api.hindsight.vectorize.io",
api_key="hsk_...",
)

agent = LlmAgent(name="assistant", model="gemini-2.0-flash")

runner = Runner(
app_name="my-app",
agent=agent,
session_service=InMemorySessionService(),
memory_service=memory,
)

# ... use runner.run_async(...) as normal. Memory is automatic.

For a self-hosted Hindsight server, point at your own URL and drop the API key:

HindsightMemoryService.from_url(hindsight_api_url="http://localhost:8888")

No api_key is needed for unauthenticated local servers.

How the memory service uses memory

The integration hooks into the two points ADK's memory service interface exposes:

  • Retain (on session end): when a session ends, Runner calls add_session_to_memory, which retains all of the session's events to a Hindsight bank keyed by (app_name, user_id).
  • Recall (on search): when the agent — or any other call — invokes search_memory(app_name, user_id, query), the integration runs a Hindsight recall against the same bank and returns the results as ADK MemoryEntry objects.

Failures are resilient: Hindsight errors in the add_* and search_memory methods are logged but never propagate to the Runner, so memory problems don't crash the agent.

For lower-level behavior, read Hindsight's recall API and Hindsight's retain API.

Per-user memory banks

By default, each (app_name, user_id) pair gets its own bank: "{app_name}::{user_id}". That keeps one user's memory isolated from another's. Override the scheme with bank_id_template:

# Per-user bank, shared across apps
HindsightMemoryService.from_url(
hindsight_api_url="https://api.hindsight.vectorize.io",
api_key="hsk_...",
bank_id_template="user::{user_id}",
)

# Static bank, shared across all users
HindsightMemoryService.from_url(
hindsight_api_url="https://api.hindsight.vectorize.io",
api_key="hsk_...",
bank_id_template="my-shared-bank",
)

Every retained event also carries app:<app_name> and user:<user_id> tags, and recall queries automatically include user:<user_id>, so users never see each other's memories.

Optional: explicit retain / recall / reflect tools

If you want the model to decide when to store or recall mid-turn, add the explicit tools instead of (or alongside) the memory service:

from google.adk.agents import LlmAgent
from hindsight_google_adk import create_hindsight_tools

tools = create_hindsight_tools(
bank_id="user-123",
hindsight_api_url="https://api.hindsight.vectorize.io",
api_key="hsk_...",
)

agent = LlmAgent(name="assistant", model="gemini-2.0-flash", tools=tools)

The agent gets three tools (toggle with include_retain / include_recall / include_reflect):

  • hindsight_retain(content) — store information to long-term memory
  • hindsight_recall(query) — search memory and return matches
  • hindsight_reflect(query) — synthesize a coherent answer from memory

You can use both patterns at once — the memory service for automatic retention on session end, and the tools for agent-driven recall mid-turn. They share a bank when the bank ids align.

Verify that memory is working

A good test sequence is:

  1. run an agent turn under a Runner with the HindsightMemoryService attached
  2. let the agent record a decision, fact, or preference
  3. end the session so its events are retained
  4. start a new session with the same app_name and user_id
  5. ask about the earlier detail so the agent calls search_memory

If the recalled results surface the earlier detail, the setup is working.

Common mistakes

Changing app_name or user_id between sessions

The bank is derived from (app_name, user_id) by default. If either value changes, the new session reads a different bank and won't see the earlier memory.

Testing retain too early

Session events are retained when the session ends. If you check before the session completes, the content may not have been stored yet.

Assuming memory is global

By default each (app_name, user_id) pair gets its own bank. That is usually what you want, but do not expect one user to recall another user's context unless you set a shared bank_id_template.

Passing an API key to a local server

Hindsight Cloud needs an api_key. A self-hosted, unauthenticated server does not — just set hindsight_api_url to your local URL.

FAQ

Do I need Hindsight Cloud?

No. A self-hosted Hindsight server works too — pass its URL to hindsight_api_url and omit api_key.

Do I have to use the explicit tools?

No. The HindsightMemoryService handles retain-on-session-end and recall-on-search_memory automatically. The FunctionTool wrappers are optional, for when you want the agent to control memory mid-turn.

How is memory scoped?

Per (app_name, user_id) by default, using the template "{app_name}::{user_id}". Override it with bank_id_template.

Can I set app-wide defaults once?

Yes. Call configure(...) at startup and later HindsightMemoryService.from_url() / create_hindsight_tools() calls use it as a fallback.

Next Steps