Batch actions
A batch over a folder or a page tree
An editor action can run over a whole folder or page tree (ADR-236). In the Editor Action Center, open Run this on several records under the action, and choose a folder (Choose folder, for files) or the page at the top of the tree (Choose page, for pages) in TYPO3's element browser. In the file list, AI actions in the context menu of a folder lists the actions on files, and Run this on the files in this folder under one of them opens this page with that folder already chosen (ADR-267). From the command line or the scheduler:
vendor/bin/typo3 nrllm:editor-action:batch set_file_alternative_text \
--user=jane --folder=1:/products/
vendor/bin/typo3 nrllm:agent:work
A batch writes nothing. Each record becomes one ordinary run, and each run stops at its approval card with the generated text. The field keeps its value until somebody approves that card, so a folder of 100 images is 100 cards, each decided on its own. There is no switch for writing directly.
-- names the backend user the runs act as. Their rights decide which files
and pages are reached, a file they may not edit stays out, and the cards appear in their inbox. It must be an active
user and cannot be _cli_. A user disabled later makes the run fail.
The image is read when the worker picks the run up, as that user. A file that cannot be sent any more fails its run, and no model is asked. See Vision editor actions for folders to exclude.
A batch can be repeated. A card waiting for approval, a rejected card and a model
that declined keep their record out until the run is purged. A run that failed,
was cancelled or ran out of budget decided nothing, so its record is tried again.
So is the record of a card that was approved but whose write failed: the run
completes, because the model is told, and the record is as it was.
A vision action
skips a file that holds a text in one of the fields it fills, and it leaves out
fields switched off in Vision editor actions. A daily schedule therefore
picks up new files and never replaces a text. -- adds a
field to that check, for example -- on
update_.
For a page the model gets the text of the page and its content elements, as the
page stood when the batch was queued. A tree holds the pages -- may edit
inside their mounts, without folders and recyclers.
A batch started in the Editor Action Center while the editor works in a draft
workspace runs in that workspace: the tree, the empty fields and the page text
are read as the workspace shows them, and each run records the workspace, so an
approved text is stored there as a draft, wherever the editor works when the
card is decided. Whether a tool writes into a workspace at all is the tool's
own decision; one that does not refuses there. A card decided in a draft
workspace does not keep its record out of a live batch, nor the reverse. The
command and the scheduler run in the live workspace, whatever workspace
-- last worked in, and need a user who may work in live
(ADR-265).
At most 100 runs of one action are open at a time, the number of cards the inbox shows. A file the action cannot handle, such as a PDF for a vision action, takes no place among them. The command reports the rest, and a later batch picks them up once cards are decided.
Worker operating profile
Deploy web processes separately from Doctrine consumers. Each consumer executes one message at a time; start a bounded number of processes against the same transport to control concurrency. Atomic run claims prevent duplicate ownership when two consumers receive the same run. Size concurrency against model rate limits, memory per request and database capacity.
TYPO3 14.3 supports the Symfony-style consumer limits:
vendor/bin/typo3 messenger:consume doctrine --time-limit=3600 \
--memory-limit=256M --limit=100
On TYPO3 13.4, use the existing messenger: command with a
supervisor and the core's configured stop-worker listeners; the Symfony-style
options above are available from TYPO3 14.2. A supervisor should restart exited
consumers, stop them gracefully and leave enough time for a running model call
to finish. The existing non-idempotent write fence still governs recovery when
a process is killed during a write.
Run the reaper periodically, for example once per minute with --.
Its lease duration must exceed the maximum provider/tool request duration plus
the scheduling margin. A reaper retry is bounded by the runtime's existing
retry budget; it is not an alternative message broker.
vendor/bin/typo3 nrllm:agent:status --json --transport=doctrine \
--minimum-workers=1 --worker-max-age=120 --max-queue-wait=300
The command returns success when no run lease is expired, all queued timestamps
are known, queue wait is within the limit and the requested transport has enough
live consumers. It returns failure for an unhealthy snapshot, or invalid for
malformed options. -- explicitly disables the consumer
requirement for a synchronous-only installation. Counts of running runs include
interactive runs and must not be interpreted as a count of consumer processes.
Consumers renew a random process heartbeat at most once per 30 seconds, including
when idle. Only consumers serving the transport's default queue count; a
consumer restricted to other queue names cannot establish its health. Stopped
consumers remove their entry; active heartbeat updates prune entries older than
24 hours. Transport names contain no user or host identity.
Heartbeat storage and stop cleanup are best effort. A telemetry failure does not stop consumption; failed heartbeat attempts retry at most once per 30 seconds with the same process identity. Failed cleanup can leave a heartbeat until it ages out. Warnings contain only the operation and exception class, without connection details. Missing or stale observations remain visible to monitoring; a failed status read is an error and does not produce a healthy snapshot.
A long blocking model/tool call delays the next consumer heartbeat. Set
-- above the configured call timeout and polling margin. A
heartbeat proves that the consumer event loop ran recently; it cannot prove
that a remote provider is available. Monitor provider failures separately.
Queue-entry time is recorded for each enqueue/requeue, rather than guessed from
run age. Legacy or future timestamps contribute to unknown_.
oldest_ is null when no measured queued row exists, and
zero when a measured row has just entered the queue. JSON contains aggregate
counts and durations only, without prompts, document data, actors or secrets.