A lightweight and elegant Agent framework
Project description
lovia
lovia is a lightweight async agent framework for Python. It keeps the core small, lets you bring your own model provider, and adds practical opt-in layers for tools, sandboxes, sessions, workflows, and a tiny web UI.
pip install lovia
import asyncio
from lovia import Agent, Runner, tool
@tool
async def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
async def main() -> None:
agent = Agent(
name="calc",
instructions="Answer briefly. Use tools when useful.",
model="openai:gpt-4o-mini",
tools=[add],
)
result = await Runner.run(agent, "What is 2 + 3?")
print(result.output)
asyncio.run(main())
Why lovia?
- Small core: only
httpxandpydanticare hard dependencies. - Async-first: public APIs are async; sync helpers are convenience wrappers.
- Provider-neutral: use OpenAI-compatible chat, OpenAI Responses, or your own provider.
- Tools without ceremony: turn a typed Python function into a model tool with
@tool. - Sandboxed coding tools: attach file and shell tools with a clear root boundary.
- Optional layers: web UI, MCP, search, Rich examples, and Prefect workflows stay in extras.
Install extras
| Need | Install |
|---|---|
| Core agent framework | pip install lovia |
.env loading in examples |
pip install "lovia[dotenv]" |
| DuckDuckGo search tool | pip install "lovia[tools]" |
| MCP integration | pip install "lovia[mcp]" |
| Web UI | pip install "lovia[web]" |
| Rich terminal examples | pip install "lovia[rich]" |
| Prefect workflow example | pip install "lovia[prefect]" |
| Everything used by examples | pip install "lovia[examples,web]" |
| Development | pip install -e ".[dev]" |
Core concepts
Agent
Agent is a dataclass that describes the assistant: name, instructions, model,
tools, output type, hooks, sandbox, and runtime policy.
agent = Agent(
name="writer",
instructions="Write concise, concrete answers.",
model="openai:gpt-4o-mini",
)
Runner
Runner executes the loop: send messages to the model, run requested tools,
append results, and stop when the model returns a final answer.
result = await Runner.run(agent, "Draft a release note.")
print(result.output)
Streaming gives you typed events:
from lovia import events
handle = Runner.stream(agent, "Tell me a short story.")
async for ev in handle:
if isinstance(ev, events.TextDelta):
print(ev.delta, end="", flush=True)
result = await handle.result()
Tool
Any typed Python callable can become a tool. lovia generates JSON Schema from type hints and docstrings.
from typing import Annotated
from pydantic import Field
from lovia import tool
@tool(strict=True)
async def search_docs(
query: Annotated[str, Field(description="What to search for")],
limit: Annotated[int, Field(ge=1, le=10)] = 5,
) -> list[str]:
"""Search internal docs."""
return [f"result for {query}"]
Use needs_approval=True for sensitive tools. In streaming mode, the runner
emits ApprovalRequired; your UI or CLI can approve or deny it.
Built-in tools
Practical tools live under lovia.tools. Nothing is imported automatically.
from lovia.tools.http import http_fetch
from lovia.tools.search import duckduckgo_search_tool
from lovia.tools.todo import TodoList, todo_tools
from lovia.tools.human import HumanChannel, ask_human
from lovia.tools.time import now
from lovia.tools.think import think
todos = TodoList()
agent = Agent(
name="assistant",
model="openai:gpt-4o-mini",
tools=[
http_fetch,
duckduckgo_search_tool(),
*todo_tools(todos),
now,
think,
],
)
Focused examples live in examples/tools/.
Sandbox and coding tools
For coding agents, attach a sandbox instead of manually wiring each file/shell tool:
from lovia import Agent
from lovia.sandbox import Sandbox
agent = Agent(
name="coder",
instructions="Make small, safe edits.",
model="openai:gpt-4o-mini",
sandbox=Sandbox.local(".", mode="coding"),
)
mode="coding" exposes read/write/edit/list/glob plus shell with approval.
mode="readonly" exposes only read/list/glob. mode="trusted" allows shell
without approval.
You can also use the factories directly:
from lovia.tools import coding_tools
agent = Agent(
name="coder",
model="openai:gpt-4o-mini",
tools=coding_tools(root=".", mode="coding"),
)
Local sandbox paths are root-relative and reject absolute paths, .. escapes,
and symlink escapes. Local shell commands still run as the host user; the local
sandbox is a convenience boundary, not a hard security boundary.
Structured output
Pass a Pydantic model to get validated output:
from pydantic import BaseModel
class Summary(BaseModel):
title: str
bullets: list[str]
agent = Agent(
name="summarizer",
model="openai:gpt-4o-mini",
output_type=Summary,
)
result = await Runner.run(agent, "Summarize lovia.")
print(result.output.title)
You can override the output type per call:
result = await Runner.run(agent, "Return JSON summary.", output_type=Summary)
Sessions and long conversations
Use sessions to persist transcript state:
from lovia.stores import SQLiteSession
session = SQLiteSession("chat.db")
await Runner.run(agent, "Remember my project is named Atlas.", session=session, session_id="u1")
await Runner.run(agent, "What is my project called?", session=session, session_id="u1")
For long-running chats, add a context policy:
from lovia import SummarizingContextPolicy
policy = SummarizingContextPolicy(keep_recent_messages=10)
result = await Runner.run(agent, "continue", context_policy=policy)
Web UI
The optional web layer gives you a small FastAPI app with:
- streamed assistant responses via SSE;
- persistent chat sessions when you pass
db_path; - HTTP approval for sensitive tools;
- markdown rendering for assistant messages;
- a Jinja2-rendered, no-build chat page.
pip install "lovia[web,dotenv]"
python examples/16_web_serve.py
from lovia.web import serve
serve(agent, host="127.0.0.1", port=8000, db_path="lovia.db")
Prefect workflows
lovia works well inside workflow orchestrators. The Prefect example wraps an agent call in a retryable task and calls it from a flow:
pip install "lovia[examples]"
python examples/24_prefect.py
from prefect import flow, task
from lovia import Agent, Runner
@task(retries=1)
async def ask_agent(topic: str) -> str:
result = await Runner.run(Agent(name="planner", model="openai:gpt-4o-mini"), topic)
return str(result.output)
@flow
async def plan() -> str:
return await ask_agent("plan a small release")
Examples
| File | What it shows |
|---|---|
examples/01_hello.py |
minimal agent run |
examples/02_tools.py |
custom @tool |
examples/03_streaming.py |
streaming output with Rich |
examples/04_structured_output.py |
Pydantic output |
examples/05_handoff.py |
agent handoff |
examples/08_skills.py |
skill catalog |
examples/11_approval.py |
tool approval |
examples/16_web_serve.py |
web UI |
examples/22_sandbox.py |
direct sandbox session |
examples/23_sandbox_agent.py |
coding agent with sandbox |
examples/24_prefect.py |
Prefect flow integration |
examples/tools/ |
focused tool demos |
examples/workflows/ |
workflow patterns |
Development
pip install -e ".[dev]"
ruff check .
ruff format --check .
mypy lovia
pytest -q
Core stays intentionally small. New integrations should normally be optional extras, examples, or user-side recipes unless they simplify the framework without adding weight.
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 lovia-0.5.2.tar.gz.
File metadata
- Download URL: lovia-0.5.2.tar.gz
- Upload date:
- Size: 383.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1a9182c01fedf20cabd48c25d4a964c4dbbfc55d780a3ae66166212ce314ef1
|
|
| MD5 |
05084d03500c9ca00427c91e43d6b314
|
|
| BLAKE2b-256 |
0bc8d3ce8c24eab6f8466f3d8fe5e6c7fe5f8ba365d50c0a81688f18b002c155
|
File details
Details for the file lovia-0.5.2-py3-none-any.whl.
File metadata
- Download URL: lovia-0.5.2-py3-none-any.whl
- Upload date:
- Size: 137.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4ca7a7f5b0b03e777c38a1f12d9a64cbf93db3a4107a101f90278a9f3e11b082
|
|
| MD5 |
409f1203a4d60e9083fca85f61cfb163
|
|
| BLAKE2b-256 |
b7bff33044ed7a12b53852c7e22070e4b0a7682b275cb45e322add8df39fefd9
|