areev 0.2.0

Rust SDK for the Areev knowledge database — gRPC and HTTP transports
Documentation
//! High-level Areev client.
//!
//! Holds an [`HttpClient`] and exposes the bare `remember` / `recall`
//! verbs plus the v1.0 resource accessors ([`Areev::memories`],
//! [`Areev::grains`], [`Areev::tools`], [`Areev::harness`],
//! [`Areev::system`], …).

use std::env;

use crate::error::Result;
use crate::http::HttpClient;
use crate::resources::{
    AgentIdentities, Authz, Chat, Compliance, Connections, Connectors, Consent, Goals, Grains,
    Harness, Hooks, Imports, KnowledgeSources, Memories, Namespaces, Policy, Preferences,
    Provenance, Scope, Sessions, System, Tools,
};
use crate::types::{RecallRequest, RecallResponse, RememberRequest, RememberResponse};

const DEFAULT_URL: &str = "https://app.areev.ai";
const DEFAULT_MEMORY: &str = "default";

/// High-level Areev client.
///
/// # Examples
///
/// ```no_run
/// # #[tokio::main]
/// # async fn main() -> areev::Result<()> {
/// use areev::Areev;
///
/// let areev = Areev::from_env();
///
/// // Bare convenience verbs.
/// areev.remember("John likes coffee").await?;
/// let results = areev.recall("what does John like?").await?;
///
/// // v1.0 resource namespaces.
/// let _health = areev.system().health().await?;
/// let _memories = areev.memories().list().await?;
/// # Ok(())
/// # }
/// ```
pub struct Areev {
    inner: HttpClient,
    memory_id: String,
}

impl Areev {
    /// Create a client from environment variables.
    ///
    /// | 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 |
    pub fn from_env() -> Self {
        let api_key = env::var("AREEV_API_KEY").ok();
        let url = env::var("AREEV_URL").unwrap_or_else(|_| DEFAULT_URL.to_string());
        let memory_id = env::var("AREEV_MEMORY_ID").unwrap_or_else(|_| DEFAULT_MEMORY.to_string());
        Self::build(api_key.as_deref(), &url, &memory_id, 3)
    }

    /// Create a client from explicit values.
    pub fn new(api_key: Option<&str>, url: Option<&str>, memory_id: Option<&str>) -> Self {
        Self::build(
            api_key,
            url.unwrap_or(DEFAULT_URL),
            memory_id.unwrap_or(DEFAULT_MEMORY),
            3,
        )
    }

    /// Create a client with a custom max-retry count (default 3).
    pub fn with_max_retries(
        api_key: Option<&str>,
        url: Option<&str>,
        memory_id: Option<&str>,
        max_retries: usize,
    ) -> Self {
        Self::build(
            api_key,
            url.unwrap_or(DEFAULT_URL),
            memory_id.unwrap_or(DEFAULT_MEMORY),
            max_retries,
        )
    }

    fn build(api_key: Option<&str>, url: &str, memory_id: &str, max_retries: usize) -> Self {
        let inner = HttpClient::new(url, memory_id, api_key).with_max_retries(max_retries);
        Self {
            inner,
            memory_id: memory_id.to_string(),
        }
    }

    /// Borrow the underlying [`HttpClient`] — escape hatch for callers
    /// that need a verb the resource layer doesn't expose yet.
    pub fn http(&self) -> &HttpClient {
        &self.inner
    }

    // ── v1.0 resource namespaces ────────────────────────────────────────

    /// Multi-memory CRUD (`list`, `create`, `get`, `delete`).
    pub fn memories(&self) -> Memories<'_> {
        Memories::new(&self.inner)
    }

    /// Grain CRUD on the configured memory.
    pub fn grains(&self) -> Grains<'_> {
        Grains::new(&self.inner, self.memory_id.clone())
    }

    /// Tool grain lifecycle + invocation.
    pub fn tools(&self) -> Tools<'_> {
        Tools::new(&self.inner, self.memory_id.clone())
    }

    /// Conversational harness chat (Flow-A).
    pub fn harness(&self) -> Harness<'_> {
        Harness::new(&self.inner, self.memory_id.clone())
    }

    /// Cluster-level system operations.
    pub fn system(&self) -> System<'_> {
        System::new(&self.inner, self.memory_id.clone())
    }

    /// Per-principal connector catalog + OAuth lifecycle (`list`,
    /// `actions`, `authorize`, `poll_oauth`, `store_credentials`).
    pub fn connectors(&self) -> Connectors<'_> {
        Connectors::new(&self.inner)
    }

    /// Connection records — the bridge from a connected connector to a
    /// Knowledge Source. A record's `id` is the `connection_id` for
    /// [`Self::knowledge_sources`]`().create(...)`.
    pub fn connections(&self) -> Connections<'_> {
        Connections::new(&self.inner)
    }

    /// Knowledge Sources — external content + review-gated proposals.
    /// Requires: Scale or Custom plan.
    pub fn knowledge_sources(&self) -> KnowledgeSources<'_> {
        KnowledgeSources::new(&self.inner, self.memory_id.clone())
    }

    /// App-style assistant chat — threads, messages, tool dispatch, SSE.
    pub fn chat(&self) -> Chat<'_> {
        Chat::new(&self.inner, self.memory_id.clone())
    }

    /// Compliance + data-subject-rights (audit, export, verify, breach,
    /// retention, metrics).
    pub fn compliance(&self) -> Compliance<'_> {
        Compliance::new(&self.inner, self.memory_id.clone())
    }

    /// Per-user, per-purpose consent grants (GDPR Art. 6/7).
    pub fn consent(&self) -> Consent<'_> {
        Consent::new(&self.inner, self.memory_id.clone())
    }

    /// Goal grains — trees, delegation, state transitions.
    pub fn goals(&self) -> Goals<'_> {
        Goals::new(&self.inner, self.memory_id.clone())
    }

    /// Agent-session context — bootstrap, state, actions, context.
    pub fn sessions(&self) -> Sessions<'_> {
        Sessions::new(&self.inner, self.memory_id.clone())
    }

    /// Outbound event webhooks. Requires: Scale or Custom plan.
    pub fn hooks(&self) -> Hooks<'_> {
        Hooks::new(&self.inner, self.memory_id.clone())
    }

    /// ReBAC relationship tuples (OpenFGA-backed).
    pub fn authz(&self) -> Authz<'_> {
        Authz::new(&self.inner, self.memory_id.clone())
    }

    /// Agent-identity (DID) registration + lifecycle.
    pub fn agent_identities(&self) -> AgentIdentities<'_> {
        AgentIdentities::new(&self.inner, self.memory_id.clone())
    }

    /// Compliance policy attachment, resolution, enforcement, residency.
    pub fn policy(&self) -> Policy<'_> {
        Policy::new(&self.inner, self.memory_id.clone())
    }

    /// Recall provenance records (EU AI Act Art. 12 transparency).
    pub fn provenance(&self) -> Provenance<'_> {
        Provenance::new(&self.inner, self.memory_id.clone())
    }

    /// Hierarchical scope tree + scoped crypto-erasure.
    pub fn scope(&self) -> Scope<'_> {
        Scope::new(&self.inner, self.memory_id.clone())
    }

    /// Per-principal key/value preferences (org/user-scoped).
    pub fn preferences(&self) -> Preferences<'_> {
        Preferences::new(&self.inner)
    }

    /// Bulk file/document import + export.
    pub fn imports(&self) -> Imports<'_> {
        Imports::new(&self.inner, self.memory_id.clone())
    }

    /// Namespace-level purge.
    pub fn namespaces(&self) -> Namespaces<'_> {
        Namespaces::new(&self.inner, self.memory_id.clone())
    }

    // ── Bare convenience verbs ──────────────────────────────────────────

    /// Store a natural-language memory. Extracts facts synchronously.
    ///
    /// For the full option set (namespace, user_id, async mode, …) use
    /// [`Areev::grains`]`().add(...)` or post a [`RememberRequest`] via
    /// [`Areev::http`].
    pub async fn remember(&self, text: &str) -> Result<RememberResponse> {
        let req = RememberRequest {
            text: text.to_string(),
            sync: Some(true),
            ..Default::default()
        };
        self.inner.remember(&req).await
    }

    /// Search memories. Returns matching grains.
    ///
    /// For the full recall surface (filters, rerank, multi-hop, …) use
    /// [`Areev::grains`]`().recall(...)`.
    pub async fn recall(&self, query: &str) -> Result<RecallResponse> {
        let req = RecallRequest {
            query: Some(query.to_string()),
            limit: Some(10),
            ..Default::default()
        };
        self.inner.recall(&req).await
    }
}