jev / jev-laravel
Framework-agnostic Jev PHP SDK with first-class Laravel integration.
Requires
- php: >=8.2
- illuminate/http: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
- phpunit/phpunit: ^10.5|^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
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.