Skip to main content

Python SDK for the Areev knowledge database — HTTP, gRPC, and MCP transports

Project description

Areev Python SDK

Python client library for the Areev knowledge database.

A grain is one typed memory fact — the atomic unit Areev stores (e.g. the Fact "John likes coffee"). Everything in this SDK ultimately reads or writes grains.

Installation

pip install areev

For gRPC transport:

pip install areev[grpc]

Quick Start

from areev import Areev

areev = Areev()  # reads AREEV_API_KEY, AREEV_URL from env
areev.remember("John likes coffee")

results = areev.recall("what does John like?")
for hit in results.results:
    print(f"  {hit.grain_type}: {hit.fields}")

The synchronous Areev exposes the same full resource surface as AsyncAreev (client.grains, client.compliance, client.scope, …) with identical guardrails — automatic retry with idempotency keys, secret/PII redaction in logs, confirm=True guards on irreversible operations, and server-side tier/credit/authz verdicts surfaced as typed exceptions:

areev = Areev()

# Data-subject rights (GDPR/CCPA) — never tier- or credit-gated, PII kept out of logs
audit   = areev.compliance.audit()
export  = areev.compliance.export_user("user-123")
verify  = areev.compliance.verify_latest()

# Irreversible erasure requires explicit confirm=True
areev.grains.forget_user("user-123", confirm=True)   # GDPR Art. 17
areev.scope.erase("/org/team-a", confirm=True)
areev.consent.grant(user_id="user-123", purpose="marketing")

Configuration

The client reads from environment variables by default:

Variable Default Description
AREEV_API_KEY API key (sent as Authorization: Bearer <key>)
AREEV_URL https://app.areev.ai Server endpoint
AREEV_MEMORY_ID default Memory database ID

Or pass them explicitly:

areev = Areev(api_key="ar_...", url="https://dub.areev.ai", memory_id="my-memory")

Async

from areev import AsyncAreev

async with AsyncAreev() as areev:
    await areev.remember("John likes coffee")
    results = await areev.recall("what does John like?")

API

The top-level client exposes two headline methods (remember, recall) plus 22 resource namespaces. They split into two groups.

Core — what most integrations use day to day:

Namespace What it's for
remember(text) / recall(query) Store NL memory (LLM extracts structure) / search it
grains Typed grain CRUD (add, get, recall, supersede, forget, …)
harness Conversational harness (Areev's LLM-plus-tools runtime)
tools v1 tools surface — bind/list/invoke tools on a harness
connectors Third-party connector catalog + OAuth (Axtion-backed)
memories Memory-database lifecycle + stats
system Health, server models, capabilities

Advanced / Compliance — governance, identity, and ingestion surfaces you reach for as you scale: compliance (GDPR/CCPA audit, export, verify), consent, scope, policy, authz, agent_identities, sessions, namespaces, provenance, preferences, hooks, goals, chat, connections, knowledge_sources, imports.

Common Core methods:

Surface Description
remember(text) Store natural-language memory (LLM extracts structure)
recall(query) Search memories → typed RecallResponse
grains.add(grain_type, **fields) Add a typed grain → content hash
grains.get(hash) Get a grain by hash
grains.recall(query) Search → typed RecallResponse (same as top-level recall)
grains.supersede(old_hash, **fields) Update a grain → new hash
grains.forget(hash) / grains.forget_many(hashes) Delete grains
harness.chat(slug=…, message=…) Single harness turn (completed / requires_action)
harness.chat_resume(slug=…, session_id=…, tool_outputs=…) Resume a paused session
harness.chat_cancel(slug=…, session_id=…) Cancel a paused session
harness.chat_interactive(slug=…, message=…, executors=…) Harness chat with auto pause/resume for client:// tools
system.health() Health check
memories.stats(memory_id) Database statistics

Harness Chat

Use harness.chat_interactive to drive a harness (Areev's LLM-plus-tools runtime) with client-side tool executors. The helper runs the pause/resume loop for you when the model calls a client:// tool:

from areev import Areev

areev = Areev()

def get_weather(_name, args):
    city = args.get("city", "unknown")
    return {"city": city, "temp_c": 22, "conditions": "sunny"}

response = areev.harness.chat_interactive(
    slug="weather-harness",
    message="What's the weather in Paris?",
    executors={"get_weather": get_weather},
    conversation_id="conv-1",
)
print(response["text"])

AsyncAreev exposes the same method as a coroutine. harness.chat, harness.chat_resume, and harness.chat_cancel are the low-level primitives if you want to run the loop yourself.

End-to-End Quickstart (async)

A full flow: connect → remember/recall → create a harness and chat → register a client-side tool → connect a third-party connector and bind one of its actions as a tool — without hand-writing a single JSON Schema.

import asyncio
from areev import AsyncAreev


async def main():
    async with AsyncAreev(
        api_key="ap_local_...",            # ap_*/ar_* key
        url="http://localhost:4210",       # your cell
        memory_id="my-first-memory",
    ) as areev:
        # 1. Remember + recall
        await areev.remember("Ada prefers email over Slack")
        hits = await areev.recall("how should I contact Ada?")
        for h in hits.results:
            print(h.grain_type, h.fields)

        # 2. Create a harness wired to a provider, then chat
        await areev.harness.create(
            name="Sales Bot",
            slug="sales-bot",
            description="Outbound sales assistant",
            llm_config={"provider_id": "openai", "model": "gpt-4o-mini"},
            # provider_type defaults to provider_id ("openai") automatically.
        )
        reply = await areev.harness.chat(slug="sales-bot", message="Say hi")
        print(reply)

        # 3. Add a client-side tool (executed in your process)
        def get_weather(_name, args):
            return {"city": args.get("city"), "temp_c": 22}

        await areev.harness.chat_interactive(
            slug="sales-bot",
            message="What's the weather in Paris?",
            executors={"get_weather": get_weather},
        )

        # 4. Connect a third-party connector (OAuth), then poll for completion
        flow = await areev.connectors.authorize(
            "gmail", redirect_uri="https://yourapp.example/oauth/cb"
        )
        print("Open this URL to authorize:", flow["authorize_url"])
        # ... user consents in the browser, provider redirects back ...
        status = await areev.connectors.poll_oauth("gmail", flow["state"])
        # poll until status["status"] == "success"

        # 5. Bind a connector action as a tool — schema fetched for you
        await areev.tools.bind_axtion(
            slug="sales-bot",
            connector="gmail",
            action="send-email",          # the action key from connectors.actions()
            description="Send an email via Gmail",
        )


asyncio.run(main())

Connectors

connectors vs connections vs harness vs chatconnectors is the third-party catalog + OAuth surface (discover providers, run the handshake); connections is the stored credential records for connectors you've already authorized; harness is the chatbot-with-tools runtime (LLM + bound tools); chat is memory-engine chat (converse over your stored grains).

client.connectors is the catalog + OAuth surface (backed by Axtion). All methods return clean, parsed data:

Method Returns
connectors.list() [{"name", "display_name", "category", "version"}, ...]
connectors.get(name) Raw connector detail (metadata + action descriptors)
connectors.actions(name) [{"name", "display_name", "description", "param_schema", "required"}, ...]
connectors.authorize(name, redirect_uri=…) {"authorize_url", "state", ...}
connectors.poll_oauth(name, state) {"status": "pending"|"success"|"error"|"expired", ...}
connectors.store_credentials(body) Store API-key credentials (non-OAuth connectors)

Canonical connector flow (OAuth → bind a tool)

# 0. Discover what's available
catalog = await areev.connectors.list()
# → [{"name": "gmail", "display_name": "Google Gmail",
#     "category": "Communication", "version": "1.0.0"}, ...]

# 1. Start the OAuth handshake for a connector key from the catalog
flow = await areev.connectors.authorize(
    "gmail", redirect_uri="https://yourapp.example/oauth/cb"
)

# 2. Send the user to the authorize URL to consent
print("Open this URL to authorize:", flow["authorize_url"])

# 3. After the provider redirects back, poll until the handshake completes
#    (back off between polls — don't hammer the endpoint in a tight loop)
import asyncio

status = await areev.connectors.poll_oauth("gmail", flow["state"])
while status["status"] == "pending":
    await asyncio.sleep(2)
    status = await areev.connectors.poll_oauth("gmail", flow["state"])
assert status["status"] == "success"

# 4. Bind one of the connector's actions as a harness tool — schema fetched
#    for you (no hand-written JSON Schema)
await areev.tools.bind_axtion(
    slug="sales-bot",
    connector="gmail",
    action="send-email",          # an action key from connectors.actions("gmail")
    description="Send an email via Gmail",
)

Prerequisite — redirect-uri allowlist. The redirect_uri you pass to connectors.authorize(...) must be pre-registered on your org by an admin. An unregistered URI is rejected before any provider redirect — the call raises ValidationError (HTTP 400). Register your callback URL(s) in org settings before going live.

tools.bind_axtion(slug=…, connector=…, action=…) looks up the action's parameter schema from connectors.actions() and binds it for you — so the agent gets a fully-typed tool without you writing any JSON Schema.

The sync client (Areev) exposes the identical surface without await.

Transports

Transport Extra Status
HTTP/REST (default) Available
gRPC areev[grpc] Available
MCP Planned

Code Generation

Generate gRPC stubs, Pydantic models, the async raw-HTTP resource clients, and the synchronous SDK surface from the Areev spec:

pip install areev[dev]
./scripts/generate.sh

The async modules under src/areev/resources/ and src/areev/http.py are the single source of truth. The sync twin (src/areev/_sync/) is derived mechanically from them by scripts/generate_sync.py (via unasync) — so the two surfaces cannot drift in their guardrails. Run python scripts/generate_sync.py --check in CI to fail the build if the committed sync tree is stale.

License

BUSL-1.1

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

areev-0.2.0.tar.gz (288.5 kB view details)

Uploaded Source

Built Distribution

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

areev-0.2.0-py3-none-any.whl (163.3 kB view details)

Uploaded Python 3

File details

Details for the file areev-0.2.0.tar.gz.

File metadata

  • Download URL: areev-0.2.0.tar.gz
  • Upload date:
  • Size: 288.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for areev-0.2.0.tar.gz
Algorithm Hash digest
SHA256 43f550fd36202b932803a10a1d70d49c94ff4006b22500b6e056ae6cc888c281
MD5 0bf2aa10aae60927f1ac28b9d9734201
BLAKE2b-256 fcac7d71861248b4458e87999ccf94b75ead5b6a475b69f87885d72d04b113b5

See more details on using hashes here.

File details

Details for the file areev-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: areev-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 163.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for areev-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8c312567461482c4e1ed8b709207d084bbac78de1276d60f9f6fec64873f90f8
MD5 413d1086a8a950ec07c23f6c8495e1b1
BLAKE2b-256 575f12dfc5d61f9c9e04482de3832dcca5bade87d4d68a68d6a9c9abc66b8be4

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