No description
End-to-end smoke against the live coolify memory stack surfaced three
gaps between the spec and what memory-api actually writes:
1. memory-api wraps the /ingest payload under `metadata.*` in Qdrant —
our domain fields (fact_type, scope.states, …) don't live at the top
of the payload, they're nested. `build_qdrant_filter` now auto-prefixes
any non-top-level key with `metadata.`. Callers can write
`{"fact_type": "legal"}` and it just works; top-level fields
(`agent_id`, `memory_type`, `source`, …) pass through unprefixed.
2. The deployed BGE-M3 TEI image doesn't serve /embed_sparse (returns
424 Failed Dependency). Stored points have `has_sparse=false`.
`BGEClient.embed_sparse` now returns `{}` on 4xx and logs a warning;
`QdrantReader.hybrid_query` falls back to a dense-only query when
sparse is empty. RRF fusion is skipped in that path.
3. `scripts/smoke.sh` had a missing `shift` after reading the limit
positional arg — caused arg leakage onto the CLI (`--limit 5 5`).
The cleanup hint also referenced a stale agent_id; now reads from
$ARTENSCHUTZ_AGENT_ID.
Smoke is now green end-to-end: 18 records ingested across bnatschg /
mhbasp / biotopwertliste(BY) / state-berlin under
agent_id=gruenstifter_smoketest, hybrid + payload-filter searches all
return hits. 24/24 unit tests pass.
Companion fixes pushed to github.com/machine-machine/agent.memory.system:
d0e9529 fix: /memory/store passed wrong kwarg name to AgentMemory
ebc896c fix: don't close caller-supplied clients in AgentMemory.close()
|
||
|---|---|---|
| scripts | ||
| sources | ||
| src/artenschutz_router | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| COOLIFY-DEPLOY.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| pyproject.toml | ||
| README.md | ||
artenschutz-router
Sidecar service for Artenschutzgutachten domain queries against
agent.memory.system. m2-memory stays untouched.
- Writes proxy memory-api
/memory/store— the existing endpoint accepts arbitrarymetadata: dict, so our Fact / Exemplar payloads slot in. - Reads go directly to Qdrant for rich payload-filtered hybrid queries (dense + sparse via the existing BGE-M3 TEI service).
See .planning/notes/artenschutz-digest-concept.md in GST-DATA for the
draft concept that birthed this.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/health |
Live-probe Qdrant, BGE-M3, memory-api |
POST |
/search/generic |
Hybrid search (or scroll if no query); arbitrary payload filters |
POST |
/ingest |
Push a Fact or Exemplar record |
Domain-specific endpoints (/facts/search, /exemplar/search,
/mitigation/search) are deferred to a later phase — they will be thin
wrappers over /search/generic.
Quick start (local dev)
cp .env.example .env
# Edit .env to point QDRANT_URL / BGE_TEI_URL / MEMORY_API_URL at your stack
docker compose up --build
curl http://localhost:8080/health
If you're targeting the production Coolify memory stack, leave the default
container-name URLs and ensure the coolify Docker network is joined.
Running ingest
# After you've placed authoritative source files into sources/...
artenschutz-ingest --source bnatschg --router-url http://localhost:8080
artenschutz-ingest --source mhbasp --router-url http://localhost:8080
artenschutz-ingest --source biotopwertliste --router-url http://localhost:8080
artenschutz-ingest --source state-berlin --router-url http://localhost:8080
See sources/README.md for which files each source expects.
Tests
pip install -e .[dev]
pytest
Architecture
m2-gpt agents
↓
artenschutz-router (this repo)
├─ /ingest ─→ memory-api /memory/store (unchanged)
└─ /search/generic ─→ Qdrant /points/query + BGE-M3 TEI /embed[_sparse]
↓
agent_memory collection (Qdrant)