From e85f793b1666b68cd1187824b5157914b0195596 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Fri, 6 Sep 2024 00:29:22 +0400 Subject: [PATCH 01/13] Adds embeddings --- src/Embeddings/Document.php | 50 ++++++++++++ src/Embeddings/DocumentFactory.php | 20 +++++ src/Embeddings/DocumentSplitter.php | 80 +++++++++++++++++++ src/Embeddings/Embedding.php | 22 +++++ .../EmbeddingGeneratorInterface.php | 10 +++ .../EmbeddingRepositoryInterface.php | 14 ++++ .../EmbeddingSourceRegistryInterface.php | 10 +++ .../EmbeddingSourceRepositoryInterface.php | 16 ++++ .../Exception/EmbeddingException.php | 10 +++ .../EmbeddingSourceNotFoundException.php | 10 +++ src/Embeddings/NullSource.php | 13 +++ src/Embeddings/Source.php | 13 +++ src/Embeddings/Source/FileSource.php | 16 ++++ 13 files changed, 284 insertions(+) create mode 100644 src/Embeddings/Document.php create mode 100644 src/Embeddings/DocumentFactory.php create mode 100644 src/Embeddings/DocumentSplitter.php create mode 100644 src/Embeddings/Embedding.php create mode 100644 src/Embeddings/EmbeddingGeneratorInterface.php create mode 100644 src/Embeddings/EmbeddingRepositoryInterface.php create mode 100644 src/Embeddings/EmbeddingSourceRegistryInterface.php create mode 100644 src/Embeddings/EmbeddingSourceRepositoryInterface.php create mode 100644 src/Embeddings/Exception/EmbeddingException.php create mode 100644 src/Embeddings/Exception/EmbeddingSourceNotFoundException.php create mode 100644 src/Embeddings/NullSource.php create mode 100644 src/Embeddings/Source.php create mode 100644 src/Embeddings/Source/FileSource.php diff --git a/src/Embeddings/Document.php b/src/Embeddings/Document.php new file mode 100644 index 0000000..c34a48d --- /dev/null +++ b/src/Embeddings/Document.php @@ -0,0 +1,50 @@ +embedding = null; + $this->hash = \md5($content); + $this->length = \mb_strlen($content); + } + + final public function withEmbedding(Embedding $embedding): self + { + $new = clone $this; + $new->embedding = $embedding; + + return $new; + } + + final public function hasEmbedding(): bool + { + return $this->embedding !== null; + } + + final public function getEmbedding(): ?Embedding + { + return $this->embedding; + } + + public function __toString(): string + { + return $this->content; + } + + public function isEquals(Document $document): bool + { + return $this->hash === $document->hash; + } +} diff --git a/src/Embeddings/DocumentFactory.php b/src/Embeddings/DocumentFactory.php new file mode 100644 index 0000000..f5e424c --- /dev/null +++ b/src/Embeddings/DocumentFactory.php @@ -0,0 +1,20 @@ +filterText($document->content); + $length = $document->length; + + if ($content === '') { + return [$document]; + } + + if ($separator === '') { + return []; + } + + if ($length <= $maxLength) { + return [$document]; + } + + $words = \explode($separator, $content); + + return \array_map( + static fn(string $chunk): Document => new Document( + content: $chunk, + source: $document->source, + ), + $this->createChunks($words, $maxLength, $separator, $wordOverlap), + ); + } + + private function filterText(string $text): string + { + // Remove special characters (except for basic punctuation) + $text = \preg_replace('/[^a-zA-Z0-9\s,.!?]/', '', $text); + + // Remove extra spaces + return \trim(\preg_replace('/\s+/', ' ', $text)); + } + + /** + * @param array $words + * @return array + */ + private function createChunks(array $words, int $maxLength, string $separator, int $wordOverlap): array + { + $chunks = []; + $chunk = ''; + + $i = 0; + while ($i < count($words)) { + // If adding the next word would exceed the chunk size, add the current chunk and start a new one + if (\strlen($chunk . $separator . $words[$i]) > $maxLength) { + $chunks[] = \trim($chunk); + // Set the starting point of the next chunk considering word overlap + $start = \max(0, $i - $wordOverlap); + $chunk = \implode($separator, \array_slice($words, $start, $wordOverlap)); + } + + $chunk .= $separator . $words[$i]; + $i++; + } + + // Add the last chunk + if (!empty($chunk)) { + $chunks[] = \trim($chunk); + } + + return $chunks; + } +} diff --git a/src/Embeddings/Embedding.php b/src/Embeddings/Embedding.php new file mode 100644 index 0000000..ee698c1 --- /dev/null +++ b/src/Embeddings/Embedding.php @@ -0,0 +1,22 @@ +vector); + } + + public function count(): int + { + return $this->size(); + } +} diff --git a/src/Embeddings/EmbeddingGeneratorInterface.php b/src/Embeddings/EmbeddingGeneratorInterface.php new file mode 100644 index 0000000..95d5aaf --- /dev/null +++ b/src/Embeddings/EmbeddingGeneratorInterface.php @@ -0,0 +1,10 @@ + $path]); + } +} From f49c1f361e2d384de624a8fb85b489fe0af6a85f Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Fri, 6 Sep 2024 00:35:17 +0400 Subject: [PATCH 02/13] Adds context source link --- src/Solution/ContextSourceLink.php | 27 +++++++++++++++++++++++++++ src/Solution/SolutionType.php | 1 + 2 files changed, 28 insertions(+) create mode 100644 src/Solution/ContextSourceLink.php diff --git a/src/Solution/ContextSourceLink.php b/src/Solution/ContextSourceLink.php new file mode 100644 index 0000000..a0789f9 --- /dev/null +++ b/src/Solution/ContextSourceLink.php @@ -0,0 +1,27 @@ +name; + } +} diff --git a/src/Solution/SolutionType.php b/src/Solution/SolutionType.php index b29529d..07012ec 100644 --- a/src/Solution/SolutionType.php +++ b/src/Solution/SolutionType.php @@ -11,4 +11,5 @@ enum SolutionType: string case Model = 'model'; case Tool = 'tool'; case Agent = 'agent'; + case Context = 'context'; } From ce8dc7e825ce609d84559123f2f9f20f7ebc163c Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Fri, 6 Sep 2024 00:35:36 +0400 Subject: [PATCH 03/13] Adds description for tool link --- src/Solution/ToolLink.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Solution/ToolLink.php b/src/Solution/ToolLink.php index 92268fb..f7686ed 100644 --- a/src/Solution/ToolLink.php +++ b/src/Solution/ToolLink.php @@ -4,6 +4,9 @@ namespace LLM\Agents\Solution; +/** + * A tool link is a solution that points to a tool that can be used to solve a problem. + */ class ToolLink extends Solution { public function __construct( From c77c18141db5d188b520671885677ebe882dbed1 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Fri, 6 Sep 2024 00:36:08 +0400 Subject: [PATCH 04/13] Fix expected object type --- src/AgentExecutor/Interceptor/GeneratePromptInterceptor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AgentExecutor/Interceptor/GeneratePromptInterceptor.php b/src/AgentExecutor/Interceptor/GeneratePromptInterceptor.php index d0e2b0f..2c3daca 100644 --- a/src/AgentExecutor/Interceptor/GeneratePromptInterceptor.php +++ b/src/AgentExecutor/Interceptor/GeneratePromptInterceptor.php @@ -10,7 +10,7 @@ use LLM\Agents\AgentExecutor\ExecutorInterceptorInterface; use LLM\Agents\AgentExecutor\InterceptorHandler; use LLM\Agents\LLM\AgentPromptGeneratorInterface; -use LLM\Agents\LLM\Prompt\Chat\Prompt; +use LLM\Agents\LLM\Prompt\Chat\PromptInterface; final readonly class GeneratePromptInterceptor implements ExecutorInterceptorInterface { @@ -23,7 +23,7 @@ public function execute( ExecutionInput $input, InterceptorHandler $next, ): Execution { - if (!$input->prompt instanceof Prompt) { + if (!$input->prompt instanceof PromptInterface) { $input = $input->withPrompt( $this->promptGenerator->generate( $this->agents->get($input->agent), From c5387d71bc2757f3b5b435d8b10b53edb783f0b6 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Fri, 6 Sep 2024 10:34:52 +0400 Subject: [PATCH 05/13] Adds some description for embeddings interfaces. Document and Source are json serializable now --- src/Embeddings/Document.php | 11 ++++++++++- src/Embeddings/DocumentSplitter.php | 4 ++++ src/Embeddings/Embedding.php | 7 ++++++- src/Embeddings/EmbeddingGeneratorInterface.php | 9 ++++++++- src/Embeddings/EmbeddingRepositoryInterface.php | 10 ++++++++-- .../EmbeddingSourceRegistryInterface.php | 3 +++ .../EmbeddingSourceRepositoryInterface.php | 5 +++++ src/Embeddings/Source.php | 14 +++++++++++++- 8 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/Embeddings/Document.php b/src/Embeddings/Document.php index c34a48d..eb62795 100644 --- a/src/Embeddings/Document.php +++ b/src/Embeddings/Document.php @@ -4,7 +4,7 @@ namespace LLM\Agents\Embeddings; -class Document implements \Stringable +class Document implements \Stringable, \JsonSerializable { /** @var Embedding|null */ private ?Embedding $embedding; @@ -47,4 +47,13 @@ public function isEquals(Document $document): bool { return $this->hash === $document->hash; } + + public function jsonSerialize(): array + { + return [ + 'content' => $this->content, + 'source' => $this->source, + 'embedding' => $this->embedding, + ]; + } } diff --git a/src/Embeddings/DocumentSplitter.php b/src/Embeddings/DocumentSplitter.php index a8738b6..870c1e3 100644 --- a/src/Embeddings/DocumentSplitter.php +++ b/src/Embeddings/DocumentSplitter.php @@ -4,6 +4,10 @@ namespace LLM\Agents\Embeddings; +/** + * Splits a document into smaller chunks that can be processed by the + * embedding generator and stored in the database. + */ final class DocumentSplitter { public function split( diff --git a/src/Embeddings/Embedding.php b/src/Embeddings/Embedding.php index ee698c1..a5c9ed9 100644 --- a/src/Embeddings/Embedding.php +++ b/src/Embeddings/Embedding.php @@ -4,7 +4,7 @@ namespace LLM\Agents\Embeddings; -readonly class Embedding implements \Countable +readonly class Embedding implements \Countable, \JsonSerializable { public function __construct( public array $vector, @@ -19,4 +19,9 @@ public function count(): int { return $this->size(); } + + public function jsonSerialize(): array + { + return $this->vector; + } } diff --git a/src/Embeddings/EmbeddingGeneratorInterface.php b/src/Embeddings/EmbeddingGeneratorInterface.php index 95d5aaf..c7aa4e4 100644 --- a/src/Embeddings/EmbeddingGeneratorInterface.php +++ b/src/Embeddings/EmbeddingGeneratorInterface.php @@ -6,5 +6,12 @@ interface EmbeddingGeneratorInterface { - public function generate(Document ...$document): array; + /** + * Generate embeddings for the given documents. + * The embeddings will be injected into the documents. + * + * @param Document ...$documents + * @return array List of documents with embeddings + */ + public function generate(Document ...$documents): array; } diff --git a/src/Embeddings/EmbeddingRepositoryInterface.php b/src/Embeddings/EmbeddingRepositoryInterface.php index 7eca2f3..f06b06c 100644 --- a/src/Embeddings/EmbeddingRepositoryInterface.php +++ b/src/Embeddings/EmbeddingRepositoryInterface.php @@ -4,11 +4,17 @@ namespace LLM\Agents\Embeddings; +/** + * This is an abstraction for a repository that can search for similar documents based on embeddings. + * It can be implemented by a database, a search engine, or any other storage that can handle embeddings. + */ interface EmbeddingRepositoryInterface { /** - * @param array $embedding Vector representation of the document + * Search for documents similar to the given embedding + * + * @param Embedding $embedding Vector representation of the document * @return Document[] */ - public function search(array $embedding, int $limit = 5): array; + public function search(Embedding $embedding, int $limit = 5): array; } diff --git a/src/Embeddings/EmbeddingSourceRegistryInterface.php b/src/Embeddings/EmbeddingSourceRegistryInterface.php index 97f502c..7d4f739 100644 --- a/src/Embeddings/EmbeddingSourceRegistryInterface.php +++ b/src/Embeddings/EmbeddingSourceRegistryInterface.php @@ -6,5 +6,8 @@ interface EmbeddingSourceRegistryInterface { + /** + * Register a new embedding source, like Vector database. + */ public function register(string $name, EmbeddingRepositoryInterface $agent): void; } diff --git a/src/Embeddings/EmbeddingSourceRepositoryInterface.php b/src/Embeddings/EmbeddingSourceRepositoryInterface.php index ebd2915..b735670 100644 --- a/src/Embeddings/EmbeddingSourceRepositoryInterface.php +++ b/src/Embeddings/EmbeddingSourceRepositoryInterface.php @@ -6,9 +6,14 @@ use LLM\Agents\Embeddings\Exception\EmbeddingSourceNotFoundException; +/** + * This is an abstraction for retrieving embedding sources like Vector databases. + */ interface EmbeddingSourceRepositoryInterface { /** + * Retrieve an embedding source by name + * * @param non-empty-string $sourceName The name of the source * @throws EmbeddingSourceNotFoundException */ diff --git a/src/Embeddings/Source.php b/src/Embeddings/Source.php index bc4c354..0dc15fc 100644 --- a/src/Embeddings/Source.php +++ b/src/Embeddings/Source.php @@ -4,10 +4,22 @@ namespace LLM\Agents\Embeddings; -readonly class Source +/** + * Source of a document. It can be a file, a database, etc. + * Metadata can be used to store additional information like the path of the file or the database name. + */ +readonly class Source implements \JsonSerializable { public function __construct( public string $type, public array $metadata = [], ) {} + + public function jsonSerialize(): array + { + return [ + 'type' => $this->type, + 'metadata' => $this->metadata, + ]; + } } From 5ec2a5863ff3e0c3c9bc03dcaad7b12b832c2a69 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Fri, 6 Sep 2024 19:54:49 +0400 Subject: [PATCH 06/13] Adds interfaces for linked entities - context source - agents --- src/Agent/AgentInterface.php | 5 ----- src/Agent/HasLinkedAgentsInterface.php | 15 +++++++++++++++ src/Embeddings/HasContextSourcesInterface.php | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 src/Agent/HasLinkedAgentsInterface.php create mode 100644 src/Embeddings/HasContextSourcesInterface.php diff --git a/src/Agent/AgentInterface.php b/src/Agent/AgentInterface.php index 655fcc3..43bf5c4 100644 --- a/src/Agent/AgentInterface.php +++ b/src/Agent/AgentInterface.php @@ -28,11 +28,6 @@ public function getInstruction(): string; */ public function getTools(): array; - /** - * @return array - */ - public function getAgents(): array; - public function getModel(): Model; /** diff --git a/src/Agent/HasLinkedAgentsInterface.php b/src/Agent/HasLinkedAgentsInterface.php new file mode 100644 index 0000000..c40e0b7 --- /dev/null +++ b/src/Agent/HasLinkedAgentsInterface.php @@ -0,0 +1,15 @@ + + */ + public function getAgents(): array; +} diff --git a/src/Embeddings/HasContextSourcesInterface.php b/src/Embeddings/HasContextSourcesInterface.php new file mode 100644 index 0000000..aa850a0 --- /dev/null +++ b/src/Embeddings/HasContextSourcesInterface.php @@ -0,0 +1,17 @@ + + */ + public function getContextSources(): array; +} From d6ec6cb6161a8bde1fe9d78e01b924b5fa3b2560 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Fri, 6 Sep 2024 20:10:11 +0400 Subject: [PATCH 07/13] Adds new interfaces --- src/Agent/AgentAggregate.php | 15 ++++++++++++++- src/Agent/AgentInterface.php | 5 ----- src/Agent/HasLinkedToolsInterface.php | 17 +++++++++++++++++ .../Interceptor/InjectToolsInterceptor.php | 5 +++++ ...php => HasLinkedContextSourcesInterface.php} | 2 +- 5 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 src/Agent/HasLinkedToolsInterface.php rename src/Embeddings/{HasContextSourcesInterface.php => HasLinkedContextSourcesInterface.php} (86%) diff --git a/src/Agent/AgentAggregate.php b/src/Agent/AgentAggregate.php index dd8ec45..98c5768 100644 --- a/src/Agent/AgentAggregate.php +++ b/src/Agent/AgentAggregate.php @@ -6,7 +6,9 @@ use LLM\Agents\Agent\Exception\AgentModelException; use LLM\Agents\Agent\Exception\MissingModelException; +use LLM\Agents\Embeddings\HasLinkedContextSourcesInterface; use LLM\Agents\Solution\AgentLink; +use LLM\Agents\Solution\ContextSourceLink; use LLM\Agents\Solution\MetadataType; use LLM\Agents\Solution\Model; use LLM\Agents\Solution\Solution; @@ -17,7 +19,10 @@ /** * @psalm-type TAssociation = Solution|Model|ToolLink|AgentLink */ -class AgentAggregate implements AgentInterface +class AgentAggregate implements AgentInterface, + HasLinkedAgentsInterface, + HasLinkedToolsInterface, + HasLinkedContextSourcesInterface { /** * @var array @@ -56,6 +61,14 @@ public function getTools(): array ); } + public function getContextSources(): array + { + return \array_filter( + $this->agent->getMetadata(), + static fn(Solution $association): bool => $association instanceof ContextSourceLink, + ); + } + public function getAgents(): array { return \array_filter( diff --git a/src/Agent/AgentInterface.php b/src/Agent/AgentInterface.php index 43bf5c4..480c534 100644 --- a/src/Agent/AgentInterface.php +++ b/src/Agent/AgentInterface.php @@ -23,11 +23,6 @@ public function getDescription(): ?string; public function getInstruction(): string; - /** - * @return array - */ - public function getTools(): array; - public function getModel(): Model; /** diff --git a/src/Agent/HasLinkedToolsInterface.php b/src/Agent/HasLinkedToolsInterface.php new file mode 100644 index 0000000..da38d3a --- /dev/null +++ b/src/Agent/HasLinkedToolsInterface.php @@ -0,0 +1,17 @@ + + */ + public function getTools(): array; +} diff --git a/src/AgentExecutor/Interceptor/InjectToolsInterceptor.php b/src/AgentExecutor/Interceptor/InjectToolsInterceptor.php index ef8efa5..3a357bf 100644 --- a/src/AgentExecutor/Interceptor/InjectToolsInterceptor.php +++ b/src/AgentExecutor/Interceptor/InjectToolsInterceptor.php @@ -6,6 +6,7 @@ use LLM\Agents\Agent\AgentRepositoryInterface; use LLM\Agents\Agent\Execution; +use LLM\Agents\Agent\HasLinkedToolsInterface; use LLM\Agents\AgentExecutor\ExecutionInput; use LLM\Agents\AgentExecutor\ExecutorInterceptorInterface; use LLM\Agents\AgentExecutor\InterceptorHandler; @@ -29,6 +30,10 @@ public function execute( ): Execution { $agent = $this->agents->get($input->agent); + if (!$agent instanceof HasLinkedToolsInterface) { + return $next($input); + } + $tools = \array_map( fn(ToolLink $tool): ToolInterface => $this->tools->get($tool->getName()), $agent->getTools(), diff --git a/src/Embeddings/HasContextSourcesInterface.php b/src/Embeddings/HasLinkedContextSourcesInterface.php similarity index 86% rename from src/Embeddings/HasContextSourcesInterface.php rename to src/Embeddings/HasLinkedContextSourcesInterface.php index aa850a0..6917aeb 100644 --- a/src/Embeddings/HasContextSourcesInterface.php +++ b/src/Embeddings/HasLinkedContextSourcesInterface.php @@ -6,7 +6,7 @@ use LLM\Agents\Solution\ContextSourceLink; -interface HasContextSourcesInterface +interface HasLinkedContextSourcesInterface { /** * Get the sources of the context storage. From c77a0b3054b3a99c35d1dd93b909fa276a3df887 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Fri, 6 Sep 2024 20:48:26 +0400 Subject: [PATCH 08/13] Fix --- src/Agent/AgentAggregate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Agent/AgentAggregate.php b/src/Agent/AgentAggregate.php index 98c5768..6c4655d 100644 --- a/src/Agent/AgentAggregate.php +++ b/src/Agent/AgentAggregate.php @@ -64,7 +64,7 @@ public function getTools(): array public function getContextSources(): array { return \array_filter( - $this->agent->getMetadata(), + $this->associations, static fn(Solution $association): bool => $association instanceof ContextSourceLink, ); } From 4735effa58a3f0c41275068185c8bddaa74a75d4 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Sat, 7 Sep 2024 11:08:24 +0400 Subject: [PATCH 09/13] Add phpdoc --- src/Agent/Agent.php | 7 ++++ src/Agent/AgentFactoryInterface.php | 18 ++++++++++ src/Agent/AgentInterface.php | 35 +++++++++++++++++++ src/Agent/AgentRegistryInterface.php | 11 ++++++ src/Agent/AgentRepositoryInterface.php | 20 +++++++++++ src/Agent/Execution.php | 7 ++++ src/Agent/HasLinkedAgentsInterface.php | 2 ++ src/Agent/HasLinkedToolsInterface.php | 2 +- src/AgentExecutor/ExecutorInterface.php | 23 ++++++++++++ src/Embeddings/EmbeddingSourceManager.php | 27 ++++++++++++++ .../EmbeddingSourceRegistryInterface.php | 2 +- 11 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 src/Embeddings/EmbeddingSourceManager.php diff --git a/src/Agent/Agent.php b/src/Agent/Agent.php index 58d332d..e38c8e1 100644 --- a/src/Agent/Agent.php +++ b/src/Agent/Agent.php @@ -9,6 +9,13 @@ final class Agent extends Solution { + /** + * @param string $key The unique key of the agent that is used to retrieve it + * @param string $name The name of the agent + * @param string $description The short description + * @param string $instruction The initial instruction for the agent to interact with the user + * @param bool $isActive + */ public function __construct( public readonly string $key, string $name, diff --git a/src/Agent/AgentFactoryInterface.php b/src/Agent/AgentFactoryInterface.php index ce2ab67..5cf4fa1 100644 --- a/src/Agent/AgentFactoryInterface.php +++ b/src/Agent/AgentFactoryInterface.php @@ -4,7 +4,25 @@ namespace LLM\Agents\Agent; +namespace LLM\Agents\Agent; + +/** + * It defines a contract for creating instances of agents. It encapsulates the complex process of agent + * initialization, configuration, and setup. + * + * Purpose: + * 1. Abstraction: It provides a level of abstraction between the agent creation + * process and the rest of the application, allowing for different implementation + * strategies without affecting the client code. + * + * 2. Flexibility: By using a factory interface, the framework can support multiple + * types of agents or different initialization strategies for agents without + * changing the core logic. + */ interface AgentFactoryInterface { + /** + * Create and return a fully initialized agent instance. + */ public function create(): AgentInterface; } diff --git a/src/Agent/AgentInterface.php b/src/Agent/AgentInterface.php index 480c534..dee208b 100644 --- a/src/Agent/AgentInterface.php +++ b/src/Agent/AgentInterface.php @@ -11,32 +11,67 @@ use LLM\Agents\Solution\ToolLink; /** + * Represents an AI agent capable of performing tasks, making decisions, + * and interacting with various tools and other agents. * @psalm-type TAssociation = Solution|Model|ToolLink|AgentLink */ interface AgentInterface { + /** + * Get the unique key identifier for the agent. + */ public function getKey(): string; + /** + * Get the human-readable name of the agent. + */ public function getName(): string; + /** + * Get the description of the agent's purpose and capabilities. + */ public function getDescription(): ?string; + /** + * Get the primary instruction set for the agent. + */ public function getInstruction(): string; + /** + * Get the language model associated with this agent. + */ public function getModel(): Model; /** + * Get the agent's memory, containing learned information and experiences. + * * @return array */ public function getMemory(): array; /** + * Get the list of predefined prompts for the agent. + * * @return array */ public function getPrompts(): array; /** + * Get the agent's configuration settings. + * + * This method returns an array of configuration settings for the agent, + * which can include parameters for the LLM (Language Model) client configuration. + * These settings may affect how the agent interacts with the language model, + * including parameters like temperature, max tokens, and other model-specific options. + * * @return array + * + * @example + * [ + * new SolutionMetadata(MetadataType::Configuration, 'temperature', 0.7), + * new SolutionMetadata(MetadataType::Configuration, 'max_tokens', 150), + * new SolutionMetadata(MetadataType::Configuration, 'top_p', 1), + * ] */ public function getConfiguration(): array; } diff --git a/src/Agent/AgentRegistryInterface.php b/src/Agent/AgentRegistryInterface.php index d094dd6..bd4ddcd 100644 --- a/src/Agent/AgentRegistryInterface.php +++ b/src/Agent/AgentRegistryInterface.php @@ -6,14 +6,25 @@ use LLM\Agents\Agent\Exception\AgentAlreadyRegisteredException; +/** + * It defines the contract for a registry that manages the registration of agents. + * + * Purpose: + * - Provide a centralized mechanism for registering new agents in the system. + * - Allow for dynamic addition of agents at runtime. + */ interface AgentRegistryInterface { /** + * Register a new agent in the system. + * * @throws AgentAlreadyRegisteredException */ public function register(AgentInterface $agent): void; /** + * Retrieve all registered agents. + * * @return AgentInterface[] */ public function all(): iterable; diff --git a/src/Agent/AgentRepositoryInterface.php b/src/Agent/AgentRepositoryInterface.php index 975faed..119d6ff 100644 --- a/src/Agent/AgentRepositoryInterface.php +++ b/src/Agent/AgentRepositoryInterface.php @@ -6,12 +6,32 @@ use LLM\Agents\Agent\Exception\AgentNotFoundException; +/** + * It defines the contract for a repository that provides access to registered agents. + * + * Purpose: + * - Provide a standardized way to retrieve specific agents by their unique keys. + * - Allow checking for the existence of agents in the system. + * + * This interface is essential for components that need to work with specific + * agents. It abstracts the storage and retrieval mechanisms, allowing for + * different implementations (e.g., in-memory, database-backed) without + * affecting the consumers of the interface. + */ interface AgentRepositoryInterface { /** + * Retrieve an agent by its unique key. + * + * @param non-empty-string $key The unique key of the agent to retrieve. * @throws AgentNotFoundException */ public function get(string $key): AgentInterface; + /** + * Check if an agent with the given key exists in the repository. + * + * @param non-empty-string $key The key to check for existence. + */ public function has(string $key): bool; } diff --git a/src/Agent/Execution.php b/src/Agent/Execution.php index 4bc3e26..81b724d 100644 --- a/src/Agent/Execution.php +++ b/src/Agent/Execution.php @@ -7,8 +7,15 @@ use LLM\Agents\LLM\Prompt\Chat\PromptInterface; use LLM\Agents\LLM\Response\Response; +/** + * Represents the result of an agent's execution, including the response and the prompt used. + */ final readonly class Execution { + /** + * @param Response $result The response from the agent's execution. + * @param PromptInterface $prompt The prompt used for the execution. + */ public function __construct( public Response $result, public PromptInterface $prompt, diff --git a/src/Agent/HasLinkedAgentsInterface.php b/src/Agent/HasLinkedAgentsInterface.php index c40e0b7..808d012 100644 --- a/src/Agent/HasLinkedAgentsInterface.php +++ b/src/Agent/HasLinkedAgentsInterface.php @@ -9,6 +9,8 @@ interface HasLinkedAgentsInterface { /** + * Get the list of other agents this agent can interact with. + * * @return array */ public function getAgents(): array; diff --git a/src/Agent/HasLinkedToolsInterface.php b/src/Agent/HasLinkedToolsInterface.php index da38d3a..1916e57 100644 --- a/src/Agent/HasLinkedToolsInterface.php +++ b/src/Agent/HasLinkedToolsInterface.php @@ -9,7 +9,7 @@ interface HasLinkedToolsInterface { /** - * Get the tools linked to the agent. + * Get the list of tools available to the agent. * * @return array */ diff --git a/src/AgentExecutor/ExecutorInterface.php b/src/AgentExecutor/ExecutorInterface.php index 17fd19d..0020d29 100644 --- a/src/AgentExecutor/ExecutorInterface.php +++ b/src/AgentExecutor/ExecutorInterface.php @@ -11,8 +11,23 @@ use LLM\Agents\LLM\Prompt\Context; use LLM\Agents\LLM\PromptContextInterface; +/** + * This interface defines the contract for agent executors. + */ interface ExecutorInterface { + /** + * Execute an agent task with the given parameters. + * + * @param string $agent The unique identifier or key of the agent to execute. + * @param string|\Stringable|Prompt $prompt The prompt to send to the agent. + * @param ContextInterface|null $context An optional execution context carrying user-specific information such as authentication details, session data, etc. + * @param OptionsInterface|null $options Optional configuration options specific to the LLM being used. This includes settings like temperature, max tokens, etc. + * @param PromptContextInterface $promptContext Additional context for prompt generation. This is used to provide extra information for generating the prompt. + * + * @throws \LLM\Agents\Agent\Exception\AgentNotFoundException If the specified agent is not found. + * @throws \LLM\Agents\AgentExecutor\Exception\ExecutorException If an error occurs during execution. + */ public function execute( string $agent, string|\Stringable|Prompt $prompt, @@ -21,5 +36,13 @@ public function execute( PromptContextInterface $promptContext = new Context(), ): Execution; + /** + * Add one or more interceptors to the executor's pipeline. + * + * Interceptors allow for modifying the execution flow, adding pre- or post-processing steps, + * or altering the behavior of the executor without changing its core implementation. + * This can be used for tasks such as logging, modifying the context or options, or + * implementing complex execution strategies. + */ public function withInterceptor(ExecutorInterceptorInterface ...$interceptor): self; } diff --git a/src/Embeddings/EmbeddingSourceManager.php b/src/Embeddings/EmbeddingSourceManager.php new file mode 100644 index 0000000..c2a8e50 --- /dev/null +++ b/src/Embeddings/EmbeddingSourceManager.php @@ -0,0 +1,27 @@ + */ + private array $sources = []; + + public function register(string $name, EmbeddingRepositoryInterface $repository): void + { + $this->sources[$name] = $repository; + } + + public function get(string $sourceName): EmbeddingRepositoryInterface + { + if (!isset($this->sources[$sourceName])) { + throw new EmbeddingSourceNotFoundException(\sprintf('Embedding source "%s" not found', $sourceName)); + } + + return $this->sources[$sourceName]; + } +} diff --git a/src/Embeddings/EmbeddingSourceRegistryInterface.php b/src/Embeddings/EmbeddingSourceRegistryInterface.php index 7d4f739..e493d85 100644 --- a/src/Embeddings/EmbeddingSourceRegistryInterface.php +++ b/src/Embeddings/EmbeddingSourceRegistryInterface.php @@ -9,5 +9,5 @@ interface EmbeddingSourceRegistryInterface /** * Register a new embedding source, like Vector database. */ - public function register(string $name, EmbeddingRepositoryInterface $agent): void; + public function register(string $name, EmbeddingRepositoryInterface $repository): void; } From 940ef36b0f4b30f383651f182d5fe7cf49fa0b10 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Sat, 7 Sep 2024 12:00:38 +0400 Subject: [PATCH 10/13] Adds phpdoc . Refactors tool execution --- src/AgentExecutor/ExecutionInput.php | 40 ++++++++++++ .../ExecutorInterceptorInterface.php | 42 ++++++++++++ src/AgentExecutor/ExecutorInterface.php | 3 + src/AgentExecutor/ExecutorPipeline.php | 5 ++ src/LLM/AgentPromptGeneratorInterface.php | 17 +++++ src/LLM/LLMInterface.php | 19 ++++++ src/Tool/ExecutorAwareInterface.php | 10 --- src/Tool/ExecutorInterface.php | 10 --- .../LanguageExecutor/PhpLanguageExecutor.php | 19 ++++++ src/Tool/LanguageExecutorAwareInterface.php | 16 +++++ src/Tool/LanguageExecutorInterface.php | 45 +++++++++++++ src/Tool/PhpTool.php | 23 +++++++ src/Tool/SchemaMapperInterface.php | 16 +++-- src/Tool/ToolExecutor.php | 65 ++++++++++--------- src/Tool/ToolInterface.php | 16 +++-- src/Tool/ToolLanguage.php | 4 ++ src/Tool/ToolRegistryInterface.php | 10 ++- src/Tool/ToolRepositoryInterface.php | 11 +++- 18 files changed, 310 insertions(+), 61 deletions(-) delete mode 100644 src/Tool/ExecutorAwareInterface.php delete mode 100644 src/Tool/ExecutorInterface.php create mode 100644 src/Tool/LanguageExecutor/PhpLanguageExecutor.php create mode 100644 src/Tool/LanguageExecutorAwareInterface.php create mode 100644 src/Tool/LanguageExecutorInterface.php create mode 100644 src/Tool/PhpTool.php diff --git a/src/AgentExecutor/ExecutionInput.php b/src/AgentExecutor/ExecutionInput.php index f27cf4f..d9730de 100644 --- a/src/AgentExecutor/ExecutionInput.php +++ b/src/AgentExecutor/ExecutionInput.php @@ -9,6 +9,31 @@ use LLM\Agents\LLM\Prompt\Chat\PromptInterface; use LLM\Agents\LLM\PromptContextInterface; +/** + * Represents the immutable input for an agent execution. + * + * This class encapsulates all necessary information for executing an agent, + * including the agent key, prompt, context, options, and prompt context. + * It is designed to be immutable, with all modifier methods returning new instances. + * + * @example + * // Creating an initial ExecutionInput + * $input = new ExecutionInput( + * agent: 'my_agent', + * prompt: 'Hello, agent!', + * context: $context, + * options: $options, + * promptContext: $promptContext + * ); + * + * // Modifying the input (creates a new instance) + * $newInput = $input->withAgent(...) + * ->withPrompt(...; + * + * // The original $input remains unchanged + * assert($input->agent === 'my_agent'); + * assert($newInput->agent === 'another_agent'); + */ final readonly class ExecutionInput { public function __construct( @@ -19,6 +44,9 @@ public function __construct( public PromptContextInterface $promptContext, ) {} + /** + * Create a new input with a different agent. + */ public function withAgent(string $agent): self { return new self( @@ -30,6 +58,9 @@ public function withAgent(string $agent): self ); } + /** + * Create a new input with a different prompt context. + */ public function withPromptContext(PromptContextInterface $context): self { return new self( @@ -41,6 +72,9 @@ public function withPromptContext(PromptContextInterface $context): self ); } + /** + * Create a new input with a different context. + */ public function withContext(ContextInterface $context): self { return new self( @@ -52,6 +86,9 @@ public function withContext(ContextInterface $context): self ); } + /** + * Create a new input with a different prompt. + */ public function withPrompt(PromptInterface $prompt): self { return new self( @@ -63,6 +100,9 @@ public function withPrompt(PromptInterface $prompt): self ); } + /** + * Create a new input with different options. + */ public function withOptions(OptionsInterface $options): self { return new self( diff --git a/src/AgentExecutor/ExecutorInterceptorInterface.php b/src/AgentExecutor/ExecutorInterceptorInterface.php index 8593943..ed9352b 100644 --- a/src/AgentExecutor/ExecutorInterceptorInterface.php +++ b/src/AgentExecutor/ExecutorInterceptorInterface.php @@ -6,8 +6,50 @@ use LLM\Agents\Agent\Execution; +/** + * Interceptors allow for modifying the execution flow, adding pre- or post-processing steps, + * or altering the behavior of the executor without changing its core implementation. + * + * @example + * Here's an example of a logging interceptor: + * + * ```php + * final readonly class LoggingInterceptor implements ExecutorInterceptorInterface + * { + * public function __construct(private LoggerInterface $logger) {} + * + * public function execute(ExecutionInput $input, InterceptorHandler $next): Execution + * { + * $this->logger->info('Executing agent: ' . $input->agent); + * + * $startTime = \microtime(true); + * $execution = $next($input); + * $duration = \microtime(true) - $startTime; + * + * $this->logger->info('Execution completed', [ + * 'agent' => $input->agent, + * 'duration' => $duration, + * 'resultType' => get_class($execution->result), + * ]); + * + * return $execution; + * } + * } + * ``` + */ interface ExecutorInterceptorInterface { + /** + * Execute the interceptor logic. + * + * This method is called as part of the execution pipeline. It can modify the input, + * perform additional operations, or alter the execution flow. + * + * @param ExecutionInput $input The current execution input + * @param InterceptorHandler $next The next handler in the pipeline + * + * @return Execution The result of the execution after this interceptor's processing + */ public function execute( ExecutionInput $input, InterceptorHandler $next, diff --git a/src/AgentExecutor/ExecutorInterface.php b/src/AgentExecutor/ExecutorInterface.php index 0020d29..5c1fb30 100644 --- a/src/AgentExecutor/ExecutorInterface.php +++ b/src/AgentExecutor/ExecutorInterface.php @@ -19,6 +19,9 @@ interface ExecutorInterface /** * Execute an agent task with the given parameters. * + * This method orchestrates the execution of the agent's task, passing it through + * the chain of interceptors before finally generating a response from the LLM. + * * @param string $agent The unique identifier or key of the agent to execute. * @param string|\Stringable|Prompt $prompt The prompt to send to the agent. * @param ContextInterface|null $context An optional execution context carrying user-specific information such as authentication details, session data, etc. diff --git a/src/AgentExecutor/ExecutorPipeline.php b/src/AgentExecutor/ExecutorPipeline.php index d191975..c6585e2 100644 --- a/src/AgentExecutor/ExecutorPipeline.php +++ b/src/AgentExecutor/ExecutorPipeline.php @@ -16,6 +16,11 @@ use LLM\Agents\LLM\Prompt\PromptInterface; use LLM\Agents\LLM\PromptContextInterface; +/** + * Implements the execution pipeline for LLM agents. + * + * This class manages the flow of execution through a series of interceptors. + */ final class ExecutorPipeline implements ExecutorInterface { /** @var ExecutorInterceptorInterface[] */ diff --git a/src/LLM/AgentPromptGeneratorInterface.php b/src/LLM/AgentPromptGeneratorInterface.php index 59a3fbb..3bf983b 100644 --- a/src/LLM/AgentPromptGeneratorInterface.php +++ b/src/LLM/AgentPromptGeneratorInterface.php @@ -8,8 +8,25 @@ use LLM\Agents\LLM\Prompt\Chat\Prompt; use LLM\Agents\LLM\Prompt\Chat\PromptInterface; +/** + * Interface for generating prompts for AI agents. + * + * This interface defines the contract for classes responsible for generating + * prompts that will be sent to AI agents. It allows for customization of the + * prompt based on the specific agent, user input, and context. + */ interface AgentPromptGeneratorInterface { + /** + * Generate a prompt for an AI agent. + * + * @param AgentInterface $agent The agent for which to generate the prompt. + * @param string|\Stringable $userPrompt The user's input or query. + * @param PromptContextInterface $context Additional context for prompt generation. + * @param PromptInterface $prompt An optional initial prompt to build upon. + * + * @return PromptInterface The generated prompt ready to be sent to the AI agent. + */ public function generate( AgentInterface $agent, string|\Stringable $userPrompt, diff --git a/src/LLM/LLMInterface.php b/src/LLM/LLMInterface.php index 4ecd6a5..7246c7e 100644 --- a/src/LLM/LLMInterface.php +++ b/src/LLM/LLMInterface.php @@ -7,8 +7,27 @@ use LLM\Agents\LLM\Prompt\PromptInterface; use LLM\Agents\LLM\Response\Response; +/** + * This interface defines the contract for LLM implementations. + * It provides a standardized way to generate responses from various LLM providers. + */ interface LLMInterface { + /** + * Generate a response from the LLM based on the given prompt and context. + * + * This method is responsible for sending the prompt to the LLM, processing the response, + * and returning it in a standardized format. + * + * @param ContextInterface $context The context for the current request, which may include user information, session data, or other relevant details. + * @param PromptInterface $prompt The prompt to send to the LLM. This could be a simple string or a more complex structure containing multiple messages. + * @param OptionsInterface $options Additional options to customize the LLM request, such as temperature, max tokens, or other model-specific parameters. + * + * @throws \LLM\Agents\LLM\Exception\LLMException If there's an error communicating with the LLM or processing the response. + * @throws \LLM\Agents\LLM\Exception\RateLimitException If the LLM provider's rate limit is exceeded. + * @throws \LLM\Agents\LLM\Exception\TimeoutException If the request to the LLM times out. + * @throws \LLM\Agents\LLM\Exception\LimitExceededException If the request exceeds the LLM provider's limits (e.g., max tokens, max characters). + */ public function generate( ContextInterface $context, PromptInterface $prompt, diff --git a/src/Tool/ExecutorAwareInterface.php b/src/Tool/ExecutorAwareInterface.php deleted file mode 100644 index fc8516c..0000000 --- a/src/Tool/ExecutorAwareInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -execute($input); + } +} diff --git a/src/Tool/LanguageExecutorAwareInterface.php b/src/Tool/LanguageExecutorAwareInterface.php new file mode 100644 index 0000000..8cf9220 --- /dev/null +++ b/src/Tool/LanguageExecutorAwareInterface.php @@ -0,0 +1,16 @@ +getExecutableCode(); + * + * // Execute the Python script + * $output = ....; // Run the script using the Python interpreter + * + * return $output; + * } + * } + * ``` + */ +interface LanguageExecutorInterface +{ + /** + * Execute the given tool with the provided input. + * + * This method should handle the execution of the tool's code in the specific + * language that this executor is designed for. It should properly set up the + * execution environment, run the code, and handle any language-specific + * intricacies. + * + * @param ToolInterface $tool The tool to be executed. For non-PHP languages, this should typically implement LanguageExecutorAwareInterface. + */ + public function execute(ToolInterface $tool, object $input): string|\Stringable; +} diff --git a/src/Tool/PhpTool.php b/src/Tool/PhpTool.php new file mode 100644 index 0000000..50ad1a9 --- /dev/null +++ b/src/Tool/PhpTool.php @@ -0,0 +1,23 @@ +|string $class + * @template T of object + * @param string $json The JSON string to convert. + * @param class-string|string|null $class The target class to map the JSON to. If null, returns a stdClass. * - * @return T + * @return T The resulting PHP object. */ public function toObject(string $json, ?string $class = null): object; } diff --git a/src/Tool/ToolExecutor.php b/src/Tool/ToolExecutor.php index 6a8ef41..ebabe37 100644 --- a/src/Tool/ToolExecutor.php +++ b/src/Tool/ToolExecutor.php @@ -5,60 +5,63 @@ namespace LLM\Agents\Tool; use LLM\Agents\Tool\Exception\ExecutorNotFoundException; -use LLM\Agents\Tool\Exception\UnsupportedToolExecutionException; +use LLM\Agents\Tool\LanguageExecutor\PhpLanguageExecutor; +/** + * Executes tools based on their language and input. + * + * This class is responsible for executing tools of various programming languages. + * It uses a strategy pattern to delegate execution to language-specific executors. + */ final class ToolExecutor { - /** - * @var array - */ - private array $executors = []; + /** @var array */ + private array $languageExecutors = []; public function __construct( private readonly ToolRepositoryInterface $tools, private readonly SchemaMapperInterface $schemaMapper, - ) {} + ) { + $this->registerLanguageExecutor(ToolLanguage::PHP, new PhpLanguageExecutor()); + } - public function register(ToolLanguage $language, ExecutorInterface $executor): void + /** + * Registers a language-specific executor. + */ + public function registerLanguageExecutor(ToolLanguage $language, LanguageExecutorInterface $executor): void { - $this->executors[$language->value] = $executor; + $this->languageExecutors[$language->value] = $executor; } + /** + * Executes a tool with the given input. + * + * @param string $tool The unique name of the tool to execute. + * @param string $input JSON-encoded input for the tool. + * @return string|\Stringable The result of the tool execution. + * @throws ExecutorNotFoundException If no executor is found for the tool's language. + */ public function execute(string $tool, string $input): string|\Stringable { $tool = $this->tools->get($tool); $input = $this->schemaMapper->toObject($input, $tool->getInputSchema()); - if ($tool->getLanguage() === ToolLanguage::PHP) { - try { - return $tool->execute($input); - } catch (\Throwable $e) { - return \json_encode([ - 'error' => $e->getMessage(), - ]); - } - } - - if (! $this->has($tool->getLanguage())) { + if (!isset($this->languageExecutors[$tool->getLanguage()->value])) { throw new ExecutorNotFoundException($tool->getLanguage()); } - $executor = $this->executors[$tool->getLanguage()->value]; - - if ($tool instanceof ExecutorAwareInterface) { - try { - return $tool->setExecutor($executor)->execute($input); - } catch (\Throwable $e) { - return \json_encode([ - 'error' => $e->getMessage(), - ]); - } + $executor = $this->languageExecutors[$tool->getLanguage()->value]; + try { + return $executor->execute($tool, $input); + } catch (\Throwable $e) { + return \json_encode(['error' => $e->getMessage()]); } - - throw new UnsupportedToolExecutionException($tool->getName()); } + /** + * Checks if an executor is registered for the given language. + */ public function has(ToolLanguage $language): bool { return isset($this->executors[$language->value]); diff --git a/src/Tool/ToolInterface.php b/src/Tool/ToolInterface.php index ffb084f..a851bee 100644 --- a/src/Tool/ToolInterface.php +++ b/src/Tool/ToolInterface.php @@ -5,23 +5,31 @@ namespace LLM\Agents\Tool; /** + * Represents a tool that can be used by an AI agent to perform specific tasks. + * * @template T of object */ interface ToolInterface { + /** + * Get the unique name of the tool. + */ public function getName(): string; + /** + * Get the human-readable description of the tool's functionality. + */ public function getDescription(): string; /** + * Get the input schema class name for the tool. + * * @return class-string|string */ public function getInputSchema(): string; - public function getLanguage(): ToolLanguage; - /** - * @param T $input + * Get the programming language used to implement the tool. */ - public function execute(object $input): string|\Stringable; + public function getLanguage(): ToolLanguage; } diff --git a/src/Tool/ToolLanguage.php b/src/Tool/ToolLanguage.php index b4ff32b..560e4f4 100644 --- a/src/Tool/ToolLanguage.php +++ b/src/Tool/ToolLanguage.php @@ -6,6 +6,10 @@ use LLM\Agents\Tool\Exception\LanguageIsNotSupportedException; +/** + * This enum defines the supported programming languages for tools. + * It provides a mapping between language names and their corresponding MIME types. + */ enum ToolLanguage: string { case PHP = 'php'; diff --git a/src/Tool/ToolRegistryInterface.php b/src/Tool/ToolRegistryInterface.php index b7559ec..2f707de 100644 --- a/src/Tool/ToolRegistryInterface.php +++ b/src/Tool/ToolRegistryInterface.php @@ -4,12 +4,20 @@ namespace LLM\Agents\Tool; +/** + * This interface defines the contract for registering and retrieving tools. + */ interface ToolRegistryInterface { + /** + * Register one or more tools in the registry. + */ public function register(ToolInterface ...$tools): void; /** - * @return iterable + * Retrieve all registered tools. + * + * @return iterable An iterable collection of all registered tools */ public function all(): iterable; } diff --git a/src/Tool/ToolRepositoryInterface.php b/src/Tool/ToolRepositoryInterface.php index cf7a969..8b292eb 100644 --- a/src/Tool/ToolRepositoryInterface.php +++ b/src/Tool/ToolRepositoryInterface.php @@ -6,12 +6,21 @@ use LLM\Agents\Tool\Exception\ToolNotFoundException; +/** + * This interface defines the contract for retrieving specific tools from the repository. + */ interface ToolRepositoryInterface { /** - * @throws ToolNotFoundException + * Retrieve a tool by its name. + * + * @param string $name The unique name of the tool to retrieve + * @throws ToolNotFoundException If the tool with the given name is not found */ public function get(string $name): ToolInterface; + /** + * Check if a tool with the given name exists in the repository. + */ public function has(string $name): bool; } From ea720baefc5be6277394901c163f55511f7fbab1 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Sat, 7 Sep 2024 12:05:05 +0400 Subject: [PATCH 11/13] Fix --- src/Tool/PhpTool.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Tool/PhpTool.php b/src/Tool/PhpTool.php index 50ad1a9..92ccac8 100644 --- a/src/Tool/PhpTool.php +++ b/src/Tool/PhpTool.php @@ -4,6 +4,10 @@ namespace LLM\Agents\Tool; +/** + * @template T of object + * @extends Tool + */ abstract class PhpTool extends Tool { /** From 597b997f29bda51be166523295b203dc9f755a89 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Sat, 7 Sep 2024 12:09:16 +0400 Subject: [PATCH 12/13] Updates readme --- README.md | 50 ++++++++++++-------------------------------------- 1 file changed, 12 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index f1a7706..b2dd165 100644 --- a/README.md +++ b/README.md @@ -104,10 +104,10 @@ class SiteStatusCheckerAgent extends AgentAggregate Now, let's implement the tool used by this agent: ```php -use LLM\Agents\Tool\Tool; +use LLM\Agents\Tool\PhpTool; use LLM\Agents\Tool\ToolLanguage; -class CheckSiteAvailabilityTool extends Tool +class CheckSiteAvailabilityTool extends PhpTool { public const NAME = 'check_site_availability'; @@ -217,7 +217,7 @@ execution. Here's an example of how you might call the linked agent: ```php -use LLM\Agents\Tool\Tool; +use LLM\Agents\Tool\PhpTool; use LLM\Agents\Agent\AgentExecutor; use LLM\Agents\LLM\Prompt\Chat\ToolCallResultMessage; use LLM\Agents\LLM\Response\ToolCalledResponse; @@ -227,7 +227,7 @@ use LLM\Agents\Tool\ToolLanguage; /** * @extends PhpTool */ -final class AskAgentTool extends Tool +final class AskAgentTool extends PhpTool { public const NAME = 'ask_agent'; @@ -735,44 +735,18 @@ class PromptGeneratorBootloader extends Bootloader This class is responsible for handling conversions between JSON schemas and PHP objects. -Here's an example implementation of the `LLM\Agents\Tool\SchemaMapperInterface`: +We provide a schema mapper package that you can use to implement the `SchemaMapperInterface` in your project. This +package is a super handy JSON Schema Mapper for the LLM Agents project. -```php -use CuyZ\Valinor\Mapper\TreeMapper; -use LLM\Agents\Tool\SchemaMapperInterface; -use Spiral\JsonSchemaGenerator\Generator as JsonSchemaGenerator; - -final readonly class SchemaMapper implements SchemaMapperInterface -{ - public function __construct( - private JsonSchemaGenerator $generator, - private TreeMapper $mapper, - ) {} - - public function toJsonSchema(string $class): array - { - if (json_validate($class)) { - return json_decode($class, associative: true); - } - - if (class_exists($class)) { - return $this->generator->generate($class)->jsonSerialize(); - } +**To install the package:** - throw new \InvalidArgumentException("Invalid class or JSON schema provided: $class"); - } - - public function toObject(string $json, ?string $class = null): object - { - if ($class === null) { - return json_decode($json, associative: false); - } - - return $this->mapper->map($class, json_decode($json, associative: true)); - } -} +```bash +composer require llm-agents/schema-mapper ``` +> **Note:** Read full documentation of the `llm-agents/schema-mapper` +> package [here](https://github.com/llm-agents-php/schema-mapper) + ### → ContextFactoryInterface It provides a clean way to pass execution-specific data through the system without tightly coupling components or overly From c4a8b0c0c7bac7f9441832ace30b116c1c007a71 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Sat, 7 Sep 2024 12:18:24 +0400 Subject: [PATCH 13/13] Updates readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b2dd165..a4d6998 100644 --- a/README.md +++ b/README.md @@ -741,10 +741,10 @@ package is a super handy JSON Schema Mapper for the LLM Agents project. **To install the package:** ```bash -composer require llm-agents/schema-mapper +composer require llm-agents/json-schema-mapper ``` -> **Note:** Read full documentation of the `llm-agents/schema-mapper` +> **Note:** Read full documentation of the `llm-agents/json-schema-mapper` > package [here](https://github.com/llm-agents-php/schema-mapper) ### → ContextFactoryInterface