Metadata-Version: 2.3
Name: avalan
Version: 1.0.12
Summary: Multi-backend, multi-modal framework for seamless AI agent development, orchestration, and deployment
License: MIT
Author: The Avalan Team
Author-email: avalan@avalan.ai
Requires-Python: >=3.11.11
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Operating System :: OS Independent
Provides-Extra: agent
Provides-Extra: all
Provides-Extra: audio
Provides-Extra: cpu
Provides-Extra: memory
Provides-Extra: mlx
Provides-Extra: quantization
Provides-Extra: secrets
Provides-Extra: server
Provides-Extra: test
Provides-Extra: tool
Provides-Extra: translation
Provides-Extra: vendors
Provides-Extra: vision
Provides-Extra: vllm
Requires-Dist: accelerate (==1.7.0) ; extra == "all"
Requires-Dist: accelerate (==1.7.0) ; extra == "cpu"
Requires-Dist: anthropic (==0.52.0) ; extra == "all"
Requires-Dist: anthropic (==0.52.0) ; extra == "vendors"
Requires-Dist: bitsandbytes (==0.45.5) ; extra == "all"
Requires-Dist: bitsandbytes (==0.45.5) ; extra == "quantization"
Requires-Dist: boto3 (==1.38.29) ; extra == "all"
Requires-Dist: boto3 (==1.38.29) ; extra == "secrets"
Requires-Dist: boto3 (==1.38.29) ; extra == "test"
Requires-Dist: faiss-cpu (==1.11.0) ; extra == "all"
Requires-Dist: faiss-cpu (==1.11.0) ; extra == "memory"
Requires-Dist: faiss-cpu (==1.11.0) ; extra == "test"
Requires-Dist: fastapi (==0.115.12) ; extra == "all"
Requires-Dist: fastapi (==0.115.12) ; extra == "server"
Requires-Dist: fastapi (==0.115.12) ; extra == "test"
Requires-Dist: google-genai (==1.16.1) ; extra == "all"
Requires-Dist: google-genai (==1.16.1) ; extra == "vendors"
Requires-Dist: humanize (==4.12.3)
Requires-Dist: jinja2 (==3.1.6) ; extra == "agent"
Requires-Dist: jinja2 (==3.1.6) ; extra == "all"
Requires-Dist: keyring (==25.6.0) ; extra == "all"
Requires-Dist: keyring (==25.6.0) ; extra == "secrets"
Requires-Dist: keyring (==25.6.0) ; extra == "test"
Requires-Dist: markitdown[pdf] (==0.1.1) ; extra == "all"
Requires-Dist: markitdown[pdf] (==0.1.1) ; extra == "memory"
Requires-Dist: markitdown[pdf] (==0.1.1) ; extra == "test"
Requires-Dist: mcp (==1.9.1) ; extra == "all"
Requires-Dist: mcp (==1.9.1) ; extra == "server"
Requires-Dist: mcp (==1.9.1) ; extra == "test"
Requires-Dist: mlx-lm (==0.24.1) ; extra == "all"
Requires-Dist: mlx-lm (==0.24.1) ; extra == "mlx"
Requires-Dist: mlx-lm (==0.24.1) ; extra == "test"
Requires-Dist: openai (==1.82.0) ; extra == "all"
Requires-Dist: openai (==1.82.0) ; extra == "vendors"
Requires-Dist: packaging (==25.0)
Requires-Dist: pandas (==2.2.3)
Requires-Dist: pgvector (==0.4.1) ; extra == "all"
Requires-Dist: pgvector (==0.4.1) ; extra == "memory"
Requires-Dist: pgvector (==0.4.1) ; extra == "test"
Requires-Dist: pillow (==11.2.1) ; extra == "all"
Requires-Dist: pillow (==11.2.1) ; extra == "test"
Requires-Dist: pillow (==11.2.1) ; extra == "vendors"
Requires-Dist: pillow (==11.2.1) ; extra == "vision"
Requires-Dist: playwright (==1.52.0) ; extra == "all"
Requires-Dist: playwright (==1.52.0) ; extra == "test"
Requires-Dist: playwright (==1.52.0) ; extra == "tool"
Requires-Dist: protobuf (==6.31.0) ; extra == "all"
Requires-Dist: protobuf (==6.31.0) ; extra == "translation"
Requires-Dist: psycopg[binary,pool] (==3.2.9) ; extra == "all"
Requires-Dist: psycopg[binary,pool] (==3.2.9) ; extra == "memory"
Requires-Dist: psycopg[binary,pool] (==3.2.9) ; extra == "test"
Requires-Dist: pydantic (==2.11.5) ; extra == "all"
Requires-Dist: pydantic (==2.11.5) ; extra == "server"
Requires-Dist: pydantic (==2.11.5) ; extra == "test"
Requires-Dist: pytest (==8.3.5) ; extra == "all"
Requires-Dist: pytest (==8.3.5) ; extra == "test"
Requires-Dist: rich (==14.0.0)
Requires-Dist: sentence-transformers (==4.1.0) ; extra == "all"
Requires-Dist: sentence-transformers (==4.1.0) ; extra == "memory"
Requires-Dist: sentencepiece (==0.2.0) ; extra == "all"
Requires-Dist: sentencepiece (==0.2.0) ; extra == "translation"
Requires-Dist: sympy (==1.14.0) ; extra == "all"
Requires-Dist: sympy (==1.14.0) ; extra == "tool"
Requires-Dist: tiktoken (==0.9.0) ; extra == "all"
Requires-Dist: tiktoken (==0.9.0) ; extra == "test"
Requires-Dist: tiktoken (==0.9.0) ; extra == "translation"
Requires-Dist: tiktoken (==0.9.0) ; extra == "vendors"
Requires-Dist: torch (==2.7.0)
Requires-Dist: torch (==2.7.0) ; extra == "test"
Requires-Dist: torchaudio (==2.7.0) ; extra == "all"
Requires-Dist: torchaudio (==2.7.0) ; extra == "audio"
Requires-Dist: torchaudio (==2.7.0) ; extra == "test"
Requires-Dist: torchvision (==0.22.0) ; extra == "all"
Requires-Dist: torchvision (==0.22.0) ; extra == "vision"
Requires-Dist: transformers (==4.52.3)
Requires-Dist: transformers (==4.52.3) ; extra == "test"
Requires-Dist: tree-sitter (==0.24.0) ; extra == "all"
Requires-Dist: tree-sitter (==0.24.0) ; extra == "memory"
Requires-Dist: tree-sitter (==0.24.0) ; extra == "test"
Requires-Dist: tree-sitter-python (==0.23.6) ; extra == "all"
Requires-Dist: tree-sitter-python (==0.23.6) ; extra == "memory"
Requires-Dist: tree-sitter-python (==0.23.6) ; extra == "test"
Requires-Dist: uvicorn (==0.34.2) ; extra == "all"
Requires-Dist: uvicorn (==0.34.2) ; extra == "server"
Requires-Dist: vllm[cpu] (==0.1.0) ; extra == "vllm"
Project-URL: Bug Tracker, https://github.com/avalan-ai/avalan/issues
Project-URL: Documentation, https://github.com/avalan-ai/avalan#readme
Project-URL: Homepage, https://avalan.ai
Project-URL: Repository, https://github.com/avalan-ai/avalan
Description-Content-Type: text/markdown

<h1 align="center">avalan</h1>
<h3 align="center">The multi-backend, multi-modal framework for effortless AI agent development, orchestration, and deployment</h3>

<p align="center">
  <img src="https://github.com/avalan-ai/avalan/actions/workflows/test.yml/badge.svg" alt="Tests" />
  <img src="https://codecov.io/gh/avalan-ai/avalan/branch/main/graph/badge.svg" alt="Code coverage" />
  <img src="https://img.shields.io/github/last-commit/avalan-ai/avalan.svg" alt="Last commit" />
  <img src="https://img.shields.io/github/v/release/avalan-ai/avalan?label=Release" alt="Release" />
  <img src="https://img.shields.io/pypi/l/avalan.svg" alt="License" />
</p>

avalan empowers developers and enterprises to easily build, orchestrate, and deploy intelligent AI agents—locally or in the cloud—across millions of models via a unified SDK and CLI, featuring multi-backend support ([transformers](https://github.com/huggingface/transformers), [vLLM](https://github.com/vllm-project/vllm), [mlx-lm](https://github.com/ml-explore/mlx-lm)), multi-modal integration (NLP, vision, audio), and native adapters for platforms like OpenRouter, Ollama, OpenAI, DeepSeek, and Gemini. Enhanced by sophisticated memory management, advanced reasoning (including ReACT tooling and adaptive planning), and intuitive pipelines with branching, filtering, and recursive workflows, avalan ensures agents continuously learn and adapt. Comprehensive observability through real-time metrics, event tracing, and statistical dashboards provides deep insights and robust governance, making avalan ideal for everything from individual experimentation to enterprise-scale AI deployments.

# Quick Look

Check out [the CLI documentation](docs/CLI.md) to see what it can do, but if you want to jump right in, you can run any locally installed model and tweak sampling settings like `--temperature`, `--top-p`, and `--top-k`. In this example, we prompt the model as "Aurora" and limit the response to 100 new tokens:

```bash
echo 'Who are you, and who is Leo Messi?' \
  | avalan model run "meta-llama/Meta-Llama-3-8B-Instruct" \
      --system "You are Aurora, a helpful assistant" \
      --max-new-tokens 100 \
      --temperature .1 \
      --top-p .9 \
      --top-k 20
```

Just as easily as you can run local models, you can use vendors. Simply swap in a vendor-backed [engine URI](docs/ai_uri.md) to run on an external API. For instance, to hit OpenAI's GPT-4o endpoint with the same sampling parameters:

```
echo 'Who are you, and who is Leo Messi?' \
  | avalan model run "ai://$OPENAI_API_KEY@openai/gpt-4o" \
      --system "You are Aurora, a helpful assistant" \
      --max-new-tokens 100 \
      --temperature .1 \
      --top-p .9 \
      --top-k 20
```

Avalan makes it trivial to spin up a chat-based agent that can invoke external tools, even while streaming. Below is an example using a locally installed 8B-parameter LLM, enabling recent memory, and loading a calculator tool. The agent starts with a math question and then keeps the conversation open for follow-up questions:

```bash
echo "What is (4 + 6) and then that result times 5, divided by 2?" \
  | avalan agent run \
      --engine-uri "NousResearch/Hermes-3-Llama-3.1-8B" \
      --tool "math.calculator" \
      --memory-recent \
      --run-max-new-tokens 1024 \
      --name "Tool" \
      --role "You are a helpful assistant named Tool, that can resolve user requests using tools." \
      --stats \
      --conversation
```

Check the GPU hard at work towards the bottom:

![Example use of an ephemeral tool agent with memory](https://avalan.ai/images/agent_ephemeral_tool.gif)

With tooling, agents get real-time knowledge. Here's an 8B model looking for avalan's latest release, using a browser to do so:

```bash
echo "What's avalan's latest release in pypi?" | \
    avalan agent run \
        --engine-uri "NousResearch/Hermes-3-Llama-3.1-8B" \
        --tool "browser.open" \
        --memory-recent \
        --run-max-new-tokens 1024 \
        --name "Tool" \
        --role "You are a helpful assistant named Tool, that can resolve user requests using tools." \
        --stats
```

You can point an agent to specific locations for gaining knowledge:

```bash
echo "Tell me what avalan does based on the web page https://raw.githubusercontent.com/avalan-ai/avalan/refs/heads/main/README.md" | \
    avalan agent run \
        --engine-uri "NousResearch/Hermes-3-Llama-3.1-8B" \
        --tool "browser.open" \
        --memory-recent \
        --run-max-new-tokens 1024 \
        --name "Tool" \
        --role "You are a helpful assistant named Tool, that can resolve user requests using tools." \
        --stats
```

Through the avalan microframework, you can easily integrate real time token
streaming with your own code, as [this example shows](https://github.com/avalan-ai/avalan/blob/main/docs/examples/text_generation.py):

```python
from asyncio import run
from avalan.model.entities import GenerationSettings
from avalan.model.nlp.text import TextGenerationModel

async def example() -> None:
    print("Loading model... ", end="", flush=True)
    with TextGenerationModel("meta-llama/Meta-Llama-3-8B-Instruct") as lm:
        print("DONE.", flush=True)

        system_prompt = """
            You are Leo Messi, the greatest football/soccer player of all
            times.
        """

        async for token in await lm(
            "Who are you?",
            system_prompt=system_prompt,
            settings=GenerationSettings(temperature=0.9, max_new_tokens=256)
        ):
            print(token, end="", flush=True)

if __name__ == "__main__":
    run(example())
```

Besides natural language processing, you can also work with other types of
models, such as those that handle vision, like the following
[image classification example](https://github.com/avalan-ai/avalan/blob/main/docs/examples/vision_image_classification.py):

```python
from asyncio import run
from avalan.model.vision.detection import ObjectDetectionModel
import os
import sys

async def example(path: str) -> None:
    print("Loading model... ", end="", flush=True)
    with ObjectDetectionModel("facebook/detr-resnet-50") as od:
        print(f"DONE. Running classification for {path}", flush=True)

        for entity in await od(path):
            print(entity, flush=True)

if __name__ == "__main__":
    path = sys.argv[1] if len(sys.argv)==2 and os.path.isfile(sys.argv[1]) \
           else sys.exit(f"Usage: {sys.argv[0]} <valid_file_path>")
    run(example(path))
```

Looking for sequence to sequence models? Just as easy, like this [summarization
example shows](https://github.com/avalan-ai/avalan/blob/main/docs/examples/seq2seq_summarization.py):

```python
from asyncio import run
from avalan.model.entities import GenerationSettings
from avalan.model.nlp.sequence import SequenceToSequenceModel

async def example() -> None:
    print("Loading model... ", end="", flush=True)
    with SequenceToSequenceModel("facebook/bart-large-cnn") as s:
        print("DONE.", flush=True)

        text = """
            Andres Cuccittini, commonly known as Andy Cucci, is an Argentine
            professional footballer who plays as a forward for the Argentina
            national team. Regarded by many as the greatest footballer of all
            time, Cucci has achieved unparalleled success throughout his career.

            Born on July 25, 1988, in Ushuaia, Argentina, Cucci began playing
            football at a young age and joined the Boca Juniors youth
            academy.
            """

        summary = await s(text, GenerationSettings(num_beams=4, max_length=60))
        print(summary)

if __name__ == "__main__":
    run(example())
```

You can also perform translations, as [the following example shows](https://github.com/avalan-ai/avalan/blob/main/docs/examples/seq2seq_translation.py).
You'll need the `translation` extra installed for this to run:

```python
from asyncio import run
from avalan.model.entities import GenerationSettings
from avalan.model.nlp.sequence import TranslationModel

async def example() -> None:
    print("Loading model... ", end="", flush=True)
    with TranslationModel("facebook/mbart-large-50-many-to-many-mmt") as t:
        print("DONE.", flush=True)

        text = """
            Lionel Messi, commonly known as Leo Messi, is an Argentine
            professional footballer who plays as a forward for the Argentina
            national team. Regarded by many as the greatest footballer of all
            time, Messi has achieved unparalleled success throughout his career.
        """

        translation = await t(
            text,
            source_language="en_US",
            destination_language="es_XX",
            settings=GenerationSettings(num_beams=4, max_length=512)
        )

        print(" ".join([line.strip() for line in text.splitlines()]).strip())
        print("-" * 12)
        print(translation)

if __name__ == "__main__":
    run(example())
```

You can also create AI agents. Let's create one to handle gettext translations.
Create a file named [agent_gettext_translator.toml](https://github.com/avalan-ai/avalan/blob/main/docs/examples.agent_gettext_translator.toml)
with the following contents:

```toml
[agent]
role = """
You are an expert translator that specializes in translating gettext
translation files.
"""
task = """
Your task is to translate the given gettext template file,
from the original {{source_language}} to {{destination_language}}.
"""
instructions = """
The text to translate is marked with `msgid`, and it's quoted.
Your translation should be defined in `msgstr`.
"""
rules = [
    """
    Ensure you keep the gettext format intact, only altering
    the `msgstr` section.
    """,
    """
    Respond only with the translated file.
    """
]

[template]
source_language = "English"
destination_language = "Spanish"

[engine]
uri = "meta-llama/Meta-Llama-3-8B-Instruct"

[run]
use_cache = true
max_new_tokens = 1024
skip_special_tokens = true
```

You can now run your agent. Let's give it a gettext translation template file,
have our agent translate it for us, and show a visual difference of what the
agent changed:

```bash
icdiff locale/avalan.pot <(
    cat locale/avalan.pot |
        avalan agent run docs/examples/agent_gettext_translator.toml --quiet
)
```

![diff showing what the AI translator agent modified](https://avalan.ai/images/agent_translator_diff.png)

There are more agent, NLP, multimodal, audio, and vision examples in the
[docs/examples](https://github.com/avalan-ai/avalan/blob/main/docs/examples)
folder.

# Install

Create your virtual environment and install packages:

```bash
poetry install avalan
```

> [!TIP]
> At time of this writing, while Python 3.12 is stable and available
> in Homebrew, sentenpiece, a package added by the extra `translation`,
> requires Python 3.11, so you may want to force the python version when
> creating the virtual environment: `python-3.11 -m venv .venv/`

> [!TIP]
> If you will be using avalan with a device other than `cuda`, or wish to
> use `--low-cpu-mem-usage` you'll need the CPU packages installed, so run
> `poetry install --extras 'cpu'` You can also specify multiple extras to install,
> for example with:
>
> ```bash
> poetry install avalan --extras 'agent audio cpu memory secrets server test translation vision'
> ```
>
> Or you can install all extras at once with:
>
> ```bash
> poetry install avalan --extras all
> ```

> [!TIP]
> If you are going to be using transformer loading classes that haven't yet
> made it into a transformers package released version, install transformers
> development edition:
> `poetry install git+https://github.com/huggingface/transformers --no-cache`

> [!TIP]
> On MacOS, sentencepiece may have issues while installing. If so,
> ensure Xcode CLI is installed, and install needed Homebrew packages
> with:
>
> `xcode-select --install`
> `brew install cmake pkg-config protobuf sentencepiece`


