Skip to content
Merged
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
3 changes: 2 additions & 1 deletion .agents/skills/batchor-dev/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ Use this skill for normal contributor work in this repository.
3. Load only the design docs that match the task:
- `docs/design_docs/ARCHITECTURE.md` for package layout and runtime boundaries
- `docs/design_docs/OPENAI_BATCHING.md` for provider-specific batching behavior
- `docs/design_docs/ANTHROPIC_BATCHING.md` for Anthropic Message Batches behavior
- `docs/design_docs/STORAGE_AND_RUNS.md` for durable state, run lifecycle, and retention
- `docs/smoke-test.md` for the full validation matrix

## Repo map

- `src/batchor/runtime/`: orchestration, run handles, validation, retry, token budgeting
- `src/batchor/providers/`: provider interfaces and OpenAI Batch implementation
- `src/batchor/providers/`: provider interfaces and OpenAI, Anthropic, and Gemini implementations
- `src/batchor/storage/`: SQLite, Postgres, and in-memory durability backends
- `src/batchor/sources/`: file-backed checkpointable item sources
- `src/batchor/artifacts/`: durable request/output artifact handling
Expand Down
40 changes: 36 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- library-first run controls
- a small operator CLI for CSV and JSONL jobs

It is intentionally narrow today: OpenAI is the CLI default, Gemini is opt-in through `batchor[gemini]`, SQLite is the CLI durability backend, and the Python API exposes the broadest configuration surface.
It is intentionally narrow today: OpenAI is the CLI default, Anthropic and Gemini are opt-in through provider extras, SQLite is the CLI durability backend, and the Python API exposes the broadest configuration surface.

## What problem it solves

Expand All @@ -37,6 +37,7 @@ Most OpenAI Batch examples stop at "upload a JSONL file and poll until it finish
Built-in implementations:

- `OpenAIProviderConfig` + `OpenAIBatchProvider`
- `AnthropicProviderConfig` + `AnthropicBatchProvider` for Claude Message Batches
- `GeminiProviderConfig` + `GeminiBatchProvider` for text-only Gemini Batch jobs
- `SQLiteStorage`
- `PostgresStorage` as an opt-in durable control-plane backend
Expand All @@ -53,7 +54,7 @@ Important constraints:
- the CLI supports file-backed inputs only
- users still own selecting and ordering input files or partitions
- the built-in CLI uses SQLite durability only
- the CLI supports OpenAI plus Gemini Developer API and Vertex AI text jobs
- the CLI supports OpenAI, Anthropic, Gemini Developer API, and Vertex AI text jobs
- Gemini support is text-only for now and does not build multimodal requests
- structured-output rehydration requires an importable module-level Pydantic model
- raw output artifacts are retained by default and must be exported before raw pruning
Expand Down Expand Up @@ -102,6 +103,7 @@ graph LR

subgraph providers["providers/"]
OpenAI["OpenAIBatchProvider"]
Anthropic["AnthropicBatchProvider"]
Gemini["GeminiBatchProvider"]
end

Expand All @@ -123,6 +125,7 @@ graph LR
BatchRunner --> Run
BatchRunner --> Executor
BatchRunner --> OpenAI
BatchRunner --> Anthropic
BatchRunner --> Gemini
BatchRunner --> SQLite
BatchRunner --> LocalFS
Expand Down Expand Up @@ -165,6 +168,12 @@ For Gemini Batch support, install the optional extra:
pip install "batchor[gemini]"
```

For Anthropic Message Batches support:

```bash
pip install "batchor[anthropic]"
```

## Agent setup

Batchor keeps contributor tooling separate from the tools intended for researchers and downstream projects:
Expand Down Expand Up @@ -195,8 +204,8 @@ Supported Python versions:

For Python API usage, auth resolution is:

1. explicit provider config credentials such as `OpenAIProviderConfig(api_key=...)` or `GeminiProviderConfig(api_key=...)`
2. ambient provider environment variables, currently `OPENAI_API_KEY` or `GEMINI_API_KEY`
1. explicit provider config credentials such as `OpenAIProviderConfig(api_key=...)`, `AnthropicProviderConfig(api_key=...)`, or `GeminiProviderConfig(api_key=...)`
2. ambient provider environment variables: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `GEMINI_API_KEY`
3. Vertex AI Application Default Credentials when `GeminiProviderConfig(vertexai=True, ...)` or `GOOGLE_GENAI_USE_VERTEXAI=true` is used

The Python library does not auto-load `.env`.
Expand Down Expand Up @@ -226,6 +235,29 @@ run = runner.run_and_wait(
print(run.results()[0].output_text)
```

### Anthropic text job

```python
from batchor import AnthropicProviderConfig, BatchItem, BatchJob, BatchRunner, PromptParts


runner = BatchRunner(storage="memory")
run = runner.run_and_wait(
BatchJob(
items=[BatchItem(item_id="row1", payload="Summarize this text")],
build_prompt=lambda item: PromptParts(prompt=item.payload),
provider_config=AnthropicProviderConfig(
model="claude-sonnet-4-5",
max_tokens=1024,
),
)
)

print(run.results()[0].output_text)
```

Anthropic support maps Batchor attempt identifiers deterministically to Claude-safe `custom_id` values and supports system prompts, `message_params`, and structured outputs through `output_config.format`.

### Gemini text job

```python
Expand Down
33 changes: 33 additions & 0 deletions docs/design_docs/ANTHROPIC_BATCHING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Anthropic Batching

The built-in Anthropic provider targets the Claude Message Batches API.

## Request mapping

Each Batchor item attempt becomes one Anthropic batch request:

- Batchor's durable correlation identifier is deterministically hashed into Anthropic's 64-character-safe `custom_id` alphabet
- `PromptParts.prompt` becomes one user message
- `PromptParts.system_prompt` becomes the top-level `system` parameter
- `model` and `max_tokens` come from `AnthropicProviderConfig`
- `message_params` supplies optional Messages API parameters
- structured output schemas use `output_config.format`

Batchor rejects provider-owned fields in `message_params` so replayed requests cannot silently change model, token limit, messages, system prompt, or streaming behavior.

## Submission and lifecycle

Anthropic accepts request objects directly rather than an uploaded JSONL file. The provider therefore stages Batchor's durable request artifact in memory only for the upload/create boundary, then calls `messages.batches.create(requests=...)`.

Anthropic `in_progress` maps to Batchor's active status and `ended` maps to `completed`. Once ended, the provider streams `messages.batches.results(...)` into Batchor's raw output artifact. Result order is not assumed; correlation always uses `custom_id`.

The four Anthropic result types map as follows:

- `succeeded`: Batchor success
- `errored`, `canceled`, and `expired`: Batchor item error, subject to the configured retry policy

## Limits and retention

Anthropic currently limits a Message Batch to 100,000 requests or 256 MB. Batchor's default chunk limits are lower than both limits. Claude batch results remain available from Anthropic for 29 days; Batchor downloads and retains them according to its artifact policy, so durable runs do not depend on that remote retention window after ingestion.

Message Batches are not eligible for Anthropic Zero Data Retention. Users should account for Anthropic's batch retention policy when selecting workloads.
7 changes: 5 additions & 2 deletions docs/design_docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ graph TB
subgraph providers["providers/"]
BatchProvider["BatchProvider (ABC)"]
OpenAIProvider["OpenAIBatchProvider"]
AnthropicProvider["AnthropicBatchProvider"]
GeminiProvider["GeminiBatchProvider"]
ProviderRegistry
end
Expand Down Expand Up @@ -95,6 +96,7 @@ graph TB
MemoryStateStore -.->|implements| StateStore
BatchRunner -->|submits/polls| BatchProvider
OpenAIProvider -.->|implements| BatchProvider
AnthropicProvider -.->|implements| BatchProvider
GeminiProvider -.->|implements| BatchProvider
BatchRunner -->|stores artifacts| ArtifactStore
LocalArtifactStore -.->|implements| ArtifactStore
Expand Down Expand Up @@ -126,7 +128,7 @@ one logical source, while callers remain responsible for selecting and ordering
the child sources up front.

Provider adaptation is intentionally concentrated behind `BatchProvider`.
The runtime stores one durable internal custom identifier per item attempt, while each provider maps that identifier to its own request shape. OpenAI uses `custom_id`; the Gemini Developer API uses `key`; Vertex AI uses a request label that is returned with the original request in GCS output.
The runtime stores one durable internal custom identifier per item attempt, while each provider maps that identifier to its own request shape. OpenAI and Anthropic use `custom_id`; the Gemini Developer API uses `key`; Vertex AI uses a request label that is returned with the original request in GCS output.
Provider hooks also own response-text extraction so structured-output parsing can stay generic across provider payload shapes.

## Main user-facing flow
Expand Down Expand Up @@ -311,6 +313,7 @@ Owns provider-facing abstractions and implementations:
- base provider contract
- provider registry
- OpenAI Batch implementation
- Anthropic Message Batches implementation

The provider layer is responsible for:

Expand Down Expand Up @@ -436,7 +439,7 @@ That split gives `batchor`:
## Current invariants

1. Public execution is run-oriented: `start()`, `get_run()`, `run_and_wait()`.
2. OpenAI Batch and text-only Gemini Batch are built-in Python and CLI providers; OpenAI remains the CLI default.
2. OpenAI Batch, Anthropic Message Batches, and text-only Gemini Batch are built-in Python and CLI providers; OpenAI remains the CLI default.
3. SQLite is the default durable backend.
4. Postgres is an opt-in durable backend for shared control-plane state.
5. Structured outputs require a module-level Pydantic v2 model for rehydration.
Expand Down
4 changes: 2 additions & 2 deletions docs/design_docs/OPENAI_BATCHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

This document describes the OpenAI-specific behavior inside `batchor`.

OpenAI remains the default and most feature-complete provider path. Gemini has its own design note in [`GEMINI_BATCHING.md`](GEMINI_BATCHING.md), while this page focuses only on OpenAI Batch semantics.
OpenAI remains the default and most feature-complete provider path. Anthropic and Gemini have their own design notes in [`ANTHROPIC_BATCHING.md`](ANTHROPIC_BATCHING.md) and [`GEMINI_BATCHING.md`](GEMINI_BATCHING.md), while this page focuses only on OpenAI Batch semantics.

## Current behavior

The Python API and CLI both support OpenAI. The CLI is OpenAI-only today.
The Python API and CLI both support OpenAI, which remains the CLI default.

## Request construction

Expand Down
8 changes: 2 additions & 6 deletions docs/design_docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ This file tracks important work that should be explicit in the extracted reposit

## Next Practical Steps

- add Postgres storage backend
- extend resumable ingestion beyond the built-in CSV/JSONL sources
- add automated retention windows on top of the explicit export/prune lifecycle
- add more input adapters beyond CSV and JSONL
- expose non-OpenAI providers through CLI workflows once provider-specific auth and flags are stable
- add CLI structured-output workflows if the importability story can stay durable and predictable

## Longer-Term Ideas

- additional provider coverage beyond OpenAI and text-only Gemini
- artifact store abstraction
- additional provider coverage beyond OpenAI, Anthropic, and text-only Gemini
- remote/shared artifact store implementations beyond the local filesystem abstraction
- partial-result streaming APIs
- richer CLI or operator workflow beyond the current file-backed text-job surface

Expand Down
2 changes: 2 additions & 0 deletions docs/doc-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This page explains what each document is for so readers do not have to guess whi
| `design_docs/BOUNDARY_AND_PHILOSOPHY.md` | Ownership boundary between `batchor`, storage/artifacts, and user pipelines. |
| `design_docs/ARCHITECTURE.md` | Canonical runtime diagrams, package structure, main flows, and extension seams. |
| `design_docs/OPENAI_BATCHING.md` | OpenAI request construction, token budgeting, splitting, and batch polling behavior. |
| `design_docs/ANTHROPIC_BATCHING.md` | Anthropic Message Batches request construction, polling, result parsing, limits, and retention. |
| `design_docs/GEMINI_BATCHING.md` | Gemini text-only request construction, batch polling, response parsing, and current limits. |
| `design_docs/STORAGE_AND_RUNS.md` | Durable `Run` lifecycle, rehydration, checkpoints, control state, artifact retention, and operator semantics. |
| `design_docs/STORAGE_MIGRATIONS.md` | SQLite schema-versioning and migration guidance. |
Expand All @@ -40,3 +41,4 @@ This page explains what each document is for so readers do not have to guess whi
- Incremental terminal-result reads/exports are documented in the Python API and storage docs.
- Raw output/error artifact retention is now configurable per run through `ArtifactPolicy`.
- Gemini text-only Batch support is available through the Python API and default provider registry.
- Anthropic Message Batches support is available through the Python API, CLI, and default provider registry.
21 changes: 21 additions & 0 deletions docs/getting-started/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ pip install "batchor[gemini]"
echo "GEMINI_API_KEY=..." > .env
```

For Anthropic:

```bash
pip install "batchor[anthropic]"
echo "ANTHROPIC_API_KEY=..." > .env
```

## Start a run from JSONL

```bash
Expand All @@ -66,6 +73,20 @@ Use `--prompt-template` when the prompt should be derived from several fields.

Exactly one of `--prompt-field` or `--prompt-template` is required.

## Start an Anthropic run

```bash
batchor start \
--input input/items.jsonl \
--id-field id \
--prompt-field text \
--provider anthropic \
--model claude-sonnet-4-5 \
--anthropic-max-tokens 1024
```

Use `--anthropic-message-params` for an additional JSON object such as `'{"temperature":0.2}'`.

## Start a Gemini Developer API run

```bash
Expand Down
14 changes: 13 additions & 1 deletion docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,20 @@ pip install "batchor[gemini]"

Gemini support is text-only and is available through both the Python API and CLI.

Anthropic support uses the optional Anthropic SDK dependency:

```bash
pip install "batchor[anthropic]"
```

## What gets installed

The package includes:

- the Python library
- the `batchor` CLI
- the built-in OpenAI provider integration
- the built-in Anthropic provider integration when `batchor[anthropic]` is installed
- the built-in Gemini provider integration when `batchor[gemini]` is installed
- SQLite and Postgres storage implementations

Expand Down Expand Up @@ -63,11 +70,16 @@ For Gemini Developer API usage, authentication resolution is:
1. `GeminiProviderConfig(api_key=...)`
2. `GEMINI_API_KEY`

For Anthropic usage, authentication resolution is:

1. `AnthropicProviderConfig(api_key=...)`
2. `ANTHROPIC_API_KEY`

Vertex AI uses Application Default Credentials and resolves project/location from explicit `GeminiProviderConfig` fields or `GOOGLE_CLOUD_PROJECT` and `GOOGLE_CLOUD_LOCATION`. Vertex batches also require a writable `gs://` staging prefix.

The Python library does not auto-load `.env`.

The CLI loads a local `.env` as a convenience for operator usage. It resolves `OPENAI_API_KEY` for OpenAI, `GEMINI_API_KEY` for the Gemini Developer API, and the documented Google Cloud environment variables for Vertex AI. Rehydrated `status`, `wait`, and result operations load the same `.env` before reconstructing a provider.
The CLI loads a local `.env` as a convenience for operator usage. It resolves `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, and the documented Google Cloud environment variables for Vertex AI. Rehydrated `status`, `wait`, and result operations load the same `.env` before reconstructing a provider.

## Storage defaults

Expand Down
26 changes: 26 additions & 0 deletions docs/getting-started/python-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ print(run.results()[0].output_text)

Use `storage="memory"` only for tests or short-lived local experiments. For durable runs, use the default SQLite storage or an explicit backend.

## Anthropic text job

Install `batchor[anthropic]`, then use the same runner lifecycle with an Anthropic provider config:

```python
from batchor import AnthropicProviderConfig, BatchItem, BatchJob, BatchRunner, PromptParts


runner = BatchRunner(storage="memory")
run = runner.run_and_wait(
BatchJob(
items=[BatchItem(item_id="row1", payload="Summarize this text")],
build_prompt=lambda item: PromptParts(prompt=item.payload),
provider_config=AnthropicProviderConfig(
model="claude-sonnet-4-5",
max_tokens=1024,
),
)
)

print(run.results()[0].output_text)
```

If `api_key` is omitted, the provider resolves `ANTHROPIC_API_KEY`. Extra Messages API parameters such as `temperature` can be supplied through `message_params`; Batchor reserves the fields it constructs itself.

## Gemini text job

Gemini Batch support is available through the Python API after installing `batchor[gemini]`.
Expand Down Expand Up @@ -131,6 +156,7 @@ Notes:
- `output` is the parsed Pydantic object
- `output_text` preserves the raw text that was parsed
- with `GeminiProviderConfig`, the same `structured_output=` argument is sent through Gemini `generation_config.response_json_schema`
- with `AnthropicProviderConfig`, it is sent through Anthropic `output_config.format`

## Durable run lifecycle

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ If that is the mental model you were missing from the generated docs, start with

## Current surface

- Built-in providers: OpenAI Batch, plus text-only Gemini Batch for Python API usage
- Built-in providers: OpenAI Batch, Anthropic Message Batches, and text-only Gemini Batch through Python and CLI workflows
- Durable storage: SQLite by default, Postgres as an opt-in control-plane backend
- Ephemeral storage: in-memory state store
- Artifact backend: local filesystem via `LocalArtifactStore`
Expand Down
2 changes: 1 addition & 1 deletion docs/policies/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Before submitting changes:
Please keep changes aligned with the documented package boundary:

- durable batch execution
- OpenAI Batch provider support
- OpenAI, Anthropic, and Gemini Batch provider support
- SQLite-backed local durability by default

Out-of-scope proposals are still useful, but should usually start as an issue discussing fit before implementation.
10 changes: 10 additions & 0 deletions docs/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Most users only need a small subset of the package:
- `BatchRunner`: start, resume, and run orchestration
- `Run`: refresh, wait, inspect, export, and prune
- `OpenAIProviderConfig`: built-in provider config
- `AnthropicProviderConfig`: built-in Anthropic Message Batches config
- `GeminiProviderConfig`: built-in Gemini provider config for text batch jobs; the common fields are also exposed by the CLI
- `SQLiteStorage` and `PostgresStorage`: durable control-plane backends
- `CompositeItemSource`, `CsvItemSource`, `JsonlItemSource`, and `ParquetItemSource`: deterministic item streaming
Expand Down Expand Up @@ -73,6 +74,15 @@ This is the built-in Gemini Batch implementation. Most consumers only need `Gemi
show_root_heading: true
heading_level: 2

## Anthropic provider

Install `batchor[anthropic]` for the SDK dependency. Most consumers only need `AnthropicProviderConfig`.

::: batchor.providers.anthropic
options:
show_root_heading: true
heading_level: 2

## Sources

These sources support durable resume through source fingerprints and checkpoints.
Expand Down
Loading
Loading