timeout((int) config('ai.timeout', 60)); return filled($provider->api_key) ? $client->withToken($provider->api_key) : $client; } public function generate(AIProvider $provider, array $messages, array $options = []): array { $base = rtrim((string) ($provider->base_url ?: 'https://api.openai.com/v1'), '/'); $payload = ['model' => $options['model'] ?? $provider->default_model, 'messages' => $messages, 'temperature' => $options['temperature'] ?? config('ai.temperature', 0.3), 'max_tokens' => $options['max_tokens'] ?? config('ai.max_output_tokens', 2048)]; $response = $this->client($provider)->post($base.'/chat/completions', array_filter($payload, fn ($v) => $v !== null)); $response->throw(); $json = $response->json(); return ['text' => (string) data_get($json, 'choices.0.message.content', ''), 'usage' => (array) data_get($json, 'usage', []), 'raw' => $json]; } public function test(AIProvider $provider): array { $result = $this->generate($provider, [['role' => 'user', 'content' => 'Reply with OK only.']], ['max_tokens' => 8, 'temperature' => 0]); return ['ok' => true, 'message' => trim($result['text']) ?: 'Provider responded successfully.']; } }