batchwizard 0.2.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- batchwizard-0.5.0/.github/workflows/ci.yml +52 -0
- batchwizard-0.5.0/.github/workflows/publish.yml +37 -0
- batchwizard-0.5.0/.gitignore +162 -0
- batchwizard-0.5.0/PKG-INFO +205 -0
- batchwizard-0.5.0/README.md +175 -0
- batchwizard-0.5.0/docs/anthropic.md +78 -0
- batchwizard-0.5.0/docs/job-lifecycle.md +121 -0
- batchwizard-0.5.0/pyproject.toml +74 -0
- batchwizard-0.5.0/src/batchwizard/__init__.py +24 -0
- batchwizard-0.5.0/src/batchwizard/cli.py +648 -0
- batchwizard-0.5.0/src/batchwizard/config.py +90 -0
- batchwizard-0.5.0/src/batchwizard/models.py +155 -0
- batchwizard-0.5.0/src/batchwizard/processor.py +275 -0
- batchwizard-0.5.0/src/batchwizard/providers/__init__.py +33 -0
- batchwizard-0.5.0/src/batchwizard/providers/anthropic.py +331 -0
- batchwizard-0.5.0/src/batchwizard/providers/base.py +50 -0
- batchwizard-0.5.0/src/batchwizard/providers/openai.py +196 -0
- batchwizard-0.5.0/src/batchwizard/store.py +310 -0
- batchwizard-0.5.0/src/batchwizard/ui.py +198 -0
- {batchwizard-0.2.0 → batchwizard-0.5.0}/src/batchwizard/utils.py +19 -5
- batchwizard-0.5.0/tests/conftest.py +25 -0
- batchwizard-0.5.0/tests/test_anthropic_provider.py +427 -0
- batchwizard-0.5.0/tests/test_anthropic_sdk_contract.py +134 -0
- batchwizard-0.5.0/tests/test_cli.py +444 -0
- batchwizard-0.5.0/tests/test_config.py +40 -0
- batchwizard-0.5.0/tests/test_openai_provider.py +341 -0
- batchwizard-0.5.0/tests/test_openai_sdk_contract.py +112 -0
- batchwizard-0.5.0/tests/test_orchestrator.py +453 -0
- batchwizard-0.5.0/tests/test_store.py +201 -0
- batchwizard-0.5.0/tests/test_ui.py +50 -0
- batchwizard-0.5.0/uv.lock +1252 -0
- batchwizard-0.2.0/PKG-INFO +0 -206
- batchwizard-0.2.0/README.md +0 -179
- batchwizard-0.2.0/pyproject.toml +0 -37
- batchwizard-0.2.0/src/batchwizard/__init__.py +0 -6
- batchwizard-0.2.0/src/batchwizard/cli.py +0 -192
- batchwizard-0.2.0/src/batchwizard/config.py +0 -48
- batchwizard-0.2.0/src/batchwizard/models.py +0 -18
- batchwizard-0.2.0/src/batchwizard/processor.py +0 -153
- batchwizard-0.2.0/src/batchwizard/ui.py +0 -258
- {batchwizard-0.2.0 → batchwizard-0.5.0}/LICENSE +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
lint:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v7.0.0
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0
|
|
18
|
+
persist-credentials: false
|
|
19
|
+
- uses: astral-sh/setup-uv@v8.3.2
|
|
20
|
+
- run: uv sync --frozen --group dev
|
|
21
|
+
- run: uv run --frozen ruff check .
|
|
22
|
+
- run: uv run --frozen ruff format --check .
|
|
23
|
+
|
|
24
|
+
test:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
strategy:
|
|
27
|
+
matrix:
|
|
28
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
29
|
+
steps:
|
|
30
|
+
- uses: actions/checkout@v7.0.0
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 0
|
|
33
|
+
persist-credentials: false
|
|
34
|
+
- uses: astral-sh/setup-uv@v8.3.2
|
|
35
|
+
with:
|
|
36
|
+
python-version: ${{ matrix.python-version }}
|
|
37
|
+
- run: uv sync --frozen --group dev
|
|
38
|
+
- run: uv run --frozen pytest tests/
|
|
39
|
+
|
|
40
|
+
build:
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v7.0.0
|
|
44
|
+
with:
|
|
45
|
+
fetch-depth: 0
|
|
46
|
+
persist-credentials: false
|
|
47
|
+
- uses: astral-sh/setup-uv@v8.3.2
|
|
48
|
+
- run: uv build
|
|
49
|
+
- uses: actions/upload-artifact@v7.0.1
|
|
50
|
+
with:
|
|
51
|
+
name: dist
|
|
52
|
+
path: dist/
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v7.0.0
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
persist-credentials: false
|
|
18
|
+
- uses: astral-sh/setup-uv@v8.3.2
|
|
19
|
+
- run: uv build
|
|
20
|
+
- uses: actions/upload-artifact@v7.0.1
|
|
21
|
+
with:
|
|
22
|
+
name: dist
|
|
23
|
+
path: dist/
|
|
24
|
+
|
|
25
|
+
publish:
|
|
26
|
+
needs: build
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
environment: pypi
|
|
29
|
+
permissions:
|
|
30
|
+
# Required for PyPI Trusted Publishing (OIDC) — no API token needed
|
|
31
|
+
id-token: write
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/download-artifact@v8.0.1
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# poetry
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
102
|
+
#poetry.lock
|
|
103
|
+
|
|
104
|
+
# pdm
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
106
|
+
#pdm.lock
|
|
107
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
108
|
+
# in version control.
|
|
109
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
110
|
+
.pdm.toml
|
|
111
|
+
.pdm-python
|
|
112
|
+
.pdm-build/
|
|
113
|
+
|
|
114
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
115
|
+
__pypackages__/
|
|
116
|
+
|
|
117
|
+
# Celery stuff
|
|
118
|
+
celerybeat-schedule
|
|
119
|
+
celerybeat.pid
|
|
120
|
+
|
|
121
|
+
# SageMath parsed files
|
|
122
|
+
*.sage.py
|
|
123
|
+
|
|
124
|
+
# Environments
|
|
125
|
+
.env
|
|
126
|
+
.venv
|
|
127
|
+
env/
|
|
128
|
+
venv/
|
|
129
|
+
ENV/
|
|
130
|
+
env.bak/
|
|
131
|
+
venv.bak/
|
|
132
|
+
|
|
133
|
+
# Spyder project settings
|
|
134
|
+
.spyderproject
|
|
135
|
+
.spyproject
|
|
136
|
+
|
|
137
|
+
# Rope project settings
|
|
138
|
+
.ropeproject
|
|
139
|
+
|
|
140
|
+
# mkdocs documentation
|
|
141
|
+
/site
|
|
142
|
+
|
|
143
|
+
# mypy
|
|
144
|
+
.mypy_cache/
|
|
145
|
+
.dmypy.json
|
|
146
|
+
dmypy.json
|
|
147
|
+
|
|
148
|
+
# Pyre type checker
|
|
149
|
+
.pyre/
|
|
150
|
+
|
|
151
|
+
# pytype static type analyzer
|
|
152
|
+
.pytype/
|
|
153
|
+
|
|
154
|
+
# Cython debug symbols
|
|
155
|
+
cython_debug/
|
|
156
|
+
|
|
157
|
+
# PyCharm
|
|
158
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
159
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
160
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
161
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
162
|
+
#.idea/
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: batchwizard
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Durable batch orchestration across OpenAI and Anthropic
|
|
5
|
+
Project-URL: Homepage, https://github.com/cmakafui/batchwizard
|
|
6
|
+
Project-URL: Repository, https://github.com/cmakafui/batchwizard
|
|
7
|
+
Project-URL: Issues, https://github.com/cmakafui/batchwizard/issues
|
|
8
|
+
Author: Carl Kugblenu
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: anthropic,async,batch,cli,openai
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: anthropic[aiohttp]<1,>=0.117
|
|
22
|
+
Requires-Dist: loguru>=0.7
|
|
23
|
+
Requires-Dist: openai[aiohttp]<3,>=2.46
|
|
24
|
+
Requires-Dist: pydantic-settings>=2.3
|
|
25
|
+
Requires-Dist: pydantic>=2.8
|
|
26
|
+
Requires-Dist: python-dotenv>=1.0
|
|
27
|
+
Requires-Dist: rich>=13.7
|
|
28
|
+
Requires-Dist: typer>=0.12
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# BatchWizard
|
|
32
|
+
|
|
33
|
+
BatchWizard is one durable CLI for OpenAI and Anthropic batch jobs. Submit
|
|
34
|
+
provider-native JSONL, close the terminal, and come back later: a local SQLite
|
|
35
|
+
manifest remembers what is running, what still needs to be downloaded, and what
|
|
36
|
+
needs your attention.
|
|
37
|
+
|
|
38
|
+
It deliberately does not translate prompts between APIs. OpenAI and Anthropic
|
|
39
|
+
have different request formats and capabilities; BatchWizard gives them one
|
|
40
|
+
operational lifecycle without pretending they are the same protocol.
|
|
41
|
+
|
|
42
|
+
## Quickstart
|
|
43
|
+
|
|
44
|
+
Install BatchWizard as an isolated Python 3.11+ tool:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv tool install batchwizard
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Provide one or both standard API-key environment variables:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
export OPENAI_API_KEY="..."
|
|
54
|
+
export ANTHROPIC_API_KEY="..."
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Submit native JSONL to either provider:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
batchwizard submit openai.jsonl --endpoint /v1/responses
|
|
61
|
+
batchwizard submit --provider anthropic anthropic.jsonl
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The submit process can exit once the providers accept the work. One later
|
|
65
|
+
command resumes every actionable job, grouped by provider:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
batchwizard watch --output-directory ./results
|
|
69
|
+
batchwizard status --all
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`watch` is intentionally provider-free. The manifest records which adapter owns
|
|
73
|
+
each batch, so a single invocation can resume a mixture of OpenAI and Anthropic
|
|
74
|
+
jobs. Missing credentials or a temporary download failure for one provider do
|
|
75
|
+
not erase work or prevent other provider groups from advancing.
|
|
76
|
+
|
|
77
|
+
## Input formats
|
|
78
|
+
|
|
79
|
+
BatchWizard accepts each provider's native JSONL rather than maintaining a lossy
|
|
80
|
+
common prompt schema.
|
|
81
|
+
|
|
82
|
+
| | OpenAI | Anthropic |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| Select with | default, or `--provider openai` | `--provider anthropic` |
|
|
85
|
+
| JSONL row | `{"custom_id", "method", "url", "body"}` | `{"custom_id", "params"}` |
|
|
86
|
+
| Model location | `body.model` | `params.model` |
|
|
87
|
+
| Submission | file upload, then Batch creation | requests sent inline to Message Batches |
|
|
88
|
+
| Provider status | Batch `status` | Message Batch `processing_status` |
|
|
89
|
+
| Results | provider output and error files | unordered result stream split by outcome |
|
|
90
|
+
| Recovery after an uncertain submit | automatic intent matching through Batch metadata | manual attachment by batch ID |
|
|
91
|
+
|
|
92
|
+
### OpenAI
|
|
93
|
+
|
|
94
|
+
```jsonl
|
|
95
|
+
{"custom_id":"ticket-1","method":"POST","url":"/v1/responses","body":{"model":"gpt-5.4","input":"Classify this ticket as billing, technical, or other."}}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The endpoint passed to BatchWizard must match the `url` in every row:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
batchwizard submit openai.jsonl --endpoint /v1/responses
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`/v1/chat/completions` is the default. BatchWizard also accepts the Responses,
|
|
105
|
+
Embeddings, Completions, Moderations, Images, and Videos Batch API endpoints.
|
|
106
|
+
|
|
107
|
+
### Anthropic
|
|
108
|
+
|
|
109
|
+
```jsonl
|
|
110
|
+
{"custom_id":"ticket-1","params":{"model":"claude-opus-4-8","max_tokens":256,"messages":[{"role":"user","content":"Classify this ticket as billing, technical, or other."}]}}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
batchwizard submit --provider anthropic anthropic.jsonl
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
BatchWizard validates the batch envelope, `custom_id` syntax and uniqueness,
|
|
118
|
+
batch size, `max_tokens`, and the non-streaming requirement before submission.
|
|
119
|
+
Anthropic remains responsible for validating its evolving Messages parameter
|
|
120
|
+
surface. See [Anthropic Message Batches](docs/anthropic.md) for result routing,
|
|
121
|
+
prompt caching, cancellation, and retention behavior.
|
|
122
|
+
|
|
123
|
+
## Durable jobs and recovery
|
|
124
|
+
|
|
125
|
+
The manifest separates remote execution from local artifact collection. A
|
|
126
|
+
provider can report a batch complete while its result files are still pending
|
|
127
|
+
locally; that row remains actionable until collection succeeds or the provider
|
|
128
|
+
confirms that the artifacts are no longer available.
|
|
129
|
+
|
|
130
|
+
Submission is durable too. BatchWizard writes an intent before making provider
|
|
131
|
+
requests. If a connection fails after the remote service may have accepted the
|
|
132
|
+
batch, it keeps that intent instead of blindly submitting a duplicate:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
batchwizard reconcile
|
|
136
|
+
batchwizard reconcile INTENT
|
|
137
|
+
batchwizard reconcile INTENT --batch-id MSGBATCH_ID
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
OpenAI intents can be matched through Batch metadata. Anthropic does not expose
|
|
141
|
+
equivalent batch metadata, so its uncertain submissions are attached after the
|
|
142
|
+
matching batch is identified with `list-jobs`.
|
|
143
|
+
|
|
144
|
+
The lifecycle and SQLite migrations are documented in
|
|
145
|
+
[Job lifecycle](docs/job-lifecycle.md).
|
|
146
|
+
|
|
147
|
+
## Result files
|
|
148
|
+
|
|
149
|
+
Provider output stays JSONL and is written atomically:
|
|
150
|
+
|
|
151
|
+
- `<batch_id>_results.jsonl` contains successful rows.
|
|
152
|
+
- `<batch_id>_errors.jsonl` contains request-level failures when present.
|
|
153
|
+
|
|
154
|
+
Anthropic result rows can arrive in any order. BatchWizard preserves each raw row
|
|
155
|
+
and routes `succeeded` results to the results file and `errored`, `expired`, or
|
|
156
|
+
`canceled` results to the errors file.
|
|
157
|
+
|
|
158
|
+
## Credentials and configuration
|
|
159
|
+
|
|
160
|
+
Environment variables are the preferred way to supply credentials. Keys can
|
|
161
|
+
also be persisted for convenience:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
batchwizard configure --provider openai --set-key "$OPENAI_API_KEY"
|
|
165
|
+
batchwizard configure --provider anthropic --set-key "$ANTHROPIC_API_KEY"
|
|
166
|
+
batchwizard configure --show --provider openai
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Persisted keys are plaintext JSON. BatchWizard writes the configuration
|
|
170
|
+
atomically with owner-only file permissions, but it does not use the operating
|
|
171
|
+
system keychain in v0.5. Treat that file as a secret; keyring-backed storage is
|
|
172
|
+
deferred to v0.6.
|
|
173
|
+
|
|
174
|
+
## Commands
|
|
175
|
+
|
|
176
|
+
| Command | Purpose |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| `submit` | Submit files and return after provider acceptance. |
|
|
179
|
+
| `watch` | Resume actionable jobs and collect terminal artifacts. |
|
|
180
|
+
| `process` | Submit, watch, and collect in one invocation. |
|
|
181
|
+
| `status` | Inspect the local SQLite manifest. |
|
|
182
|
+
| `reconcile` | Recover a submission with an uncertain provider outcome. |
|
|
183
|
+
| `list-jobs` | List recent jobs directly from one provider. |
|
|
184
|
+
| `cancel` | Request cancellation for a tracked or provider-native batch ID. |
|
|
185
|
+
| `download` | Collect result artifacts for one batch. |
|
|
186
|
+
| `configure` | Store, inspect, or reset local settings. |
|
|
187
|
+
|
|
188
|
+
Use `batchwizard <command> --help` for the exact arguments and options.
|
|
189
|
+
|
|
190
|
+
## Development
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
uv sync --all-groups
|
|
194
|
+
uv run pytest
|
|
195
|
+
uv run ruff format --check .
|
|
196
|
+
uv run ruff check .
|
|
197
|
+
uv build
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The supported runtime matrix is Python 3.11 through 3.14. The lockfile is
|
|
201
|
+
committed; update it intentionally with `uv lock --upgrade-package <package>`.
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# BatchWizard
|
|
2
|
+
|
|
3
|
+
BatchWizard is one durable CLI for OpenAI and Anthropic batch jobs. Submit
|
|
4
|
+
provider-native JSONL, close the terminal, and come back later: a local SQLite
|
|
5
|
+
manifest remembers what is running, what still needs to be downloaded, and what
|
|
6
|
+
needs your attention.
|
|
7
|
+
|
|
8
|
+
It deliberately does not translate prompts between APIs. OpenAI and Anthropic
|
|
9
|
+
have different request formats and capabilities; BatchWizard gives them one
|
|
10
|
+
operational lifecycle without pretending they are the same protocol.
|
|
11
|
+
|
|
12
|
+
## Quickstart
|
|
13
|
+
|
|
14
|
+
Install BatchWizard as an isolated Python 3.11+ tool:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uv tool install batchwizard
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Provide one or both standard API-key environment variables:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
export OPENAI_API_KEY="..."
|
|
24
|
+
export ANTHROPIC_API_KEY="..."
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Submit native JSONL to either provider:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
batchwizard submit openai.jsonl --endpoint /v1/responses
|
|
31
|
+
batchwizard submit --provider anthropic anthropic.jsonl
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The submit process can exit once the providers accept the work. One later
|
|
35
|
+
command resumes every actionable job, grouped by provider:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
batchwizard watch --output-directory ./results
|
|
39
|
+
batchwizard status --all
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`watch` is intentionally provider-free. The manifest records which adapter owns
|
|
43
|
+
each batch, so a single invocation can resume a mixture of OpenAI and Anthropic
|
|
44
|
+
jobs. Missing credentials or a temporary download failure for one provider do
|
|
45
|
+
not erase work or prevent other provider groups from advancing.
|
|
46
|
+
|
|
47
|
+
## Input formats
|
|
48
|
+
|
|
49
|
+
BatchWizard accepts each provider's native JSONL rather than maintaining a lossy
|
|
50
|
+
common prompt schema.
|
|
51
|
+
|
|
52
|
+
| | OpenAI | Anthropic |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| Select with | default, or `--provider openai` | `--provider anthropic` |
|
|
55
|
+
| JSONL row | `{"custom_id", "method", "url", "body"}` | `{"custom_id", "params"}` |
|
|
56
|
+
| Model location | `body.model` | `params.model` |
|
|
57
|
+
| Submission | file upload, then Batch creation | requests sent inline to Message Batches |
|
|
58
|
+
| Provider status | Batch `status` | Message Batch `processing_status` |
|
|
59
|
+
| Results | provider output and error files | unordered result stream split by outcome |
|
|
60
|
+
| Recovery after an uncertain submit | automatic intent matching through Batch metadata | manual attachment by batch ID |
|
|
61
|
+
|
|
62
|
+
### OpenAI
|
|
63
|
+
|
|
64
|
+
```jsonl
|
|
65
|
+
{"custom_id":"ticket-1","method":"POST","url":"/v1/responses","body":{"model":"gpt-5.4","input":"Classify this ticket as billing, technical, or other."}}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The endpoint passed to BatchWizard must match the `url` in every row:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
batchwizard submit openai.jsonl --endpoint /v1/responses
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`/v1/chat/completions` is the default. BatchWizard also accepts the Responses,
|
|
75
|
+
Embeddings, Completions, Moderations, Images, and Videos Batch API endpoints.
|
|
76
|
+
|
|
77
|
+
### Anthropic
|
|
78
|
+
|
|
79
|
+
```jsonl
|
|
80
|
+
{"custom_id":"ticket-1","params":{"model":"claude-opus-4-8","max_tokens":256,"messages":[{"role":"user","content":"Classify this ticket as billing, technical, or other."}]}}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
batchwizard submit --provider anthropic anthropic.jsonl
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
BatchWizard validates the batch envelope, `custom_id` syntax and uniqueness,
|
|
88
|
+
batch size, `max_tokens`, and the non-streaming requirement before submission.
|
|
89
|
+
Anthropic remains responsible for validating its evolving Messages parameter
|
|
90
|
+
surface. See [Anthropic Message Batches](docs/anthropic.md) for result routing,
|
|
91
|
+
prompt caching, cancellation, and retention behavior.
|
|
92
|
+
|
|
93
|
+
## Durable jobs and recovery
|
|
94
|
+
|
|
95
|
+
The manifest separates remote execution from local artifact collection. A
|
|
96
|
+
provider can report a batch complete while its result files are still pending
|
|
97
|
+
locally; that row remains actionable until collection succeeds or the provider
|
|
98
|
+
confirms that the artifacts are no longer available.
|
|
99
|
+
|
|
100
|
+
Submission is durable too. BatchWizard writes an intent before making provider
|
|
101
|
+
requests. If a connection fails after the remote service may have accepted the
|
|
102
|
+
batch, it keeps that intent instead of blindly submitting a duplicate:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
batchwizard reconcile
|
|
106
|
+
batchwizard reconcile INTENT
|
|
107
|
+
batchwizard reconcile INTENT --batch-id MSGBATCH_ID
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
OpenAI intents can be matched through Batch metadata. Anthropic does not expose
|
|
111
|
+
equivalent batch metadata, so its uncertain submissions are attached after the
|
|
112
|
+
matching batch is identified with `list-jobs`.
|
|
113
|
+
|
|
114
|
+
The lifecycle and SQLite migrations are documented in
|
|
115
|
+
[Job lifecycle](docs/job-lifecycle.md).
|
|
116
|
+
|
|
117
|
+
## Result files
|
|
118
|
+
|
|
119
|
+
Provider output stays JSONL and is written atomically:
|
|
120
|
+
|
|
121
|
+
- `<batch_id>_results.jsonl` contains successful rows.
|
|
122
|
+
- `<batch_id>_errors.jsonl` contains request-level failures when present.
|
|
123
|
+
|
|
124
|
+
Anthropic result rows can arrive in any order. BatchWizard preserves each raw row
|
|
125
|
+
and routes `succeeded` results to the results file and `errored`, `expired`, or
|
|
126
|
+
`canceled` results to the errors file.
|
|
127
|
+
|
|
128
|
+
## Credentials and configuration
|
|
129
|
+
|
|
130
|
+
Environment variables are the preferred way to supply credentials. Keys can
|
|
131
|
+
also be persisted for convenience:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
batchwizard configure --provider openai --set-key "$OPENAI_API_KEY"
|
|
135
|
+
batchwizard configure --provider anthropic --set-key "$ANTHROPIC_API_KEY"
|
|
136
|
+
batchwizard configure --show --provider openai
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Persisted keys are plaintext JSON. BatchWizard writes the configuration
|
|
140
|
+
atomically with owner-only file permissions, but it does not use the operating
|
|
141
|
+
system keychain in v0.5. Treat that file as a secret; keyring-backed storage is
|
|
142
|
+
deferred to v0.6.
|
|
143
|
+
|
|
144
|
+
## Commands
|
|
145
|
+
|
|
146
|
+
| Command | Purpose |
|
|
147
|
+
| --- | --- |
|
|
148
|
+
| `submit` | Submit files and return after provider acceptance. |
|
|
149
|
+
| `watch` | Resume actionable jobs and collect terminal artifacts. |
|
|
150
|
+
| `process` | Submit, watch, and collect in one invocation. |
|
|
151
|
+
| `status` | Inspect the local SQLite manifest. |
|
|
152
|
+
| `reconcile` | Recover a submission with an uncertain provider outcome. |
|
|
153
|
+
| `list-jobs` | List recent jobs directly from one provider. |
|
|
154
|
+
| `cancel` | Request cancellation for a tracked or provider-native batch ID. |
|
|
155
|
+
| `download` | Collect result artifacts for one batch. |
|
|
156
|
+
| `configure` | Store, inspect, or reset local settings. |
|
|
157
|
+
|
|
158
|
+
Use `batchwizard <command> --help` for the exact arguments and options.
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
uv sync --all-groups
|
|
164
|
+
uv run pytest
|
|
165
|
+
uv run ruff format --check .
|
|
166
|
+
uv run ruff check .
|
|
167
|
+
uv build
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The supported runtime matrix is Python 3.11 through 3.14. The lockfile is
|
|
171
|
+
committed; update it intentionally with `uv lock --upgrade-package <package>`.
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
[MIT](LICENSE)
|