Skip to content

Commit

Permalink
TASK: Add hidden date message together with the extended tool result
Browse files Browse the repository at this point in the history
  • Loading branch information
mficzel committed Jan 23, 2024
1 parent 3148f80 commit 8e486f4
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 29 deletions.
52 changes: 44 additions & 8 deletions Classes/Controller/AssistantModuleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use OpenAI\Contracts\ClientContract as OpenAiClientContract;
use OpenAI\Responses\Assistants\AssistantResponse;
use OpenAI\Responses\Threads\Messages\ThreadMessageResponse;
use OpenAI\Responses\Threads\Runs\Steps\ThreadRunStepResponseMessageCreationStepDetails;
use OpenAI\Responses\Threads\Runs\ThreadRunResponseRequiredActionFunctionToolCall;
use OpenAI\Responses\Threads\Runs\ThreadRunResponseToolFunction;
use Psr\Log\LoggerInterface;
Expand Down Expand Up @@ -78,7 +79,15 @@ public function newThreadAction(string $assistantId): void

public function createThreadAction(string $assistantId, string $message): void
{
$runResponse = $this->client->threads()->createAndRun(['assistant_id' => $assistantId, "thread" => ['messages' => [['role' => 'user', 'content' => $message]]]]);
$runResponse = $this->client->threads()->createAndRun([
'assistant_id' => $assistantId,
"thread" => [
'messages' => [
['role' => 'user', 'content' => 'current date: ' . (new \DateTimeImmutable())->format('Y-m-d'), 'metadata' => ['role' => 'system']],
['role' => 'user', 'content' => $message]
]
]
]);
$this->waitForRun($runResponse->threadId, $runResponse->id);
$this->redirect(actionName: 'showThread', arguments: ['threadId' => $runResponse->threadId, 'assistantId' => $assistantId]);
}
Expand All @@ -93,12 +102,19 @@ public function addThreadMessageAction(string $threadId, string $assistantId, st

public function showThreadAction(string $threadId, string $assistantId): void
{
$data = $this->client->threads()->messages()->list($threadId)->data;
$threadMessageResponses = $this->client->threads()->messages()->list($threadId)->data;

$threadMessageResponsesFiltered = array_filter(
$threadMessageResponses,
fn(ThreadMessageResponse $threadMessageResponse) => ($threadMessageResponse->metadata['role'] ?? null) !== 'system'
);

$messages = array_reverse(array_map(
$messages = array_reverse(
array_map(
fn(ThreadMessageResponse $threadMessageResponse) => MessageRecord::fromThreadMessageResponse($threadMessageResponse),
$data
));
$threadMessageResponsesFiltered
),
);

$this->view->assignMultiple([
'messages' => $messages,
Expand All @@ -110,24 +126,44 @@ public function showThreadAction(string $threadId, string $assistantId): void
private function waitForRun(string $threadId, string $runId): void
{
$threadRunResponse = $this->client->threads()->runs()->retrieve($threadId, $runId);
$combinedMetadata = [];
while ($threadRunResponse->status !== 'completed') {
if ($threadRunResponse->status === 'requires_action') {
if ($threadRunResponse->requiredAction) {
if ($threadRunResponse->requiredAction?->submitToolOutputs) {
$this->logger->info("chatbot tool calls", $threadRunResponse->requiredAction?->submitToolOutputs->toArray());
$toolOutputs = [];
foreach ($threadRunResponse->requiredAction->submitToolOutputs->toolCalls as $requiredToolCall) {
if ($requiredToolCall instanceof ThreadRunResponseRequiredActionFunctionToolCall) {
$toolInstance = $this->toolbox->findByName($requiredToolCall->function->name);
if ($toolInstance instanceof ToolContract) {
$toolResult = $toolInstance->execute(json_decode($requiredToolCall->function->arguments, true));
$toolOutputs["tool_outputs"][] = ['tool_call_id' => $requiredToolCall->id, 'output' => json_encode($toolResult)];
$toolOutputs["tool_outputs"][] = ['tool_call_id' => $requiredToolCall->id, 'output' => json_encode($toolResult->getData())];
$combinedMetadata[] = ['tool_call_id' => $requiredToolCall->id, 'data' => $toolResult->getData(), 'metadata' => $toolResult->getMetadata()];
}
}
}
$this->logger->info("chatbot tool submit", $toolOutputs);
$this->client->threads()->runs()->submitToolOutputs($threadId, $runId, $toolOutputs);
}
}
sleep(5);
sleep(1);
$threadRunResponse = $this->client->threads()->runs()->retrieve($threadId, $runId);
}
$this->logger->info("thread run response", $threadRunResponse->toArray());

// // add tool metadata
// if ($combinedMetadata) {
// $stepList = $this->client->threads()->runs()->steps()->list($threadId, $threadRunResponse->id);
// foreach ($stepList->data as $stepResponse) {
// $stepDetails = $stepResponse->stepDetails;
// if ($stepDetails instanceof ThreadRunStepResponseMessageCreationStepDetails) {
// $messageId = $stepDetails->messageCreation->messageId;
// if ($messageId) {
// $this->client->threads()->messages()->modify($threadId, $messageId, ['metadata' => ['tools' => json_encode($combinedMetadata)]]);
// break;
// }
// }
// }
// }
}
}
4 changes: 3 additions & 1 deletion Classes/Domain/MessageRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function __construct(
public readonly string $id,
public readonly string $role,
public readonly array $content,
public readonly array $metadata,
) {
}

Expand All @@ -28,7 +29,8 @@ public static function fromThreadMessageResponse(ThreadMessageResponse $response
return new self(
$response->id,
$response->role,
$response->content
$response->content,
$response->metadata
);
}
}
3 changes: 1 addition & 2 deletions Classes/Tools/ToolContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public function getParameterSchema(): array;

/**
* @param mixed[] $parameters
* @return mixed[]
*/
public function execute(array $parameters): array|\JsonSerializable;
public function execute(array $parameters): ToolResultContract;
}
23 changes: 23 additions & 0 deletions Classes/Tools/ToolResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);

namespace Sitegeist\Chatterbox\Tools;

class ToolResult implements ToolResultContract
{
public function __construct(
protected readonly array|\JsonSerializable $data,
protected readonly array|\JsonSerializable $metadata,
) {
}

public function getData(): array|\JsonSerializable
{
return $this->data;
}

public function getMetadata(): array|\JsonSerializable
{
return $this->metadata;
}
}
11 changes: 11 additions & 0 deletions Classes/Tools/ToolResultContract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);

namespace Sitegeist\Chatterbox\Tools;

interface ToolResultContract {

public function getData(): array|\JsonSerializable;

public function getMetadata(): array|\JsonSerializable;
}
52 changes: 34 additions & 18 deletions Resources/Private/Fusion/Root.fusion
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,30 @@ prototype(Sitegeist.Chatterbox:Assistant.Edit) < prototype(Neos.Fusion:Component

<div class="neos-control-group">
<label class="neos-control-label" >Tools</label>
<div class="neos-controls neos-controls-row">
<Neos.Fusion.Form:Select attributes.rows="20" attributes.class="neos-span12" field.name="assistant[selectedTools]" field.multiple>
<Neos.Fusion:Loop items={availableTools} itemName="tool" >
<Neos.Fusion.Form:Select.Option option.value={tool.name}>{tool.description}</Neos.Fusion.Form:Select.Option>
</Neos.Fusion:Loop>
</Neos.Fusion.Form:Select>
</div>
<table class="neos-table neos-span-6">
<thead>
<tr>
<th></th>
<th>Description</th>
</tr>
</thead>
<tbody>
<Neos.Fusion:Loop items={availableTools} itemName="tool">
<tr>
<td>
<label class="neos-checkbox" for={"tool-" + tool.name}>
<Neos.Fusion.Form:Checkbox attributes.id={"tool-" + tool.name} field.name="assistant[selectedTools]" field.multiple field.value={tool.name} />
<span></span>
</label>
</td>
<td>
{tool.description}

</td>
</tr>
</Neos.Fusion:Loop>
</tbody>
</table>
</div>

<div class="neos-control-group">
Expand Down Expand Up @@ -154,17 +171,16 @@ prototype(Sitegeist.Chatterbox:Assistant.ShowThread) < prototype(Neos.Fusion:Com
<legend>Show Thread {threadId}</legend>

<Neos.Fusion:Loop items={messages} itemName="message">
<Neos.Fusion:Loop items={message.content} itemName="messageContent">
<Neos.Fusion:Fragment @if={messageContent.type == 'text'}>
<div style={['margin: 20px 0;', (message.role == 'user') ? 'padding-left:0px;' : 'padding-left:50px;']}>
<p>{message.role}</p>
<span style={['min-width: 460px; padding:10px; border-radius: 10px; display:inline-block;', (message.role == 'user') ? 'background-color: #00b5ff;' : 'background-color: grey;']}>
<pre>{messageContent.text.value}</pre>
</span>
<br/>
</div>
</Neos.Fusion:Fragment>
</Neos.Fusion:Loop>
<div style={['margin: 20px 0;', (message.role == 'user') ? 'padding-left:0px;' : 'padding-left:50px;']}>
<p>{message.role}</p>
<span style={['min-width: 460px; padding:10px; border-radius: 10px; display:inline-block;', (message.role == 'user') ? 'background-color: #00b5ff;' : 'background-color: grey;']}>
<Neos.Fusion:Loop items={message.content} itemName="messageContent">
<pre @if={messageContent.type == 'text'}>{messageContent.text.value}</pre>
</Neos.Fusion:Loop>
</span>
<br/>
</div>
<pre @if={message.metadata}>{Json.stringify(message.metadata)}</pre>
</Neos.Fusion:Loop>

<Neos.Fusion.Form:Form
Expand Down

0 comments on commit 8e486f4

Please sign in to comment.