withRetry( fn () => $this->client()->post(self::API_URL, [ 'model' => $config['model'] ?? $this->model, 'max_tokens' => $config['max_tokens'] ?? 4096, 'temperature' => $config['temperature'] ?? 1.0, 'system' => $systemPrompt, 'messages' => [ ['role' => 'user', 'content' => $userPrompt], ], ]), 'Claude' ); $data = $response->json(); $durationMs = (int) ((microtime(true) - $startTime) * 1000); return new AgenticResponse( content: $data['content'][0]['text'] ?? '', model: $data['model'], inputTokens: $data['usage']['input_tokens'] ?? 0, outputTokens: $data['usage']['output_tokens'] ?? 0, durationMs: $durationMs, stopReason: $data['stop_reason'] ?? null, raw: $data, ); } public function stream( string $systemPrompt, string $userPrompt, array $config = [] ): Generator { $response = $this->client() ->withOptions(['stream' => true]) ->post(self::API_URL, [ 'model' => $config['model'] ?? $this->model, 'max_tokens' => $config['max_tokens'] ?? 4096, 'temperature' => $config['temperature'] ?? 1.0, 'stream' => true, 'system' => $systemPrompt, 'messages' => [ ['role' => 'user', 'content' => $userPrompt], ], ]); yield from $this->parseSSEStream( $response->getBody(), fn (array $data) => $data['delta']['text'] ?? null ); } public function name(): string { return 'claude'; } public function defaultModel(): string { return $this->model; } public function isAvailable(): bool { return ! empty($this->apiKey); } private function client(): PendingRequest { return Http::withHeaders([ 'x-api-key' => $this->apiKey, 'anthropic-version' => self::API_VERSION, 'content-type' => 'application/json', ])->timeout(300); } }