Changelog¶
0.3.1 (renamed)¶
The project is now "Autonomous Agent Architecture" (AAA). It is much more than a set of algorithms, and the name now says so. What changed:
- The PyPI distribution is
autonomous-agent-architecture(it wasautonomous-agent-algos, whose last release is 0.3.0).pip install autonomous-agent-architecture. - The GitHub repository is
innerkorehq/AutonomousAgentArchitectureand the documentation is at https://innerkorehq.github.io/AutonomousAgentArchitecture/. The old repository address redirects; the old documentation address does not. - The import name is unchanged:
import aaa. No code changes are needed beyond the package name in your requirements. The code is otherwise identical to 0.3.0.
aaa-server 0.1.0 (2026-10-16)¶
First release of the separate aaa-server package (it requires autonomous-agent-architecture>=0.3.1). Everything in the "HTTP server" and "MCP server and A2A" entries under 0.3.0 below ships here, plus: POST /mcp and the experimental A2A endpoint, the Dockerfile/compose.yaml deployment, and the fix that builds an async factory inside the server's own event loop.
0.3.0 (2026-10-16)¶
A large release: everything below is additive to the 0.2 API and log format (see Upgrading).
Operations (see backup and restore, upgrading, performance, deployment)
aaa store verify <store> [--blobs DIR] [--deep]/aaa.events.verify.verify_store: a read-only consistency check of every run's log and blob references, for after a restore. Verified on a restored Postgres dump.scripts/bench_cluster.pyand measured Redis/Postgres multi-worker throughput (with the connection-budget finding).Dockerfile,compose.yamlanddeploy/app.py: the server in a non-root container with Postgres; smoke-tested end to end. No Helm chart.RedisEventStore.create(max_connections=...): the pool now scales with the partition count; the redis-py 8 default of 100 starved a 16-partition worker (Too many connections).- Fix (
aaa-server): anasyncfactory given toaaa-server servewas run in a throw-away event loop, so a connection pool it opened failed with "Event loop is closed" on the first request. The configuration is now built inside the server's own loop.
Evals (see the guide)
- Scores now reach the backends:
LangfuseSink,PhoenixSink,LangSmithSinkandOTelSinkimplementscore()(OnlineEvaluatorpasses the run's span). Verified against real Langfuse 2.x and Phoenix servers; LangSmith by mock only. Dataset.from_traces(scrubbed by default),aaa.eval.redteam(attack corpus,evaluate_guard,attack_suite,NoLeak,Resisted), andSimulatedUser+SessionEvalRunnerfor multi-turn evaluation.CaseResult.turns.
New algorithms (see the guide)
Reflexion(fresh attempts informed by written lessons; validator or LLM critic; lessons returned and re-injectable),Debate(parallel agents, rounds, judge or vote; at most 7 agents and 4 rounds),SwarmwithAgent(handoffs as tool calls: an agent can only use its own tools, one transfer per turn, capped transfers) andTreeOfThoughts(beam search with a hard call bound).LLMLoop.request_for(state, messages)hook (ordinary loops are unchanged);LoopStategainsagent/handoffs, omitted from its serialized form when unused so existing logs and snapshots fold identically. New eventsaaa.swarm.handoffandaaa.reflexion.feedback.
MCP server and A2A (see serving tools over MCP and the server guide)
aaa.mcp.MCPToolServer/serve_stdio/aaa mcp serve: expose aToolRegistryto any MCP client (SDK 1.x and 2.x). Approval-gated tools are hidden unless you provide anapproval=callback; failures never leak internals; tenant and user are fixed by the host;run_agentruns algorithms under a server-side budget and is opt-in.aaa-server:POST /mcp(stateless Streamable HTTP subset, behind the server's auth and limits, Origin-checked) and experimental A2A 1.0 (A2AConfig: agent card,SendMessage,SendStreamingMessage,SubscribeToTask,GetTask,ListTasks,CancelTask), both verified against the officialmcpanda2a-sdkclients.
HTTP server (new package aaa-server; see the guide and threat model)
- Starlette/ASGI app with SSE: runs (idempotent start, cancel, resumable event stream via
Last-Event-ID), tool approvals over HTTP (approvescope, pending calls only), chat sessions with streaming replies. Tenant, user and metadata come only from the authenticated principal; foreign ids are indistinguishable from missing ones; the event stream is a filtered projection; budgets are a server-side ceiling. - Authentication:
ApiKeyAuthenticator(hashed, constant-time) andJWTAuthenticatorwithJWKSKeys(algorithm allow-list, requiredexp/iss/aud/sub, rate-limited key refresh). Admission:InMemoryRateLimiter,RedisRateLimiter(atomic Lua script), event-sourcedQuotaStorewith race-free reservation, open-run and stream caps. aaa-server serve module:factory(loopback by default). The core library gains a read-onlyaaacommand:aaa store check|runs|events.- Core is now
0.3.0.dev0;aaa-serveris versioned and released separately (server-v*tags).
Built-in tools and a code sandbox (see the guide and threat model)
aaa.tools.builtin:http_fetch_tool(SSRF-hardened: every resolved address must be public, the connection is pinned to the validated address, every redirect re-checked, bodies capped while streaming),read_file_tool/list_files_tool(confined to a root, secrets and hidden files refused),web_search_toolwithSearXNGSearch(verified against a real SearXNG) andBraveSearch.aaa.sandbox:DockerSandbox(no network, read-only filesystem, no capabilities, resource and output limits, nothing mounted from the host, a new container per run), the dev-onlySubprocessSandbox(unsafe=True)andcode_exec_tool, which requires human approval by default.
Ingestion (see the guide)
aaa.ingest:DirectoryLoader/FileLoader/PDFLoader(extrapdf),RecursiveChunker(characters or tokens) andMarkdownChunker, andPipeline.sync(): incremental (unchanged sources skipped, only changed chunks re-embedded, stale chunks and removed sources deleted), batched and retried embedding, a manifest kept in the store itself, per-tenant, resumable. Run against pgvector, sqlite-vec, Qdrant, LanceDB, Chroma and Pinecone Local in CI.VoyageReranker(Voyage AI's rerank endpoint). A Jina reranker is not included: Jina's documentation does not specify its response format.
Hybrid search
HybridSearch.query_hybridis now implemented byInMemoryVectorStore(BM25),PgVectorStore(full-texttsvcolumn, added automatically) andSqliteVecStore(FTS5 via triggers), fusing keyword relevance with similarity by reciprocal rank.EmbeddingIndex(..., hybrid=True|"auto")/search(..., hybrid=);Hit.metric == "rrf". NewHybridUnavailable.
Native providers (see LLM gateways)
provider="anthropic"(AnthropicClient: Messages API, tool use, forced-tool structured output, images and PDFs, prompt caching, streaming) andprovider="gemini"(GeminiClient: Generative Language API, function calling, JSON-schema output, images/audio/files, streaming, embeddings). Plain httpx, no vendor SDK; shapes validated against the vendors' SDK types in CI.
Multimodal messages (see the guide and threat model)
Message.parts: images, audio and files after the text (aaa.llm.parts:ImagePart,AudioPart,FilePart), validated at creation (type vs kind, image signatures, https-only URLs, size). Text-only messages serialize exactly as before.- The engine moves attachment bytes into the blob store before an event is appended (salted per run, so erasing a run deletes exactly its media); the log keeps references. Without a blob store, attachments over 256 KiB are refused.
engine.startnow storesinputin its JSON form. - Clients declare
modalities; an unsupported attachment fails the call withUnsupportedModalityinstead of being dropped. OpenAI chat-completions and Responses clients send images, audio (chat) and files. Session.send(..., attachments=),{"attachments": [...]}as an algorithm input,GuardContext.has_media, attachment-aware token counting, theClearMediacontext strategy (in the default policy), and trace/redactor handling that never exposes or corrupts attachment bytes.
Event-format safety net (see the guide)
- Frozen fixtures of real v0.2.0 logs (every built-in event type, 24 scenarios) and the Projection state they fold to, replayed by the current code on every CI run (
tests/unit/test_event_compat.py); the trace and CloudEvents exporters are checked against them too. - The SQLite, PostgreSQL and Redis stores record a layout version (
await store.schema_version()): a store written by a newer release is refused (SchemaTooNew), 0.1/0.2 stores are adopted as version 1, and a migration framework (ordered, transactional, run once under the setup lock) is in place for the first layout change. Stores now also close their connection pool / thread when opening fails.
Policy and hygiene
- Stability and deprecation policy: versioning while 0.x, stable vs provisional vs experimental modules, an additive-only rule for the event log, and a two-minor-release deprecation window (
aaa._compat.deprecated). SECURITY.md, a rootCONTRIBUTING.md, Dependabot for Actions and Python dependencies; Python 3.13 is now tested in CI.- Docs: deployment guide no longer says OpenTelemetry is missing, and states that schema upcasting happens on write, never on read.
0.2.0 (2026-10-15)¶
Observability, evals, guardrails and persistent vector search, each with adapters for the common libraries and services. New optional extras: otel, langfuse, langsmith, phoenix, autoevals, pgvector, qdrant, sqlitevec, lancedb, chroma, pinecone, bedrock. Additive: new OutcomeKind.BLOCKED, Hit.metric / Hit.higher_is_better, LLMHandler(guards=) and ToolHandler(guards=).
Observability (see the guide)
aaa.observe.Observer: derives traces from the event log (aaa.trace.spans_from_events) and exports them whole, parents first, once per cluster, without ever failing a run. Sinks:InMemorySink,ConsoleSink,CallableSink,OTelSinkand presetsLangfuseSink,LangSmithSink,PhoenixSink(extrasotel,langfuse,langsmith,phoenix). Content capture is opt-in; sampling, tenant filter, incremental export of open sessions,backfill.
More guard adapters
BedrockGuard(ApplyGuardrail),AzurePromptShieldGuard,LakeraGuard,GuardrailsAIGuardandNeMoGuard, with the same stage and action semantics as the built-in guards. Extrabedrock.
More vector stores
SqliteVecStore(one file, exact, filters in SQL),LanceDBStore(embedded; exact filters evaluated client-side in growing batches) andChromaStore(embedded or server; refuses what Chroma cannot express),PineconeStore(own namespaces, waits for eventual consistency), all through the same contract suite. Extrassqlitevec,lancedb,chroma,pinecone.
Vector stores (see the guide)
aaa.vector:VectorStoreprotocol (vectors + payload, namespaces, dimension checks),EmbeddingIndex(store, embedder)implementing the existingIndex(soRAGAgent,search_toolandNativeMemoryrun on a persistent store), a small filter language with identical semantics in every store (UnsupportedFilterinstead of silent post-filtering),TenantVectorStore(namespace wall plus an outer tenant filter),RerankingIndex.- Stores:
InMemoryVectorStore,PgVectorStore(pgvector over asyncpg, HNSW, jsonb filters) andQdrantStore(server or in-process), all run through one shared contract suite.Hitgainsmetricandhigher_is_better. CI's PostgreSQL image is nowpgvector/pgvector:pg16.
Guardrails (see the guide)
aaa.guard:GuardPolicy+LLMHandler(guards=)/ToolHandler(guards=)checkinput,output,tool_callandtool_result. Actions allow / flag / redact / approve / block; a blocked run ends as the newOutcomeKind.BLOCKED, a blocked tool call is a normal tool failure, a poisoned tool result is replaced by a placeholder,approveuses the existing approval flow.- Every check leaves an
aaa.guard.verdictevent (content hash, never content; counted in spend; shown as a guardrail span). The stored verdict wins, so a classifier is not called twice for the same content, including after a crash; a guard failure follows itson_errorpolicy and is never reused.GuardWatcherruns guards in observe mode. - Guards: regex, deny-list, max length, tool allow-list / escalation,
LLMJudgeGuard(any model, Llama Guard categories), callable; adaptersOpenAIModerationGuard,PresidioGuardandPresidioRedactor.
Evals (see the guide)
-
aaa.eval:Dataset/Case(list, JSONL, CSV),EvalSuite(real runs; concurrency, repeats, per-case budget; trajectory, steps, tokens and cost read back from the log), built-in metrics (text, outcome, tool use, budgets, semantic similarity,LLMJudge, callables),EvalReport(summaries, baseline regression,assert_okfor CI, Markdown/JUnit), andOnlineEvaluator(sampled, cost-capped scoring of live runs, recorded asaaa.eval.scoreevents and sent to score-capable sinks). -
Adapters for autoevals, DeepEval, Ragas (metrics judged through your own
LLMClient) and Inspect AI (aaa_solver). -
Foundations:
aaa.score.Score,aaa.safe.safe_subscribe(isolated, bounded observer workers).
0.1.1 (2026-10-15)¶
Chat sessions and provider-side state (see the guide)
aaa.session.SessionManager/Session: a durable multi-turn conversation. A session is a long-lived run; each user message starts a child run of your algorithm; the reply is recorded by whichever worker finishes the turn, so a turn survives the process that sent it. One turn at a time, per-tenant namespacing, whole-conversation budget, streaming,context=for long histories (summaries persisted and reused), and erasure/retention as for any run.- Provider-held conversation state:
OpenAIResponsesClient(provider="openai_responses") plus a smallServerStateClientprotocol. TheLLMHandlercontinues from the provider's handle and sends only new messages (within a run and across session turns), falls back to a full request when the state is gone or the context policy rewrote the conversation, andengine.erasedeletes provider-held state (ErasureReport.provider_state). Usage.cached_tokensandprice_cached_in_per_mtok;Engine.await_event;FakeStatefulClientfor tests.
Release process
- Releases publish to PyPI from GitHub through trusted publishing (no stored token); the release workflow skips a version that is already on PyPI.
0.1.0 (2026-10-15)¶
Context management (see the guide)
aaa.context.ContextPolicy+LLMHandler(client, context=policy): each request is fitted to the model's window as a send-time view; the logical conversation, the delta requests and the log are untouched.- Strategies:
TruncateToolResults,ClearToolResults,Summarize(incremental; persisted asaaa.context.summaryevents, reused by content hash across restarts and workers, billed to the run),DropOldest. Tool calls stay with their results; the head and recent turns are never touched. - Calibrated token estimates (
CalibratedCounterlearns fromusage.prompt_tokens; optionalTiktokenCounter); trigger/target hysteresis; one deeper retry when the provider still reports an overflow.
MCP client (see the guide)
aaa.mcp.MCPClient: connect to any MCP server over stdio, Streamable HTTP, or your own openClient/ClientSession, and use its tools as AAA tools (SchemaTool: argument validation against the server's JSON Schema, timeouts, approval, execution guard). Works with both the 1.x and 2.xmcpSDK.- Safety policy from MCP annotations: read-only/idempotent tools are
at_least_once, everything elseat_most_once;approval="destructive"follows the spec's "no annotations means destructive";trust_annotations=False,include/exclude, result truncation. mcp_memory(client, add=..., search=...): any MCP memory server as an AAAMemory. Resources can be listed and read.- Tested against real SDK servers in-process, over stdio and over HTTP with credentials, on both SDK versions in CI.
Long-term memory (see the guide)
aaa.memory: a smallMemoryprotocol (add,search) with optional capabilities (Updatable,Deletable,Forgettable,Profiled,Listable) and a tenant/user/agentScope.- Backends:
NativeMemory,Mem0Memory(open source and hosted),GraphitiMemory(temporal, point-in-time recall),SupermemoryMemory(HTTP),LangGraphStoreMemory(any LangGraph store, LangMem records read natively),CallableMemoryfor any other library,FakeMemoryfor tests. - Event-native:
MemoryHandler(aaa.memory.requested→completed/failed, replayable, redacted, crash-safe writes),ToolLoop(recall=True)automatic recall,WriteBack,memory_tools. - Erasure:
engine.forget_memory(scope),TenantScope.forget_memory(user=...), anderase_all()reaches registered memory backends. - Also: run metadata (
start(meta=...),TenantScope.start(user=...)),ToolContext.tenant/meta,LLMEmbedder, optional extrasmem0,graphiti,langgraph,langmem. - CI: an
adaptersjob replays each adapter's calls against the real libraries' signatures and runs weekly against their newest releases.
Privacy: tenancy, redaction, retention (see the guide)
Event.tenant, inherited by every derived event;engine.tenant(name)scopes that namespace run ids and check ownership on every lookup;Engine(require_tenant=True).Engine(redactor=...)withPatternRedactor(e-mail, Luhn-checked cards, SSN, API keys, JWT, bearer),KeyRedactorandstandard_redactor(): applied before persistence and delivery.engine.erase(scrub or delete),engine.purgeandEngine(retention=[RetentionPolicy(...)])applied bysweep().EventStoregainedscrubanddelete_stream(all four backends), which also remove snapshots and the bus outbox copies. Claim-checked blobs are now namespaced per stream so erasing one run cannot affect another.
Quality gates
- CI: ruff,
pyright(0 errors over the library, examples and scripts) and the full suite on Python 3.11 and 3.12 against real Postgres and Redis. - Type-correctness fixes found by pyright: the
EventBusandEventStoreprotocols now declare what the engine and users rely on (aclose,drain,abort,execution_guard);Algorithm.on_eventandLLMClient.complete/streamtake positional-only parameters so any implementation naming (e,request, ...) type-checks (previously every built-in algorithm was rejected when passed toEngine.run);Outcome.valueno longer forces narrowing before indexing. - Python 3.11: long-lived loops could outlive a cancellation (the standard library's
asyncio.timeout, used by redis-py, can swallow a cancel that races its deadline), which madeabort()/shutdown hang with Redis. Loops now re-raise a swallowed cancel, andaaa.core.wait_for/wait_eventreplaceasyncio.wait_forwhere tasks are shut down by cancellation.
Resilience
- Store outages no longer fail runs or lose reactions: bounded retry with backoff (
Engine(store_retry=...)),Redeliverso the bus delivers an event again, a tool result retried until recorded (ToolHandler(result_retry=...)), and distributed-bus consumers that survive backend errors. Fixed a race where a tool task cancelled before its first step left its bus message unacknowledged. Tested with real dropped Postgres and Redis connections.
First public version. Alpha: see Status and limitations.
Runtime and data
- Event-sourced engine: append-only log, deterministic ids, idempotent appends, budgets, deadlines, cancellation, child runs with spend roll-up, signals.
- Projections with versioned snapshots; incremental state for every built-in algorithm.
- Event stores: in-memory, SQLite, PostgreSQL, Redis, all passing one contract suite. CloudEvents 1.0 conversion. Versioned payload schemas with upcasters.
- Claim-check blob storage (in-memory, file) with integrity verification. In-memory hybrid (BM25 + vector) index.
Item/Codecdata layer with capability preflight.
Delivery and clustering
- In-process bus and a partitioned
DistributedBusover Postgres (transactional outbox,LISTEN/NOTIFY, advisory-lock leases) and Redis (Streams + Lua), with consumer groups, cursors, fair-share rebalancing, durable acknowledgement andClientBusfor submit-only processes. - Single-process crash recovery (
recover()), clustersweep(), adoption of any run by any worker.
LLM layer
- OpenAI-compatible client with streaming, tool calls and structured output; presets for LiteLLM proxy, Portkey, Cloudflare, Vercel, Bifrost, Kong, MLflow; LiteLLM SDK adapter; retry and circuit-breaker wrappers; typed errors; fake and replay clients; delta requests so long conversations stay linear.
Algorithms
ToolLoop,ReAct,PlanAndExecute,Router,Supervisor,GenerateTestRepair,GeneratorCritic,WorkflowGraph,FSM,SelfConsistency,RAGAgent.
Tools
- Typed
@toolwith schema generation, pools, timeouts, human approval, and the execution guard (durable acknowledgement, execution lease, fencing attempts,at_least_once/at_most_once, idempotency keys), fully configurable globally and per tool.
Docs and tooling
- This documentation site, with every example executed by the test suite. License: MIT.