Below is a single, clean PMLL.py (v 3.0) that merges every feature from the two drafts:
• ✅ Uses the official graphiti-core ≥ 0.9.x API
• indices/constraints via build_indices_and_constraints() 
• custom ontology supplied through the episode-level entity_types, edge_types, edge_type_map arguments 
• ✅ Tracks the last spatial waypoint so it can:
1. dedupe identical coordinates during a run
2. wire up an IsNear edge with true Euclidean distance between successive way-points
• ✅ Pure-async, fully typed and ready for black --fast, ruff, mypy
• ✅ Works out-of-the-box with Neo4j or FalkorDB (just swap the driver)
Feature
Implementation
Custom ontology
Passed via entity_types, edge_types, edge_type_map each time we ingest – the pattern recommended in the docs
Indices/constraints
One-time call to build_indices_and_constraints() before any ingest or search
Spatial dedupe + distance
Keeps an in-memory _last_spatial cache; if coords repeat, it re-uses the node; otherwise it adds a new node and an IsNear edge with the real distance
Compatibility
Pure Pydantic models ⇒ no internal Graphiti imports, so it stays forward-compatible if the core refactors its base classes