Google ADK plugin for MemEngine persistent memory layer
Project description
memengine-adk
Google ADK plugin and tools for MemEngine — a standalone persistent memory layer for AI agents.
What is this?
memengine-adk integrates MemEngine into Google ADK agents, giving them persistent long-term memory across sessions without changing your agent logic.
MemEngine runs as a separate HTTP service. This package is the ADK-side adapter.
Requirements
- Python 3.10+
google-adk >= 0.1.0- A running MemEngine instance
Installation
pip install memengine-adk
Start MemEngine before running your agent:
uvicorn memengine.main:app --host 0.0.0.0 --port 8001
Admin UI: http://localhost:8001/admin
Integration Approaches
| Approach | Memory happens | Agent changes needed | Best for |
|---|---|---|---|
| Plugin | Every turn, automatically | None | Production chatbots, assistants |
| Tools | When agent decides | Add tool descriptions | Autonomous agents |
| Callbacks | You control everything | Full custom integration | Advanced use cases |
Approach 1: Plugin (Recommended)
The plugin hooks into ADK's Runner and handles all memory reads and writes automatically.
from google.adk.agents import LlmAgent
from google.adk.runners import InMemoryRunner
from memengine_adk import MemEnginePlugin
plugin = MemEnginePlugin(
base_url="http://localhost:8001",
user_id="user_001", # stable user identifier
agent_id="my_assistant", # memory namespace
top_k=5, # memories to inject per turn
)
agent = LlmAgent(
name="my_agent",
model="gemini-2.0-flash",
instruction="You are a helpful personal assistant.",
)
runner = InMemoryRunner(
agent=agent,
app_name="my_app",
plugins=[plugin],
)
async for event in runner.run_async(
user_id="user_001",
session_id="session_abc",
new_message="My name is Alice and I prefer dark mode.",
):
if event.is_final_response():
print(event.content.parts[0].text)
How the plugin works
| Callback | When it runs | What it does |
|---|---|---|
on_user_message_callback |
User sends a message | Enqueues async long-term memory write evaluation |
before_model_callback |
Before each LLM call | Calls /memory/process, injects system_prompt |
after_model_callback |
After each LLM reply | Caches assistant reply for next turn's write evaluation |
MemEnginePlugin parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
base_url |
str | http://localhost:8001 |
MemEngine service URL |
user_id |
str | default_user |
Stable user identifier |
agent_id |
str | adk_agent |
Memory namespace — different agent_ids are fully isolated |
top_k |
int | 5 |
Max long-term memories injected per turn |
enabled |
bool | True |
Set False to disable without removing the plugin |
Approach 2: Tools (Explicit Agent Control)
Exposes memory as ADK FunctionTools. The agent decides when to save and fetch.
from google.adk.agents import LlmAgent
from google.adk.runners import InMemoryRunner
from memengine_adk import MemEngineSaveTool, MemEngineFetchTool
save_tool = MemEngineSaveTool(
base_url="http://localhost:8001",
user_id="user_001",
agent_id="my_assistant",
)
fetch_tool = MemEngineFetchTool(
base_url="http://localhost:8001",
user_id="user_001",
agent_id="my_assistant",
)
agent = LlmAgent(
name="my_agent",
model="gemini-2.0-flash",
instruction="""You are a helpful personal assistant with persistent memory.
Use fetch_memories at the start of conversations to recall what you know about the user.
Use save_memory when the user shares something important (name, preferences, decisions).""",
tools=[save_tool, fetch_tool],
)
runner = InMemoryRunner(agent=agent, app_name="my_app")
Available tools
save_memory(content, chat_id)
Save important information to long-term memory. Use when the user shares something worth remembering across future conversations.
fetch_memories(query, limit)
Retrieve stored memories. Supports optional keyword filter. Returns up to limit records (default 10).
Approach 3: Callbacks (Manual Integration)
Use MemEngineClient directly for full control in custom runners or non-standard ADK setups.
from memengine_adk import MemEngineClient
client = MemEngineClient(base_url="http://localhost:8001")
# Before LLM call — get enriched system_prompt
result = await client.process(
user_id="user_001",
agent_id="my_assistant",
chat_id="session_abc",
user_input=user_message,
assistant_output=last_reply,
)
system_prompt = result["system_prompt"]
# List memories
memories = await client.list_memories(user_id="user_001", agent_id="my_assistant")
for m in memories:
print(m.content, m.score)
await client.aclose()
MemEngineClient methods
| Method | Description |
|---|---|
process(user_id, agent_id, chat_id, user_input, assistant_output) |
Process a turn, returns system_prompt and long_term_written |
list_memories(user_id, agent_id, limit, q) |
List long-term memories with optional keyword filter |
aclose() |
Close the underlying HTTP client |
Environment Variables
All constructor parameters can be set via environment variables for convenience:
export MEMENGINE_URL=http://localhost:8001
export MEMENGINE_USER_ID=user_001
export MEMENGINE_AGENT_ID=my_assistant
import os
plugin = MemEnginePlugin(
base_url=os.getenv("MEMENGINE_URL", "http://localhost:8001"),
user_id=os.getenv("MEMENGINE_USER_ID", "default_user"),
agent_id=os.getenv("MEMENGINE_AGENT_ID", "adk_agent"),
)
Running the Examples
cd sdk/memengine-adk
# Plugin demo (automatic memory)
python -m examples.plugin_demo.agent
# Tools demo (agent-controlled memory)
python -m examples.tools_demo.agent
Both examples read MEMENGINE_URL, MEMENGINE_USER_ID, MEMENGINE_AGENT_ID from environment.
Memory Concepts
agent_id is the namespace. Memories are scoped by (user_id, agent_id). Two agents with different agent_id values have completely separate memory spaces for the same user.
Long-term writes are async. When long_term_written > 0, it means the turn was enqueued for memory extraction — not instantly persisted. The MemEngine background worker processes it shortly after.
system_prompt replaces your static instruction. The value returned by /memory/process already includes your agent's configured base instruction plus short-term context and long-term memories. If you use the Plugin, this is injected automatically.
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file memengine_adk-0.1.0.tar.gz.
File metadata
- Download URL: memengine_adk-0.1.0.tar.gz
- Upload date:
- Size: 7.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f5e696599a68e17fb06466d35ac1401ab4cb50bdf85acb3dbdc9fe2ed1372a7
|
|
| MD5 |
3d4680aa99d9431acb7e7d01ab17a204
|
|
| BLAKE2b-256 |
7d2758df97d811ff7bf8d13cd42c7e6f5a4ad52b69cb59f02f6b49eba71d57b7
|
File details
Details for the file memengine_adk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: memengine_adk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42cfbaf2296e0a120e2aa5ece1007a8aacfdfc7279da10df4c0d410106e867c0
|
|
| MD5 |
2914a4767bffb8feb36bbc60b7ff2801
|
|
| BLAKE2b-256 |
d3d445ae17ae19b728795cd2ee60ff361314df8584a4bf0b8353a40977f19c71
|