isRunTerminal($sessionId, $runId)) { return; } if ($this->cancelChecker->isCanceled($sessionId, $runId)) { $this->appendCanceled($sessionId, $runId); return; } $context = $this->contextBuilder->build($sessionId, $runId); if ($this->cancelChecker->isCanceled($sessionId, $runId)) { $this->appendCanceled($sessionId, $runId); return; } $providerName = $this->resolveProviderName(); $startedAt = microtime(true); logger('agent provider request', [ 'sessionId' => $sessionId, 'runId' => $runId, 'provider' => $providerName, ]); try { $reply = $this->provider->generate($context); } catch (ProviderException $exception) { $latencyMs = (int) ((microtime(true) - $startedAt) * 1000); $this->outputSink->appendError($sessionId, $runId, $exception->errorCode, $exception->getMessage(), [ 'retryable' => $exception->retryable, 'http_status' => $exception->httpStatus, 'provider' => $providerName, 'latency_ms' => $latencyMs, 'raw_message' => $exception->rawMessage, ], "run:{$runId}:error:provider"); $this->outputSink->appendRunStatus($sessionId, $runId, 'FAILED', [ 'error' => $exception->getMessage(), 'dedupe_key' => "run:{$runId}:status:FAILED", ]); throw $exception; } $latencyMs = (int) ((microtime(true) - $startedAt) * 1000); logger('agent provider response', [ 'sessionId' => $sessionId, 'runId' => $runId, 'provider' => $providerName, 'latency_ms' => $latencyMs, ]); if ($this->cancelChecker->isCanceled($sessionId, $runId)) { $this->appendCanceled($sessionId, $runId); return; } $this->outputSink->appendAgentMessage($sessionId, $runId, $reply, [ 'provider' => $providerName, ], "run:{$runId}:agent:message"); if ($this->cancelChecker->isCanceled($sessionId, $runId)) { $this->appendCanceled($sessionId, $runId); return; } $this->outputSink->appendRunStatus($sessionId, $runId, 'DONE', [ 'dedupe_key' => "run:{$runId}:status:DONE", ]); } private function isRunTerminal(string $sessionId, string $runId): bool { $latestStatus = Message::query() ->where('session_id', $sessionId) ->where('type', 'run.status') ->whereRaw("payload->>'run_id' = ?", [$runId]) ->orderByDesc('seq') ->first(); $status = $latestStatus ? ($latestStatus->payload['status'] ?? null) : null; return in_array($status, self::TERMINAL_STATUSES, true); } private function appendCanceled(string $sessionId, string $runId): void { $this->outputSink->appendRunStatus($sessionId, $runId, 'CANCELED', [ 'dedupe_key' => "run:{$runId}:status:CANCELED", ]); } private function resolveProviderName(): string { if ($this->provider instanceof DummyAgentProvider) { return 'dummy'; } return str_replace("\0", '', get_class($this->provider)); } }