diff --git a/hermes_state.py b/hermes_state.py index 7242e6b17..71a89a286 100644 --- a/hermes_state.py +++ b/hermes_state.py @@ -744,8 +744,18 @@ class SessionDB: # Trigram FTS5 for CJK/substring search try: cursor.execute("SELECT * FROM messages_fts_trigram LIMIT 0") - except sqlite3.OperationalError: - cursor.executescript(FTS_TRIGRAM_SQL) + except sqlite3.OperationalError as exc: + if "no such table" not in str(exc).lower(): + raise + try: + cursor.executescript(FTS_TRIGRAM_SQL) + except sqlite3.OperationalError as fts_exc: + err = str(fts_exc).lower() + if "fts5" not in err and "no such module" not in err: + raise + # Same FTS5-unavailable cause already warned about above for + # messages_fts; the trigram table is an additional CJK index, + # so just degrade silently here. CJK search falls back to LIKE. self._conn.commit() diff --git a/tests/test_hermes_state.py b/tests/test_hermes_state.py index d14f065ae..a6c33a5cb 100644 --- a/tests/test_hermes_state.py +++ b/tests/test_hermes_state.py @@ -11,12 +11,16 @@ class _NoFtsCursor(sqlite3.Cursor): """Simulate a SQLite build without the fts5 module.""" def execute(self, sql, parameters=()): - if sql.strip() == "SELECT * FROM messages_fts LIMIT 0": - raise sqlite3.OperationalError("no such table: messages_fts") + probe = sql.strip() + if probe in ( + "SELECT * FROM messages_fts LIMIT 0", + "SELECT * FROM messages_fts_trigram LIMIT 0", + ): + raise sqlite3.OperationalError("no such table: " + probe.split()[-3]) return super().execute(sql, parameters) def executescript(self, sql_script): - if "CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5" in sql_script: + if "USING fts5" in sql_script: raise sqlite3.OperationalError("no such module: fts5") return super().executescript(sql_script) @@ -167,6 +171,10 @@ class TestSessionLifecycle: db = SessionDB(db_path=tmp_path / "state.db") try: assert db._fts_enabled is False + # Neither FTS5 virtual table should have been created on a build + # that lacks the fts5 module — both init paths must degrade. + assert db._fts_table_exists("messages_fts") is False + assert db._fts_table_exists("messages_fts_trigram") is False db.create_session(session_id="s1", source="cli") db.append_message("s1", role="user", content="hello from sqlite without fts")