Rust SDK
dakera-client v0.12.3 · async (Tokio)dakera-client is the official Rust client for the Dakera REST API, with an optional gRPC transport. This page shows how to install it, connect to a server, and call the memory, session, search, knowledge-graph and admin APIs from async Rust; it is written for Rust developers building agents or services on Dakera.
crates.io · docs.rs · GitHub · Changelog
Current releasedakera-client 0.12.3released 2026-10-22 · release train 0.12.3
import_document(),import_attachment_document(),wait_for_document_job(),list_documents(),get_document(),delete_document().NeighborhoodModeandwith_include_summaries()on recall,context_memorieson the response,matched_texton results.- The API key is redacted from
Debugoutput.
cargo add dakera-client@0.12.3 What changed → All current versions →
# Cargo.toml
[dependencies]
dakera-client = "0.12"
tokio = { version = "1", features = ["full"] }
serde_json = "1"
The latest release is 0.12.3 (edition 2021, stable Rust). The crate declares no minimum supported Rust version; build with a current stable toolchain.
- While a v0.12.0 server starts (models loading),
GET /healthanswers503.client.health()no longer reports that as healthy; gate traffic onclient.ready()(GET /health/ready) orclient.wait_until_ready(timeout). - With authentication on (the default), v0.12.0 requires an API key on gRPC calls. Set it with
GrpcClientConfig::with_api_key(orDAKERA_API_KEY); the client sends it asx-api-key. MemoryPolicy::default()still carriesconsolidated_count: Some(0), a read-only field that v0.12.0 refuses to change. Read the current policy, edit it and write it back (see Memory policy).
Client setup
use dakera_client::DakeraClient;
// Keep the URL and key out of source code, for example:
// export DAKERA_URL=http://<YOUR_SERVER_IP>:3000
// export DAKERA_API_KEY=your-api-key
let client = DakeraClient::builder(
std::env::var("DAKERA_URL").unwrap_or_else(|_| "http://localhost:3000".into()),
)
.api_key(std::env::var("DAKERA_API_KEY").unwrap_or_default())
.build()?;
// Wait for readiness before the first request
let ready = client.ready().await?;
assert!(ready.ready);
DakeraClient::new(url) builds a client without a key, for servers with authentication off. Every method is async and returns dakera_client::Result<T>.
Memory operations
use dakera_client::{BatchForgetRequest, BatchMemoryFilter, BatchRecallRequest,
ForgetRequest, RecallRequest, StoreMemoryRequest};
// Store
let stored = client.store_memory(
StoreMemoryRequest::new("my-agent", "User is learning Rust")
.with_importance(0.8)
.with_tags(vec!["learning".into()]),
).await?;
println!("stored {}", stored.memory_id);
// Recall (semantic search)
let response = client.recall(
RecallRequest::new("my-agent", "which programming language is the user learning?").with_top_k(10),
).await?;
for m in &response.memories {
println!("{} (score: {:.2})", m.content, m.score);
}
// Get, then forget by ID
let memory = client.get_memory("my-agent", &stored.memory_id).await?;
client.forget(ForgetRequest::by_ids("my-agent", vec![memory.id.clone()])).await?;
// Filter-based recall and delete (no embedding)
let tagged = client.batch_recall(
BatchRecallRequest::new("my-agent")
.with_filter(BatchMemoryFilter::default().with_tags(vec!["learning".into()]))
.with_limit(50),
).await?;
let deleted = client.batch_forget(BatchForgetRequest::new(
"my-agent",
BatchMemoryFilter::default().with_tags(vec!["obsolete".into()]),
)).await?;
println!("{} listed, {} deleted", tagged.memories.len(), deleted.deleted_count);
Each recall result's score is the server's ranking score (smart_score). Scores are not comparable with v0.11 scores; re-check any absolute cut-off after upgrading.
Sessions
let session = client.start_session("my-agent").await?;
client.store_memory(
StoreMemoryRequest::new("my-agent", "Found 2 issues in the review")
.with_session(session.id.clone()),
).await?;
let ended = client.end_session(&session.id, Some("Review complete".to_string())).await?;
println!("{} memories in the session", ended.memory_count);
let sessions = client.list_sessions("my-agent").await?;
start_session_with_metadata(agent_id, json) attaches metadata to the session.
ChatMemorySession
ChatMemorySession wraps a session for LLM chat loops: it opens a session on create, stores each turn with its role as a tag, and ends the session on close().
use std::sync::Arc;
use dakera_client::{ChatMemorySession, DakeraClient};
let client = Arc::new(DakeraClient::builder("http://localhost:3000")
.api_key("my-key")
.build()?);
let session = ChatMemorySession::create(Arc::clone(&client), "chat-agent").await?;
session.store("user", "What is the capital of France?").await?;
session.store("assistant", "The capital of France is Paris.").await?;
let memories = session.recall("capital cities").await?;
session.close().await?;
Text documents and search
These methods work on a namespace of documents that the server embeds for you.
use dakera_client::{FullTextSearchRequest, HybridSearchRequest, QueryTextRequest,
TextDocument, UpsertTextRequest};
// Upsert documents (embedded server-side)
client.upsert_text("docs", UpsertTextRequest::new(vec![
TextDocument::new("doc-001", "Quarterly revenue report Q1 2026"),
])).await?;
// Semantic query
let results = client.query_text("docs", QueryTextRequest::new("revenue trends", 5)).await?;
// BM25 full-text search
let hits = client.fulltext_search("docs", FullTextSearchRequest::new("quarterly report", 5)).await?;
// Hybrid search: pass a query vector, or use text_only for BM25 alone
let hybrid = client.hybrid_search("docs", HybridSearchRequest::text_only("revenue", 10)).await?;
Raw vectors use upsert, query, delete, bulk_update_vectors, bulk_delete_vectors and count_vectors; index statistics use fulltext_stats and get_index_stats.
Namespaces
use dakera_client::CreateNamespaceRequest;
client.create_namespace("production", CreateNamespaceRequest::new()
.with_dimensions(1024)
.with_index_type("hnsw")).await?;
let names = client.list_namespaces().await?;
client.delete_namespace("old-namespace").await?;
Memory policy
// Read, edit and write back the namespace's lifecycle policy
let mut policy = client.get_memory_policy("production").await?;
policy.episodic_ttl_seconds = Some(604_800);
policy.working_ttl_seconds = Some(3_600);
client.set_memory_policy("production", policy).await?;
The write replaces the stored policy. Starting from get_memory_policy keeps the fields you do not change, including the read-only consolidated_count.
Knowledge graph
use dakera_client::{DeduplicateRequest, KnowledgeGraphRequest};
// Graph around a seed memory
let graph = client.knowledge_graph(KnowledgeGraphRequest {
agent_id: "my-agent".into(),
memory_id: Some("mem-abc".into()),
depth: Some(2),
min_similarity: None,
}).await?;
// Find near-duplicates without deleting (dry run)
let dupes = client.deduplicate(DeduplicateRequest {
agent_id: "my-agent".into(),
threshold: Some(0.93),
memory_type: None,
dry_run: true,
}).await?;
println!("{} duplicates found", dupes.duplicates_found);
Also available: full_knowledge_graph, summarize, memory_path, knowledge_query, knowledge_export and cross_agent_network (the last needs an admin key with no namespace restriction on v0.12.0).
Entities, feedback and import/export
use dakera_client::FeedbackSignal;
// Extract entities from text
let entities = client.extract_entities("Alice met Bob at Google HQ", None).await?;
// Feedback on a recalled memory
client.feedback_memory("mem-abc", "my-agent", FeedbackSignal::Upvote).await?;
client.patch_memory_importance("mem-abc", "my-agent", 0.9).await?;
let summary = client.get_agent_feedback_summary("my-agent").await?;
// Export an agent's memories as JSONL
let export = client.export_memories("jsonl", Some("my-agent"), None, None).await?;
import_memories(data, format, agent_id, namespace) imports Mem0, Zep, JSONL or CSV data.
Event streaming
// Server-sent memory events (needs an admin key with no namespace restriction)
let mut events = client.stream_memory_events().await?;
while let Some(event) = events.recv().await {
let event = event?;
println!("{} {}", event.event_type, event.agent_id);
}
Admin and operations
Admin methods need an admin key with no namespace restriction on v0.12.0; key management and backup restore, upload and download need super_admin.
use dakera_client::{AutoPilotConfigRequest, AutoPilotTriggerAction, CompactionRequest,
DecayConfigUpdateRequest};
let cluster = client.cluster_status().await?;
let backups = client.list_backups().await?;
let diag = client.ops_diagnostics().await?;
let jobs = client.ops_list_jobs().await?;
client.ops_compact(CompactionRequest { namespace: Some("production".into()), force: false }).await?;
// AutoPilot (background dedup and consolidation)
let status = client.autopilot_status().await?;
client.autopilot_update_config(AutoPilotConfigRequest {
enabled: Some(true),
dedup_threshold: Some(0.93),
..Default::default()
}).await?;
client.autopilot_trigger(AutoPilotTriggerAction::Dedup).await?;
// Decay engine
let decay = client.decay_config().await?;
client.decay_update_config(DecayConfigUpdateRequest {
half_life_hours: Some(168.0),
..Default::default()
}).await?;
Also available: create_backup, slow_queries, ttl_stats, storage_tier_overview, memory_type_stats, admin_enable_maintenance / admin_disable_maintenance, consolidate_agent, get_consolidation_log and the API key methods (create_key, rotate_key, …). See docs.rs for every signature.
gRPC transport
# Cargo.toml
dakera-client = { version = "0.12", features = ["grpc"] }
use dakera_client::grpc::{GrpcClient, GrpcClientConfig};
let grpc = GrpcClient::connect(GrpcClientConfig::new("http://localhost:50051")).await?;
let health = grpc.health().await?;
The gRPC client covers vector operations (upsert, query, delete_vectors, namespaces, health) with connection pooling (GrpcConnectionPool). Against a v0.12.0 server with authentication on, configure the key with GrpcClientConfig::with_api_key.
Timeouts and retries
use std::time::Duration;
use dakera_client::{DakeraClient, RetryConfig};
let client = DakeraClient::builder("http://localhost:3000")
.api_key("your-key")
.timeout(Duration::from_secs(30))
.retry_config(RetryConfig {
max_retries: 3,
base_delay: Duration::from_millis(500),
max_delay: Duration::from_secs(10),
jitter: true,
})
.build()?;
Error handling
use dakera_client::ClientError;
match client.get_memory("my-agent", "mem-abc").await {
Ok(memory) => println!("{}", memory.content),
Err(ClientError::Server { status: 404, .. }) => println!("not found"),
Err(ClientError::RateLimitExceeded { retry_after }) => println!("retry after {retry_after:?} s"),
Err(ClientError::Authorization { status, message, .. }) => eprintln!("{status}: {message}"),
Err(e) => eprintln!("error: {e}"),
}
ClientError variants: Http, Json, Server (status, message, typed code), Authorization, Config, NamespaceNotFound, VectorNotFound, InvalidUrl, Connection, Timeout, RateLimitExceeded, and Grpc with the grpc feature. 401 is reported as Server and 403 as Authorization. Connection errors, timeouts, rate limits and 5xx / 408 responses count as retryable.
See also: REST API reference · Quickstart · Why Rust for AI memory · Go SDK · Python SDK
Rust agent with native memory
cargo add dakera-client adds an async Rust client built on Tokio, with typed requests and responses and a typed error enum. A good fit for latency-sensitive agent loops written in Rust.