-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from llm-agents-php/feature/agent-executor-pipe…
…line Adds agent executor pipeline
- Loading branch information
Showing
13 changed files
with
437 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor\Exception; | ||
|
||
class ExecutorException extends \DomainException | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor\Exception; | ||
|
||
final class InvalidPromptException extends ExecutorException | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor; | ||
|
||
use LLM\Agents\LLM\ContextInterface; | ||
use LLM\Agents\LLM\OptionsInterface; | ||
use LLM\Agents\LLM\Prompt\Chat\PromptInterface; | ||
use LLM\Agents\LLM\PromptContextInterface; | ||
|
||
final readonly class ExecutionInput | ||
{ | ||
public function __construct( | ||
public string $agent, | ||
public \Stringable|string|PromptInterface $prompt, | ||
public ContextInterface $context, | ||
public OptionsInterface $options, | ||
public PromptContextInterface $promptContext, | ||
) {} | ||
|
||
public function withAgent(string $agent): self | ||
{ | ||
return new self( | ||
$agent, | ||
$this->prompt, | ||
$this->context, | ||
$this->options, | ||
$this->promptContext, | ||
); | ||
} | ||
|
||
public function withPromptContext(PromptContextInterface $context): self | ||
{ | ||
return new self( | ||
$this->agent, | ||
$this->prompt, | ||
$this->context, | ||
$this->options, | ||
$context, | ||
); | ||
} | ||
|
||
public function withContext(ContextInterface $context): self | ||
{ | ||
return new self( | ||
$this->agent, | ||
$this->prompt, | ||
$context, | ||
$this->options, | ||
$this->promptContext, | ||
); | ||
} | ||
|
||
public function withPrompt(PromptInterface $prompt): self | ||
{ | ||
return new self( | ||
$this->agent, | ||
$prompt, | ||
$this->context, | ||
$this->options, | ||
$this->promptContext, | ||
); | ||
} | ||
|
||
public function withOptions(OptionsInterface $options): self | ||
{ | ||
return new self( | ||
$this->agent, | ||
$this->prompt, | ||
$this->context, | ||
$options, | ||
$this->promptContext, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor; | ||
|
||
use LLM\Agents\Agent\Execution; | ||
|
||
interface ExecutorInterceptorInterface | ||
{ | ||
public function execute( | ||
ExecutionInput $input, | ||
InterceptorHandler $next, | ||
): Execution; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor; | ||
|
||
use LLM\Agents\Agent\Execution; | ||
use LLM\Agents\LLM\ContextInterface; | ||
use LLM\Agents\LLM\OptionsInterface; | ||
use LLM\Agents\LLM\Prompt\Chat\Prompt; | ||
use LLM\Agents\LLM\Prompt\Context; | ||
use LLM\Agents\LLM\PromptContextInterface; | ||
|
||
interface ExecutorInterface | ||
{ | ||
public function execute( | ||
string $agent, | ||
string|\Stringable|Prompt $prompt, | ||
?ContextInterface $context = null, | ||
?OptionsInterface $options = null, | ||
PromptContextInterface $promptContext = new Context(), | ||
): Execution; | ||
|
||
public function withInterceptor(ExecutorInterceptorInterface ...$interceptor): self; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor; | ||
|
||
use LLM\Agents\Agent\Execution; | ||
use LLM\Agents\AgentExecutor\Exception\InvalidPromptException; | ||
use LLM\Agents\LLM\ContextFactoryInterface; | ||
use LLM\Agents\LLM\ContextInterface; | ||
use LLM\Agents\LLM\LLMInterface; | ||
use LLM\Agents\LLM\OptionsFactoryInterface; | ||
use LLM\Agents\LLM\OptionsInterface; | ||
use LLM\Agents\LLM\Prompt\Chat\Prompt; | ||
use LLM\Agents\LLM\Prompt\Context; | ||
use LLM\Agents\LLM\Prompt\PromptInterface; | ||
use LLM\Agents\LLM\PromptContextInterface; | ||
|
||
final class ExecutorPipeline implements ExecutorInterface | ||
{ | ||
/** @var ExecutorInterceptorInterface[] */ | ||
private array $interceptors = []; | ||
private int $offset = 0; | ||
|
||
public function __construct( | ||
private readonly LLMInterface $llm, | ||
private readonly OptionsFactoryInterface $optionsFactory, | ||
private readonly ContextFactoryInterface $contextFactory, | ||
) {} | ||
|
||
public function execute( | ||
string $agent, | ||
\Stringable|string|Prompt $prompt, | ||
?ContextInterface $context = null, | ||
?OptionsInterface $options = null, | ||
PromptContextInterface $promptContext = new Context(), | ||
): Execution { | ||
$context ??= $this->contextFactory->create(); | ||
$options ??= $this->optionsFactory->create(); | ||
|
||
if (!isset($this->interceptors[$this->offset])) { | ||
if (!$prompt instanceof PromptInterface) { | ||
throw new InvalidPromptException(\sprintf('Prompt must be an instance of %s', PromptInterface::class)); | ||
} | ||
|
||
$result = $this->llm->generate($context, $prompt, $options); | ||
|
||
return new Execution( | ||
result: $result, | ||
prompt: $prompt, | ||
); | ||
} | ||
|
||
return $this->interceptors[$this->offset]->execute( | ||
input: new ExecutionInput( | ||
agent: $agent, | ||
prompt: $prompt, | ||
context: $context, | ||
options: $options, | ||
promptContext: $promptContext, | ||
), | ||
next: new InterceptorHandler(executor: $this->next()), | ||
); | ||
} | ||
|
||
public function withInterceptor(ExecutorInterceptorInterface ...$interceptor): ExecutorInterface | ||
{ | ||
$pipeline = clone $this; | ||
$pipeline->interceptors = \array_merge($this->interceptors, $interceptor); | ||
|
||
return $pipeline; | ||
} | ||
|
||
private function next(): self | ||
{ | ||
$pipeline = clone $this; | ||
$pipeline->offset++; | ||
return $pipeline; | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
src/AgentExecutor/Interceptor/GeneratePromptInterceptor.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor\Interceptor; | ||
|
||
use LLM\Agents\Agent\AgentRepositoryInterface; | ||
use LLM\Agents\Agent\Execution; | ||
use LLM\Agents\AgentExecutor\ExecutionInput; | ||
use LLM\Agents\AgentExecutor\ExecutorInterceptorInterface; | ||
use LLM\Agents\AgentExecutor\InterceptorHandler; | ||
use LLM\Agents\LLM\AgentPromptGeneratorInterface; | ||
use LLM\Agents\LLM\Prompt\Chat\Prompt; | ||
|
||
final readonly class GeneratePromptInterceptor implements ExecutorInterceptorInterface | ||
{ | ||
public function __construct( | ||
private AgentRepositoryInterface $agents, | ||
private AgentPromptGeneratorInterface $promptGenerator, | ||
) {} | ||
|
||
public function execute( | ||
ExecutionInput $input, | ||
InterceptorHandler $next, | ||
): Execution { | ||
if (!$input->prompt instanceof Prompt) { | ||
$input = $input->withPrompt( | ||
$this->promptGenerator->generate( | ||
$this->agents->get($input->agent), | ||
$input->prompt, | ||
$input->promptContext, | ||
), | ||
); | ||
} | ||
|
||
return $next($input); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor\Interceptor; | ||
|
||
use LLM\Agents\Agent\AgentRepositoryInterface; | ||
use LLM\Agents\Agent\Execution; | ||
use LLM\Agents\AgentExecutor\ExecutionInput; | ||
use LLM\Agents\AgentExecutor\ExecutorInterceptorInterface; | ||
use LLM\Agents\AgentExecutor\InterceptorHandler; | ||
|
||
final readonly class InjectModelInterceptor implements ExecutorInterceptorInterface | ||
{ | ||
public function __construct( | ||
private AgentRepositoryInterface $agents, | ||
) {} | ||
|
||
public function execute( | ||
ExecutionInput $input, | ||
InterceptorHandler $next, | ||
): Execution { | ||
$agent = $this->agents->get($input->agent); | ||
|
||
$input = $input->withOptions( | ||
$input->options->with('model', $agent->getModel()->name), | ||
); | ||
|
||
return $next($input); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
src/AgentExecutor/Interceptor/InjectOptionsInterceptor.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor\Interceptor; | ||
|
||
use LLM\Agents\Agent\AgentRepositoryInterface; | ||
use LLM\Agents\Agent\Execution; | ||
use LLM\Agents\AgentExecutor\ExecutionInput; | ||
use LLM\Agents\AgentExecutor\ExecutorInterceptorInterface; | ||
use LLM\Agents\AgentExecutor\InterceptorHandler; | ||
|
||
final readonly class InjectOptionsInterceptor implements ExecutorInterceptorInterface | ||
{ | ||
public function __construct( | ||
private AgentRepositoryInterface $agents, | ||
) {} | ||
|
||
public function execute( | ||
ExecutionInput $input, | ||
InterceptorHandler $next, | ||
): Execution { | ||
$agent = $this->agents->get($input->agent); | ||
|
||
foreach ($agent->getConfiguration() as $configuration) { | ||
$input->withOptions( | ||
$input->options->with($configuration->key, $configuration->content), | ||
); | ||
} | ||
|
||
return $next($input); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/AgentExecutor/Interceptor/InjectResponseIntoPromptInterceptor.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace LLM\Agents\AgentExecutor\Interceptor; | ||
|
||
use LLM\Agents\Agent\Execution; | ||
use LLM\Agents\AgentExecutor\ExecutionInput; | ||
use LLM\Agents\AgentExecutor\ExecutorInterceptorInterface; | ||
use LLM\Agents\AgentExecutor\InterceptorHandler; | ||
use LLM\Agents\LLM\Response\ChatResponse; | ||
use LLM\Agents\LLM\Response\ToolCalledResponse; | ||
|
||
final class InjectResponseIntoPromptInterceptor implements ExecutorInterceptorInterface | ||
{ | ||
public function execute( | ||
ExecutionInput $input, | ||
InterceptorHandler $next, | ||
): Execution { | ||
$execution = $next($input); | ||
|
||
$prompt = $execution->prompt; | ||
|
||
if ( | ||
$execution->result instanceof ChatResponse | ||
|| $execution->result instanceof ToolCalledResponse | ||
) { | ||
$prompt = $prompt->withAddedMessage($execution->result->toMessage()); | ||
} | ||
|
||
return new Execution( | ||
result: $execution->result, | ||
prompt: $prompt, | ||
); | ||
} | ||
} |
Oops, something went wrong.