PHPackages                             juzhax/ai-client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. juzhax/ai-client

ActiveLibrary

juzhax/ai-client
================

Framework-independent PHP SDK for the Justin AI Platform REST API.

v1.1.2(1mo ago)020MITPHPPHP ^8.3

Since Jul 14Pushed 1mo agoCompare

[ Source](https://github.com/juzhax/ai-client)[ Packagist](https://packagist.org/packages/juzhax/ai-client)[ RSS](/packages/juzhax-ai-client/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (5)Versions (5)Used By (0)

Juzhax AI Client
================

[](#juzhax-ai-client)

A framework-independent PHP 8.3+ SDK for the [Justin AI Platform](https://ai.justin.my) REST API. It talks only to the AI Platform and never directly to an underlying AI provider.

Installation
------------

[](#installation)

```
composer require juzhax/ai-client
```

Install any PSR-18 client and PSR-17 implementation. Guzzle is one option:

```
composer require guzzlehttp/guzzle
```

Configuration
-------------

[](#configuration)

```
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Psr7\HttpFactory;
use Juzhax\AiClient\ApiKey;
use Juzhax\AiClient\Client;
use Juzhax\AiClient\Config;

$factory = new HttpFactory();
$config = new Config(
    baseUrl: 'https://ai.justin.my',
    apiKey: new ApiKey($_ENV['AI_PLATFORM_KEY']),
    timeout: 30,
    userAgent: 'my-app/1.0',
    retry: 2,
);

$client = new Client(
    config: $config,
    httpClient: new GuzzleClient(['timeout' => $config->timeout]),
    requestFactory: $factory,
    streamFactory: $factory,
);
```

PSR-18 does not define a portable per-request timeout option. Set the configured `timeout` on your chosen PSR-18 implementation, as shown above. The SDK remains independent of that implementation.

Every request sends bearer authentication plus `Accept: application/json`, `Content-Type: application/json`, and the configured `User-Agent`. Retries apply only to 429, 502, 503, and 504 responses. `retry` is the number of retries after the first attempt.

Usage
-----

[](#usage)

```
$health = $client->health()->ping();
$application = $client->applications()->me();
$request = $client->requests()->find('req_123');
```

All public results are immutable DTOs. Provider-defined JSON is available through a `JsonData` object rather than an associative response array.

### Workflows

[](#workflows)

```
use Juzhax\AiClient\Data\JsonData;
use Juzhax\AiClient\Requests\WorkflowRunRequest;

$input = (object) ['customer_id' => 'cus_123', 'question' => 'Where is my order?'];
$run = $client->workflows()->run('customer-support', new WorkflowRunRequest(new JsonData($input)));
$latest = $client->workflows()->status($run->id);
```

### Agents

[](#agents)

```
use Juzhax\AiClient\Requests\AgentRunRequest;

$result = $client->agents()->run('support', new AgentRunRequest('Help me reset my password'));
echo $result->output;
```

### Prompts

[](#prompts)

```
use Juzhax\AiClient\Data\JsonData;
use Juzhax\AiClient\Requests\PromptRunRequest;

$variables = new JsonData((object) ['topic' => 'Laravel queues']);
$result = $client->prompts()->run(
    'explain-topic',
    new PromptRunRequest(variables: $variables),
);

echo $result->output;
echo $result->usage->value->total_tokens;
```

The API key must be project-scoped with the `prompts:run` ability. The prompt must have an active version and reference a registered agent. By default, the platform uses the provider and model configured for the prompt. Pass `provider` and `model` to `PromptRunRequest` only when you need to override them; override values must match active catalogue entries.

Framework examples
------------------

[](#framework-examples)

Laravel does not need a package integration or facade. Bind the configured client in a service provider:

```
$this->app->singleton(Client::class, fn () => new Client(
    config: new Config(config('services.ai.url'), new ApiKey(config('services.ai.key'))),
    httpClient: new \GuzzleHttp\Client(['timeout' => 30]),
    requestFactory: new \GuzzleHttp\Psr7\HttpFactory(),
    streamFactory: new \GuzzleHttp\Psr7\HttpFactory(),
));
```

In WordPress, load Composer's autoloader and construct the same plain PHP client:

```
require_once __DIR__.'/vendor/autoload.php';

$factory = new \GuzzleHttp\Psr7\HttpFactory();
$client = new Client(
    new Config('https://ai.justin.my', new ApiKey(get_option('ai_platform_key'))),
    new \GuzzleHttp\Client(['timeout' => 30]),
    $factory,
    $factory,
);
```

Symfony's `Psr18Client` can be supplied with Symfony's PSR-17 factories in exactly the same constructor; no SDK adapter is required.

Error handling
--------------

[](#error-handling)

```
use Juzhax\AiClient\Exception\AuthenticationException;
use Juzhax\AiClient\Exception\NetworkException;
use Juzhax\AiClient\Exception\RateLimitException;
use Juzhax\AiClient\Exception\ValidationException;

try {
    $result = $client->agents()->run('support', new AgentRunRequest('Hello'));
} catch (AuthenticationException $e) {
    // Invalid or unauthorized API key.
} catch (ValidationException $e) {
    // Inspect $e->error, an ApiErrorResponse DTO.
} catch (RateLimitException $e) {
    // Retries were exhausted.
} catch (NetworkException $e) {
    // Transport exceptions are wrapped and never exposed directly.
}
```

Other non-success API responses throw `ApiException`; malformed responses throw `AiException`.

Development
-----------

[](#development)

```
composer install
composer test
```

Tests use a mock PSR-18 client and never make network requests.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance92

Actively maintained with recent releases

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

4

Last Release

40d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/1c987f79f79066e79e29efb47ec646f3dad3f819805453f0f3e97e94ef49042d?d=identicon)[juzhax](/maintainers/juzhax)

---

Top Contributors

[![juzhax](https://avatars.githubusercontent.com/u/1167187?v=4)](https://github.com/juzhax "juzhax (4 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/juzhax-ai-client/health.svg)

```
[![Health](https://phpackages.com/badges/juzhax-ai-client/health.svg)](https://phpackages.com/packages/juzhax-ai-client)
```

###  Alternatives

[tempest/framework

The PHP framework that gets out of your way.

2.3k42.4k21](/packages/tempest-framework)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

86538.6k](/packages/flow-php-flow)[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

8.0k1.1B4.6k](/packages/guzzlehttp-psr7)[cakephp/cakephp

The CakePHP framework

8.9k20.4M1.9k](/packages/cakephp-cakephp)[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

36863.5k2](/packages/telnyx-telnyx-php)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
