Client
Generate AI content from PHP with one method call. The Client resolves your configured provider from johannschopplich.copilot options and dispatches text or structured-output requests – reaching the same providers with the same credentials as the Panel, over its own server-side transport.
use JohannSchopplich\Copilot\AI\Client;
$result = Client::instance()->generateObject(
messages: [
['role' => 'user', 'content' => "What's 2+2?"],
],
schema: ['type' => 'object', 'properties' => ['answer' => ['type' => 'integer']], 'required' => ['answer']],
);
Construction
use JohannSchopplich\Copilot\AI\Client;
$client = Client::instance();
The singleton reads johannschopplich.copilot options once and reuses them until you call Client::reset().
use JohannSchopplich\Copilot\AI\Client;
use JohannSchopplich\Copilot\AI\Resolver;
$client = new Client(
resolver: Resolver::fromKirbyOptions(),
);
A fresh resolution against changed config – useful when options are swapped at runtime, for example in tests.
use JohannSchopplich\Copilot\AI\Client;
use JohannSchopplich\Copilot\AI\Providers\OpenAIProvider;
use JohannSchopplich\Copilot\AI\ProviderConfig;
$provider = new OpenAIProvider(new ProviderConfig(
apiKey: 'sk-test-xxx',
model: 'gpt-5.6-luna',
));
$client = new Client(providerOverride: $provider);
Bypass the resolver entirely. Intended for tests and one-off scripts.
Methods
generateObject
public function generateObject(array $messages, array $schema): array
system message is forwarded – Anthropic concatenates them into its top-level system field, while the OpenAI-compatible providers pass the list through unchanged.Returns the decoded JSON response as an associative array. Throws ProviderException on any failure.
generateText
public function generateText(array $messages): string
system message is forwarded – Anthropic concatenates them into its top-level system field, while the OpenAI-compatible providers pass the list through unchanged.Returns the response text as a plain string. Throws ProviderException on any failure.
requireApiKey
public function requireApiKey(): void
Asserts that the configured default provider has an API key. Throws Kirby\Exception\AuthException with a message pointing to the missing config path. Useful as a preflight before kicking off a long batch operation.
The check applies to the resolved default provider only. A client constructed with an explicit provider instance returns early, since that provider carries its own credentials – the key check then happens on the first request.
reset (static)
public static function reset(): void
Clear the cached singleton. Call this in tests that swap config between cases.
Error Handling
use JohannSchopplich\Copilot\AI\Client;
use JohannSchopplich\Copilot\AI\Exception\ProviderException;
use Kirby\Exception\AuthException;
try {
$client = Client::instance();
$client->requireApiKey();
$result = $client->generateObject($messages, $schema);
} catch (AuthException $error) {
// Missing API key
} catch (ProviderException $error) {
// Upstream failure – $error->getDetails() carries provider/model/response context
}
Forcing a Provider for One Call
The resolver always dispatches to the provider set at johannschopplich.copilot.provider. To force a different one for a single call, use providerOverride:
use JohannSchopplich\Copilot\AI\Client;
use JohannSchopplich\Copilot\AI\Providers\AnthropicProvider;
use JohannSchopplich\Copilot\AI\Resolver;
use JohannSchopplich\Copilot\AI\ProviderName;
$config = Resolver::fromKirbyOptions()->forProvider(ProviderName::Anthropic);
$client = new Client(providerOverride: new AnthropicProvider($config));
$result = $client->generateObject($messages, $schema);
Use From a Sister Plugin
The Copilot AI strategy in Content Translator is a working example of consuming Client::generateObject() from another plugin. See the AI Strategy CLI script for a complete page-translation workflow that selects the AI strategy at call time.