Skip to content

Commit

Permalink
Hook points onEvent(), wiretap(), onError() added to Instructor class
Browse files Browse the repository at this point in the history
  • Loading branch information
ddebowczyk committed Mar 7, 2024
1 parent 167d7f5 commit dcb3b9b
Show file tree
Hide file tree
Showing 27 changed files with 303 additions and 165 deletions.
36 changes: 36 additions & 0 deletions examples/Wiretap/run.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

$loader = require 'vendor/autoload.php';
$loader->add('Cognesy\\Instructor\\', __DIR__ . '../../src/');

use Cognesy\Instructor\Instructor;
use Symfony\Component\Validator\Constraints as Assert;

enum Role : string {
case CEO = 'ceo';
case CTO = 'cto';
case Developer = 'developer';
case Other = 'other';
}

class UserDetail
{
public string $name;
public Role $role;
#[Assert\Positive]
public int $age;
}

$user = (new Instructor)
->wiretap(fn($event) => $event->print())
->respond(
messages: [["role" => "user", "content" => "Contact our CTO, Jason is -28 years old -- Tom"]],
responseModel: UserDetail::class,
)
;

assert($user->role == null);
12 changes: 7 additions & 5 deletions src/Core/RequestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
use Cognesy\Instructor\Contracts\CanTransformResponse;
use Cognesy\Instructor\Events\RequestHandler\RequestSentToLLM;
use Cognesy\Instructor\Events\RequestHandler\ResponseGenerated;
use Cognesy\Instructor\Events\RequestHandler\ResponseGenerationFailed;
use Cognesy\Instructor\Events\RequestHandler\ResponseModelBuilt;
use Cognesy\Instructor\Events\RequestHandler\ResponseReceivedFromLLM;
use Cognesy\Instructor\Events\RequestHandler\ResponseTransformationFinished;
use Cognesy\Instructor\Events\RequestHandler\ResponseTransformationStarted;
use Cognesy\Instructor\Events\RequestHandler\ResponseTransformed;
use Cognesy\Instructor\Events\RequestHandler\ResponseConvertedToObject;
use Cognesy\Instructor\Events\RequestHandler\ResponseValidationFailed;
use Exception;

Expand Down Expand Up @@ -68,21 +69,22 @@ protected function tryRespond(
$json = $response->toolCalls[0]->functionArguments;
[$object, $errors] = $responseModel->toResponse($json);
if (empty($errors)) {
$this->eventDispatcher->dispatch(new ResponseConvertedToObject($object));
if ($object instanceof CanTransformResponse) {
$this->eventDispatcher->dispatch(new ResponseTransformationStarted($object));
$result = $object->transform();
$this->eventDispatcher->dispatch(new ResponseTransformationFinished($result));
$this->eventDispatcher->dispatch(new ResponseTransformed($result));
} else {
$result = $object;
}
$this->eventDispatcher->dispatch(new ResponseGenerated($result));
return $result;
}
$this->eventDispatcher->dispatch(new ResponseValidationFailed($errors));
$this->eventDispatcher->dispatch(new ResponseValidationFailed($retries, $errors));
$messages[] = ['role' => 'assistant', 'content' => $json];
$messages[] = ['role' => 'user', 'content' => $this->retryPrompt . '\n' . $errors];
$retries++;
}
$this->eventDispatcher->dispatch(new ResponseGenerationFailed($retries, $errors));
throw new Exception("Failed to extract data due to validation constraints: " . $errors);
}
}
72 changes: 19 additions & 53 deletions src/Events/Event.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Cognesy\Instructor\Events;
use Carbon\Carbon;
use Cognesy\Instructor\Utils\Console;
use Ramsey\Uuid\Uuid;

abstract class Event
Expand All @@ -14,71 +15,36 @@ public function __construct()
$this->createdAt = Carbon::now();
}

public function __toString(): string
{
return $this->short();
public function toLog(): string {
return $this->logFormat((string) $this);
}

protected function format(string $message): string
{
return $this->short($message);
public function toConsole(): string {
$message = (string) $this;
$message = str_replace("\n", ' ', $message);
return $this->consoleFormat($message);
}

private function long(string $message): string
{
$shortId = substr($this->eventId, -4);
public function print(): void {
echo $this->toConsole()."\n";
}

private function logFormat(string $message): string {
$class = (new \ReflectionClass($this))->getName();
$segments = explode('\\', $class);
$eventName = $segments[count($segments) - 1];
$eventGroup = $segments[count($segments) - 2];
$source = "...\\{$eventGroup}\\{$eventName}";
return "({$shortId}) {$this->createdAt->format('Y-m-d H:i:s v')}ms [$source] : $message";
return "({$this->eventId}) {$this->createdAt->format('Y-m-d H:i:s v')}ms [$class] - $message";
}

private function short(string $message = '') : string {
private function consoleFormat(string $message = '') : string {
$segments = explode('\\', (new \ReflectionClass($this))->getName());
$eventName = array_pop($segments);
$eventGroup = implode('\\', $segments);
return $this->columns([
return Console::columns([
[7, '(.'.substr($this->eventId, -4).')'],
[5, $this->createdAt->format('v').'ms'],
[15, "{$eventGroup}\\", STR_PAD_LEFT],
[20, "{$eventName}", STR_PAD_LEFT],
[14, $this->createdAt->format('H:i:s v').'ms'],
//[15, "{$eventGroup}\\", STR_PAD_LEFT],
[24, "{$eventName}"],
'-',
[-1, $message],
]);
}

private function columns(array $columns): string {
$terminalWidth = 140;
$message = '';
foreach ($columns as $row) {
if (is_string($row)) {
$message .= $row;
} else {
if ($row[0] == -1) {
$row[0] = $terminalWidth - strlen($message);
}
$message .= $this->toColumn(
chars: $row[0],
text: $row[1],
align: $row[2]??STR_PAD_RIGHT
);
}
$message .= ' ';
}
return trim($message);
}

private function toColumn(int $chars, mixed $text, int $align): string {
$short = ($align == STR_PAD_LEFT)
? substr($text, -$chars)
: substr($text, 0, $chars);
if ($text != $short) {
$short = ($align == STR_PAD_LEFT)
? ''.substr($short,1)
: substr($short, 0, -1).'';
}
return str_pad($short, $chars, ' ', $align);
], 140);
}
}
21 changes: 21 additions & 0 deletions src/Events/Instructor/ErrorRaised.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Cognesy\Instructor\Events\Instructor;

use Cognesy\Instructor\Events\Event;
use Throwable;

class ErrorRaised extends Event
{
public function __construct(
public Throwable $e
)
{
parent::__construct();
}

public function __toString(): string
{
return $this->e->getMessage();
}
}
2 changes: 1 addition & 1 deletion src/Events/Instructor/RequestReceived.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->request));
return json_encode($this->request);
}
}
2 changes: 1 addition & 1 deletion src/Events/Instructor/ResponseSent.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->response));
return json_encode($this->response);
}
}
2 changes: 1 addition & 1 deletion src/Events/LLM/ChunkReceived.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public function __construct(

public function __toString(): string
{
return $this->format($this->chunk);
return $this->chunk;
}
}
2 changes: 1 addition & 1 deletion src/Events/LLM/PartialJsonReceived.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public function __construct(

public function __toString(): string
{
return $this->format($this->partialJson);
return $this->partialJson;
}
}
2 changes: 1 addition & 1 deletion src/Events/LLM/RequestSent.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->request));
return json_encode($this->request);
}
}
2 changes: 1 addition & 1 deletion src/Events/LLM/ResponseReceived.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->response));
return json_encode($this->response);
}
}
2 changes: 1 addition & 1 deletion src/Events/LLM/StreamedResponseFinished.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->lastResponse));
return json_encode($this->lastResponse);
}
}
2 changes: 1 addition & 1 deletion src/Events/LLM/StreamedResponseReceived.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->response));
return json_encode($this->response);
}
}
4 changes: 2 additions & 2 deletions src/Events/RequestHandler/RequestSentToLLM.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode([
return json_encode([
'messages' => $this->messages,
'tool' => $this->responseModel->functionName,
'tools' => $this->responseModel->functionCall,
'model' => $this->request->model,
'options' => $this->request->options
]));
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Cognesy\Instructor\Events\Event;

class ResponseTransformationStarted extends Event
class ResponseConvertedToObject extends Event
{
public function __construct(
public mixed $object
Expand All @@ -14,6 +14,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->object));
return json_encode($this->object);
}
}
6 changes: 1 addition & 5 deletions src/Events/RequestHandler/ResponseGenerated.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@

class ResponseGenerated extends Event
{

/**
* @param mixed $response
*/
public function __construct(
public mixed $response
)
Expand All @@ -19,6 +15,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->response));
return json_encode($this->response);
}
}
24 changes: 24 additions & 0 deletions src/Events/RequestHandler/ResponseGenerationFailed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
namespace Cognesy\Instructor\Events\RequestHandler;

use Cognesy\Instructor\Events\Event;

class ResponseGenerationFailed extends Event
{
public function __construct(
public int $retries,
public string $errors
)
{
parent::__construct();
}

public function __toString(): string
{
return json_encode([
'retries' => $this->retries,
'errors' => $this->errors
]);
}
}

2 changes: 1 addition & 1 deletion src/Events/RequestHandler/ResponseModelBuilt.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->requestedModel));
return json_encode($this->requestedModel);
}
}
4 changes: 1 addition & 3 deletions src/Events/RequestHandler/ResponseReceivedFromLLM.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode(
$this->response
));
return json_encode($this->response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Cognesy\Instructor\Events\Event;

class ResponseTransformationFinished extends Event
class ResponseTransformed extends Event
{
public function __construct(
public mixed $result
Expand All @@ -14,6 +14,6 @@ public function __construct(

public function __toString(): string
{
return $this->format(json_encode($this->result));
return json_encode($this->result);
}
}
Loading

0 comments on commit dcb3b9b

Please sign in to comment.