Skip to main content

Minimal, streaming-first, protocol-driven foundation for LLM-powered agents

Project description

axio

PyPI Python License: MIT

Minimal, streaming-first, protocol-driven foundation for LLM-powered agents.

No dependencies. Three protocols. An agent loop that just works.

Features

  • Streaming agent loop - run_stream() yields typed events as they arrive; no buffering, no polling
  • Three clean protocols - CompletionTransport, ContextStore, PermissionGuard; swap any piece without touching the rest
  • Concurrent tool dispatch - all tool calls in a turn run via asyncio.gather automatically
  • Context compaction - compact_context() summarises old history to stay within token limits
  • Testing helpers - StubTransport, make_tool_use_response(), make_echo_tool() ship in axio.testing
  • Plugin-ready - entry-point groups (axio.tools, axio.transport, axio.guards) for drop-in extensions

Installation

pip install axio

Quick start

import asyncio
from axio.agent import Agent
from axio.context import MemoryContextStore
from axio.tool import Tool

# 1. Define a tool
async def greet(name: str) -> str:
    """Return a greeting for the given name."""
    return f"Hello, {name}!"

greet_tool = Tool(name="greet", description="Greet someone by name", handler=greet)

# 2. Wire up the agent (transport comes from an axio-transport-* package)
from axio_transport_openai import OpenAITransport

transport = OpenAITransport(api_key="sk-...", model="gpt-4o-mini")
agent = Agent(system="You are helpful.", transport=transport, tools=[greet_tool])

# 3. Run
async def main() -> None:
    ctx = MemoryContextStore()
    async for event in agent.run_stream("Please greet Alice", ctx):
        print(event)

asyncio.run(main())

Architecture

  User message
       │
       ▼
  ┌─────────┐   stream()    ┌─────────────────────┐
  │  Agent  │ ────────────▶ │ CompletionTransport  │
  │  loop   │ ◀──────────── │ (Anthropic, OpenAI, …) │
  └─────────┘  StreamEvent  └─────────────────────┘
       │
       │ tool_use?
       ▼
  ┌──────────┐   check()   ┌─────────────────┐
  │   Tool   │ ──────────▶ │ PermissionGuard │
  │ handler  │             │ (path, LLM, …)  │
  └──────────┘             └─────────────────┘
       │
       ▼
  ┌──────────────┐
  │ ContextStore │  append() / get_history() / fork() / compact()
  └──────────────┘

Protocols

CompletionTransport

from typing import Protocol, runtime_checkable
from collections.abc import AsyncIterator
from axio.events import StreamEvent
from axio.messages import Message
from axio.tool import Tool

@runtime_checkable
class CompletionTransport(Protocol):
    def stream(
        self, messages: list[Message], tools: list[Tool], system: str
    ) -> AsyncIterator[StreamEvent]: ...

ContextStore

from axio.context import ContextStore
from axio.messages import Message

class MyContextStore(ContextStore):
    def __init__(self) -> None:
        self._messages: list[Message] = []

    async def append(self, message: Message) -> None:
        self._messages.append(message)

    async def get_history(self) -> list[Message]:
        return list(self._messages)

    # Everything else - session_id, close(), fork(), clear(),
    # get/set_context_tokens(), add_context_tokens(), list_sessions()
    # - has a default implementation.

PermissionGuard

PermissionGuard is an abstract base class (ABC). Subclass it and implement check():

from typing import Any
from axio.permission import PermissionGuard
from axio.tool import Tool

class MyGuard(PermissionGuard):
    async def check(self, tool: Tool[Any], **kwargs: Any) -> dict[str, Any]:
        # return kwargs to allow, raise GuardError to deny
        return kwargs

Stream events

Event Description
TextDelta Incremental assistant text chunk
ToolUseStart Tool call begins (name + id)
ToolInputDelta Streaming JSON fragment for tool arguments
ToolResult Tool execution result
IterationEnd One LLM round complete - carries Usage + StopReason
Error Transport or tool exception
SessionEndEvent Agent loop finished - carries total Usage

Tools

from axio.tool import Tool

async def summarise(text: str, max_words: int = 20) -> str:
    """Summarise the given text in one sentence."""
    # your implementation
    return "..."

tool = Tool(
    name="summarise",
    description="Summarise text",   # overrides docstring if set
    handler=summarise,
    concurrency=4,                   # max parallel executions
)

Testing

from axio.agent import Agent
from axio.testing import (
    StubTransport,
    make_tool_use_response,
    make_text_response,
    make_ephemeral_context,
    make_echo_tool,
)

async def test_agent_calls_tool():
    transport = StubTransport([
        make_tool_use_response("echo", tool_input={"msg": "hi"}),
        make_text_response("Done"),
    ])
    agent = Agent(system="", tools=[make_echo_tool()], transport=transport)
    result = await agent.run("say hi", make_ephemeral_context())
    assert result == "Done"

Plugin entry points

[project.entry-points."axio.tools"]
my_tool = "my_package:MyHandler"

[project.entry-points."axio.transport"]
my_backend = "my_package:MyTransport"

[project.entry-points."axio.guards"]
my_guard = "my_package:MyGuard"

Ecosystem

Package Purpose
axio-transport-anthropic Anthropic Claude transport
axio-transport-openai OpenAI-compatible transport (OpenAI, Nebius, OpenRouter, custom)
axio-transport-codex ChatGPT OAuth transport
axio-context-sqlite SQLite-backed persistent context store
axio-tools-local Shell, file, Python tools
axio-tools-mcp MCP server bridge
axio-tools-docker Docker sandbox tools
axio-tui Textual TUI application
axio-tui-guards Permission guard plugins

License

MIT

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

axio-0.9.0.tar.gz (84.5 kB view details)

Uploaded Source

Built Distribution

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

axio-0.9.0-py3-none-any.whl (34.0 kB view details)

Uploaded Python 3

File details

Details for the file axio-0.9.0.tar.gz.

File metadata

  • Download URL: axio-0.9.0.tar.gz
  • Upload date:
  • Size: 84.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for axio-0.9.0.tar.gz
Algorithm Hash digest
SHA256 2c709a1a6a2b15deddbc2b8dc896dca87746bca9c88d374030c0421c9559cd73
MD5 f8b528a98a8b0ca907075789f325f82a
BLAKE2b-256 b5af6d50a18e2b914e139a360087d49036786ad075193deba75d08cef9daa987

See more details on using hashes here.

Provenance

The following attestation bundles were made for axio-0.9.0.tar.gz:

Publisher: publish.yml on mosquito/axio-agent

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

File details

Details for the file axio-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: axio-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 34.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for axio-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 67c4b039f1097b618b75cda406a164e3c4c4814112a7e36bd5814647da2a87a0
MD5 9762f3a8032e4d6dc07c4d3e5a8290d2
BLAKE2b-256 2b102447138eb5ec350bcd26b99b5debd5ad0cad67840ffeb0c3cd3a3b78adfb

See more details on using hashes here.

Provenance

The following attestation bundles were made for axio-0.9.0-py3-none-any.whl:

Publisher: publish.yml on mosquito/axio-agent

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