Skip to content

Laravel

AI assistant

Build this with Claude Code, Cursor or Copilot

Copy a Tessero-tuned prompt for Laravel, grounded in 10 real API signatures , into your IDE's AI. No chatbot, just exact context.

Packages not published yet. Tessero is not on Packagist yet and has no tagged release, so there are no prebuilt binaries. The package-name install commands on this page do not work yet. The install page has the commands that work today.

tessero/laravel connects Tessero to Laravel 12 and newer (12 and 13 today). Laravel 10 and 11 are not supported: every release on those lines is affected by security advisories that will not be fixed there.

composer require tessero/laravel
php artisan vendor:publish --tag=tessero-config     # optional
php artisan tessero:doctor

What you get

Piece Purpose
TesseroServiceProvider (auto-discovered) config, TesseroManager singleton, runtime settings, response macro, tessero:doctor
Tessero facade array, zeros, fromBytes, memmap, load, openMemmap, linprog, milp, solveMdp, normal, random, info, backend
Casts\AsNDArray (alias Casts\TensorCast) Eloquent column ⇄ array
Rules\NumericArray validates request input before it becomes an array
response()->ndarray($a) JSON response written from native memory

Backends

TESSERO_BACKEND=auto (default) uses the native extension when it is loaded and the FFI package otherwise. Arrays come back as Tessero\Ext\NDArray or Tessero\NDArray. Both have the same core API, and solver results from the facade are plain PHP arrays with the same keys on either backend, so controllers and jobs do not depend on which one is installed.

Set ext or ffi to require one. Boot then fails loudly if it is missing, which is useful in production images.

Configuration

config/tessero.php. Every key can be set from the environment:

Key Env Default Meaning
backend TESSERO_BACKEND auto auto, ext, ffi
threads TESSERO_THREADS 1 OpenMP threads for large element-wise kernels and MDP sweeps
memory_budget TESSERO_MEMORY_BUDGET 268435456 (256 MiB) native memory cap per worker, bytes; 0 = unlimited
blas_threads TESSERO_BLAS_THREADS 1 OpenBLAS threads (FFI linear algebra)
epsilon TESSERO_EPSILON 1e-6 default MDP tolerance
cast_format TESSERO_CAST_FORMAT json default storage format for casts
max_elements TESSERO_MAX_ELEMENTS 1 000 000 default cap for validation

threads, memory_budget, blas_threads and epsilon are applied at boot and re-applied at the start of every Octane request and task, and before every queued job. Long-lived workers therefore never carry one request's settings into the next. See [Memory and threads(https://github.com/DMJ-CV-91913/tessero/blob/main/docs/operations/memory-and-threads.md) before raising threads under FPM.

Eloquent casts

use Tessero\Laravel\Casts\AsNDArray;

class Forecast extends Model
{
    protected $casts = [
        'quantiles'  => AsNDArray::class,                   // JSON nested arrays
        'covariance' => AsNDArray::class . ':binary',       // exact, compact
        'features'   => AsNDArray::class . ':binary,float32',
    ];
}

$f = Forecast::find(1);
$f->covariance->shape();          // an NDArray
$f->quantiles = $q->mul(1.1);     // assign an NDArray, a PHP array, or null
$f->save();
Format Column contents Size (float64) Exact
json [[1.5, 2.0], …] ~20 bytes/value to 17 significant digits (round-trips)
binary {"dtype":"float64","shape":[24],"b64":"…"} ~10.7 bytes/value bit-exact, including NaN payloads and -0.0

Either format is read back whatever the setting, so you can switch cast_format without migrating data. Use a json or text/longtext column. toArray()/toJson() on the model serialise the attribute as nested lists.

Validating input

use Tessero\Laravel\Rules\NumericArray;

$data = $request->validate([
    'prices'  => ['required', new NumericArray(ndim: 1, maxElements: 8784)],
    'weights' => ['required', new NumericArray(shape: [null, 3])],        // n × 3
    'mask'    => ['sometimes', new NumericArray(allowBool: true)],
]);
$prices = Tessero::array($data['prices']);

The rule checks list arrays (no string keys), a rectangular shape, the dimension count or exact shape, the element cap, and that every leaf is an int or finite float. It rejects numeric strings, so use it on JSON request bodies. Form-encoded input arrives as strings and needs casting first. NumericArray::check($value, …) returns the error message (or null) outside Laravel.

Always cap maxElements on public endpoints. A request body is cheap to send, and native memory is not counted by memory_limit ([Security(https://github.com/DMJ-CV-91913/tessero/blob/main/docs/operations/security.md)).

Responses

return response()->ndarray($forecast->mean(0));                 // 200, application/json
return response()->ndarray($matrix, 201, ['X-Model' => 'v3']);

The body is written by toJson() straight from native memory.

Solvers from controllers and jobs

use Tessero\Laravel\Facades\Tessero;

$plan = Tessero::linprog(c: $c, A_ub: $A, b_ub: $b, bounds: $bounds);
if (! $plan['success']) {
    abort(422, $plan['message']);
}

$policy = Tessero::solveMdp($P, $R, gamma: 0.97)['policy'];   // 'policy_iteration' or 'value_iteration'
$draws  = Tessero::normal(seed: $scenarioId, shape: [1000, 24]);

Long solves belong in queued jobs. The provider re-applies thread and memory settings before each job.

Octane

Tessero holds no per-request global state: arrays are ordinary PHP objects freed when they go out of scope. Two things to know:

  • Do not keep large arrays in static properties or singletons unless you mean to. They stay resident for the worker's lifetime and count against its memory budget.
  • Settings are process-wide (see above); the provider resets them for each request.

Diagnostics

php artisan tessero:doctor          # backend, versions, SIMD, OpenMP, threads, memory
php artisan tessero:doctor --json   # for health checks

Testing your application

The FFI package works in any PHPUnit run with ffi.enable=1. Add it to phpunit.xml:

<php><ini name="ffi.enable" value="1"/></php>

To force a backend in tests set TESSERO_BACKEND in phpunit.xml <env>.

Edit this page on GitHub