apiKey = $apiKey; } /** * Build request payload for provider */ abstract protected function buildRequest(array $messages, array $options): array; /** * Get authorization headers for provider */ abstract protected function getAuthHeaders(): array; /** * Make HTTP request with retry logic */ protected function makeRequest(string $endpoint, array $data): array { $attempt = 0; $lastException = null; while ($attempt < $this->retryAttempts) { try { $response = Http::withHeaders($this->getAuthHeaders()) ->timeout($this->timeout) ->post($this->baseUrl . $endpoint, $data); if ($response->successful()) { return $response->json(); } // Handle specific HTTP errors if ($response->status() === 401) { throw new ProviderException('Invalid API key', 401); } if ($response->status() === 429) { throw new ProviderException('Rate limit exceeded', 429); } if ($response->status() >= 500) { throw new ProviderException('Provider server error', $response->status()); } throw new ProviderException( 'Request failed: ' . $response->body(), $response->status() ); } catch (\Exception $e) { $lastException = $e; $attempt++; if ($attempt < $this->retryAttempts) { Log::warning("Provider request failed, retrying ({$attempt}/{$this->retryAttempts})", [ 'provider' => static::class, 'error' => $e->getMessage() ]); usleep($this->retryDelay * 1000); } } } throw new ProviderException( 'All retry attempts failed: ' . ($lastException ? $lastException->getMessage() : 'Unknown error'), $lastException ? $lastException->getCode() : 500 ); } /** * Validate API key by making a test request */ public function validateApiKey(): bool { try { $this->chatCompletion([ ['role' => 'user', 'content' => 'test'] ], ['max_tokens' => 5]); return true; } catch (\Exception $e) { return false; } } }