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,
|
guard). The CLI is a print-only command -- no event writes,
|
||||||
no state mutation. compute_and_emit() runs in S4's offline pass instead
|
no state mutation. compute_and_emit() runs in S4's offline pass instead
|
||||||
(see `iai_mcp.s4.run_offline_pass`).
|
(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()
|
Uses the daemon's topology handler via the control socket so the CLI
|
||||||
graph, _assignment, _rich_club = build_runtime_graph(store)
|
never needs to instantiate a local store (avoids lancedb/Qdrant deps
|
||||||
snap = compute_topology_snapshot(graph)
|
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:
|
def _fmt(v) -> str:
|
||||||
if v is None:
|
if v is None:
|
||||||
|
|
|
||||||
|
|
@ -433,7 +433,31 @@ def check_f_lancedb_readable() -> CheckResult:
|
||||||
Open a MemoryStore handle. The constructor opens the lancedb connection;
|
Open a MemoryStore handle. The constructor opens the lancedb connection;
|
||||||
if the directory is corrupt / permission-denied / disk-full, the
|
if the directory is corrupt / permission-denied / disk-full, the
|
||||||
constructor raises and we report FAIL.
|
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:
|
try:
|
||||||
from iai_mcp.store import MemoryStore
|
from iai_mcp.store import MemoryStore
|
||||||
|
|
||||||
|
|
@ -443,11 +467,24 @@ def check_f_lancedb_readable() -> CheckResult:
|
||||||
True,
|
True,
|
||||||
"opens without error",
|
"opens without error",
|
||||||
)
|
)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
raise
|
||||||
|
except SystemExit:
|
||||||
|
raise
|
||||||
except Exception as e: # noqa: BLE001 — surface any open failure
|
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(
|
return CheckResult(
|
||||||
"(f) lancedb store readable",
|
"(f) lancedb store readable",
|
||||||
False,
|
False,
|
||||||
f"open failed: {type(e).__name__}: {e}",
|
f"open failed: {exc_name}: {e}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1289,6 +1289,52 @@ class QdrantStore:
|
||||||
except Exception:
|
except Exception:
|
||||||
return pd.DataFrame(columns=["src", "dst", "edge_type", "weight", "updated_at"])
|
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
|
# ------------------------------------------------------------------ db shim
|
||||||
|
|
||||||
class _DbShim:
|
class _DbShim:
|
||||||
|
|
@ -1311,6 +1357,8 @@ class QdrantStore:
|
||||||
def to_pandas(self) -> pd.DataFrame:
|
def to_pandas(self) -> pd.DataFrame:
|
||||||
if self._name == EDGES_TABLE:
|
if self._name == EDGES_TABLE:
|
||||||
return self._store.edges_as_dataframe()
|
return self._store.edges_as_dataframe()
|
||||||
|
elif self._name == RECORDS_TABLE:
|
||||||
|
return self._store.records_as_dataframe()
|
||||||
elif self._name == EVENTS_TABLE:
|
elif self._name == EVENTS_TABLE:
|
||||||
return pd.DataFrame()
|
return pd.DataFrame()
|
||||||
return pd.DataFrame()
|
return pd.DataFrame()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue