From 1a5b931345c91bf44ceee2513089599fa6d31673 Mon Sep 17 00:00:00 2001 From: ddebowczyk Date: Thu, 29 Aug 2024 07:18:51 +0200 Subject: [PATCH] Configurability cont. --- composer.json | 3 +- config/instructor.php | 19 +++++-- src/ApiClient/ApiClient.php | 4 +- src/ApiClient/Contracts/CanCallApi.php | 11 +--- src/ApiClient/Factories/ApiClientFactory.php | 13 +---- .../Traits/HandlesAsyncApiResponse.php | 55 ------------------- .../Traits/HandlesDefaultMaxTokens.php | 3 +- src/Clients/Anthropic/AnthropicClient.php | 3 - src/Clients/Azure/AzureClient.php | 3 - src/Clients/Cohere/CohereClient.php | 3 - src/Clients/FireworksAI/FireworksAIClient.php | 3 - src/Clients/Gemini/GeminiClient.php | 3 - src/Clients/Groq/GroqClient.php | 3 - src/Clients/Mistral/MistralClient.php | 3 - src/Clients/Ollama/OllamaClient.php | 3 - src/Clients/OpenAI/OpenAIClient.php | 3 - src/Clients/OpenRouter/OpenRouterClient.php | 3 - src/Clients/TogetherAI/TogetherAIClient.php | 3 - src/Configs/RequestHandlingConfig.php | 17 +++--- .../ApiClient/ApiAsyncRequestInitiated.php | 7 --- .../ApiClient/ApiAsyncResponseReceived.php | 7 --- src/Events/Traits/HandlesEventListeners.php | 2 - src/Events/Traits/HandlesEvents.php | 1 - src/Utils/Env.php | 1 - src/Utils/Settings.php | 15 +++++ 25 files changed, 49 insertions(+), 142 deletions(-) delete mode 100644 src/ApiClient/Traits/HandlesAsyncApiResponse.php delete mode 100644 src/Events/ApiClient/ApiAsyncRequestInitiated.php delete mode 100644 src/Events/ApiClient/ApiAsyncResponseReceived.php create mode 100644 src/Utils/Settings.php diff --git a/composer.json b/composer.json index fe27ce42..7861e7c1 100644 --- a/composer.json +++ b/composer.json @@ -77,7 +77,8 @@ "symfony/type-info": "^7.1", "symfony/validator": "^6.4 || ^7.0", "vlucas/phpdotenv": "^5.6", - "spatie/array-to-xml": "^3.3" + "spatie/array-to-xml": "^3.3", + "adbario/php-dot-notation": "^3.3" }, "scripts": { "tests": "@php vendor/bin/pest", diff --git a/config/instructor.php b/config/instructor.php index fabcc57b..5d9141da 100644 --- a/config/instructor.php +++ b/config/instructor.php @@ -3,10 +3,10 @@ use Cognesy\Instructor\Utils\Env; return [ - 'defaultConnection' => 'openai', + 'useObjectReferences' => Env::get('INSTRUCTOR_USE_OBJECT_REFERENCES', false), 'cache' => [ 'enabled' => Env::get('INSTRUCTOR_CACHE_ENABLED', false), - 'expiry' => Env::get('INSTRUCTOR_CACHE_EXPIRY', 3600), + 'expiryInSeconds' => Env::get('INSTRUCTOR_CACHE_EXPIRY', 3600), 'path' => Env::get('INSTRUCTOR_CACHE_PATH', '/tmp/instructor/cache'), ], 'debug' => [ @@ -14,8 +14,8 @@ 'stopOnDebug' => Env::get('INSTRUCTOR_STOP_ON_DEBUG', false), 'forceDebug' => Env::get('INSTRUCTOR_FORCE_DEBUG', false), ], - 'useObjectReferences' => Env::get('INSTRUCTOR_USE_OBJECT_REFERENCES', false), + 'defaultConnection' => 'openai', 'connections' => [ 'anthropic' => [ 'clientType' => ClientType::Anthropic->value, @@ -75,7 +75,7 @@ 'clientType' => ClientType::Groq->value, 'apiUrl' => Env::get('GROQ_API_URL', 'https://api.groq.com/openai/v1'), 'apiKey' => Env::get('GROQ_API_KEY', ''), - 'defaultModel' => Env::get('GROQ_DEFAULT_MODEL', 'llama3-8b-8192'), + 'defaultModel' => Env::get('GROQ_DEFAULT_MODEL', 'gemma2-9b-it'), 'defaultMaxTokens' => Env::get('GROQ_DEFAULT_MAX_TOKENS', 1024), 'connectTimeout' => Env::get('GROQ_CONNECT_TIMEOUT', 3), 'requestTimeout' => Env::get('GROQ_REQUEST_TIMEOUT', 30), @@ -89,6 +89,15 @@ 'connectTimeout' => Env::get('MISTRAL_CONNECT_TIMEOUT', 3), 'requestTimeout' => Env::get('MISTRAL_REQUEST_TIMEOUT', 30), ], + 'ollama' => [ + 'clientType' => ClientType::Ollama->value, + 'apiUrl' => Env::get('OLLAMA_API_URL', 'http://localhost:11434/v1'), + 'apiKey' => Env::get('OLLAMA_API_KEY', ''), + 'defaultModel' => Env::get('OLLAMA_DEFAULT_MODEL', 'gemma2:2b'), + 'defaultMaxTokens' => Env::get('OLLAMA_DEFAULT_MAX_TOKENS', 1024), + 'connectTimeout' => Env::get('OLLAMA_CONNECT_TIMEOUT', 3), + 'requestTimeout' => Env::get('OLLAMA_REQUEST_TIMEOUT', 30), + ], 'openai' => [ 'clientType' => ClientType::OpenAI->value, 'apiUrl' => Env::get('OPENAI_API_URL', 'https://api.openai.com/v1'), @@ -105,7 +114,7 @@ 'clientType' => ClientType::OpenRouter->value, 'apiUrl' => Env::get('OPENROUTER_API_URL', 'https://api.openrouter.io/v1'), 'apiKey' => Env::get('OPENROUTER_API_KEY', ''), - 'defaultModel' => Env::get('OPENROUTER_DEFAULT_MODEL', 'gpt-4o-mini'), + 'defaultModel' => Env::get('OPENROUTER_DEFAULT_MODEL', 'microsoft/phi-3.5-mini-128k-instruct'), 'defaultMaxTokens' => Env::get('OPENROUTER_DEFAULT_MAX_TOKENS', 1024), 'connectTimeout' => Env::get('OPENROUTER_CONNECT_TIMEOUT', 3), 'requestTimeout' => Env::get('OPENROUTER_REQUEST_TIMEOUT', 30), diff --git a/src/ApiClient/ApiClient.php b/src/ApiClient/ApiClient.php index 64fa4151..7ef92280 100644 --- a/src/ApiClient/ApiClient.php +++ b/src/ApiClient/ApiClient.php @@ -8,6 +8,7 @@ use Cognesy\Instructor\Events\EventDispatcher; use Cognesy\Instructor\Events\Traits\HandlesEventListeners; use Cognesy\Instructor\Events\Traits\HandlesEvents; +use Cognesy\Instructor\Utils\Settings; use Saloon\Enums\Method; abstract class ApiClient implements CanCallApi @@ -19,7 +20,6 @@ abstract class ApiClient implements CanCallApi use Traits\HandlesApiRequest; use Traits\HandlesApiRequestFactory; use Traits\HandlesApiResponse; - use Traits\HandlesAsyncApiResponse; use Traits\HandlesDebug; use Traits\HandlesDefaultMaxTokens; use Traits\HandlesDefaultModel; @@ -34,6 +34,8 @@ public function __construct( ) { $this->withEventDispatcher($events ?? new EventDispatcher('api-client')); $this->clientType = ClientType::fromClientClass(static::class); + $this->withMaxTokens(Settings::get("connections.{$this->clientType->value}.defaultMaxTokens", 1024)); + $this->withModel(Settings::get("connections.{$this->clientType->value}.defaultModel", '')); } /// PUBLIC API ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/ApiClient/Contracts/CanCallApi.php b/src/ApiClient/Contracts/CanCallApi.php index e033fcca..7f21e03e 100644 --- a/src/ApiClient/Contracts/CanCallApi.php +++ b/src/ApiClient/Contracts/CanCallApi.php @@ -7,24 +7,19 @@ use Cognesy\Instructor\ApiClient\Responses\PartialApiResponse; use Cognesy\Instructor\Enums\Mode; use Generator; -use GuzzleHttp\Promise\PromiseInterface; use Saloon\Enums\Method; interface CanCallApi { public function request(array $body, string $endpoint, Method $method): static; - + public function respond(ApiRequest $request) : ApiResponse; public function get() : ApiResponse; - /** @return Generator */ public function stream() : Generator; - public function async() : PromiseInterface; + public function getModeRequestClass(Mode $mode) : string; + public function withApiRequest(ApiRequest $request) : static; public function defaultMaxTokens() : int; public function defaultModel() : string; - - public function getModeRequestClass(Mode $mode) : string; - - public function withApiRequest(ApiRequest $request) : static; } diff --git a/src/ApiClient/Factories/ApiClientFactory.php b/src/ApiClient/Factories/ApiClientFactory.php index a0cc8f0a..362653a5 100644 --- a/src/ApiClient/Factories/ApiClientFactory.php +++ b/src/ApiClient/Factories/ApiClientFactory.php @@ -4,21 +4,18 @@ use Cognesy\Instructor\ApiClient\Contracts\CanCallApi; use Cognesy\Instructor\ApiClient\Enums\ClientType; use Cognesy\Instructor\Events\EventDispatcher; +use Cognesy\Instructor\Utils\Settings; use InvalidArgumentException; class ApiClientFactory { protected CanCallApi $defaultClient; - protected array $config = []; public function __construct( - public string $configPath, public EventDispatcher $events, public ApiRequestFactory $apiRequestFactory, ) { - $this->config = $this->readConfig($this->configPath); - - $defaultConnection = $this->config['defaultConnection'] ?? null; + $defaultConnection = Settings::get('defaultConnection'); if (!$defaultConnection) { throw new InvalidArgumentException("No default client connection found"); } @@ -26,7 +23,7 @@ public function __construct( } public function client(string $connection) : CanCallApi { - $clientConfig = $this->config['connections'][$connection] ?? null; + $clientConfig = Settings::get("connections.$connection"); if (!$clientConfig) { throw new InvalidArgumentException("No client connection config found for '{$connection}'"); } @@ -60,8 +57,4 @@ protected function getFromConfig(array $config): CanCallApi { ->withModel($config['defaultModel'] ?? '') ->withMaxTokens($config['defaultMaxTokens'] ?? 1024); } - - protected function readConfig(string $configPath): array { - return require __DIR__ . $configPath; - } } diff --git a/src/ApiClient/Traits/HandlesAsyncApiResponse.php b/src/ApiClient/Traits/HandlesAsyncApiResponse.php deleted file mode 100644 index 9027f3dc..00000000 --- a/src/ApiClient/Traits/HandlesAsyncApiResponse.php +++ /dev/null @@ -1,55 +0,0 @@ -isStreamedRequest()) { - throw new Exception('Async does not support streaming'); - } - - $request = $this->getApiRequest(); - return $this->asyncRaw( - request: $request, - onSuccess: fn(Response $response) => $this->apiRequest->toApiResponse($response), - onError: fn(Exception $exception) => throw $exception - ); - } - - protected function asyncRaw(ApiRequest $request, callable $onSuccess = null, callable $onError = null) : PromiseInterface { - $this?->events->dispatch(new ApiAsyncRequestInitiated($request->toArray())); - $promise = $this->connector()->sendAsync($request); - if (!empty($onSuccess)) { - $promise->then(function (Response $response) use ($onSuccess) { - $this?->events->dispatch(new ApiAsyncResponseReceived( - $response->status(), - $this->getRequestHeaders($response), - $response->content(), - )); - $onSuccess($response); - }); - } - if (!empty($onError)) { - $promise->otherwise(function (RequestException $exception) use ($onError) { - $this?->events->dispatch(new ApiRequestErrorRaised($exception)); - $onError($exception); - }); - } - return $promise; - } -} \ No newline at end of file diff --git a/src/ApiClient/Traits/HandlesDefaultMaxTokens.php b/src/ApiClient/Traits/HandlesDefaultMaxTokens.php index 8d096a04..6b3c4b82 100644 --- a/src/ApiClient/Traits/HandlesDefaultMaxTokens.php +++ b/src/ApiClient/Traits/HandlesDefaultMaxTokens.php @@ -1,10 +1,9 @@ defaultMaxTokens; diff --git a/src/Clients/Anthropic/AnthropicClient.php b/src/Clients/Anthropic/AnthropicClient.php index 64d54f17..04563308 100644 --- a/src/Clients/Anthropic/AnthropicClient.php +++ b/src/Clients/Anthropic/AnthropicClient.php @@ -8,9 +8,6 @@ class AnthropicClient extends ApiClient { - public string $defaultModel = 'claude-3-5-sonnet-20240620'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/Azure/AzureClient.php b/src/Clients/Azure/AzureClient.php index 9b0c6b6e..6f8ad67e 100644 --- a/src/Clients/Azure/AzureClient.php +++ b/src/Clients/Azure/AzureClient.php @@ -8,9 +8,6 @@ class AzureClient extends ApiClient { - public string $defaultModel = 'gpt-3.5-turbo'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/Cohere/CohereClient.php b/src/Clients/Cohere/CohereClient.php index 4add0a1c..6c8f45d5 100644 --- a/src/Clients/Cohere/CohereClient.php +++ b/src/Clients/Cohere/CohereClient.php @@ -8,9 +8,6 @@ class CohereClient extends ApiClient { - public string $defaultModel = 'command-r'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/FireworksAI/FireworksAIClient.php b/src/Clients/FireworksAI/FireworksAIClient.php index c1af6343..a1655384 100644 --- a/src/Clients/FireworksAI/FireworksAIClient.php +++ b/src/Clients/FireworksAI/FireworksAIClient.php @@ -8,9 +8,6 @@ class FireworksAIClient extends ApiClient { - public string $defaultModel = 'accounts/fireworks/models/mixtral-8x7b-instruct'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/Gemini/GeminiClient.php b/src/Clients/Gemini/GeminiClient.php index 9d8007d0..1ea9f3e3 100644 --- a/src/Clients/Gemini/GeminiClient.php +++ b/src/Clients/Gemini/GeminiClient.php @@ -8,9 +8,6 @@ class GeminiClient extends ApiClient { - public string $defaultModel = 'gemini-1.5-flash'; - public int $defaultMaxTokens = 4096; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/Groq/GroqClient.php b/src/Clients/Groq/GroqClient.php index 38fe3a4d..495e7b46 100644 --- a/src/Clients/Groq/GroqClient.php +++ b/src/Clients/Groq/GroqClient.php @@ -8,9 +8,6 @@ class GroqClient extends ApiClient { - public string $defaultModel = 'gemma2-9b-it'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/Mistral/MistralClient.php b/src/Clients/Mistral/MistralClient.php index aa4efcb9..612fbc19 100644 --- a/src/Clients/Mistral/MistralClient.php +++ b/src/Clients/Mistral/MistralClient.php @@ -8,9 +8,6 @@ class MistralClient extends ApiClient { - public string $defaultModel = 'mistral-small'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/Ollama/OllamaClient.php b/src/Clients/Ollama/OllamaClient.php index 271bbd83..c2d05985 100644 --- a/src/Clients/Ollama/OllamaClient.php +++ b/src/Clients/Ollama/OllamaClient.php @@ -8,9 +8,6 @@ class OllamaClient extends ApiClient { - public string $defaultModel = 'gemma2:2b'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/OpenAI/OpenAIClient.php b/src/Clients/OpenAI/OpenAIClient.php index 4e577375..8747a1e3 100644 --- a/src/Clients/OpenAI/OpenAIClient.php +++ b/src/Clients/OpenAI/OpenAIClient.php @@ -9,9 +9,6 @@ class OpenAIClient extends ApiClient { - public string $defaultModel = 'gpt-4o-mini'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/OpenRouter/OpenRouterClient.php b/src/Clients/OpenRouter/OpenRouterClient.php index 1cd78272..b06b82fc 100644 --- a/src/Clients/OpenRouter/OpenRouterClient.php +++ b/src/Clients/OpenRouter/OpenRouterClient.php @@ -8,9 +8,6 @@ class OpenRouterClient extends ApiClient { - public string $defaultModel = 'microsoft/phi-3.5-mini-128k-instruct'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Clients/TogetherAI/TogetherAIClient.php b/src/Clients/TogetherAI/TogetherAIClient.php index 64f56233..748aac2e 100644 --- a/src/Clients/TogetherAI/TogetherAIClient.php +++ b/src/Clients/TogetherAI/TogetherAIClient.php @@ -8,9 +8,6 @@ class TogetherAIClient extends ApiClient { - public string $defaultModel = 'mistralai/Mixtral-8x7B-Instruct-v0.1'; - public int $defaultMaxTokens = 1024; - public function __construct( protected string $apiKey = '', protected string $baseUri = '', diff --git a/src/Configs/RequestHandlingConfig.php b/src/Configs/RequestHandlingConfig.php index ac82ef1f..2c9e8832 100644 --- a/src/Configs/RequestHandlingConfig.php +++ b/src/Configs/RequestHandlingConfig.php @@ -14,7 +14,7 @@ use Cognesy\Instructor\Schema\Factories\SchemaFactory; use Cognesy\Instructor\Schema\Factories\ToolCallBuilder; use Cognesy\Instructor\Schema\Utils\ReferenceQueue; -use Cognesy\Instructor\Utils\Env; +use Cognesy\Instructor\Utils\Settings; class RequestHandlingConfig implements CanAddConfiguration { @@ -29,7 +29,6 @@ class: ApiRequestFactory::class, $config->object( class: ApiClientFactory::class, context: [ - 'configPath' => Env::get('INSTRUCTOR_CONFIG_PATH', '/../../../config/instructor.php'), 'events' => $config->reference(EventDispatcher::class), 'apiRequestFactory' => $config->reference(ApiRequestFactory::class), ], @@ -66,7 +65,7 @@ class: ToolCallBuilder::class, $config->object( class: SchemaFactory::class, context: [ - 'useObjectReferences' => $_ENV['INSTRUCTOR_USE_OBJECT_REFERENCES'] ?? false, + 'useObjectReferences' => Settings::get('useObjectReferences') ?? false, ] ); @@ -84,18 +83,18 @@ class: ApiRequestConfig::class, $config->object( class: CacheConfig::class, context: [ - 'enabled' => $_ENV['INSTRUCTOR_CACHE_ENABLED'] ?? false, - 'expiryInSeconds' => $_ENV['INSTRUCTOR_CACHE_EXPIRY'] ?? 3600, - 'cachePath' => $_ENV['INSTRUCTOR_CACHE_PATH'] ?? '/tmp/instructor/cache', + 'enabled' => Settings::get('cache.enabled', false), + 'expiryInSeconds' => Settings::get('cache.expiryInSeconds', 3600), + 'cachePath' => Settings::get('cache.path', '/tmp/instructor/cache'), ] ); $config->object( class: DebugConfig::class, context: [ - 'debug' => $_ENV['INSTRUCTOR_DEBUG'] ?? false, - 'stopOnDebug' => $_ENV['INSTRUCTOR_STOP_ON_DEBUG'] ?? false, - 'forceDebug' => $_ENV['INSTRUCTOR_FORCE_DEBUG'] ?? false, + 'debug' => Settings::get('debug.enabled', false), + 'stopOnDebug' => Settings::get('debug.stopOnDebug', false), + 'forceDebug' => Settings::get('debug.forceDebug', false), ] ); diff --git a/src/Events/ApiClient/ApiAsyncRequestInitiated.php b/src/Events/ApiClient/ApiAsyncRequestInitiated.php deleted file mode 100644 index 3a3732d2..00000000 --- a/src/Events/ApiClient/ApiAsyncRequestInitiated.php +++ /dev/null @@ -1,7 +0,0 @@ -get($key, $default); + } +}