Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Tests

on:
push:
branches:
- main
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
unit:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.13']
steps:
- uses: actions/checkout@v7

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

- name: Setup uv
uses: astral-sh/setup-uv@v8.3.2
with:
enable-cache: true

- name: Verify Codex remains optional
run: >-
uv run --python "${{ matrix.python-version }}" --extra dev python -c
'from importlib.metadata import distributions;
installed = {d.metadata["Name"].lower() for d in distributions()};
packages = {"filelock", "openai-codex",
"openai-codex-cli-bin"};
assert not packages & installed'

- name: Run tests
run: uv run --python "${{ matrix.python-version }}" --extra dev pytest

codex-provider:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ['3.10', '3.13']
steps:
- uses: actions/checkout@v7

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

- name: Setup uv
uses: astral-sh/setup-uv@v8.3.2
with:
enable-cache: true

- name: Run tests with the Codex SDK and bundled runtime
run: >-
uv run --python "${{ matrix.python-version }}"
--extra dev --extra codex pytest

codex-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v7

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.13'

- name: Setup uv
uses: astral-sh/setup-uv@v8.3.2
with:
enable-cache: true

- name: Verify bundled runtime and portable authentication lifecycle
run: >-
uv run --python 3.13 --extra dev --extra codex pytest
tests/test_codex.py::TestBackendLifecycle
tests/test_codex_runtime.py

docs:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: '3.13'

- name: Setup uv
uses: astral-sh/setup-uv@v8.3.2
with:
enable-cache: true

- name: Build documentation
run: uv run --python 3.13 --extra docs mkdocs build
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,23 @@ e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR

## [Unreleased]

### Adicionado

- Provider experimental `codex` via SDK Python oficial, disponível exclusivamente no extra `dataframeit[codex]`, com runtime pinado, autenticação em arquivo, isolamento por execução e saída estruturada validada (#111).

### Corrigido

- O provider `codex` agora rejeita schemas incompatíveis com Structured Outputs durante o preflight, orienta o login file-backed com o comando correto, compartilha `auth.json` sem depender de symlink privilegiado no Windows e impede que duas execuções do DataFrameIt atualizem a mesma credencial concorrentemente (#111).
- Checkpoints validam as linhas processadas contra o modelo Pydantic atual e exigem `reprocess_columns` somente para campos incompatíveis, evitando resultados marcados como concluídos com valores ausentes sem rejeitar campos opcionais ou com default (#111).
- A telemetria preserva tokens de leitura de cache informados por providers LangChain nos caminhos normal e com busca (#111).
- Falhas transitórias tipadas do Codex recebem retry sem serem confundidas com rate limit, e falhas de geração do JSON Schema são apresentadas como erro de configuração do provider (#111).
- A normalização automática de JSON reconhece tanto colunas `object` do pandas 2 quanto o dtype `str` do pandas 3 (#111).
- `call_langchain` em `llm.py` agora aceita `usage_metadata` tanto como dict quanto como objeto, alinhando com o tratamento já feito em `agent._extract_usage`. Antes, providers que devolvessem `usage_metadata` como objeto causavam `AttributeError` (#107).

### Alterado

- O CI valida Python 3.10 e 3.13 nos ambientes base e Codex, inicia o runtime empacotado e exercita o lifecycle e a exclusão multiprocesso da autenticação no Windows, além de fazer build da documentação em pull requests; o extra declara o runtime pré-release como limite inferior para permitir resolução limpa pelo `uv`, enquanto o SDK conserva o pin exato (#111).
- A telemetria usa as mesmas quatro colunas de tokens em todos os providers, incluindo `_cached_input_tokens`, mesmo quando a métrica permanece nula ou zero (#111).
- Leitura de `usage_metadata` extraída para helper `_parse_usage_metadata` em `llm.py` e reaproveitada por `agent._extract_usage`, eliminando divergência futura entre os dois caminhos (#107).

## [0.7.1] - 2026-05-01
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@ DataFrameIt processa textos em DataFrames usando Modelos de Linguagem (LLMs) e e
pip install dataframeit[google] # Google Gemini (recomendado)
pip install dataframeit[openai] # OpenAI
pip install dataframeit[anthropic] # Anthropic Claude
pip install dataframeit[codex] # Codex SDK oficial (experimental)
```

Configure sua API key:
Configure a autenticação do provider:

```bash
export GOOGLE_API_KEY="sua-chave" # ou OPENAI_API_KEY, ANTHROPIC_API_KEY
```

O provider experimental `codex` é opcional, não faz parte do extra `all`, usa o runtime empacotado e requer autenticação local em arquivo. Consulte a [documentação de instalação](https://bdcdo.github.io/dataframeit/getting-started/installation/) para configurar o extra e as credenciais.

## Exemplo Rápido

```python
Expand Down Expand Up @@ -61,7 +64,7 @@ print(resultado)

## Funcionalidades

- **Múltiplos providers**: Google Gemini, OpenAI, Anthropic, Cohere, Mistral via LangChain
- **Múltiplos providers**: Google Gemini, OpenAI, Anthropic, Cohere e Mistral via LangChain, além de Claude Code e Codex por seus SDKs
- **Múltiplos tipos de entrada**: DataFrame, Series, list, dict
- **Saída estruturada**: Validação automática com Pydantic
- **Resiliência**: Retry automático com backoff exponencial
Expand Down
4 changes: 1 addition & 3 deletions docs/en/getting-started/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,12 @@ For each DataFrame row:

## Automatic Columns

DataFrameIt automatically adds control columns:
DataFrameIt automatically adds the status columns. When `track_tokens=True`, it also adds usage columns; see the [LLM Reference](../reference/llm-reference.md#automatically-added-columns) for the complete table and the semantics of cached input and reasoning.

| Column | Description |
|--------|-------------|
| `_dataframeit_status` | Status: `'processed'`, `'error'`, or `None` |
| `_error_details` | Error details (when status is `'error'`) |
| `_input_tokens` | Input tokens (with `track_tokens=True`) |
| `_output_tokens` | Output tokens (with `track_tokens=True`) |

## Next Steps

Expand Down
28 changes: 25 additions & 3 deletions docs/en/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Basic Installation

DataFrameIt uses [LangChain](https://langchain.com/) to support multiple LLM providers. Choose the provider you want to use:
DataFrameIt integrates multiple LLM providers through LangChain or official SDKs for local tools. Choose the provider you want to use:

=== "Google Gemini (Recommended)"

Expand All @@ -28,12 +28,24 @@ DataFrameIt uses [LangChain](https://langchain.com/) to support multiple LLM pro

Models: `claude-sonnet-4-5`, `claude-opus-4-6`, `claude-haiku-4-5`

=== "Codex (Experimental)"

```bash
pip install dataframeit[codex]
# or
uv add "dataframeit[codex]"
```

This extra pins the official Python SDK and its compatible runtime. DataFrameIt always uses that bundled runtime; an external `codex` command does not participate in execution. The provider remains experimental because the pinned SDK and runtime versions are still prereleases.

=== "All Providers"

```bash
pip install dataframeit[all]
```

While experimental, the Codex provider is not included in `all`; install `dataframeit[codex]` separately.

## With Polars (Optional)

If you use Polars instead of Pandas:
Expand All @@ -50,9 +62,9 @@ For `.xlsx` checkpoints or reading Excel files via `read_df()`:
pip install dataframeit[excel]
```

## API Keys Configuration
## Authentication Configuration

Set the environment variable for your provider:
Configure the credentials for your provider:

=== "Google Gemini"

Expand All @@ -78,6 +90,16 @@ Set the environment variable for your provider:

Get your key at: [Anthropic Console](https://console.anthropic.com/)

=== "Codex"

If `auth.json` does not exist yet, install the [official Codex CLI](https://learn.chatgpt.com/docs/codex/cli) and authenticate once:

```bash
codex --config cli_auth_credentials_store='"file"' login
```

The external CLI is used only to create `auth.json`; the explicit option prevents the credentials from being stored only in the system keyring. This is the only file from Codex's persistent state linked into the ephemeral `CODEX_HOME`; the app server still inherits the process environment variables. DataFrameIt executes the runtime pinned by the extra; do not pass `api_key` to `dataframeit()` for this provider.

## Verifying Installation

```python
Expand Down
5 changes: 1 addition & 4 deletions docs/en/guides/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,7 @@ result = dataframeit(

### Added Columns

| Column | Description |
|--------|-------------|
| `_input_tokens` | Input tokens per row |
| `_output_tokens` | Output tokens per row |
The result records usage per row; the [LLM Reference](../reference/llm-reference.md#automatically-added-columns) defines each column and how to interpret null or zero values in `_cached_input_tokens`.

### Calculating Costs

Expand Down
24 changes: 23 additions & 1 deletion docs/en/guides/providers.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
# Providers

Configure different LLM providers via LangChain.
Configure different LLM providers through LangChain or official SDKs for local tools.

## Supported Providers

| Provider | Identifier | Current Models (2025) |
|----------|------------|----------------------|
| Google | `google_genai` | gemini-3-flash-preview, gemini-2.5-flash, gemini-2.5-pro |
| OpenAI | `openai` | gpt-5.2, gpt-5.2-mini, gpt-4.1 |
| OpenAI Codex (experimental) | `codex` | Models supported by the bundled runtime |
| Anthropic | `anthropic` | claude-sonnet-4-5, claude-opus-4-6, claude-haiku-4-5 |
| Groq | `groq` | llama-3.3-70b-versatile, llama-3.1-8b-instant, openai/gpt-oss-120b, openai/gpt-oss-20b, groq/compound |
| Cohere | `cohere` | command-r, command-r-plus |
Expand Down Expand Up @@ -88,6 +89,27 @@ result = dataframeit(
| `gpt-5.2` | Maximum quality | High |
| `gpt-4.1` | Coding, precise instructions | Medium |

## OpenAI Codex (Experimental)

The `codex` provider uses the [official Python SDK](https://github.com/openai/codex/tree/main/sdk/python) and remains experimental. For extra installation, runtime selection, and local file-backed authentication, see [Installation](../getting-started/installation.md).

```python
result = dataframeit(
df,
Model,
PROMPT,
text_column='text',
provider='codex',
model='gpt-5.4',
model_kwargs={'effort': 'medium'},
parallel_requests=3,
)
```

For this provider, `model_kwargs` accepts only `effort`. `use_search=True` is not supported. The Pydantic model must have fields at the root and use the [JSON Schema subset accepted by Structured Outputs](https://developers.openai.com/api/docs/guides/structured-outputs#supported-schemas); `RootModel`, `Any`, dynamic-key `dict` fields, fixed tuples, and sets are rejected during preflight. Authentication configured during installation comes from `auth.json`, so do not pass `api_key` to `dataframeit()`.

DataFrameIt keeps one `codex app-server` per DataFrame run and opens one ephemeral thread per row. Every run uses isolated `CODEX_HOME` and workspace directories; `auth.json` is the only file from Codex's persistent state linked into the runtime, which still inherits the process environment variables. While one run uses the credential, another DataFrameIt run with the same `auth.json` fails before starting the runtime; this prevents concurrent refresh without affecting `parallel_requests` within the active run. This lock coordinates DataFrameIt instances only, so do not run the Codex CLI with the same credential until processing finishes. Web search, shell access, and MCP servers are disabled; approvals are denied, and the read-only sandbox blocks writes. The runtime may still present internal utilities such as `apply_patch` without granting permission to change files.

## Anthropic Claude

```bash
Expand Down
14 changes: 7 additions & 7 deletions docs/en/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,17 @@ def dataframeit(
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `resume` | bool | `True` | Continue from where it stopped (skips processed rows) |
| `reprocess_columns` | list | `None` | List of columns to force reprocessing |
| `reprocess_columns` | list | `None` | Fields to force reprocessing; when resuming with a changed model, it must cover fields incompatible with previously processed rows |
| `status_column` | str | `None` | Custom name for status column |

#### Model

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `model` | str | `'gemini-3-flash-preview'` | LLM model name |
| `provider` | str | `'google_genai'` | LangChain provider |
| `api_key` | str | `None` | API key (uses env var if None) |
| `model_kwargs` | dict | `None` | Extra parameters (temperature, etc.) |
| `provider` | str | `'google_genai'` | Provider identifier; `codex` uses the official SDK instead of LangChain |
| `api_key` | str | `None` | API key (uses env var if None); not accepted with `provider='codex'` |
| `model_kwargs` | dict | `None` | Extra parameters; with `codex`, only `effort` is accepted |

#### Resilience

Expand All @@ -85,7 +85,7 @@ def dataframeit(

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `use_search` | bool | `False` | Enable web search via Tavily |
| `use_search` | bool | `False` | Enable web search via Tavily; not supported with `provider='codex'` |
| `search_per_field` | bool | `False` | Execute separate search per field |
| `max_results` | int | `5` | Results per search (1-20) |
| `search_depth` | str | `'basic'` | `'basic'` or `'advanced'` |
Expand All @@ -105,12 +105,12 @@ Returns data in the same format as input with extracted columns added.

### Added Columns

The status columns below exist independently of token tracking. When `track_tokens=True`, see the [LLM Reference](llm-reference.md#automatically-added-columns) for the usage columns and their semantics.

| Column | Description |
|--------|-------------|
| `_dataframeit_status` | `'processed'`, `'error'`, or `None` |
| `_error_details` | Error details (when applicable) |
| `_input_tokens` | Input tokens (if `track_tokens=True`) |
| `_output_tokens` | Output tokens (if `track_tokens=True`) |

### Examples

Expand Down
Loading