baseUrl = $this->baseUrl ?? (string) config('agent.openai.base_url', ''); $this->apiKey = $this->apiKey ?? (string) config('agent.openai.api_key', ''); $this->organization = $this->organization ?? (string) config('agent.openai.organization', ''); $this->project = $this->project ?? (string) config('agent.openai.project', ''); $this->timeoutSeconds = $this->timeoutSeconds ?? (int) config('agent.provider.timeout_seconds', 30); $this->connectTimeoutSeconds = $this->connectTimeoutSeconds ?? (int) config('agent.provider.connect_timeout_seconds', 5); } /** * Opens a streaming response for the Chat Completions endpoint. * * @param array $payload */ public function openStream(array $payload): ResponseInterface { $baseUrl = trim((string) $this->baseUrl); $apiKey = trim((string) $this->apiKey); if ($baseUrl === '' || $apiKey === '') { throw new ProviderException('CONFIG_MISSING', 'Agent provider configuration missing', false); } $endpoint = rtrim($baseUrl, '/').'/chat/completions'; $headers = [ 'Authorization' => 'Bearer '.$apiKey, 'Accept' => 'text/event-stream', ]; if (trim((string) $this->organization) !== '') { $headers['OpenAI-Organization'] = (string) $this->organization; } if (trim((string) $this->project) !== '') { $headers['OpenAI-Project'] = (string) $this->project; } try { $response = Http::withHeaders($headers) ->connectTimeout($this->connectTimeoutSeconds) ->timeout($this->timeoutSeconds) ->withOptions(['stream' => true]) ->post($endpoint, $payload); } catch (ConnectionException $exception) { throw new ProviderException( 'CONNECTION_FAILED', 'Agent provider connection failed', true, null, $exception->getMessage() ); } $status = $response->status(); if ($status < 200 || $status >= 300) { $retryable = $status === 429 || $status >= 500; throw new ProviderException( 'HTTP_ERROR', 'Agent provider failed', $retryable, $status, $response->body() ); } return $response->toPsrResponse(); } }