Skip to Content
MemoryOverview

Memory

Memory lets an agent remember things across conversations: what a user told it last week, their preferences, facts about them. Use it whenever the same users come back to your agent more than once. Pass memory= to Agent, pass user_id= to agent.run(), and every run reads from and writes to that user’s memory.

Memory holds three kinds of state: episodes (past conversation turns), working blocks (small per-user scratch data that is always injected), and Facts (structured (subject, predicate, object) triples extracted from chats). One Agent with one Memory partitions automatically by user_id, so you don’t need any namespace plumbing in your app.

from loomflow import Agent # In-memory (default; lost on restart) agent = Agent("...", model="claude-opus-4-7", memory="inmemory") # Single-file SQLite (persistent, no server) agent = Agent("...", model="claude-opus-4-7", memory="sqlite:./bot.db") # Chroma (ephemeral / persistent) agent = Agent("...", model="claude-opus-4-7", memory="chroma") agent = Agent("...", model="claude-opus-4-7", memory="chroma:./chroma-db") # Postgres + pgvector agent = Agent("...", model="claude-opus-4-7", memory="postgres://user:pw@localhost/loomflow") # Redis (with optional RediSearch HNSW vector index) agent = Agent("...", model="claude-opus-4-7", memory="redis://localhost:6379/0")

Those are five of the six backends. The sixth, VectorMemory (in-process, with embedding recall), has no URL form; construct it directly and pass the instance. See Backends.

Pass user_id= to agent.run and the framework partitions every recall and write automatically:

await agent.run("Hi, I'm Alice and I live in Tokyo.", user_id="alice") await agent.run("Hi, I'm Bob.", user_id="bob") # Alice's lives_in fact never surfaces in Bob's recall.

user_id must be a string, or None for the anonymous bucket; anything else raises TypeError, so pass numeric ids through str().

What ships by default

  • Auto fact extraction. Every agent.run() against a real model pulls structured (subject, predicate, object) claims into the bi-temporal fact store. It is on by default for Anthropic, OpenAI and LiteLLM models.
  • Auto-attached fact store. The resolver wires a fact store for every backend automatically (pass with_facts=False to skip it).
  • Auto-picked embedder. OpenAIEmbedder("text-embedding-3-small") if OPENAI_API_KEY is set, HashEmbedder() otherwise. Set LOOMFLOW_EMBEDDER (for example LOOMFLOW_EMBEDDER=hash) to force a choice.
  • user_id partition. Every backend honours the multi-tenant contract, so one shared file or pool serves any number of users.
  • Lazy connect for async backends. Postgres and Redis URLs return a LazyMemory proxy; the connection opens on the first agent.run, so Agent(...) stays synchronous. A Postgres URL also creates its tables then.

Read more

Three ways to construct memory

1. URL string: the resolver picks defaults

agent = Agent("...", model="claude-opus-4-7", memory="postgres://localhost/loomflow")

2. Dict form for tweaks

agent = Agent("...", model="claude-opus-4-7", memory={ "backend": "chroma", "path": "./chroma-db", "namespace": "tenant_a", "embedder": "openai-large", "with_facts": True, })

3. Explicit instance for full control

from loomflow.memory.chroma import ChromaMemory from loomflow.memory.embedder import OpenAIEmbedder memory = ChromaMemory.local( "./chroma-db", with_facts=True, embedder=OpenAIEmbedder() ) agent = Agent("...", model="claude-opus-4-7", memory=memory)

Tools see the active scope automatically

Inside any tool, get_run_context() returns the live RunContext:

from loomflow import get_run_context, tool @tool async def my_orders() -> list[dict]: ctx = get_run_context() return await db.query("orders", user_id=ctx.user_id)

You don’t need to thread user_id through every tool signature.

Memory vs Vector stores. Memory is for conversational state: episodes, working blocks, and Facts built up over time. VectorStore (see RAG) is for document corpora: what your agent retrieves from but doesn’t build up. They are different primitives with different backends.

Last updated on