Observed since 20 Oct, 23:13 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
A minimal, hackable agentic framework: LLM calls via litellm, @tool-decorated functions, and MCP server support.
A small, hackable agentic framework in ~500 lines you fully own and can read top to bottom in an afternoon:
@tool decorator turns any python function into an LLM-callable tool with
an auto-generated JSON schema (from type hints + docstring).pip install agentropic
import asyncio
from agentropic import Agent, tool
@tool()
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"It's sunny in {city}."
async def main():
agent = Agent(
name="assistant",
model="gpt-4o-mini", # any litellm model string
instructions="You are helpful and concise.",
tools=[get_weather],
)
print(await agent.arun("What's the weather in Paris?"))
asyncio.run(main())
Sync usage: agent.run("...") (wraps arun in asyncio.run for you).
stream=True)Same shape as the OpenAI / Anthropic SDKs. Tool calls work while streaming.
async for event in await agent.arun("Weather in Tokyo?", stream=True):
if event.type == "text":
print(event.text, end="", flush=True)
elif event.type == "tool_call":
print(f"\n[calling {event.tool_call.name}({event.tool_call.arguments})]")
elif event.type == "tool_result":
print(f"[-> {event.tool_call.result}]")
elif event.type == "done":
result = event.result # full AgentRunResult (usage, tool_calls, ...)
With verbose=True (the default) the colourful terminal tracer already prints
tokens live, so only print event.text yourself when using verbose=False
(e.g. rendering into your own UI).
Sync: for event in agent.run("...", stream=True): ...
Text only: async for token in agent.astream("..."): ...
from agentropic import Agent
from agentropic.mcp import StdioServer, HTTPServer
agent = Agent(
name="fs-agent",
model="gpt-4o-mini",
mcp_servers=[
StdioServer(command="npx", args=["-y", "@modelcontextprotocol/server-filesystem", "."]),
# HTTPServer(url="https://example.com/mcp", headers={"Authorization": "Bearer ..."}),
],
)
# Option A: connect once, keep servers alive across turns (recommended)
async with agent:
print(await agent.arun("List the files in the current directory."))
print(await agent.arun("Now read README.md"))
# Option B: no context manager — servers connect/disconnect around each run
print(await agent.arun("List the files in the current directory."))
Requires the optional MCP dependency: pip install "agentropic[mcp]", plus whatever
the server itself needs (e.g. Node.js for npx servers). Transports: StdioServer,
HTTPServer (streamable HTTP), SSEServer (legacy SSE).
src/agentropic/
├── __init__.py # public API surface
├── agent.py # the run loop: LLM <-> tools <-> memory
├── llm.py # thin litellm wrapper (swap providers here)
├── tools.py # @tool decorator, Tool, ToolRegistry, schema generation
├── memory.py # in-memory conversation history (swap for your own store)
└── mcp/
└── client.py # MCP stdio/SSE client -> Tool adapter
Everything is a plain, editable python file — no hidden magic, no plugin
registry you can't inspect. Read agent.py first; that's the whole loop.
.add(), .get(), .clear()
matching Memory and pass memory=YourMemory() to Agent.Agent instances and route
between them yourself, or wrap one agent's arun as a tool for another.Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.3.1 | 20 Oct 2026 | 7 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 23:13 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:063771eb48247597ec967a1072e3994ef360652ec4bbc0103e64ec22aa9cea15