Metadata-Version: 2.4
Name: codex-ai
Version: 0.2.4
Summary: Gemini-first and OpenAI provider helpers for Codex
Project-URL: Homepage, https://github.com/codexdlc/codex-ai
Project-URL: Documentation, https://codexdlc.github.io/codex-ai/
Project-URL: Repository, https://github.com/codexdlc/codex-ai
Project-URL: Issues, https://github.com/codexdlc/codex-ai/issues
Author: CodexDLC
License: Apache-2.0
License-File: LICENSE
Keywords: gemini,google-genai,llm,openai,waas
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.12
Requires-Dist: codex-core<0.5.0,>=0.2.2
Requires-Dist: pydantic<3.0,>=2.0
Provides-Extra: all
Requires-Dist: google-genai==2.3.0; extra == 'all'
Requires-Dist: openai<2.0,>=1.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: bandit>=1.7; extra == 'dev'
Requires-Dist: detect-secrets>=1.5; extra == 'dev'
Requires-Dist: google-genai==2.3.0; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: openai<2.0,>=1.0; extra == 'dev'
Requires-Dist: pip-audit>=2.7; extra == 'dev'
Requires-Dist: pre-commit>=3.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mike>=2.0; extra == 'docs'
Requires-Dist: mkdocs-include-markdown-plugin; extra == 'docs'
Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
Requires-Dist: mkdocs>=1.5; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
Provides-Extra: gemini
Requires-Dist: google-genai==2.3.0; extra == 'gemini'
Provides-Extra: openai
Requires-Dist: openai<2.0,>=1.0; extra == 'openai'
Description-Content-Type: text/markdown

# codex-ai <!-- Type: LANDING -->

[![PyPI version](https://img.shields.io/pypi/v/codex-ai.svg)](https://pypi.org/project/codex-ai/)
[![Python](https://img.shields.io/pypi/pyversions/codex-ai.svg)](https://pypi.org/project/codex-ai/)
[![CI](https://github.com/codexdlc/codex-ai/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/codexdlc/codex-ai/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/codexdlc/codex-ai/blob/main/LICENSE)

Gemini-first API helpers for the Codex ecosystem. The active surface is direct Gemini text, JSON, Gemini image, and Imagen generation. OpenAI remains as a small text-only adapter, and the router/dispatcher layer is kept for legacy text workflows.

## Install

```bash
pip install codex-ai
pip install "codex-ai[gemini]"
pip install "codex-ai[openai]"
pip install "codex-ai[openai,gemini]"
```

Requires Python 3.12 or newer.

## Gemini Direct API

```python
from pydantic import BaseModel

from codex_ai import GeminiProvider


class LootItem(BaseModel):
    name: str
    power: int


gemini = GeminiProvider(api_key="AIza...")

text = await gemini.generate_text("Write one short tavern rumor.")
loot = await gemini.generate_json("Create one loot item.", schema=LootItem)
image_bytes, content_type = await gemini.generate_image_bytes(
    "Square tactical dark fantasy ruined capital city map, no labels.",
    model="gemini-3-pro-image-preview",
    response_mime_type="image/png",
    image_config={"aspect_ratio": "1:1", "image_size": "4K"},
)

imagen_bytes, imagen_content_type = await gemini.generate_imagen_bytes(
    "A fantasy clan banner, game icon style.",
    response_mime_type="image/jpeg",
)
```

`answer(prompt)` remains available as a compatibility wrapper for text generation.

`generate_image_bytes()` targets Gemini image models through `generate_content` and treats
`response_mime_type` as a preferred/fallback MIME type. It does not pass image MIME values
to Gemini's text `response_mime_type` config field. Pass Gemini image controls such as
`aspect_ratio` and `image_size` with `image_config`; if a `4K` request is rejected,
the Gemini provider retries once with `2K`. Use `generate_imagen_bytes()` for
Imagen models; that path uses `generate_images` and passes the requested MIME as
`output_mime_type`.

## Legacy Text Router

```python
from codex_ai import GeminiProvider, LLMDispatcher, LLMMessage, LLMRouter, PromptResult

router = LLMRouter()


@router.prompt("chat")
async def build_chat(text: str, **kw) -> PromptResult:
    return PromptResult(
        messages=[LLMMessage(role="user", content=text)],
        system="You are a helpful assistant.",
    )


dispatcher = LLMDispatcher(provider=GeminiProvider(api_key="AIza..."))
dispatcher.include_router(router)

response = await dispatcher.process("chat", text="Hello!")
```

Use this path only when you already have prompt builders registered through `LLMRouter`.
New Gemini integrations should call `generate_text()`, `generate_json()`,
`generate_image_bytes()`, or `generate_imagen_bytes()` directly.

## Modules

| Module | Extra | Description |
| :--- | :--- | :--- |
| `codex_ai.providers.gemini` | `[gemini]` | Primary API: Gemini text, JSON, Gemini image, and Imagen generation via pinned `google-genai` |
| `codex_ai.providers.openai` | `[openai]` | Text-only OpenAI Chat Completions adapter |
| `codex_ai.core` | - | Legacy text router/dispatcher contracts and shared provider exceptions |

## Development

```bash
uv sync --extra dev
uv run pytest
uv run mypy src/
uv run pre-commit run --all-files
uv build --no-sources
```

## Documentation

Full docs with architecture, API reference, and data flow diagrams:

**[codexdlc.github.io/codex-ai](https://codexdlc.github.io/codex-ai/)**
