Skip to main content

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 httpx and pydantic are 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lovia-0.5.2.tar.gz (383.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lovia-0.5.2-py3-none-any.whl (137.8 kB view details)

Uploaded Python 3

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

Hashes for lovia-0.5.2.tar.gz
Algorithm Hash digest
SHA256 d1a9182c01fedf20cabd48c25d4a964c4dbbfc55d780a3ae66166212ce314ef1
MD5 05084d03500c9ca00427c91e43d6b314
BLAKE2b-256 0bc8d3ce8c24eab6f8466f3d8fe5e6c7fe5f8ba365d50c0a81688f18b002c155

See more details on using hashes here.

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

Hashes for lovia-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 4ca7a7f5b0b03e777c38a1f12d9a64cbf93db3a4107a101f90278a9f3e11b082
MD5 409f1203a4d60e9083fca85f61cfb163
BLAKE2b-256 b7bff33044ed7a12b53852c7e22070e4b0a7682b275cb45e322add8df39fefd9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page