Metadata-Version: 2.4
Name: shiro-memory
Version: 5.6.0
Summary: Persistent memory for Shiro — upgraded to antaris-memory v5.5.0 feature parity. Stripped: MCP, Supabase collection, sharding.
Author-email: Antaris Analytics <dev@antarisanalytics.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/Antaris-Analytics-LLC/shiro-memory
Project-URL: Repository, https://github.com/Antaris-Analytics-LLC/shiro-memory
Keywords: ai,memory,agents,llm,persistence,recall
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: embeddings
Requires-Dist: openai>=1.0; extra == "embeddings"
Provides-Extra: semantic
Requires-Dist: sentence-transformers>=2.0; extra == "semantic"
Provides-Extra: all
Requires-Dist: openai>=1.0; extra == "all"
Provides-Extra: pro
Requires-Dist: openai>=1.0; extra == "pro"
Requires-Dist: sentence-transformers>=2.0; extra == "pro"
Dynamic: license-file

# shiro-memory

Persistent memory for AI agents. Shiro's personal memory library — forked from [antaris-memory](https://github.com/Antaris-Analytics-LLC/antaris-suite), upgraded to v5.5.0 feature parity, with MCP/cloud backends stripped per spec.

[![PyPI](https://img.shields.io/pypi/v/shiro-memory)](https://pypi.org/project/shiro-memory/)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-green.svg)](https://python.org)
[![License](https://img.shields.io/badge/license-Apache%202.0-orange.svg)](LICENSE)

## Install

```bash
pip install shiro-memory==5.5.2
```

Zero external dependencies. No API keys required for core memory. No external services.

## What's stripped (intentional)

| Feature | Status | Reason |
|---|---|---|
| MCP server | ❌ Removed | OpenClaw handles the agent interface |
| GCS / cloud backends | ❌ Removed | File-based storage only |
| Sharding | ⚠️ Present but unused | Accepted but ignored; not needed at Shiro's scale |

Everything else from antaris-memory 5.5.0 is present, including fact decomposition, fuzzy dedup, enrichment, and the ingest speed fixes.

## Quick Start

```python
from antaris_memory import MemorySystem

mem = MemorySystem(
    workspace="~/.openclaw/shiro-store/shared",
    agent_name="shiro-shared",   # REQUIRED — prevents memory bleed between agents
    half_life=30,                # 30-day decay (longer than default 7)
)
mem.load()

mem.ingest("My favorite color is cobalt blue", source="conversation")

results = mem.search("favorite color")
for r in results:
    print(r.entry.content)

mem.save()
```

**`agent_name` is required.** Without it, a `UserWarning` is raised and memories from different agents blend together with no way to separate them.

## Private / Shared Architecture

shiro-memory is designed around two completely isolated `MemorySystem` instances:

```python
# Private store — Jason's sessions only
private = MemorySystem(
    workspace="~/.openclaw/shiro-store/private",
    agent_name="shiro-private",
)
private.load()

# Shared store — all sessions
shared = MemorySystem(
    workspace="~/.openclaw/shiro-store/shared",
    agent_name="shiro-shared",
)
shared.load()
```

These stores are file-isolated and have no cross-pollination path. Memories ingested into `private` — including all atomically decomposed facts — **cannot appear in `shared` search results**. The isolation is architectural, not tag-based.

## LLM Enrichment + Fact Decomposition (highest-leverage features)

Wire up any LLM to dramatically improve recall and enable atomic fact extraction:

```python
import anthropic, json

client = anthropic.Anthropic()

def enricher(content: str) -> dict:
    resp = client.messages.create(
        model="claude-haiku-4-5-20251001",
        max_tokens=400,
        messages=[{"role": "user", "content": f"""Return JSON only:
{{"tags": ["tag1"], "summary": "search-optimized restatement",
 "keywords": ["kw1"], "search_queries": ["natural query that should find this"],
 "facts": ["atomic fact 1", "atomic fact 2"]}}
Content: {content[:400]}"""}]
    )
    try:
        return json.loads(resp.content[0].text)
    except Exception:
        return {}

mem = MemorySystem(
    workspace="~/.openclaw/shiro-store/shared",
    agent_name="shiro-shared",
    enricher=enricher,
)
```

**Auto-detection:** `enrichers.py` also provides `auto_enricher()` which detects available API keys automatically (checks `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY` in order). No provider is hardcoded.

```python
from antaris_memory.enrichers import auto_enricher

enricher = auto_enricher()  # returns None if no keys found
mem = MemorySystem(workspace=..., agent_name=..., enricher=enricher)
```

**What enrichment unlocks:**
- 3× TF weight on `search_queries` — vocabulary-gap queries find correct memories
- 2× weight on `enriched_summary` and `keywords`
- **Fact decomposition** — each memory is split into 1–5 atomic facts stored as separate `memory_type="fact"` entries, each with `parent_hash` provenance linkage and independently searchable
- Fuzzy dedup (Jaccard similarity ≥ 0.85) prevents near-duplicate facts from accumulating; re-ingesting similar content bumps `confidence` instead of creating duplicates

Without enrichment: BM25 on raw content only (~3.5% R@1 on vocabulary-gap queries).
With enrichment: query-document pairs at ingest time (~85.5% R@1).

## Memory Types

```python
# Mistakes decay 10× slower and score 2× higher — they stick around
mem.ingest_mistake(
    what_happened="Used DROP TABLE instead of TRUNCATE",
    correction="Always use TRUNCATE for clearing data",
    root_cause="Confused SQL semantics under pressure",
    severity="high",
)

# Facts — verified knowledge (also produced automatically by enrichment)
mem.ingest_fact("Production DB is PostgreSQL 14.2 on RDS us-east-1", source="infra-docs")

# Preferences — persist 3× longer
mem.ingest_preference("Prefers concise responses under 200 words", source="feedback")

# Procedures — task-matched recall
mem.ingest_procedure("Deployment: test → tag → staging → monitor 10min → prod", source="runbook")
```

## Bulk Ingest (O(n) performance)

v5.5.0 introduced `ingest_bulk()` — deferred WAL flush that eliminates the O(n²) ingest signature at scale:

```python
# Up to 22× faster at small scale, 6× faster at 10K entries
mem.ingest_bulk([
    "Memory one",
    "Memory two",
    "Memory three",
], source="batch-import")
```

**Performance (Mac Mini M4):**

| Store Size | Time | Rate |
|---|---|---|
| 1,000 | 0.6s | ~1,600/s |
| 5,000 | 3.9s | ~1,300/s |
| 10,000 | 9.7s | ~1,030/s |

Before v5.5.0: 10K took 59s at ~170/s with O(n²) scaling.

## Search

```python
# 11-layer search pipeline
results = mem.search(
    "production deployment failure",
    limit=10,
    memory_type="mistake",     # filter by type: "fact", "episodic", "semantic", "mistake"
    explain=True,              # include score breakdown
)

# Search with co-occurrence expansion
results, ctx = mem.search_with_context(
    "API problems",
    cooccurrence_boost=True,
)
print(f"Expanded: {ctx.expanded_query}")
```

## Re-decompose Existing Memories

If enrichment was added after initial ingest, extract facts from existing memories retroactively:

```python
count = mem.re_decompose(limit=500)
print(f"Decomposed {count} new facts from existing memories")
```

## Context Packets (cold-spawn solver)

```python
packet = mem.build_context_packet(
    task="Deploy auth service to production",
    tags=["deployment", "auth"],
    max_tokens=1200,
    include_mistakes=True,
)
print(packet.render())  # inject into agent system prompt
```

## Stats & Health

```python
stats = mem.get_stats()
print(f"Entries: {stats['total_entries']}")
print(f"Hot/Warm/Cold: {stats['hot_entries']}/{stats['warm_entries']}/{stats['cold_entries']}")
print(f"Enriched: {stats['enriched_entries']}")
print(f"Facts: {stats.get('fact_entries', 0)}")

health = mem.get_health()
print(health["status"])  # "ok" or "degraded"
```

## OpenClaw Plugin

The OpenClaw plugin is in `openclaw-plugin/index.js`. See [PLUGIN_SPEC.md](PLUGIN_SPEC.md) for architecture details.

**v5.5.1 install:**
```bash
# 1. Install library
pip install shiro-memory==5.5.2

# 2. Copy plugin
cp openclaw-plugin/index.js ~/.openclaw/extensions/shiro-memory/index.js

# 3. Restart OpenClaw
```

**Store layout:**
```
~/.openclaw/shiro-store/
├── private/    ← shiro-private (Jason's sessions only)
└── shared/     ← shiro-shared (all sessions)
```

**Upgrading from 4.9.x:** Existing memory stores are fully backward compatible. `_content_norms` and the fact dedup index are rebuilt automatically on first load. No migration needed.

## Version History

| Version | Date | Notes |
|---|---|---|
| **5.5.2** | 2026-03-16 | README updated with full feature documentation, install instructions, private/shared architecture guide, performance tables, re_decompose() usage. |
| 5.5.1 | 2026-03-16 | Full antaris-memory 5.5.0 feature port. Fact decomposition, fuzzy dedup, confidence tracking, ingest_bulk O(n²)→linear. Judge-reviewed: forget/delete_source ghost entry fix, duplicate stats() removed. |
| 4.9.3 | 2026-03-11 | Cross-session recall (`cross_session_recall` param on `search()`) |
| 4.9.2 | 2026-03-10 | Fix `MemoryEntry.__slots__` missing `agent_id`/`channel_id` |
| 4.9.1 | 2026-03-10 | Fix search.py (v1 engine → 11-layer); Plugin v2.1.1 temp-file fix |
| 4.9.0 | 2026-03-10 | Full v5.0.1 feature parity upgrade; Plugin v2.1.0 |
| 4.1.0 | 2026-02-26 | Original fork baseline |

## License

Apache 2.0 — see [LICENSE](LICENSE)

---

*shiro-memory is maintained by [Antaris Analytics LLC](https://antarisanalytics.ai). Based on [antaris-memory](https://github.com/Antaris-Analytics-LLC/antaris-suite).*
