v0.20.0
Every operator-facing setting in the backend now either works or is gone. This release closes out the config audit that found five classes of provider, model and configuration fields which were stored and displayed — but never applied.
Note: version 0.19.1 was prepared but never tagged (its release run was cancelled); its two criteria-mode fixes first ship in this release.
⚠️ Breaking changes
Provider timeouts are real now (#384, #400). The API timeout field was write-only: every provider request ran on TYPO3's default HTTP timeout of 0 — unbounded — so a silent provider could pin a PHP-FPM worker indefinitely. Requests are now bounded by a total-response timeout: the configuration's effective timeout (≥ 120 s by default, model default 120 s) wins, the provider's api_timeout is the fallback for direct adapter calls (test connection, model listing, setup wizard). The field default moves 30 → 120 s and the upgrade wizard nrLlm_providerApiTimeout120 migrates rows persisted at the old default. Two consequences to know about:
- Timed-out requests are not retried — a timed-out multi-minute generation is not re-sent three more times.
- Streaming is bounded by the same total timeout: a stream still emitting when the timeout fires aborts. Long generations need a raised configuration or model timeout (60–300 s for reasoning models).
max_retries means retries (#387, #400). Setting it to 0 — a value the form always allowed — used to send zero HTTP requests and fail with "Failed to connect to provider after 0 attempts: Unknown error". It now sends exactly one request; the default of 3 sends up to 4 requests on persistently failing providers.
BudgetServiceInterface::check() gained an optional ?LlmConfiguration parameter (#389, #401) — third-party implementations of the interface must update their signature.
The PromptTemplate stack is removed (#399, #404, ADR-069). It was never usable at runtime — the tx_nrllm_prompttemplate table had no TCA, so every repository call failed — and nothing consumed it; prompt snippets (ADR-031) and tasks superseded the concept. Drop the orphaned table via the database analyzer (Admin Tools → Maintenance → Analyze Database Structure).
Budget caps that actually cap
The Configuration record's Limits tab (max requests / tokens / cost per day) is now enforced (#389, #401). The budget gate checks the dispatched configuration's current-day usage alongside the per-user budget — most restrictive wins, and an exhausted cap denies the request with a scope-labelled reason. Callers without a backend user (CLI, scheduler, frontend plugins) were previously never budget-checked at all; configuration caps now gate them too.
Model limits feed the request
A model's Max output tokens and an embedding model's Dimensions had zero production callers (#390, #402). They now act as defaults-when-unset: max_tokens resolves as per-call option → configuration → model → provider default (a configuration max_tokens of 0 now means "no explicit limit"), and embedding calls pick up the model's dimensions when the caller left them unset. Criteria-mode configurations also got a cache-key fix so embedding cache entries no longer collide under an empty model id.
Headers that actually get sent
The provider's Organization ID is emitted as the OpenAI-Organization header (including the OpenAI-compatible adapter types), and the options JSON's customHeaders are applied on every request path — streaming included — with names and values sanitized against header injection (#388, #403). The shipped options placeholder now shows the working syntax. Per-provider proxy is documented as not implemented; the global TYPO3 HTTP proxy applies.
Also in this release
- Criteria-mode configurations work with every
*ForConfiguration()call, and dotted preset identifiers no longer break embedding cache tags (the untagged 0.19.1 fixes, #372). - A test batch covering 14 previously-untested classes (#398), raising full-suite coverage to ~89 %.
Documentation/Changelog.rstis back in sync withCHANGELOG.md(0.17.0–0.19.1 backfilled).
Full changelog: v0.19.0...v0.20.0