relata-sdk 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. relata_sdk-0.2.0/.gitignore +259 -0
  2. relata_sdk-0.2.0/PKG-INFO +407 -0
  3. relata_sdk-0.2.0/README.md +375 -0
  4. relata_sdk-0.2.0/examples/analytics.py +231 -0
  5. relata_sdk-0.2.0/examples/audit.py +358 -0
  6. relata_sdk-0.2.0/examples/basic_query.py +126 -0
  7. relata_sdk-0.2.0/examples/face_search.py +225 -0
  8. relata_sdk-0.2.0/examples/graph_traversal.py +245 -0
  9. relata_sdk-0.2.0/examples/memory_quickstart.py +22 -0
  10. relata_sdk-0.2.0/pyproject.toml +64 -0
  11. relata_sdk-0.2.0/relata/__init__.py +127 -0
  12. relata_sdk-0.2.0/relata/_http.py +405 -0
  13. relata_sdk-0.2.0/relata/a2a.py +157 -0
  14. relata_sdk-0.2.0/relata/audit.py +237 -0
  15. relata_sdk-0.2.0/relata/backup.py +257 -0
  16. relata_sdk-0.2.0/relata/client.py +597 -0
  17. relata_sdk-0.2.0/relata/exceptions.py +203 -0
  18. relata_sdk-0.2.0/relata/governance.py +499 -0
  19. relata_sdk-0.2.0/relata/identity.py +267 -0
  20. relata_sdk-0.2.0/relata/ingest.py +209 -0
  21. relata_sdk-0.2.0/relata/log.py +162 -0
  22. relata_sdk-0.2.0/relata/mcp.py +383 -0
  23. relata_sdk-0.2.0/relata/memory.py +479 -0
  24. relata_sdk-0.2.0/relata/models.py +354 -0
  25. relata_sdk-0.2.0/relata/objects.py +228 -0
  26. relata_sdk-0.2.0/relata/query.py +601 -0
  27. relata_sdk-0.2.0/relata/s3.py +190 -0
  28. relata_sdk-0.2.0/relata/streaming.py +320 -0
  29. relata_sdk-0.2.0/relata/system.py +129 -0
  30. relata_sdk-0.2.0/relata/tenants.py +246 -0
  31. relata_sdk-0.2.0/relata/tokens.py +167 -0
  32. relata_sdk-0.2.0/relata/vectors.py +209 -0
  33. relata_sdk-0.2.0/relata_adapters/__init__.py +20 -0
  34. relata_sdk-0.2.0/relata_adapters/_base.py +87 -0
  35. relata_sdk-0.2.0/relata_adapters/ag2.py +85 -0
  36. relata_sdk-0.2.0/relata_adapters/autogen.py +50 -0
  37. relata_sdk-0.2.0/relata_adapters/crewai.py +56 -0
  38. relata_sdk-0.2.0/relata_adapters/langchain.py +64 -0
  39. relata_sdk-0.2.0/relata_adapters/llamaindex.py +60 -0
  40. relata_sdk-0.2.0/relata_adapters/pydantic_ai.py +88 -0
  41. relata_sdk-0.2.0/relata_adapters/registry.py +76 -0
  42. relata_sdk-0.2.0/relata_adapters/smolagents.py +88 -0
  43. relata_sdk-0.2.0/relata_langgraph/__init__.py +180 -0
  44. relata_sdk-0.2.0/tests/test_adapters.py +135 -0
  45. relata_sdk-0.2.0/tests/test_agent_verbs_coverage.py +190 -0
  46. relata_sdk-0.2.0/tests/test_async_memory.py +66 -0
  47. relata_sdk-0.2.0/tests/test_introspection_and_headers.py +199 -0
  48. relata_sdk-0.2.0/tests/test_langgraph_checkpointer.py +98 -0
  49. relata_sdk-0.2.0/tests/test_log_tokens_backup_stats.py +308 -0
  50. relata_sdk-0.2.0/tests/test_memory.py +189 -0
  51. relata_sdk-0.2.0/tests/test_memory_completion_and_query_cursor.py +204 -0
  52. relata_sdk-0.2.0/tests/test_sdk_modules_wave.py +404 -0
  53. relata_sdk-0.2.0/tests/test_streaming_tenants_safety.py +212 -0
  54. relata_sdk-0.2.0/tests/test_transport_and_adapters.py +243 -0
@@ -0,0 +1,259 @@
1
+ # =============================================================================
2
+
3
+ # Relata — .gitignore
4
+ # =============================================================================
5
+ # Layered by tool. Keep entries grouped and alphabetised within groups.
6
+ # Anything generated, machine-specific, or secret stays out of git.
7
+ # Spec corpus (SPECS.md, DECISIONS.md, etc.), source code, and CI config stay IN.
8
+ # =============================================================================
9
+
10
+ # -----------------------------------------------------------------------------
11
+ # Rust / Cargo
12
+ # -----------------------------------------------------------------------------
13
+ /target/
14
+ **/target/
15
+ **/*.rs.bk
16
+ Cargo.lock.bak
17
+
18
+ # Cargo.lock IS committed for binaries (relata-cli) and applications, but the
19
+ # workspace publishes only binaries today. If a publishable library is added
20
+ # later, narrow this rule per ADR.
21
+ # (Cargo.lock is intentionally NOT ignored.)
22
+
23
+ # Cargo registry / git caches that some tools dump locally
24
+ .cargo/registry/
25
+ .cargo/git/
26
+
27
+ # Coverage and profiling output
28
+ *.profraw
29
+ *.profdata
30
+ coverage/
31
+ tarpaulin-report.html
32
+ cobertura.xml
33
+ lcov.info
34
+ flamegraph.svg
35
+ perf.data
36
+ perf.data.old
37
+ samply.json
38
+ *.cargo-ok
39
+ CLAUDE.md
40
+ # Criterion benchmark output (large; regenerate locally)
41
+ **/criterion/
42
+
43
+ # rust-analyzer / IDE incrementals
44
+ rust-analyzer-*.log
45
+
46
+ # -----------------------------------------------------------------------------
47
+ # Build artefacts (engine binaries, signed bundles, release outputs)
48
+ # -----------------------------------------------------------------------------
49
+ /dist/
50
+ /build/
51
+ /release/
52
+ *.dSYM/
53
+ *.pdb
54
+
55
+ # Air-gap install bundles (large; not source of truth)
56
+ /airgap-bundle/
57
+ *.airgap.tar
58
+ *.airgap.tar.zst
59
+
60
+ # -----------------------------------------------------------------------------
61
+ # Generated docs (mdbook, rustdoc) — sources are committed, output is not
62
+ # -----------------------------------------------------------------------------
63
+ /docs/book/
64
+ /target/doc/
65
+
66
+ # -----------------------------------------------------------------------------
67
+ # Conformance corpus (M0.5) and benchmark data
68
+ # -----------------------------------------------------------------------------
69
+ # Sample-data generators are committed under relata-conformance/<pack>/generators/
70
+ # Generated fixtures (Parquet, CSV, JSON) are large and reproducible — ignore them.
71
+ /relata-conformance/*/fixtures/generated/
72
+ /relata-conformance/*/snapshots/
73
+ **/conformance-results-*.json
74
+ **/BENCHMARKS-RESULTS.local.md
75
+ **/BENCHMARKS-CONFORMANCE.local.md
76
+
77
+ # Legacy roadmap state mirror (M0.1.E). GitHub Issues/Milestones are current.
78
+ /roadmap_state.json
79
+
80
+ # -----------------------------------------------------------------------------
81
+ # Secrets, credentials, KMS material — NEVER commit
82
+ # -----------------------------------------------------------------------------
83
+ .env
84
+ .env.*
85
+ !.env.example
86
+ *.pem
87
+ *.key
88
+ *.p12
89
+ *.pfx
90
+ *.crt
91
+ *.cer
92
+ *.csr
93
+ !relata-conformance/**/*.pem.example
94
+ !relata-conformance/**/*.key.example
95
+ secrets/
96
+ credentials.json
97
+ **/kms-cache/
98
+ **/hsm-session-*
99
+
100
+ # AWS / GCP / Azure / Cloudflare local credentials
101
+ .aws/credentials
102
+ .aws/config
103
+ gcloud/
104
+ .azure/
105
+ .cloudflare/
106
+ .config/rclone/
107
+
108
+ # TUF / Sigstore local material (ADR-058)
109
+ # Root metadata and Rekor pins are committed under docs/security/;
110
+ # session keys, cosign keys, and rekor signing material are NOT.
111
+ *.cosign.key
112
+ *.cosign.pub
113
+ !cosign.pub.example
114
+ # License files generated by the License Manager (test / demo artefacts)
115
+ *.lic
116
+ /tuf-staging/
117
+ /tuf-private/
118
+
119
+ # -----------------------------------------------------------------------------
120
+ # Object-store local emulators (MinIO, fake-s3) used in dev
121
+ # -----------------------------------------------------------------------------
122
+ /minio-data/
123
+ /.minio.sys/
124
+ /fake-s3/
125
+ /localstack/
126
+
127
+ # Kafka / Redpanda local data
128
+ /kafka-data/
129
+ /redpanda-data/
130
+
131
+ # etcd / FoundationDB local data (writer-lease fallback for M4.A.3)
132
+ /etcd-data/
133
+ /fdb-data/
134
+ /fdb.cluster
135
+
136
+ # -----------------------------------------------------------------------------
137
+ # Tracing / profiling artefacts
138
+ # -----------------------------------------------------------------------------
139
+ /traces/
140
+ *.svg.tmp
141
+ chrome-trace-*.json
142
+ otel-traces-*.json
143
+ *.heap-profile
144
+
145
+ # -----------------------------------------------------------------------------
146
+ # SDKs (sdks/python, sdks/typescript, sdks/go) — language-local artefacts
147
+ # -----------------------------------------------------------------------------
148
+ # Python (uv + pyo3)
149
+ __pycache__/
150
+ *.py[cod]
151
+ *$py.class
152
+ *.so
153
+ *.pyd
154
+ .venv/
155
+ venv/
156
+ .env-py/
157
+ .pytest_cache/
158
+ .mypy_cache/
159
+ .ruff_cache/
160
+ .pdm-build/
161
+ .pdm-python
162
+ dist-py/
163
+ build-py/
164
+ *.egg-info/
165
+ *.whl
166
+ uv.lock.bak
167
+
168
+ # Maturin / pyo3 build output
169
+ sdks/python/target/
170
+ sdks/python/*.so
171
+ sdks/python/*.dylib
172
+
173
+ # TypeScript / Node
174
+ node_modules/
175
+ dist-ts/
176
+ .npm/
177
+ .pnp.*
178
+ .yarn/
179
+ .parcel-cache/
180
+ *.tsbuildinfo
181
+ .next/
182
+ .turbo/
183
+
184
+ # Go
185
+ sdks/go/bin/
186
+ sdks/go/pkg/
187
+ sdks/go/vendor/
188
+
189
+ # -----------------------------------------------------------------------------
190
+ # Editor / IDE
191
+ # -----------------------------------------------------------------------------
192
+ .vscode/
193
+ !.vscode/extensions.json
194
+ !.vscode/settings.shared.json
195
+ .idea/
196
+ *.iml
197
+ *.swp
198
+ *.swo
199
+ *~
200
+ .*.swp
201
+ .*.swo
202
+ .zed/
203
+ .nvim/
204
+ .code-workspace
205
+
206
+ # -----------------------------------------------------------------------------
207
+ # OS noise
208
+ # -----------------------------------------------------------------------------
209
+ .DS_Store
210
+ .DS_Store?
211
+ ._*
212
+ .Spotlight-V100
213
+ .Trashes
214
+ ehthumbs.db
215
+ Thumbs.db
216
+ Desktop.ini
217
+ $RECYCLE.BIN/
218
+
219
+ # -----------------------------------------------------------------------------
220
+ # CI / test scratch
221
+ # -----------------------------------------------------------------------------
222
+ /tmp/
223
+ /.tmp/
224
+ /scratch/
225
+ /.scratch/
226
+ *.log
227
+ !CHANGELOG*.md
228
+ test-output/
229
+ junit*.xml
230
+
231
+ # -----------------------------------------------------------------------------
232
+ # Simulation output — all generated; not part of the shipped artefact
233
+ # -----------------------------------------------------------------------------
234
+ simulation-output/
235
+ landing/simulation-output/
236
+
237
+ # -----------------------------------------------------------------------------
238
+ # AI/editor session state (chat-tool scratch — never commit)
239
+ # -----------------------------------------------------------------------------
240
+ .vibekit/
241
+ .claude/
242
+ .cursor/
243
+ .aider*
244
+ .aider/
245
+ .windsurf/
246
+
247
+ # -----------------------------------------------------------------------------
248
+ # Local overrides (last-resort escape hatch; document in PR if used)
249
+ # -----------------------------------------------------------------------------
250
+ *.local
251
+ *.local.*
252
+ .local/
253
+ LOCAL.md
254
+ NOTES.local.md
255
+ data/
256
+ docs/src/usecases/screenshots/
257
+
258
+ # Local Relata runtime state (CLI store, WAL, local data) — never commit
259
+ .relata/
@@ -0,0 +1,407 @@
1
+ Metadata-Version: 2.4
2
+ Name: relata-sdk
3
+ Version: 0.2.0
4
+ Summary: Python SDK for the Relata enterprise-grade data engine
5
+ Project-URL: Homepage, https://relata.io
6
+ Project-URL: Documentation, https://docs.relata.io/sdk/python
7
+ Project-URL: Repository, https://github.com/OpenWorkBench-Co/RelataDB
8
+ Project-URL: Issues, https://github.com/OpenWorkBench-Co/RelataDB/issues
9
+ Author-email: Relata <sdk@relata.io>
10
+ License: Apache-2.0
11
+ Keywords: analytics,bi-temporal,data-engine,ontology,relata
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Apache Software License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Database
20
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: pydantic>=2.6
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy>=1.10; extra == 'dev'
27
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
28
+ Requires-Dist: pytest>=8.0; extra == 'dev'
29
+ Requires-Dist: respx>=0.21; extra == 'dev'
30
+ Requires-Dist: ruff>=0.4; extra == 'dev'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # Relata Python SDK
34
+
35
+ Python SDK for the [Relata](https://relatadb.dev) enterprise-grade data engine.
36
+
37
+ Relata is a Rust-native, ontology-driven engine built for bi-temporal, governed knowledge workloads: link analysis, identity resolution, full-text and vector search, access-scoped restricted data, and provenance-tracked analytics.
38
+
39
+ ## Requirements
40
+
41
+ - Python 3.11+
42
+ - `httpx >= 0.27`
43
+ - `pydantic >= 2.6`
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ pip install relata-sdk
49
+ # or with uv
50
+ uv add relata-sdk
51
+ ```
52
+
53
+ ## Quick start
54
+
55
+ ```python
56
+ from relata import RelataClient
57
+
58
+ with RelataClient("http://localhost:9090", purpose="analytics") as client:
59
+ result = client.query("SELECT * FROM Person WHERE name LIKE 'Ahmed%' LIMIT 10")
60
+ for row in result:
61
+ print(row)
62
+ ```
63
+
64
+ ## Agent memory in three lines
65
+
66
+ For agent-memory workloads, `Memory` is a Mem0-style one-liner surface over the
67
+ governed `/memory/*` verbs — governance (purpose + ACL) stays on by default:
68
+
69
+ ```python
70
+ from relata import Memory
71
+
72
+ with Memory("http://localhost:9090", purpose="agent-notes") as m:
73
+ mem_id = m.add("Alice prefers dark mode") # store
74
+ hits = m.search("ui preferences", top_k=5) # recall (confidence × recency × relevance)
75
+ m.forget(mem_id) # governed retract, not a hard delete
76
+ ```
77
+
78
+ See `examples/memory_quickstart.py`. For async apps, `AsyncMemory` has the same
79
+ surface: `async with AsyncMemory(...) as m: await m.add(...); await m.search(...)`.
80
+
81
+ ## Agent-framework adapters
82
+
83
+ Drop-in, governed memory backends for the major agent frameworks — each maps the
84
+ framework's memory/storage interface onto Relata, and none imports its framework
85
+ (so they load with or without it installed):
86
+
87
+ | Framework | Import | Shape |
88
+ |---|---|---|
89
+ | LangChain | `relata_adapters.langchain.RelataMemory` | `BaseMemory` |
90
+ | LlamaIndex | `relata_adapters.llamaindex.RelataMemory` | `BaseMemory` |
91
+ | CrewAI | `relata_adapters.crewai.RelataStorage` | `Storage` |
92
+ | AutoGen | `relata_adapters.autogen.RelataMemory` | `Memory` (async) |
93
+ | LangGraph | `relata_langgraph.RelataCheckpointer` | checkpointer |
94
+
95
+ ```python
96
+ from relata_adapters.langchain import RelataMemory
97
+
98
+ mem = RelataMemory(base_url="http://localhost:9090", purpose="agent")
99
+ # chain = ConversationChain(llm=..., memory=mem)
100
+ ```
101
+
102
+ The adapters use the semantic-memory model (store + relevance recall), the same
103
+ paradigm as Mem0. They wrap the `Memory` client, so governance stays on.
104
+
105
+ ## Core concepts
106
+
107
+ ### Every query must declare a purpose
108
+
109
+ Relata enforces a mandatory `purpose` on every query. The purpose must be a string registered in the tenant's `PurposeRegistry` (e.g. `"analytics"`, `"audit"`, `"analysis"`). Queries without a purpose are rejected at the wire.
110
+
111
+ Set a default on the client:
112
+
113
+ ```python
114
+ client = RelataClient("http://localhost:9090", purpose="analytics")
115
+ ```
116
+
117
+ Or override per-call:
118
+
119
+ ```python
120
+ result = client.query("SELECT COUNT(*) FROM Person", purpose="audit")
121
+ ```
122
+
123
+ ### Bearer token authentication
124
+
125
+ When the server is configured with `RELATA_BEARER_TOKEN`, pass the token to the client:
126
+
127
+ ```python
128
+ client = RelataClient(
129
+ "https://relata.example.com",
130
+ bearer_token="your-token",
131
+ purpose="analytics",
132
+ )
133
+ ```
134
+
135
+ > **What identity does my SDK client use by default?**
136
+ >
137
+ > Without a bearer token, every request runs as the **`api-user`** principal —
138
+ > a built-in identity with read access to all domain types and write access
139
+ > in open (lite) mode. Audit entries, quota charges, and ACL decisions all
140
+ > attribute to `api-user`.
141
+ >
142
+ > MCP requests (`McpClient`) run as **`mcp-client`** — a different principal
143
+ > with separate audit and quota accounting.
144
+ >
145
+ > For multi-tenant production: set a bearer token + `tenant=` on every
146
+ > request. See `docs/src/end-users/defaults.md` for the full default-behavior
147
+ > reference.
148
+
149
+ ### Fluent query builder
150
+
151
+ ```python
152
+ result = (
153
+ client.select("Person")
154
+ .where("nationality = 'IN'")
155
+ .where("age > 25")
156
+ .as_of("2025-01-01") # bi-temporal point-in-time
157
+ .with_provenance() # include PROV-O columns
158
+ .order_by("name ASC")
159
+ .limit(20)
160
+ .execute()
161
+ )
162
+ ```
163
+
164
+ ### Relata SQL extensions
165
+
166
+ | Extension | Example |
167
+ |---|---|
168
+ | Bi-temporal | `SELECT * FROM Person AS OF '2024-06-01'` |
169
+ | Provenance | `SELECT * FROM Person WITH PROVENANCE` |
170
+ | Graph traversal | `FROM PATHS_BETWEEN('person-123', 'org-456', max_hops => 4)` |
171
+ | Face search | `WHERE MATCH_FACE(probe_embedding, stored_embedding, 0.92)` |
172
+ | Identity lookup | `FROM LOOKUP_IDENTITY('+919876543210')` |
173
+ | Hybrid search | `SELECT *, HYBRID_SCORE('terror finance') AS score FROM Document` |
174
+
175
+ ### QueryResult is iterable
176
+
177
+ ```python
178
+ result = client.query("SELECT * FROM Person LIMIT 10")
179
+
180
+ # Iterate over rows
181
+ for row in result:
182
+ print(row["name"])
183
+
184
+ # Access by index
185
+ first = result.rows[0]
186
+
187
+ # Check if empty
188
+ if not result:
189
+ print("No results")
190
+
191
+ # Row count
192
+ print(f"{len(result)} rows in {result.elapsed_ms} ms")
193
+ ```
194
+
195
+ ### Async support
196
+
197
+ ```python
198
+ import asyncio
199
+ from relata import RelataClient
200
+
201
+ async def main():
202
+ async with RelataClient("http://localhost:9090", purpose="analytics") as client:
203
+ result = await client.aquery("SELECT * FROM Person LIMIT 5")
204
+ for row in result:
205
+ print(row)
206
+
207
+ asyncio.run(main())
208
+ ```
209
+
210
+ ### Error handling
211
+
212
+ ```python
213
+ from relata.exceptions import (
214
+ PurposeError, # missing or unregistered purpose
215
+ QuotaError, # per-principal cost quota exhausted
216
+ AuthError, # invalid or missing bearer token
217
+ ConnectionError, # server unreachable
218
+ RelataError, # base class — catch all SDK errors
219
+ )
220
+
221
+ try:
222
+ result = client.query("SELECT * FROM Person")
223
+ except PurposeError as exc:
224
+ print(f"Fix: set purpose= on client or per query. {exc}")
225
+ except QuotaError as exc:
226
+ print(f"Quota exhausted — reduce query scope. {exc}")
227
+ except AuthError as exc:
228
+ print(f"Auth failed — check bearer_token. {exc}")
229
+ except ConnectionError as exc:
230
+ print(f"Cannot reach server. {exc}")
231
+ ```
232
+
233
+ ## API reference
234
+
235
+ ### `RelataClient`
236
+
237
+ ```python
238
+ RelataClient(
239
+ base_url: str,
240
+ *,
241
+ bearer_token: str | None = None,
242
+ purpose: str | None = None,
243
+ timeout: float = 30.0,
244
+ tenant: str | None = None, # X-Organization-Id (multi-tenant)
245
+ acting_as: str | None = None, # X-Acting-As (delegation)
246
+ delegated_by: str | None = None, # X-Delegated-By
247
+ headers: dict[str, str] | None = None, # arbitrary header overlay
248
+ max_retries: int = 0, # retry on connection errors
249
+ retry_backoff_secs: float = 0.5, # exponential backoff base
250
+ )
251
+ ```
252
+
253
+ | Method | Returns | Description |
254
+ |---|---|---|
255
+ | `query(sql, *, purpose)` | `QueryResult` | Execute a SQL query |
256
+ | `health()` | `HealthResponse` | Check node health |
257
+ | `status()` | `StatusResponse` | Node status + quota |
258
+ | `stats()` | `Stats` | Engine-wide counts (records/states/snapshot_rows/log_leaves/tokens) |
259
+ | `version()` | `VersionInfo` | Build info (version, commit, profile, schema_version) |
260
+ | `ready()` | `ReadyReport` | 9-condition readiness report |
261
+ | `audit_count()` | `AuditCountResponse` | Audit log entry count + chain validity |
262
+ | `cluster_nodes()` | `list[ClusterNode]` | List cluster nodes |
263
+ | `select(*cols)` | `QueryBuilder` | Start a fluent query |
264
+ | `close()` | — | Close sync connections |
265
+ | `aquery(...)` | `QueryResult` | Async query |
266
+ | `ahealth()` ... `astats()` ... `aready()` etc. | — | Async mirrors of every method above |
267
+ | `aclose()` | — | Close async connections |
268
+
269
+ ### v1.1 typed clients (`from_client(client)`)
270
+
271
+ Each module inherits the parent client's auth, tenant, and purpose context:
272
+
273
+ | Module | Class | Surface |
274
+ |---|---|---|
275
+ | `relata.governance` | `GovernanceClient` | Rules, retention (holds + WORM), breakglass, alerts, DSAR |
276
+ | `relata.mcp` | `McpClient` | 22 typed MCP tool wrappers + generic `call_tool` |
277
+ | `relata.a2a` | `A2AClient` | A2A tasks + LangGraph checkpoints + agent card |
278
+ | `relata.audit` | `AuditClient` | Audit entries (filtered/paginated) + signed receipts + PDF export |
279
+ | `relata.identity` | `IdentityClient` | Identity label/uncertainty + lookup tables + ERASE SUBJECT |
280
+ | `relata.objects` | `ObjectClient` | Typed upsert + batch via `/ingest?object_type=` |
281
+ | `relata.ingest` | `IngestClient` | Bulk NDJSON + CSV + media status |
282
+ | `relata.vectors` | `VectorClient` | KNN + hybrid search + similar-to (SQL-backed) |
283
+ | `relata.s3` | `S3Client` | boto3 / httpx / aiobotocore wrapper for the S3 protocol door |
284
+ | `relata.system` | `SystemClient` | LLM config + test + jobs status |
285
+ | `relata.streaming` | `StreamingClient` | NDJSON row streams + SSE consumers (watch/alerts) + Arrow IPC |
286
+ | `relata.tenants` | `TenantAdminClient` | Tenant CRUD + quota + sharing agreements + platform admin |
287
+
288
+ Each has an async mirror (`Async*`).
289
+
290
+ ### v1.1 transport hardening (#79)
291
+
292
+ - **RFC 7807 problem+json parsing** — every error carries `code`, `type_url`, `retryable`, `request_id`.
293
+ - **Typed exceptions** — `ForbiddenError` (403), `NotFoundError` (404), `ConflictError` (409), `ValidationError` (422), `RateLimitedError` (429, with `retry_after`).
294
+ - **Retry** — `RelataClient(..., max_retries=3, retry_backoff_secs=0.5)`.
295
+ - **X-Request-ID** — auto-generated per request; caller-supplied IDs respected; server's response ID stamped on exceptions.
296
+
297
+ ### Custom object types
298
+
299
+ RelataDB is ontology-governed — unknown types are rejected on both ingest and
300
+ read. Register custom types at runtime via `POST /types` (persisted across
301
+ restart):
302
+
303
+ ```python
304
+ # Register a custom type
305
+ client._sync.post("/types", {
306
+ "name": "AgentTask",
307
+ "fields": [
308
+ {"name": "task_id", "type": "string"},
309
+ {"name": "status", "type": "string"},
310
+ ]
311
+ })
312
+
313
+ # Now ingest + query work
314
+ client._sync.post("/ingest?object_type=AgentTask", {"task_id": "t-1", "status": "done"})
315
+ ```
316
+
317
+ For ACL access in strict mode, grant via env var:
318
+ ```bash
319
+ RELATA_ACL_GRANT=AgentTask:read+write
320
+ ```
321
+
322
+ Unknown types return `400` on both ingest and read — fail-closed by design.
323
+
324
+ ### v1.1 QueryBuilder extensions (#76)
325
+
326
+ | Method | Description |
327
+ |---|---|
328
+ | `.limit(n, after="cursor")` | Keyset pagination (`LIMIT n AFTER 'cursor'`) |
329
+ | `.since(cursor)` | Incremental reads (`WHERE system_from > cursor`) |
330
+
331
+ The builder also validates identifiers (`from_()`, `select()`) and refuses
332
+ dangerous tokens in `where()` (SQL-injection stopgap).
333
+
334
+ ### Agent-framework adapters
335
+
336
+ | Framework | Import | Shape |
337
+ |---|---|---|
338
+ | LangChain | `relata_adapters.langchain.RelataMemory` | `BaseMemory` |
339
+ | LlamaIndex | `relata_adapters.llamaindex.RelataMemory` | `BaseMemory` |
340
+ | CrewAI | `relata_adapters.crewai.RelataStorage` | `Storage` |
341
+ | AutoGen v0.2 | `relata_adapters.autogen.RelataMemory` | `Memory` (async) |
342
+ | LangGraph | `relata_langgraph.RelataCheckpointer` | checkpointer |
343
+ | AG2 (v0.4+) | `relata_adapters.ag2.RelataAG2Memory` | `MemoryProtocol` |
344
+ | Pydantic-AI | `relata_adapters.pydantic_ai.RelataMemoryBackend` | memory backend |
345
+ | smolagents | `relata_adapters.smolagents.RelataTool` | tool callable |
346
+ | Auto-detect | `relata_adapters.registry.get_memory_adapter()` | picks the right class |
347
+
348
+ ### `QueryBuilder`
349
+
350
+ | Method | Description |
351
+ |---|---|
352
+ | `.select(*cols)` | Columns or table name shorthand |
353
+ | `.from_(table)` | FROM table |
354
+ | `.where(condition)` | Add WHERE predicate (multiple calls → AND) |
355
+ | `.as_of(timestamp)` | Bi-temporal AS OF |
356
+ | `.with_provenance()` | Append WITH PROVENANCE |
357
+ | `.purpose(p)` | Override purpose for this query |
358
+ | `.limit(n)` | LIMIT |
359
+ | `.offset(n)` | OFFSET |
360
+ | `.order_by(*cols)` | ORDER BY |
361
+ | `.paths_between(src, dst, max_hops)` | PATHS_BETWEEN graph operator |
362
+ | `.match_face(probe, candidate, threshold)` | MATCH_FACE operator |
363
+ | `.lookup_identity(value)` | LOOKUP_IDENTITY operator |
364
+ | `.hybrid_score(text)` | HYBRID_SCORE ranking |
365
+ | `.raw(sql)` | Raw SQL escape hatch |
366
+ | `.sql()` | Return assembled SQL without executing |
367
+ | `.execute()` | Execute (sync) |
368
+ | `.aexecute()` | Execute (async) |
369
+
370
+ ### Response models
371
+
372
+ | Model | Fields |
373
+ |---|---|
374
+ | `QueryResult` | `rows`, `query_id`, `elapsed_ms`, `row_count` |
375
+ | `HealthResponse` | `status`, `profile`, `node_id` |
376
+ | `StatusResponse` | `profile`, `role`, `query_quota` |
377
+ | `AuditCountResponse` | `entries`, `chain_valid` |
378
+ | `ClusterNode` | `node_id`, `role`, `url` |
379
+ | `VersionInfo` | `version`, `commit`, `profile`, `schema_version`, `features` |
380
+ | `Stats` | `records`, `states`, `snapshot_rows`, `log_leaves`, `tokens` |
381
+ | `ReadyReport` | `is_ready`, `status`, `reason`, `detail` |
382
+
383
+ ## Examples
384
+
385
+ See the `examples/` directory:
386
+
387
+ | File | Demonstrates |
388
+ |---|---|
389
+ | `basic_query.py` | Getting started, health check, quota check |
390
+ | `analytics.py` | Full analytics workflow: identity → cases → graph → provenance |
391
+ | `face_search.py` | MATCH_FACE operator, threshold comparison, CCTV temporal search |
392
+ | `graph_traversal.py` | PATHS_BETWEEN, temporal network shift, hub detection |
393
+ | `audit.py` | Chain verification, audit summary, anomaly detection |
394
+
395
+ ## Deployment profiles
396
+
397
+ Relata ships three deployment profiles. The SDK works identically across all three:
398
+
399
+ | Profile | Use case | Binary |
400
+ |---|---|---|
401
+ | `lite` | Embedded / single-process | `RELATA_PROFILE=lite relata serve` |
402
+ | `server` | Single-node production | `RELATA_PROFILE=server relata serve` |
403
+ | `cluster` | Multi-node distributed | `RELATA_PROFILE=cluster relata serve` |
404
+
405
+ ## License
406
+
407
+ AGPL-3.0-only. See the root `LICENSE` file.