Changelog 

All notable changes to the TYPO3 LLM Extension are documented here.

The format follows Keep a Changelog and the project adheres to Semantic Versioning.

Version 0.43.13 (2026-11-04) 

Five administrator tools for site chores (ADR-257). list_redirects lists the redirects of EXT:redirects; create_redirect, update_redirect and disable_redirect create, change and switch off one redirect under the redirects module's rules, and the approval card shows each field before and after and when visitors get the change. clear_cache clears one cache group or the page caches by tag; its card names a full flush as one. The four writers ship disabled and pause for approval.

Version 0.43.12 (2026-11-04) 

Routing can rank by what calls actually took and cost. With the new setting routing.callHistory (off by default), the Balanced, Quality and Economy modes add each model's mean latency over its last seven days of calls of the same operation, and rank cost by the measured cost per call instead of the list price wherever every priced candidate has one (ADR-256). A call through a criteria-mode configuration now records its cost and model, so cost budgets count those calls from this version on. Provider health is looked up by adapter type, which can change decisions in a measured mode. Database change: two columns on tx_nrllm_telemetry.

Version 0.43.11 (2026-11-04) 

A configuration can answer a repeated plain chat or completion request from a cache: the new field answer_cache_ttl (seconds, 0 = off by default, at most one day) serves the same answer again without a provider call. Agent runs, tool calls, schema-bound calls and streamed answers are never cached, and an answer is kept only where the content privacy level is full for the provider that served it (ADR-249). Evaluation runs always ask the model. Database change: one column on tx_nrllm_configuration.

Version 0.43.10 (2026-11-04) 

The text under a record select says what the chosen model, configuration, task, provider or skill is for, and changes with the choice, also for keyboard and screen reader users. Next to the select, a button creates a new record and another opens the module that lists them; each is shown only to users who may use it (ADR-255, Choosing a record from a list).

Version 0.43.9 (2026-11-03) 

A consuming extension reads what it spent and how often each of its operations ran and failed through the public ExtensionUsageReaderInterface, which also says how far back the per-call counts reach (ADR-248). A streamed call records its caller on the usage aggregate as a non-streamed call does, so its cost is no longer filed as unattributed.

Version 0.43.8 (2026-11-03) 

A tool call whose arguments do not fit the schema its tool was offered with is answered with what does not fit, and nothing of that turn runs: no tool, no approval card, no question, no external call budget (ADR-246). Azure OpenAI provider records send the key in the api-key header and reach the deployment with an api-version, or the v1 API when the endpoint ends in /openai/v1 (ADR-247). Telemetry rows of a configuration in automatic model selection name the model the selection chose instead of an empty one, and such a configuration passes that model to the adapter, so its embeddings no longer fall back to the adapter's default model.

Version 0.43.7 (2026-11-03) 

The skill select of a configuration and a task filters and labels its skills on TYPO3 13.4 and 14.3: an orphaned or disabled skill is offered only where it is already attached, with its state in the label, and a new always attachment no longer offers a process skill. Before, the select offered every skill unfiltered.

Version 0.43.6 (2026-11-03) 

The page for running an editor action on several records no longer asks for typed record numbers or a typed page number or folder identifier: the records, and the page or folder a background batch starts from, are chosen in TYPO3's element browser, on TYPO3 13.4 and 14.3. The server checks the choice as before.

Version 0.43.5 (2026-11-02) 

A task can be marked for the places that offer it, in the new field Offered first in. The editors' module AI tasks lists the tasks marked for it first, under Prepared for this module, and labels the other groups by category; a task marked only for another extension's place is left out there. Another extension orders its own task select by a placement with TaskPlacementItems::groupByPlacement() (ADR-245, Placements). Run the database schema update for the new column tx_nrllm_task.placements.

Version 0.43.4 (2026-11-02) 

A site can name the LLM configuration its AI calls use and the DeepL key its translations use, as identifiers in two site settings of the new set netresearch/nr-llm; a site that names neither keeps the installation's (ADR-244, Site settings). A caller states its site with withSite(), which also scopes the term lists bound to a site.

Version 0.43.3 (2026-11-02) 

A provider and a task can tighten the privacy level for what is stored of their runs, with a privacy_level field. It cannot loosen the global level (ADR-242). The rule set is a tagged snippet plus a term list, with no new record (ADR-243). Run the database schema update for the new columns.

Version 0.43.2 (2026-11-02) 

In an agent run that offers tools, as the AI chat does, a term list checks only what a writing tool would store. Chat text streams and stays free, and a search for a forbidden term runs (ADR-238). A reasoning model of OpenAI gets an output limit of at least 16,000 tokens unless the call switches thinking off, and an answer that ends without text at the limit raises OutputBudgetExhaustedException (ADR-241).

Version 0.43.1 (2026-11-01) 

The text of a tool round reaches an observer while the model writes it, on OpenAI's Responses transport (ADR-240). A chat can show an answer before the round has ended. A run of text without whitespace now waits in the live redaction until it ends, up to 4 KB, so a JWT is masked whole (ADR-088).

Version 0.43.0 (2026-11-01) 

Term lists, a mark on what an AI wrote, and where the time of a model call goes. Update the database schema: pages and tt_content gain tx_nrllm_ai_written, and the table tx_nrllm_term_list is new. Until the update ran, new pages and content elements cannot be saved. A consumer pinned to ^0.42 needs ^0.43. Details in the repository CHANGELOG.md.

  • Term lists: forbidden and required terms in a record stop generated text, and the editor reads which term and which list did it (ADR-238).
  • A page or content element an agent run or a fill run wrote carries tx_nrllm_ai_written (ADR-239).
  • The step of a model call in the Verlauf shows the cached part of the prompt, the wall time of the HTTP call and the time the provider reports.

Version 0.42.0 (2026-11-01) 

Background work. Update the database schema: tx_nrllm_agentrun gains origin, answer and outcome. A consumer pinned to ^0.41 needs ^0.42. Details in the repository CHANGELOG.md.

  • nrllm:task:enqueue queues an AI Task, nrllm:agent:work works the queue from cron or the scheduler without a Messenger consumer, and the Agent Runs module lists these runs under Background runs (ADR-234).
  • AgentRuntimeInterface::defer() stores a queued run and never executes it in the caller. A class outside nr-llm that implements the interface has to add it.
  • worker.technicalBeUserUid names the backend user whose grants on a vault secret count on the command line. With allowCliAccess off and without this setting, every queued run fails on its first model call.
  • The editor actions for the alternative text and the file metadata send the image to the model (ADR-235). They are no longer offered on a model that declares capabilities without vision.
  • An editor action runs over a folder or a page tree in the background, from the batch page and from nrllm:editor-action:batch. Each record becomes a run that waits for its own approval (ADR-236).
  • An empty field can be filled by AI after a save, from fieldFill.fields (ADR-237).

Version 0.41.18 (2026-10-31) 

Behaviour change in guided processes; no database schema or extension setting change. Details in the repository CHANGELOG.md.

  • In a run holding a process pin, a turn that pauses for input runs the reads beside the question before the pause, as a turn that pauses on a proposal already does (ADR-214, amendment of 2026-10-31). A process step can report its progress and highlight in the same response as its question, without a model round of their own. A remote tool, a write and a second input call beside the question do not run. Outside process runs nothing changes.

Version 0.41.17 (2026-10-30) 

Bug fix; no database schema or extension setting change. Details in the repository CHANGELOG.md.

  • A write proposal shows a length only against a configured range (ADR-214): the approval card of update_page_metadata and update_content_element no longer shows a bare character count, such as "Länge 23 Zeichen" for a page title, for a field without a range in tools.structuredPreview.ranges. With the shipped default only pages.description carries one.
  • The fourth parameter of FieldMeasurer::measure(), $countWithoutRange, is optional, deprecated and ignored. It stays in place so that an existing call keeps passing $richText fifth; new calls omit it and pass richText: by name.

Version 0.41.16 (2026-10-30) 

Bug fix; no database schema change. Details in the repository CHANGELOG.md.

  • Gemini structured output keeps properties whose type is one type plus null, such as ["string", "null"]: they are sent as that type with nullable: true. An object whose properties were all nullable previously reached Gemini without properties, and Gemini rejected the request with HTTP 400.
  • An object without any expressible property, and an array without expressible items, are left out of the response schema instead of being sent empty.

Version 0.41.15 (2026-10-29) 

Bug fix; no database schema change. The unused extension settings image.dalle.defaultModel and image.dalle.defaultSize are removed. Details in the repository CHANGELOG.md.

  • Image generation without a model no longer calls the retired dall-e-3: DallEImageService::generate() and generateMultiple() take the model registry's default image model and fall back to gpt-image-2. An explicit model still wins. ImageGenerationOptions defaults model to null.
  • ImageGenerationOptions::hd() is sent as quality high to gpt-image models; standard is not sent, so the API default auto applies.
  • The image test page reports a request the provider refuses as a refused request with its status code (502) instead of "not configured". The exception carries the status through getStatusCode().

Version 0.41.14 (2026-10-29) 

No database schema or extension setting change. Details in the repository CHANGELOG.md.

  • Optional revision of a DeepL translation by a language model (ADR-233): TranslationOptions::withPolish() lets translateWithTranslator() and its batch variant revise the result for fluency, terminology and tone. The revision is an ordinary request (a polished translation uses two); when it changes tags, placeholders or glossary terms, adds text, fails or is refused by the budget, the first translation is returned. Off by default.

Version 0.41.13 (2026-10-28) 

No database schema or extension setting change. Details in the repository CHANGELOG.md.

  • A streamed answer reaches the caller while the provider is still writing it. The streaming adapters send with nr-vault's sendStreaming() (nr-vault 1.1) instead of the blocking sendRequest(), which delivered every chunk at the end. A provider without an API key, such as a local Ollama, streams too, after the same host check, and each such call writes an nr-vault audit row.
  • A dropped connection before the first chunk still lets the streaming fallback try the next configuration. A 401 or 429 whose error body is cut off keeps its exception class.
  • With nr-vault 0.16 or without curl_multi_* the request is sent as before.

Version 0.41.12 (2026-10-28) 

No database schema or extension setting change. Details in the repository CHANGELOG.md.

  • New developer page Report usage from your own provider calls: how an extension that calls a provider with its own code checks the editor's budget and reports its usage, so its calls count against the budget and appear in Analytics and the billing report under its extension key.
  • Translations through translateWithTranslator() and translateBatchWithTranslator() keep the caller named with withCallerSource(); before, DeepL and the LLM translator recorded them unattributed.
  • nrllm:demo:seed records seeded completion usage as complete.

Version 0.41.11 (2026-10-28) 

No database schema or extension setting change. Details in the repository CHANGELOG.md.

  • An editor's own budget status is public API: UserBudgetStatusService, the value objects UserBudgetStatus, BudgetWindowStatus and BudgetMeter, and LocalizedNumberFormatter are now @api, so another extension can show the usage and limits the AI Tasks module shows (ADR-232).
  • The billing report names its entitlement count "Entitled to AI Tasks". Users whose access comes only from an extension with its own permission checks, such as an editor assistant or a chat, are not part of it.

Version 0.41.10 (2026-10-28) 

No database schema change. A new extension setting billing.markupPercent (whole percent, default 0) sets the markup of the billing report. Details in the repository CHANGELOG.md.

  • A monthly billing report in the Analytics module: for a calendar month, the estimated cost with the markup, the active editors with their cost, the editors entitled to the AI features as of today, and the results by service type, calling extension and task, with a CSV export of the same month.

Version 0.41.9 (2026-10-28) 

Bug fix; no database schema or extension setting change. Details in the repository CHANGELOG.md.

  • Backend views print token counts and USD amounts in the backend user's language: a German reader sees "5.138.706" and "11,40 $" instead of "5,138,706" and "$11.40". This covers the AI Tasks budget panel, the run estimate, the Analytics and overview modules, the usage columns of the list views, the AI actions batch estimate and the agent runs. Amounts stay in USD.

Version 0.41.8 (2026-10-28) 

No database schema or extension setting change. A new AJAX route nrllm_aitask_budget serves the AI Tasks budget panel. Details in the repository CHANGELOG.md.

  • The AI Tasks module shows editors their own usage today and this month against their personal budget, with a progress bar per limit, and says when no personal limit is set. The run form adds a cost estimate for one run of the task and states whether the budget lets the next run start, naming the limit that would refuse it.
  • Landing pages: canonical and language alternate metadata outside the document head is rejected, and the bilingual title panels follow the shared page family.

Version 0.41.7 (2026-10-25) 

Bug fix; no database schema or extension setting change. ReplaceFileReferenceTool takes a fourth constructor argument, which the container wires. Details in the repository CHANGELOG.md.

  • The writing tools set_file_reference_alternative_text, attach_file_to_record and replace_file_reference check every record of another table that holds an inline child, up the chain, before they write. An editor can no longer change a file reference on an inline child whose outer record is locked, outside their grant or on a page they may not edit. A relation of a table to itself, such as a grid container holding content elements, is not followed, because the page module edits those children on their own (ADR-230).

Version 0.41.6 (2026-10-25) 

New feature; no database schema or extension setting change. Details in the repository CHANGELOG.md.

  • The new writing tool set_file_reference_alternative_text sets the alternative text of one use of an image (sys_file_reference), in place and in the reference's language. It ships disabled, works in the live workspace only and asks for approval (ADR-230).

Version 0.41.5 (2026-10-25) 

Database schema change: run the database analyzer, because tx_nrllm_skill gains the column page. Existing rows keep today's behaviour, and no skill approval is invalidated. Two additive public API changes. Details in the repository CHANGELOG.md.

  • A skill can declare in its frontmatter whether it works on a page: page: required, optional or none. Skill::getPageNeed() returns it as SkillPageNeed. The field is not part of the version digest.
  • ApproverNotPermittedException and SubmitterNotPermittedException say why they refused: getCause() and getDenialReason(). A surface can tell a switched-off tool from missing permissions.
  • The decision and reranker sidecar images install filelock 4.2.4 and setuptools 84.2.1 for open advisories.
  • The public product site: mobile layout, language switch and a header shared with the other Netresearch pages.

Version 0.41.4 (2026-10-24) 

Bug fix; no database schema or extension setting change. One additive public API change: ApprovalDenialReason gains the case KEEP. Details in the repository CHANGELOG.md.

  • A guided process can tell "keep the current content" from "skip this point". The denial result for KEEP says the point is settled and must not be called skipped.

Version 0.41.3 (2026-10-22) 

Bug fixes; no database schema or extension setting change. One additive public API change: SuspendedRunState takes an optional maxIterations as its last constructor parameter. Details in the repository CHANGELOG.md.

  • A resumed agent run keeps the round cap it was started with. Before, every segment after an approval or an answered input ran on the loop default of 5. A run suspended before this release resumes on the default as before.
  • set_page_social_image with replace removes a copy of the old reference that a translation left on the default-language page, also on TYPO3 14.3.10.

Version 0.41.2 (2026-10-22) 

Bug fixes; no public API, database schema or extension setting change. Details in the repository CHANGELOG.md.

  • An invoked process skill is composed as its own section, "Active process", ahead of the approved skills, and governs the order of steps and the structure of answers; approved skills keep applying to wording, terminology and safety. Before, an approved skill attached always could override the process, so a guided tour ended its first turn without the tool calls it prescribes.
  • Skill import refuses a GitHub repository tree that GitHub reports as truncated and keeps the last known-good skills, and a malformed GitHub response keeps its typed failure when the diagnostic logger throws.
  • The decision and reranker sidecar images build again on Python 3.14, lock their dependencies with uv and install certifi 2026.10.19.

Version 0.41.1 (2026-10-21) 

Bug fixes and test coverage; no public API or extension setting change. Update the database schema: skill sources gain two columns for the synchronization lease. Skill sources, skills and the skill audit table must share one database connection. Details in the repository CHANGELOG.md.

  • A process skill attached in the field "Skills loaded on demand" is listed, can be started and continues; before, only skills loaded always counted (ADR-214).
  • Gemini tool conversations keep native thought signatures and echo native function-call IDs through parallel calls and stored approval resumes (ADR-222, ADR-224).
  • MCP imports skip tools whose schema they cannot keep intact instead of importing a weakened schema.
  • A failing preview read check no longer blanks the approval inbox, and optional diagnostic loggers that throw no longer replace the original outcome in agent recovery, governance, MCP import, skill tokens and the Ollama model picker.
  • Skill metadata closes only at a standalone --- delimiter.
  • Skill synchronization holds a persisted lease and publishes skill, orphan and audit changes in one transaction (ADR-221).
  • Gemini responses keep every visible text part and separate native thinking (ADR-223); MCP imports report tool names another server already holds.

Version 0.41.0 (2026-10-20) 

Approved skill versions, guided processes and skills loaded on demand (ADR-214, ADR-228), with a security fix for the read tools. Callers of the PHP API are unaffected; a class that implements AgentRuntimeInterface, ToolCallPolicyInterface or ToolLoopServiceInterface has to follow their new members. Update the database schema and run the upgrade wizard "Write the version digest onto existing skills". Details in the repository CHANGELOG.md.

  • An administrator approves one version of a skill; an approved version from a trusted source is composed into the system message as an instruction, every other skill stays fenced. Skills can be written in the backend and loaded on demand through the new load_skill builtin.
  • A guided process is started, continued and ended through a skill invocation and decided in the chat, one proposal per turn. New builtins ask_choice and highlight_record ship disabled.
  • Approval cards carry a write's record, fields and proposed values as structured data, and a write states whether it did everything it planned.
  • Invocation rules, optional actor-bound MCP authentication, retrieval experiment provenance, verified evaluation generators and worker operations status (ADR-215, ADR-216, ADR-217, ADR-219, ADR-220).
  • Security: the read tools check web mounts against the run's acting user, not the backend user of the request (#1022).

Version 0.40.0 (2026-10-08) 

Every built-in approval preview is in the acting user's language. No breaking change to the PHP API; details in the repository CHANGELOG.md.

  • The approval cards of the remaining fifteen previewing tools and the lines the tool loop puts on a card use the acting user's language (ADR-213, #1016). Runs suspended before the upgrade bounce once at resume.
  • New public class ApprovalPreviewHeadings names the first line of every built-in preview for approval cards in other extensions.
  • TCA labels on approval cards resolve TYPO3 14 translation domain references.
  • attach_file_to_content_element refuses a translated content element.

Version 0.39.0 (2026-10-07) 

Typed decisions (ADR-211), hidden-record reading, a tool to attach a file to any record's file field, and localised approval previews. Breaking changes to the PHP API; full details and the migration in the repository CHANGELOG.md.

  • Breaking: completeStructured() and completeStructuredForConfiguration() return a StructuredCompletionResponse; read ->data where the array was read. Implementations of CompletionServiceInterface and LlmServiceManagerInterface gain the optional ?ModelResolution parameter, the latter also decideForConfiguration().
  • Breaking: model prices are float and stored as decimal(12,2) (database compare).
  • Breaking: the llm_judge evaluation grader is replaced by --grader decision.
  • DecisionServiceInterface, the TypeSafe provider and a local decision sidecar answer typed yes/no, choice and score questions.
  • read_records and search_records take include_hidden (#1009).
  • New writing tool attach_file_to_record (ADR-212, #1011).
  • Approval previews of create_page_draft, move_page and delete_record use the acting user's language (ADR-213, #1012).

Versions 0.21.0 to 0.38.2 are listed in the repository CHANGELOG.md.

Version 0.20.0 (2026-07-16) 

Closes out the operator-config audit: every backend-visible provider, model and configuration setting now either works or is gone. Three breaking changes; full details in the repository CHANGELOG.md.

  • Breaking: the provider API timeout is now applied as a total-response timeout (previously write-only — requests ran unbounded). Default moves 30 → 120 seconds; the nrLlm_providerApiTimeout120 upgrade wizard migrates rows persisted at the old default; timed-out requests are not retried (#384).
  • Breaking: Max retries counts retries after the initial attempt — 0 sends exactly one request instead of none (#387).
  • Breaking: the never-functional PromptTemplate stack is removed (ADR-069); drop the orphaned tx_nrllm_prompttemplate table via the database analyzer (#399). BudgetServiceInterface::check() gained an optional ?LlmConfiguration parameter (#389).
  • Per-configuration daily limits (requests / tokens / cost) are enforced alongside per-user budgets — most restrictive wins (#389).
  • Model Max output tokens and Dimensions act as call defaults when the caller and configuration leave them unset (#390).
  • Provider Organization ID is sent as OpenAI-Organization; options.customHeaders is applied on all request paths (#388).

Version 0.19.1 (2026-07-15, first shipped with 0.20.0) 

Prepared but never tagged; its fixes first ship in 0.20.0.

  • Criteria-mode configurations work with every *ForConfiguration() call — the model is resolved through ModelSelectionService instead of the (null) direct relation (#372).
  • Embedding cache tags built from dotted preset identifiers are sanitized (#372).

Version 0.19.0 (2026-07-14) 

  • Per-user usage attribution for the specialized speech and image services (ADR-057): transcription, synthesis and image generation record the calling backend user instead of the ambient bucket (#362).
  • Configuration identifiers with dots no longer crash cached calls — cache keys and tags are sanitized (#365); LlmTranslator chat rows carry the per-user attribution (#361); backend model-test button fixed (#363).

Version 0.18.0 (2026-07-14) 

  • Configuration presets module UI (ADR-056 follow-up): the Configurations backend module surfaces pending presets with one-click apply/update.

Version 0.17.0 (2026-07-13) 

  • Configuration presets: consuming extensions declare the LlmConfiguration records they need via the nr_llm.configuration_preset registration (ADR-056).

Version 0.16.1 (2026-07-10) 

Compatibility fixes for strict-mode MySQL/MariaDB, surfaced by the new MariaDB CI leg: the setup wizard's AJAX persist path now enforces the column length limits and the TCA identifier contract (overlong values previously produced a 500 instead of being truncated), generated identifier suffixes are collision-free within a batch, and decimal-backed values such as temperature are rounded to their column scale so every DBMS round-trips identical values.

For the complete, itemised list see the canonical CHANGELOG.md.

Version 0.16.0 (2026-07-10) 

This release adds RAG site-search tools: the new rag tool group lets agent runs answer questions about the website's own public content with cited evidence. site_rag_query returns curated sources (source_id, title, URL, match excerpt) from a priority cascade over whichever search index is installed — EXT:solr (via its HTTP select API), ke_search, indexed_search — with an always-available pages/tt_content database fallback that matches natural-language questions word-wise; site_fetch_source reads a source's full indexed text. Index-level filtering is strictly public-only (what the anonymous visitor could read), and every evidence package names the answering backend. See ADR-049.

For the complete, itemised list see the canonical CHANGELOG.md.

Version 0.15.0 (2026-07-09) 

This release turns the Tool Playground into a glass-box run inspector — every request, response, tool execution and the final answer stream live into an ordered step list with token, cost and timing detail, plus a dry-run mode that shows the exact prompt without calling the model — and grows the built-in tool set to 39 tools in 7 groups: record history ("who changed this?"), URL resolution, TCA/TypoScript validation, error-analysis (last exception, source read/search, URL probe), FAL file tools and system diagnostics. Groups can be toggled centrally, restricted per configuration and selected per run, cascading fail-closed.

Breaking: ToolInterface gained getGroup(): string — every tool implementer must declare its group (third-party tools: use the extension key).

For the complete, itemised list see the canonical CHANGELOG.md.

Version 0.14.1 (2026-07-05) 

A patch release fixing tool calling with parameterless tools. A tool that takes no arguments emitted its (empty) JSON-Schema properties — and its empty replayed call arguments — as a JSON array [] instead of an object {}, which strict providers such as Ollama reject with an HTTP 400. The bounded agent loop and the Tool Playground now work when a parameterless tool (environment, PHP info, or backend user/group introspection) is offered.

The Skills, Tools and Playground admin documentation was also refreshed to match the shipped backend (module section count, the full built-in tool catalogue, two-tier tool authorization, and updated screenshots).

For the complete, itemised list see the canonical CHANGELOG.md.

Version 0.14.0 (2026-07-04) 

This release adds a Skills and Tools system: extensions and editors can ingest SKILL.md files from GitHub (SHA-pinned, admin-reviewed) and attach them to tasks and configurations, and a function-calling tool runtime lets a model run an agent loop over an admin-curated, permission-gated set of tools — with an interactive tool playground in the backend. It also lands a broad security and accessibility hardening pass (SSRF/CSRF fixes, API keys moved out of URLs, RBAC on tool execution, EN/DE translations, WCAG text alternatives), and the CI now actually runs the functional and backend end-to-end suites so they gate merges.

Breaking: custom ToolInterface implementations must now declare a requiresAdmin(): bool method — true for tools that expose system, host, or cross-user data, false for tools that self-enforce the acting user's TYPO3 permissions. Without it the tool fails at runtime (ADR-038).

Together AI, Fireworks AI and Perplexity are now first-class OpenAI-compatible providers, and provider endpoints entered in the wizard or the record editor are canonicalized on save so they no longer break when saved without an API version path.

For the complete, itemised list see the canonical CHANGELOG.md.

Version 0.13.0 (2026-06-26) 

Provider selection is now database-driven end to end. Breaking: the extension-configuration defaultProvider fallback is removed — select a provider per call (the options object's provider field) or mark a Configuration active and default in the backend module; otherwise getProvider(null) throws (ADR-034). The dead plugin.tx_nrllm TypoScript constants/setup were removed and the "no provider specified" error now carries actionable backend-module guidance (#254, #255).

For the complete, itemised list see the canonical CHANGELOG.md.

Version 0.12.0 (2026-06-11) 

Specialized services (image, text-to-speech, transcription) gain full usage and cost tracking, join the model registry with image/text_to_speech/ transcription capabilities, and resolve their model and system prompt from Configuration records (ADR-032, ADR-033). Adds a prompt-snippet library (tx_nrllm_promptsnippet, ADR-031), per-request timeouts on the secure HTTP client, and arbitrary gpt-image sizes. Requires nr-vault ^0.10.0.

For the complete, itemised list see the canonical CHANGELOG.md.

Version 0.11.1 (2026-06-10) 

Security and robustness fixes from the extension-wide code review: the setup wizard dispatches through nr-vault's SSRF-guarded secure HTTP client, the provider adapters surface streaming errors as typed, credential-sanitized exceptions, TTS text splitting is multibyte-safe, and FAL/Whisper configuration parsing is hardened.

For the complete, itemised list see the canonical CHANGELOG.md.

Version 0.11.0 (2026-06-10) 

The backend module's default Configuration is now the single source of truth for generic completion: chat(), complete() and streamChat() resolve the active default database-backed configuration (provider adapter, model and vault-backed credentials) when no provider is pinned, with per-call options overriding the stored defaults. The extension-configuration defaultProvider becomes a fallback for installations without a usable default configuration.

For the complete, itemised list see the canonical CHANGELOG.md.

Added 

  • Default-configuration routing for generic completion. Calls without a pinned provider route through the module-managed default LlmConfiguration; per-call ChatOptions override its stored defaults. chatWithConfiguration() / completeWithConfiguration() / streamChatWithConfiguration() accept an $optionOverrides array.

Changed 

  • The extension-configuration defaultProvider is consulted only when no usable default configuration exists. Defaults without a model, or with backend-group access restrictions, are skipped — group-restricted configurations are never auto-applied without a backend-user context.

Version 0.10.0 (2026-06-09) 

The specialized AI services (DALL-E, FAL, Whisper, TTS, DeepL) now authenticate through nr-vault's audited secure HTTP client instead of plaintext API keys, bringing them in line with the database-backed providers (ADR-012, ADR-030).

For the complete, itemised list see the canonical CHANGELOG.md.

Changed 

  • Specialized services authenticate through nr-vault. Each service stores an nr-vault secret identifier and authenticates via $vault->http()->withAuthentication(...); the secret is resolved, injected, audited, and memory-scrubbed inside the vault and never surfaces in this extension. FAL (Authorization: Key …) and DeepL (Authorization: DeepL-Auth-Key …) use the nr-vault 0.8.0 prefix option. DeepL's Free/Pro routing stays automatic via a one-time, scrubbed :fx suffix check.

Removed 

  • Plaintext API keys for the specialized services. Configuration keys are now nr-vault identifiers (providers.openai.apiKeyIdentifier, image.fal.apiKeyIdentifier, translators.deepl.apiKeyIdentifier). Requires netresearch/nr-vault ^0.8.0.

Version 0.9.0 (2026-06-08) 

This release migrates image generation to OpenAI's gpt-image-\* model family (DALL·E-3 was retired by OpenAI), makes chat JSON mode actually request JSON, and corrects the empty base-URL handling of the specialized services.

For the complete, itemised list see the canonical CHANGELOG.md.

Added 

  • gpt-image-\* image generation. ImageGenerationOptions accepts the gpt-image-* family by prefix and validates its size set (1024x1024 / 1536x1024 / 1024x1536 / auto); DallEImageService maps the family to a shared capability profile and sends a minimal payload (gpt-image rejects response_format / style / quality), reading the returned b64_json.

Fixed 

  • Chat JSON mode. OpenAiProvider now maps response_format=json to OpenAI's {"type":"json_object"} so CompletionService::completeJson() receives valid JSON instead of prose.
  • Empty base URL. An empty ext_conf baseUrl for the DALL·E, FAL and TTS services now falls back to the provider default instead of being used as a scheme-less request URL.

Version 0.8.0 (2026-06-02) 

This release adds usage analytics and turns on real cost tracking, and completes the provider middleware pipeline that now powers fallback, pre-flight budget enforcement, usage accounting, and response caching around every provider call. It also migrates the domain API to typed value objects.

For the complete, itemised list see the canonical CHANGELOG.md.

Added 

  • Usage Analytics dashboard. A new Admin Tools → LLM → Analytics submodule with cost and request trends, breakdowns by provider, model, and service, KPI tiles, and per-user usage against each user's monthly budget. The Providers, Models, Configurations, and Tasks list views also gained per-row Cost / Requests / Tokens (last 30 days) columns. See Usage analytics.
  • Real cost tracking. Usage is now priced from the configured model rates (prompt/completion token split), so the AI cost this month widget and the dashboard show real figures instead of 0. The tx_nrllm_service_usage table gained model and token-split columns plus per-task attribution.
  • Automatic budget pre-flight. Completion, embedding, translation, and vision requests are checked against the configured budget before the call is made.

Changed 

  • The domain API moved to typed value objects (chat messages, tool specs, vision content, capability sets, provider options). The legacy string/array options accessors are deprecated in favour of the typed equivalents.
  • Requires netresearch/nr-vault ^0.6.0.

Breaking 

  • The legacy Model::CAPABILITY_* class constants have been removed in favour of the ModelCapability backed enum (for example ModelCapability::CHAT->value). They had been deprecated since the enum was introduced.

Version 0.7.0 (2026-04-22) 

Added 

  • Provider fallback chain. LlmConfiguration can now list other configuration identifiers to retry against when the primary fails with a retryable error (connection / HTTP 5xx / 429 rate- limit). Non-retryable errors (4xx other than 429, configuration problems, unsupported feature) bubble up unchanged. Streaming is intentionally excluded from fallback because chunks cannot be replayed against a different provider. See ADR-021: Provider Fallback Chain and Fallback chain.
  • Attribute-based provider registration. New #[AsLlmProvider(priority: N)] attribute. Providers bearing the attribute are automatically tagged and made public by ProviderCompilerPass at container compile time; no services.yaml edit required. Legacy yaml tagging still works for third-party providers and takes precedence when both mechanisms are present. See ADR-022: Attribute-Based Provider Registration and Registering a provider.
  • Per-capability BE group permissions. Every ModelCapability enum value is now a native TYPO3 customPermOptions entry under the nrllm namespace. BE group editors see a checkbox per capability (chat, completion, embeddings, vision, streaming, tools, json_mode, audio). New CapabilityPermissionService resolves checks against the current BE user with admin short-circuit and CLI / frontend bypass. See ADR-023: Native Backend Capability Permissions. These registrations and the check service were later removed (ADR-117: Withdraw the backend capability permissions); current backend access uses Backend user permissions.
  • Dashboard widgets. Two TYPO3 dashboard widgets sourced from tx_nrllm_service_usage: AI cost this month (NumberWithIconWidget) and AI requests by provider (7d) (BarChartWidget). Loaded conditionally from Configuration/Services.php only when typo3/cms-dashboard is installed. See ADR-024: Dashboard Widgets.
  • Per-user AI budgets. New tx_nrllm_user_budget table with six independent ceilings (requests / tokens / cost × daily / monthly). New BudgetService::check() aggregates usage on demand from tx_nrllm_service_usage — one DB roundtrip for both windows via conditional SUM(). Orthogonal to the existing per-configuration daily limits: both checks must pass. See ADR-025: Per-User AI Budgets and Per-user AI budgets.

Changed 

  • CI: mutation testing runs only on push, merge_group and schedule events. PR CI gets the fuzz suite + unit / functional / PHPStan / rector / code style; the  15 min mutation job is deferred because its per-PR signal is hard for authors to action locally.
  • CI: .semgrepignore added to exclude Tests/, Build/Scripts/ and vendor directories from Opengrep SAST. Previously failing on legitimate unlink() fixture cleanup.
  • CI: fuzz workflow now invoked with fuzz-testsuite: fuzzy matching the phpunit.xml suite name.

Version 0.6.0 (2026-03-24) 

Added 

  • DocumentCapableInterface: providers can now advertise PDF/document support; ChatCapabilitiesInterface exposes this via getProviderCapabilities().
  • Multimodal content arrays in chatCompletion: pass images, PDFs, and text blocks as structured content arrays alongside regular string messages.
  • Tool message conversion: tool_result blocks are now mapped correctly when assembling provider payloads.

Changed 

  • Migrated CI infrastructure to netresearch/typo3-ci-workflows shared workflows (PHP tests, docs, E2E).
  • Replaced GrumPHP with CaptainHook for pre-commit hooks.

Fixed 

  • PHPStan baseline regenerated; ignoreErrors patterns broadened for deprecation and array function rules to handle phpstan-typo3 v2/v3 parameter name differences.
  • E2E tests stabilised: heading verification added, module overview landing page assertions updated.

Version 0.5.0 (2026-03-09) 

Added 

  • AI-powered full-chain task wizard: describe a task in plain language, AI generates task + configuration + model recommendation in one step.
  • AI-powered configuration wizard: generate configurations with system prompts, parameters, and model selection.
  • Custom TCA ModelIdElement: input field with "Fetch Models" button that populates from provider API, auto-fills capabilities and pricing.
  • ModelConstraintsWizard: field wizard that loads parameter constraint bounds per model.
  • Dashboard improvements: side-by-side wizard callouts, fixed headline from "LLM Providers" to "LLM Integration".
  • Task execution UI: collapsible prompt details, improved result display.
  • Enhanced model discovery: better Anthropic, Google, DeepSeek, Mistral support.
  • TER publish workflow.
  • Documentation: wizards guide with screenshots, tasks section, updated configuration reference.

Changed 

  • Renamed SafeCastTrait extracted from duplicated helpers in TaskController and WizardGeneratorService.
  • SQL injection defense: regex whitelist validation for table/column names in FetchRecordsRequest and LoadRecordDataRequest.

Fixed 

  • Restored method_exists() guards for setShortcutContext() (TYPO3 v13 compatibility).
  • PHPUnit 12: replaced createStub with createMock to fix deprecation warnings.

Version 0.4.8 (2026-03-07) 

Changed 

  • Rewritten introduction with value-oriented positioning.
  • Restructured README around value proposition and audience segments.
  • Updated package metadata with value-oriented descriptions.
  • Added integration guide for extension developers.

Version 0.4.7 (2026-03-07) 

Added 

  • Help page in the LLM backend module.
  • Setup wizard links on empty-state list pages.

Fixed 

  • Use canonical endpoint URLs for known providers in setup wizard.
  • Remove container class from backend module templates.

Version 0.4.6 (2026-03-06) 

Fixed 

  • Add Fluid-compatible getHasApiKey() getter for {provider.hasApiKey} in templates.

Version 0.4.5 (2026-03-06) 

Fixed 

  • Use GET /v1/models for Anthropic connection test.

Version 0.4.4 (2026-03-06) 

Fixed 

  • Use table-specific connection and simplify column checks.
  • Wrap test cleanup in try/finally and assert labelField.

Version 0.4.3 (2026-03-06) 

Fixed 

  • Handle tables without uid column in TCA utilities.
  • Remove hardcoded temperature from chat completions.

Version 0.4.2 (2026-03-06) 

Fixed 

  • Add rootLevel to provider, configuration, and model TCA definitions.

Version 0.4.1 (2026-03-06) 

Fixed 

  • Use max_completion_tokens instead of max_tokens for OpenAI chat completions.

Version 0.4.0 (2026-03-06) 

Breaking 

  • Prevent plaintext API key storage via setup wizard; keys now require vault encryption.

Fixed 

  • Cast ExtensionConfiguration timeout values to integer.

Changed 

  • Use Symfony Uuid::v7() instead of manual UUID generation.

Version 0.3.2 (2026-03-04) 

Added 

  • Extract thinking blocks from LLM responses (<think> tag support).

Fixed 

  • Preserve newlines in extractThinkingBlocks.
  • Restrict CI push trigger to main branch only.
  • Add merge_group trigger to CI workflow.

Version 0.3.1 (2026-03-02) 

Fixed 

  • Add Overview submodule for TYPO3 v13 module overview compatibility.

Version 0.3.0 (2026-03-01) 

Added 

  • Expose chatWithConfiguration and streamChatWithConfiguration on LlmServiceManagerInterface.

Fixed 

  • Use integer values for f:be.infobox state attribute for TYPO3 v13 compatibility.
  • Explicitly enable fuzz and mutation tests.

Version 0.2.2 (2026-03-01) 

Fixed 

  • Use tools parent for TYPO3 v13 module compatibility.

Changed 

  • Consolidate caller workflows into 4 grouped files.
  • Fix documentation issues found by analysis.

Version 0.2.1 (2026-02-28) 

Changed 

  • Require netresearch/nr-vault ^0.4.0 for API key encryption.

Version 0.2.0 (2026-02-28) 

Added 

  • PHP 8.2+ and TYPO3 v13.4+ compatibility.
  • TYPO3 v13.4 ddev install command.
  • Coverage uploads and fuzz/mutation CI workflow.
  • Unit tests for enums, WizardResult DTO, providers, services, and specialized classes.
  • Coverage tests for PromptTemplateService and TranslationService.

Changed 

  • Moved phpunit.xml and phpstan-baseline.neon into Build/ directory.
  • Expanded CI matrix to PHP 8.2-8.5 and TYPO3 v13.4/v14.
  • Replaced TYPO3 v14-only APIs with v13-compatible equivalents.
  • Narrowed testing-framework to ^9.0 for PHPUnit 12 compatibility.
  • Removed dead ProviderRegistry class and orphaned phpstan baseline file.
  • Removed 55 dead translation keys.
  • Harmonized composer script naming to ci:test:php:* convention.
  • Migrated CI to centralized workflows.
  • Added SPDX copyright and license headers.
  • Replaced generic emails with GitHub references.

Fixed 

  • Resolved CI failures for PHP 8.2 and TYPO3 v13 compatibility.
  • Resolved PHPStan failures for dual TYPO3 v13/v14 support.
  • Fixed PHPUnit deprecation warnings.
  • Used CoversNothing for excluded exception and enum test classes.
  • Localized user-facing hardcoded strings in controllers.
  • Disabled functional tests in CI (environment-specific).
  • Fixed direct php-cs-fixer call in ci:test:php:cgl script.

Version 0.1.2 (2026-01-11) 

Fixed 

  • Fixed CI: use correct org secret name for TER token.
  • Simplified TER upload workflow.

Version 0.1.1 (2026-01-11) 

Fixed 

  • Fixed CI: create zip archive for TER upload.

Version 0.1.0 (2026-01-11) 

Initial release of the TYPO3 LLM Extension.

Added 

Core Features

  • Multi-provider support (OpenAI, Anthropic Claude, Google Gemini, Ollama, OpenRouter, Mistral, Groq).
  • Unified API via LlmServiceManager.
  • Provider abstraction layer with capability interfaces.
  • Typed response objects (CompletionResponse, EmbeddingResponse).
  • Three-tier configuration architecture (Providers, Models, Configurations).
  • Encrypted API key storage using sodium_crypto_secretbox.

Feature Services

  • CompletionService: Text completion with format control (JSON, Markdown).
  • EmbeddingService: Vector generation with caching and similarity calculations.
  • VisionService: Image analysis with alt-text, title, description generation.
  • TranslationService: Translation with formality control and glossary support.
  • PromptTemplateService: Centralized prompt management with database-driven templates.

Specialized Services

  • Image generation (DALL-E).
  • Text-to-speech (TTS) and speech transcription (Whisper).
  • DeepL translation integration.

Provider Capabilities

  • Chat completions across all providers.
  • Embeddings (OpenAI, Gemini).
  • Vision/image analysis (all providers).
  • Streaming responses (all providers).
  • Tool/function calling (all providers).

Infrastructure

  • TYPO3 caching framework integration.
  • Backend module for provider management and testing.
  • Prompt template management with versioning and performance tracking.
  • Comprehensive exception hierarchy.
  • Type-safe enums and DTOs for domain constants.

Developer Experience

  • Option objects with factory presets (ChatOptions).
  • Full backwards compatibility with array options.
  • Extensive PHPDoc documentation.
  • Type-safe method signatures.

Security

  • Enterprise readiness security workflows and supply chain controls.
  • SLSA Level 3 provenance, Cosign signatures, and SBOM generation.
  • OpenSSF Scorecard and Best Practices compliance.

Testing

  • Comprehensive unit and integration tests.
  • E2E testing with Playwright.
  • Property-based (fuzz) testing support.

Upgrade Guides 

Upgrading from Pre-Release 

If you used a pre-release version:

  1. Remove old extension

    Remove old extension
    composer remove netresearch/nr-llm
    Copied!
  2. Clear caches

    Clear caches
    vendor/bin/typo3 cache:flush
    Copied!
  3. Install current version

    Install current version
    composer require netresearch/nr-llm:^0.2
    Copied!
  4. Run database migrations

    Run database migrations
    vendor/bin/typo3 database:updateschema
    Copied!
  5. Update configuration

    Review your TypoScript and extension configuration for any changed keys or deprecated options.

Breaking Changes Policy 

This extension follows semantic versioning:

  • Major versions (x.0.0): May contain breaking changes
  • Minor versions (0.x.0): New features, backwards compatible
  • Patch versions (0.0.x): Bug fixes only

Breaking Changes Documentation 

Each major version will document:

  1. Removed or changed public APIs
  2. Migration steps with code examples
  3. Compatibility layer availability
  4. Deprecation timeline for removed features

Deprecation Policy 

  1. Features are marked deprecated in minor versions
  2. Deprecated features remain functional for one major version
  3. Deprecated features are removed in the next major version
  4. Migration documentation provided before removal