Metadata-Version: 2.4
Name: alloy-ai
Version: 0.3.0
Summary: Alloy (Python): Python for logic. English for intelligence.
Author: George Lydakis
License: MIT
Project-URL: Homepage, https://github.com/lydakis/alloy
Project-URL: Repository, https://github.com/lydakis/alloy
Project-URL: Issues, https://github.com/lydakis/alloy/issues
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: openai<2,>=1.99.6
Requires-Dist: python-dotenv<2,>=1.1.1
Provides-Extra: openai
Requires-Dist: openai<2,>=1.99.6; extra == "openai"
Requires-Dist: python-dotenv<2,>=1.1.1; extra == "openai"
Provides-Extra: anthropic
Requires-Dist: anthropic<0.65,>=0.62.0; extra == "anthropic"
Provides-Extra: gemini
Requires-Dist: google-genai<2,>=1.29.0; extra == "gemini"
Requires-Dist: aiohttp<4,>=3.9; extra == "gemini"
Provides-Extra: providers
Requires-Dist: openai<2,>=1.99.6; extra == "providers"
Requires-Dist: python-dotenv<2,>=1.1.1; extra == "providers"
Requires-Dist: anthropic<0.65,>=0.62.0; extra == "providers"
Requires-Dist: google-genai<2,>=1.29.0; extra == "providers"
Requires-Dist: aiohttp<4,>=3.9; extra == "providers"
Requires-Dist: ollama<0.6,>=0.5.3; extra == "providers"
Provides-Extra: ollama
Requires-Dist: ollama<0.6,>=0.5.3; extra == "ollama"
Provides-Extra: dev
Requires-Dist: pytest<9,>=8.4.1; extra == "dev"
Requires-Dist: pytest-asyncio<1.2,>=0.25.2; extra == "dev"
Requires-Dist: pytest-cov<7,>=5.0.0; extra == "dev"
Requires-Dist: pytest-xdist<4,>=3.6.1; extra == "dev"
Requires-Dist: ruff<0.13,>=0.12.8; extra == "dev"
Requires-Dist: black<26,>=25.1.0; extra == "dev"
Requires-Dist: mypy<2,>=1.17.1; extra == "dev"
Requires-Dist: pre-commit<5,>=4.3.0; extra == "dev"
Requires-Dist: hypothesis<7,>=6.115.0; extra == "dev"
Requires-Dist: python-dateutil<3,>=2.9.0.post0; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs<2,>=1.6; extra == "docs"
Requires-Dist: mkdocs-material<10,>=9.5; extra == "docs"
Requires-Dist: mkdocstrings<0.31,>=0.28; extra == "docs"
Requires-Dist: mkdocstrings-python<2,>=1.16; extra == "docs"
Requires-Dist: pymdown-extensions<11,>=10.11; extra == "docs"
Requires-Dist: mkdocs-llmstxt<1,>=0.3; extra == "docs"
Requires-Dist: mkdocs-gen-files<1,>=0.5; extra == "docs"
Dynamic: license-file

# Alloy (Python)

Python for logic. English for intelligence.

[![CI](https://github.com/lydakis/alloy/actions/workflows/ci.yml/badge.svg)](https://github.com/lydakis/alloy/actions/workflows/ci.yml)
[![Docs](https://github.com/lydakis/alloy/actions/workflows/docs.yml/badge.svg)](https://docs.alloy.fyi/)
[![Docs Site](https://img.shields.io/badge/docs-website-blue)](https://docs.alloy.fyi/)
[![PyPI](https://img.shields.io/pypi/v/alloy-ai.svg)](https://pypi.org/project/alloy-ai/)
[![Downloads](https://pepy.tech/badge/alloy-ai)](https://pepy.tech/project/alloy-ai)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

```python
from alloy import command

@command(output=float)
def extract_price(text: str) -> str:
    return f"Extract the price from: {text}"

print(extract_price("This costs $49.99"))  # 49.99
```

Write typed AI functions that feel like normal Python. No framework, no abstractions —
just functions that happen to use AI.

[Install](#install) • [Tutorial](https://docs.alloy.fyi/tutorial/) • [Examples](examples/) • [Docs](https://docs.alloy.fyi)

## Install

```bash
pip install alloy-ai                    # OpenAI only
pip install 'alloy-ai[anthropic]'       # With Anthropic
pip install 'alloy-ai[providers]'       # All providers
```

Quick start (OpenAI):

```bash
export OPENAI_API_KEY=sk-...
python -c "from alloy import ask; print(ask('Say hello'))"
```

## Why Alloy?

**🎯 Types you can trust**: Provider‑enforced structured outputs. Get a real `float`, not a string to parse.

**🐍 Just Python**: Commands are functions. Tools are functions. Everything composes.

**⚡ Production‑ready**: Retries, contracts, streaming, cross‑provider support — batteries included.

**🔍 Zero magic**: See what’s happening. Control what’s happening. No hidden state.

## Examples

**Exploration with `ask`** — Quick one‑offs and streaming

```python
from alloy import ask

# One‑liner exploration
print(ask("List 3 reasons Alloy is useful."))

# Stream text output (text‑only streaming)
for chunk in ask.stream("Write a two‑sentence pitch for Alloy."):
    print(chunk, end="")
```

**Typed outputs** — Get back real Python objects

```python
from dataclasses import dataclass
from alloy import command

@dataclass
class Analysis:
    sentiment: str
    score: float
    keywords: list[str]

@command(output=Analysis)
def analyze(text: str) -> str:
    return f"Analyze this text: {text}"

result = analyze("Alloy is amazing!")
print(result.score)  # 0.95
```

TypedDict outputs are supported too:

```python
from typing import TypedDict
from alloy import command

class Product(TypedDict):
    name: str
    price: float

@command(output=Product)
def make() -> str:
    return "Return a Product with name='Test' and price=9.99 (numeric literal)."

print(make()["price"])  # 9.99
```

**Tools + Contracts** — Safe multi‑step workflows

```python
from alloy import command, tool, ensure, require

@tool
@ensure(lambda x: x > 0, "Result must be positive")
def calculate(expression: str) -> float:
    return eval(expression)  # simplified example

@command(tools=[calculate])
def solve(problem: str) -> str:
    return f"Solve step by step: {problem}"
```

See more in [examples/](examples/) and the
[Examples guide](https://docs.alloy.fyi/examples/).

<details>
<summary>📦 More installation options</summary>

```bash
# Specific providers
pip install 'alloy-ai[anthropic]'
pip install 'alloy-ai[gemini]'
pip install 'alloy-ai[ollama]'

# Development
pip install -e '.[dev]'
```

</details>

<details>
<summary>🔧 Configuration</summary>

```bash
export ALLOY_MODEL=gpt-5-mini
export ALLOY_TEMPERATURE=0.2
export ALLOY_MAX_TOOL_TURNS=10
```

Or in Python:

```python
from alloy import configure
configure(model="gpt-5-mini", temperature=0.2)
```

</details>

<details>
<summary>🧪 Run examples offline</summary>

```bash
export ALLOY_BACKEND=fake
make examples-quick
```

</details>

## Providers

Works with major providers — same code, zero changes:

| Provider | Models (examples) | Setup |
|----------|--------------------|-------|
| OpenAI   | gpt‑5              | `export OPENAI_API_KEY=...` |
| Anthropic| claude‑4           | `export ANTHROPIC_API_KEY=...` |
| Google   | gemini             | `export GOOGLE_API_KEY=...` |
| Local    | ollama             | `ollama run <model>` + `ALLOY_MODEL=ollama:<model>` |

See the [full provider guide](https://docs.alloy.fyi/guide/providers/).

## Next Steps

New to Alloy? → [10‑minute tutorial](https://docs.alloy.fyi/tutorial/)

Ready to build? → [Browse examples](examples/)

Need details? → [Read the docs](https://docs.alloy.fyi)

## Contributing

We welcome contributions! See [.github/CONTRIBUTING.md](.github/CONTRIBUTING.md).

## License

MIT — see [LICENSE](LICENSE).
