Metadata-Version: 2.4
Name: dreamguard
Version: 0.1.1
Summary: Reversible memory compilation for AI agents: compress memory without losing the raw data, and roll back when recall drops.
Author: Manojkumar V
License: MIT
Project-URL: Homepage, https://github.com/manojkumar16122/dreamguard
Project-URL: Issues, https://github.com/manojkumar16122/dreamguard/issues
Keywords: ai,agents,llm,memory,rollback,context-compression
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: groq
Requires-Dist: groq>=0.11; extra == "groq"
Provides-Extra: server
Requires-Dist: fastapi>=0.110; extra == "server"
Requires-Dist: uvicorn>=0.29; extra == "server"
Requires-Dist: python-dotenv>=1.0; extra == "server"
Requires-Dist: groq>=0.11; extra == "server"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# 🛡️ DreamGuard

**Reversible memory compilation for AI agents.** Compress your agent's memory without losing the raw data, and roll back when recall drops.

[![PyPI](https://img.shields.io/pypi/v/dreamguard)](https://pypi.org/project/dreamguard/)
[![Python](https://img.shields.io/pypi/pyversions/dreamguard)](https://pypi.org/project/dreamguard/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/manojkumar16122/dreamguard/blob/main/LICENSE)

![DreamGuard demo: recall drops after compression and recovers to 100% after rollback](https://raw.githubusercontent.com/manojkumar16122/dreamguard/main/docs/dreamguard-demo.png)

## The problem

Long-running agents compress their memory ("dreaming" / consolidation) to keep the context window small. The common approach rewrites memory **in place**: once a detail is summarised away, it is gone for good. If the summary dropped the one port number, ticket owner or ID the agent needs later, there is no way back.

## The idea

DreamGuard treats memory like a build step:

- **Raw episodes are never deleted.**
- Every compressed fact is **linked back to its source episodes** (provenance).
- If recall quality drops, **`rollback()`** restores the exact raw context.

```
 record() ──► episodes (immutable)
                 │  dream()
                 ▼
         semantic_memories ──provenance──► episodes
                 │  rollback()
                 ▼
     compressed facts deactivated, raw context restored
```

## Install

```bash
pip install dreamguard                 # core library, zero dependencies
pip install "dreamguard[groq]"         # + Groq LLM compressor
pip install "dreamguard[server]"       # + dashboard, API and Groq support
```

Requires Python 3.10+.

## Quick start

```python
from dreamguard import MemoryEngine, HeuristicCompressor

mem = MemoryEngine(HeuristicCompressor(retention=0.7), destructive=False)
mem.record(1, "api_port=8421")
mem.record(2, "region=ap-south-1")

mem.dream()              # compress; raw episodes + provenance are kept
print(mem.context())     # what your agent sees: the compressed digest
mem.rollback()           # back to the exact raw episodes
print(mem.context())
```

`MemoryEngine` accepts **any compressor** with a `compress(lines: list[str]) -> str` method, so you can plug in any LLM.

## Auto-rollback with canary questions

Pick facts that must never be lost, test them after every compression, and roll back automatically if recall falls below a threshold:

```python
from dreamguard import MemoryEngine, GroqCompressor   # pip install "dreamguard[groq]"

# export GROQ_API_KEY=gsk_...   (and optionally GROQ_MODEL=openai/gpt-oss-120b)
mem = MemoryEngine(GroqCompressor(), destructive=False)

CANARIES = [("Which port does redis use?", "6391"), ("Who approved r-1093?", "tomas berg")]
THRESHOLD = 0.85

def guarded_dream(mem, ask):
    """ask(memory_text, [questions]) -> [answers]; your LLM call."""
    mem.dream()
    answers = ask(mem.context(), [q for q, _ in CANARIES])
    score = sum(exp in a.lower() for (_, exp), a in zip(CANARIES, answers)) / len(CANARIES)
    if score < THRESHOLD:
        mem.rollback()          # compression rejected, raw memory restored
    return score
```

## Dashboard and CLI

```bash
pip install "dreamguard[server]"
dreamguard serve                 # dashboard at http://localhost:8000
dreamguard benchmark             # offline simulation in your terminal
dreamguard benchmark --auto      # auto-rollback when accuracy < 85%
```

The dashboard has two pages:

- **`/`** is the offline simulation: a 50-turn chart plus a hands-on memory panel (record, dream, rollback).
- **`/live`** runs a real LLM through the flow. Set `GROQ_API_KEY` (and optionally `GROQ_MODEL`) in your environment or a `.env` file, then click **Load scenario → Evaluate → Dream → Evaluate → Rollback → Evaluate**.

In `/live`, an LLM compresses 12 engineering-log episodes, then answers 8 factual questions from each system's remaining memory. Answers are graded against known ground truth. In one example run, recall fell to 50% after compression; after rollback DreamGuard returned to 100% while in-place memory stayed at 50%. LLM output varies by model and run, but the rollback guarantee does not, because it restores the raw text.

## How it works

| Table | Purpose |
|---|---|
| `episodes` | Raw, append-only memory (`turn`, `content`) |
| `semantic_memories` | Compressed digests, with an `active` flag |
| `provenance` | `memory_id → episode_id` links from each digest to its sources |

| Method | What it does |
|---|---|
| `record(turn, content)` | Append a raw episode |
| `dream()` | Compress episodes not yet covered by an active digest |
| `rollback()` | Deactivate digests so raw episodes become the context again |
| `context()` | Active digests plus any uncovered raw episodes |
| `snapshot()` | Episodes, facts and provenance as dicts |
| `evaluate(truth)` | Fraction of `key=value` details recoverable from the context |

With `destructive=True` the engine mimics in-place dreaming: it deletes raw data and re-compresses digests together with new episodes, so loss compounds and cannot be undone. Use it as a baseline for comparisons.

## Benchmark methodology

The built-in benchmark is a **synthetic simulation**, not a measurement of any production system:

1. Each turn records one exact detail, e.g. `param_7=48213`.
2. Every 10 turns memory is compressed with a seeded lossy compressor that keeps each value with probability 0.7.
3. After every turn, recall is the fraction of all details seen so far that appear verbatim in the agent's visible context.

It shows that *if* compression is lossy, an irreversible design loses information permanently while a design that keeps raw data can restore it. It does **not** show how any specific LLM or product behaves.

**Trade-off:** after a rollback the agent context is raw again and therefore larger. You trade the size benefit of compression for recall until the next dream.

## REST API (with `[server]`)

| Method | Path | Description |
|---|---|---|
| POST | `/api/record` | `{"content": "..."}` record an episode |
| POST | `/api/dream` | Compress uncovered episodes |
| POST | `/api/rollback` | Deactivate compressed memory |
| GET | `/api/memory` | Episodes, facts, provenance, context size |
| GET | `/api/benchmark` | Run the simulation (`seed`, `retention`, `auto_rollback`, `rollback_at`) |

Interactive docs at `/docs`.

## Roadmap

- [ ] Selective rollback (restore only the episodes behind a specific fact)
- [ ] Built-in guarded dream with canary checks
- [ ] Pluggable storage backends (Postgres, vector DBs)
- [ ] Rollback triggers driven by task-level eval signals

## Contributing

Issues and PRs are welcome at [github.com/manojkumar16122/dreamguard](https://github.com/manojkumar16122/dreamguard).

```bash
git clone https://github.com/manojkumar16122/dreamguard
cd dreamguard
pip install -e ".[dev,server]"
pytest
```

## License

MIT. Built by [Manojkumar V](https://github.com/manojkumar16122).
