Skip to content

Commit

Permalink
feat(traits): introduce configurable agents and conditionable utiliti…
Browse files Browse the repository at this point in the history
…es 🛠️

- Added `HasConfig` and `Conditionable` traits for enhanced configurability and condition-based code execution.
- Implemented `PendingAgentChain` for chaining agent tasks efficiently.
- Defined `ArrayStore` contract and repository for array-based storage and manipulation.
- Introduced new `RatSplitAnswerAgent`, `RatDraftAgent`, and `GetQueryAgent` for specialized agent operations.
- Added blade templates for new agent prompts.
- Created `AgentChain` class to manage sequences of agent tasks.
- Enhanced `Helpers` with multi-type support for plugin booting.
- Added tests for `RatAgentChain` to ensure accurate agent chain execution.
  • Loading branch information
use-the-fork committed Oct 17, 2024
1 parent 95856a8 commit 24d4ec4
Show file tree
Hide file tree
Showing 19 changed files with 604 additions and 2 deletions.
10 changes: 10 additions & 0 deletions resources/views/Prompts/Rat/DraftPrompt.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<message type="user">
### Instruction
Try to answer this question/instruction with step-by-step thoughts and make the answer more structural. Split the answer into several paragraphs.
{!! $question !!}

@include('synapse::Parts.OutputSchema')
</message>



11 changes: 11 additions & 0 deletions resources/views/Prompts/Rat/GetQueryPrompt.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<message type="user">
## User input: {{ $question }}

## Response
{{ $answer }}

## Instruction
Summarize the content with a focus on the last sentences to create a concise search query for Bing. Use search syntax to make the query specific and relevant for content verification.

@include('synapse::Parts.OutputSchema')
</message>
12 changes: 12 additions & 0 deletions resources/views/Prompts/Rat/SplitAnswerPrompt.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<message type="user">
## User input: {{ $question }}

## Response
{{ $answer }}

## Instruction
Split the answer of the question into multiple paragraphs with each paragraph containing a complete thought.
The answer should be splited into less than {{ $number_of_paragraphs }} paragraphs.

@include('synapse::Parts.OutputSchema')
</message>
76 changes: 76 additions & 0 deletions src/AgentChain.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

declare(strict_types=1);

namespace UseTheFork\Synapse;

use UseTheFork\Synapse\AgentTask\PendingAgentChain;
use UseTheFork\Synapse\Traits\HasConfig;
use UseTheFork\Synapse\Traits\Makeable;
use UseTheFork\Synapse\ValueObject\Message;

class AgentChain
{
use Makeable;
use HasConfig;

protected PendingAgentChain $pendingAgentChain;
protected $pipeline;

public function __construct(array $agents)
{
foreach ($agents as $agent) {
if(! ($agent instanceof Agent)){
throw new \Exception("Agent must be an instance of Agent");
}
}

$this->config()->add('persistInputs', []);
$this->config()->add('agents', collect($agents));
$this->pendingAgentChain = $this->createPendingAgentChain();

}

/**
* Create a new PendingAgentTask
*/
public function createPendingAgentChain(): PendingAgentChain
{
return new PendingAgentChain($this);
}

/**
* Handles the user input and extra agent arguments to retrieve the response.
*
* @param array|null $input The input array.
* @param array|null $extraAgentArgs The extra agent arguments array.
* @return Message The final message from the agent.
*
* @throws Throwable
*/
public function handle(?array $input): Message
{
$this->config()->add('input', $input);
$this->config()->get('agents')->each(function ($agent) use ($input) {
$input = [
...$this->config()->get('input'),
...$this->config()->get('persistInputs')
];
$response = $agent->handle($input);
$this->config()->add('input', $response->content());
});

return Message::make([
'role' => 'agent',
'finish_reason' => 'stop',
'content' => $this->config()->get('input')
]);
}

public function persistInputs(array $inputs): static
{
$this->config()->add('persistInputs', $inputs);

return $this;
}
}
46 changes: 46 additions & 0 deletions src/AgentTask/PendingAgentChain.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace UseTheFork\Synapse\AgentTask;

use UseTheFork\Synapse\AgentChain;
use UseTheFork\Synapse\AgentTask\StartTasks\BootTraits;

class PendingAgentChain
{

protected AgentChain $agentChain;

public function __construct(AgentChain $agentChain)
{
$this->agentChain = $agentChain;

$this
->tap(new BootTraits);

}

/**
* Tap into the agent chain
*
* @return $this
*/
protected function tap(callable $callable): static
{
$callable($this);

return $this;
}

/**
* Retrieve the agent associated with the current task.
*
* @return AgentChain The current agent instance.
*/
public function agent(): AgentChain
{
return $this->agentChain;
}

}
3 changes: 2 additions & 1 deletion src/AgentTask/StartTasks/BootTraits.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace UseTheFork\Synapse\AgentTask\StartTasks;


use UseTheFork\Synapse\AgentTask\PendingAgentChain;
use UseTheFork\Synapse\AgentTask\PendingAgentTask;
use UseTheFork\Synapse\Helpers\Helpers;

Expand All @@ -13,7 +14,7 @@ class BootTraits
/**
* Boot the plugins
*/
public function __invoke(PendingAgentTask $pendingAgentTask): PendingAgentTask
public function __invoke(PendingAgentTask|PendingAgentChain $pendingAgentTask): PendingAgentTask|PendingAgentChain
{

$agent = $pendingAgentTask->agent();
Expand Down
27 changes: 27 additions & 0 deletions src/Agents/Rat/GetQueryAgent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace UseTheFork\Synapse\Agents\Rat;

use UseTheFork\Synapse\Agent;
use UseTheFork\Synapse\Traits\Agent\ValidatesOutputSchema;
use UseTheFork\Synapse\ValueObject\SchemaRule;

class GetQueryAgent extends Agent
{
use ValidatesOutputSchema;

protected string $promptView = 'synapse::Prompts.Rat.GetQueryPrompt';

public function resolveOutputSchema(): array
{
return [
SchemaRule::make([
'name' => 'query',
'rules' => 'required|string',
'description' => 'The query to search for.',
]),
];
}
}
27 changes: 27 additions & 0 deletions src/Agents/Rat/RatDraftAgent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace UseTheFork\Synapse\Agents\Rat;

use UseTheFork\Synapse\Agent;
use UseTheFork\Synapse\Traits\Agent\ValidatesOutputSchema;
use UseTheFork\Synapse\ValueObject\SchemaRule;

class RatDraftAgent extends Agent
{
use ValidatesOutputSchema;

protected string $promptView = 'synapse::Prompts.Rat.DraftPrompt';

public function resolveOutputSchema(): array
{
return [
SchemaRule::make([
'name' => 'answer',
'rules' => 'required|string',
'description' => 'Your answer split in to paragraphs.',
]),
];
}
}
32 changes: 32 additions & 0 deletions src/Agents/Rat/RatSplitAnswerAgent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace UseTheFork\Synapse\Agents\Rat;

use UseTheFork\Synapse\Agent;
use UseTheFork\Synapse\Traits\Agent\ValidatesOutputSchema;
use UseTheFork\Synapse\ValueObject\SchemaRule;

class RatSplitAnswerAgent extends Agent
{
use ValidatesOutputSchema;

protected string $promptView = 'synapse::Prompts.Rat.SplitAnswerPrompt';

public function resolveOutputSchema(): array
{
return [
SchemaRule::make([
'name' => 'paragraphs',
'rules' => 'required|array',
'description' => 'Your answer split in to paragraphs.',
]),
SchemaRule::make([
'name' => 'paragraphs.*',
'rules' => 'required|string',
'description' => 'A paragraph of your answer.',
]),
];
}
}
60 changes: 60 additions & 0 deletions src/Contracts/ArrayStore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace UseTheFork\Synapse\Contracts;

interface ArrayStore
{
/**
* Add an item to the repository.
*
* @return $this
*/
public function add(string $key, mixed $value): static;

/**
* Retrieve all the items.
*
* @return array<string, mixed>
*/
public function all(): array;

/**
* Retrieve a single item.
*/
public function get(string $key, mixed $default = null): mixed;

/**
* Determine if the store is empty
*/
public function isEmpty(): bool;

/**
* Determine if the store is not empty
*/
public function isNotEmpty(): bool;

/**
* Merge in other arrays.
*
* @param array<string, mixed> ...$arrays
* @return $this
*/
public function merge(array ...$arrays): static;

/**
* Remove an item from the store.
*
* @return $this
*/
public function remove(string $key): static;

/**
* Overwrite the entire repository's contents.
*
* @param array<string, mixed> $data
* @return $this
*/
public function set(array $data): static;
}
3 changes: 2 additions & 1 deletion src/Helpers/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Closure;
use ReflectionClass;
use UseTheFork\Synapse\AgentTask\PendingAgentChain;
use UseTheFork\Synapse\AgentTask\PendingAgentTask;

/**
Expand All @@ -22,7 +23,7 @@ final class Helpers
*
* @throws \ReflectionException
*/
public static function bootPlugin(PendingAgentTask $pendingAgentTask, string $trait): void
public static function bootPlugin(PendingAgentTask|PendingAgentChain $pendingAgentTask, string $trait): void
{
$agent = $pendingAgentTask->agent();

Expand Down
Loading

0 comments on commit 24d4ec4

Please sign in to comment.