HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/app/Http/Controllers/Api/AIHubController.php
<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use Acelle\Ai\AIHandler\Data\AIContext;
use Acelle\Ai\AIHandler\Exception\AIEngineException;
use Acelle\Ai\AIHandler\Exception\AIEngineTimeoutException;
use Acelle\Ai\Plugins\ClaudeCLI\Engines\ClaudeCLIEngine;
use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

/**
 * Hub AI passthrough — pure "string → engine.ask → string" proxy.
 *
 * Receives a fully-composed prompt string from a Bearer-token-
 * authenticated downstream caller and runs it through the locally-
 * installed Claude Code CLI binary. The Hub knows nothing about
 * system vs user vs multi-turn structure — that's the consumer's
 * concern, baked into the `context` string upstream via
 * `AIContext::toString()`'s canonical flattening convention.
 *
 * Thin proxy — does NOT go through the plugin's task pipeline:
 *   - Engine = hardcoded ClaudeCLI; config (model/timeout) from ENV.
 *   - No TaskRegistry, no observability writes.
 *   - Plain JSON response (no AcelleWireProtocol envelope).
 *
 * Wire shape (post-3.2 — see plugin CHANGELOG for v3.1 → v3.2 migration):
 *   - Success (HTTP 200): `{content, model, finish_reason, usage}`. NO
 *     `ok` field — HTTP 200 alone signals success.
 *   - Error (HTTP 502 / 504): `{error, code}` — `code` is `timeout` or
 *     `engine_error`. NO `ok: false` — HTTP status IS the failure signal.
 *   - Validation 422 (Laravel default): `{message, errors: {context: [...]}}`.
 */
final class AIHubController extends Controller
{
    public function handle(Request $request): JsonResponse
    {
        $data = $request->validate([
            'context' => 'required|string',
        ]);

        $engine = new ClaudeCLIEngine(
            binaryPath: (string) env('HUB_AI_CLAUDE_CLI_PATH', 'claude'),
            model:      (string) env('HUB_AI_CLAUDE_CLI_MODEL', 'sonnet'),
            timeout:    (int) env('HUB_AI_CLAUDE_CLI_TIMEOUT', 60),
        );

        try {
            $res = $engine->ask(AIContext::parse($data['context']));
        } catch (AIEngineTimeoutException $e) {
            return response()->json(['error' => $e->getMessage(), 'code' => 'timeout'], 504);
        } catch (AIEngineException $e) {
            return response()->json(['error' => $e->getMessage(), 'code' => 'engine_error'], 502);
        }

        return response()->json([
            'content'       => $res->content,
            'model'         => $res->model,
            'finish_reason' => $res->finishReason,
            'usage'         => $res->usage?->toArray(),
        ], 200);
    }
}