CopilotAIStrategy

Context-aware AI translation through any Copilot provider – batched, validated, and resilient to malformed model responses.

Selected via 'strategy' => 'ai' in the plugin config – or by passing a CopilotAIStrategy instance directly. Provider credentials stay in Kirby Copilot; this plugin never talks to an AI provider itself.

Selecting 'strategy' => 'ai' without the Copilot plugin installed throws LogicException.

Behavior

Translations come back as a schema-constrained array. Chunks where the response length doesn't match the input keep their source text and are reported as rejections. Units are packed into chunks bounded by 50 items and 100,000 bytes – a single oversized unit rides alone, never split.

The budget counts bytes, not characters. Scripts outside ASCII cost 2–4 bytes per character in UTF-8, so a Japanese or Greek page fills a chunk several times sooner than an English one.

LLM batching preserves per-item context naturally, so table cells ride along with prose.

<cN/> KirbyTag placeholders are validated after the strategy returns, so that guarantee holds for every strategy rather than this one – see KirbyTags.

Construction

public function __construct(
    Client|null $client = null,
    string|null $systemPrompt = null,
)
client
\\JohannSchopplich\\Copilot\\AI\\Client | null
Inject a Copilot client. Defaults to Client::instance().
systemPrompt
String | null
Override the system prompt for this instance. Falls back to johannschopplich.content-translator.ai.systemPrompt, then to the built-in default.

Usage

config.php
return [
    'johannschopplich.content-translator' => [
        'strategy' => 'ai',
    ],
    'johannschopplich.copilot' => [
        'provider' => 'openai',
        'providers' => [
            'openai' => ['apiKey' => env('OPENAI_API_KEY')],
        ],
    ],
];
For the full default system prompt and a copy-paste-safe customization template, see the AI Translation docs.

Drop Reasons

Each dropped unit emits a content-translator.translate:warning event with one of these reasons:

ReasonCause
<upstream error message>Upstream provider call threw (rate limit, network, auth)
response length mismatchThe AI returned more or fewer translations than units sent
non-string translationA non-string value appeared in the response array
empty translationNothing but whitespace appeared in the response array
Wire content-translator.translate:warning to logging or alerting to surface drops in production.