diff --git a/src/Core/RequestHandler.php b/src/Core/RequestHandler.php index 4a022aa5..2a9689c8 100644 --- a/src/Core/RequestHandler.php +++ b/src/Core/RequestHandler.php @@ -6,7 +6,6 @@ use Cognesy\Instructor\Data\Request; use Cognesy\Instructor\Enums\Mode; use Cognesy\Instructor\Events\EventDispatcher; -use Cognesy\Instructor\Events\Instructor\InstructorDone; use Cognesy\Instructor\Events\Instructor\ResponseGenerated; use Cognesy\Instructor\Events\Request\NewValidationRecoveryAttempt; use Cognesy\Instructor\Events\Request\ValidationRecoveryLimitReached; @@ -16,7 +15,6 @@ use Cognesy\Instructor\Extras\LLM\Data\PartialLLMResponse; use Cognesy\Instructor\Extras\LLM\Inference; use Cognesy\Instructor\Extras\LLM\InferenceResponse; -use Cognesy\Instructor\Stream; use Cognesy\Instructor\Utils\Json\Json; use Cognesy\Instructor\Utils\Result\Result; use Exception; @@ -39,40 +37,16 @@ public function __construct( EventDispatcher $events, ) { $this->events = $events; + $this->retries = 0; + $this->errors = []; } - /** - * Executes the request and returns the response - */ - public function get() : mixed { - if ($this->request->isStream()) { - return $this->stream()->final(); - } - $result = $this->responseFor($this->request); - $this->events->dispatch(new InstructorDone(['result' => $result])); - return $result->value(); - } - - /** - * Executes the request and returns the response stream - */ - public function stream() : Stream { - // TODO: do we need this? cannot we just turn streaming on? - if (!$this->request->isStream()) { - throw new Exception('Instructor::stream() method requires response streaming: set "stream" = true in the request options.'); - } - $stream = $this->streamResponseFor($this->request); - return new Stream($stream, $this->events); - } - - // INTERNAL ////////////////////////////////////////////////////////////// + // PUBLIC ////////////////////////////////////////////////////////////// /** * Generates response value */ - protected function responseFor(Request $request) : LLMResponse { - $this->init(); - + public function responseFor(Request $request) : LLMResponse { $processingResult = Result::failure("No response generated"); while ($processingResult->isFailure() && !$this->maxRetriesReached($request)) { $llmResponse = $this->getInference($request)->toLLMResponse(); @@ -94,9 +68,7 @@ protected function responseFor(Request $request) : LLMResponse { * @param Request $request * @return Generator */ - protected function streamResponseFor(Request $request) : Generator { - $this->init(); - + public function streamResponseFor(Request $request) : Generator { $processingResult = Result::failure("No response generated"); while ($processingResult->isFailure() && !$this->maxRetriesReached($request)) { $stream = $this->getInference($request)->toPartialLLMResponses(); @@ -112,10 +84,7 @@ protected function streamResponseFor(Request $request) : Generator { yield $llmResponse->withValue($value); } - protected function init() : void { - $this->retries = 0; - $this->errors = []; - } + // INTERNAL /////////////////////////////////////////////////////////// protected function getInference(Request $request) : InferenceResponse { $inference = new Inference( diff --git a/src/InstructorResponse.php b/src/InstructorResponse.php new file mode 100644 index 00000000..5974830d --- /dev/null +++ b/src/InstructorResponse.php @@ -0,0 +1,50 @@ +events = $events; + $this->requestHandler = $requestHandler; + $this->request = $request; + } + + /** + * Executes the request and returns the response + */ + public function get() : mixed { + if ($this->request->isStream()) { + return $this->stream()->final(); + } + $result = $this->requestHandler->responseFor($this->request); + $this->events->dispatch(new InstructorDone(['result' => $result])); + return $result->value(); + } + + /** + * Executes the request and returns the response stream + */ + public function stream() : Stream { + // TODO: do we need this? cannot we just turn streaming on? + if (!$this->request->isStream()) { + throw new Exception('Instructor::stream() method requires response streaming: set "stream" = true in the request options.'); + } + $stream = $this->requestHandler->streamResponseFor($this->request); + return new Stream($stream, $this->events); + } +} \ No newline at end of file diff --git a/src/Traits/Instructor/HandlesInvocation.php b/src/Traits/Instructor/HandlesInvocation.php index cc36d31b..ae489dd7 100644 --- a/src/Traits/Instructor/HandlesInvocation.php +++ b/src/Traits/Instructor/HandlesInvocation.php @@ -9,6 +9,9 @@ use Cognesy\Instructor\Data\ResponseModel; use Cognesy\Instructor\Enums\Mode; use Cognesy\Instructor\Events\Instructor\RequestReceived; +use Cognesy\Instructor\Extras\LLM\Inference; +use Cognesy\Instructor\Extras\LLM\InferenceResponse; +use Cognesy\Instructor\InstructorResponse; use Cognesy\Instructor\Schema\Factories\SchemaFactory; use Cognesy\Instructor\Schema\Factories\ToolCallBuilder; use Cognesy\Instructor\Schema\Utils\ReferenceQueue; @@ -69,7 +72,7 @@ public function request( string $toolDescription = '', string $retryPrompt = '', Mode $mode = Mode::Tools, - ) : RequestHandler { + ) : InstructorResponse { $this->queueEvent(new RequestReceived()); $this->dispatchQueuedEvents(); @@ -98,7 +101,7 @@ public function request( cachedContext: $this->cachedContext ?? [], ); - return new RequestHandler( + $requestHandler = new RequestHandler( request: $request, responseGenerator: new ResponseGenerator( $this->responseDeserializer, @@ -116,10 +119,35 @@ public function request( httpClient: $this->httpClient, events: $this->events, ); + + return new InstructorResponse( + request: $request, + requestHandler: $requestHandler, + events: $this->events, + ); } // INTERNAL ///////////////////////////////////////////////// + protected function getInference(Request $request) : InferenceResponse { + $inference = new Inference( + connection: $this->connection, + httpClient: $this->httpClient, + driver: $this->driver, + events: $this->events, + ); + return $inference + ->create( + $request->toMessages(), + $request->model(), + $request->toolCallSchema(), + $request->toolChoice(), + $request->responseFormat(), + $request->options(), + $request->mode() + ); + } + private function makeResponseModel( string|array|object $requestedSchema, string $toolName,