Search by

jev / jev-laravel

abenojardev

Framework-agnostic Jev PHP SDK with first-class Laravel integration.

dev-main 2026-09-24 05:00 UTC

This package is auto-updated.

Last update: 2026-09-24 05:03:56 UTC


README

Thin, typed PHP client for Jev decision requests. The core client has no Laravel dependency in its API; the Laravel adapter adds container binding, config, a facade, HTTP transport, and a network-free fake.

Requirements

  • PHP 8.2+
  • Laravel 11 or 12 for the Laravel integration

Installation

composer require jev/jev-laravel
php artisan vendor:publish --tag=jev-config

Set credentials in .env:

JEV_API_KEY=your-api-key
JEV_BASE_URL=https://api.jev.dev
JEV_TIMEOUT=5
JEV_CONNECT_TIMEOUT=2
JEV_RETRIES=1

The service provider is auto-discovered. The published config is the source of truth for transport settings.

Laravel usage

The contract is the primary API and can be injected into any service:

use Jev\Contracts\JevClient;
use Jev\DTO\Question;

final class DecideBookingRoute
{
    public function __construct(private JevClient $jev) {}

    public function handle(array $state)
    {
        return $this->jev->decide($state, [
            Question::make('needs_tool', 'Does this require a tool?')->boolean(),
            Question::make('route', 'Which route should handle this?')->enum(['respond', 'clarify', 'tool']),
        ]);
    }
}

$result = app(DecideBookingRoute::class)->handle([
    'workflow' => 'enquiry',
    'stage' => 'awaiting_confirmation',
    'user_message' => 'Yes',
]);

$route = $result->get('route')->string();

The facade supports fluent requests:

use Jev\Laravel\Facades\Jev;

$result = Jev::state(['stage' => 'awaiting_confirmation'])
    ->ask('confirm', 'Is this a confirmation?')->boolean()
    ->ask('confidence', 'Confidence')->number(0, 1)
    ->run();

Supported question types are boolean(), string(), number(min, max), and enum([...]). Keys are application-owned and are used to address results:

$confirmed = $result->get('confirm')->boolean();
$raw = $result->get('confidence')->value();

Plain PHP

Implement the transport contract with your HTTP client of choice, then construct the framework-agnostic client:

use Jev\Contracts\Transport;
use Jev\DTO\JevRequest;
use Jev\Jev;

$transport = new class implements Transport {
    public function send(JevRequest $request): array
    {
        // Send $request->toArray() and return status, lowercase headers, and decoded body.
    }
};

$client = new Jev($transport);

Errors and safety

Catch Jev\Exceptions\JevException or its specific subclasses: AuthenticationException, RateLimitException, TimeoutException, TransportException, and ValidationException. Exceptions expose safe metadata such as status, request ID, error code, and retry-after; API keys and request bodies are never included.

State is caller-owned. The SDK does not persist, mutate, summarize, or log it. Retries are configurable and apply only to transport failures and rate limits; permanent validation and authentication responses are not retried.

Testing

Use the fake in Laravel tests:

use Jev\Contracts\JevClient;
use Jev\Laravel\Testing\JevFake;

$fake = new JevFake(['needs_tool' => true, 'route' => 'tool']);
$this->app->instance(JevClient::class, $fake);

// Run application code, then:
$fake->assertAsked('needs_tool');
$fake->assertAsked('route');

For state-dependent tests, use $fake->respondUsing(fn ($request) => ['route' => $request->state['route']]);. The fake never performs network requests.

Run the package tests with:

composer install
composer test

API shape

The adapter sends POST {base_url}/v1/decide with state and normalized questions. It accepts a response containing a results map (or the compatibility alias answers), optional usage, meta, and request_id. This wire format is intentionally hidden behind DTOs so Jev API evolution does not leak into application code.

Scope

This package is an SDK and Laravel adapter. Conversation memory, thread persistence, queues, RAG/prompt storage, long-term user memory, and replacements for Laravel's queue/cache/database/HTTP systems belong in the host application or a separate package.