Skip to content

vis kickstart#1637

Open
leshy wants to merge 5 commits intodevfrom
feat/memory2-vis-kickstart
Open

vis kickstart#1637
leshy wants to merge 5 commits intodevfrom
feat/memory2-vis-kickstart

Conversation

@leshy
Copy link
Contributor

@leshy leshy commented Mar 21, 2026

memory vis kickstart branch

@leshy leshy mentioned this pull request Mar 21, 2026
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 21, 2026

Greptile Summary

This PR kickstarts a memory visualization layer: it adds a TestVisualizer test scaffold for querying the go2_bigoffice replay database (text search, pose-radius search, object detection, path reconstruction), extends test_e2e.py with CLIP image-embedding and text-search tests, adds a module-scoped clip fixture to the shared conftest, and widens the SqliteVectorStore error handling from dict-guard checks to exception catching. A large (~191 MB) LFS-tracked replay database is also added.

Key issues found:

  • vectorstore/sqlite.py: The broad except sqlite3.OperationalError: pass/return [] will silently swallow legitimate errors (DB locked, corrupt pages, etc.) that the previous _tables dict guard never hid. The catch should be narrowed to "no such table" errors only.
  • test_visualizer.py: det.ts in test_detect_objects should be obs.ts — detection objects don't carry timestamps, causing an AttributeError at runtime. Also missing the @pytest.mark.tool marker (causing CI failures when the LFS DB is absent), has a double-teardown in the store fixture, and a duplicate assertion in test_search_reconstruct_full_path.
  • conftest.py: Duplicate return statement in the blob_store fixture (line 96 is unreachable dead code).

Confidence Score: 3/5

  • Not safe to merge as-is: the visualizer tests have a runtime AttributeError bug and will fail in CI without the @pytest.mark.tool guard; the vector store change silently swallows real DB errors.
  • The det.ts AttributeError in test_detect_objects is a definite runtime failure. The missing @pytest.mark.tool marker will break standard CI runs that don't have the LFS database. The overly broad exception catch in SqliteVectorStore is a regression in observability. Three concrete bugs across the key changed files warrant fixes before merge.
  • dimos/memory2/test_visualizer.py (runtime bug + missing marker + fixture teardown) and dimos/memory2/vectorstore/sqlite.py (overly broad exception catch).

Important Files Changed

Filename Overview
dimos/memory2/vectorstore/sqlite.py Replaces specific _tables dict guards with broad sqlite3.OperationalError catches — silently swallows real errors (locked DB, corrupt pages) in both search and delete.
dimos/memory2/conftest.py Adds a module-scoped clip CLIP fixture; has a duplicate return statement at line 96 (dead code) in the blob_store fixture.
dimos/memory2/test_visualizer.py New visualizer test scaffold; has det.ts bug (should be obs.ts), duplicate assertion, double teardown in the store fixture, and missing @pytest.mark.tool marker.
dimos/memory2/test_e2e.py Adds TestEmbedImages tests for CLIP embedding and text-search over stored frames; correctly marked with @pytest.mark.tool and functionally sound.
dimos/memory/type.py New placeholder file containing only the Apache license header — no implementation yet.
data/.lfs/go2_bigoffice.db.tar.gz Adds a large (~191 MB) LFS-tracked replay database used by the visualizer and e2e tests.

Sequence Diagram

sequenceDiagram
    participant T as Test / Visualizer
    participant S as SqliteStore
    participant VS as SqliteVectorStore
    participant CLIP as CLIPModel
    participant VLM as MoondreamVlModel

    T->>S: stream("color_image", Image)
    T->>CLIP: embed_text("a door")
    CLIP-->>T: Embedding (query vector)

    T->>S: stream("color_image_embedded", Image).search(query, k=10)
    S->>VS: search("color_image_embedded", query, k=10)
    Note over VS: try execute SELECT ... MATCH<br/>except OperationalError → []
    VS-->>S: [(rowid, similarity), ...]
    S-->>T: Observation[]

    opt Object detection path
        T->>VLM: query_detections(obs.data, "bottle")
        VLM-->>T: DetectionResult[]
        T->>S: lidar.at(obs.ts).first().data
        S-->>T: PointCloud2
    end

    opt Embed & save path
        T->>S: video.transform(QualityWindow).transform(EmbedImages(clip)).save(embedded)
        loop for each downsampled frame
            S->>CLIP: embed_image(frame)
            CLIP-->>S: Embedding
            S->>VS: put("color_image_embedded", key, embedding)
        end
    end
Loading

Last reviewed commit: "vis kickstart"

@pytest.fixture(params=["file_blob_store", "sqlite_blob_store"])
def blob_store(request: pytest.FixtureRequest) -> BlobStore:
return request.getfixturevalue(request.param)
return request.getfixturevalue(request.param)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Duplicate return statement is dead code

Line 96 is an exact copy of line 95. The second return can never be reached and should be removed.

Suggested change
return request.getfixturevalue(request.param)

(Delete the duplicate line entirely.)

Comment on lines +96 to +97
except sqlite3.OperationalError:
return []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Overly broad OperationalError catch silently hides real failures

The original guard (if stream_name not in self._tables: return []) only suppressed the "stream hasn't been written yet" case. The replacement catches every sqlite3.OperationalError, which includes database-is-locked errors, corrupt pages, out-of-disk-space errors, and malformed SQL — all of which would now silently return [] or no-op instead of surfacing to the caller.

Consider narrowing the catch to the specific "no such table" message:

        try:
            rows = self._conn.execute(
                f'SELECT rowid, distance FROM "{stream_name}_vec" WHERE embedding MATCH ? AND k = ?',
                (json.dumps(vec), k),
            ).fetchall()
        except sqlite3.OperationalError as e:
            if "no such table" in str(e).lower():
                return []
            raise

The same pattern applies to the delete method (lines 102–105).

Comment on lines +107 to +108
lidar.at(det.ts).first().data
) # get a related lidar frame (can try and project)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 det.ts should likely be obs.ts

det is a detection result returned by vlm.query_detections(obs.data, "bottle"). Detection objects represent spatial regions within a single image frame, so they don't carry a per-frame timestamp — ts lives on the parent observation (obs). Calling det.ts will raise an AttributeError at runtime.

Suggested change
lidar.at(det.ts).first().data
) # get a related lidar frame (can try and project)
lidar.at(obs.ts).first().data

Comment on lines +114 to +115
assert obs.pose is not None
assert obs.pose is not None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Duplicate assertion

Line 115 is an identical copy of line 114. The second assert is dead code.

Suggested change
assert obs.pose is not None
assert obs.pose is not None
def test_search_reconstruct_full_path(self, store: SqliteStore) -> None:
for obs in store.streams.color_image_embedded:
assert obs.pose is not None

Comment on lines +34 to +39
@pytest.fixture(scope="module")
def store() -> Iterator[SqliteStore]:
db = SqliteStore(path=str(DB_PATH))
with db:
yield db
db.stop()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Double teardown: db.stop() called after context manager already closes the store

The with db: block invokes __exit__, which should close the connection and call stop() internally. Calling db.stop() again on line 39 after the with block exits risks a double-close on the underlying SQLite connection, which can raise exceptions or silently corrupt state.

Suggested change
@pytest.fixture(scope="module")
def store() -> Iterator[SqliteStore]:
db = SqliteStore(path=str(DB_PATH))
with db:
yield db
db.stop()
@pytest.fixture(scope="module")
def store() -> Iterator[SqliteStore]:
with SqliteStore(path=str(DB_PATH)) as db:
yield db

# Actual prerequisite for this is a good python API


class TestVisualizer:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 TestVisualizer is missing the @pytest.mark.tool marker

All integration tests in test_e2e.py that depend on the large replay database (go2_bigoffice.db) are guarded with @pytest.mark.tool. TestVisualizer hits the same database but lacks this marker, so these tests will run in a standard pytest invocation and fail if the LFS-backed database is not present.

Suggested change
class TestVisualizer:
@pytest.mark.tool
class TestVisualizer:

leshy added 4 commits March 21, 2026 16:10
- SqliteVectorStore: only catch "no such table" OperationalError, re-raise others
- test_visualizer: fix det.ts → obs.ts, add @pytest.mark.tool, remove double teardown and duplicate assertion
- conftest: remove unreachable duplicate return
…ypes

- EmbeddingModel/CLIPModel: @overload so single-arg returns Embedding, multi-arg returns list
- conftest: cast getfixturevalue returns to correct Store/BlobStore types
- MobileCLIPModel, TorchReIDModel: add matching overloads for embed/embed_text
- Remove now-redundant cast in memory/embedding.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant