Phase 3 lane: queueable Job that resolves a profile via ProfileSelector,
posts POST {gateway}/v1/responses to the chosen Hermes gateway, persists
ticket_id/profile_id/response_id/run_id/status in agent_dispatches, and
chains CaptureDispatchResultJob.
Migration 2026_04_25_000003 creates agent_dispatches table (FK-free,
Postgres-compatible).
HermesClient: thin Laravel HTTP wrapper around the Hermes /v1/responses
endpoint with Authorization header + JSON body.
DispatchMantisTicketJob behaviour:
- Resolves profile via ProfileSelector::pickFor()
- Null-profile → log warn + ->release(60) requeue
- Otherwise POSTs to gateway, persists AgentDispatch row, queues
CaptureDispatchResultJob
AgentDispatch Eloquent model with minimal $fillable.
Pest Feature test (Http::fake): verifies request shape, persisted row,
downstream capture-job queueing, and the no-profile requeue path.
Test file conditionally aliases minimal stubs for sibling-lane services
so this file remains runnable before #826/#828 fully land in dev.
Codex note: php -l clean; pest skipped (no vendor/).
Closes tasks.lthn.sh/view.php?id=827
Co-authored-by: Codex <noreply@openai.com>
48 lines
1.2 KiB
PHP
48 lines
1.2 KiB
PHP
<?php
|
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Core\Mod\Agentic\Services;
|
|
|
|
use Core\Mod\Agentic\Models\AgentProfile;
|
|
use Illuminate\Http\Client\PendingRequest;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
class HermesClient
|
|
{
|
|
/**
|
|
* Create a Hermes response run for a Mantis ticket prompt.
|
|
*
|
|
* @param array<string, mixed> $metadata
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function createResponse(AgentProfile $profile, string $input, array $metadata = []): array
|
|
{
|
|
$response = $this->request($profile)->post($this->url($profile), [
|
|
'model' => 'default',
|
|
'input' => $input,
|
|
'metadata' => $metadata,
|
|
]);
|
|
|
|
$response->throw();
|
|
|
|
$payload = $response->json();
|
|
|
|
return is_array($payload) ? $payload : [];
|
|
}
|
|
|
|
private function request(AgentProfile $profile): PendingRequest
|
|
{
|
|
return Http::withToken((string) $profile->api_key_cipher)
|
|
->acceptJson()
|
|
->asJson()
|
|
->timeout(60);
|
|
}
|
|
|
|
private function url(AgentProfile $profile): string
|
|
{
|
|
return rtrim($profile->gateway_url, '/').'/v1/responses';
|
|
}
|
|
}
|