Skip to content

derinworks/penr-oz-agent-memory-rust

Repository files navigation

penr-oz-agent-memory-rust

Implementation of Agent memory vector store proxy written in Rust.

The server exposes a simple HTTP API for storing and retrieving agent memories using semantic vector search. Embeddings are generated by pluggable providers (Ollama, OpenAI, Anthropic (Voyage AI)) and memories can optionally be persisted in a Qdrant vector database.


Docker Compose development environment

The fastest way to get a fully working memory stack is with Docker Compose. It starts a Qdrant vector database and, optionally, an Ollama instance for local embeddings.

Prerequisites

  • Docker with the Compose plugin

1. Copy the environment file

cp .env.example .env

Edit .env to change default ports or set QDRANT_API_KEY. If you change a port, update the corresponding URL in config.toml too (e.g. [qdrant].url or [embedding.providers.ollama].base_url).

Note: .env is consumed by Docker Compose for container configuration only. The Rust server (cargo run) reads environment variables from the shell — export any server-level vars (e.g. SESSION_API_KEY) in your shell, or set them directly in config.toml.

2. Start the stack

Qdrant only (use an external Ollama, OpenAI, or Anthropic for embeddings):

docker compose up -d

Qdrant + Ollama (fully local, no API keys required):

docker compose --profile ollama up -d

Qdrant will be available at http://localhost:6333 and Ollama (if started) at http://localhost:11434.

3. Pull the embedding model (Ollama profile only)

docker compose exec ollama ollama pull nomic-embed-text

4. Enable Qdrant in config.toml

Uncomment the [qdrant] section so the server connects to the container:

[qdrant]
url        = "http://localhost:6333"
collection = "agent_memory"
dimensions = 768
distance   = "Cosine"

If you are using the Ollama container, the base_url in [embedding.providers.ollama] should be http://localhost:11434.

5. Start the server

cargo run

The server connects to Qdrant on startup and is ready to accept requests.

Stopping the stack

docker compose down          # stop containers, keep volumes
docker compose down -v       # stop containers and delete data volumes

Quick start (without Docker)

1. Configure the server

Copy and edit config.toml. The defaults use Ollama with the nomic-embed-text model for embeddings and keep everything in-memory (no Qdrant required for the /memory endpoints).

[server]
host = "127.0.0.1"
port = 8080

[embedding]
default_provider = "ollama"

[embedding.providers.ollama]
type     = "ollama"
base_url = "http://localhost:11434"
model    = "nomic-embed-text"

Pull the embedding model if you haven't already:

ollama pull nomic-embed-text

2. Start the server

cargo run

The server listens on http://127.0.0.1:8080 by default.


API overview

Method Path Description
GET /health Liveness probe; lists providers
POST /api/embed Generate an embedding for arbitrary text
POST /memory Store a memory (in-memory vector store)
GET /memory/search Semantic search over in-memory store
DELETE /memory/{id} Delete a stored memory entry
POST /api/memory Store a memory in Qdrant (requires [qdrant])
POST /api/search Semantic search over Qdrant (requires [qdrant])
POST /api/sessions Create a session
GET /api/sessions List sessions
GET /api/sessions/{id} Get a session by ID

Example client

examples/agent_client.rs is a self-contained Rust CLI that walks through the complete memory lifecycle:

  1. Health check – verifies the server is up and shows available providers
  2. Store memories – persists a set of agent facts with metadata and a session tag
  3. Semantic search – queries memories by natural-language questions
  4. Agent workflow – simulates an agent that recalls context before responding, then stores its synthesised response as a new memory
  5. Delete – removes one memory entry to demonstrate the full lifecycle

Running the example

With the server already running (cargo run), open a second terminal and run:

cargo run --example agent_client

Pass a custom server URL as the first argument if needed:

cargo run --example agent_client http://localhost:8080

Example output

Agent Memory Client Demo
========================
Server: http://127.0.0.1:8080

--- Step 1: Health Check ---
  status          : ok
  default provider: ollama
  providers       : ["ollama"]

--- Step 2: Storing Memories (session=demo-agent-session) ---
  stored [preference    ] The user prefers concise explanations over verbose ones. (id=3f2a1c8b…)
  stored [tech-stack    ] The project uses Rust for the backend and React for the frontend. (id=9e7d4b2a…)
  stored [infrastructure] The deployment target is AWS us-east-1 region. (id=1a5c9f3e…)
  stored [security      ] Authentication is handled via JWT tokens with a 24-hour expiry. (id=8b2d6e4f…)
  stored [workflow      ] The team follows trunk-based development with feature flags. (id=4c7a1d9b…)

--- Step 3: Semantic Search ---
  query: "What cloud infrastructure does the project use?"
    [0.872] (infrastructure) The deployment target is AWS us-east-1 region.
    [0.731] (workflow) The team follows trunk-based development with feature flags.
    [0.614] (tech-stack) The project uses Rust for the backend and React for the frontend.

  query: "How does the team handle authentication and security?"
    [0.891] (security) Authentication is handled via JWT tokens with a 24-hour expiry.
    ...

--- Step 4: Simulated Agent Workflow ---
  Task: 'Explain the deployment process'
  Agent recalled 2 relevant memories:
    - The deployment target is AWS us-east-1 region.
    - The team follows trunk-based development with feature flags.

  Agent stores its synthesised response…
  Stored agent response (id=6d3e8f1a…)

--- Step 5: Memory Lifecycle – Deleting a Memory ---
  Deleted memory id=3f2a1c8b…

Demo complete.  Memory lifecycle demonstrated:
  [ok] Health check
  [ok] Store memories with metadata and session tags
  [ok] Semantic search with session filtering
  [ok] Agent context retrieval and response storage
  [ok] Delete a memory entry

Configuration reference

Embedding providers

The server supports multiple embedding providers. Set the active provider in config.toml and optionally override it per-request with ?provider=<name>.

Provider Type Default model Dimensions
Ollama ollama nomic-embed-text 768
OpenAI openai text-embedding-3-small 1536
Anthropic¹ claude voyage-3 1024

¹ The claude provider calls the Anthropic Embeddings API (https://api.anthropic.com/v1/embeddings), which is powered by Voyage AI models (e.g. voyage-3, voyage-3-lite). Configure it with an Anthropic API key — not a Voyage AI key. See the Anthropic embeddings docs for details.

Qdrant vector store (optional)

Uncomment the [qdrant] section in config.toml to enable persistent vector storage. Without it the /api/memory and /api/search endpoints return 503, but all other endpoints (including /memory) continue to work.

[qdrant]
url        = "http://localhost:6333"
collection = "agent_memory"
dimensions = 768   # must match the embedding model
distance   = "Cosine"

Session store (optional)

Add a [database] section to enable SQLite-backed sessions:

[database]
url = "sqlite://sessions.db"

Set the SESSION_API_KEY environment variable to require an X-Api-Key header on all session endpoints.


License

MIT

About

Implementation of Agent memory vector store proxy written in Rust

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages