Configuration presets 

A consuming extension can declare the LlmConfiguration records it needs as configuration presets. nr_llm lists declared-but-not-yet imported presets as pending; a backend admin imports one with a single confirmation. See ADR-056 for the design rationale.

A preset expresses requirements — model capabilities and constraints as ModelSelectionCriteria — never a concrete provider, model, or API key. The imported record runs in criteria selection mode, so ModelSelectionService resolves the actual model on every run against whatever the admin has configured.

Declaring presets in your extension 

Implement ConfigurationPresetProviderInterface. The nr_llm.configuration_preset DI tag is applied automatically when your extension's Services.yaml has autoconfigure: true (the TYPO3 default):

<?php

declare(strict_types=1);

namespace Vendor\NrAiSearch\Integration;

use Netresearch\NrLlm\Domain\DTO\ModelSelectionCriteria;
use Netresearch\NrLlm\Service\Preset\ConfigurationPreset;
use Netresearch\NrLlm\Service\Preset\ConfigurationPresetProviderInterface;

final class AiSearchPresetProvider implements ConfigurationPresetProviderInterface
{
    public function getPresets(): array
    {
        return [
            new ConfigurationPreset(
                identifier: 'nr_ai_search.chat',
                name: 'AI Search Chat',
                description: 'Answers site-search questions with tool support.',
                criteria: new ModelSelectionCriteria(
                    capabilities: ['chat', 'tools'],
                    minContextLength: 8000,
                ),
                systemPrompt: 'You answer questions about this website.',
                temperature: 0.2,
                maxTokens: 2000,
            ),
            new ConfigurationPreset(
                identifier: 'nr_ai_search.embedding',
                name: 'AI Search Embeddings',
                description: 'Creates embeddings for the search index.',
                criteria: new ModelSelectionCriteria(
                    capabilities: ['embedding'],
                    preferLowestCost: true,
                ),
            ),
        ];
    }
}
Copied!

Rules the value object enforces at construction time:

  • The identifier is lowercase [a-z0-9_] segments separated by dots and must be namespaced with your extension key (nr_ai_search.chat) so presets from different extensions cannot collide. Duplicate identifiers across providers fail fast at container build time.
  • The criteria must require at least one capability.

All other fields (system prompt, temperature, max tokens, the daily budget ceilings maxRequestsPerDay / maxTokensPerDay / maxCostPerDay, allowedToolGroups) are optional seeds; null keeps the column default of the created record.

At runtime, resolve the imported configuration by its identifier as usual, for example through LlmConfigurationServiceInterface.

Import flow 

  1. The admin queries the pending presets (AJAX route nrllm_preset_list). Each entry carries a preflight result: whether the criteria currently match an active model (satisfiable + matchedModelLabel), or which requirement eliminates every candidate (missingRequirement).
  2. The admin confirms one import (AJAX route nrllm_preset_import with the preset identifier). nr_llm creates an active, criteria-mode tx_nrllm_configuration record and stores the preset's checksum in preset_checksum.
  3. The record is a normal configuration from then on — the admin can edit or delete it. A preset whose identifier already has a record is never offered again (and an import attempt is refused), so imports are idempotent; the stored checksum makes a changed declaration detectable.

Both endpoints are restricted to backend administrators (ADR-037). Admins normally go through the Configurations backend module, which renders the pending presets — including each preflight result — above the configuration records and imports one through nrllm_preset_import with a single click; see Importing configuration presets.

Change detection 

nrllm_preset_list additionally returns a drifted list: imported presets whose current declaration checksum no longer matches the preset_checksum stored at import time. Each entry carries identifier, name, and configurationUid. The Configurations module flags such records with a non-blocking "Preset changed" hint.

Detection only: nr_llm never updates an imported record automatically. If your extension changes a preset declaration, document what admins should adjust — the checksum-driven update flow (diff + re-confirm) is deliberately deferred (ADR-056).