Agentling
Agentling is an open-source Python framework for building tool-using AI agents: a clean ReAct loop, typed memory, streaming events, self-healing tool errors, and progressive-disclosure skills, in around 800 lines of readable async code.
Built with
Agentling is a tiny async framework for building reliable, observable tool-using agents in Python. It gives you a clean ReAct loop, typed memory, streaming events, self-healing tool errors, and progressive-disclosure skills, in a codebase small enough to read in one sitting (around 800 lines of source). It is open source under MIT, published on PyPI, and built around one idea: an agent is a loop that turns a model, some tools, and a memory of what happened into more actions, until it has an answer.
import asyncio
from agentling import Agent, OpenAIModel, tool
@tool
def get_weather(city: str) -> str:
"""Get the current weather for a city.
Args:
city: The city to look up.
"""
return f"It is 22C and sunny in {city}."
async def main() -> None:
agent = Agent(model=OpenAIModel("gpt-4o-mini"), tools=[get_weather])
print(await agent.run("What's the weather in Paris?"))
asyncio.run(main())Why I built it#
Most agent frameworks are either too magical to understand or too heavy to trust. I wanted one you could actually read end to end, that still did the hard parts right. Agentling is the result, and its design choices are all in service of that:
- Async first. The loop, tools, and model calls are all
async, and a single turn's tool calls run concurrently by default. - One code path. Blocking and streaming share the exact same loop. There is one async generator; blocking mode just drains it, so there is no second implementation to keep in sync.
- Typed memory. A run is a list of typed steps, not a bag of raw messages. Steps render themselves back into model messages and serialize to JSON, which gives you free persistence, replay, and multi-turn continuation.
- Progressive-disclosure skills. Drop in a
SKILL.mdfolder and the model sees only its name and description until it decides to load it, so a big skill library stays cheap in context. - Self-healing. A tool that raises becomes an observation the model can recover from, not a crash.
- Small and readable. No metaclasses, no plugin registry, no DSL. Around 800 lines you can actually read.
Architecture#
Agentling is a small set of focused modules that depend on each other in one direction only: the agent depends on skills, tools, memory, events, and models, and nothing depends on the agent.
| Module | Responsibility |
|---|---|
models.py | Provider-neutral message types, streaming deltas, the Model protocol, and the OpenAIModel adapter. |
tools.py | The @tool decorator, JSON Schema generation from signatures, argument validation, and the built-in final_answer tool. |
memory.py | Typed steps (TaskStep, ActionStep, FinalStep), the Memory container, and JSON serialization. |
events.py | Streaming event types and the print_events renderer. |
skills.py | The Skill dataclass, the SKILL.md loader, and entry-point tool resolution. |
agent.py | The Agent config, the AgentSession that holds one run's state, and the ReAct loop that ties it together. |
The whole framework hangs off a single async generator. Each iteration is one step: it streams a model turn, runs whatever tools the model asked for (concurrently by default), records the outcome to memory, and checks whether the run is done. The loop ends when the model calls final_answer, replies with plain text and no tool calls, or hits the step limit and is asked for one last tool-free answer.
Robustness built in#
The details are where an agent framework earns trust, so Agentling bakes several in:
- Forgiving termination. If the model replies with plain text and no tool call, that text is taken as the answer, so it does not matter whether the model reliably calls
final_answer. - Self-healing tool errors. A raised exception becomes a tagged error observation with a hint ("fix the arguments" or "try a different approach"), so one bad call does not kill the run.
- Loop detection. An exact repeat of the previous step's tool calls gets a nudge, helping the model break out of a stuck cycle.
- Graceful interruption.
session.interrupt()stops at the next step boundary and preserves memory, so you can resume withrun(..., reset=False).
Stack and install#
Agentling needs Python 3.11+, and its only runtime dependencies are the OpenAI client (used by the built-in provider adapter) and PyYAML (for skill frontmatter). Any OpenAI-compatible endpoint works by pointing OpenAIModel at a different base_url, and you can write your own adapter against the small Model protocol.
pip install agentlingThe repo ships runnable examples (some offline, no API key needed), a full test suite, and CI. It is deliberately small, so a few things are out of scope for now: schema validation covers a practical subset of JSON Schema, there is no built-in tracing backend (the event stream and step callbacks are the hooks), tools run as trusted code with no sandbox, and long runs need a context_manager to trim or summarize context.
Agentling borrows the best ideas from the ecosystem: the clean ReAct loop and code-first tools popularised by smolagents, and the progressive-disclosure skill format used by Claude. Its contribution is packaging those ideas into a small, typed, async codebase you can read end to end.
More projects
UK Visa Sponsor MCP Server
An MCP server that lets AI assistants search the UK Register of Licensed Visa Sponsors: check sponsorship, filter by route, and pull stats in natural language.
Python · FastMCP · Docker
UK Visa Sponsor Search
Search the entire UK Register of Licensed Sponsors: 125,000+ verified companies, updated from GOV.UK, in one fast, filterable interface.
Next.js 16 · React 19 · TypeScript · MongoDB Atlas · Mongoose · Tailwind CSS v4 · shadcn/ui · Framer Motion · Railway
Adzuna Job Search MCP Server
A FastMCP server that gives AI assistants live job-market data: search roles, analyze salaries, and research employers across 12 countries.
Python · FastMCP · Adzuna API · Docker · PyPI · GitHub Actions