Python SDK for the connordb engine (machine-only, gRPC). Atomic multi-modal commits, async embedding freshness, hybrid search.
Project description
connordb — Python SDK
Python SDK for ConnorDB — the system of record for agent memory. One ACID engine that gives a swarm of agents durable, auditable, tamper-evident memory: atomic multi-modal commit (row + BM25 + dense vector + sparse + typed payload under one fsync), in-process embed worker, LSN-watermark read-your-writes, server-side hybrid search. It also collapses the 5-service RAG stack (vector DB + document DB + embed service + queue + read-your-writes cache + retry + reranker) into that single engine. The SDK talks to a running engine over gRPC (the canonical machine transport, ADR 0006); the previous HTTP client was removed in v1.0.0.
A single GrpcClient.insert(...) call commits row + BM25 + dense vector + sparse + typed payload under one fsync; the embed worker runs server-side off the commit path; wait_for_embed(lsn) blocks on the LSN watermark; search_hybrid(...) fuses the indexes in one round-trip.
Install
pip install connordb # full SDK (grpcio + protobuf)
Or in dev mode:
cd clients/connordb-py
pip install -e ".[dev]"
pytest
Quick start
from connordb import GrpcClient
with GrpcClient(target="localhost:50051", api_key="…") as c:
# Atomic multi-modal commit.
lsn = c.insert(
id="doc-1",
text="ship the patch",
embedding=[0.1, 0.2, 0.3, 0.4], # match the engine's --embedding-dim
payload={"category": "urgent"},
collection="notes",
)
# Read-your-writes on the vector index.
c.wait_for_embed(lsn)
# Hybrid search: BM25 + dense fused via RRF.
hits = c.search_hybrid(query="patch", k=10, include_text=True)
for h in hits:
print(h["rank"], h["id"], h.get("distance") or h.get("score"))
Surface
The full method list lives in src/connordb/grpc.py.
The canonical wire contract is the proto under
proto/connordb/v1/
and the QueryPlan AST in
docs/query_grammar.schema.json
(also discoverable at runtime via GrpcClient.get_grammar()).
Agent-facing API (selected)
| Method | RPC | Notes |
|---|---|---|
insert(id, text, embedding=..., payload=..., collection=...) |
EngineService.Insert |
Atomic multi-modal commit. |
insert_if_unchanged(id, expected_lsn, text, embedding=...) |
EngineService.InsertIfLsnMatches |
CAS by LSN (ADR 0013). |
search_hybrid(query, k, include_text=...) |
EngineService.SearchHybrid |
BM25 + dense + sparse RRF fused server-side (ADR 0004). |
wait_for_embed(lsn) / wait_for_projection(name, lsn) |
EngineService.EmbedWait / WaitForProjection |
Read-your-writes watermarks (ADR 0005, 0010). |
snapshot_as_of(as_of_lsn=...) |
EngineService.SnapshotAsOf |
Whole-tenant time travel (ADR 0014). |
subscribe(...) |
EngineService.Subscribe |
Push-based change feed (ADR 0008). |
cluster_topology() -> ClusterTopology |
ClusterService.ClusterTopology |
ADR 0016 Phase 7: epoch + leader + per-member view (id, addr, in_sync, last_ack_lsn). Target the cluster-internal port (--cluster-port), not --grpc-port. |
record_tool_call(tool_name, args, result, cited_lsns=...) -> int |
EngineService.RecordToolCall |
ADR 0017 Phase A: tamper-evident record of an external tool invocation. Returns the LSN of the ToolCall causal frame. |
record_decision(decision_id, cited_lsns, summary) -> int |
EngineService.RecordDecision |
ADR 0017 Phase A: agent decision with verified citations. Cross-tenant cites raise PermissionDenied. |
traceback(root_lsn, max_depth=5) -> TraceGraph |
EngineService.Traceback |
ADR 0017 Phase A: walk the citation graph rooted at root_lsn. Returns nodes + edges in BFS order. |
endorse_row(target_lsn) -> int |
EngineService.EndorseRow |
ADR 0018 Phase A: durably endorse another agent's row. Idempotent on (target_lsn, caller_agent_id); self-endorse raises PermissionDenied. Returns the LSN of the Endorse belief frame. |
dispute_row(target_lsn, reason) -> int |
EngineService.DisputeRow |
ADR 0018 Phase A: durably dispute another agent's row with a free-form reason (max 1024 bytes). Multiple disputes per row coexist by design. Returns the LSN of the Dispute belief frame. |
set_storage_mode(mode) |
EngineService.SetStorageMode |
ADR 0019 Phase B: switch the tenant between "rowstore" and "dual". "field" reserved for Phase C. |
field_insert(id, text, payload, vector=...) |
EngineService.FieldInsert |
ADR 0019 §4: mirrored rowstore + field deformation under one fsync. Returns row_lsn + field_lsn. |
field_sample(region, k, basis_id=..., as_of_lsn=...) |
EngineService.ExecutePlan (FieldSample stage) |
ADR 0020 §4: sample k coords from a Region (anchor / anchor_lsn / tile / union / intersection / difference). Returns samples + aggregate_quality. |
field_seal() |
EngineService.FieldSeal |
ADR 0019 §4: freeze the current field epoch. |
field_evolve_basis(seed=...) |
EngineService.FieldEvolveBasis |
ADR 0019 §4: explicit audited basis relearn. |
v1.8.0 — continuous-field storage (ADR 0019 / 0020 / 0021)
Tenants can opt into the continuous-field projection alongside the rowstore. Five new methods, one new builder class, two new response shapes:
from connordb import GrpcClient, Region
with GrpcClient("localhost:50051", api_key="…") as c:
# 1. Opt the tenant into dual-mode storage.
c.set_storage_mode("dual")
# 2. Insert a row — committed atomically into rowstore + field.
receipt = c.field_insert(
id="doc-1",
text="hello world",
payload=b"...", # opaque blob driving the deformation
vector=[0.1] * 384,
)
field_lsn = receipt["field_lsn"]
# 3. Sample the latent space addressed by a region AST.
region = Region.union([
Region.anchor_lsn(field_lsn, radius=0.25),
Region.tile("tile-east-1"),
])
out = c.field_sample(region=region, k=16)
for s in out["samples"]:
print(s["field_coord_id"], s["quality"]["residual_norm"])
print(out["aggregate_quality"]) # ADR 0021 §6 summary
search_hybrid(...) and execute_plan(...) both grew an optional
structured return path: pass with_field_hits=True to search_hybrid
when a plan included a FieldSample stage with Disjoint fusion;
execute_plan surfaces field_hits + aggregate_quality
automatically when the response carries them. Every TextHit /
VectorHit / FieldHit now exposes a source discriminator —
"rowstore" (default for legacy hits), "field", or "mixed_fused".
The tenant_id kwarg on every field-mode method is a forward-compat
explicit override (sent as x-tenant-id metadata). The engine
derives the active tenant from the API-key auth context; the
override is validated against it.
v1.3.0 — multi-agent belief primitives (ADR 0018 Phase A)
The audit chain becomes the team's shared belief register. Two new methods let agents durably mark what they have validated together without writing near-duplicate rows, and durably challenge what they disagree on without silently overwriting it:
from connordb import GrpcClient
# Two agents both connected to the same tenant.
with GrpcClient("localhost:50051", api_key="…", agent_id="planner") as p, \
GrpcClient("localhost:50051", api_key="…", agent_id="verifier") as v:
# planner writes a fact.
lsn = p.insert(id="fact-1", text="the launch is Friday", embedding=...)
# verifier confirms it — endorsement is durable + tamper-evident.
p_endorse_lsn = v.endorse_row(target_lsn=lsn)
# ... or disputes it with reason.
# dispute = v.dispute_row(target_lsn=lsn, reason="actually Monday")
Cross-tenant target → NotFound. Self-endorse → PermissionDenied.
Empty / oversize reason → InvalidArgument. Both RPCs require the
caller to identify via the x-agent-id metadata (set via the
agent_id= constructor arg). Disputes are sticky: the engine never
silently merges or overwrites — the kept row plus every dispute
remain together until a future operator resolution (Phase C).
v1.2.0 — causal tracing (ADR 0017 Phase A)
The audit chain becomes the public reasoning API. Three new methods let an agent answer "why did the swarm decide X at LSN L" in one RPC, with structural atomicity no external trace store can match:
from connordb import GrpcClient
with GrpcClient("localhost:50051", api_key="…") as c:
tool_lsn = c.record_tool_call(
"web_search",
args={"q": "connordb"},
result={"hits": 3},
)
decision_lsn = c.record_decision(
"deploy-friday",
cited_lsns=[tool_lsn],
summary="green retrieval, deploying",
)
graph = c.traceback(decision_lsn, max_depth=5)
for n in graph.nodes:
print(n.kind, n.lsn, n.label)
for e in graph.edges:
print(e.from_lsn, "→", e.to_lsn, f"({e.edge_type})")
Cross-tenant cites are rejected with PermissionDenied; future
LSNs with InvalidArgument. The cited set is hash-bound into the
per-tenant SHA-256 audit chain — post-hoc re-citation breaks the
chain on verify_audit_chain.
v1.1.0 — cluster topology
ADR 0016 Phase 7 ships cluster_topology() returning a frozen
ClusterTopology dataclass with epoch, leader_node_id,
leader_addr, and members: List[ClusterMember]. Each member carries
id, addr, in_sync, and last_ack_lsn. Available on every node;
the leader's view is strongly consistent, a follower's is eventually
consistent.
v1.0.0 — the transport cut
The HTTP Client from v0.x was deleted in this release (Sprint 6, ADR 0006).
ConnorDB is machine-only post-pivot; the engine no longer exposes HTTP, so
the SDK does not either.
Migration: replace connordb.Client(...) with connordb.GrpcClient(...).
Method names are mostly identical (insert, delete, count,
search_hybrid, …); see the docstring on each method for the new shape.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file connordb-1.8.5.tar.gz.
File metadata
- Download URL: connordb-1.8.5.tar.gz
- Upload date:
- Size: 88.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa9d8e72dd51612a05cae2da0907003ff893d853fe0337db40d8ac1a5c8088cf
|
|
| MD5 |
01767c3a92721980a1e4be8e829efcb4
|
|
| BLAKE2b-256 |
a5b30c2d283b4bedba50d2fa3593b94b5c90d4f2b5b81fd07a91cac14507184d
|
File details
Details for the file connordb-1.8.5-py3-none-any.whl.
File metadata
- Download URL: connordb-1.8.5-py3-none-any.whl
- Upload date:
- Size: 84.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3020765931bf78feadd82095491ae43b5afcb86c62af0801425121f33605ae8d
|
|
| MD5 |
f008d9db1d3388e3a7a5aa5be32c2a53
|
|
| BLAKE2b-256 |
b1bc6d491151afe15efe95879217d75fa39598a753008bcebc795c7353681d06
|