Protocols¶
Axio’s extensibility comes from a small set of runtime-checkable protocols and abstract base classes. Implement any of them to plug your own components into the framework — no subclassing the agent, no monkey-patching.
classDiagram
class CompletionTransport {
<<Protocol>>
+stream(messages, tools, system) AsyncIterator~StreamEvent~
}
class ContextStore {
<<ABC>>
+session_id str
+append(message)
+get_history() list~Message~
+clear()
+fork() ContextStore
}
class PermissionGuard {
<<ABC>>
+check(handler) handler
}
Agent --> CompletionTransport
Agent --> ContextStore
Tool --> PermissionGuard
CompletionTransport¶
The transport protocol has a single method:
@runtime_checkable
class CompletionTransport(Protocol):
def stream(
self,
messages: list[Message],
tools: list[Tool],
system: str,
) -> AsyncIterator[StreamEvent]: ...
The agent calls stream() on every iteration, passing the full conversation
history, the available tools, and the system prompt. The transport yields
StreamEvent values as they arrive from the LLM.
Built-in transports: OpenAITransport, NebiusTransport, CodexTransport.
See Writing Transports for a step-by-step guide.
ContextStore¶
The context store manages conversation history. It is an abstract base class with async methods:
class ContextStore(ABC):
@property
@abstractmethod
def session_id(self) -> str: ...
@abstractmethod
async def append(self, message: Message) -> None: ...
@abstractmethod
async def get_history(self) -> list[Message]: ...
@abstractmethod
async def clear(self) -> None: ...
@abstractmethod
async def fork(self) -> ContextStore: ...
MemoryContextStore is the built-in in-memory implementation. The axio-tui
package includes a SQLite-backed store for persistence across sessions.
Implement your own ContextStore to back conversations with Redis, a database,
or any other storage layer.
See Context & Messages for details on the message model.
PermissionGuard¶
Guards gate tool execution. They sit between parameter validation and handler invocation:
class PermissionGuard(ABC):
@abstractmethod
async def check(self, handler: Any) -> Any: ...
A guard receives the validated handler instance and either returns it (allowing
execution) or raises GuardError to deny. Guards can also modify the handler
before returning it.
Multiple guards compose sequentially — each guard’s output is passed to the next.
See Guards for the full guard system and Writing Guards for a how-to guide.
Additional transport protocols¶
Beyond CompletionTransport, Axio defines protocols for other AI modalities:
ImageGenTransportasync generate(prompt, *, size, n) -> list[bytes]TTSTransportsynthesize(text, *, voice) -> AsyncIterator[bytes]STTTransportasync transcribe(audio, media_type) -> strEmbeddingTransportasync embed(texts) -> list[list[float]]
These follow the same pattern — implement the protocol, pass the object in, and the framework handles the rest.