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 Model — never a concrete provider, model, or
API key. The imported record runs in criteria selection mode, so
Model resolves the actual model on every run
against whatever the admin has configured.
Declaring presets in your extension
Implement Configuration. The
nr_llm.configuration_preset DI tag is applied automatically when your
extension's Services. 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,
),
),
];
}
}
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
Llm.
Import flow
- 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). - The admin confirms one import (AJAX route
nrllm_preset_importwith the presetidentifier). nr_llm creates an active, criteria-modetx_nrllm_configurationrecord and stores the preset's checksum inpreset_checksum. - 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). A backend-module UI on top of these endpoints is a planned follow-up.