pgmem
Guides

Integrate pgmem into your agent

Wire pgmem into your agent's turn loop.

Wiring pgmem into an agent is one rule applied to your turn loop: read memory to build the prompt, write memory after you reply. Only the read (compile_context) is on the response path; everything else runs after the user has their answer.

Prerequisites

  • pgmem installed and the schema applied.
  • An embedder and an LLM client if you want the semantic graph (Tier 4) and compaction. The turn/memory/context surface works without them, but a real agent usually wants both.
  • You've skimmed How a turn flows.

The llm you pass to PgMem powers pgmem's internal work (compaction summaries, graph extraction). Generating the user-facing reply is your own call against context.messages — the same provider or a different one. pgmem hands you messages; how you call your model is up to you.

Steps

Construct the client once

Build PgMem at startup and reuse it across turns and sessions. It holds the connection pool.

from pgmem import PgMem

mem = await PgMem.create(
    dsn="postgresql://user:pass@host:5432/db",  # your database
    embedder=embedder,  # your Embedder implementation
    llm=llm,            # your LLMClient implementation
)

Resume or create a session per conversation

Create a fresh session for a new conversation; resume only to pick one up that was interrupted mid-flight (e.g. a crashed worker). resume is group-scoped for tenant isolation.

if session_id:
    session = await mem.session.resume(session_id, group_id)
else:
    session = await mem.session.create(group_id=group_id, user_id=user_id)
session_id = session.uuid

On each turn: record input, compile, reply

async def on_turn(user_text: str) -> str:
    await session.add_turn(role="user", content=user_text)

    context = await session.compile_context(query=user_text)
    reply = await respond(context.messages)  # your own model call

    await session.add_turn(role="assistant", content=reply)
    return reply

compile_context is pure indexed reads under a token budget — no LLM — so it fits the latency budget. Pass token_budget= and strategy= to tune what the model sees (see Tune retrieval).

Compact off the turn

After replying, fold the turn buffer down without blocking the next turn. This returns immediately; summarisation and validation run in the background.

    await session.compact_async()

End the session when the conversation is over

Sealing preserves state for audit and queues promotion of eligible memory into the graph.

await session.end()

Verify

Restart your process mid-conversation and call mem.session.resume(session_id, group_id) — the active execution state and recent turns come back, so the agent continues where it left off. A new conversation gets a fresh session and retrieves only the durable continuity it needs.

Gotchas

Keep memory writes and compaction off the response path. add_turn is a cheap write, but compact_async, add_episode, and session.end (promotion) do real work — never await them inline before producing the reply.

  • Create a fresh session per conversation; don't resume an old one to "continue" past context — let retrieval bring back the saga and facts instead.
  • Without an embedder, the semantic tier (Tier 4) is skipped; the rest still works.

On this page