Loading docs…
We're open source. If actrone-memory has been useful to you, a star on GitHub means a lot to us.
Star the projectLoading docs…
Python (actrone-memory) ships 16 drop-in adapters (LangChain, LangGraph, CrewAI, AutoGen, LlamaIndex, Haystack, DSPy, Agno, AWS Strands, Claude Agent SDK, Google ADK, Microsoft Agent Framework, OpenAI Agents SDK, Pydantic AI, Semantic Kernel, and smolagents), each connecting the same two-tier store to the framework, through its own memory interface where it has a stable one and as ready-to-use context otherwise. TypeScript (actrone-memory) ships a framework-agnostic recall/remember core plus 11 named framework adapters, including Vercel AI SDK, LangChain.js, LangGraph.js, and Mastra.
The adapters ship with actrone-memory in both languages: in Python as installable extras, in TypeScript in the actrone-memory/adapters entry point:
| Setup | Package | Import path |
|---|---|---|
| Python: self-hosted (Redis + Qdrant) | actrone-memory | actrone_memory.integrations.* |
| TypeScript: self-hosted | actrone-memory | actrone-memory/adapters |
Note
actrone-memory. TypeScript takes a related but lighter approach: one framework-agnostic recall/remember core (memoryFor) plus 11 named framework wrappers built on it, all in actrone-memory/adapters with no separate install extras: see TypeScript adapters.pip install "actrone-memory[langchain]"from actrone_memory.integrations.langchain import ActroneChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
history = ActroneChatMessageHistory(agent_id="support-bot", session_id="user-session-42")
# `runnable` is your prompt | model chain; its prompt has a MessagesPlaceholder("history")
chain = RunnableWithMessageHistory(
runnable,
lambda session_id: history,
input_messages_key="input",
history_messages_key="history",
)
response = await chain.ainvoke(
{"input": "What did we discuss last time?"},
config={"configurable": {"session_id": "user-session-42"}},
)ActroneChatMessageHistory implements LangChain's BaseChatMessageHistory, which is the same in LangChain 0.x and 1.x: LangChain loads the history before each call and appends the new messages after. On LangChain 0.x only, the older ActroneMemory (a BaseMemory) also works with ConversationChain; LangChain 1.x removed both.
pip install "actrone-memory[langgraph]"from actrone_memory.integrations.langgraph import ActroneCheckpointer
from langgraph.graph import StateGraph, MessagesState
checkpointer = ActroneCheckpointer(agent_id="research-agent")
graph = StateGraph(MessagesState)
# ... add nodes and edges ...
compiled = graph.compile(checkpointer=checkpointer)
# Memory is automatically persisted across invocations
result = await compiled.ainvoke(
{"messages": [{"role": "user", "content": "What's the status?"}]},
config={"configurable": {"thread_id": "thread-42"}},
)Note
thread_id in the config dict to identify sessions: this maps to session_id in the memory store.pip install "actrone-memory[crewai]"from actrone_memory.integrations.crewai import ActroneCrewMemory
from crewai import Agent, Crew, Task
memory = ActroneCrewMemory(agent_id="research-crew", session_id="q4-review")
researcher = Agent(role="Senior Researcher", goal="Find accurate information",
backstory="Expert at analysing data")
# Recall what the crew learned before, and put it in the task itself
context = await memory.build_context("Q4 earnings")
task = Task(description=f"{context}\n\nSummarise Q4 earnings.", agent=researcher,
expected_output="A short summary")
result = Crew(agents=[researcher], tasks=[task]).kickoff()
# Store what the crew concluded, for the next run
await memory.save(result.raw, {"task_input": "Summarise Q4 earnings."})The adapter feeds memory into the task text rather than replacing CrewAI's own memory storage, so it works the same across CrewAI versions. search() returns the most relevant stored memories if you would rather format them yourself.
pip install "actrone-memory[autogen]"from actrone_memory.integrations.autogen import ActroneAutoGenMemory
from autogen_agentchat.agents import AssistantAgent
memory = ActroneAutoGenMemory(
agent_id="research-agent",
session_id="session-1",
token_budget=4096,
)
agent = AssistantAgent(
name="researcher",
model_client=model_client,
memory=[memory], # pass as a list: AutoGen supports multiple memory backends
)
# Relevant memories are injected before each model call
await agent.run(task="Summarise Apple Q4 earnings")The adapter implements the autogen_core.memory.Memory protocol. AutoGen calls update_context() before each model call, which injects the relevant memories as a system message. Storing is up to you: call await memory.add(...) with the content worth keeping, and query() to search directly.
pip install "actrone-memory[llamaindex]"
pip install llama-index-llms-openai # the OpenAI LLM used belowfrom actrone_memory.integrations.llamaindex import ActroneLlamaMemory
from llama_index.core.chat_engine import SimpleChatEngine
from llama_index.llms.openai import OpenAI
memory = ActroneLlamaMemory(
agent_id="research-agent",
session_id="session-1",
token_budget=4096,
)
engine = SimpleChatEngine.from_defaults(
llm=OpenAI(model="gpt-4o"),
memory=memory,
)
# Sync usage (works in Jupyter and scripts)
response = engine.chat("What did we discuss earlier?")
# Async usage
response = await engine.achat("What did we discuss earlier?")Tip
get() / put() interface alongside the async variants. The adapter handles the event-loop bridging automatically. You can use either form depending on your application context.pip install "actrone-memory[haystack]"Two components are available, a retriever for RAG pipelines and a writer for persisting conversation turns:
from actrone_memory.integrations.haystack import ActroneRetriever, ActroneWriter
from haystack import Pipeline
# Retrieval: returns memories as Haystack Documents
retriever = ActroneRetriever(agent_id="research-agent", top_k=10)
result = retriever.run(query="Apple Q4 earnings")
# result["documents"]: list of Document objects with content + meta
# In a pipeline, feed the documents to your prompt builder
pipeline = Pipeline()
pipeline.add_component("memory", retriever)
pipeline.add_component("prompt_builder", your_prompt_builder) # takes a `documents` input
pipeline.add_component("llm", your_llm_component)
pipeline.connect("memory.documents", "prompt_builder.documents")
pipeline.connect("prompt_builder", "llm")
# After the pipeline answers, persist the turn with the writer
writer = ActroneWriter(agent_id="research-agent", session_id="session-1")
writer.run(user_message="What was Apple's revenue?", assistant_message=reply_text)Tip
replies list.pip install "actrone-memory[dspy]"from actrone_memory.integrations.dspy import ActroneRM
import dspy
# Register as the global retriever
rm = ActroneRM(agent_id="research-agent", k=10)
dspy.settings.configure(rm=rm)
# Or use directly inside a DSPy Module
class RAGModule(dspy.Module):
def __init__(self):
super().__init__()
self.retrieve = ActroneRM(agent_id="research-agent", k=5)
self.generate = dspy.ChainOfThought("context, question -> answer")
def forward(self, question: str) -> dspy.Prediction:
context = self.retrieve(question).passages
return self.generate(context=context, question=question)
# After inference, persist the turn to keep memory current
await rm.store_turn(
agent_id="research-agent",
session_id="session-1",
user_message=question,
assistant_message=result.answer,
)The forward() method accepts a single string or a list of strings and returns a dspy.Prediction with a passages attribute, a flat list of content strings, interleaved across queries when multiple are given.
pip install "actrone-memory[agno]"from actrone_memory import MemoryManager
from actrone_memory.integrations.agno import ActroneAgnoMemory
mm = await MemoryManager.create()
memory = ActroneAgnoMemory("support-bot", "s1", memory_manager=mm)
context = await memory.additional_context("how do escalations work")
# agent = Agent(model=model, additional_context=context); await agent.arun(user_input)
await memory.remember("how do escalations work?", "they page the on-call engineer")pip install "actrone-memory[strands]"from actrone_memory import MemoryManager
from actrone_memory.integrations.aws_strands import ActroneStrandsMemory
mm = await MemoryManager.create()
memory = ActroneStrandsMemory("support-bot", "s1", memory_manager=mm)
system_prompt = await memory.system_prompt("You are support.", "friday deploy freeze")
# agent = Agent(model=model, system_prompt=system_prompt); agent(user_input)
await memory.remember("can we deploy friday?", "no, prod deploys are frozen on fridays")Tip
strands (matching the strands-agents package name) even though the import path is actrone_memory.integrations.aws_strands.pip install "actrone-memory[claude_agent_sdk]"from actrone_memory import MemoryManager
from actrone_memory.integrations.claude_agent_sdk import ActroneClaudeAgentMemory
mm = await MemoryManager.create()
memory = ActroneClaudeAgentMemory("support-bot", "s1", memory_manager=mm)
system_prompt = await memory.append_to_system_prompt("You are support.", "refunds policy")
# query(prompt=user_input, options=ClaudeAgentOptions(system_prompt=system_prompt))
await memory.remember("refund policy?", "manager approval over 500")pip install "actrone-memory[google_adk]"from actrone_memory import MemoryManager
from actrone_memory.integrations.google_adk import ActroneGoogleADKMemory
mm = await MemoryManager.create()
memory = ActroneGoogleADKMemory("support-bot", "s1", memory_manager=mm)
# Tier 2: Runner(agent=agent, app_name="support", memory_service=memory.as_memory_service())
context = await memory.build_context("index rebuild schedule") # Tier 1
await memory.remember("when does the index rebuild?", "nightly at 2am")Tip
build_context) for any ADK agent, or a Tier 2 as_memory_service() that plugs directly into ADK's Runner.pip install "actrone-memory[microsoft_agent_framework]"from actrone_memory import MemoryManager
from actrone_memory.integrations.microsoft_agent_framework import ActroneAgentFrameworkMemory
mm = await MemoryManager.create()
memory = ActroneAgentFrameworkMemory("support-bot", "s1", memory_manager=mm)
# Tier 2: ChatAgent(chat_client=client, context_providers=[memory.as_context_provider()])
context = await memory.build_context("who is the account owner") # Tier 1
await memory.remember("account owner?", "Jane Doe")pip install "actrone-memory[openai_agents]"from actrone_memory import MemoryManager
from actrone_memory.integrations.openai_agents import ActroneOpenAIAgentsMemory
mm = await MemoryManager.create()
memory = ActroneOpenAIAgentsMemory("support-bot", "s1", memory_manager=mm)
instructions = await memory.instructions_for("You are support.", "enterprise plan")
# Runner.run(Agent(name="support", instructions=instructions), user_input)
await memory.remember("what plan?", "enterprise")pip install "actrone-memory[pydantic_ai]"from actrone_memory import MemoryManager
from actrone_memory.integrations.pydantic_ai import ActronePydanticAIMemory
mm = await MemoryManager.create()
memory = ActronePydanticAIMemory("support-bot", "s1", memory_manager=mm)
system_prompt = await memory.system_prompt("deployment approvals")
# register system_prompt via @agent.system_prompt (dynamic), then agent.run(user_input)
await memory.remember("how many approvals?", "two")pip install "actrone-memory[semantic_kernel]"from actrone_memory import MemoryManager
from actrone_memory.integrations.semantic_kernel import ActroneSemanticKernelMemory
mm = await MemoryManager.create()
memory = ActroneSemanticKernelMemory("support-bot", "s1", memory_manager=mm)
# Tier 1: a system-message string; or Tier 2: memory.add_to_chat_history(history, query)
system = await memory.system_message("ticket sla")
await memory.remember("what is the sla?", "24 hours")pip install "actrone-memory[smolagents]"from actrone_memory import MemoryManager
from actrone_memory.integrations.smolagents import ActroneSmolagentsMemory
mm = await MemoryManager.create()
memory = ActroneSmolagentsMemory("support-bot", "s1", memory_manager=mm)
user_input = "what is the build server named?"
task = await memory.task_context(user_input) + user_input
# result = agent.run(task)
await memory.remember(user_input, "atlas")The TypeScript library exposes one small, framework-agnostic surface in actrone-memory/adapters. memoryFor(mm, agentId, sessionId) binds a manager to a conversation and returns recall / remember (plus search / inject). Anything that accepts a system string works, no framework-specific packages required, and this is the base every named adapter below is built on.
import { MemoryManager } from "actrone-memory"
import { memoryFor } from "actrone-memory/adapters"
const mm = await MemoryManager.create()
const memory = memoryFor(mm, "support-bot", "user-session-42")
// Before the model call: retrieve a ready-to-prepend system string
const { systemPrompt } = await memory.recall("what did we discuss last time?", 4096)
// ... call your LLM with systemPrompt prepended ...
// After the model call: persist the completed turn
await memory.remember("what did we discuss last time?", assistantReply)Every named adapter below follows the same shape: memoryFor underneath, one method that returns a system-context string or message (the exact name matches the framework's own vocabulary), and a remember / saveTurn to persist the exchange. None of them are separate install extras. They're structural against an optional peer dependency, so just import the one you need.
import { MemoryManager } from 'actrone-memory'
import { vercelMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const prompt = 'summarise the account status'
const mem = await vercelMemory(mm, { agentId: 'support-bot', sessionId: 'session-1', query: prompt })
// streamText: pass mem.onFinish, and the turn is saved when the stream completes
const stream = streamText({ model, system: mem.system, prompt, onFinish: mem.onFinish(prompt) })
// generateText has no onFinish option, so save the turn yourself
const { text } = await generateText({ model, system: mem.system, prompt })
await mem.onFinish(prompt)({ text })import { MemoryManager } from 'actrone-memory'
import { langchainMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = langchainMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const context = await memory.loadContext('account standing') // prepend to your prompt
await memory.saveTurn('what is my account standing?', 'in good standing')import { MemoryManager } from 'actrone-memory'
import { langgraphMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = langgraphMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
// pre-model node: merge recalled memory into state.messages
const sys = await memory.loadMemories('what does the customer prefer?')
// post-model node: persist the completed turn
await memory.saveTurn('what does the customer prefer?', 'email over phone')import { MemoryManager } from 'actrone-memory'
import { mastraMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = mastraMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const system = await memory.getSystemContext('ticket SLA')
// ...agent.generate({ ...context, system })...
await memory.remember('what is the ticket SLA?', '24 hours')import { MemoryManager } from 'actrone-memory'
import { llamaindexMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = llamaindexMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const systemPrompt = await memory.getSystemPrompt('index rebuild schedule')
// ...agent.chat({ message: userInput, systemPrompt })...
await memory.saveTurn('when does the index rebuild?', 'nightly at 2am')import { MemoryManager } from 'actrone-memory'
import { openaiAgentsMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = openaiAgentsMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const instructions = await memory.withMemory('You are a helpful agent.', 'the customer plan')
// ...run(new Agent({ instructions }), userInput)...
await memory.remember('what plan is the customer on?', 'Enterprise')import { MemoryManager } from 'actrone-memory'
import { genkitMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = genkitMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const system = await memory.getSystem('deployment approvals')
// ...ai.generate({ system, prompt: userInput })...
await memory.remember('how many approvals for a deploy?', 'two')import { MemoryManager } from 'actrone-memory'
import { voltagentMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = voltagentMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const instructions = await memory.withInstructions('You are a support agent.', 'deployment approvals')
// ...new Agent({ instructions }).generateText(userInput)...
await memory.remember('how many approvals for a deploy?', 'two')import { MemoryManager } from 'actrone-memory'
import { cloudflareAgentsMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = cloudflareAgentsMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const system = await memory.getSystem('deployment approvals')
// ...generateText({ model, system, prompt: userInput })...
await memory.remember('how many approvals for a deploy?', 'two')import { MemoryManager } from 'actrone-memory'
import { inngestAgentKitMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = inngestAgentKitMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const system = await memory.withSystem('You are a support agent.', 'deployment approvals')
// ...createAgent({ name: 'support', system, model })...
await memory.remember('how many approvals for a deploy?', 'two')import { MemoryManager } from 'actrone-memory'
import { claudeAgentMemory } from 'actrone-memory/adapters'
const mm = await MemoryManager.create()
const memory = claudeAgentMemory(mm, { agentId: 'support-bot', sessionId: 'session-1' })
const systemPrompt = await memory.appendToSystemPrompt('You are a support agent.', 'deployment approvals')
// ...query({ prompt: userInput, options: { systemPrompt } })...
await memory.remember('how many approvals for a deploy?', 'two')Note
langchainChatHistory implements LangChain.js's own BaseListChatMessageHistory shape (drop it into RunnableWithMessageHistory), and llamaindexChatMemory implements LlamaIndex.TS's current Memory interface (add/get/clear). Both sit alongside the simpler langchainMemory / llamaindexMemory shown above, reach for them when the framework needs an actual message-history object rather than a context string. And below every adapter, the module-level recall / remember / loadMessages / formatContext functions are the same primitives, callable directly for any framework or vanilla LLM call.Both packages ship an actrone-memory command-line tool that generates a framework recipe without touching your existing code. It either prints the snippet or writes exactly one new file, and never edits anything that already exists:
actrone-memory add langgraph # print install + recipe
actrone-memory add langgraph --write memory.py # write ONE new file
actrone-memory list # list all supported frameworksnpx actrone-memory add langgraph # print install + recipe
npx actrone-memory add langgraph --write memory.ts # write ONE new file
npx actrone-memory list # list all supported frameworksTip
--write refuses to overwrite an existing file: it only ever creates a new, self-contained one. Run list for the exact framework identifiers each CLI accepts. Most match the import-path names used throughout this page (e.g. langgraph, aws_strands), not always the pip/npm extra name.When you use multiple adapters in the same process, share a single memory manager to avoid creating redundant connections and reconstructing config on every call:
from actrone_memory import MemoryManager
from actrone_memory.integrations.langchain import ActroneChatMessageHistory
from actrone_memory.integrations.haystack import ActroneRetriever
mm = await MemoryManager.create() # one shared instance, in-memory by default, or
# Redis + Qdrant if ACTRONE_BACKEND=redis_qdrant is set
history = ActroneChatMessageHistory(
agent_id="my-agent", session_id="s1", memory_manager=mm
)
retriever = ActroneRetriever(
agent_id="my-agent", memory_manager=mm
)
# Both share the same store and connections, no duplicate embedder/pool setup