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.
- clear_derived_state() None[source]¶
Clear every object-derived live slice and persistent cache. Flush-scale operations only; single-object edits should use invalidate_object instead.
- 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.
- invalidate_object(object_id: str) int[source]¶
Drop the caption and relation cache entries that mention one object. This is the mutation-path invalidation: an operator edit changes one object, so only that object’s caption and the pairs it participates in can be stale. Wiping both caches wholesale on every edit (and flushing them to disk) would throw away hundreds of unrelated LLM answers per keystroke. Returns entries dropped; callers decide when a disk flush is worth it.
- 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.