Metadata-Version: 2.4
Name: alloy-ai
Version: 0.1.2
Summary: Alloy (Python): Python for logic. English for intelligence.
Author: George Lydakis
License: MIT
Project-URL: Homepage, https://github.com/lydakis/alloy-py
Project-URL: Repository, https://github.com/lydakis/alloy-py
Project-URL: Issues, https://github.com/lydakis/alloy-py/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.63,>=0.62.0; extra == "anthropic"
Provides-Extra: gemini
Requires-Dist: google-genai<2,>=1.29.0; 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.63,>=0.62.0; extra == "providers"
Requires-Dist: google-genai<2,>=1.29.0; 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: 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"
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"
Dynamic: license-file

Alloy (Python): Python for logic. English for intelligence.

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

License: MIT

This repository contains an early scaffold of the Alloy library per `alloy-spec-v1.md`.

Quick start
- Install (all providers): `pip install 'alloy-ai[providers]'`
- Or minimal (OpenAI only): `pip install alloy-ai`
- Create `.env` with `OPENAI_API_KEY=...`
- Use the API:

```python
from dataclasses import dataclass
from dotenv import load_dotenv
from alloy import command, ask, configure

load_dotenv()
# Optional: configure() — default model is `gpt-5-mini` if omitted
# configure(model="gpt-5-mini", temperature=0.7)

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

print(ExtractPrice("This item costs $49.99."))
print(ask("Say hi"))
```

Notes
- OpenAI backend is implemented for sync/async/streaming.
- Streaming with tools is not yet supported.
- For structured outputs, Alloy attempts to use OpenAI structured responses (JSON schema). If unavailable, the model may still return JSON, which Alloy parses best-effort.
- Configuration defaults: Alloy uses `model=gpt-5-mini` if `configure(...)` is not called. You can also set process environment variables instead of a `.env` file:
  - `ALLOY_MODEL`, `ALLOY_TEMPERATURE`, `ALLOY_MAX_TOKENS`, `ALLOY_SYSTEM`/`ALLOY_DEFAULT_SYSTEM`, `ALLOY_RETRY`.
  - Example: `export ALLOY_MODEL=gpt-4o` then run your script.

Examples
- See `examples/basic_usage.py` and `examples/tools_demo.py` (tools + contracts).

Offline mode (dev only)
- To run examples without network/API keys, set `ALLOY_BACKEND=fake`.
- Example: `ALLOY_BACKEND=fake python examples/basic_usage.py`

Config precedence
- Defaults: `model=gpt-5-mini`, `max_tool_turns=2`.
- Process env (ALLOY_*) overrides defaults.
- Context/use_config and `configure(...)` override env/defaults.
- Per-call overrides (e.g., `ask(..., model=...)`) override everything above.

Make targets
- `make setup` — install dev deps and package in editable mode.
- `make test`, `make lint`, `make typecheck` — CI-like checks.
- `make examples` — runs `examples/basic_usage.py` and `examples/tools_demo.py`.
  - Tip: `ALLOY_BACKEND=fake make examples` to run offline.

Troubleshooting
- API key: Ensure `OPENAI_API_KEY` is set (process env or `.env`).
- Model choice: Prefer `gpt-5-mini` for fastest latency; switch via `configure(model=...)` or `ALLOY_MODEL`.
- Timeouts/slow runs: Reduce `max_tokens`, lower `temperature`, prefer smaller models, and cap tool loops.
- Tool loops: Alloy caps tool iterations by default (`max_tool_turns=2`). Adjust via `configure(max_tool_turns=1)` or env `ALLOY_MAX_TOOL_TURNS`.
- Rate limits (429): Shorten prompts/outputs, add retries with backoff, or use lower-throughput settings.

Integration tests
- OpenAI: Set `OPENAI_API_KEY` (and optionally `ALLOY_IT_MODEL`, default `gpt-5-mini`). Run `pytest -q` — OpenAI integration tests auto-enable.
- Anthropic: Set `ANTHROPIC_API_KEY` and `ALLOY_IT_MODEL=claude-3.5-sonnet` (or another Claude). Run `pytest -q` — Anthropic integration tests auto-enable.
- Gemini: Set `GOOGLE_API_KEY` and `ALLOY_IT_MODEL=gemini-1.5-pro` (or another Gemini). Run `pytest -q` — Gemini integration tests auto-enable.
  - SDK note: Gemini support uses `google-genai` (GA).

How to run locally
- Install providers bundle: `pip install 'alloy-ai[providers]'`
- Create `.env` with `OPENAI_API_KEY=...`
- Option A (no install):
  - `python examples/basic_usage.py`
  - `python examples/tools_demo.py`
  - (examples add `src/` to `sys.path` for you)
- Option B (editable install):
  - `pip install -e '.[providers]'`
  - Then run from anywhere.

.env example
```
OPENAI_API_KEY=sk-...
```
Support matrix (v1)
- OpenAI (GPT-4/5 and o-series): completions, typed commands, ask, streaming (no tools in stream), tool-calling, structured JSON for object schemas, tool-loop cap.
- Anthropic (Claude 3/3.5): completions and tool-calling loop (no streaming yet).
- Google (Gemini 1.5): basic completions (no tools/streaming in scaffold). Uses `google-genai` by default.
- Ollama (local): basic completions via `model="ollama:<name>"` (no tools/streaming in scaffold).
- ReAct fallback: not implemented yet (planned for local models/LLMs without native tools).

Install options
- Base: `pip install alloy-ai` (includes OpenAI + python-dotenv).
- All providers: `pip install 'alloy-ai[providers]'` (OpenAI, Anthropic, Gemini via `google-genai`, Ollama).
- Specific extras: `pip install 'alloy-ai[anthropic]'`, `pip install 'alloy-ai[gemini]'`, `pip install 'alloy-ai[ollama]'`.
Documentation
- Full docs: https://lydakis.github.io/alloy-py/

Releases
- Changelog: CHANGELOG.md
- Publishing: Create a tag like `v0.1.1` on main — CI builds and uploads to PyPI (needs Trusted Publishing for `alloy-ai` or a configured token).
