survos / ai-batch-bundle
Persistent AI batch orchestration for Symfony AI: durable job handles, lifecycle tracking, result archives and replay.
Package info
github.com/survos/ai-batch-bundle
Type:symfony-bundle
pkg:composer/survos/ai-batch-bundle
Fund package maintenance!
Requires
- php: ^8.5
- survos/kit-bundle: ^2.33
- symfony/ai-open-ai-platform: ^0.14
- symfony/ai-platform: ^0.14
- symfony/filesystem: ^8.1
- symfony/framework-bundle: ^8.1
- symfony/http-client: ^8.1
- symfony/scheduler: ^8.1
Requires (Dev)
- phpunit/phpunit: ^13.0
- symfony/ai-agent: ^0.14
Suggests
- doctrine/orm: For persisting AiBatch entities
- symfony/ai-agent: For building batch requests from Agent/MessageBag patterns
- symfony/messenger: For async result processing
Provides
None
Conflicts
- api-platform/core: <5.0
Replaces
None
- dev-main
- 2.42.14
- 2.41.9
- 2.39.0
- 2.34.1
- 2.33.0
- 2.31.12
- 2.28.3
- 2.28.2
- 2.26.9
- 2.17.0
- 2.15.15
- 2.12.0
- 2.11.8
- 2.10.19
- 2.10.18
- 2.10.17
- 2.10.16
- 2.10.15
- 2.10.14
- 2.10.13
- 2.10.12
- 2.10.11
- 2.10.10
- 2.10.9
- 2.10.8
- 2.10.7
- 2.10.6
- 2.10.5
- 2.10.4
- 2.10.3
- 2.10.2
- 2.10.1
- 2.10.0
- 2.9.4
- 2.9.3
- 2.9.2
- 2.9.1
- 2.9.0
- 2.8.4
- 2.8.3
- 2.8.1
- 2.8.0
- 2.7.23
- 2.7.22
- 2.7.21
- 2.7.20
- 2.7.19
- 2.7.18
- 2.7.17
- 2.7.16
- 2.7.15
- 2.7.14
- 2.7.13
- 2.7.12
- 2.7.11
- 2.7.10
- 2.7.9
- 2.7.8
- 2.7.7
- 2.7.6
- 2.7.5
- 2.7.4
- 2.7.3
- 2.7.2
- 2.7.1
- 2.7.0
- 2.6.0
- 2.5.8
- 2.5.7
- 2.5.6
- 2.5.5
- 2.5.3
- 2.5.2
- 2.5.1
- 2.5.0
- 2.4.4
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.0
- 2.2.5
- 2.2.4
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.2
- 2.1.1
- 2.0.220
- 2.0.219
- 2.0.218
- 2.0.217
- 2.0.216
- 2.0.215
- 2.0.214
- 2.0.213
- 2.0.212
- 2.0.211
- 2.0.210
- 2.0.209
- 2.0.208
- 2.0.207
- 2.0.206
- 2.0.205
- 2.0.204
- 2.0.203
- 2.0.202
- 2.0.201
- 2.0.200
- 2.0.199
- 2.0.198
- 2.0.197
- 2.0.196
- 2.0.195
- 2.0.194
- 2.0.193
- 2.0.192
- 2.0.191
- 2.0.190
- 2.0.189
- 2.0.188
- 2.0.187
- 2.0.186
- 2.0.185
- 2.0.184
- 2.0.183
- 2.0.182
- 2.0.181
- 2.0.180
- 2.0.179
- 2.0.178
- 2.0.177
- 2.0.176
- 2.0.175
- 2.0.174
- 2.0.173
- 2.0.172
- 2.0.171
- 2.0.170
- 2.0.169
- 2.0.168
- 2.0.167
- 2.0.166
- 2.0.165
- 2.0.164
This package is auto-updated.
Last update: 2026-10-15 10:02:29 UTC
README
Persistent batch orchestration for Symfony AI 0.14: durable job handles, application batch records, progress, archives, replay, and scheduler messages. Symfony AI owns native OpenAI submission, polling, and result conversion.
Package identity
Install survos/ai-batch-bundle from the Survos monorepo. tacman/ai-batch-bundle
is the historical package name, not a second bundle to install. The PHP namespace
Tacman\AiBatch and TacmanAiBatchBundle registration are deliberately retained:
existing services, Doctrine entity metadata, application handlers, and queued messages
use those names. Renaming the Composer package does not require renaming those classes.
composer require survos/ai-batch-bundle
Tacman\AiBatch\TacmanAiBatchBundle::class => ['all' => true],
The kit base registers commands and Doctrine mappings. Existing mapping name/alias
TacmanAiBatch is preserved. Store OPENAI_API_KEY in the host application's environment.
Doctrine persistence is owned by the host application; use its migration workflow.
Native jobs with persistence
Inject Tacman\AiBatch\Service\NativeOpenAiBatchService for new OpenAI batches.
Build the same message bags used for synchronous calls, keyed by stable subject IDs.
use Symfony\AI\Platform\Message\Message; use Symfony\AI\Platform\Message\MessageBag; use Tacman\AiBatch\Entity\AiBatch; $batch = new AiBatch(); $batch->datasetKey = 'my-collection'; $batch->task = 'description'; $entityManager->persist($batch); $entityManager->flush(); $handle = $nativeBatch->submit($batch, 'gpt-4o-mini', [ 'object_123' => new MessageBag(Message::ofUser('Describe this object.')), ]); $entityManager->flush();
The serializable handle is stored under meta.symfony_ai_job in the existing JSON
column. No database schema migration is required. The entity also keeps its provider
ID, request count, submission time, and application metadata. A later worker loads
that entity and resumes the provider job:
$status = $nativeBatch->refresh($batch); $entityManager->flush(); if ($status->isTerminal()) { $nativeBatch->archive($batch, $archivePath); $entityManager->flush(); }
Archive retrieval can fail if a terminal job has no output/error file; the exception leaves any previous archive intact. Canceled/expired jobs can have partial output. Each archive row preserves the subject ID, success/error/canceled/expired outcome, content, and error. Files are atomically replaced only after a complete download. Replay is offline:
foreach (NativeOpenAiBatchService::replay($archivePath) as $row) { // Apply successful rows idempotently using $row['custom_id']; retain failures for review/retry. }
Archives are versioned normalized JSONL (symfony-ai-batch-v1), not raw provider
responses. results() also exposes native BatchItem objects directly. The caller
owns persistence transactions, deduplication, and exactly-once application to subjects.
Submitting an already-associated entity is rejected. An HTTP submit and a database
flush are not atomic: if a flush fails after acceptance, retain/reconcile the returned
handle before retrying. This service does not promise remote exactly-once submission.
Existing jobs and other providers
OpenAiBatchClient, AiBatchBuilder, BatchRequest, BatchJob, and the legacy
BatchCapablePlatformInterface remain compatibility APIs. Existing applications use
raw Chat Completions JSONL, uploaded file IDs, provider response bodies, and saved
archives. Symfony's new OpenAI batches use /v1/responses; silently sending old jobs
through that converter would break them. Native services therefore require a stored
native handle and explicitly reject legacy rows. Legacy batch:replay stays separate
from NativeOpenAiBatchService::replay().
Anthropic and Mistral adapters remain available through BatchClients. Native OpenAI
support does not replace those providers' batch APIs.
The scheduler dispatches PollBatchesMessage every two minutes. Host handlers choose
the native service when $batch->getJobHandle() is non-null and their existing adapter
otherwise. They remain responsible for applying results and recording appliedCount.
Existing handlers are not switched automatically.
Demo
See demo/README.md. It runs against released Symfony AI 0.14, using files to demonstrate handle persistence across processes, without a fork, Doctrine database, or custom provider protocol. Its local numeric database IDs from the old demo are not inputs to the new fetch command.