Skip to main content

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

PyPI License: MIT Python

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, LLM

async def main():
    agent = Agent(llm=LLM())                     # 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, LLMSettings

Agent(llm=LLM())                                                                          # Ollama (default)
Agent(llm=LLM(settings=LLMSettings(provider="openai", model="gpt-4o")))                   # OPENAI_API_KEY
Agent(llm=LLM(settings=LLMSettings(provider="anthropic", model="claude-3-5-sonnet")))     # ANTHROPIC_API_KEY
Agent(llm=LLM(settings=LLMSettings(provider="groq", model="llama-3.3-70b-versatile")))    # GROQ_API_KEY

Provider and model can also be set via ACTANTS_PROVIDER / ACTANTS_MODEL environment variables, or by passing a provider instance as the first positional argument to LLM. Since 0.5.3, the provider name alone also works: LLM(provider="openai", model="gpt-4o").

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 import Agent, LLM, ToolRegistry
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:
    registry = ToolRegistry()
    for tool in mcp.tools():
        registry.register(tool)
    agent = Agent(llm=LLM(), tools=registry)

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 import Agent, LLM, ToolRegistry
from actants.a2a import RemoteAgent

registry = ToolRegistry()
registry.register(RemoteAgent("https://example.com"))
agent = Agent(llm=LLM(), tools=registry)

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

Project details


Download files

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

Source Distribution

actants-0.5.3.tar.gz (72.0 kB view details)

Uploaded Source

Built Distribution

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

actants-0.5.3-py3-none-any.whl (69.2 kB view details)

Uploaded Python 3

File details

Details for the file actants-0.5.3.tar.gz.

File metadata

  • Download URL: actants-0.5.3.tar.gz
  • Upload date:
  • Size: 72.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for actants-0.5.3.tar.gz
Algorithm Hash digest
SHA256 3bde76d7e5b1eb5db3919baf373d1a1f981eca740719de38f758bf442b537fb3
MD5 bb30edb351c4e6c9831649e2e8c8e2a7
BLAKE2b-256 ddb7c7b00a75588b4ccccc6a9b13ea182704c6ed21f3f9876c3cd5b0dd46729e

See more details on using hashes here.

Provenance

The following attestation bundles were made for actants-0.5.3.tar.gz:

Publisher: release.yml on openintelligence-labs/actants

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

File details

Details for the file actants-0.5.3-py3-none-any.whl.

File metadata

  • Download URL: actants-0.5.3-py3-none-any.whl
  • Upload date:
  • Size: 69.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for actants-0.5.3-py3-none-any.whl
Algorithm Hash digest
SHA256 616806f47b6eeca3c832b685e3e8c735800223152fd3dc3a556e8f64213740c8
MD5 6b253aa038f16d8e26cbf7d8fadd0b77
BLAKE2b-256 6b98434237e48b54b023a1639fbecc80f65cb0634d24a3a04bb8547697e599c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for actants-0.5.3-py3-none-any.whl:

Publisher: release.yml on openintelligence-labs/actants

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