fix: support Qdrant backend on non-AVX CPUs
- doctor: skip LanceDB check when qdrant_storage/ dir detected - topology: use daemon socket instead of local store (avoids lancedb crash) - qdrant_store: add records_as_dataframe() + wire into _TableShim so build_runtime_graph() works with Qdrant (was returning empty)
This commit is contained in:
parent
01e5903035
commit
8492719735
3 changed files with 110 additions and 8 deletions
|
|
@ -1499,14 +1499,31 @@ def cmd_topology(args: argparse.Namespace) -> int:
|
|||
guard). The CLI is a print-only command -- no event writes,
|
||||
no state mutation. compute_and_emit() runs in S4's offline pass instead
|
||||
(see `iai_mcp.s4.run_offline_pass`).
|
||||
"""
|
||||
from iai_mcp.retrieve import build_runtime_graph
|
||||
from iai_mcp.sigma import compute_topology_snapshot
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore()
|
||||
graph, _assignment, _rich_club = build_runtime_graph(store)
|
||||
snap = compute_topology_snapshot(graph)
|
||||
Uses the daemon's topology handler via the control socket so the CLI
|
||||
never needs to instantiate a local store (avoids lancedb/Qdrant deps
|
||||
on non-AVX CPUs or when QDRANT_URL is only in systemd env).
|
||||
"""
|
||||
snap = _send_socket_request({"type": "topology"})
|
||||
if snap is None:
|
||||
print("ERROR: daemon unreachable", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
def _fmt(v) -> str:
|
||||
if v is None:
|
||||
return "insufficient_data"
|
||||
if isinstance(v, float):
|
||||
return f"{v:.4f}"
|
||||
return str(v)
|
||||
|
||||
print(f"C: {_fmt(snap.get('C'))}")
|
||||
print(f"L: {_fmt(snap.get('L'))}")
|
||||
print(f"sigma: {_fmt(snap.get('sigma'))}")
|
||||
print(f"communities: {_fmt(snap.get('community_count'))}")
|
||||
print(f"rich_club_ratio: {_fmt(snap.get('rich_club_ratio'))}")
|
||||
print(f"N: {_fmt(snap.get('N'))}")
|
||||
print(f"regime: {_fmt(snap.get('regime'))}")
|
||||
return 0
|
||||
|
||||
def _fmt(v) -> str:
|
||||
if v is None:
|
||||
|
|
|
|||
|
|
@ -433,7 +433,31 @@ def check_f_lancedb_readable() -> CheckResult:
|
|||
Open a MemoryStore handle. The constructor opens the lancedb connection;
|
||||
if the directory is corrupt / permission-denied / disk-full, the
|
||||
constructor raises and we report FAIL.
|
||||
|
||||
Skips gracefully when Qdrant is the active backend or lancedb is
|
||||
unavailable (non-AVX CPU, etc.) — returns PASS with skip reason.
|
||||
"""
|
||||
from iai_mcp.store import _use_qdrant
|
||||
|
||||
if _use_qdrant():
|
||||
return CheckResult(
|
||||
"(f) lancedb store readable",
|
||||
True,
|
||||
"skipped (Qdrant backend active)",
|
||||
)
|
||||
|
||||
# Heuristic: qdrant_storage/ directory present → Qdrant is the active
|
||||
# backend even if QDRANT_URL is not set in the current shell (e.g.
|
||||
# systemd service provides it but interactive shell does not).
|
||||
env_path = os.environ.get("IAI_MCP_STORE")
|
||||
store_root = Path(env_path) if env_path else (Path.home() / ".iai-mcp")
|
||||
if (store_root / "qdrant_storage").exists():
|
||||
return CheckResult(
|
||||
"(f) lancedb store readable",
|
||||
True,
|
||||
"skipped (Qdrant backend detected via qdrant_storage/)",
|
||||
)
|
||||
|
||||
try:
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
|
|
@ -443,11 +467,24 @@ def check_f_lancedb_readable() -> CheckResult:
|
|||
True,
|
||||
"opens without error",
|
||||
)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except SystemExit:
|
||||
raise
|
||||
except Exception as e: # noqa: BLE001 — surface any open failure
|
||||
# Non-AVX CPUs may crash in lancedb native libs (SIGILL); treat as
|
||||
# unavailable rather than a store corruption failure.
|
||||
exc_name = type(e).__name__
|
||||
if exc_name == "IllegalInstruction" or "illegal" in str(e).lower():
|
||||
return CheckResult(
|
||||
"(f) lancedb store readable",
|
||||
True,
|
||||
f"skipped (lancedb unavailable on this CPU: {exc_name})",
|
||||
)
|
||||
return CheckResult(
|
||||
"(f) lancedb store readable",
|
||||
False,
|
||||
f"open failed: {type(e).__name__}: {e}",
|
||||
f"open failed: {exc_name}: {e}",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1289,6 +1289,52 @@ class QdrantStore:
|
|||
except Exception:
|
||||
return pd.DataFrame(columns=["src", "dst", "edge_type", "weight", "updated_at"])
|
||||
|
||||
def records_as_dataframe(self) -> "pd.DataFrame":
|
||||
"""Return all records from the records collection as a pandas DataFrame."""
|
||||
try:
|
||||
records = self.all_records()
|
||||
if not records:
|
||||
return pd.DataFrame(columns=[
|
||||
"id", "tier", "literal_surface", "embedding",
|
||||
"community_id", "centrality", "pinned",
|
||||
"tags_json", "language", "aaak_index",
|
||||
"stability", "difficulty", "last_reviewed",
|
||||
"never_decay", "never_merge", "detail_level",
|
||||
"s5_trust_score", "structure_hv",
|
||||
])
|
||||
rows = []
|
||||
for r in records:
|
||||
rows.append({
|
||||
"id": str(r.id),
|
||||
"tier": r.tier,
|
||||
"literal_surface": r.literal_surface,
|
||||
"embedding": r.embedding,
|
||||
"community_id": str(r.community_id) if r.community_id else None,
|
||||
"centrality": r.centrality,
|
||||
"pinned": r.pinned,
|
||||
"tags_json": r.tags_json if hasattr(r, "tags_json") else "[]",
|
||||
"language": r.language,
|
||||
"aaak_index": r.aaak_index,
|
||||
"stability": r.stability,
|
||||
"difficulty": r.difficulty,
|
||||
"last_reviewed": str(r.last_reviewed) if r.last_reviewed else None,
|
||||
"never_decay": r.never_decay,
|
||||
"never_merge": r.never_merge,
|
||||
"detail_level": r.detail_level,
|
||||
"s5_trust_score": r.s5_trust_score,
|
||||
"structure_hv": r.structure_hv.hex() if r.structure_hv else "",
|
||||
})
|
||||
return pd.DataFrame(rows)
|
||||
except Exception:
|
||||
return pd.DataFrame(columns=[
|
||||
"id", "tier", "literal_surface", "embedding",
|
||||
"community_id", "centrality", "pinned",
|
||||
"tags_json", "language", "aaak_index",
|
||||
"stability", "difficulty", "last_reviewed",
|
||||
"never_decay", "never_merge", "detail_level",
|
||||
"s5_trust_score", "structure_hv",
|
||||
])
|
||||
|
||||
# ------------------------------------------------------------------ db shim
|
||||
|
||||
class _DbShim:
|
||||
|
|
@ -1311,6 +1357,8 @@ class QdrantStore:
|
|||
def to_pandas(self) -> pd.DataFrame:
|
||||
if self._name == EDGES_TABLE:
|
||||
return self._store.edges_as_dataframe()
|
||||
elif self._name == RECORDS_TABLE:
|
||||
return self._store.records_as_dataframe()
|
||||
elif self._name == EVENTS_TABLE:
|
||||
return pd.DataFrame()
|
||||
return pd.DataFrame()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue