Skip to content

Commit

Permalink
Cleanup of FunctionCallFactory
Browse files Browse the repository at this point in the history
  • Loading branch information
ddebowczyk committed Mar 9, 2024
1 parent 907522e commit 614ab0b
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 125 deletions.
7 changes: 3 additions & 4 deletions config/autowire.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class: Deserializer::class,
class: FunctionCallFactory::class,
context: [
'schemaFactory' => $config->reference(SchemaFactory::class),
'schemaBuilder' => $config->reference(SchemaBuilder::class),
'referenceQueue' => $config->reference(ReferenceQueue::class),
]
);
Expand Down Expand Up @@ -68,8 +67,8 @@ class: ResponseHandler::class,
class: ResponseModelFactory::class,
context: [
'functionCallFactory' => $config->reference(FunctionCallFactory::class),
'responseDeserializer' => $config->reference(CanDeserializeResponse::class),
'responseValidator' => $config->reference(CanValidateResponse::class),
'schemaFactory' => $config->reference(SchemaFactory::class),
'schemaBuilder' => $config->reference(SchemaBuilder::class),
]
);
$config->declare(class: SchemaMap::class);
Expand All @@ -80,7 +79,7 @@ class: SchemaFactory::class,
'schemaMap' => $config->reference(SchemaMap::class),
'propertyMap' => $config->reference(PropertyMap::class),
'typeDetailsFactory' => $config->reference(TypeDetailsFactory::class),
'useObjectReferences' => false,
'useObjectReferences' => true,
]
);
$config->declare(class: TypeDetailsFactory::class);
Expand Down
37 changes: 22 additions & 15 deletions examples/Streaming/run.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,32 @@

// CASE 1: Keep generating Person objects based on the input message

$stream = $instructor->respond(
messages: "His name is Jason, he is 28 years old.",
responseModel: Stream::of(Person::class),
class Person {
public string $name;
public ?int $age;
}

$sequence = $instructor->respond(
messages: "His name is Jason and he's 28 yo, and his friend is John. They both work with Kate, who is CMO.",
responseModel: Sequence::of(Person::class),
options: ['stream' => true],
);

foreach($stream as $response){
dump($response);
foreach($sequence as $person){
dump($person);
}

// CASE 2: Get partial updates of the Person object

$person = $instructor->respond(
messages: "His name is Jason, he is 28 years old.",
responseModel: Person::class,
onUpdate: onUpdate(...),
options: ['stream' => true],
);

function onUpdate(Person $person) {
dump($person);
}
//$person = $instructor->respond(
// messages: "His name is Jason, he is 28 years old.",
// responseModel: Person::class,
// onObjectUpdate: onObjectUpdate(...), // runs all validations
// onFieldUpdate: onFieldUpdate(...), // runs field validations
// onEachUpdate: onUpdate(...), // does not run validations
// options: ['stream' => true],
//);
//
//function onUpdate(Person $person) {
// dump($person);
//}
10 changes: 10 additions & 0 deletions src/Contracts/CanReceiveEvents.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Cognesy\Instructor\Contracts;

use Cognesy\Instructor\Events\Event;

interface CanReceiveEvents
{
public function onEvent(Event $event) : void;
}
7 changes: 7 additions & 0 deletions src/Core/RequestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public function respond(Request $request) : mixed {
$request->responseModel
);
$this->eventDispatcher->dispatch(new ResponseModelBuilt($requestedModel));
if ($requestedModel->class) {
}
return $this->tryRespond($request, $requestedModel);
}

Expand Down Expand Up @@ -86,6 +88,11 @@ protected function tryRespond(
$this->eventDispatcher->dispatch(new ResponseGenerationFailed($request, $e->getMessage()));
throw $e;
}
// TODO: this is workaround for now, find the source of bug
// something is not returning array of errors, but a DeserializationException
if (!is_array($errors)) {
$errors = [$errors->getMessage()];
}
$messages[] = ['role' => 'assistant', 'content' => $json];
$messages[] = ['role' => 'user', 'content' => $this->retryPrompt . ': ' . implode(", ", $errors)];
$retries++;
Expand Down
15 changes: 12 additions & 3 deletions src/Core/ResponseModel.php
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
<?php
namespace Cognesy\Instructor\Core;

use Cognesy\Instructor\Schema\Data\Schema\Schema;

class ResponseModel
{
public mixed $instance; // calculated
public ?string $class; // calculated
public ?array $functionCall; // calculated
public Schema $schema; // calculated
public array $jsonSchema;
public bool $receivesEvents = false;

public string $functionName = 'extract_data';
public string $functionDescription = 'Extract data from provided content';

public function __construct(
string $class = null,
mixed $instance = null,
array $functionCall = null,
string $class = null,
mixed $instance = null,
Schema $schema = null,
array $jsonSchema = null,
array $functionCall = null,
)
{
$this->class = $class;
$this->instance = $instance;
$this->functionCall = $functionCall;
$this->schema = $schema;
$this->jsonSchema = $jsonSchema;
}
}
78 changes: 50 additions & 28 deletions src/Core/ResponseModelFactory.php
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
<?php
namespace Cognesy\Instructor\Core;

use Cognesy\Instructor\Contracts\CanDeserializeResponse;
use Cognesy\Instructor\Contracts\CanProvideSchema;
use Cognesy\Instructor\Contracts\CanValidateResponse;
use Cognesy\Instructor\Contracts\CanReceiveEvents;
use Cognesy\Instructor\Schema\Data\Schema\ObjectSchema;
use Cognesy\Instructor\Schema\Factories\FunctionCallFactory;
use Cognesy\Instructor\Schema\Factories\SchemaFactory;
use Cognesy\Instructor\Schema\Utils\SchemaBuilder;
use Exception;


class ResponseModelFactory
{
private FunctionCallFactory $functionCallFactory;
private CanDeserializeResponse $responseDeserializer;
private CanValidateResponse $responseValidator;
private SchemaFactory $schemaFactory;
private SchemaBuilder $schemaBuilder;

private string $functionName = 'extract_data';
private string $functionDescription = 'Extract data from provided content';

public function __construct(
FunctionCallFactory $functionCallFactory,
CanDeserializeResponse $responseDeserializer,
CanValidateResponse $responseValidator,
SchemaFactory $schemaFactory,
SchemaBuilder $schemaBuilder
) {
$this->functionCallFactory = $functionCallFactory;
$this->responseDeserializer = $responseDeserializer;
$this->responseValidator = $responseValidator;
$this->schemaFactory = $schemaFactory;
$this->schemaBuilder = $schemaBuilder;
}

public function from(mixed $requestedModel) : ResponseModel {
Expand All @@ -41,18 +42,20 @@ public function from(mixed $requestedModel) : ResponseModel {
private function makeStringResponseModel(string $requestedModel) : ResponseModel {
$class = $requestedModel;
$instance = new $class;
$functionCall = $this->functionCallFactory->fromClass(
$requestedModel,
$schema = $this->schemaFactory->schema($class);
$jsonSchema = $schema->toArray($this->functionCallFactory->onObjectRef(...));
$functionCall = $this->functionCallFactory->render(
$jsonSchema,
$this->functionName,
$this->functionDescription
);
// make model object
return new ResponseModel(
$class,
$instance,
$schema,
$jsonSchema,
$functionCall,
$this->responseDeserializer,
$this->responseValidator
);
}

Expand All @@ -62,18 +65,20 @@ private function makeArrayResponseModel(array $requestedModel) : ResponseModel {
throw new Exception('Provided JSON schema must contain $comment field with fully qualified class name');
}
$instance = new $class;
$functionCall = $this->functionCallFactory->fromArray(
$requestedModel,
$schema = $this->schemaBuilder->fromArray($requestedModel);
$jsonSchema = $requestedModel;
$functionCall = $this->functionCallFactory->render(
$jsonSchema,
$this->functionName,
$this->functionDescription
);
// make model object
return new ResponseModel(
$class,
$instance,
$schema,
$jsonSchema,
$functionCall,
$this->responseDeserializer,
$this->responseValidator
);
}

Expand All @@ -85,55 +90,72 @@ private function makeSchemaProviderResponseModel(mixed $requestedModel) : Respon
$class = $requestedModel;
$instance = new $class;
}
$functionCall = $this->functionCallFactory->fromArray(
$instance->toJsonSchema(),
$jsonSchema = $instance->toJsonSchema();
$schema = $this->schemaBuilder->fromArray($jsonSchema);
$functionCall = $this->functionCallFactory->render(
$jsonSchema,
$this->functionName,
$this->functionDescription
);
// make model object
return new ResponseModel(
$class,
$instance,
$schema,
$jsonSchema,
$functionCall,
$this->responseDeserializer,
$this->responseValidator
);
}

private function makeSchemaResponseModel(ObjectSchema $requestedModel) : ResponseModel {
$schema = $requestedModel;
$class = $schema->type->class;
$instance = new $class;
$functionCall = $this->functionCallFactory->fromSchema(
$schema,
$schema = $requestedModel;
$jsonSchema = $schema->toArray($this->functionCallFactory->onObjectRef(...));
$functionCall = $this->functionCallFactory->render(
$jsonSchema,
$this->functionName,
$this->functionDescription
);
// make model object
return new ResponseModel(
$class,
$instance,
$schema,
$jsonSchema,
$functionCall,
$this->responseDeserializer,
$this->responseValidator
);
}

private function makeInstanceResponseModel(object $requestedModel) : ResponseModel {
$class = get_class($requestedModel);
$instance = $requestedModel;
$functionCall = $this->functionCallFactory->fromClass(
get_class($requestedModel),
$schema = $this->schemaFactory->schema($class);
$jsonSchema = $schema->toArray($this->functionCallFactory->onObjectRef(...));
$functionCall = $this->functionCallFactory->render(
$jsonSchema,
$this->functionName,
$this->functionDescription
);
// make model object
return new ResponseModel(
$class,
$instance,
$schema,
$jsonSchema,
$functionCall,
$this->responseDeserializer,
$this->responseValidator
);
}

private function canReceiveEvents(mixed $requestedModel, ResponseModel $responseModel) : array {
return match (true) {
//$requestedModel instanceof ObjectSchema => $requestedModel->eventHandlers,
is_subclass_of($requestedModel, CanReceiveEvents::class) => true,
is_subclass_of($responseModel, CanReceiveEvents::class) => true,
is_string($requestedModel) => [],
is_array($requestedModel) => [],
default => [],
};
}
}
34 changes: 34 additions & 0 deletions src/Extras/Sequence/Sequence.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Cognesy\Instructor\Extras\Sequence;

use Iterator;
use IteratorAggregate;
use Traversable;

class Sequence implements Sequenceable, IteratorAggregate
{
private string $class;
private Iterator $iterator;

public function __construct(string $class) {
$this->class = $class;
}

public static function of(string $class) : Sequenceable {
return new self($class);
}

public function getSequenceClass() : string {
return $this->class;
}

public function getIterator(): Traversable
{
return $this->iterator;
}

public function setIterator(Iterator $iterator) {
$this->iterator = $iterator;
}
}
8 changes: 8 additions & 0 deletions src/Extras/Sequence/Sequenceable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Cognesy\Instructor\Extras\Sequence;

interface Sequenceable
{
public static function of(string $class) : Sequenceable;
}
7 changes: 6 additions & 1 deletion src/Schema/Data/Schema/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

namespace Cognesy\Instructor\Schema\Data\Schema;

use Cognesy\Instructor\Events\Event;
use Cognesy\Instructor\Schema\Data\TypeDetails;

class Schema
abstract class Schema
{
public TypeDetails $type;
public string $name = '';
public string $description = '';
public bool $canReceiveEvents = false;

public function __construct(
TypeDetails $type,
Expand All @@ -27,4 +29,7 @@ public function toArray(callable $refCallback = null) : array
'description' => $this->description,
]);
}

public function onEvent(Event $event) : void {
}
}
Loading

0 comments on commit 614ab0b

Please sign in to comment.