Metadata-Version: 2.4
Name: synapse-memory-sdk
Version: 1.1.1
Summary: Python SDK for Synapse Memory API — persistent memory for AI agents
Author-email: Michael Schäfer <michael@schaefer.zone>
License: MIT
Project-URL: Homepage, https://gitlab.com/schaefer-services/synapse-sdk-py
Project-URL: Repository, https://gitlab.com/schaefer-services/synapse-sdk-py.git
Project-URL: Issues, https://gitlab.com/schaefer-services/synapse-sdk-py/-/issues
Keywords: synapse,memory,llm,ai,agent,persistent,claude,cursor,mcp
Classifier: Development Status :: 4 - Beta
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: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28.0
Provides-Extra: async
Requires-Dist: aiohttp>=3.9.0; extra == "async"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
Requires-Dist: aiohttp>=3.9.0; extra == "dev"
Dynamic: license-file

# synapse-memory-sdk – Python-SDK für Synapse

[![PyPI version](https://img.shields.io/pypi/v/synapse-memory-sdk.svg)](https://pypi.org/project/synapse-memory-sdk/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Python-SDK für die [Synapse Memory API](https://gitlab.com/schaefer-services/synapse) –
persistente Gedächtnisfunktionen für KI-Agenten. Das SDK kapselt alle
HTTP-Endpunkte der Synapse-API in einer typisierten Client-Klasse und
bietet Retries, Timeouts und automatische JSON-Parserung. Es ist in reinem
Python ohne externe Dependencies (außer `requests`) geschrieben und läuft
auf jeder Python-Laufzeit ab Version 3.10. Für asynchrone Anwendungen
kann das optionale `aiohttp`-Extra installiert werden.

## Übersicht

synapse-memory-sdk ist das offizielle Python-SDK für die Synapse-Memory-
API. Es erlaubt KI-Agenten, Python-Skripten, Backend-Services und
anderen Python-Anwendungen, persistente Erinnerungen über Sessions
hinweg zu speichern und abzurufen. Das SDK folgt dem Pattern „ein Client
pro Mind" und gruppiert Endpunkte in domänenspezifische Sub-APIs
(`memory`, `chat`, `scheduler`, `webhooks`, `visualization`, `compact`,
`sharing`). Die aktuelle Version `1.1.0` unterstützt alle Endpunkte der
Synapse-API ab Version 1.4.0 und ist vollständig rückwärtskompatibel.

## Installation

```bash
pip install synapse-memory-sdk
```

Für asynchrone Anwendungen kann das optionale `async`-Extra installiert
werden, das `aiohttp` als Alternative zu `requests` mitbringt:

```bash
pip install "synapse-memory-sdk[async]"
```

Für die Entwicklung (Tests, Linting) wird das `dev`-Extra empfohlen:

```bash
pip install "synapse-memory-sdk[dev]"
```

Das Paket wird als Wheel und Source-Distribution ausgeliefert und ist
mit Python 3.10, 3.11, 3.12 und 3.13 kompatibel (siehe `classifiers` in
`pyproject.toml`). Die einzige Runtime-Dependency ist
`requests>=2.28.0`, das in den meisten Python-Umgebungen bereits
vorhanden ist.

## Quick Start

```python
from synapse_memory import Synapse

synapse = Synapse(
    base_url="https://synapse.schaefer.zone",
    mind_key="your-mind-key-uuid",
)

# Alle Erinnerungen abrufen (LLM-formatierter Text)
text = synapse.memory.recall()
print(text)

# Neue Erinnerung speichern
synapse.memory.store(
    category="fact",
    content="Nutzer ist Michael Schäfer",
    key="user_name",
    priority="critical",
    source="user",
)

# Erinnerungen suchen
results = synapse.memory.search("insolvenz")

# Mit dem Menschen chatten
msgs = synapse.chat.poll()
if msgs["messages"]:
    print(msgs["messages"][0]["content"])
    synapse.chat.reply("Verstanden!")

# Persistente Variablen (überleben Container-Restarts)
synapse.scheduler.set_var("last_run", str(int(time.time())))
last_run = synapse.scheduler.get_var("last_run")
```

## API-Referenz

### `synapse.memory`

| Methode | Beschreibung |
|---|---|
| `recall()` | Alle Erinnerungen als LLM-formatierter Text |
| `list(category?, tag?, limit?, offset?)` | Gefilterte Listenabfrage |
| `store(**params)` | Speichern oder Upsert (category, content, key?, tags?, priority?, source?, confidence?, idempotency_key?) |
| `search(q, limit?)` | Volltextsuche (FTS5) |
| `semantic_search(q, limit?, threshold?)` | Semantische Suche (Embeddings) |
| `update(memory_id, **params)` | Aktualisieren per ID |
| `delete(memory_id)` | Löschen per ID |
| `stats()` | Statistiken (verifiziert/agent/system) |
| `unverified(limit?)` | Unverifizierte Erinnerungen listen |
| `contradictions(within_seconds?)` | Widersprüche erkennen |
| `audit(limit?, action?)` | Audit-Log abrufen |
| `related(memory_id)` | Verwandte Erinnerungen (Shared Tags) |
| `by_tag(tag)` | Nach Tag filtern |
| `diff(since)` | Inkrementelle Syncs |
| `expiring(within_seconds?)` | Bald ablaufende Erinnerungen |
| `health()` | Mind-Health-Check |
| `sync(memories)` | Bulk-Sync |
| `export(format?)` | Mind als JSON/CSV exportieren |

### `synapse.chat`

| Methode | Beschreibung |
|---|---|
| `poll(since_id?)` | Neue Nachrichten des Menschen abholen |
| `reply(content, reply_to_id?)` | Antwort senden |
| `status()` | Online-Status (online/idle/offline) |
| `history(limit?)` | Vollständige Historie (nur JWT) |
| `unread(role?)` | Ungelesene zählen (nur JWT) |

### `synapse.scheduler`

| Methode | Beschreibung |
|---|---|
| `list_crons()` / `create_cron(...)` / `delete_cron(id)` / `toggle_cron(id)` | Cron-Jobs verwalten |
| `list_vars()` / `get_var(key)` / `set_var(key, value?)` / `delete_var(key)` | Persistente Variablen |

### `synapse.webhooks` (v1.4.0)

| Methode | Beschreibung |
|---|---|
| `register(url, events)` | Webhook registrieren |
| `list()` / `get(id)` / `update(id, ...)` / `delete(id)` | Webhook-Verwaltung |
| `test(id)` | Webhook-Test-Event senden |

### `synapse.visualization` (v1.4.0)

| Methode | Beschreibung |
|---|---|
| `graph(max_nodes?)` | Memory-Graph erzeugen |
| `tags()` | Tag-Häufigkeiten abrufen |
| `timeline(since?, until?)` | Zeitstrahl generieren |

### `synapse.compact` (v1.4.0)

| Methode | Beschreibung |
|---|---|
| `compact(dry_run?)` | Memories zusammenfassen |

### `synapse.sharing` (v1.4.0, nur JWT)

| Methode | Beschreibung |
|---|---|
| `share(mind_id, email, acl)` | Mind mit anderem Nutzer teilen |
| `list_shares(mind_id)` | Geteilte Minds auflisten |
| `update_share(mind_id, share_id, acl)` | ACL-Level ändern |
| `delete_share(mind_id, share_id)` | Freigabe widerrufen |

## Konfiguration

Der `Synapse`-Konstruktor akzeptiert folgende Parameter:

| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
| `base_url` | `str` | – | Basis-URL der Synapse-Instanz (Pflichtfeld) |
| `mind_key` | `str` | – | Mind Key für Authentifizierung (Pflichtfeld) |
| `jwt` | `Optional[str]` | `None` | Optionaler JWT für Mensch-only-Endpunkte |
| `timeout` | `int` | `30` | Request-Timeout in Sekunden |
| `max_retries` | `int` | `2` | Anzahl Retries bei 5xx/429-Fehlern |

Der `base_url` wird automatisch um trailing Slashes bereinigt, sodass
sowohl `https://synapse.schaefer.zone` als auch
`https://synapse.schaefer.zone/` als valide Eingaben akzeptiert werden.
Der Mind Key wird als `Authorization: Bearer <key>`-Header an jeden
Request angehängt; der optionale JWT kann für Mensch-only-Endpunkte
(`memory.verify`, `sharing.*`) als `token`-Override pro Request übergeben
werden.

## Fehlerbehandlung

Fehler werden als `SynapseError`-Instanzen geworfen, die den HTTP-Status-
Code, den Response-Body und den angefragten Pfad enthalten. Bei
Netzwerkfehlern (Timeout, DNS, Connection Refused) wird der Status `0`
gesetzt und die ursprüngliche Fehlermeldung im `message`-Feld
mitgeführt. Bei 5xx- und 429-Fehlern führt das SDK automatisch bis zu
`max_retries` Wiederholungen mit exponentiellem Backoff (0,5 Sek × Versuch)
durch, bevor es den Fehler endgültig wirft. Die Anwendung sollte
`SynapseError`-Instanzen abfangen und je nach Status-Code reagieren:
`401` bedeutet, dass der Mind Key ungültig ist und neu geladen werden
muss, `429` bedeutet, dass das Rate-Limit erreicht wurde und ein Backoff
erfolgt, `404` bedeutet, dass die angefragte Ressource nicht existiert.

## CI/CD

Die Pipeline in `.gitlab-ci.yml` inkludiert das Template
`schaeferms/ci-templates/templates/master.yml` und durchläuft die Stages
`lint`, `test`, `build` und `publish`. Der `test:python`-Job läuft im
Image `python:3.12-slim` mit den Tags `linux` und `docker`, installiert
das Paket via `pip install -e ".[dev]"` und verifiziert den Import
(`python3 -c "from synapse_memory import Synapse; print('Import OK')"`).

Der `build:python`-Job baut das Paket via `python3 -m build` und lädt
das `dist/*.whl` und `dist/*.tar.gz` als Artifacts mit 14-tägiger
Aufbewahrung hoch. Der `publish:pypi`-Job hängt vom `build:python`-Job
ab, läuft nur auf `main` und prüft zuerst, ob `TWINE_PASSWORD` gesetzt
ist. Ist das Password nicht gesetzt, bricht der Job sauber mit einer
Hinweismeldung ab (kein Pipeline-Fehler). Andernfalls lädt er das
Paket via `twine upload dist/* --username __token__ --password
"$TWINE_PASSWORD" --non-interactive` nach PyPI hoch. Wöchentliche
Pipelines (Montag 09:00 UTC) fangen Dependency-Breakage früh ab.

## Deployment

Als PyPI-Paket wird synapse-memory-sdk nicht selbst deployed, sondern in
Anwendungen installiert. Für die Veröffentlichung einer neuen Version
wird die `version` in `pyproject.toml` erhöht, nach `main` gepusht und
die CI-Pipeline übernimmt den PyPI-Publish automatisch. Vor einem
Publish sollte `python3 -m build && pip install -e ".[dev]" && pytest`
lokal durchlaufen, weil die CI identisch vorgeht. Für die Installation
in einer Anwendung reicht `pip install synapse-memory-sdk`; für
asynchrone Anwendungen `pip install "synapse-memory-sdk[async]"`.

## Entwicklung

```bash
git clone https://gitlab.com/schaefer-services/synapse-sdk-py.git
cd synapse-sdk-py
pip install -e ".[dev]"
python3 -c "from synapse_memory import Synapse; print('Import OK')"
pytest
```

Die Quelltexte liegen unter `synapse_memory/` und sind nach
Verantwortlichkeiten aufgeteilt: `synapse.py` (Hauptklasse mit
`request`-Methode und Sub-API-Instanzen), `memory.py`, `chat.py`,
`scheduler.py`, `webhooks.py`, `visualization.py` (enthält auch
`CompactApi` und `SharingApi`), `types.py` (Typdefinitionen),
`error.py` (`SynapseError`-Klasse). Der Build erfolgt via
`python3 -m build`, das Wheel und Source-Distribution unter `dist/`
erzeugt.

Für Tests wird `pytest` verwendet; die Testsuite liegt derzeit nur
minimal vor und soll mit neuen Features erweitert werden. Neue Methoden
sollten mit Tests für Happy-Path und Fehlerfall ausgeliefert werden.
Der Default-Branch `main` ist geschützt, alle Änderungen laufen über
Merge Requests. Vor dem Merge muss die Pipeline grün sein und der
Import-Check erfolgreich durchlaufen.

## Tech Stack

- **Runtime**: Python 3.10+ (3.10, 3.11, 3.12, 3.13 getestet)
- **HTTP**: `requests>=2.28.0` (synchron), optional `aiohttp>=3.9.0` (async)
- **Build**: `setuptools>=64` + `wheel` via `python3 -m build`
- **Test**: `pytest>=7.0`, `pytest-asyncio>=0.21`
- **CI**: GitLab CI mit Templates aus `schaeferms/ci-templates`
- **Publish**: `twine upload` nach PyPI

## Lizenz

MIT – siehe [LICENSE](LICENSE).

## Autor

Michael Schäfer · Schäfer Services · [michael@schaefer.zone](mailto:michael@schaefer.zone)


## Dokumentation

Die weiterführende Doku liegt in `documentation/` und richtet sich an
unterschiedliche Leser:innen: `architecture.md` dokumentiert die Schichten
(Hauptklasse, Sub-APIs, Typdefinitionen, Fehlerbehandlung), die HTTP-Logik
mit Retries und Timeouts sowie die Authentifizierungs-Strategie;
`deployment.md` behandelt die PyPI-Veröffentlichung, CI/CD-Pipeline,
Versionierung nach Semantic Versioning und das Rollback-Verfahren;
`development.md` erklärt das Setup, die Code-Struktur, Python-Konventionen
nach PEP 8 und PEP 484, Tests mit `pytest` und den Merge-Request-Workflow.
Neue Features sollten mit begleitenden Docstrings und mindestens einem
Happy-Path-Test ausgeliefert werden.

| Datei | Inhalt |
|---|---|
| `documentation/architecture.md` | Schichten, HTTP-Logik, Auth, Erweiterbarkeit |
| `documentation/deployment.md` | PyPI-Veröffentlichung, CI/CD, Versionierung, Rollback |
| `documentation/development.md` | Setup, Code-Struktur, Python-Konventionen, MR-Workflow |

## Beispiele

### Erinnerung mit Idempotency-Key speichern

```python
import os
from synapse_memory import Synapse

synapse = Synapse(
    base_url="https://synapse.schaefer.zone",
    mind_key=os.environ["SYNAPSE_MIND_KEY"],
)

synapse.memory.store(
    category="fact",
    content="User hat am 2025-06-25 ein Meeting mit Anna",
    key="meeting_anna",
    priority="high",
    source="user",
    idempotency_key="meeting-anna-2025-06-25",  # Retries erzeugen kein Duplikat
)
```

### Inkrementeller Sync von Erinnerungen

```python
from datetime import datetime, timedelta

since = (datetime.utcnow() - timedelta(hours=1)).isoformat()
changed = synapse.memory.diff(since)
print(f"Seit {since}: {len(changed)} Änderungen")
```

### Chat mit Menschen durchführen

```python
# Auf neue Nachrichten vom Menschen warten
msgs = synapse.chat.poll()
for msg in msgs["messages"]:
    print(f"Mensch: {msg['content']}")
    synapse.chat.reply(f"Verstanden: {msg['content']}")
```

### Webhook für neue Erinnerungen registrieren

```python
synapse.webhooks.register(
    url="https://my-app.com/webhook",
    events=["memory.created", "memory.updated"],
)
```

### Fehlerbehandlung

```python
from synapse_memory import Synapse, SynapseError

try:
    synapse.memory.search("insolvenz")
except SynapseError as e:
    if e.status == 401:
        print("Mind Key ungültig – neu laden")
    elif e.status == 429:
        print("Rate Limit – Backoff")
    elif e.status == 0:
        print(f"Netzwerkfehler: {e}")
    else:
        print(f"Sonstiger Fehler ({e.status}): {e.body}")
```

## Roadmap

Die weitere Entwicklung konzentriert sich auf vier Stränge: (1) Ausbau der
Testabdeckung mit `requests_mock` für deterministische Tests, die aktuell
noch minimal ist; (2) optionale Async-Implementierung über `aiohttp`, die
das `async`-Extra bereits vorhält, aber noch nicht alle Endpunkte abdeckt;
(3) Dataclasses für alle Parameter-Objekte statt `**kwargs`, was die IDE-
Autovervollständigung verbessert und Typprüfung mit `mypy` erleichtert;
(4) optionale Pydantic-Integration für Validierung von Response-JSONs,
die Anwendern eine zusätzliche Validierungsschicht bietet. Konkrete
Releases werden in `CHANGELOG.md` nachverfolgt, das mit dem PyPI-Paket
mitgeliefert wird.
