Local-first AI app framework: LLM gateway, agents, embeddings, storage, CLI helpers, observability. Build agents with one import. Ollama-default, async, typed.
Project description
actants
A Python framework for building LLM agents. Defaults to Ollama for local development; integrates OpenAI, Anthropic, Gemini, Groq, and Mistral via opt-in extras. Includes MCP (Model Context Protocol) and A2A (Agent2Agent Protocol) clients and servers, an embeddings client, SQLite-based storage helpers, OpenTelemetry GenAI tracing, and a Click + Rich CLI scaffold.
Install
pip install actants
Optional extras:
| Extra | Adds |
|---|---|
openai |
OpenAI provider |
anthropic |
Anthropic provider |
gemini |
Google Gemini provider |
groq |
Groq provider |
mistral |
Mistral provider |
mcp |
MCP client + server |
a2a |
A2A client + server |
cache |
sqlite-vec semantic cache |
cli |
Click + Rich CLI helpers |
all |
OpenAI + Anthropic + cache + cli |
pip install 'actants[openai,anthropic,mcp,a2a]'
For the default Ollama provider, also install Ollama and pull a model:
ollama pull llama3.2
Quickstart
import asyncio
from actants import Agent
async def main():
agent = Agent() # Ollama, llama3.2 by default
result = await agent.run("Say hello.")
print(result.content)
asyncio.run(main())
Tools
Register async functions as tools and pass them to an Agent:
from actants import Agent, LLM, ToolRegistry
tools = ToolRegistry()
async def add(a: int, b: int) -> int:
return a + b
tools.register_function(
"add",
"Add two integers",
add,
input_schema={
"type": "object",
"properties": {"a": {"type": "integer"}, "b": {"type": "integer"}},
"required": ["a", "b"],
},
)
agent = Agent(llm=LLM(model="llama3.2"), tools=tools)
result = await agent.run("What is 17 + 25?")
The model decides when to call the tool; Agent dispatches it and feeds
the result back through the tool-calling loop.
Streaming
Agent.stream() yields typed events:
from actants.agents import (
AgentTextDelta,
AgentToolCallStarted,
AgentToolCallCompleted,
AgentRunCompleted,
)
async for event in agent.stream("explain transformers in one paragraph"):
match event:
case AgentTextDelta(text=t):
print(t, end="", flush=True)
case AgentToolCallStarted(call=c):
print(f"\n→ {c.name}({c.arguments})")
case AgentToolCallCompleted(value=v):
print(f" ← {v}")
case AgentRunCompleted():
print()
Switching providers
from actants import Agent, LLM
Agent(llm=LLM()) # Ollama (default)
Agent(llm=LLM(provider="openai", model="gpt-4o")) # OPENAI_API_KEY
Agent(llm=LLM(provider="anthropic", model="claude-3-5-sonnet")) # ANTHROPIC_API_KEY
Agent(llm=LLM(provider="groq", model="llama-3.3-70b-versatile")) # GROQ_API_KEY
See Configuration for the full list of environment variables.
MCP
Expose an agent's tools over the Model Context Protocol:
from actants.mcp import serve
serve(agent) # stdio
serve(agent, transport="streamable-http", port=8000) # HTTP
Consume tools from one or more MCP servers:
from actants.mcp import MCPClient
async with MCPClient({
"git": {"command": "uvx", "args": ["mcp-server-git"]},
"fs": {"command": "uvx", "args": ["mcp-server-filesystem", "/tmp"]},
}) as mcp:
agent = Agent(llm=LLM(), tools=mcp.tools())
The config shape matches Claude Desktop's mcpServers. Requires the
[mcp] extra and the official mcp Python SDK.
A2A
Run an agent as an A2A server:
from actants.a2a import serve
serve(agent, host="0.0.0.0", port=9000)
# /.well-known/agent-card.json + JSON-RPC at /
Call a remote A2A agent as a tool:
from actants.a2a import RemoteAgent
remote = RemoteAgent("https://example.com")
agent = Agent(llm=LLM(), tools=[remote])
The Agent Card is auto-generated from the agent's tool registry. Streaming
uses Server-Sent Events. Requires the [a2a] extra and the official
a2a-sdk Python package.
Tracing
actants emits OpenTelemetry GenAI semantic-convention spans
(invoke_agent, chat, execute_tool, embeddings). Cost is recorded
under actants.cost.usd because the OTel GenAI spec does not yet define a
cost attribute. Spans are forwarded to whichever OTLP collector you
configure; actants itself sends nothing.
Project layout
Agent state, memory, hooks, streaming events
LLM provider gateway, retry, fallback, cost, cache
Provider Ollama, OpenAI, Anthropic, Gemini, Groq, Mistral
Opt-in modules: mcp, a2a, embeddings, storage, cli, tracing,
observability, config, testing.
Status
actants is pre-1.0. The public API listed in actants.__all__ is
documented; everything else is implementation detail and may change. The
package emits no telemetry.
Links
- Issues: https://github.com/openintelligence-labs/actants/issues
- License: MIT
- Part of Open Intelligence Labs
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file actants-0.5.2.tar.gz.
File metadata
- Download URL: actants-0.5.2.tar.gz
- Upload date:
- Size: 71.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36b7fcc434a15a35c79d670cac0be5f66712d02805ee568ae5a997c594d342eb
|
|
| MD5 |
619106a612a701f89e35526b204467f2
|
|
| BLAKE2b-256 |
6d1ef76fb907dd962835f9a0b2573964b654f097e03eb1dbaea7312d1e195d74
|
Provenance
The following attestation bundles were made for actants-0.5.2.tar.gz:
Publisher:
release.yml on openintelligence-labs/actants
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
actants-0.5.2.tar.gz -
Subject digest:
36b7fcc434a15a35c79d670cac0be5f66712d02805ee568ae5a997c594d342eb - Sigstore transparency entry: 1431786234
- Sigstore integration time:
-
Permalink:
openintelligence-labs/actants@487f2aceb7aa2d479950f9d87d52f88f02716730 -
Branch / Tag:
refs/tags/v0.5.2 - Owner: https://github.com/openintelligence-labs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@487f2aceb7aa2d479950f9d87d52f88f02716730 -
Trigger Event:
push
-
Statement type:
File details
Details for the file actants-0.5.2-py3-none-any.whl.
File metadata
- Download URL: actants-0.5.2-py3-none-any.whl
- Upload date:
- Size: 68.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f99b5d51481be9e9ec5e826ab7fb9f74272d30b9db93d294afee71ce42b6aad
|
|
| MD5 |
b0d958b0e11b425f06b6a12bd51b64ca
|
|
| BLAKE2b-256 |
5495f831abab7b12f9e3eadf04a80124bc85bf3ba3877998fc631e7f331f9cd1
|
Provenance
The following attestation bundles were made for actants-0.5.2-py3-none-any.whl:
Publisher:
release.yml on openintelligence-labs/actants
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
actants-0.5.2-py3-none-any.whl -
Subject digest:
8f99b5d51481be9e9ec5e826ab7fb9f74272d30b9db93d294afee71ce42b6aad - Sigstore transparency entry: 1431786991
- Sigstore integration time:
-
Permalink:
openintelligence-labs/actants@487f2aceb7aa2d479950f9d87d52f88f02716730 -
Branch / Tag:
refs/tags/v0.5.2 - Owner: https://github.com/openintelligence-labs
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@487f2aceb7aa2d479950f9d87d52f88f02716730 -
Trigger Event:
push
-
Statement type: