A minimal, reusable Python framework for building LLM agents with tools and an observe-act loop.
Project description
agentloop
A small, reusable Python agentic framework for building LLM agents with tools, memory, and an observe–act loop. Other developers can extend it by registering tools, swapping LLM providers, and hooking lifecycle events—without pulling in a heavy dependency stack.
Features
- Agent loop — model → tool calls → tool results → repeat until done or
max_iterations - Tool registry — decorate functions; JSON schema inferred from type hints
- Pluggable LLM providers — OpenAI-compatible API built-in; implement one method for custom backends
- Memory — conversation history with optional system prompt
- Events —
on_tool_call,on_iteration,on_run_end, genericsubscribe()hooks - Mock provider — run examples and tests without an API key
Install
From PyPI (after you publish — see PUBLISHING.md):
pip install agentloop-framework
pip install "agentloop-framework[openai]" # OpenAI-compatible provider
From source (development):
cd agentloop
pip install -e .
# For OpenAI / Azure / Ollama (OpenAI-compatible HTTP API):
pip install -e ".[openai]"
# Development:
pip install -e ".[dev]"
The PyPI name is
agentloop-frameworkbecauseagentloopis already taken. Imports remainfrom agentloop import ....
Quick start (no API key)
import asyncio
from agentloop import Agent
from agentloop.providers import MockProvider
from agentloop.tools import ToolRegistry
tools = ToolRegistry()
@tools.register(description="Echo text back.")
def echo(text: str) -> str:
return text
agent = Agent.create(
provider=MockProvider(MockProvider.tool_then_answer("echo", {"text": "hi"}, final="Done.")),
system="You are helpful.",
tools=tools,
)
asyncio.run(agent.run("Say hi"))
Run the bundled example:
python examples/basic_mock.py
Example agents
Chatbot (multi-turn)
Interactive CLI chat with persistent memory and tools (time, calculator):
python examples/chatbot.py --mock # offline, no API key
python examples/chatbot.py --live # needs OPENAI_API_KEY
Voice agent
Speak to the agent and hear replies (or use --text to type):
python examples/voice_agent.py --text --mock # easiest start
pip install -e ".[voice]"
python examples/voice_agent.py --mock # microphone + speaker
See examples/README.md for full details.
Cloud Run + Pinecone RAG + React UI
Production-style deployment with vector search:
# See deploy/cloud-run/README.md for full steps
docker build -f deploy/cloud-run/Dockerfile -t agentloop-chat .
Stack: React chat UI → FastAPI /api/chat → agentloop → Pinecone on Google Cloud Run.
Live LLM (OpenAI-compatible)
import asyncio
from agentloop import Agent
from agentloop.providers import OpenAICompatibleProvider
from agentloop.tools import ToolRegistry
tools = ToolRegistry()
@tools.register(description="Add two integers.")
def add(a: int, b: int) -> int:
return a + b
agent = Agent.create(
provider=OpenAICompatibleProvider(model="gpt-4o-mini"),
system="Use tools when math is needed.",
tools=tools,
)
asyncio.run(agent.run("What is 12 + 30?"))
Environment variables:
| Variable | Purpose |
|---|---|
OPENAI_API_KEY |
API key |
OPENAI_BASE_URL |
Base URL (default https://api.openai.com/v1; use for Ollama, Azure, vLLM) |
OPENAI_MODEL |
Model id (example script only) |
Architecture
flowchart LR
User[User task] --> Loop[AgentLoop]
Loop --> LLM[LLMProvider.chat]
LLM -->|tool_calls| Tools[ToolRegistry.execute]
Tools --> Memory[ConversationMemory]
Memory --> Loop
LLM -->|final text| Result[RunResult]
Extension points
| Piece | How to extend |
|---|---|
| LLM | Class with async def chat(messages, tools) -> LLMResponse — see examples/custom_provider.py |
| Tools | @registry.register or registry.add(name, handler, ...) |
| Memory | Pass ConversationMemory(system_prompt=...) into AgentLoop |
| Observability | AgentEvents(on_tool_call=..., subscribe=lambda e, p: ...) |
| Low-level control | Use AgentLoop directly instead of Agent |
Project layout
agentloop/
agent.py # Agent.create() builder
loop.py # Core observe–act loop
tools.py # ToolRegistry
memory.py # ConversationMemory
events.py # AgentEvents
types.py # Message, ToolCall, RunResult, ...
providers/
base.py # LLMProvider protocol
openai_compatible.py
mock.py
examples/
chatbot.py # Multi-turn interactive chat
voice_agent.py # Speech input / spoken output
helpers.py # Shared tools + agent factory
README.md
tests/
Tests
pytest
Design choices
- Minimal core — zero required runtime dependencies;
httpxonly for the optional OpenAI provider. - Async-first —
asynciothroughout; sync wrappers can wrapasyncio.runin your app. - Provider-agnostic — not tied to Cursor or any single vendor; bring your own model endpoint.
License
MIT
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 agentloop_framework-0.1.0.tar.gz.
File metadata
- Download URL: agentloop_framework-0.1.0.tar.gz
- Upload date:
- Size: 27.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b739dd30cafb5429ce89200bd23597a2501404b876e640cb9ba5f87be02d78ae
|
|
| MD5 |
d90c2217053ab618c5b8c570c03996bf
|
|
| BLAKE2b-256 |
6ebda53c6e66eda83413f71f7d012bd3a253d197808501f232e398d8bccb8f7a
|
File details
Details for the file agentloop_framework-0.1.0-py3-none-any.whl.
File metadata
- Download URL: agentloop_framework-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e5f2dd18c1a6838c589d4b0081a312f02f99ab6af5001557484dd49d3a1b4cfd
|
|
| MD5 |
2c6b47feed30ea9c481c746b9e66f7f5
|
|
| BLAKE2b-256 |
4f6024e98d8449c74284440b8df6c18a91df3df5ca73ef6df04f8fb6364400ac
|