diff --git a/Plugin/unraid/api/ai.php b/Plugin/unraid/api/ai.php index 2d67f00..6744636 100644 --- a/Plugin/unraid/api/ai.php +++ b/Plugin/unraid/api/ai.php @@ -85,6 +85,21 @@ const VV_AI_JOB_TTL = 3600; // seconds before a job file is reaped $isPost = $_SERVER['REQUEST_METHOD'] === 'POST'; $action = trim($isPost ? ($_POST['action'] ?? '') : ($_GET['action'] ?? 'stats')); +// Request trace. There is no nginx access log on this host and the CSRF prepend exits with an +// empty body, so without this there is no way to tell "the request never arrived" from "the +// request arrived and failed" — which is exactly the ambiguity that made the first hang +// undiagnosable. Excludes poll, which would otherwise write a line per second per open tab. +function vv_ai_log(string $msg): void { + if (!is_dir('/var/log/varaverk')) return; + @file_put_contents('/var/log/varaverk/ai.log', + date('Y-m-d H:i:s') . ' ' . $msg . "\n", FILE_APPEND | LOCK_EX); +} +if ($action !== 'poll') { + vv_ai_log(sprintf('%s action=%s from=%s', + $_SERVER['REQUEST_METHOD'] ?? '?', $action ?: '(none)', + $_SERVER['REMOTE_ADDR'] ?? '?')); +} + // ── stats ───────────────────────────────────────────────────────────────────── if ($action === 'stats') { echo json_encode(['ok' => true, 'stats' => vv_ai_stats()]); @@ -169,7 +184,13 @@ if ($action === 'ask') { echo json_encode(['ok' => false, 'error' => 'ai_chat_worker.php not found']); exit; } - @file_put_contents($jobFile, json_encode(['status' => 'pending'])); + // Not suppressed: if the job file cannot be written the worker has nowhere to report and + // the page polls a token that will never resolve — which looks exactly like a hang. + if (file_put_contents($jobFile, json_encode(['status' => 'pending'])) === false) { + vv_ai_log('ask FAILED — cannot write ' . $jobFile); + echo json_encode(['ok' => false, 'error' => 'Cannot write job file to ' . VV_AI_JOB_DIR]); + exit; + } $cmd = 'nohup php ' . escapeshellarg($worker) . ' ' . escapeshellarg($jobFile) . ' ' @@ -178,7 +199,10 @@ if ($action === 'ask') { . escapeshellarg($kind) . ' ' . escapeshellarg(($_POST['think'] ?? '1') === '1' ? '1' : '0') . ' >/dev/null 2>&1 true, 'token' => $token]); exit;