scene_service.scene_graph.store¶
Live scene graph and persistent caption/relation caches.
Two single-threaded asyncio writers own disjoint slices:
the geometric loop updates nodes and deterministic geometric edges; and
the model builder updates semantic edges that geometry cannot decide.
get_snapshot() combines both slices for MCP and web consumers.
Cache persistence uses simple JSON files so the system can survive restarts without re-calling the LLM for every object pair. Only the caption + relation caches are persisted; the live node/edge slices are rebuilt each tick. Cache I/O failures are swallowed — the worst case is a redundant LLM call.
Classes
|
In-memory live graph (two writer slices) + on-disk JSON caches. |
- class scene_service.scene_graph.store.SceneGraphStore(cache_dir: str = '/data/robonix/scene_graph/cache', map_id: str | None = None)[source]¶
Bases:
objectIn-memory live graph (two writer slices) + on-disk JSON caches.
- get_cached_caption(node: SceneGraphNode) str | None[source]¶
- get_cached_relation(a: SceneGraphNode, b: SceneGraphNode, hint: GeometryHint, semantic_only: bool = False) SceneGraphEdge | None[source]¶
- get_geometric_edges() list[SceneGraphEdge][source]¶
Current geometric (contact/containment) edges, owned by the fast loop. The builder reads these to skip pairs geometry already decided, spending LLM budget only on the residual.
- get_semantic_edges() list[SceneGraphEdge][source]¶
Current semantic edges — the builder reads these to carry edges forward across rebuilds (hysteresis).
- get_snapshot() SceneGraphSnapshot | None[source]¶
Compose the live graph for read-only consumers (MCP, web).
Nodes come from the geometric loop; edges are the geometric slice followed by the semantic slice. The builder skips pairs geometry already decided, so the slices are disjoint by construction; the dedup on (source, target, relation) — geometric wins — only guards the ~1 s startup window before the geometric debounce emits, and keeps distinct relations on the same pair (e.g. geometric on_top_of + semantic attached_to). Returns None before the first geometric tick has populated anything, preserving the prior “no snapshot yet” contract for callers.
- prune_relations(live_object_ids: set[str]) int[source]¶
Drop cached edges with an endpoint no longer in the registry. Returns how many were evicted. Complements put_cached_relation’s keep-latest-per-pair eviction: that bounds growth across an object’s moves, this bounds it across object departures. Called by the builder each rebuild before flushing to disk.
- put_cached_caption(node: SceneGraphNode) None[source]¶
- put_cached_relation(a: SceneGraphNode, b: SceneGraphNode, hint: GeometryHint, edge: SceneGraphEdge, semantic_only: bool = False) None[source]¶
- set_geometric(nodes: list[SceneGraphNode], edges: list[SceneGraphEdge]) None[source]¶
Replace the geometric slice (nodes + contact/containment edges). The dict/list references are swapped in one step, so a concurrent get_snapshot() never sees a half-updated geometric layer. Called by the fast geometric loop each tick.
- set_semantic_edges(edges: list[SceneGraphEdge]) None[source]¶
Replace the semantic (LLM-inferred) edge slice. Called by the builder once per rebuild, after residual inference + hysteresis.