Luminova Framework

PHP Luminova: AI Client Base Abstract Class

Last updated: 2026-03-18 10:14:20

Using the Luminova Base AI class, to integrate AI functionalities into your applications, enhancing the capabilities and providing users with advanced AI-powered features.

The Luminova Base AI client (Luminova\Base\AI) is the abstract foundation that all AI provider clients extend. It provides shared utilities for option management, request building, response parsing, and model resolution, so individual clients only need to implement provider-specific logic.


Configuration

Configure default AI clients and behavior via AI Client Configuration.


Available Clients

Luminova ships with ready-to-use AI client classes that extend the base:

  • OpenAI Client – Text generation, embeddings, images, TTS, audio, and fine-tuning via the OpenAI API.
  • Ollama Client – Local or remote open-source model support via the Ollama API.
  • Anthropic Client – Claude model family including batch processing via the Anthropic API.

Integrations

This guide explains how to create a custom AI client provider that integrates natively with the Luminova AI system. By extending Luminova\Base\AI and implementing Luminova\Interface\AIClientInterface, your client becomes usable anywhere the built-in OpenAI, Ollama, or Anthropic clients are used, including the AI helper, the singleton, and the client registry.


Architecture Overview

The Luminova AI stack has three layers:

AIClientInterface          ← Contract: defines every public method
       ↑
Luminova\Base\AI           ← Abstract base: shared HTTP, options, parsing utilities
       ↑
Your\Client\MyProvider     ← Concrete: provider-specific request/response logic

Your client only needs to handle what the provider's API actually does differently. Everything else like option merging, model resolution, user injection, error normalization, endpoint URL building, fluent chaining is already implemented in the base class and inherited for free.


Create the Client Class

Place your client under any namespace you like. Extend Luminova\Base\AI and declare the two required protected properties: $url and $endpoints.

// /app/Ai/Client/MyProvider.php

namespace App\AI\Client;

use Luminova\Base\AI;
use Luminova\Http\Client\Novio;

class MyProvider extends AI
{
    /**
     * Base API URL for MyProvider.
     * Must end with a trailing slash.
     */
    protected string $url = 'https://api.myprovider.io/v1/';

    /**
     * Named endpoint map.
     * Keys are logical names used when calling $this->endpoint().
     * Values are the URL path segments relative to $url.
     */
    protected array $endpoints = [
        'chat'       => 'chat/completions',
        'models'     => 'models',
        'embeddings' => 'embeddings',
    ];

    public function __construct(string $apiKey)
    {
        $this->http = new Novio([
            'headers' => [
                'Authorization' => 'Bearer ' . $apiKey,
                'Content-Type'  => 'application/json',
            ],
        ]);
    }
}

The endpoint() helper appends path segments directly to $url .

$endpoints is an associative map of logical names to URL path segments. Add an entry for every endpoint your client calls. Endpoint names are arbitrary, just be consistent with what you pass to $this->endpoint().


Understand What the Base Provides

Before overriding anything, be aware of what Luminova\Base\AI already does for you. You only need to override what the base default behavior does not cover.

MethodBase behaviorOverride when
generate()Delegates to message()Your API has a dedicated completion endpoint
message()Calls chat(['role'=>'user','content'=>$prompt])Rarely needed
chat()Not implemented — returns []Always — this is the core method
vision()Not implemented — returns []Provider supports multimodal input
embed()Not implemented — returns []Provider supports embeddings
image()Returns falseProvider supports image generation
speech()Returns falseProvider supports TTS
audio()Returns falseProvider supports audio transcription
webSearch()Returns []Provider supports web search
models()Calls __models()Only if your models endpoint differs
model()Calls __models($name)Only if your model detail endpoint differs
fineTune()Returns []Provider supports fine-tuning
fineTuneDataset()Returns []Provider supports fine-tuning
fineTuneStatus()Returns []Provider supports fine-tuning
setBaseUrl()Updates $this->urlNever — inherited as-is
setModel()Updates $this->modelNever — inherited as-is
user()Updates $this->user + optionsNever — inherited as-is

Implement Client Method Logic

Client methods should follow a consistent structure by using the helpers provided in the base class. This ensures predictable behavior across all AI clients.

public function method(array|string $messages, array $options = []): array
{
    // Build full endpoint URL
    $url = $this->endpoint(
        'chat', 
        suffix: '' // Optional URI suffix
    );

    // Normalize string input as required via provider
    if (is_string($messages)) {
        $messages = [['role' => 'user', 'content' => $messages]];
    } elseif (isset($messages['role'])) {
        $messages = [$messages];
    }

    // Attach messages payload as needed
    $options['messages'] = $messages;

    // Merge caller options with instance defaults ($this->model, $this->user, etc.)
    // This allow method like clearOptions(), getOptions() to work consistently
    $this->parseOptions($options);

    $finalOption = ['body' => $this->options]; 

    // Attach custom headers if defined
    if($this->headers){
        $finalOption['headers'] => $this->headers;
    }

    // Send API HTTP request
    $res = $this->send(
        'POST',         // HTTP method
        $url,           // Full API URL
        $finalOption    // Full HTTP client options
    );

    // Normalize response if need to
    return $res;
}

Key helpers available inside any method

HelperPurpose
$this->endpoint(')Builds the full URL using $this->url, endpoint mapping, and optional suffix
$this->parseOptions()Merges input options with defaults and injects model/user if missing
$this->send()Sends the HTTP request and returns a decoded response
$this->toResponse()Handles JSON/NDJSON decoding and throw AIException on API errors
$this->eHandler()Normalizes exceptions into AIException (keeps LuminovaException unchanged)
$this->headersPer-request headers
$this->optionsAccumulated request options (populated by parseOptions())
$this->modelDefault model set via setModel()
$this->httpThe underlying HTTP client instance

Full Example Client

Below is a complete, realistic custom client for a fictional provider called MyProvider.

// /app/Ai/Client/MyProvider.php

namespace App\AI\Client;

use Luminova\Base\AI;
use Luminova\Http\Client\Novio;

class MyProvider extends AI
{
    protected string $url = 'https://api.myprovider.io/v1/';

    protected array $endpoints = [
        'chat'       => 'chat/completions'
    ];

    public function __construct(
        string $apiKey,
        ?string $organization = null
    ) {
        $headers = [
            'Authorization' => 'Bearer ' . $apiKey,
            'Content-Type'  => 'application/json',
        ];

        if ($organization !== null) {
            $headers['X-Organization'] = $organization;
        }

        $this->http = new Novio(['headers' => $headers]);
    }

    public function chat(array|string $messages, array $options = []): array
    {
        $url = $this->endpoint('chat');

        if (is_string($messages)) {
            $messages = [['role' => 'user', 'content' => $messages]];
        } elseif (isset($messages['role'])) {
            $messages = [$messages];
        }

        $options['messages'] = $messages;
        $options['model']  ??= $this->model ?? 'my-chat-model';

        $this->parseOptions($options);
        $finalOption = ['body' => $this->options]; 

        if($this->headers){
            $finalOption['headers'] => $this->headers;
        }

        $res = $this->send('POST', $url, $finalOption);

        return $res['choices'][0]['message'] ?? [];
    }
}

Register Custom Client

use App\AI\Client\MyProvider;

$client = new MyProvider(env('MY_PROVIDER_KEY'));
$reply  = $client->message('Hello from MyProvider!');

Register Via AI Named Registry

use Luminova\AI\AI;
use App\AI\Client\MyProvider;

// Register a live instance
AI::register('myprovider', new MyProvider(env('MY_PROVIDER_KEY')));

// Access via static magic call
$reply = AI::Myprovider()->message('Hello!');

// Or via AI::client()
$reply = AI::client('myprovider')->message('Hello!');

Register Via the AI Singleton

use Luminova\AI\AI;
use App\AI\Client\MyProvider;

AI::getInstance(new MyProvider(env('MY_PROVIDER_KEY')))
    ->message('Using MyProvider on the singleton.');

As the App Default (Config)

To make your client the application-wide default without modifying the AI helper, register it before the first call for example in a service provider, bootstrap file or application/controller's onCreate method:

use Luminova\AI\AI;
use App\AI\Client\MyProvider;

AI::register('myprovider', new MyProvider(env('MY_PROVIDER_KEY')));

Then in App\Config\AI:

// /app/Config/AI.php

public string $handler = 'myprovider';

Common Mistakes

Not calling parseOptions() before send()

Without this call, $this->model, $this->user, and any fluent options set via ->temperature(0.7) will not be merged into the request body.

// Wrong — skips model/user injection
$this->options = $options;
$res = $this->send('POST', $url, ['body' => $this->options]);

// Correct
$this->parseOptions($options);
$res = $this->send('POST', $url, ['body' => $this->options]);

Not normalizing string input in chat()

The interface contract allows chat() to receive a plain string, a single message array, or a full messages array. All three must be handled.

if (is_string($messages)) {
    $messages = [['role' => 'user', 'content' => $messages]];
} elseif (isset($messages['role'])) {
    $messages = [$messages];
}

Returning raw provider response instead of a content array

Every method must return a normalized content array, not the raw JSON structure. Callers including the AI manager, expect consistent output regardless of the underlying provider.

// Wrong — exposes provider-specific structure
return $res;

// Correct — extract and return the content
return $res['choices'][0]['message'] ?? [];

Class Definition

Properties

options

AI client options.

protected array<string,mixed> $options = [];

headers

HTTP client headers.

protected array<string,mixed> $headers = [];

http

HTTP client instance.

protected Psr\Http\Client\ClientInterface|Luminova\Http\Client\Novio|null $http = null;

url

AI Client API Base URL.

protected string $url = '';

endpoints

AI client API URI endpoint names and their URL path segments.

protected array<string,string> $endpoints = [];

model

Default model used when none is specified per-request.

protected ?string $model = '';

user

Default user ID used when none is specified per-request.

protected string|int $user = '';

Methods

constructor

Initialize Base AI client constructor.

public __construct()

__call

Dynamically set a request option using a fluent method call.

Any undefined method invoked on the instance will be treated as anoption name and stored in the default request options.

public __call(string $name, array $arguments): static

Parameters:

ParameterTypeDescription
$namestringThe option name being set.
$argumentsarrayOption value arguments.

Return Value:

static - Returns the current instance.


__models

Retrieve available models or details for a specific model.

This method adapts the request based on the AI client implementation.Standard providers (such as OpenAI or compatible APIs) use a GETrequest to list models or retrieve a specific model by name.

When $name is null, a list of available models is returned.When $name is provided, details for the specified model are returned.

protected __models(?string $name = null): array

Parameters:

ParameterTypeDescription
$namestring|nullOptional model name. If provided, the method
returns details for that specific model.

Return Value:

array - Returns an array of models when $name is null,otherwise returns the model details.

Throws:

See Also:

  • Luminova\Base\self::model() - For specific method details.
  • Luminova\Base\self::models() - For list of all models.

getHeaders

Retrieve all client HTTP headers.

public getHeaders(): array<string,mixed>

Return Value:

array<string,mixed> - Return an associative array of HTTP headers.


header

Set AI client specific API request header.

public header(string $name, mixed $value): static

Parameters:

ParameterTypeDescription
$namestringThe header name.
$valuemixedThe header value.

Return Value:

static - Returns the current instance.


headers

Sets AI client specific API request headers at once.

public headers(array<string,mixed> $headers): static

Parameters:

ParameterTypeDescription
$headersarray<string,mixed>The array headers key-value.

Return Value:

static - Returns the current instance.

Note:This replaces the old headers with new value if already exists


option

Explicitly set a request option.

This method provides a direct and IDE-friendly way to definerequest parameters when the option name is dynamic or whenavoiding the magic method.

public option(string $name, mixed $value): static

Parameters:

ParameterTypeDescription
$namestringThe option name.
$valuemixedThe option value.

Return Value:

static - Returns the current instance.


options

Retrieve all AI request options.

public options(): array<string,mixed>

Return Value:

array<string,mixed> - Returns the current AI client options.


clearOptions

Clear all AI client options.

This ensures options are cleared before reusing same object.

public clearOptions(): static

Return Value:

static - Returns the current instance.


clearHeaders

Clear all custom API request headers.

This ensures headers are cleared before reusing same object.

public clearHeaders(): static

Return Value:

static - Returns the current instance.

See Also:

  • Luminova\Base\self::clearOptions() - To clear options.

setBaseUrl

Set the client's API base URL.

Useful when targeting a self-hosted or proxied endpoint insteadof the client's default public API URL.

public setBaseUrl(string $baseurl): static

Parameters:

ParameterTypeDescription
$baseurlstringFully-qualified base URL (e.g. http://localhost:11434/api/).

Return Value:

static - Returns instance of client class.


setModel

Set the default model for all subsequent AI requests.

When set, this model will be used unless overridden via $options['model']in individual method calls.

public setModel(\BackedEnum|Luminova\AI\Model<\BackedEnum>|string $model): static

Parameters:

ParameterTypeDescription
$model\BackedEnum|Luminova\AI\Model<\BackedEnum>|stringModel identifier or enum model
(e.g, Model::GPT_4_1_MINI or gpt-4.1-mini).

Return Value:

static - Returns instance of client class.


user

Set the default user ID for all subsequent AI requests.

When set, this user will be used unless overridden via $options['user']in individual method calls.

public user(string|int $user): static

Parameters:

ParameterTypeDescription
$userstring|intThe request users identifier.

Return Value:

static - Returns instance of client class.


generate

Generate a text completion for a given prompt.

Sends a single prompt string and returns the generated response.Internally delegates to message() or the client's nativecompletion endpoint.

public generate(string $prompt, array $options = []): array

Parameters:

ParameterTypeDescription
$promptstringThe input prompt to complete.
$optionsarrayOptional request parameters.
@type string model Model identifier. Default varies by client.
@type float temperature Sampling temperature (0–2). Default 0.7.
@type int max_tokens Maximum tokens to generate. Default 1024.
@type float top_p Nucleus sampling probability (0–1). Default 1.0.

Return Value:

array - Generated completion output.

Throws:


chat

Send a chat conversation and receive a reply.

Accepts either a pre-built messages array (multi-turn) or a rawstring (treated as a single user message). All clients normalizethe input into the format their API expects.

public chat(array|string $messages, array<string,mixed> $options = []): array

Parameters:

ParameterTypeDescription
$messagesarray|stringSingle user message string, a single message
associative array (['role' => 'user', 'content' => '...']),
or a full conversation array of message objects.
$optionsarray<string,mixed>Optional request parameters.
@type string model Model identifier.
@type float temperature Sampling temperature.
@type int max_tokens Maximum tokens in the reply.
@type string user End-user identifier for abuse monitoring.

Return Value:

array - The assistant's reply message(s).

Throws:


message

Send a single user message and receive a reply.

Convenience wrapper around chat() for simple single-turn interactions.

public message(string $prompt, array $options = []): array

Parameters:

ParameterTypeDescription
$promptstringThe user message to send.
$optionsarrayOptional request parameters (see chat()).

Return Value:

array - The assistant's reply message(s).

Throws:


image

Generate images or edit image from a text prompt.

Returns an array of image URLs or base64-encoded image data dependingon the response_format option, or false if the client does notsupport image generation (e.g. Ollama).

Sends a source image (and an optional mask) together with a prompt sothe model can modify only the designated area.

public image(string $prompt, array $options = []): array|false

Parameters:

ParameterTypeDescription
$promptstringDescriptive text prompt for the image.
$optionsarrayOptional request parameters.
@type string model Image model (e.g. gpt-image-1, dall-e-3).
@type string size Image dimensions (e.g. 1024x1024). Default 1024x1024.
@type string response_format Output format: url or b64_json. Default url.
@type int n Number of images to generate. Default 1.
@type array edits
@type string image Absolute path to the source image (PNG, max 4 MB).
@type string mask Absolute path to the mask image (PNG, max 4 MB, transparent areas are edited).

Return Value:

array|false - Array of image result objects, or false if unsupported.

Throws:


vision

Send one or more images with a text prompt for visual analysis.

It builds a multimodal user message containing image content blocks followedby the text prompt.

Each entry in $images accepts one of:

  • A URL string (https://…) — sent as {"type":"url","url":"…"}
  • An absolute local file path — base64-encoded and sent as{"type":"base64","media_type":"…","data":"…"}
  • A pre-built content block array (passed through unchanged)
public vision(string $prompt, string|string[] $images, array $options = []): array

Parameters:

ParameterTypeDescription
$promptstringText instruction for the model.
$imagesstring|string[]Image URL(s), file path(s), or pre-built blocks.
$optionsarrayOptional request parameters (see chat()).

@type string model Model identifier. Default claude-opus-4-6.
@type int max_tokens Max tokens. Default 1024.

Return Value:

array - The assistant's content array.

Throws:


embed

Generate a vector embedding for the given text input.

Embeddings are dense numeric vector representations of text, usefulfor semantic search, clustering, RAG (retrieval-augmented generation),and recommendation systems. Pass a string for a single embedding or anarray of strings for batch embeddings.

public embed(string|array $input, array $options = []): array

Parameters:

ParameterTypeDescription
$inputstring|arrayA single text string or an array of text strings.
$optionsarrayOptional request parameters.

Return Value:

array - Flat float array for single input, or array of float arrays for batch input.

Throws:


speech

Convert text to speech and save to a local file.

Returns the public URL of the saved audio file on success.Returns false if the client does not support TTS (e.g. Ollama).

public speech(string $text, array $options = []): string|false

Parameters:

ParameterTypeDescription
$textstringThe text to convert to audio.
$optionsarrayOptional request parameters.
@type string voice Voice identifier: alloy, echo, fable, onyx, nova, shimmer. Default alloy.
@type float speed Playback speed (0.25–4.0). Default 1.0.
@type string response_format Audio format: mp3, opus, aac, flac, wav, pcm. Default mp3.
@type string path Directory path to save the audio file. Default writeable/ai/speech.
@type string symlink Optional public directory path for a symbolic link to the saved file.

Return Value:

string|false - Absolute URL to the saved file, or false on failure/unsupported.

Throws:


audio

Transcribe or translate audio to text.

Sends an audio file to the client's transcription endpoint andreturns the recognized text. Returns false if the client doesnot support audio transcription (e.g. Ollama).

public audio(string $prompt, string $filename, array $options = []): string|false

Parameters:

ParameterTypeDescription
$promptstringOptional context hint to guide transcription accuracy.
$filenamestringAbsolute path to the local audio file.
$optionsarrayOptional request parameters.

@type string model Transcription model (e.g. whisper-1). Default whisper-1.
@type string language BCP-47 language code for the audio (e.g. en). Default auto-detect.
@type string response_format Output format: json, text, srt, vtt. Default json.
@type float temperature Sampling temperature. Default 0.

Return Value:

string|false - Transcribed text on success, false on failure/unsupported.

Throws:


models

Retrieve a list of available models.

public models(): array

Return Value:

array - Array of model objects (list).

Throws:


model

Retrieve detailed information about a specific model.

public model(string $name): array

Parameters:

ParameterTypeDescription
$namestringModel identifier.

Return Value:

array - Model detail array.

Throws:


webSearch

Perform a web search and return AI-augmented results.

The client queries the web and returns a structured response thatmay include cited sources, snippets, or a synthesized answer.

public webSearch(string $query, array $options = []): array

Parameters:

ParameterTypeDescription
$querystringThe search query string.
$optionsarrayOptional client-specific parameters.
@type string model Model identifier (OpenAI: uses built-in web_search_preview tool).
@type int limit Maximum number of results to return (Ollama-specific).

Return Value:

array - Search results or AI-synthesized answer array.

Throws:


fineTune

Fine-tune a model with a custom dataset.

Submits a training job to the client using either an uploadedfile ID (OpenAI) or a raw modelfile/dataset path (Ollama). Thereturned array contains the job details, which can be polled viafineTuneStatus().

public fineTune(string $model, string $dataset, array $options = []): array

Parameters:

ParameterTypeDescription
$modelstringSuffix or display name for the resulting fine-tuned model.
$datasetstringTraining file path, raw modelfile content, or uploaded file ID.
$optionsarrayOptional training parameters.
@type string model Base model to fine-tune (e.g. gpt-4.1-mini, llama3).
@type int n_epochs Training epochs. Default auto.
@type string suffix Custom suffix appended to the fine-tuned model name.
@type bool auto_delete_file Automatically delete the training file after upload (default false).
@type string system System prompt to embed in the modelfile (Ollama only).

Return Value:

array - Fine-tuning job response or model creation result.

Throws:


fineTuneDataset

Prepare and submit a structured dataset array for fine-tuning.

Converts a high-level [input => ..., output => ...] array into theclient's native training format (JSONL for OpenAI, Modelfile for Ollama),writes it to a temporary file, and calls fineTune() automatically.

public fineTuneDataset(array $dataset, array $options = []): array

Parameters:

ParameterTypeDescription
$datasetarray<int,array{input: string, output: string}>Training examples.
$optionsarrayOptional training parameters (see fineTune()).

@type string suffix Suffix for the fine-tuned model name. Default fine-tuned.
@type string model Base model identifier.
@type string system System prompt (Ollama only).

Return Value:

array - Fine-tuning job response (see fineTune()).

Throws:


fineTuneStatus

Poll the status of a fine-tuning job.

public fineTuneStatus(string $jobId): array

Parameters:

ParameterTypeDescription
$jobIdstringThe fine-tuning job ID returned by fineTune() or
the model name to check (Ollama).

Return Value:

array - Status response. Contains at minimum a status key(queued, running, succeeded, failed for OpenAI;building or ready for Ollama).

Throws:


send

Send HTTP request to AI client API,

protected send(string $method, string $url, array<string,mixed> $finalOptions): array

Parameters:

ParameterTypeDescription
$methodstringThe HTTP request method.
$urlstringThe full API request URL.
$finalOptionsarray<string,mixed>The HTTP client options built for AI client.

Return Value:

array - Return http request API response array.

Throws:


endpoint

Build the full URL for a named endpoint.

protected endpoint(string $name, string $suffix = ''): string

Parameters:

ParameterTypeDescription
$namestringThe endpoint URI name from $this->endpoints.
$suffixstringOptional URL path suffix appended after endpoint segment (e.g, foo/bar).

Return Value:

string - Fully-qualified endpoint URL.

Throws:


toResponse

Decode the HTTP response body into an associative array.

Supports both standard JSON and newline-delimited JSON (NDJSON) streams.Automatically strips SSE-style data: prefixes and ignores empty lines.Invalid JSON lines are skipped, or optionally collected as raw entries.

protected toResponse(Psr\Http\Message\ResponseInterface $res): array

Parameters:

ParameterTypeDescription
$resPsr\Http\Message\ResponseInterfaceRaw HTTP response.
$parseRawboolWhether to capture non-JSON lines under a __raw key.

Return Value:

array - The normalized response data.

Throws:


toModelFile

Convert a structured dataset array into Modelfile directive lines.

public static toModelFile(array<string,mixed> $dataset): string

Recognizes three top-level keys:

  • parametersPARAMETER name value lines
  • templatesTEMPLATE value lines
  • messagesMESSAGE role content lines

Any other key is written as key value verbatim.

Parameters:

ParameterTypeDescription
$datasetarray<string,mixed>Structured dataset to serialize.

Return Value:

string - Modelfile content string (no leading/trailing whitespace).

Throws:


parseOptions

Parse the base parameter array for an AI request.

protected parseOptions(array $options = []): void

Merges sensible $this->options with caller-supplied $options.

Parameters:

ParameterTypeDescription
$optionsarrayCaller-supplied options.

eHandler

Normalize and re-throw exceptions from API calls.

protected eHandler(\Throwable $e): never

LuminovaException, other classes are re-thrown as Luminova\Exceptions\AIException.

Parameters:

ParameterTypeDescription
$e\ThrowableThe caught exception.

Throws: