Skip to main content

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

connordb-1.8.5.tar.gz (88.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

connordb-1.8.5-py3-none-any.whl (84.9 kB view details)

Uploaded Python 3

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

Hashes for connordb-1.8.5.tar.gz
Algorithm Hash digest
SHA256 fa9d8e72dd51612a05cae2da0907003ff893d853fe0337db40d8ac1a5c8088cf
MD5 01767c3a92721980a1e4be8e829efcb4
BLAKE2b-256 a5b30c2d283b4bedba50d2fa3593b94b5c90d4f2b5b81fd07a91cac14507184d

See more details on using hashes here.

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

Hashes for connordb-1.8.5-py3-none-any.whl
Algorithm Hash digest
SHA256 3020765931bf78feadd82095491ae43b5afcb86c62af0801425121f33605ae8d
MD5 f008d9db1d3388e3a7a5aa5be32c2a53
BLAKE2b-256 b1bc6d491151afe15efe95879217d75fa39598a753008bcebc795c7353681d06

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page