entelix 0.5.4

entelix — web-service-native Rust agentic AI SDK (facade re-export crate)
Documentation

entelix

Rust 1.95 Edition 2024 License: MIT

English | 한국어

Where every agent realizes its purpose.

General-purpose agentic-AI SDK in Rust. Build any agent that runs an LLM-driven control loop with tools, memory, and durable state. Multi-tenant from day 1. OpenTelemetry GenAI semconv-native. Architectural invariants enforced by CI. Anthropic managed-agents shape. LangChain + LangGraph parity.


Why entelix?

  • Multi-tenant firstTenantId at every persistence boundary; Postgres FORCE ROW LEVEL SECURITY is defense-in-depth on every backend; cross-tenant data leakage is structurally impossible by API design.
  • Type-enforced architecture — sealed RenderedForLlm<T> carrier (compile-time LLM / operator channel separation); sealed CompactedHistory (tool_call / tool_result pair invariant impossible to break); TenantId newtype with validating constructor.
  • Production observability from day 1 — OpenTelemetry GenAI semconv gen_ai.* attributes; cost emits transactionally (Ok branch only); typed AuditSink channel records sub-agent invocation / supervisor handoff / wake-resume / memory recall / usage-limit breach / context-compaction events without coupling emit sites to a persistence backend.
  • Cross-vendor IR — Anthropic Messages, OpenAI Chat, OpenAI Responses, Gemini, and Bedrock Converse codecs route across Direct (any HTTPS), Bedrock (SigV4), Vertex (gcp_auth), and Foundry (api-key + AAD) transports. Capability honesty: LossyEncode warnings on every coerced field, Other { raw } for unknown vendor signals — no silent fallback.
  • MCP first-class — every server-initiated channel (Roots, Elicitation, Sampling); per-tenant (tenant_id, server_name) pool isolation; HTTP-only by design.
  • CI-enforced invariantscargo xtask invariants runs typed-AST visitors per push for filesystem-free, naming taxonomy, silent-fallback, lock-ordering, public-API drift, supply-chain, feature-matrix gates.

Quick Start

cargo add entelix
use std::sync::Arc;
use entelix::auth::ApiKeyProvider;
use entelix::codecs::AnthropicMessagesCodec;
use entelix::ir::Message;
use entelix::transports::DirectTransport;
use entelix::{ChatModel, ExecutionContext};

#[tokio::main]
async fn main() -> entelix::Result<()> {
    entelix::install_default_tls();
    let creds = Arc::new(ApiKeyProvider::anthropic(std::env::var("ANTHROPIC_API_KEY")?));
    let transport = DirectTransport::anthropic(creds)?;
    let model = ChatModel::new(AnthropicMessagesCodec, transport, "claude-opus-4-7")
        .with_system("Answer in one sentence.");

    let reply = model
        .complete(vec![Message::user("Define entelechy.")], &ExecutionContext::new())
        .await?;
    println!("{reply:?}");
    Ok(())
}

Key Features

LLM call — cross-vendor IR

// Same `ModelRequest` IR routes through every codec.
// `LossyEncode` warnings expose every coerced field.
let model = ChatModel::new(AnthropicMessagesCodec, transport, "claude-opus-4-7")
    .with_validation_retries(2);                     // schema-mismatch retry budget

let reply: Translation = model
    .complete_typed::<Translation>(messages, &ctx)   // typed structured output
    .await?;

LCEL composition

use entelix::{ChatPromptTemplate, JsonOutputParser, RunnableExt};

let chain = prompt.pipe(model).pipe(parser);       // compile-time I/O checking
let result = chain.invoke(input, &ctx).await?;

StateGraph control flow (LangGraph parity)

use entelix::{Annotated, Append, Max, StateGraph, StateMerge, RunnableLambda};

#[derive(Clone, Default, StateMerge)]
struct AgentState {
    log: Annotated<Vec<String>, Append<String>>,    // accumulated across nodes
    score: Annotated<i32, Max<i32>>,                // best-of across branches
    last_phase: String,                             // last-write-wins
}

let graph = StateGraph::<AgentState>::new()
    .add_contributing_node("plan", plan)            // typed delta + per-field merge
    .add_send_edges("plan", ["a", "b", "c"], scatter, "score")  // parallel fan-out
    .add_conditional_edges("score", router, [("plan", "plan"), ("done", entelix::END)])
    .set_entry_point("plan")
    .with_checkpointer(Arc::new(postgres_checkpointer))         // resume after crash
    .compile()?;

Auto-compaction (Claude Agent SDK parity)

use entelix::{HeadDropCompactor, MessageRunnableCompactionExt, SummaryCompactor};

// Drop oldest turns when context approaches threshold.
let model = my_model.with_compaction(Arc::new(HeadDropCompactor), 8_192);

// Or LLM-summary compaction (LangChain SummarizationMiddleware parity).
let summariser = SummaryCompactor::new(Arc::new(summary_model));
let model = my_model.with_compaction(Arc::new(summariser), 8_192);

Production HTTP server

use entelix::{AgentRouterBuilder, SERVER_DEFAULT_TENANT_HEADER};

let router = AgentRouterBuilder::new(agent)
    .with_checkpointer(Arc::clone(&postgres_checkpointer))
    .with_tenant_header(SERVER_DEFAULT_TENANT_HEADER)   // multi-tenant strict mode
    .build()?;

let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?;
axum::serve(listener, router).await?;

Endpoints: POST /v1/threads/{thread_id}/runs, GET /v1/threads/{thread_id}/stream, POST /v1/threads/{thread_id}/wake, GET /v1/health.

Tools — built-in + #[tool] macro

use entelix::tool;

#[tool]
/// Add two numbers.                              // first paragraph → LLM-facing description
async fn add(_ctx: &AgentContext<()>, a: i64, b: i64) -> Result<i64> {
    Ok(a + b)
}
// Generates `Add` unit struct + `SchemaTool` impl + JSON Schema.

Built-ins: HttpFetchTool (layered SSRF defense — allowlist, DNS resolver, redirect / size caps), Calculator, SchemaTool typed-I/O adapter. Sandboxed shell / file / code / list-dir tools live in the entelix-tools-coding companion crate and delegate syscalls through the Sandbox trait.

Memory patterns

BufferMemory (sliding window), SummaryMemory (rolling LLM summary), ConsolidatingBufferMemory (auto-summary on size threshold), EntityMemory (entity-keyed facts), EpisodicMemory<V> (time-ordered episodes), SemanticMemory<E, V> (vector retrieval), GraphMemory<N, E> (typed nodes + timestamped edges, BFS traversal + shortest-path).

MCP — every server-initiated channel

use entelix::{ChatModelSamplingProvider, McpServerConfig, StaticRootsProvider};

let server = McpServerConfig::http("https://server.example/mcp")
    .with_roots_provider(Arc::new(StaticRootsProvider::new(roots)))
    .with_sampling_provider(Arc::new(ChatModelSamplingProvider::new(chat)));

How entelix differs

Feature LangChain LangGraph Claude Agent SDK pydantic-ai entelix
Language Python Python TypeScript Python Rust
Multi-tenant first-class
Postgres FORCE RLS
Graph memory (typed nodes/edges + BFS)
Auto-compaction (drop + LLM-summary)
Typed structured output + retry budget
Sealed LLM/operator channel carrier
OTel GenAI semconv native
Typed audit sink (record_* verbs)
Run budget axes (incl. USD cost) ✓ (no USD) ✓ (incl. USD)
Vendor-specific extension escape-hatch (*Ext)
Distributed session lock (Postgres + Redis)
MCP server-initiated channels (full coverage)
CI-enforced architectural invariants

What entelix is NOT

  • No direct filesystem / shell calls in first-party crates — sandboxed wrappers (SandboxedShellTool, SandboxedReadFileTool, …) ship in the entelix-tools-coding companion crate and every syscall delegates through the Sandbox trait. Concrete Sandbox impls (Landlock / Seatbelt / e2b / modal) live as companion crates, not in core.
  • No local inference — application-layer SDK; pair with candle / mistral.rs if you need it.
  • No vector DB reimplementation — production VectorStore impls ship as entelix-memory-qdrant / entelix-memory-pgvector; bring your own via the trait.
  • No document loaders — that's swiftide's job.
  • No Python interop — Rust-first.

Workspace

entelix                  — facade (re-exports gated by feature flags)
entelix-core             — IR, Codec, Transport, Tool, Auth, ChatModel + tower::Service spine
entelix-runnable         — Runnable trait + LCEL .pipe() + Sequence/Parallel/Router/Lambda
entelix-prompt           — PromptTemplate, ChatPromptTemplate, MessagesPlaceholder, FewShot
entelix-graph            — StateGraph, Reducer, StateMerge trait, Dispatch, Checkpointer, interrupts
entelix-graph-derive     — proc-macro: #[derive(StateMerge)] emits Contribution + builders + impl
entelix-tool-derive      — proc-macro: #[tool] generates SchemaTool impl from an async fn signature
entelix-session          — SessionGraph event log + Compactor + SessionAuditSink, fork, archival watermark
entelix-memory           — Store + Embedder/Retriever/EmbeddingRetriever/VectorStore/GraphMemory traits + memory patterns
entelix-memory-openai    — OpenAI Embeddings concrete Embedder (companion)
entelix-memory-qdrant    — qdrant gRPC concrete VectorStore (companion)
entelix-memory-pgvector  — Postgres + pgvector concrete VectorStore with row-level security (companion)
entelix-graphmemory-pg   — Postgres concrete GraphMemory with WITH RECURSIVE BFS + UNNEST bulk insert (companion)
entelix-rag              — RAG primitives (Document/Lineage, splitters, Chunker, IngestionPipeline) + corrective-RAG (CRAG) recipe
entelix-persistence      — Postgres + Redis Checkpointer/Store/SessionLog with row-level security + advisory lock
entelix-tokenizer-tiktoken — Vendor-accurate TokenCounter wrapping tiktoken-rs (OpenAI BPE: cl100k_base / o200k_base / p50k_base / r50k_base)
entelix-tokenizer-hf     — Vendor-accurate TokenCounter wrapping HuggingFace `tokenizers` (Llama / Qwen / Mistral / DeepSeek / Gemma / Phi)
entelix-tools            — HttpFetchTool, Calculator, SchemaTool, skills, memory tools
entelix-tools-coding     — Sandbox-trait-backed shell / code / fs tools + Anthropic Skills layout (vertical companion)
entelix-mcp              — native JSON-RPC 2.0 over MCP streamable-http; Roots + Elicitation + Sampling channels; ChatModelSamplingProvider behind `chatmodel-sampling` feature
entelix-cloud            — Bedrock (SigV4) / Vertex (gcp_auth) / Foundry (AAD) transports
entelix-policy           — TenantPolicy, RateLimiter, PiiRedactor, CostMeter, QuotaLimiter, PolicyLayer
entelix-otel             — OpenTelemetry GenAI semconv tower::Layer + cache token telemetry + agent root span
entelix-server           — axum HTTP + multi-mode SSE + tenant middleware
entelix-auth-claude-code — Claude.ai OAuth credential provider (Claude Code CLI shared storage)
entelix-agents           — ReAct, Supervisor, Hierarchical, Chat recipes + Subagent

entelix-core depends on no other entelix crate. The DAG is enforced at workspace level.

The facade entelix crate gates optional sub-crates behind feature flags so you don't pay for layers you don't use. Canonical list in crates/entelix/Cargo.tomlfull enables every feature.


Examples

Working examples under crates/entelix/examples/ — quickstart through end-to-end production workflow, covering LCEL composition, StateGraph control flow (16_state_merge_pipeline shows derive(StateMerge) + add_contributing_node + add_send_edges end-to-end), HITL graph interrupts (04_hitl) and HITL tool-dispatch approval pause-and-resume (18_tool_approval), memory, multi-agent supervisor / hierarchical recipes, every streaming mode, every codec × transport pair, MCP per-tenant isolation, MCP sampling via ChatModelSamplingProvider (17_mcp_sampling_provider), auto-compaction (25_auto_compaction), and the axum AgentRouterBuilder.


Inspirations

  • Anthropic Managed Agents — Session / Harness / Hand decoupling, cattle-not-pets, lazy provisioning
  • LangChain LCELRunnable + .pipe() composition primitive
  • LangGraph — typed state-graph control flow + Annotated[T, reducer] + Checkpointer + HITL
  • OpenTelemetry GenAI semconv — vendor-neutral observability vocabulary

Reading order

  1. CLAUDE.md — invariants, lock ordering, error conventions, managed-agent shape
  2. docs/architecture/principles.md — living design contract
  3. Per-crate crates/<name>/CLAUDE.md — surface, crate-local rules, forbidden patterns
  4. docs/public-api/ — frozen per-crate API baselines (facade excluded by design)

Support


License

MIT.


English | 한국어

Made with Rust 🦀