Skip to main content

Composable agentic framework on top of atomr actors and atomr-infer.

Project description

atomr-agents

A native Rust agentic framework built as a layered actor / strategy / harness substrate on top of atomr and atomr-infer. atomr-agents gives you a single mental model — pluggable strategies that resolve under shared budgets, channelled state with first-class checkpointing, tool-call orchestration with parallel dispatch, and durable harness loops — that scales from a one-off chatbot to a multi-tenant production agent platform.

use atomr_agents::prelude::*;

// One Pipeline composes prompt → model → parser like LCEL.
let pipeline = Pipeline::from(prompt)
    .then(model)
    .then(parser)
    .build();

let answer = pipeline.call(input, ctx).await?;

Python parity wave

The Python facade in 0.3 catches up to the Rust surface. The native extension atomr_agents._native is now split into hierarchical submodules — errors, core, observability, registry, tool, skill, persona, agent, workflow, harness, eval, guest — mirroring atomr-infer/inference-py-bindings. The top-level package re-exports the full surface, ships a PEP 561 py.typed marker, and exposes async coroutines / async iterators over pyo3-async-runtimes.

Install

pip install atomr-agents

For an editable workflow against the local checkout:

pip install maturin
maturin develop --features python -m crates/py-bindings/Cargo.toml
pip install -e ".[dev]"

Host-mode async event stream

EventBus.stream() returns an EventStream that implements the Python async iterator protocol. Drive a producer on the same loop and consume events as they fire:

import asyncio
from atomr_agents.observability import EventBus


async def main() -> None:
    bus = EventBus()
    stream = bus.stream()

    bus.emit_tool_invoked("calc", args_hash=0, elapsed_ms=5, ok=True)
    bus.emit_tool_invoked("search", args_hash=1, elapsed_ms=12, ok=True)

    async for ev in stream:
        print(ev.kind, ev.timestamp_ms)
        if ev.kind == "tool_invoked" and ev.tool == "search":
            break


asyncio.run(main())

Async registry publish

Registry.publish_async returns a Python awaitable backed by a tokio future, so version pins land without blocking the event loop:

import asyncio
from atomr_agents.registry import Registry


async def main() -> None:
    registry = Registry()
    record = await registry.publish_async(
        "tool_set", "calc", "0.1.0", {"name": "calc"}
    )
    print(record.kind, record.id, record.version)


asyncio.run(main())

Guest-mode @tool decorator

atomr_agents.guest exposes real decorators wired through _native.guest.register_*_factory. A guest tool is a class with an async def invoke(self, args, ctx) method:

from atomr_agents.guest import tool


@tool(toolset="calc")
class Add:
    name = "add"

    async def invoke(self, args: dict, ctx) -> dict:
        return {"sum": args["a"] + args["b"]}

Mirror decorators are available for @strategy, @persona, @skill, @parser, @scorer, @memory_store, and @embedder.

Where things live

The hierarchical layout is reflected in the Python facade — every submodule has a one-to-one .py mirror under atomr_agents/:

from atomr_agents.errors import RegistryError
from atomr_agents.core import TokenBudget, AgentId
from atomr_agents.agent import AgentSpec, AgentBudgets
from atomr_agents.tool import ToolDescriptor, ToolCallParser
from atomr_agents.observability import EventBus, RunTreeBuilder
from atomr_agents.registry import Registry

The top-level package keeps the 0.2.x convenience names — so from atomr_agents import EventBus, Registry still works.

Roadmap

Agent.run_turn, Harness.run, and WorkflowRunner.run are not yet exposed as Python coroutines. The Rust types are generic over four-plus strategy traits, so PyO3 cannot construct them from a stable #[pyclass] shape; they need a Boxed* adapter (BoxedAgent / BoxedHarness / BoxedWorkflow) under crates/agent / crates/harness / crates/workflow. Until that adapter lands, host code drives the loop in Rust and observes progress over the (already async-iterable) EventBus. See docs/python-api.md for the full module map.

Why an agentic framework, in Rust, on actors

Agentic systems don't fail because the models aren't good enough — they fail because the substrate underneath them treats context, composition, and persistence as afterthoughts. Glue-code retry policies, opaque memory, hand-rolled tool loops, brittle handoff between agents — that's where 3 a.m. pages come from.

Composition is the unit of work. A real agent is a Pipeline of prompts, models, parsers, and tools — each with its own retry, fallback, timeout, cache, and trace policy. atomr-agents makes every component a Callable with the same composition surface, so with_retry, with_fallbacks, and with_config apply uniformly to prompts, models, retrievers, and parsers alike.

State is channelled, durable, and forkable. Long-running agents need more than chat history. They need typed channels with reducers (AppendMessages, MergeMap, LastWriteWins, MaxByTimestamp), per-super-step checkpoints keyed by (workflow, run, step), and fork-with-edit so an operator can branch a divergent run from any prior state. atomr-agents ships LangGraph's state model verbatim in atomr's actor idiom.

Tool calls are parallel and provider-agnostic. When a model emits five tool calls in one turn, atomr-agents fans them into a JoinSet and aggregates in original order. The streaming tool_call_delta parser handles OpenAI and Anthropic deltas natively; new providers plug in behind the same Provider enum. Per-call deltas are also surfaced as Event::ToolCallStreamed so tracers and UIs see tool intent in real time, distinct from the post-call Event::ToolInvoked. RichTool returns ToolReturn::{Content, ContentAndArtifact, Command} so a tool can also drive graph control flow.

Provider runtimes are opt-in feature flags. Enable provider-anthropic, provider-openai, or provider-gemini on the umbrella to pull the corresponding atomr-infer-runtime-* crate and re-export its *Config / *Pricing / *Runner via atomr_agents::agent::providers::{anthropic, openai, gemini}. Cost reports include cached_tokens (Anthropic prompt-cache, OpenAI cached input) and reasoning_tokens (o1-style) automatically.

Granular efficiency. Rust gives us deterministic resource use, zero-cost abstractions, and ownership-as-concurrency-safety. Strategy trait generics monomorphize the per-turn pipeline; Box<dyn> opt-in exists for config-driven loading. The whole 26-crate workspace builds under cargo check --workspace in seconds and ships zero runtime overhead beyond what the actor crate already pays.

What's in the box

Crate What it does
atomr-agents Umbrella facade re-exporting the public surface, feature-flag-driven
atomr-agents-core Ids, budgets (token / time / money / iteration), AgentContext, RunId, structured Event taxonomy, error types
atomr-agents-callable Callable trait, CallableHandle, Pipeline builder (then / fan_out / assign), decorators (with_retry / with_fallbacks / with_config / with_timeout / Branch / Lambda)
atomr-agents-strategy Strategy trait family (ToolStrategy, MemoryStrategy, SkillStrategy, RoutingStrategy, PolicyStrategy, LoopStrategy, TerminationStrategy) + combinators
atomr-agents-context ContextAssembler — priority-merge under a TokenBudget
atomr-agents-observability EventBus, RunTree builder, Tracer trait, StdoutTracer / JsonlTracer / LangSmithTracer
atomr-agents-state StateSchema + 5 reducers, RunState, Checkpointer trait + InMemoryCheckpointer, fork-with-edit; SQLite/Postgres backend stubs behind features
atomr-agents-tool Tool / RichTool traits, ToolDescriptor, ToolSet + ToolSetRegistry, PermissionSpec, provider-aware ToolCallParser (OpenAI / Anthropic), HandoffTool
atomr-agents-skill Skill, SkillSet, Static / Keyword skill strategies
atomr-agents-memory MemoryStore (short-term) + LongStore (long-term, namespace-tupled), RecencyMemoryStrategy / SummarizingMemoryStrategy / ChainedMemoryStrategy, WriteMemoryTool / UpdateMemoryTool / RecallMemoryTool
atomr-agents-embed Embedder trait, MockEmbedder, AnnIndex + InMemoryAnnIndex, EmbeddingToolStrategy
atomr-agents-retriever Retriever zoo: Bm25 / Vector / MultiQuery / ContextualCompression / ParentDocument / Ensemble (RRF) / SelfQuery / EmbeddingsFilter / TimeWeighted
atomr-agents-ingest Loader (text / md / json / csv) + splitters (Recursive / MarkdownHeader / Code / Token / Semantic) + CachedEmbedder + IngestPipeline
atomr-agents-persona All five structural strategies (Static, BigFive, Mbti, Jungian, Composite) + emphasis strategies (Static, AudienceAdaptive, TaskAdaptive, MoodState, GoalConditioned)
atomr-agents-instruction ComposedInstructionStrategy<P, T, B>, ChatPromptTemplate, MessagesPlaceholder, FewShotChatTemplate, LengthBasedSelector / SemanticSimilaritySelector
atomr-agents-agent Agent<I, T, Ms, Sk> actor + per-turn pipeline, tool-call loop with parallel dispatch, AgentMiddleware (logging / retry / rate-limit / redaction / tool-error-recovery), InferenceClient adapter for any ModelRunner
atomr-agents-workflow DAG primitives, WorkflowRunner, StatefulRunner (channelled state), Interruptible (interrupt() + interrupt_before / _after + Command::{Continue, Resume, Update, Goto}), Subgraph, dispatch_fan_out (Send-API analogue)
atomr-agents-harness Harness<L, T> actor, LoopStrategy / TerminationStrategy, durable iteration log; Harness is itself a Callable
atomr-agents-org Org / Department / Team, OrgRoutingStrategy impls (RoundRobin / LoadAware / CapabilityMatch), Policy::narrow, NamespacedMemory (read-cascade + write-gating), swarm_loop helper
atomr-agents-registry Versioned artifact registry with (kind, id, version) keys + publish_gated for eval-regression blocking
atomr-agents-eval EvalSuite, Scorer (Contains / Equality / Regex / LlmJudgeScorer / RubricScorer / PairwiseScorer), RegressionGate, AnnotationQueue
atomr-agents-cache LlmCache trait + InMemoryLlmCache + SemanticLlmCache (cosine match on prompt embedding); SQLite/Redis backend stubs behind features
atomr-agents-parser Parser<T> trait, JsonParser / JsonSchemaParser / SchemaParser<T> / EnumParser / CommaListParser / XmlParser / YamlParser, OutputFixingParser, RetryWithErrorParser, StreamingPartialJsonParser
atomr-agents-stt-core SpeechToText / StreamingSession traits, Capabilities (advertised per backend via a pub const), AudioInput / Transcript / StreamEvent, MockSpeechToText
atomr-agents-stt-remote-core Shared HTTP / WebSocket plumbing for cloud STT backends: reqwest client builder, tokio-tungstenite connect helper, SecretRef (env / literal / file), retry / rate-limit / timeout config
atomr-agents-stt-audio symphonia-based decoder, rubato resampler, and (feature mic) cpal-based MicCaptureSession with backpressure-aware mpsc producer
atomr-agents-stt-runtime-openai OpenAI Whisper / gpt-4o-transcribe REST batch backend
atomr-agents-stt-runtime-deepgram Deepgram REST + WebSocket backend; speaker-count diarization, partial results, VAD endpointing
atomr-agents-stt-runtime-assemblyai AssemblyAI REST upload + Universal-Streaming WebSocket; named-speaker diarization
atomr-agents-stt-runtime-whisper Local whisper.cpp via whisper-rs (gated behind the whisper-cpp feature). Optional download-models helper fetches ggml weights
atomr-agents-stt-diarize-sherpa Diarizer trait, MockDiarizer, sherpa-onnx-backed SherpaDiarizer (gated behind sherpa-onnx), apply_to_transcript stitching
atomr-agents-stt-voice VoiceSession (Live vs TurnBased { silence_ms }), Vad trait + EnergyVad/SileroVad, pump_mic_to_stream glue
atomr-agents-stt-tool TranscribeTool (a Tool the model can call) and voice_input_skill(stt) -> (Skill, DynTool) for declarative agent integration
atomr-agents-py-bindings atomr_agents._native PyO3 module — Event / EventBus / Registry / stt.SpeechToText / voice.VoiceSession exposed to Python
atomr-agents-cli atomr-agents binary with eval / registry / harness / serve (Studio-style read+resume inspector) subcommands
atomr-agents-testkit Stub crate today. For tests, depend on atomr-infer-testkit (re-exports MockRunner / MockScript) directly — that's what crates/agent tests use.

Plus a Python facade — pip install atomr-agents — that exposes the host-mode Registry / EventBus and the guest-mode @tool / @strategy / @persona decorators.

Quick start (Rust)

The umbrella crate is published on crates.io as atomr-agents:

[dependencies]
atomr-agents = { version = "0.2", features = ["agent", "harness", "eval"] }
atomr-infer  = { version = "0.6", features = ["openai"] }   # or any provider

Or, to pull a provider runtime through the umbrella so Agent / LocalRunnerClient / OpenAiRunner come from one crate:

atomr-agents = { version = "0.2", features = ["agent", "provider-openai"] }
# or features = ["agent", "provider-anthropic"], ["agent", "provider-gemini"]

A minimal agent against MockRunner (good for tests; swap for any ModelRunner in production):

use std::sync::Arc;
use atomr_agents::prelude::*;
use atomr_agents::agent::{Agent, AgentBudgets, InferenceClient, LocalRunnerClient, Provider};
use atomr_agents::tool::{StaticToolStrategy, DynTool};
use atomr_agents::memory::{InMemoryStore, RecencyMemoryStrategy};
use atomr_agents::skill::StaticSkillStrategy;
use atomr_agents::persona::StaticPersonaStrategy;
use atomr_agents::instruction::{
    ComposedInstructionStrategy, StaticBehaviorStrategy, StaticTaskStrategy,
};
use atomr_agents::observability::EventBus;
use atomr_infer_testkit::{MockRunner, MockScript};

let runner = MockRunner::new(MockScript::from_text(["the answer is ", "42"]));
let inference: Arc<dyn InferenceClient> =
    Arc::new(LocalRunnerClient::new(runner, Provider::OpenAi));

let agent = Agent {
    id: AgentId::from("a-1"),
    model: "mock".into(),
    instructions: ComposedInstructionStrategy::new(
        StaticPersonaStrategy::new("You are a helpful assistant."),
        StaticTaskStrategy("Answer arithmetic questions.".into()),
        StaticBehaviorStrategy("Reply tersely.".into()),
    ),
    tools: StaticToolStrategy::new(Vec::<DynTool>::new()),
    memory: RecencyMemoryStrategy::new(Arc::new(InMemoryStore::new()), 5, 30),
    skills: StaticSkillStrategy::new(vec![]),
    inference,
    bus: EventBus::new(),
    max_tool_iterations: 3,
};

let r = agent
    .run_turn("what's 1+2".into(), AgentBudgets::default())
    .await?;
println!("{}", r.text);

Add tools, switch the MockRunner to a real ModelRunner (OpenAI, Anthropic, vLLM, …), and the same code runs unchanged.

Quick start (Python)

pip install atomr-agents
from atomr_agents import EventBus, Registry

bus = EventBus()
bus.subscribe(lambda ev: print(ev.kind, ev.timestamp_ms))

registry = Registry()
registry.publish("tool_set", "ts", "0.1.0", {"tools": ["calc"]})
print(registry.latest("tool_set", "ts"))

See docs/python.md for the full host/guest model and the subinterpreter-pool dispatcher pattern inherited from atomr's pycore.

Documentation map

License

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

atomr_agents-0.6.0-cp311-cp311-win_amd64.whl (4.1 MB view details)

Uploaded CPython 3.11Windows x86-64

atomr_agents-0.6.0-cp311-cp311-manylinux_2_34_x86_64.whl (4.3 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.34+ x86-64

atomr_agents-0.6.0-cp311-cp311-manylinux_2_34_aarch64.whl (4.3 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.34+ ARM64

atomr_agents-0.6.0-cp311-cp311-macosx_11_0_arm64.whl (4.0 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

File details

Details for the file atomr_agents-0.6.0-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for atomr_agents-0.6.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 58c22d71634d595d270dc2705287df01706744dcac877f79629520a86243c3cc
MD5 06f8a2939be065faa486c206a5ca7044
BLAKE2b-256 f62c7d22838fc2ada7c0feb777ffc39d1585a6495f00b2d1dec0992de54286f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for atomr_agents-0.6.0-cp311-cp311-win_amd64.whl:

Publisher: release.yml on rustakka/atomr-agents

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file atomr_agents-0.6.0-cp311-cp311-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for atomr_agents-0.6.0-cp311-cp311-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 c95dffce510e66dcfd3793e610ce438ff40f408d990edadc0ca55b9792e7cf4f
MD5 6db12a5d3e18a62c36bd093b2f00fbaa
BLAKE2b-256 fa565af295282afdf1dfc65b13cc2dbc579b57178f34058588c254580dc97545

See more details on using hashes here.

Provenance

The following attestation bundles were made for atomr_agents-0.6.0-cp311-cp311-manylinux_2_34_x86_64.whl:

Publisher: release.yml on rustakka/atomr-agents

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file atomr_agents-0.6.0-cp311-cp311-manylinux_2_34_aarch64.whl.

File metadata

File hashes

Hashes for atomr_agents-0.6.0-cp311-cp311-manylinux_2_34_aarch64.whl
Algorithm Hash digest
SHA256 8f33e964792443a16cf2ee0abf57b0740d0f198e9b01dabb9cc100c960870a77
MD5 cf35b087cba66cfca262a04ac0a0b284
BLAKE2b-256 e3d72f32d6d77ed7071c98bcdf4660f51b76f674930cbad78f18ac37c72998f1

See more details on using hashes here.

Provenance

The following attestation bundles were made for atomr_agents-0.6.0-cp311-cp311-manylinux_2_34_aarch64.whl:

Publisher: release.yml on rustakka/atomr-agents

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file atomr_agents-0.6.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for atomr_agents-0.6.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9809a907a6d71998d2ae114af04c34bff29a3ee41891d3edee2378e66d22fd6f
MD5 e7c3df95ef30ffd795a16b1b432c6965
BLAKE2b-256 49877048974e3de838f23b077f371a0f14240fe62cdcb711a195b2b187bca85b

See more details on using hashes here.

Provenance

The following attestation bundles were made for atomr_agents-0.6.0-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: release.yml on rustakka/atomr-agents

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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