Skip to main content

lughus logo

PyPI version Supported Python versions License: MIT

lughus

Micro-framework for building A2A agents with LiteLLM. Register tools, run an agentic loop, get a result. No graphs, no runners, no magic.

Install

pip install lughus              # Core (litellm, python-dotenv, jsonschema)
pip install lughus[server]      # + FastAPI, uvicorn, a2a-sdk
pip install lughus[all]         # Everything

Quick Start

A complete agent in one script. Register a tool, call agent_loop, get the LLM's response:

import asyncio
import json

from lughus import ToolRegistry, agent_loop
from lughus.testing import MockLLM


# 1. Create a tool registry and register a tool
registry = ToolRegistry()


@registry.tool(
    "greet",
    "Greet a user by name.",
    {
        "type": "object",
        "properties": {
            "name": {"type": "string", "description": "Name to greet"},
        },
        "required": ["name"],
        "additionalProperties": False,
    },
)
def greet(*, name: str, state) -> str:
    return json.dumps({"greeting": f"Hello, {name}!"})


# 2. Create an LLM (MockLLM for offline testing, LLM for production)
llm = MockLLM(
    [
        # Turn 1: LLM calls the greet tool
        [{"name": "greet", "arguments": {"name": "World"}, "id": "call_1"}],
        # Turn 2: LLM produces a text response (ends the loop)
        "Hello, World!",
    ]
)


# 3. Run the agent loop
async def main():
    result = await agent_loop(
        llm,
        system="You are a greeting assistant. Use the greet tool.",
        context="Say hello to World",
        registry=registry,
        tool_names=["greet"],
        state=None,
    )
    print(result)  # "Hello, World!"
    print(f"{result.iterations} iterations, {result.total_tokens} tokens")


asyncio.run(main())

For production, swap MockLLM for a real LLM:

from lughus import LLM

llm = LLM(model="openai/gpt-4o", max_output_tokens=16384)

Features

  • agent_loop() -- iterates LLM + tools until a text response, with parallel tool execution
  • agent_loop_stream() -- same, but yields text chunks as the LLM generates them
  • ToolRegistry -- @registry.tool() decorator for sync and async Python functions
  • BaseGateway -- A2A AgentExecutor (message extraction, artifact handling)
  • LLM -- thin wrapper around litellm.acompletion(), supports 100+ providers
  • build_app() / serve() -- A2A ASGI app + uvicorn in one call
  • Governance -- deterministic tool policies, scoped permissions, human-in-the-loop approvals
  • Observability -- native OpenTelemetry traces and metrics on every request

Configuration

All configuration is via environment variables. Key settings:

Variable Default Description
AGENT_MODEL (required) LiteLLM model string (e.g. openai/gpt-4o)
MAX_OUTPUT_TOKENS 16384 Max output tokens per LLM call
HOST / PORT 0.0.0.0 / 8080 Server listen address
LUGHUS_ENV development Set production for strict startup validation
API_BEARER_TOKEN (not set) Bearer token for non-health routes

Provider routing is automatic via LiteLLM:

export AGENT_MODEL="openai/gpt-4o"       && export OPENAI_API_KEY="sk-..."
export AGENT_MODEL="anthropic/claude-sonnet-4-20250514" && export ANTHROPIC_API_KEY="sk-ant-..."
export AGENT_MODEL="gemini/gemini-2.5-flash" && export GEMINI_API_KEY="..."

Scaffold a New Agent

lughus new my_agent
cd my_agent && pip install -e ".[dev]" && pytest -q
python -m my_agent  # starts A2A server on :8080

Governance

Tools can declare risk levels, required scopes, and approval workflows. The policy engine evaluates actions deterministically before execution -- prompt instructions are never used as access controls. See docs/guides/agentic-design.md for agentic design rules.

from lughus import ToolRegistry, ToolRisk, ToolEffect

registry = ToolRegistry()

@registry.tool(
    "deploy",
    "Deploy to production.",
    {"type": "object", "properties": {"service": {"type": "string"}}, "required": ["service"]},
    risk=ToolRisk.CRITICAL,
    effects=frozenset([ToolEffect.WRITE, ToolEffect.IRREVERSIBLE]),
    requires_approval=True,
)
def deploy(*, service: str, state) -> str:
    return json.dumps({"status": "deployed"})

Links

License

MIT -- see LICENSE.

Download files

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

Source Distribution

lughus-0.15.0.tar.gz (182.3 kB view details)

Uploaded Source

Built Distribution

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

lughus-0.15.0-py3-none-any.whl (123.4 kB view details)

Uploaded Python 3

File details

Details for the file lughus-0.15.0.tar.gz.

File metadata

  • Download URL: lughus-0.15.0.tar.gz
  • Upload date:
  • Size: 182.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lughus-0.15.0.tar.gz
Algorithm Hash digest
SHA256 b79ea65b859f54dcd767e9a9a51f9d8b86d259e373ba8ac2f9bccc6bfb09d90b
MD5 0d38af3f7c8b7fc2cde00a8e1680d721
BLAKE2b-256 e7c6fa882b153c3343d93fcbb6716c08e24243932c01debb795c4f00135fa3c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for lughus-0.15.0.tar.gz:

Publisher: publish.yml on hdg-zero/lughus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file lughus-0.15.0-py3-none-any.whl.

File metadata

  • Download URL: lughus-0.15.0-py3-none-any.whl
  • Upload date:
  • Size: 123.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for lughus-0.15.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bcb5ca87150c1e24db7fffb4e793402a7045242bca154da611f992eaac3ec7b2
MD5 60690d398433f505ef87025d16348dcc
BLAKE2b-256 3a801042dd8f11fc8f62bb2329ff637ef2842d903b1d01fa693f9ccd5fed77ab

See more details on using hashes here.

Provenance

The following attestation bundles were made for lughus-0.15.0-py3-none-any.whl:

Publisher: publish.yml on hdg-zero/lughus

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.20.0

2 files

0.19.0

2 files

0.18.0

2 files

0.17.0

2 files

This release

0.15.0 This release

2 files

0.14.1

2 files

0.12.0

2 files

0.11.0

2 files

0.10.2

2 files

0.10.1

2 files

0.9.0

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page