@areev/sdk
v0.2.0
Published
TypeScript SDK for the Areev knowledge database — HTTP, MCP, and A2A transports
Readme
Areev TypeScript SDK
TypeScript client library for the Areev knowledge database.
What is a grain?
A grain is the atomic unit of memory in Areev — one immutable, hash-chained,
cryptographically verifiable fact. Every remember, recall, and grains.*
call operates on grains. There are 10 grain types (Fact, Event, State,
Workflow, Tool, Observation, Goal, Reasoning, Consensus, Consent); the two
you will use most are Fact (a subject–relation–object fact, e.g. "John
likes coffee") and Observation (raw natural-language text that Areev later
distills into Facts). Each stored grain is content-addressed by a SHA-256
blob_hash — that hash is what grains.add / grains.supersede return and what
grains.get / grains.forget take.
Installation
npm install @areev/sdkQuick Start
import { Areev } from "@areev/sdk";
const areev = new Areev(); // reads AREEV_API_KEY, AREEV_URL from env
await areev.remember("John likes coffee");
const { results } = await areev.recall("what does John like?");
console.log(results);Everything beyond remember/recall lives on a resource namespace
(areev.grains, areev.tools, areev.harness, areev.memories, …):
const hash = await areev.grains.add("fact", {
subject: "john", relation: "likes", object: "coffee", confidence: 0.95,
});
const grain = await areev.grains.get(hash);
await areev.grains.forget(hash);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:
const areev = new Areev({
apiKey: "ar_...",
url: "https://dub.areev.ai",
memoryId: "my-memory",
});API
The client exposes two bare top-level methods and 22 resource namespaces.
| Top-level method | Description |
|------------------|-------------|
| remember(text) | Store natural-language memory (LLM extracts structure) |
| recall(query) | Search memories |
Everything else is a resource namespace off the client. They split into a small Core set that most applications use, and an Advanced set for specialized workflows (governance, connectors, agent identity, bulk import).
Core namespaces
| Namespace | Example | What it's for |
|-----------|---------|---------------|
| grains | grains.add(type, fields), grains.recall(query), grains.get(hash), grains.forget(hash), grains.supersede(oldHash, fields) | Direct grain CRUD + search |
| harness | harness.chat(...), harness.chatInteractive(...), harness.create(...) | Conversational agents (Areev runs the LLM + tool loop) |
| tools | tools.bind(...), tools.bindAxtion(...), tools.invoke(...), tools.list(slug) | Declare + invoke an agent's callable tools |
| memories | memories.list(), memories.stats(memoryId) | List + inspect memory databases |
| system | system.health(), system.config(), system.models() | Server health + capability discovery |
Advanced namespaces
| Namespace | What it's for |
|-----------|---------------|
| connectors | Third-party connector catalog + OAuth handshake (Axtion-backed) |
| connections | Stored provider credentials that back a Knowledge Source |
| knowledgeSources | Sync external sources (Drive, Dropbox, Confluence, Notion, Web Search) into memory |
| chat | Low-level streaming chat (SSE) — most callers want harness instead |
| sessions / goals | Session context windows + goal tracking |
| consent / compliance / scope | GDPR/CCPA consent, data-subject export/erasure, scope-level erase |
| authz / agentIdentities / policy | ReBAC grants, agent DIDs/delegation, policy engine |
| provenance | Which grains fed a given recall |
| hooks / imports / namespaces / preferences | Webhooks, bulk import/export, namespace admin, per-principal prefs |
connectorsvsconnectionsvschatvsharness—connectorsis the third-party connector catalog + OAuth handshake (Axtion-backed; discover + authorize a provider);connectionsis the stored credential a Knowledge Source then syncs against;chatis the low-level SSE stream where you drive the LLM yourself;harnessis the managed agent runtime where Areev runs the LLM + tool loop for you (what most callers want).
The full set: grains, memories, tools, harness, chat, knowledgeSources, compliance, consent, goals, sessions, hooks, authz, agentIdentities, policy, provenance, scope, preferences, imports, namespaces, system, connectors, connections.
Harness Chat
Use harness.chatInteractive 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:
import { Areev } from "@areev/sdk";
import type { ChatExecutors } from "@areev/sdk";
const areev = new Areev();
const executors: ChatExecutors = new Map();
executors.set("get_weather", async (_name, args) => {
const { city = "unknown" } = (args as { city?: string }) ?? {};
return { city, temp_c: 22, conditions: "sunny" };
});
const response = await areev.harness.chatInteractive({
slug: "weather-harness",
message: "What's the weather in Paris?",
conversationId: "conv-1",
executors,
});
console.log(response.text);harness.chat, harness.chatResume, and harness.chatCancel are the low-level primitives if you want to run the loop yourself.
End-to-End Quickstart
A full flow: 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 { Areev } from "@areev/sdk";
import type { ChatExecutors } from "@areev/sdk";
const areev = new Areev({
apiKey: "ap_local_...", // ap_*/ar_* key
url: "http://localhost:4210", // your cell
memoryId: "my-first-memory",
});
// 1. Remember + recall
await areev.remember("Ada prefers email over Slack");
const hits = await areev.recall("how should I contact Ada?");
for (const h of hits.results) console.log(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",
llmConfig: { provider_id: "openai", model: "gpt-4o-mini" },
// provider_type defaults to provider_id ("openai") automatically.
});
const reply = await areev.harness.chat({ slug: "sales-bot", message: "Say hi" });
console.log(reply);
// 3. Add a client-side tool (executed in your process)
const executors: ChatExecutors = new Map();
executors.set("get_weather", async (_name, args) => {
const { city } = (args as { city?: string }) ?? {};
return { city, temp_c: 22 };
});
await areev.harness.chatInteractive({
slug: "sales-bot",
message: "What's the weather in Paris?",
executors,
});
// 4. Connect a third-party connector (OAuth), then poll for completion
const flow = await areev.connectors.authorize("gmail", {
redirectUri: "https://yourapp.example/oauth/cb",
});
console.log("Open this URL to authorize:", flow.authorizeUrl);
// ... user consents in the browser, provider redirects back ...
let status = await areev.connectors.pollOauth("gmail", flow.state!);
while (status.status === "pending") {
await new Promise((r) => setTimeout(r, 2000)); // back off between polls
status = await areev.connectors.pollOauth("gmail", flow.state!);
}
// 5. Bind a connector action as a tool — schema fetched for you
await areev.tools.bindAxtion({
slug: "sales-bot",
connector: "gmail",
action: "send-email", // the action key from connectors.actions()
description: "Send an email via Gmail",
});Connecting a third-party connector (runnable)
A complete OAuth flow — discover a connector, mint an authorize URL, poll until the credential is stored, then bind one of its actions as a tool. The SDK never touches the provider token; it lives in the Axtion credential vault.
Prerequisite — redirect-uri allowlist.
connectors.authorizefails unless theredirectUriyou pass is on the server-side allowlist (AXTION_OAUTH_ALLOWED_REDIRECT_URIS, a comma-separated list configured on the deployment). Register every callback URL your app uses there first; an unlisted URI is rejected by Axtion before the provider handshake begins.
import { Areev } from "@areev/sdk";
const areev = new Areev();
const REDIRECT_URI = "https://yourapp.example/oauth/cb"; // must be allowlisted
// 1. Discover available connectors.
const catalog = await areev.connectors.list();
console.log(catalog.map((c) => c.name)); // e.g. ["gmail", "google-drive", ...]
// 2. Mint the provider authorize URL and send the user to it.
const flow = await areev.connectors.authorize("gmail", {
redirectUri: REDIRECT_URI,
});
console.log("Open this URL to authorize:", flow.authorizeUrl);
// ... user consents in the browser; the provider redirects back to REDIRECT_URI ...
// 3. Poll until the credential lands in the Axtion vault.
let result = await areev.connectors.pollOauth("gmail", flow.state!);
while (result.status === "pending") {
await new Promise((r) => setTimeout(r, 2000));
result = await areev.connectors.pollOauth("gmail", flow.state!);
}
if (result.status !== "success") {
throw new Error(`OAuth did not complete: ${result.status}`);
}
// 4. Bind a connector action as a fully-typed tool — schema fetched for you.
await areev.tools.bindAxtion({
slug: "sales-bot",
connector: "gmail",
action: "send-email", // an action key from connectors.actions("gmail")
description: "Send an email via Gmail",
});Connectors
client.connectors is the catalog + OAuth surface (backed by Axtion). All methods return clean, parsed data — the SDK never sees provider tokens (they live in the Axtion credential vault):
| Method | Returns |
|--------|---------|
| connectors.list() | [{ name, displayName, category, version }, ...] (parsed from the A2UI catalog) |
| connectors.get(name) | Raw connector detail (metadata + action descriptors) |
| connectors.actions(name) | [{ name, displayName, description, paramSchema, required }, ...] |
| connectors.authorize(name, { redirectUri }) | { authorizeUrl, state } (the redirectUri must be on the server's AXTION_OAUTH_ALLOWED_REDIRECT_URIS allowlist) |
| connectors.pollOauth(name, state) | { status: "pending" \| "success" \| "error" \| "expired" } |
| connectors.storeCredentials(body) | Store API-key credentials (non-OAuth connectors) |
const catalog = await areev.connectors.list();
// → [{ name: "gmail", displayName: "Google Gmail",
// category: "Communication", version: "1.0.0" }, ...]
const actions = await areev.connectors.actions("gmail");
// → [{ name: "send-email", displayName: "Send Email",
// paramSchema: {...}, required: ["to", "subject", "body"] }, ...]tools.bindAxtion({ 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. It throws NotFoundError (listing the available action keys) on an unknown action.
Transports
| Transport | Status | |-----------|--------| | HTTP/REST | Available | | MCP | Planned | | A2A | Planned |
Generated Types
Full OpenAPI types are generated from the Areev spec:
npm run codegenLicense
BUSL-1.1
