recall-pydantic-ai
Long-term memory for Pydantic AI agents, backed by Recall by Polign.
Every run starts with what the agent knows about the user in its
instructions, and the model saves new facts through a remember tool. Facts
are typed: each one is a predicate from a closed registry with a value, so
"call me Sam" replaces the old name instead of piling up a second one, and the
history of the change is kept. No second model runs on the read path, and no
embedding service is needed.
pip install recall-pydantic-ai
That is the whole install. pip also brings the recall binary and
polign-server for Linux, macOS and Windows, so there is no separate database
to download.
Usage
RecallMemory is a Pydantic AI
capability. Add it to an agent:
from dataclasses import dataclass
from polign_recall import Client
from pydantic_ai import Agent
from recall_pydantic_ai import RecallMemory
@dataclass
class Deps:
user_id: str
recall = Client(local_dir="./recall-data", typed=True) # one per process; the database lives here
agent = Agent(
"anthropic:claude-sonnet-5-5",
deps_type=Deps,
instructions="You help engineers with their projects.",
capabilities=[RecallMemory(recall, subject=lambda ctx: ctx.deps.user_id)],
)
agent.run_sync("I'm Alex. We deploy to Fly.io.", deps=Deps("user-42"))
# a later run, in a new process or a week later
result = agent.run_sync("Where do we deploy again?", deps=Deps("user-42"))
print(result.output) # Fly.io
What happens:
- At the start of each run,
RecallMemoryloads the user's current facts and adds them to the instructions inside a<recall_memory>block. - The user says "I'm Alex. We deploy to Fly.io." The model calls
remembertwice, withnameanddeployment_target. - Later the user says "actually it's Sam". The model calls
rememberagain, Recall replaces the old name, and the tool tells the modelUpdated name to Sam; it was Alex. - The next run's instructions say Sam. Alex is still in the record:
recall.history("user-42", "name")lists both.
Nothing is searched on each model request. A user's typed facts are a short
list, so the whole set fits in the instructions, and they stay the same for
the whole run, which keeps the provider's prompt cache valid. When a user has
more facts than limit (default 20), the run also searches for the prompt,
adds the matches to the block, and gives the model a search_memory tool.
subject is a fixed string or a function of the run context. Use a stable,
auth-derived identifier for the user, never a session or conversation id.
Where the memory is stored
Client(local_dir="./recall-data", typed=True) keeps the database on this machine. typed=True asks for the typed tools this capability files beliefs with (recall 0.18 or later). The
first process to open the directory starts a polign-server for it in the
background, listening on localhost only, and every other process shares that
server. It keeps running after your program exits; its process id is in
recall-data/runtime.json and its log in recall-data/server.log. This is
the quickest way to try the package and is fine for a single machine.
Agents on several machines need one shared memory. Run recall serve
somewhere they can all reach, storing into S3, GCS or Azure
(Get started shows how), then connect:
recall = Client(url="https://memory.internal:8443", api_key=os.environ["RECALL_API_KEY"], typed=True) # a recall serve started with -typed
Client.from_env() does the same from RECALL_URL and RECALL_API_KEY, and
starts a local process when RECALL_URL is unset, so the same code runs on a
laptop and in production.
Create one Client per process and share it between agents and runs. Each one
is a subprocess or an HTTP session, and calls through it are serialized; the
local read path takes a few milliseconds.
Failures
Reads fail open. If Recall is slow or down when a run starts, the run goes on
without the remembered facts and a warning is logged on the
recall_pydantic_ai logger. Writes report the failure to the model as the
tool's result (The fact was not saved: ...), so it can tell the user. An
unknown predicate or a value of the wrong type asks the model to try again.
Options
| Option | Default | What it does |
|---|---|---|
client |
required | A polign_recall.Client opened in typed mode (the default) |
subject |
required | The user, as a string or lambda ctx: ... |
limit |
20 | Facts loaded into the instructions; above it, the run searches for the prompt and offers search_memory |
who |
"the user" |
How the block and the tool descriptions refer to the person |
template |
<recall_memory>\n{context}\n</recall_memory> |
Wrapper around the block; must contain {context} |
remember_tool |
on | Give the model the remember tool. Off makes the memory read-only |
forget_tool |
off | Give the model a forget tool, so users can withdraw a fact by asking |
search_when_overflowed |
on | Search for the prompt when the user has more than limit facts |
read_timeout, write_timeout |
2 s, 10 s | Reads past the timeout fail open; writes past it tell the model the fact was not saved |
Inside a run, the capability instance the agent uses has run_subject,
beliefs (what was loaded) and matches (what the prompt search added).
Custom predicates
The remember tool's schema is built from Recall's predicate registry, so the
model only ever sees the names you allow. The built-in registry covers names,
preferences, project facts and free-form notes. To use your own, write it as
JSON and point the server at it:
{
"name": { "cardinality": "single", "value_type": "string", "description": "The name the user asks to be called" },
"plan_tier": { "cardinality": "single", "value_type": "string", "description": "The user's subscription plan" },
"open_issue": { "cardinality": "multi", "value_type": "string", "description": "A problem the user reported that is not resolved yet" }
}
recall = Client(local_dir="./recall-data", env={"POLIGN_PREDICATES": "registry.json"}, typed=True)
single means a newer value replaces the old one; multi means each value is
an additional fact. value_type is string, number, or boolean, and the
tool turns the model's text into that type ("1,200" becomes 1200, "yes"
becomes true). The file replaces the built-in registry, except note, which
Recall always keeps for statements no other predicate fits.
Limits
- The client must use Recall's typed tools. A client opened with
text=Trueis not supported yet. - Durable execution (Temporal, DBOS) is not tested. The capability reads
memory in
for_run, so a worker that rebuilds the run reads it again. - Agent specs (
Agent.from_spec) cannot createRecallMemory, since it takes a live client.
Development
cd python/recall-pydantic-ai
python -m pip install -e . pytest pytest-asyncio
pytest tests/unit_tests -q # fake Recall client, scripted model
pytest tests/integration_tests -v # the recall binary and polign-server pip installed
The integration tests start a local database in a temporary directory, stop
its server when they finish, and skip when the recall binary is not
installed. Supported versions: Python 3.10 and later, pydantic-ai-slim 2.16
and later in 2.x.
Metadata
Release files for recall-pydantic-ai 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| recall_pydantic_ai-0.1.1.tar.gz | 17.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| recall_pydantic_ai-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.1 kB
Release files / recall_pydantic_ai-0.1.1.tar.gz
| Download URL | recall_pydantic_ai-0.1.1.tar.gz |
|---|---|
| Size | 17.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e97cafcb995dc0bae8a44ca53baf0d12c4e228aba09bebf9585bbc23a907fc00
|
|
BLAKE2b-256 checksum How to use checksums |
6858b05a6321d587f416bbe46591c01b9e9111483a31d61351751fa6c158bc94
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency logRelease files / recall_pydantic_ai-0.1.1-py3-none-any.whl
| Download URL | recall_pydantic_ai-0.1.1-py3-none-any.whl |
|---|---|
| Size | 15.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c5788c171414755a151ee44fe44954f6f5b0579fe031d0870c072c552d84b317
|
|
BLAKE2b-256 checksum How to use checksums |
d73c90ff11b2db713644ca02d270f33195a11c008a6525591ce8118d1e9c0f04
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.
Transparency log