$jobId, 'contentPage' => $contentPage, 'path' => $proposal['path'], 'imageMode' => (string)($payload['imageMode'] ?? 'generate'), 'requestedCount' => (int)($options['count'] ?? 1), 'count' => count($proposal['paths'] ?? []), 'proposals' => raijuCopilotProposalAuditSummary([$proposal]) ]); return raijuAiFinishImageJob($jobId, [ 'proposal' => $proposal, 'usage' => $result['usage'] ?? null, 'limits' => $result['limits'] ?? null, 'context' => $context ]); } if ($prompt === '') { throw new RuntimeException('Image job prompt is missing.'); } if ($kind === 'agent' && empty($options['storageDir'])) { throw new RuntimeException('An agent image job needs its staging folder.'); } $result = raijuAiGenerateImage($prompt, $options); return raijuAiFinishImageJob($jobId, $result); } catch (Throwable $e) { $entry = raijuAiLoadUsage()['reservations']['image_' . $jobId] ?? []; $tasks = $entry['tasks'] ?? []; $pending = array_filter($tasks, fn($task) => !in_array($task['state'] ?? '', ['success', 'fail', 'failed', 'error'], true)); if ($tasks && !array_filter($tasks, fn($task) => empty($task['id'])) && ($pending || !empty($entry['outputs'])) && (int)($job['attempts'] ?? 0) < 10) { raijuJsonUpdate(raijuAiImageJobPath($jobId), static function (&$current) use ($e) { $current['status'] = 'queued'; $current['retryAt'] = time() + 60; $current['updatedAt'] = gmdate('c'); $current['error'] = raijuAiUtf8Prefix($e->getMessage(), 1000); }); return raijuAiPublicImageJob(raijuAiLoadImageJob($jobId)); } if ($kind === 'dashboard') { $settings = raijuAiLoadSettings(false); raijuAiRecordImageHistory([ 'status' => 'error', 'model' => (string)($options['model'] ?? raijuAiEffectiveImageModel($settings)), 'prompt' => $prompt, 'size' => (string)($options['size'] ?? ''), 'aspectRatio' => (string)($options['aspectRatio'] ?? ''), 'quality' => (string)($options['quality'] ?? ''), 'format' => (string)($options['outputFormat'] ?? ''), 'moderation' => (string)($options['moderation'] ?? ''), 'compression' => (int)($options['outputCompression'] ?? 0), 'count' => (int)($options['count'] ?? 0), 'referenceImages' => raijuAiPublicReferenceList($options), 'outputs' => [], 'error' => $e->getMessage(), 'estimatedCostCents' => 0 ]); } raijuAiAudit($kind === 'copilot' ? 'copilot-generate-image' : 'image', false, ['jobId' => $jobId, 'message' => $e->getMessage()]); return raijuAiFailImageJob($jobId, $e->getMessage()); } }